From b1cca8fbe0f554cd8e497bb30f04e71a611004c9 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 30 Nov 2018 23:36:49 +0300 Subject: [PATCH 0001/1788] extmod/uzlib: Update uzlib to v2.9.2. Major changes include robust parsing of erroneous compressed streams and updated API. --- extmod/uzlib/defl_static.h | 45 ++++++++++ extmod/uzlib/tinf.h | 120 +------------------------- extmod/uzlib/tinf_compat.h | 9 ++ extmod/uzlib/tinfgzip.c | 4 +- extmod/uzlib/tinflate.c | 172 ++++++++++++++++++++++++++++++------- extmod/uzlib/tinfzlib.c | 4 +- extmod/uzlib/uzlib.h | 169 ++++++++++++++++++++++++++++++++++++ extmod/uzlib/uzlib_conf.h | 22 +++++ 8 files changed, 391 insertions(+), 154 deletions(-) create mode 100644 extmod/uzlib/defl_static.h create mode 100644 extmod/uzlib/tinf_compat.h create mode 100644 extmod/uzlib/uzlib.h create mode 100644 extmod/uzlib/uzlib_conf.h diff --git a/extmod/uzlib/defl_static.h b/extmod/uzlib/defl_static.h new file mode 100644 index 0000000000..292734d773 --- /dev/null +++ b/extmod/uzlib/defl_static.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) uzlib authors + * + * This software is provided 'as-is', without any express + * or implied warranty. In no event will the authors be + * held liable for any damages arising from the use of + * this software. + * + * Permission is granted to anyone to use this software + * for any purpose, including commercial applications, + * and to alter it and redistribute it freely, subject to + * the following restrictions: + * + * 1. The origin of this software must not be + * misrepresented; you must not claim that you + * wrote the original software. If you use this + * software in a product, an acknowledgment in + * the product documentation would be appreciated + * but is not required. + * + * 2. Altered source versions must be plainly marked + * as such, and must not be misrepresented as + * being the original software. + * + * 3. This notice may not be removed or altered from + * any source distribution. + */ + +/* This files contains type declaration and prototypes for defl_static.c. + They may be altered/distinct from the originals used in PuTTY source + code. */ + +struct Outbuf { + unsigned char *outbuf; + int outlen, outsize; + unsigned long outbits; + int noutbits; + int comp_disabled; +}; + +void outbits(struct Outbuf *out, unsigned long bits, int nbits); +void zlib_start_block(struct Outbuf *ctx); +void zlib_finish_block(struct Outbuf *ctx); +void zlib_literal(struct Outbuf *ectx, unsigned char c); +void zlib_match(struct Outbuf *ectx, int distance, int len); diff --git a/extmod/uzlib/tinf.h b/extmod/uzlib/tinf.h index 106203a099..ae6e1c4073 100644 --- a/extmod/uzlib/tinf.h +++ b/extmod/uzlib/tinf.h @@ -1,117 +1,3 @@ -/* - * uzlib - tiny deflate/inflate library (deflate, gzip, zlib) - * - * Copyright (c) 2003 by Joergen Ibsen / Jibz - * All Rights Reserved - * http://www.ibsensoftware.com/ - * - * Copyright (c) 2014-2016 by Paul Sokolovsky - */ - -#ifndef TINF_H_INCLUDED -#define TINF_H_INCLUDED - -#include - -/* calling convention */ -#ifndef TINFCC - #ifdef __WATCOMC__ - #define TINFCC __cdecl - #else - #define TINFCC - #endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* ok status, more data produced */ -#define TINF_OK 0 -/* end of compressed stream reached */ -#define TINF_DONE 1 -#define TINF_DATA_ERROR (-3) -#define TINF_CHKSUM_ERROR (-4) -#define TINF_DICT_ERROR (-5) - -/* checksum types */ -#define TINF_CHKSUM_NONE 0 -#define TINF_CHKSUM_ADLER 1 -#define TINF_CHKSUM_CRC 2 - -/* data structures */ - -typedef struct { - unsigned short table[16]; /* table of code length counts */ - unsigned short trans[288]; /* code -> symbol translation table */ -} TINF_TREE; - -struct TINF_DATA; -typedef struct TINF_DATA { - const unsigned char *source; - /* If source above is NULL, this function will be used to read - next byte from source stream */ - unsigned char (*readSource)(struct TINF_DATA *data); - - unsigned int tag; - unsigned int bitcount; - - /* Buffer start */ - unsigned char *destStart; - /* Buffer total size */ - unsigned int destSize; - /* Current pointer in buffer */ - unsigned char *dest; - /* Remaining bytes in buffer */ - unsigned int destRemaining; - - /* Accumulating checksum */ - unsigned int checksum; - char checksum_type; - - int btype; - int bfinal; - unsigned int curlen; - int lzOff; - unsigned char *dict_ring; - unsigned int dict_size; - unsigned int dict_idx; - - TINF_TREE ltree; /* dynamic length/symbol tree */ - TINF_TREE dtree; /* dynamic distance tree */ -} TINF_DATA; - -#define TINF_PUT(d, c) \ - { \ - *d->dest++ = c; \ - if (d->dict_ring) { d->dict_ring[d->dict_idx++] = c; if (d->dict_idx == d->dict_size) d->dict_idx = 0; } \ - } - -unsigned char TINFCC uzlib_get_byte(TINF_DATA *d); - -/* Decompression API */ - -void TINFCC uzlib_init(void); -void TINFCC uzlib_uncompress_init(TINF_DATA *d, void *dict, unsigned int dictLen); -int TINFCC uzlib_uncompress(TINF_DATA *d); -int TINFCC uzlib_uncompress_chksum(TINF_DATA *d); - -int TINFCC uzlib_zlib_parse_header(TINF_DATA *d); -int TINFCC uzlib_gzip_parse_header(TINF_DATA *d); - -/* Compression API */ - -void TINFCC uzlib_compress(void *data, const uint8_t *src, unsigned slen); - -/* Checksum API */ - -/* prev_sum is previous value for incremental computation, 1 initially */ -uint32_t TINFCC uzlib_adler32(const void *data, unsigned int length, uint32_t prev_sum); -/* crc is previous value for incremental computation, 0xffffffff initially */ -uint32_t TINFCC uzlib_crc32(const void *data, unsigned int length, uint32_t crc); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* TINF_H_INCLUDED */ +/* Compatibility header for the original tinf lib/older versions of uzlib. + Note: may be removed in the future, please migrate to uzlib.h. */ +#include "uzlib.h" diff --git a/extmod/uzlib/tinf_compat.h b/extmod/uzlib/tinf_compat.h new file mode 100644 index 0000000000..f763804bd9 --- /dev/null +++ b/extmod/uzlib/tinf_compat.h @@ -0,0 +1,9 @@ +/* This header contains compatibility defines for the original tinf API + and uzlib 2.x and below API. These defines are deprecated and going + to be removed in the future, so applications should migrate to new + uzlib API. */ +#define TINF_DATA struct uzlib_uncomp + +#define destSize dest_size +#define destStart dest_start +#define readSource source_read_cb diff --git a/extmod/uzlib/tinfgzip.c b/extmod/uzlib/tinfgzip.c index f1afdd0b8d..22b000df9a 100644 --- a/extmod/uzlib/tinfgzip.c +++ b/extmod/uzlib/tinfgzip.c @@ -1,12 +1,12 @@ /* - * tinfgzip - tiny gzip decompressor + * uzlib - tiny deflate/inflate library (deflate, gzip, zlib) * * Copyright (c) 2003 by Joergen Ibsen / Jibz * All Rights Reserved * * http://www.ibsensoftware.com/ * - * Copyright (c) 2014-2016 by Paul Sokolovsky + * Copyright (c) 2014-2018 by Paul Sokolovsky * * This software is provided 'as-is', without any express * or implied warranty. In no event will the authors be diff --git a/extmod/uzlib/tinflate.c b/extmod/uzlib/tinflate.c index 21558af5bf..b93bc1fa36 100644 --- a/extmod/uzlib/tinflate.c +++ b/extmod/uzlib/tinflate.c @@ -1,11 +1,11 @@ /* - * tinflate - tiny inflate + * uzlib - tiny deflate/inflate library (deflate, gzip, zlib) * * Copyright (c) 2003 by Joergen Ibsen / Jibz * All Rights Reserved * http://www.ibsensoftware.com/ * - * Copyright (c) 2014-2016 by Paul Sokolovsky + * Copyright (c) 2014-2018 by Paul Sokolovsky * * This software is provided 'as-is', without any express * or implied warranty. In no event will the authors be @@ -35,6 +35,15 @@ #include #include "tinf.h" +#define UZLIB_DUMP_ARRAY(heading, arr, size) \ + { \ + printf("%s", heading); \ + for (int i = 0; i < size; ++i) { \ + printf(" %d", (arr)[i]); \ + } \ + printf("\n"); \ + } + uint32_t tinf_get_le_uint32(TINF_DATA *d); uint32_t tinf_get_be_uint32(TINF_DATA *d); @@ -149,6 +158,13 @@ static void tinf_build_tree(TINF_TREE *t, const unsigned char *lengths, unsigned /* scan symbol lengths, and sum code length counts */ for (i = 0; i < num; ++i) t->table[lengths[i]]++; + #if UZLIB_CONF_DEBUG_LOG >= 2 + UZLIB_DUMP_ARRAY("codelen counts:", t->table, TINF_ARRAY_SIZE(t->table)); + #endif + + /* In the lengths array, 0 means unused code. So, t->table[0] now contains + number of unused codes. But table's purpose is to contain # of codes of + particular length, and there're 0 codes of length 0. */ t->table[0] = 0; /* compute offset table for distribution sort */ @@ -158,6 +174,10 @@ static void tinf_build_tree(TINF_TREE *t, const unsigned char *lengths, unsigned sum += t->table[i]; } + #if UZLIB_CONF_DEBUG_LOG >= 2 + UZLIB_DUMP_ARRAY("codelen offsets:", offs, TINF_ARRAY_SIZE(offs)); + #endif + /* create code->symbol translation table (symbols sorted by code) */ for (i = 0; i < num; ++i) { @@ -171,10 +191,28 @@ static void tinf_build_tree(TINF_TREE *t, const unsigned char *lengths, unsigned unsigned char uzlib_get_byte(TINF_DATA *d) { - if (d->source) { + /* If end of source buffer is not reached, return next byte from source + buffer. */ + if (d->source < d->source_limit) { return *d->source++; } - return d->readSource(d); + + /* Otherwise if there's callback and we haven't seen EOF yet, try to + read next byte using it. (Note: the callback can also update ->source + and ->source_limit). */ + if (d->readSource && !d->eof) { + int val = d->readSource(d); + if (val >= 0) { + return (unsigned char)val; + } + } + + /* Otherwise, we hit EOF (either from ->readSource() or from exhaustion + of the buffer), and it will be "sticky", i.e. further calls to this + function will end up here too. */ + d->eof = true; + + return 0; } uint32_t tinf_get_le_uint32(TINF_DATA *d) @@ -182,7 +220,7 @@ uint32_t tinf_get_le_uint32(TINF_DATA *d) uint32_t val = 0; int i; for (i = 4; i--;) { - val = val >> 8 | uzlib_get_byte(d) << 24; + val = val >> 8 | ((uint32_t)uzlib_get_byte(d)) << 24; } return val; } @@ -245,21 +283,31 @@ static int tinf_decode_symbol(TINF_DATA *d, TINF_TREE *t) cur = 2*cur + tinf_getbit(d); - ++len; + if (++len == TINF_ARRAY_SIZE(t->table)) { + return TINF_DATA_ERROR; + } sum += t->table[len]; cur -= t->table[len]; } while (cur >= 0); - return t->trans[sum + cur]; + sum += cur; + #if UZLIB_CONF_PARANOID_CHECKS + if (sum < 0 || sum >= TINF_ARRAY_SIZE(t->trans)) { + return TINF_DATA_ERROR; + } + #endif + + return t->trans[sum]; } /* given a data stream, decode dynamic trees from it */ -static void tinf_decode_trees(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt) +static int tinf_decode_trees(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt) { + /* code lengths for 288 literal/len symbols and 32 dist symbols */ unsigned char lengths[288+32]; - unsigned int hlit, hdist, hclen; + unsigned int hlit, hdist, hclen, hlimit; unsigned int i, num, length; /* get 5 bits HLIT (257-286) */ @@ -286,53 +334,75 @@ static void tinf_decode_trees(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt) tinf_build_tree(lt, lengths, 19); /* decode code lengths for the dynamic trees */ - for (num = 0; num < hlit + hdist; ) + hlimit = hlit + hdist; + for (num = 0; num < hlimit; ) { int sym = tinf_decode_symbol(d, lt); + unsigned char fill_value = 0; + int lbits, lbase = 3; + + /* error decoding */ + if (sym < 0) return sym; switch (sym) { case 16: /* copy previous code length 3-6 times (read 2 bits) */ - { - unsigned char prev = lengths[num - 1]; - for (length = tinf_read_bits(d, 2, 3); length; --length) - { - lengths[num++] = prev; - } - } + if (num == 0) return TINF_DATA_ERROR; + fill_value = lengths[num - 1]; + lbits = 2; break; case 17: /* repeat code length 0 for 3-10 times (read 3 bits) */ - for (length = tinf_read_bits(d, 3, 3); length; --length) - { - lengths[num++] = 0; - } + lbits = 3; break; case 18: /* repeat code length 0 for 11-138 times (read 7 bits) */ - for (length = tinf_read_bits(d, 7, 11); length; --length) - { - lengths[num++] = 0; - } + lbits = 7; + lbase = 11; break; default: /* values 0-15 represent the actual code lengths */ lengths[num++] = sym; - break; + /* continue the for loop */ + continue; + } + + /* special code length 16-18 are handled here */ + length = tinf_read_bits(d, lbits, lbase); + if (num + length > hlimit) return TINF_DATA_ERROR; + for (; length; --length) + { + lengths[num++] = fill_value; } } + #if UZLIB_CONF_DEBUG_LOG >= 2 + printf("lit code lengths (%d):", hlit); + UZLIB_DUMP_ARRAY("", lengths, hlit); + printf("dist code lengths (%d):", hdist); + UZLIB_DUMP_ARRAY("", lengths + hlit, hdist); + #endif + + #if UZLIB_CONF_PARANOID_CHECKS + /* Check that there's "end of block" symbol */ + if (lengths[256] == 0) { + return TINF_DATA_ERROR; + } + #endif + /* build dynamic trees */ tinf_build_tree(lt, lengths, hlit); tinf_build_tree(dt, lengths + hlit, hdist); + + return TINF_OK; } /* ----------------------------- * * -- block inflate functions -- * * ----------------------------- */ -/* given a stream and two trees, inflate a block of data */ +/* given a stream and two trees, inflate next byte of output */ static int tinf_inflate_block_data(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt) { if (d->curlen == 0) { @@ -341,6 +411,10 @@ static int tinf_inflate_block_data(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt) int sym = tinf_decode_symbol(d, lt); //printf("huff sym: %02x\n", sym); + if (d->eof) { + return TINF_DATA_ERROR; + } + /* literal byte */ if (sym < 256) { TINF_PUT(d, sym); @@ -354,21 +428,45 @@ static int tinf_inflate_block_data(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt) /* substring from sliding dictionary */ sym -= 257; + if (sym >= 29) { + return TINF_DATA_ERROR; + } + /* possibly get more bits from length code */ d->curlen = tinf_read_bits(d, length_bits[sym], length_base[sym]); dist = tinf_decode_symbol(d, dt); + if (dist >= 30) { + return TINF_DATA_ERROR; + } + /* possibly get more bits from distance code */ offs = tinf_read_bits(d, dist_bits[dist], dist_base[dist]); + + /* calculate and validate actual LZ offset to use */ if (d->dict_ring) { if (offs > d->dict_size) { return TINF_DICT_ERROR; } + /* Note: unlike full-dest-in-memory case below, we don't + try to catch offset which points to not yet filled + part of the dictionary here. Doing so would require + keeping another variable to track "filled in" size + of the dictionary. Appearance of such an offset cannot + lead to accessing memory outside of the dictionary + buffer, and clients which don't want to leak unrelated + information, should explicitly initialize dictionary + buffer passed to uzlib. */ + d->lzOff = d->dict_idx - offs; if (d->lzOff < 0) { d->lzOff += d->dict_size; } } else { + /* catch trying to point before the start of dest buffer */ + if (offs > d->dest - d->destStart) { + return TINF_DATA_ERROR; + } d->lzOff = -offs; } } @@ -387,7 +485,7 @@ static int tinf_inflate_block_data(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt) return TINF_OK; } -/* inflate an uncompressed block of data */ +/* inflate next byte from uncompressed block of data */ static int tinf_inflate_uncompressed_block(TINF_DATA *d) { if (d->curlen == 0) { @@ -440,6 +538,7 @@ void uzlib_init(void) /* initialize decompression structure */ void uzlib_uncompress_init(TINF_DATA *d, void *dict, unsigned int dictLen) { + d->eof = 0; d->bitcount = 0; d->bfinal = 0; d->btype = -1; @@ -449,7 +548,7 @@ void uzlib_uncompress_init(TINF_DATA *d, void *dict, unsigned int dictLen) d->curlen = 0; } -/* inflate next byte of compressed stream */ +/* inflate next output bytes from compressed stream */ int uzlib_uncompress(TINF_DATA *d) { do { @@ -463,14 +562,19 @@ next_blk: /* read block type (2 bits) */ d->btype = tinf_read_bits(d, 2, 0); - //printf("Started new block: type=%d final=%d\n", d->btype, d->bfinal); + #if UZLIB_CONF_DEBUG_LOG >= 1 + printf("Started new block: type=%d final=%d\n", d->btype, d->bfinal); + #endif if (d->btype == 1) { /* build fixed huffman trees */ tinf_build_fixed_trees(&d->ltree, &d->dtree); } else if (d->btype == 2) { /* decode trees from stream */ - tinf_decode_trees(d, &d->ltree, &d->dtree); + res = tinf_decode_trees(d, &d->ltree, &d->dtree); + if (res != TINF_OK) { + return res; + } } } @@ -483,7 +587,7 @@ next_blk: break; case 1: case 2: - /* decompress block with fixed/dyanamic huffman trees */ + /* decompress block with fixed/dynamic huffman trees */ /* trees were decoded previously, so it's the same routine for both */ res = tinf_inflate_block_data(d, &d->ltree, &d->dtree); break; @@ -501,11 +605,13 @@ next_blk: return res; } - } while (--d->destSize); + } while (d->dest < d->dest_limit); return TINF_OK; } +/* inflate next output bytes from compressed stream, updating + checksum, and at the end of stream, verify it */ int uzlib_uncompress_chksum(TINF_DATA *d) { int res; diff --git a/extmod/uzlib/tinfzlib.c b/extmod/uzlib/tinfzlib.c index 74fade3b9d..5cb8852fcc 100644 --- a/extmod/uzlib/tinfzlib.c +++ b/extmod/uzlib/tinfzlib.c @@ -1,12 +1,12 @@ /* - * tinfzlib - tiny zlib decompressor + * uzlib - tiny deflate/inflate library (deflate, gzip, zlib) * * Copyright (c) 2003 by Joergen Ibsen / Jibz * All Rights Reserved * * http://www.ibsensoftware.com/ * - * Copyright (c) 2014-2016 by Paul Sokolovsky + * Copyright (c) 2014-2018 by Paul Sokolovsky * * This software is provided 'as-is', without any express * or implied warranty. In no event will the authors be diff --git a/extmod/uzlib/uzlib.h b/extmod/uzlib/uzlib.h new file mode 100644 index 0000000000..3a4a1ad160 --- /dev/null +++ b/extmod/uzlib/uzlib.h @@ -0,0 +1,169 @@ +/* + * uzlib - tiny deflate/inflate library (deflate, gzip, zlib) + * + * Copyright (c) 2003 by Joergen Ibsen / Jibz + * All Rights Reserved + * http://www.ibsensoftware.com/ + * + * Copyright (c) 2014-2018 by Paul Sokolovsky + * + * This software is provided 'as-is', without any express + * or implied warranty. In no event will the authors be + * held liable for any damages arising from the use of + * this software. + * + * Permission is granted to anyone to use this software + * for any purpose, including commercial applications, + * and to alter it and redistribute it freely, subject to + * the following restrictions: + * + * 1. The origin of this software must not be + * misrepresented; you must not claim that you + * wrote the original software. If you use this + * software in a product, an acknowledgment in + * the product documentation would be appreciated + * but is not required. + * + * 2. Altered source versions must be plainly marked + * as such, and must not be misrepresented as + * being the original software. + * + * 3. This notice may not be removed or altered from + * any source distribution. + */ + +#ifndef UZLIB_H_INCLUDED +#define UZLIB_H_INCLUDED + +#include +#include +#include + +#include "defl_static.h" + +#include "uzlib_conf.h" +#if UZLIB_CONF_DEBUG_LOG +#include +#endif + +/* calling convention */ +#ifndef TINFCC + #ifdef __WATCOMC__ + #define TINFCC __cdecl + #else + #define TINFCC + #endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* ok status, more data produced */ +#define TINF_OK 0 +/* end of compressed stream reached */ +#define TINF_DONE 1 +#define TINF_DATA_ERROR (-3) +#define TINF_CHKSUM_ERROR (-4) +#define TINF_DICT_ERROR (-5) + +/* checksum types */ +#define TINF_CHKSUM_NONE 0 +#define TINF_CHKSUM_ADLER 1 +#define TINF_CHKSUM_CRC 2 + +/* helper macros */ +#define TINF_ARRAY_SIZE(arr) (sizeof(arr) / sizeof(*(arr))) + +/* data structures */ + +typedef struct { + unsigned short table[16]; /* table of code length counts */ + unsigned short trans[288]; /* code -> symbol translation table */ +} TINF_TREE; + +struct uzlib_uncomp { + /* Pointer to the next byte in the input buffer */ + const unsigned char *source; + /* Pointer to the next byte past the input buffer (source_limit = source + len) */ + const unsigned char *source_limit; + /* If source_limit == NULL, or source >= source_limit, this function + will be used to read next byte from source stream. The function may + also return -1 in case of EOF (or irrecoverable error). Note that + besides returning the next byte, it may also update source and + source_limit fields, thus allowing for buffered operation. */ + int (*source_read_cb)(struct uzlib_uncomp *uncomp); + + unsigned int tag; + unsigned int bitcount; + + /* Destination (output) buffer start */ + unsigned char *dest_start; + /* Current pointer in dest buffer */ + unsigned char *dest; + /* Pointer past the end of the dest buffer, similar to source_limit */ + unsigned char *dest_limit; + + /* Accumulating checksum */ + unsigned int checksum; + char checksum_type; + bool eof; + + int btype; + int bfinal; + unsigned int curlen; + int lzOff; + unsigned char *dict_ring; + unsigned int dict_size; + unsigned int dict_idx; + + TINF_TREE ltree; /* dynamic length/symbol tree */ + TINF_TREE dtree; /* dynamic distance tree */ +}; + +#include "tinf_compat.h" + +#define TINF_PUT(d, c) \ + { \ + *d->dest++ = c; \ + if (d->dict_ring) { d->dict_ring[d->dict_idx++] = c; if (d->dict_idx == d->dict_size) d->dict_idx = 0; } \ + } + +unsigned char TINFCC uzlib_get_byte(TINF_DATA *d); + +/* Decompression API */ + +void TINFCC uzlib_init(void); +void TINFCC uzlib_uncompress_init(TINF_DATA *d, void *dict, unsigned int dictLen); +int TINFCC uzlib_uncompress(TINF_DATA *d); +int TINFCC uzlib_uncompress_chksum(TINF_DATA *d); + +int TINFCC uzlib_zlib_parse_header(TINF_DATA *d); +int TINFCC uzlib_gzip_parse_header(TINF_DATA *d); + +/* Compression API */ + +typedef const uint8_t *uzlib_hash_entry_t; + +struct uzlib_comp { + struct Outbuf out; + + uzlib_hash_entry_t *hash_table; + unsigned int hash_bits; + unsigned int dict_size; +}; + +void TINFCC uzlib_compress(struct uzlib_comp *c, const uint8_t *src, unsigned slen); + +/* Checksum API */ + +/* prev_sum is previous value for incremental computation, 1 initially */ +uint32_t TINFCC uzlib_adler32(const void *data, unsigned int length, uint32_t prev_sum); +/* crc is previous value for incremental computation, 0xffffffff initially */ +uint32_t TINFCC uzlib_crc32(const void *data, unsigned int length, uint32_t crc); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* UZLIB_H_INCLUDED */ diff --git a/extmod/uzlib/uzlib_conf.h b/extmod/uzlib/uzlib_conf.h new file mode 100644 index 0000000000..d6c9407157 --- /dev/null +++ b/extmod/uzlib/uzlib_conf.h @@ -0,0 +1,22 @@ +/* + * uzlib - tiny deflate/inflate library (deflate, gzip, zlib) + * + * Copyright (c) 2014-2018 by Paul Sokolovsky + */ + +#ifndef UZLIB_CONF_H_INCLUDED +#define UZLIB_CONF_H_INCLUDED + +#ifndef UZLIB_CONF_DEBUG_LOG +/* Debug logging level 0, 1, 2, etc. */ +#define UZLIB_CONF_DEBUG_LOG 0 +#endif + +#ifndef UZLIB_CONF_PARANOID_CHECKS +/* Perform extra checks on the input stream, even if they aren't proven + to be strictly required (== lack of them wasn't proven to lead to + crashes). */ +#define UZLIB_CONF_PARANOID_CHECKS 0 +#endif + +#endif /* UZLIB_CONF_H_INCLUDED */ From 35687a87ec3fc28654933d7d37bfb82cb04f5227 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 30 Nov 2018 23:48:03 +0300 Subject: [PATCH 0002/1788] extmod/moduzlib: Update for uzlib 2.9.2. --- extmod/moduzlib.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/extmod/moduzlib.c b/extmod/moduzlib.c index 940b72805d..f8452c72b9 100644 --- a/extmod/moduzlib.c +++ b/extmod/moduzlib.c @@ -48,7 +48,7 @@ typedef struct _mp_obj_decompio_t { bool eof; } mp_obj_decompio_t; -STATIC unsigned char read_src_stream(TINF_DATA *data) { +STATIC int read_src_stream(TINF_DATA *data) { byte *p = (void*)data; p -= offsetof(mp_obj_decompio_t, decomp); mp_obj_decompio_t *self = (mp_obj_decompio_t*)p; @@ -110,7 +110,7 @@ STATIC mp_uint_t decompio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *er } o->decomp.dest = buf; - o->decomp.destSize = size; + o->decomp.dest_limit = (byte*)buf + size; int st = uzlib_uncompress_chksum(&o->decomp); if (st == TINF_DONE) { o->eof = true; @@ -155,9 +155,10 @@ STATIC mp_obj_t mod_uzlib_decompress(size_t n_args, const mp_obj_t *args) { byte *dest_buf = m_new(byte, dest_buf_size); decomp->dest = dest_buf; - decomp->destSize = dest_buf_size; - DEBUG_printf("uzlib: Initial out buffer: " UINT_FMT " bytes\n", decomp->destSize); + decomp->dest_limit = dest_buf + dest_buf_size; + DEBUG_printf("uzlib: Initial out buffer: " UINT_FMT " bytes\n", dest_buf_size); decomp->source = bufinfo.buf; + decomp->source_limit = (byte*)bufinfo.buf + bufinfo.len; int st; bool is_zlib = true; @@ -185,7 +186,7 @@ STATIC mp_obj_t mod_uzlib_decompress(size_t n_args, const mp_obj_t *args) { dest_buf = m_renew(byte, dest_buf, dest_buf_size, dest_buf_size + 256); dest_buf_size += 256; decomp->dest = dest_buf + offset; - decomp->destSize = 256; + decomp->dest_limit = decomp->dest + 256; } mp_uint_t final_sz = decomp->dest - dest_buf; From e33bc59712aa484107dc1cd4009dd8ab2da6dcb2 Mon Sep 17 00:00:00 2001 From: Sean Burton Date: Thu, 13 Dec 2018 12:10:35 +0000 Subject: [PATCH 0003/1788] py: Remove calls to file reader functions when these are disabled. If MICROPY_PERSISTENT_CODE_LOAD or MICROPY_ENABLE_COMPILER are enabled then code gets enabled that calls file reading functions which may be disabled if no readers have been implemented. To fix this, introduce a MICROPY_HAS_FILE_READER variable, which is automatically set if MICROPY_READER_POSIX or MICROPY_READER_VFS is set but can also be manually set if a custom reader is being implemented. Then disable the file reading calls if this is not set. --- py/builtinimport.c | 7 +++---- py/mpconfig.h | 5 +++++ py/persistentcode.c | 4 ++++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/py/builtinimport.c b/py/builtinimport.c index b8ed096caf..1a333b5404 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -131,7 +131,7 @@ STATIC mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *d #endif } -#if MICROPY_ENABLE_COMPILER +#if MICROPY_MODULE_FROZEN_STR || MICROPY_ENABLE_COMPILER STATIC void do_load_from_lexer(mp_obj_t module_obj, mp_lexer_t *lex) { #if MICROPY_PY___FILE__ qstr source_name = lex->source_name; @@ -182,7 +182,7 @@ STATIC void do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code) { #endif STATIC void do_load(mp_obj_t module_obj, vstr_t *file) { - #if MICROPY_MODULE_FROZEN || MICROPY_PERSISTENT_CODE_LOAD || MICROPY_ENABLE_COMPILER + #if MICROPY_MODULE_FROZEN || MICROPY_ENABLE_COMPILER || (MICROPY_PERSISTENT_CODE_LOAD && MICROPY_HAS_FILE_READER) char *file_str = vstr_null_terminated_str(file); #endif @@ -213,7 +213,7 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) { // If we support loading .mpy files then check if the file extension is of // the correct format and, if so, load and execute the file. - #if MICROPY_PERSISTENT_CODE_LOAD + #if MICROPY_HAS_FILE_READER && MICROPY_PERSISTENT_CODE_LOAD if (file_str[file->len - 3] == 'm') { mp_raw_code_t *raw_code = mp_raw_code_load_file(file_str); do_execute_raw_code(module_obj, raw_code); @@ -229,7 +229,6 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) { return; } #else - // If we get here then the file was not frozen and we can't compile scripts. mp_raise_msg(&mp_type_ImportError, "script compilation not supported"); #endif diff --git a/py/mpconfig.h b/py/mpconfig.h index ce1a8cbfc2..68a855f199 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -464,6 +464,11 @@ #define MICROPY_READER_VFS (0) #endif +// Whether any readers have been defined +#ifndef MICROPY_HAS_FILE_READER +#define MICROPY_HAS_FILE_READER (MICROPY_READER_POSIX || MICROPY_READER_VFS) +#endif + // Hook for the VM at the start of the opcode loop (can contain variable // definitions usable by the other hook functions) #ifndef MICROPY_VM_HOOK_INIT diff --git a/py/persistentcode.c b/py/persistentcode.c index 7113b0dc2e..88e958d8ff 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -232,12 +232,16 @@ mp_raw_code_t *mp_raw_code_load_mem(const byte *buf, size_t len) { return mp_raw_code_load(&reader); } +#if MICROPY_HAS_FILE_READER + mp_raw_code_t *mp_raw_code_load_file(const char *filename) { mp_reader_t reader; mp_reader_new_file(&reader, filename); return mp_raw_code_load(&reader); } +#endif // MICROPY_HAS_FILE_READER + #endif // MICROPY_PERSISTENT_CODE_LOAD #if MICROPY_PERSISTENT_CODE_SAVE From b16146d18907b921eefec527f7a700413309dd12 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 15 Dec 2018 16:20:18 +1100 Subject: [PATCH 0004/1788] docs/machine: Change sleep to lightsleep and add timeout arguments. The machine.sleep() function can be misleading because it clashes with time.sleep() which has quite different semantics. So change it to machine.lightsleep() which shows that it is closer in behaviour to machine.deepsleep(). Also, add an optional argument to these two sleep functions to specify a maximum time to sleep for. This is a common operation and underlying hardware usually has a special way of performing this operation. The existing machine.sleep() function will remain for backwards compatibility purposes, and it can simply be an alias for machine.lightsleep() without arguments. The behaviour will be the same. --- docs/library/machine.rst | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/docs/library/machine.rst b/docs/library/machine.rst index f734cccc37..a7b5957761 100644 --- a/docs/library/machine.rst +++ b/docs/library/machine.rst @@ -63,16 +63,31 @@ Power related functions .. function:: sleep() - Stops the CPU and disables all peripherals except for WLAN. Execution is resumed from - the point where the sleep was requested. For wake up to actually happen, wake sources - should be configured first. + .. note:: This function is deprecated, use `lightsleep()` instead with no arguments. -.. function:: deepsleep() +.. function:: lightsleep([time_ms]) + deepsleep([time_ms]) - Stops the CPU and all peripherals (including networking interfaces, if any). Execution - is resumed from the main script, just as with a reset. The reset cause can be checked - to know that we are coming from `machine.DEEPSLEEP`. For wake up to actually happen, - wake sources should be configured first, like `Pin` change or `RTC` timeout. + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. .. function:: wake_reason() From 285d265eee834c763749f54a6d806e284be1160c Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 26 Dec 2018 22:44:09 +1100 Subject: [PATCH 0005/1788] stm32: Implement machine.lightsleep(). --- ports/stm32/modmachine.c | 19 ++++++++++++++----- ports/stm32/modmachine.h | 4 ++-- ports/stm32/modpyb.c | 2 +- ports/stm32/rtc.h | 2 ++ 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index 06c07812c0..e14753bfe9 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -329,17 +329,25 @@ 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) { +STATIC mp_obj_t machine_lightsleep(size_t n_args, const mp_obj_t *args) { + if (n_args != 0) { + mp_obj_t args2[2] = {MP_OBJ_NULL, args[0]}; + pyb_rtc_wakeup(2, args2); + } powerctrl_enter_stop_mode(); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_0(machine_sleep_obj, machine_sleep); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_lightsleep_obj, 0, 1, machine_lightsleep); -STATIC mp_obj_t machine_deepsleep(void) { +STATIC mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *args) { + if (n_args != 0) { + mp_obj_t args2[2] = {MP_OBJ_NULL, args[0]}; + pyb_rtc_wakeup(2, args2); + } powerctrl_enter_standby_mode(); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_0(machine_deepsleep_obj, machine_deepsleep); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_deepsleep_obj, 0, 1, machine_deepsleep); STATIC mp_obj_t machine_reset_cause(void) { return MP_OBJ_NEW_SMALL_INT(reset_cause); @@ -358,7 +366,8 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_rng), MP_ROM_PTR(&pyb_rng_get_obj) }, #endif { MP_ROM_QSTR(MP_QSTR_idle), MP_ROM_PTR(&pyb_wfi_obj) }, - { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&machine_sleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&machine_lightsleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_lightsleep), MP_ROM_PTR(&machine_lightsleep_obj) }, { MP_ROM_QSTR(MP_QSTR_deepsleep), MP_ROM_PTR(&machine_deepsleep_obj) }, { MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) }, #if 0 diff --git a/ports/stm32/modmachine.h b/ports/stm32/modmachine.h index 88fe236921..f105bbeec3 100644 --- a/ports/stm32/modmachine.h +++ b/ports/stm32/modmachine.h @@ -36,7 +36,7 @@ MP_DECLARE_CONST_FUN_OBJ_0(machine_unique_id_obj); MP_DECLARE_CONST_FUN_OBJ_0(machine_reset_obj); MP_DECLARE_CONST_FUN_OBJ_0(machine_bootloader_obj); 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); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_lightsleep_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_deepsleep_obj); #endif // MICROPY_INCLUDED_STM32_MODMACHINE_H diff --git a/ports/stm32/modpyb.c b/ports/stm32/modpyb.c index 0e8313d101..60b287fb1c 100644 --- a/ports/stm32/modpyb.c +++ b/ports/stm32/modpyb.c @@ -134,7 +134,7 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { #endif #if MICROPY_PY_PYB_LEGACY - { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&machine_sleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&machine_lightsleep_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) }, diff --git a/ports/stm32/rtc.h b/ports/stm32/rtc.h index 307f8885e3..d3840c1b73 100644 --- a/ports/stm32/rtc.h +++ b/ports/stm32/rtc.h @@ -32,4 +32,6 @@ extern const mp_obj_type_t pyb_rtc_type; void rtc_init_start(bool force_init); void rtc_init_finalise(void); +mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args); + #endif // MICROPY_INCLUDED_STM32_RTC_H From c7ed17bc4bb6127d7b6db841b453462f4ba96514 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 9 Dec 2018 23:32:09 +0300 Subject: [PATCH 0006/1788] extmod/modussl_mbedtls: Remove deprecated mbedtls/net.h header include. This header is deprecated as of mbedtls 2.8.0, as shipped with Ubuntu 18.04. Leads to #warning which is promoted to error with uPy compile options. Note that the current version of mbedtls is 2.14 at the time of writing. --- extmod/modussl_mbedtls.c | 1 - 1 file changed, 1 deletion(-) diff --git a/extmod/modussl_mbedtls.c b/extmod/modussl_mbedtls.c index ce3db0fd92..348bba4c80 100644 --- a/extmod/modussl_mbedtls.c +++ b/extmod/modussl_mbedtls.c @@ -36,7 +36,6 @@ // mbedtls_time_t #include "mbedtls/platform.h" -#include "mbedtls/net.h" #include "mbedtls/ssl.h" #include "mbedtls/x509_crt.h" #include "mbedtls/pk.h" From f8c1be85d1d80fae4b71634a411ab354756c3bda Mon Sep 17 00:00:00 2001 From: Mikhail Zakharov Date: Wed, 2 Jan 2019 10:05:17 -0500 Subject: [PATCH 0007/1788] unix/mpthreadport: Add thread deinit code to stop threads on exit. Free unused memory for threads and cancel any outstanding threads on interpreter exit to avoid possible segmentaiton fault. --- ports/unix/main.c | 4 ++++ ports/unix/mpthreadport.c | 14 ++++++++++++++ ports/unix/mpthreadport.h | 1 + 3 files changed, 19 insertions(+) diff --git a/ports/unix/main.c b/ports/unix/main.c index 1cf237a2b2..8d455fa834 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 MICROPY_PY_THREAD + mp_thread_deinit(); + #endif + #if defined(MICROPY_UNIX_COVERAGE) gc_sweep_all(); #endif diff --git a/ports/unix/mpthreadport.c b/ports/unix/mpthreadport.c index baca0a2b1e..7170379f4e 100644 --- a/ports/unix/mpthreadport.c +++ b/ports/unix/mpthreadport.c @@ -93,6 +93,19 @@ void mp_thread_init(void) { sigaction(SIGUSR1, &sa, NULL); } +void mp_thread_deinit(void) { + pthread_mutex_lock(&thread_mutex); + while (thread->next != NULL) { + thread_t *th = thread; + thread = thread->next; + pthread_cancel(th->id); + free(th); + } + pthread_mutex_unlock(&thread_mutex); + assert(thread->id == pthread_self()); + free(thread); +} + // This function scans all pointers that are external to the current thread. // It does this by signalling all other threads and getting them to scan their // own registers and stack. Note that there may still be some edge cases left @@ -127,6 +140,7 @@ void mp_thread_set_state(void *state) { } void mp_thread_start(void) { + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); pthread_mutex_lock(&thread_mutex); for (thread_t *th = thread; th != NULL; th = th->next) { if (th->id == pthread_self()) { diff --git a/ports/unix/mpthreadport.h b/ports/unix/mpthreadport.h index b158ed5bcc..dfd2975c25 100644 --- a/ports/unix/mpthreadport.h +++ b/ports/unix/mpthreadport.h @@ -29,4 +29,5 @@ typedef pthread_mutex_t mp_thread_mutex_t; void mp_thread_init(void); +void mp_thread_deinit(void); void mp_thread_gc_others(void); From 1e7b4222268d49c6a0e7b5a0033d3b25061653a7 Mon Sep 17 00:00:00 2001 From: Mikhail Zakharov Date: Wed, 2 Jan 2019 10:31:36 -0500 Subject: [PATCH 0008/1788] unix/mpthreadport: Cleanup used memory on thread exit. --- ports/unix/mpthreadport.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/ports/unix/mpthreadport.c b/ports/unix/mpthreadport.c index 7170379f4e..4efa5925b8 100644 --- a/ports/unix/mpthreadport.c +++ b/ports/unix/mpthreadport.c @@ -173,6 +173,11 @@ void mp_thread_create(void *(*entry)(void*), void *arg, size_t *stack_size) { goto er; } + ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + if (ret != 0) { + goto er; + } + pthread_mutex_lock(&thread_mutex); // create thread @@ -205,12 +210,18 @@ er: void mp_thread_finish(void) { pthread_mutex_lock(&thread_mutex); - // TODO unlink from list + thread_t *prev = NULL; for (thread_t *th = thread; th != NULL; th = th->next) { if (th->id == pthread_self()) { - th->ready = 0; + if (prev == NULL) { + thread = th->next; + } else { + prev->next = th->next; + } + free(th); break; } + prev = th; } pthread_mutex_unlock(&thread_mutex); } From 18723e9889626a0700c2defaeba82e86b0b6f08a Mon Sep 17 00:00:00 2001 From: Mikhail Zakharov Date: Wed, 2 Jan 2019 10:44:52 -0500 Subject: [PATCH 0009/1788] unix/mpthreadport: Remove busy wait loop in thread garbage collection. One can't use pthread calls in a signal handler because they are not async-signal-safe (see man signal-safety). Instead, sem_post can be used to post from within a signal handler and this should be more efficient than using a busy wait loop, waiting on a volatile variable. --- ports/unix/mpthreadport.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/ports/unix/mpthreadport.c b/ports/unix/mpthreadport.c index 4efa5925b8..29f2efe752 100644 --- a/ports/unix/mpthreadport.c +++ b/ports/unix/mpthreadport.c @@ -36,6 +36,7 @@ #include #include +#include // this structure forms a linked list, one node per active thread typedef struct _thread_t { @@ -53,7 +54,7 @@ STATIC thread_t *thread; // this is used to synchronise the signal handler of the thread // it's needed because we can't use any pthread calls in a signal handler -STATIC volatile int thread_signal_done; +STATIC sem_t thread_signal_done; // this signal handler is used to scan the regs and stack of a thread STATIC void mp_thread_gc(int signo, siginfo_t *info, void *context) { @@ -70,7 +71,7 @@ STATIC void mp_thread_gc(int signo, siginfo_t *info, void *context) { 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; + sem_post(&thread_signal_done); } } @@ -84,6 +85,7 @@ void mp_thread_init(void) { thread->ready = 1; thread->arg = NULL; thread->next = NULL; + sem_init(&thread_signal_done, 0, 0); // enable signal handler for garbage collection struct sigaction sa; @@ -122,11 +124,8 @@ void mp_thread_gc_others(void) { if (!th->ready) { continue; } - thread_signal_done = 0; pthread_kill(th->id, SIGUSR1); - while (thread_signal_done == 0) { - sched_yield(); - } + sem_wait(&thread_signal_done); } pthread_mutex_unlock(&thread_mutex); } From 51577629b2e91be3ec911167e0bd0311694166db Mon Sep 17 00:00:00 2001 From: Reagan Sanders Date: Thu, 3 Jan 2019 10:37:20 -0500 Subject: [PATCH 0010/1788] cc3200/mods/modussl: Fix ca_certs arg validation in mod_ssl_wrap_socket. Commit a0d97fe40872b46872657bedc0e47cfd704c59aa changed the argument index of ca_certs but missed updating one of the references to the new index. --- ports/cc3200/mods/modussl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/cc3200/mods/modussl.c b/ports/cc3200/mods/modussl.c index 3211570499..9a9dc95a45 100644 --- a/ports/cc3200/mods/modussl.c +++ b/ports/cc3200/mods/modussl.c @@ -85,8 +85,8 @@ STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, 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); - // chech if ca validation is required - if (args[4].u_int != SSL_CERT_NONE && args[5].u_obj == mp_const_none) { + // check if ca validation is required + if (args[4].u_int != SSL_CERT_NONE && args[6].u_obj == mp_const_none) { goto arg_error; } From 42863830be2d19c7dcdf7ccf1fa66168b1bdc13a Mon Sep 17 00:00:00 2001 From: stijn Date: Thu, 3 Jan 2019 15:19:42 +0100 Subject: [PATCH 0011/1788] py: Add optional support for 2-argument version of built-in next(). Configurable via MICROPY_PY_BUILTINS_NEXT2, disabled by default. --- ports/unix/mpconfigport_coverage.h | 1 + py/builtin.h | 4 ++++ py/modbuiltins.c | 17 +++++++++++++++ py/mpconfig.h | 5 +++++ tests/basics/builtin_next_arg2.py | 34 ++++++++++++++++++++++++++++++ 5 files changed, 61 insertions(+) create mode 100644 tests/basics/builtin_next_arg2.py diff --git a/ports/unix/mpconfigport_coverage.h b/ports/unix/mpconfigport_coverage.h index 9ab442ff92..2519482b01 100644 --- a/ports/unix/mpconfigport_coverage.h +++ b/ports/unix/mpconfigport_coverage.h @@ -39,6 +39,7 @@ #define MICROPY_MODULE_GETATTR (1) #define MICROPY_PY_DELATTR_SETATTR (1) #define MICROPY_PY_REVERSE_SPECIAL_METHODS (1) +#define MICROPY_PY_BUILTINS_NEXT2 (1) #define MICROPY_PY_BUILTINS_RANGE_BINOP (1) #define MICROPY_PY_BUILTINS_HELP (1) #define MICROPY_PY_BUILTINS_HELP_MODULES (1) diff --git a/py/builtin.h b/py/builtin.h index 6f8964a250..2066c06173 100644 --- a/py/builtin.h +++ b/py/builtin.h @@ -63,7 +63,11 @@ MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_len_obj); MP_DECLARE_CONST_FUN_OBJ_0(mp_builtin_locals_obj); MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_max_obj); MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_min_obj); +#if MICROPY_PY_BUILTINS_NEXT2 +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_next_obj); +#else MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_next_obj); +#endif MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_oct_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_ord_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_pow_obj); diff --git a/py/modbuiltins.c b/py/modbuiltins.c index c4de325c14..f0d0421d6c 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -316,6 +316,22 @@ MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_min_obj, 1, mp_builtin_min); #endif +#if MICROPY_PY_BUILTINS_NEXT2 +STATIC mp_obj_t mp_builtin_next(size_t n_args, const mp_obj_t *args) { + if (n_args == 1) { + mp_obj_t ret = mp_iternext_allow_raise(args[0]); + if (ret == MP_OBJ_STOP_ITERATION) { + nlr_raise(mp_obj_new_exception(&mp_type_StopIteration)); + } else { + return ret; + } + } else { + mp_obj_t ret = mp_iternext(args[0]); + return ret == MP_OBJ_STOP_ITERATION ? args[1] : ret; + } +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_next_obj, 1, 2, mp_builtin_next); +#else STATIC mp_obj_t mp_builtin_next(mp_obj_t o) { mp_obj_t ret = mp_iternext_allow_raise(o); if (ret == MP_OBJ_STOP_ITERATION) { @@ -325,6 +341,7 @@ STATIC mp_obj_t mp_builtin_next(mp_obj_t o) { } } MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_next_obj, mp_builtin_next); +#endif STATIC mp_obj_t mp_builtin_oct(mp_obj_t o_in) { #if MICROPY_PY_BUILTINS_STR_OP_MODULO diff --git a/py/mpconfig.h b/py/mpconfig.h index 68a855f199..48427c3e58 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -881,6 +881,11 @@ typedef double mp_float_t; #define MICROPY_PY_BUILTINS_RANGE_BINOP (0) #endif +// Support for callling next() with second argument +#ifndef MICROPY_PY_BUILTINS_NEXT2 +#define MICROPY_PY_BUILTINS_NEXT2 (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) diff --git a/tests/basics/builtin_next_arg2.py b/tests/basics/builtin_next_arg2.py new file mode 100644 index 0000000000..b00155ec54 --- /dev/null +++ b/tests/basics/builtin_next_arg2.py @@ -0,0 +1,34 @@ +# test next(iter, default) + +try: + next(iter([]), 42) +except TypeError: # 2-argument version not supported + print('SKIP') + raise SystemExit + +print(next(iter([]), 42)) +print(next(iter(range(0)), 42)) +print(next((x for x in [0] if x == 1), 43)) + +def gen(): + yield 1 + yield 2 + +g = gen() +print(next(g, 42)) +print(next(g, 43)) +print(next(g, 44)) + +class Gen: + def __init__(self): + self.b = False + + def __next__(self): + if self.b: + raise StopIteration + self.b = True + return self.b + +g = Gen() +print(next(g, 44)) +print(next(g, 45)) From c2886868b9ccbe8580f57135bb29779a5d36c1e8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 27 Jan 2019 13:17:22 +1100 Subject: [PATCH 0012/1788] stm32/rtc: Check RTCEN=1 when testing if RTC is already running on boot. It can be that LSEON and LSERDY are set yet the RTC is not enabled (this can happen for example when coming out of the ST DFU mode on an F405 with the RTC not previously initialised). In such a case the RTC is never started because the code thinks it's already running. This patch fixes this case by always checking if RTCEN is set when booting up (and also testing for a valid RTCSEL value in the case of using an LSE). --- ports/stm32/rtc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ports/stm32/rtc.c b/ports/stm32/rtc.c index 1999dfb384..250c34bcf5 100644 --- a/ports/stm32/rtc.c +++ b/ports/stm32/rtc.c @@ -124,7 +124,9 @@ void rtc_init_start(bool force_init) { rtc_need_init_finalise = false; if (!force_init) { - if ((RCC->BDCR & (RCC_BDCR_LSEON | RCC_BDCR_LSERDY)) == (RCC_BDCR_LSEON | RCC_BDCR_LSERDY)) { + uint32_t bdcr = RCC->BDCR; + if ((bdcr & (RCC_BDCR_RTCEN | RCC_BDCR_RTCSEL | RCC_BDCR_LSEON | RCC_BDCR_LSERDY)) + == (RCC_BDCR_RTCEN | RCC_BDCR_RTCSEL_0 | RCC_BDCR_LSEON | RCC_BDCR_LSERDY)) { // LSE is enabled & ready --> no need to (re-)init RTC // remove Backup Domain write protection HAL_PWR_EnableBkUpAccess(); @@ -133,7 +135,8 @@ 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) { + } else if ((bdcr & (RCC_BDCR_RTCEN | RCC_BDCR_RTCSEL)) + == (RCC_BDCR_RTCEN | 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(); From 7d8db42d17958560ccf56bbbae83ad795329aa43 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 27 Jan 2019 13:52:43 +1100 Subject: [PATCH 0013/1788] stm32/usbdev: Add USB config option for board being self powered. The new compile-time option is MICROPY_HW_USB_SELF_POWERED. Set this option to 1 in the board configuration file to indicate that the USB device is self powered. This option is disabled by default (previous behaviour). --- ports/stm32/usbd_conf.h | 6 ++++++ ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c | 15 +++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/ports/stm32/usbd_conf.h b/ports/stm32/usbd_conf.h index 1f8e754a2b..c5faf6c8c8 100644 --- a/ports/stm32/usbd_conf.h +++ b/ports/stm32/usbd_conf.h @@ -37,10 +37,16 @@ #include #include +#include "py/mpconfig.h" + #define USBD_MAX_NUM_INTERFACES 4 #define USBD_MAX_NUM_CONFIGURATION 1 #define USBD_MAX_STR_DESC_SIZ 0x100 +#if MICROPY_HW_USB_SELF_POWERED +#define USBD_SELF_POWERED 1 +#else #define USBD_SELF_POWERED 0 +#endif #define USBD_DEBUG_LEVEL 0 #endif // MICROPY_INCLUDED_STM32_USBD_CONF_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 809e0d42f3..688cdc28ba 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -96,6 +96,13 @@ #define HID_REQ_SET_IDLE (0x0a) #define HID_REQ_GET_IDLE (0x02) +// Value used in the configuration descriptor for the bmAttributes entry +#if MICROPY_HW_USB_SELF_POWERED +#define CONFIG_DESC_ATTRIBUTES (0xc0) // self powered +#else +#define CONFIG_DESC_ATTRIBUTES (0x80) // bus powered +#endif + #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 = { @@ -123,7 +130,7 @@ static const uint8_t msc_template_config_desc[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 + CONFIG_DESC_ATTRIBUTES, // bmAttributes 0xfa, // bMaxPower: in units of 2mA //========================================================================== @@ -171,7 +178,7 @@ static const uint8_t cdc_msc_template_config_desc[CDC_MSC_TEMPLATE_CONFIG_DESC_S 0x03, // bNumInterfaces: 3 interfaces 0x01, // bConfigurationValue: Configuration value 0x00, // iConfiguration: Index of string descriptor describing the configuration - 0x80, // bmAttributes: bus powered; 0xc0 for self powered + CONFIG_DESC_ATTRIBUTES, // bmAttributes 0xfa, // bMaxPower: in units of 2mA //========================================================================== @@ -308,7 +315,7 @@ static const uint8_t cdc_hid_template_config_desc[CDC_HID_TEMPLATE_CONFIG_DESC_S 0x03, // bNumInterfaces: 3 interfaces 0x01, // bConfigurationValue: Configuration value 0x00, // iConfiguration: Index of string descriptor describing the configuration - 0x80, // bmAttributes: bus powered; 0xc0 for self powered + CONFIG_DESC_ATTRIBUTES, // bmAttributes 0xfa, // bMaxPower: in units of 2mA //========================================================================== @@ -455,7 +462,7 @@ static const uint8_t cdc_template_config_desc[CDC_TEMPLATE_CONFIG_DESC_SIZE] = { 0x02, // bNumInterfaces: 2 interface 0x01, // bConfigurationValue: Configuration value 0x00, // iConfiguration: Index of string descriptor describing the configuration - 0x80, // bmAttributes: bus powered; 0xc0 for self powered + CONFIG_DESC_ATTRIBUTES, // bmAttributes 0xfa, // bMaxPower: in units of 2mA //-------------------------------------------------------------------------- From 4caf5b23588a82b2a952b0206fe87cd18a9a9050 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 27 Jan 2019 14:02:10 +1100 Subject: [PATCH 0014/1788] stm32/usbdev: Add USB config option for max power drawn by the board. The new compile-time option is MICROPY_HW_USB_MAX_POWER_MA. Set this in the board configuration file to the maximum current in mA that the board will draw over USB. The default is 500mA. --- ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 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 688cdc28ba..fee1b23ea1 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -103,6 +103,13 @@ #define CONFIG_DESC_ATTRIBUTES (0x80) // bus powered #endif +// Value used in the configuration descriptor for the bMaxPower entry +#if defined(MICROPY_HW_USB_MAX_POWER_MA) +#define CONFIG_DESC_MAXPOWER (MICROPY_HW_USB_MAX_POWER_MA / 2) // in units of 2mA +#else +#define CONFIG_DESC_MAXPOWER (0xfa) // 500mA in units of 2mA +#endif + #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 = { @@ -131,7 +138,7 @@ static const uint8_t msc_template_config_desc[MSC_TEMPLATE_CONFIG_DESC_SIZE] = { 0x01, // bConfigurationValue: Configuration value 0x00, // iConfiguration: Index of string descriptor describing the configuration CONFIG_DESC_ATTRIBUTES, // bmAttributes - 0xfa, // bMaxPower: in units of 2mA + CONFIG_DESC_MAXPOWER, // bMaxPower //========================================================================== // MSC only has 1 interface so doesn't need an IAD @@ -179,7 +186,7 @@ static const uint8_t cdc_msc_template_config_desc[CDC_MSC_TEMPLATE_CONFIG_DESC_S 0x01, // bConfigurationValue: Configuration value 0x00, // iConfiguration: Index of string descriptor describing the configuration CONFIG_DESC_ATTRIBUTES, // bmAttributes - 0xfa, // bMaxPower: in units of 2mA + CONFIG_DESC_MAXPOWER, // bMaxPower //========================================================================== // MSC only has 1 interface so doesn't need an IAD @@ -316,7 +323,7 @@ static const uint8_t cdc_hid_template_config_desc[CDC_HID_TEMPLATE_CONFIG_DESC_S 0x01, // bConfigurationValue: Configuration value 0x00, // iConfiguration: Index of string descriptor describing the configuration CONFIG_DESC_ATTRIBUTES, // bmAttributes - 0xfa, // bMaxPower: in units of 2mA + CONFIG_DESC_MAXPOWER, // bMaxPower //========================================================================== // HID only has 1 interface so doesn't need an IAD @@ -463,7 +470,7 @@ static const uint8_t cdc_template_config_desc[CDC_TEMPLATE_CONFIG_DESC_SIZE] = { 0x01, // bConfigurationValue: Configuration value 0x00, // iConfiguration: Index of string descriptor describing the configuration CONFIG_DESC_ATTRIBUTES, // bmAttributes - 0xfa, // bMaxPower: in units of 2mA + CONFIG_DESC_MAXPOWER, // bMaxPower //-------------------------------------------------------------------------- // Interface Descriptor From deb67569ff66b2111cd18679a3bbdb35655cd25d Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 2 Jan 2019 10:46:51 +1100 Subject: [PATCH 0015/1788] py/compile: Swap order of pop_block/pop_except in "except as" handler. To make the try-finally block self contained. --- py/compile.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/py/compile.c b/py/compile.c index 6db108a599..a5bdfa2af6 100644 --- a/py/compile.c +++ b/py/compile.c @@ -1582,25 +1582,32 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_ compile_store_id(comp, qstr_exception_local); } + // If the exception is bound to a variable then the of the + // exception handler is wrapped in a try-finally so that the name can + // be deleted (per Python semantics) even if the has an exception. + // In such a case the generated code for the exception handler is: + // try: + // + // finally: + // = None + // del uint l3 = 0; if (qstr_exception_local != 0) { l3 = comp_next_label(comp); compile_increase_except_level(comp, l3, MP_EMIT_SETUP_BLOCK_FINALLY); } - compile_node(comp, pns_except->nodes[1]); + compile_node(comp, pns_except->nodes[1]); // the if (qstr_exception_local != 0) { EMIT(pop_block); - } - EMIT(pop_except); - if (qstr_exception_local != 0) { EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); EMIT_ARG(label_assign, l3); EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); compile_store_id(comp, qstr_exception_local); compile_delete_id(comp, qstr_exception_local); - compile_decrease_except_level(comp); } + + EMIT(pop_except); EMIT_ARG(jump, l2); EMIT_ARG(label_assign, end_finally_label); EMIT_ARG(adjust_stack_size, 1); // stack adjust for the exception instance From e7ab4752766100a022d8fab4b947675a440b11b6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 27 Jan 2019 16:15:47 +1100 Subject: [PATCH 0016/1788] esp32: Don't put py/scheduler.o in iRAM, it's no longer needed. ISR's no longer need to be in iRAM, and the ESP IDF provides an option to specify that they are in iRAM if an application needs lower latency when handling them. But we don't use this feature for user interrupts: both timer and gpio ISR routines are registered without the ESP_INTR_FLAG_IRAM option, and so the scheduling code no longer needs to be in iRAM. --- ports/esp32/esp32.custom_common.ld | 1 - ports/esp32/machine_pin.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/ports/esp32/esp32.custom_common.ld b/ports/esp32/esp32.custom_common.ld index 9762c0d29d..d28d5e26c6 100644 --- a/ports/esp32/esp32.custom_common.ld +++ b/ports/esp32/esp32.custom_common.ld @@ -108,7 +108,6 @@ SECTIONS *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(.); _iram_end = ABSOLUTE(.); } > iram0_0_seg diff --git a/ports/esp32/machine_pin.c b/ports/esp32/machine_pin.c index 1f4226474b..a899fa62ad 100644 --- a/ports/esp32/machine_pin.c +++ b/ports/esp32/machine_pin.c @@ -112,7 +112,7 @@ void machine_pins_deinit(void) { } } -STATIC void IRAM_ATTR machine_pin_isr_handler(void *arg) { +STATIC void 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)); From f59904f7992c15a07d9be075b7fa31d7bc83c08d Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 27 Jan 2019 16:23:41 +1100 Subject: [PATCH 0017/1788] esp32/Makefile: Put all IDF compenents in .a libs to use IDF ld script. When the ESP IDF builds a project it puts all separate components into separate .a library archives. And then the esp32.common.ld linker script references these .a libraries by explicit name to put certain object files in iRAM. This patch does a similar thing for the custom build system used here, putting all IDF .o's into their respective .a. So a custom linker script is no longer needed. --- ports/esp32/Makefile | 76 +++++++- ports/esp32/esp32.custom_common.ld | 273 ----------------------------- 2 files changed, 73 insertions(+), 276 deletions(-) delete mode 100644 ports/esp32/esp32.custom_common.ld diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 64ca664ee4..9e465a9351 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -117,7 +117,7 @@ LDFLAGS += -u call_user_start_cpu0 -u uxTopUsedPriority -u ld_include_panic_high 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.common.ld LDFLAGS += -T esp32.rom.ld LDFLAGS += -T esp32.peripherals.ld @@ -634,6 +634,75 @@ 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)) + +LIB_ESPIDF = +LIB_ESPIDF += driver +LIB_ESPIDF += esp32 +LIB_ESPIDF += heap +LIB_ESPIDF += soc +LIB_ESPIDF += cxx +LIB_ESPIDF += ethernet +LIB_ESPIDF += expat +LIB_ESPIDF += pthread +LIB_ESPIDF += freertos +LIB_ESPIDF += vfs +LIB_ESPIDF += json +LIB_ESPIDF += log +LIB_ESPIDF += xtensa-debug-module +LIB_ESPIDF += tcpip_adapter +LIB_ESPIDF += app_trace +LIB_ESPIDF += app_update +LIB_ESPIDF += newlib +LIB_ESPIDF += nghttp +LIB_ESPIDF += nvs_flash +LIB_ESPIDF += smartconfig_ack +LIB_ESPIDF += spi_flash +LIB_ESPIDF += ulp +LIB_ESPIDF += lwip +LIB_ESPIDF += mbedtls +LIB_ESPIDF += wpa_supplicant + +BUILD_ESPIDF_LIB = $(BUILD)/esp-idf + +OBJ_ESPIDF_DIRS = $(sort $(dir $(OBJ_ESPIDF))) $(BUILD_ESPIDF_LIB) $(addprefix $(BUILD_ESPIDF_LIB)/,$(LIB_ESPIDF)) +$(OBJ_ESPIDF): | $(OBJ_ESPIDF_DIRS) +$(OBJ_ESPIDF_DIRS): + $(MKDIR) -p $@ + +define gen_espidf_lib_rule +$(BUILD_ESPIDF_LIB)/$(1)/lib$(1).a: $(addprefix $$(BUILD)/,$(2)) + $(ECHO) "AR $$@" + $(Q)$(AR) cru $$@ $$^ +endef + +$(eval $(call gen_espidf_lib_rule,driver,$(ESPIDF_DRIVER_O))) +$(eval $(call gen_espidf_lib_rule,esp32,$(ESPIDF_ESP32_O))) +$(eval $(call gen_espidf_lib_rule,heap,$(ESPIDF_HEAP_O))) +$(eval $(call gen_espidf_lib_rule,soc,$(ESPIDF_SOC_O))) +$(eval $(call gen_espidf_lib_rule,cxx,$(ESPIDF_CXX_O))) +$(eval $(call gen_espidf_lib_rule,ethernet,$(ESPIDF_ETHERNET_O))) +$(eval $(call gen_espidf_lib_rule,expat,$(ESPIDF_EXPAT_O))) +$(eval $(call gen_espidf_lib_rule,pthread,$(ESPIDF_PTHREAD_O))) +$(eval $(call gen_espidf_lib_rule,freertos,$(ESPIDF_FREERTOS_O))) +$(eval $(call gen_espidf_lib_rule,vfs,$(ESPIDF_VFS_O))) +$(eval $(call gen_espidf_lib_rule,json,$(ESPIDF_JSON_O))) +$(eval $(call gen_espidf_lib_rule,log,$(ESPIDF_LOG_O))) +$(eval $(call gen_espidf_lib_rule,xtensa-debug-module,$(ESPIDF_XTENSA_DEBUG_MODULE_O))) +$(eval $(call gen_espidf_lib_rule,tcpip_adapter,$(ESPIDF_TCPIP_ADAPTER_O))) +$(eval $(call gen_espidf_lib_rule,app_trace,$(ESPIDF_APP_TRACE_O))) +$(eval $(call gen_espidf_lib_rule,app_update,$(ESPIDF_APP_UPDATE_O))) +$(eval $(call gen_espidf_lib_rule,newlib,$(ESPIDF_NEWLIB_O))) +$(eval $(call gen_espidf_lib_rule,nghttp,$(ESPIDF_NGHTTP_O))) +$(eval $(call gen_espidf_lib_rule,nvs_flash,$(ESPIDF_NVS_FLASH_O))) +$(eval $(call gen_espidf_lib_rule,smartconfig_ack,$(ESPIDF_SMARTCONFIG_ACK_O))) +$(eval $(call gen_espidf_lib_rule,spi_flash,$(ESPIDF_SPI_FLASH_O))) +$(eval $(call gen_espidf_lib_rule,ulp,$(ESPIDF_ULP_O))) +$(eval $(call gen_espidf_lib_rule,lwip,$(ESPIDF_LWIP_O))) +$(eval $(call gen_espidf_lib_rule,mbedtls,$(ESPIDF_MBEDTLS_O))) +$(eval $(call gen_espidf_lib_rule,wpa_supplicant,$(ESPIDF_WPA_SUPPLICANT_O))) + +LIB = $(foreach lib,$(LIB_ESPIDF),$(BUILD_ESPIDF_LIB)/$(lib)/lib$(lib).a) + ################################################################################ # Main targets @@ -659,7 +728,7 @@ erase: ################################################################################ # Declarations to build the application -OBJ = $(OBJ_MP) $(OBJ_ESPIDF) +OBJ = $(OBJ_MP) APP_LD_ARGS = APP_LD_ARGS += $(LDFLAGS_MOD) @@ -670,6 +739,7 @@ APP_LD_ARGS += $(LIBC_LIBM) APP_LD_ARGS += $(ESPCOMP)/esp32/libhal.a 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 += $(LIB) APP_LD_ARGS += --end-group $(BUILD)/esp32_out.ld: sdkconfig.h @@ -679,7 +749,7 @@ $(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 +$(BUILD)/application.elf: $(OBJ) $(LIB) $(BUILD)/esp32_out.ld $(ECHO) "LINK $@" $(Q)$(LD) $(LDFLAGS) -o $@ $(APP_LD_ARGS) $(Q)$(SIZE) $@ diff --git a/ports/esp32/esp32.custom_common.ld b/ports/esp32/esp32.custom_common.ld deleted file mode 100644 index d28d5e26c6..0000000000 --- a/ports/esp32/esp32.custom_common.ld +++ /dev/null @@ -1,273 +0,0 @@ -/* 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 - - /* 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 : - { - _iram_start = ABSOLUTE(.); - /* 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(.); - } > 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.*) - *librtc.a:(.literal .text .literal.* .text.*) - *soc/esp32/rtc_*.o(.literal .text .literal.* .text.*) - *soc/esp32/cpu_util.o(.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 - _iram_text_end = ABSOLUTE(.); - _iram_end = ABSOLUTE(.); - } > iram0_0_seg - - .dram0.data : - { - _data_start = ABSOLUTE(.); - _bt_data_start = ABSOLUTE(.); - *libbt.a:(.data .data.*) - . = ALIGN (4); - _bt_data_end = ABSOLUTE(.); - _btdm_data_start = ABSOLUTE(.); - *libbtdm_app.a:(.data .data.*) - . = ALIGN (4); - _btdm_data_end = 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.*) - *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 - - /*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) : - { - . = ALIGN (8); - _bss_start = ABSOLUTE(.); - _bt_bss_start = ABSOLUTE(.); - *libbt.a:(.bss .bss.* COMMON) - . = ALIGN (4); - _bt_bss_end = ABSOLUTE(.); - _btdm_bss_start = ABSOLUTE(.); - *libbtdm_app.a:(.bss .bss.* COMMON) - . = ALIGN (4); - _btdm_bss_end = 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(.); - /* The heap starts right after end of this section */ - _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) - /* Addresses of memory regions reserved via - SOC_RESERVE_MEMORY_REGION() */ - soc_reserved_memory_region_start = ABSOLUTE(.); - KEEP (*(.reserved_memory_address)) - soc_reserved_memory_region_end = ABSOLUTE(.); - _rodata_end = ABSOLUTE(.); - /* Literals are also RO data. */ - _lit4_start = ABSOLUTE(.); - *(*.lit4) - *(.lit4.*) - *(.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 : - { - _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 -} From 3d49b157b89a59774fc4958dcaacd2c96ba6eaa4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 28 Jan 2019 12:36:47 +1100 Subject: [PATCH 0018/1788] esp32: Update to latest ESP IDF using sdkconfig and new ldgen procedure. Configuration for the build is now specified using sdkconfig rather than sdkconfig.h, which allows for much easier configuration with defaults from the ESP IDF automatically applied. sdkconfig.h is generated using the new ESP IDF kconfig_new tool written in Python. Custom configuration for a particular ESP32 board can be specified via the make variable SDKCONFIG. The esp32.common.ld file is also now generated using the standard ESP IDF ldgen.py tool. --- ports/esp32/Makefile | 244 +++++++++++++++++++--------- ports/esp32/README.md | 13 +- ports/esp32/boards/sdkconfig | 26 +++ ports/esp32/boards/sdkconfig.spiram | 27 +++ ports/esp32/network_ppp.c | 2 +- ports/esp32/sdkconfig.h | 193 ---------------------- 6 files changed, 233 insertions(+), 272 deletions(-) create mode 100644 ports/esp32/boards/sdkconfig create mode 100644 ports/esp32/boards/sdkconfig.spiram delete mode 100644 ports/esp32/sdkconfig.h diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 9e465a9351..b3b084bf6f 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -20,8 +20,14 @@ FLASH_MODE ?= dio FLASH_FREQ ?= 40m FLASH_SIZE ?= 4MB CROSS_COMPILE ?= xtensa-esp32-elf- +OBJDUMP = $(CROSS_COMPILE)objdump -ESPIDF_SUPHASH := 30545f4cccec7460634b656d278782dd7151098e +# SDKCONFIG should be overridden to get a different configuration +SDKCONFIG ?= boards/sdkconfig +SDKCONFIG_H = $(BUILD)/sdkconfig.h + +# the git hash of the currently supported ESP IDF version +ESPIDF_SUPHASH := 5c88c5996dbde6208e3bec05abc21ff6cd822d26 # paths to ESP IDF and its components ifeq ($(ESPIDF),) @@ -36,6 +42,8 @@ endif endif ESPCOMP = $(ESPIDF)/components ESPTOOL ?= $(ESPCOMP)/esptool_py/esptool/esptool.py +ESPCOMP_KCONFIGS = $(shell find $(ESPCOMP) -name Kconfig) +ESPCOMP_KCONFIGS_PROJBUILD = $(shell find $(ESPCOMP) -name Kconfig.projbuild) # verify the ESP IDF version ESPIDF_CURHASH := $(shell git -C $(ESPIDF) show -s --pretty=format:'%H') @@ -51,6 +59,12 @@ endif # pretty format of ESP IDF version, used internally by the IDF IDF_VER := $(shell git -C $(ESPIDF) describe) +# include sdkconfig to get needed configuration values +include $(SDKCONFIG) + +################################################################################ +# Compiler and linker flags + INC += -I. INC += -I$(TOP) INC += -I$(TOP)/lib/mp-readline @@ -78,10 +92,12 @@ INC_ESPCOMP += -I$(ESPCOMP)/newlib/platform_include INC_ESPCOMP += -I$(ESPCOMP)/newlib/include INC_ESPCOMP += -I$(ESPCOMP)/nvs_flash/include INC_ESPCOMP += -I$(ESPCOMP)/freertos/include +INC_ESPCOMP += -I$(ESPCOMP)/esp_ringbuf/include +INC_ESPCOMP += -I$(ESPCOMP)/esp_event/include INC_ESPCOMP += -I$(ESPCOMP)/tcpip_adapter/include -INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/lwip -INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/lwip/port -INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/lwip/posix +INC_ESPCOMP += -I$(ESPCOMP)/lwip/lwip/src/include +INC_ESPCOMP += -I$(ESPCOMP)/lwip/port/esp32/include +INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/apps INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/mbedtls/include INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/port/include INC_ESPCOMP += -I$(ESPCOMP)/spi_flash/include @@ -117,7 +133,7 @@ LDFLAGS += -u call_user_start_cpu0 -u uxTopUsedPriority -u ld_include_panic_high 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.common.ld +LDFLAGS += -T $(BUILD)/esp32.common.ld LDFLAGS += -T esp32.rom.ld LDFLAGS += -T esp32.peripherals.ld @@ -134,9 +150,9 @@ 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 +# Enable SPIRAM support if CONFIG_SPIRAM_SUPPORT=y in sdkconfig +ifeq ($(CONFIG_SPIRAM_SUPPORT),y) +CFLAGS_COMMON += -mfix-esp32-psram-cache-issue LIBC_LIBM = $(ESPCOMP)/newlib/lib/libc-psram-workaround.a $(ESPCOMP)/newlib/lib/libm-psram-workaround.a else LDFLAGS += -T esp32.rom.spiram_incompatible_fns.ld @@ -213,6 +229,23 @@ 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 += +################################################################################ +# Generate sdkconfig.h from sdkconfig + +$(SDKCONFIG_H): $(SDKCONFIG) + $(ECHO) "GEN $@" + $(Q)$(PYTHON) $(ESPIDF)/tools/kconfig_new/confgen.py \ + --output header $@ \ + --config $< \ + --kconfig $(ESPIDF)/Kconfig \ + --env "IDF_TARGET=esp32" \ + --env "IDF_CMAKE=n" \ + --env "COMPONENT_KCONFIGS=$(ESPCOMP_KCONFIGS)" \ + --env "COMPONENT_KCONFIGS_PROJBUILD=$(ESPCOMP_KCONFIGS_PROJBUILD)" + $(Q)touch $@ + +$(HEADER_BUILD)/qstrdefs.generated.h: $(SDKCONFIG_H) + ################################################################################ # List of object files from the ESP32 IDF components @@ -230,7 +263,11 @@ ESPIDF_DRIVER_O = $(addprefix $(ESPCOMP)/driver/,\ $(BUILD)/$(ESPCOMP)/esp32/dport_access.o: CFLAGS += -Wno-array-bounds ESPIDF_ESP32_O = $(addprefix $(ESPCOMP)/esp32/,\ brownout.o \ + cache_sram_mmu.o \ + dbg_stubs.o \ + esp_err_to_name.o \ panic.o \ + reset_reason.o \ esp_timer.o \ esp_timer_esp32.o \ ets_timer_legacy.o \ @@ -253,6 +290,7 @@ ESPIDF_ESP32_O = $(addprefix $(ESPCOMP)/esp32/,\ system_api.o \ hw_random.o \ phy_init.o \ + pm_esp32.o \ intr_alloc.o \ dport_access.o \ wifi_init.o \ @@ -262,6 +300,10 @@ ESPIDF_ESP32_O = $(addprefix $(ESPCOMP)/esp32/,\ spiram_psram.o \ ) +ESPIDF_ESP_RINGBUF_O = $(addprefix $(ESPCOMP)/esp_ringbuf/,\ + ringbuf.o \ + ) + ESPIDF_HEAP_O = $(addprefix $(ESPCOMP)/heap/,\ heap_caps.o \ heap_caps_init.o \ @@ -277,6 +319,7 @@ ESPIDF_SOC_O = $(addprefix $(ESPCOMP)/soc/,\ esp32/rtc_pm.o \ esp32/rtc_sleep.o \ esp32/rtc_time.o \ + esp32/rtc_wdt.o \ esp32/soc_memory_layout.o \ esp32/spi_periph.o \ src/memory_layout_utils.o \ @@ -312,12 +355,12 @@ ESPIDF_PTHREAD_O = $(addprefix $(ESPCOMP)/pthread/,\ # -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. +CFLAGS_ASM = -I$(BUILD) -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 -D_ESP_FREERTOS_INTERNAL +$(BUILD)/$(ESPCOMP)/freertos/%.o: CFLAGS = $(CFLAGS_BASE) -I. -I$(BUILD) $(INC_ESPCOMP) -I$(ESPCOMP)/freertos/include/freertos -D_ESP_FREERTOS_INTERNAL ESPIDF_FREERTOS_O = $(addprefix $(ESPCOMP)/freertos/,\ croutine.o \ event_groups.o \ @@ -326,7 +369,6 @@ ESPIDF_FREERTOS_O = $(addprefix $(ESPCOMP)/freertos/,\ portasm.o \ port.o \ queue.o \ - ringbuf.o \ tasks.o \ timers.o \ xtensa_context.o \ @@ -366,6 +408,7 @@ ESPIDF_APP_TRACE_O = $(addprefix $(ESPCOMP)/app_trace/,\ ) ESPIDF_APP_UPDATE_O = $(addprefix $(ESPCOMP)/app_update/,\ + esp_app_desc.o \ esp_ota_ops.o \ ) @@ -404,6 +447,7 @@ ESPIDF_NGHTTP_O = $(addprefix $(ESPCOMP)/nghttp/,\ ) ESPIDF_NVS_FLASH_O = $(addprefix $(ESPCOMP)/nvs_flash/,\ + src/nvs_ops.o \ src/nvs_types.o \ src/nvs_page.o \ src/nvs_item_hash_list.o \ @@ -433,69 +477,72 @@ ESPIDF_ULP_O = $(addprefix $(ESPCOMP)/ulp/,\ $(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 \ - netif/ppp/ppp.o \ - netif/ppp/magic.o \ - netif/ppp/lcp.o \ - netif/ppp/ipcp.o \ - netif/ppp/auth.o \ - netif/ppp/fsm.o \ - netif/ppp/ipv6cp.o \ - netif/ppp/utils.o \ - netif/ppp/vj.o \ - netif/ppp/pppos.o \ - port/freertos/sys_arch.o \ - port/netif/wlanif.o \ - port/netif/ethernetif.o \ - port/vfs_lwip.o \ + apps/dhcpserver/dhcpserver.o \ + lwip/src/api/netbuf.o \ + lwip/src/api/api_lib.o \ + lwip/src/api/netifapi.o \ + lwip/src/api/tcpip.o \ + lwip/src/api/netdb.o \ + lwip/src/api/err.o \ + lwip/src/api/api_msg.o \ + lwip/src/api/sockets.o \ + lwip/src/apps/sntp/sntp.o \ + lwip/src/core/ipv4/dhcp.o \ + lwip/src/core/ipv4/etharp.o \ + lwip/src/core/ipv4/ip4_addr.o \ + lwip/src/core/ipv4/igmp.o \ + lwip/src/core/ipv4/ip4.o \ + lwip/src/core/ipv4/autoip.o \ + lwip/src/core/ipv4/icmp.o \ + lwip/src/core/ipv6/ip6_frag.o \ + lwip/src/core/ipv6/dhcp6.o \ + lwip/src/core/ipv6/inet6.o \ + lwip/src/core/ipv6/ip6_addr.o \ + lwip/src/core/ipv6/ip6.o \ + lwip/src/core/ipv6/nd6.o \ + lwip/src/core/ipv6/mld6.o \ + lwip/src/core/ipv6/ethip6.o \ + lwip/src/core/ipv6/icmp6.o \ + lwip/src/core/mem.o \ + lwip/src/core/init.o \ + lwip/src/core/memp.o \ + lwip/src/core/sys.o \ + lwip/src/core/tcp_in.o \ + lwip/src/core/timeouts.o \ + lwip/src/core/dns.o \ + lwip/src/core/ip.o \ + lwip/src/core/pbuf.o \ + lwip/src/core/raw.o \ + lwip/src/core/tcp.o \ + lwip/src/core/def.o \ + lwip/src/core/netif.o \ + lwip/src/core/stats.o \ + lwip/src/core/inet_chksum.o \ + lwip/src/core/udp.o \ + lwip/src/core/tcp_out.o \ + lwip/src/netif/slipif.o \ + lwip/src/netif/ethernet.o \ + lwip/src/netif/lowpan6.o \ + lwip/src/netif/ethernetif.o \ + lwip/src/netif/ppp/auth.o \ + lwip/src/netif/ppp/chap-md5.o \ + lwip/src/netif/ppp/chap-new.o \ + lwip/src/netif/ppp/fsm.o \ + lwip/src/netif/ppp/ipcp.o \ + lwip/src/netif/ppp/ipv6cp.o \ + lwip/src/netif/ppp/lcp.o \ + lwip/src/netif/ppp/magic.o \ + lwip/src/netif/ppp/polarssl/md5.o \ + lwip/src/netif/ppp/ppp.o \ + lwip/src/netif/ppp/pppapi.o \ + lwip/src/netif/ppp/pppos.o \ + lwip/src/netif/ppp/upap.o \ + lwip/src/netif/ppp/utils.o \ + lwip/src/netif/ppp/vj.o \ + port/esp32/freertos/sys_arch.o \ + port/esp32/netif/ethernetif.o \ + port/esp32/netif/wlanif.o \ + port/esp32/vfs_lwip.o \ ) ESPIDF_MBEDTLS_O = $(addprefix $(ESPCOMP)/mbedtls/,\ @@ -572,6 +619,7 @@ ESPIDF_MBEDTLS_O = $(addprefix $(ESPCOMP)/mbedtls/,\ mbedtls/library/pk_wrap.o \ port/esp_bignum.o \ port/esp_hardware.o \ + port/esp_mem.o \ port/esp_sha1.o \ port/esp_sha256.o \ port/esp_sha512.o \ @@ -611,6 +659,7 @@ 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_ESP_RINGBUF_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_HEAP_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_SOC_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_CXX_O)) @@ -635,9 +684,12 @@ OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_SPI_FLASH_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_ULP_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_WPA_SUPPLICANT_O)) +$(OBJ_ESPIDF): $(SDKCONFIG_H) + LIB_ESPIDF = LIB_ESPIDF += driver LIB_ESPIDF += esp32 +LIB_ESPIDF += esp_ringbuf LIB_ESPIDF += heap LIB_ESPIDF += soc LIB_ESPIDF += cxx @@ -677,6 +729,7 @@ endef $(eval $(call gen_espidf_lib_rule,driver,$(ESPIDF_DRIVER_O))) $(eval $(call gen_espidf_lib_rule,esp32,$(ESPIDF_ESP32_O))) +$(eval $(call gen_espidf_lib_rule,esp_ringbuf,$(ESPIDF_ESP_RINGBUF_O))) $(eval $(call gen_espidf_lib_rule,heap,$(ESPIDF_HEAP_O))) $(eval $(call gen_espidf_lib_rule,soc,$(ESPIDF_SOC_O))) $(eval $(call gen_espidf_lib_rule,cxx,$(ESPIDF_CXX_O))) @@ -703,6 +756,38 @@ $(eval $(call gen_espidf_lib_rule,wpa_supplicant,$(ESPIDF_WPA_SUPPLICANT_O))) LIB = $(foreach lib,$(LIB_ESPIDF),$(BUILD_ESPIDF_LIB)/$(lib)/lib$(lib).a) +################################################################################ +# ESP IDF ldgen + +LDGEN_FRAGMENTS = $(shell find $(ESPCOMP) -name "*.lf") +LDGEN_SECTIONS_INFO = $(foreach lib,$(LIB_ESPIDF),$(BUILD_ESPIDF_LIB)/$(lib)/lib$(lib).a.sections_info) +LDGEN_SECTION_INFOS = $(BUILD_ESPIDF_LIB)/ldgen.section_infos + +define gen_sections_info_rule +$(1).sections_info: $(1) + $(ECHO) "GEN $(1).sections_info" + $(Q)$(OBJDUMP) -h $(1) > $(1).sections_info +endef + +$(eval $(foreach lib,$(LIB_ESPIDF),$(eval $(call gen_sections_info_rule,$(BUILD_ESPIDF_LIB)/$(lib)/lib$(lib).a)))) + +$(LDGEN_SECTION_INFOS): $(LDGEN_SECTIONS_INFO) $(ESPIDF)/make/ldgen.mk + $(Q)printf "$(foreach info,$(LDGEN_SECTIONS_INFO),$(info)\n)" > $@ + +$(BUILD)/esp32.common.ld: $(ESPCOMP)/esp32/ld/esp32.common.ld.in $(LDGEN_FRAGMENTS) $(SDKCONFIG) $(LDGEN_SECTION_INFOS) + $(ECHO) "GEN $@" + $(Q)$(PYTHON) $(ESPIDF)/tools/ldgen/ldgen.py \ + --input $< \ + --output $@ \ + --config $(SDKCONFIG) \ + --kconfig $(ESPIDF)/Kconfig \ + --fragments $(LDGEN_FRAGMENTS) \ + --sections $(LDGEN_SECTION_INFOS) \ + --env "IDF_TARGET=esp32" \ + --env "IDF_CMAKE=n" \ + --env "COMPONENT_KCONFIGS=$(ESPCOMP_KCONFIGS)" \ + --env "COMPONENT_KCONFIGS_PROJBUILD=$(ESPCOMP_KCONFIGS_PROJBUILD)" + ################################################################################ # Main targets @@ -742,14 +827,14 @@ APP_LD_ARGS += $(OBJ) APP_LD_ARGS += $(LIB) 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)/esp32_out.ld: $(SDKCONFIG_H) + $(Q)$(CC) -I$(BUILD) -C -P -x c -E $(ESPCOMP)/esp32/ld/esp32.ld -o $@ $(BUILD)/application.bin: $(BUILD)/application.elf $(ECHO) "Create $@" $(Q)$(ESPTOOL) --chip esp32 elf2image --flash_mode $(FLASH_MODE) --flash_freq $(FLASH_FREQ) --flash_size $(FLASH_SIZE) $< -$(BUILD)/application.elf: $(OBJ) $(LIB) $(BUILD)/esp32_out.ld +$(BUILD)/application.elf: $(OBJ) $(LIB) $(BUILD)/esp32_out.ld $(BUILD)/esp32.common.ld $(ECHO) "LINK $@" $(Q)$(LD) $(LDFLAGS) -o $@ $(APP_LD_ARGS) $(Q)$(SIZE) $@ @@ -830,7 +915,10 @@ $(BOOTLOADER_LIB_DIR)/libmicro-ecc.a: $(BOOTLOADER_LIB_MICRO_ECC_OBJ) # remaining object files BOOTLOADER_OBJ = $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/,\ soc/esp32/rtc_clk.o \ + soc/esp32/rtc_clk_init.o \ + soc/esp32/rtc_init.o \ soc/esp32/rtc_time.o \ + soc/esp32/rtc_wdt.o \ soc/esp32/cpu_util.o \ bootloader/subproject/main/bootloader_start.o \ ) @@ -843,6 +931,8 @@ BOOTLOADER_OBJ_ALL = \ $(BOOTLOADER_LIB_MICRO_ECC_OBJ) \ $(BOOTLOADER_OBJ) +$(BOOTLOADER_OBJ_ALL): $(SDKCONFIG_H) + BOOTLOADER_LIBS = BOOTLOADER_LIBS += -Wl,--start-group BOOTLOADER_LIBS += $(BOOTLOADER_OBJ) diff --git a/ports/esp32/README.md b/ports/esp32/README.md index 85df001e3f..0e6531db82 100644 --- a/ports/esp32/README.md +++ b/ports/esp32/README.md @@ -78,7 +78,7 @@ ESPIDF = #FLASH_MODE = qio #FLASH_SIZE = 4MB #CROSS_COMPILE = xtensa-esp32-elf- -#CONFIG_SPIRAM_SUPPORT = 1 +#SDKCONFIG = boards/sdkconfig.spiram include Makefile ``` @@ -92,6 +92,17 @@ are `PORT` for the serial port of your esp32 module, and `FLASH_MODE` (which may need to be `dio` for some modules) and `FLASH_SIZE`. See the Makefile for further information. +The default ESP IDF configuration settings are provided in the file +`boards/sdkconfig`, and this file is specified in the build by the make +variable `SDKCONFIG`. To use a custom configuration either set `SDKCONFIG` +in your custom `makefile` (or `GNUmakefile`) or set this variable on the +command line: +```bash +$ make SDKCONFIG=sdkconfig.myboard +``` +The file `boards/sdkconfig.spiram` is provided for ESP32 modules that have +external SPIRAM. + Building the firmware --------------------- diff --git a/ports/esp32/boards/sdkconfig b/ports/esp32/boards/sdkconfig new file mode 100644 index 0000000000..f68102bee0 --- /dev/null +++ b/ports/esp32/boards/sdkconfig @@ -0,0 +1,26 @@ +# MicroPython on ESP32, ESP IDF configuration +# The following options override the defaults + +CONFIG_IDF_TARGET="esp32" + +# Application manager +CONFIG_APP_EXCLUDE_PROJECT_VER_VAR=y +CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR=y + +# Bootloader config +CONFIG_LOG_BOOTLOADER_LEVEL_WARN=y + +# ESP32-specific +CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y +CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=n + +# FreeRTOS +CONFIG_FREERTOS_UNICORE=y +CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=2 +CONFIG_SUPPORT_STATIC_ALLOCATION=y +CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK=y + +# UDP +CONFIG_PPP_SUPPORT=y +CONFIG_PPP_PAP_SUPPORT=y +CONFIG_PPP_CHAP_SUPPORT=y diff --git a/ports/esp32/boards/sdkconfig.spiram b/ports/esp32/boards/sdkconfig.spiram new file mode 100644 index 0000000000..63908f4b05 --- /dev/null +++ b/ports/esp32/boards/sdkconfig.spiram @@ -0,0 +1,27 @@ +# MicroPython on ESP32, ESP IDF configuration with SPIRAM support +# The following options override the defaults + +CONFIG_IDF_TARGET="esp32" + +# Application manager +CONFIG_APP_EXCLUDE_PROJECT_VER_VAR=y +CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR=y + +# Bootloader config +CONFIG_LOG_BOOTLOADER_LEVEL_WARN=y + +# ESP32-specific +CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y +CONFIG_SPIRAM_SUPPORT=y +CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=n + +# FreeRTOS +CONFIG_FREERTOS_UNICORE=y +CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=2 +CONFIG_SUPPORT_STATIC_ALLOCATION=y +CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK=y + +# UDP +CONFIG_PPP_SUPPORT=y +CONFIG_PPP_PAP_SUPPORT=y +CONFIG_PPP_CHAP_SUPPORT=y diff --git a/ports/esp32/network_ppp.c b/ports/esp32/network_ppp.c index 27dd5e0437..da821478b8 100644 --- a/ports/esp32/network_ppp.c +++ b/ports/esp32/network_ppp.c @@ -40,7 +40,7 @@ #include "lwip/sys.h" #include "lwip/netdb.h" #include "lwip/dns.h" -#include "lwip/pppapi.h" +#include "netif/ppp/pppapi.h" typedef struct _ppp_if_obj_t { mp_obj_base_t base; diff --git a/ports/esp32/sdkconfig.h b/ports/esp32/sdkconfig.h deleted file mode 100644 index ba2930bca8..0000000000 --- a/ports/esp32/sdkconfig.h +++ /dev/null @@ -1,193 +0,0 @@ -/* 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 2040 -#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_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 -#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 -#define CONFIG_ESP32_DEBUG_OCDAWARE 1 -#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 -#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 - -#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 0 -#endif - -#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_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 - -#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_OFFSET 0x8000 -#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_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 -#define CONFIG_PPP_SUPPORT 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" From 9ac9aa989c89a1d6310160dd408820d1164d4dd7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 28 Jan 2019 16:16:03 +1100 Subject: [PATCH 0019/1788] esp32/machine_timer: Deinit all active timers on soft reset. Otherwise they will keep triggering the callback and access invalid data on the heap. --- ports/esp32/machine_timer.c | 23 +++++++++++++++++++++++ ports/esp32/main.c | 2 ++ ports/esp32/modmachine.h | 1 + ports/esp32/mpconfigport.h | 3 +++ 4 files changed, 29 insertions(+) diff --git a/ports/esp32/machine_timer.c b/ports/esp32/machine_timer.c index 7dca9e0143..081a46b9c1 100644 --- a/ports/esp32/machine_timer.c +++ b/ports/esp32/machine_timer.c @@ -56,10 +56,14 @@ typedef struct _machine_timer_obj_t { mp_obj_t callback; intr_handle_t handle; + + struct _machine_timer_obj_t *next; } machine_timer_obj_t; const mp_obj_type_t machine_timer_type; +STATIC void machine_timer_disable(machine_timer_obj_t *self); + STATIC esp_err_t check_esp_err(esp_err_t code) { if (code) { mp_raise_OSError(code); @@ -68,6 +72,12 @@ STATIC esp_err_t check_esp_err(esp_err_t code) { return code; } +void machine_timer_deinit_all(void) { + while (MP_STATE_PORT(machine_timer_obj_head) != NULL) { + machine_timer_disable(MP_STATE_PORT(machine_timer_obj_head)); + } +} + 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; @@ -88,6 +98,7 @@ STATIC mp_obj_t machine_timer_make_new(const mp_obj_type_t *type, size_t n_args, self->group = (mp_obj_get_int(args[0]) >> 1) & 1; self->index = mp_obj_get_int(args[0]) & 1; + self->next = NULL; return self; } @@ -98,6 +109,14 @@ STATIC void machine_timer_disable(machine_timer_obj_t *self) { esp_intr_free(self->handle); self->handle = NULL; } + + // Remove the timer from the linked-list of active timers + for (machine_timer_obj_t **t = &MP_STATE_PORT(machine_timer_obj_head); *t; t = &(*t)->next) { + if (*t == self) { + *t = (*t)->next; + break; + } + } } STATIC void machine_timer_isr(void *self_in) { @@ -131,6 +150,10 @@ STATIC void machine_timer_enable(machine_timer_obj_t *self) { 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)); + + // Add the timer to the linked-list of active timers + self->next = MP_STATE_PORT(machine_timer_obj_head); + MP_STATE_PORT(machine_timer_obj_head) = self; } 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) { diff --git a/ports/esp32/main.c b/ports/esp32/main.c index 9ca88699d2..01d22d3e75 100644 --- a/ports/esp32/main.c +++ b/ports/esp32/main.c @@ -109,6 +109,8 @@ soft_reset: } } + machine_timer_deinit_all(); + #if MICROPY_PY_THREAD mp_thread_deinit(); #endif diff --git a/ports/esp32/modmachine.h b/ports/esp32/modmachine.h index c8513a4711..b65b427b4e 100644 --- a/ports/esp32/modmachine.h +++ b/ports/esp32/modmachine.h @@ -22,5 +22,6 @@ extern const mp_obj_type_t machine_rtc_type; void machine_pins_init(void); void machine_pins_deinit(void); +void machine_timer_deinit_all(void); #endif // MICROPY_INCLUDED_ESP32_MODMACHINE_H diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 0f8deb11c3..a70f6d3180 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -210,9 +210,12 @@ extern const struct _mp_obj_module_t mp_module_onewire; #define MP_STATE_PORT MP_STATE_VM +struct _machine_timer_obj_t; + #define MICROPY_PORT_ROOT_POINTERS \ const char *readline_hist[8]; \ mp_obj_t machine_pin_irq_handler[40]; \ + struct _machine_timer_obj_t *machine_timer_obj_head; \ // type definitions for the specific machine From 5d88272342d134bec030af313188ff929aa56dd3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 28 Jan 2019 20:41:13 +1100 Subject: [PATCH 0020/1788] esp32/Makefile: Make sure that directory exists for sdkconfig.h. --- ports/esp32/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index b3b084bf6f..15073453ac 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -234,6 +234,7 @@ SRC_QSTR_AUTO_DEPS += $(SDKCONFIG_H): $(SDKCONFIG) $(ECHO) "GEN $@" + $(Q)$(MKDIR) -p $(dir $@) $(Q)$(PYTHON) $(ESPIDF)/tools/kconfig_new/confgen.py \ --output header $@ \ --config $< \ From f431795caf99ef49a5a1010063146ba25f524548 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 28 Jan 2019 20:42:12 +1100 Subject: [PATCH 0021/1788] esp32/boards: Use auto xtal freq config instead of default 40MHz. Auto-detection of the crystal frequency is convenient and allows for a single binary for many different boards. But it can be unreliable in certain situations so in production, for a given board, it's recommended to configure the correct fixed frequency. --- ports/esp32/boards/sdkconfig | 1 + ports/esp32/boards/sdkconfig.spiram | 1 + 2 files changed, 2 insertions(+) diff --git a/ports/esp32/boards/sdkconfig b/ports/esp32/boards/sdkconfig index f68102bee0..0453cccbf5 100644 --- a/ports/esp32/boards/sdkconfig +++ b/ports/esp32/boards/sdkconfig @@ -13,6 +13,7 @@ CONFIG_LOG_BOOTLOADER_LEVEL_WARN=y # ESP32-specific CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=n +CONFIG_ESP32_XTAL_FREQ_AUTO=y # FreeRTOS CONFIG_FREERTOS_UNICORE=y diff --git a/ports/esp32/boards/sdkconfig.spiram b/ports/esp32/boards/sdkconfig.spiram index 63908f4b05..4154b5e42e 100644 --- a/ports/esp32/boards/sdkconfig.spiram +++ b/ports/esp32/boards/sdkconfig.spiram @@ -14,6 +14,7 @@ CONFIG_LOG_BOOTLOADER_LEVEL_WARN=y CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y CONFIG_SPIRAM_SUPPORT=y CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=n +CONFIG_ESP32_XTAL_FREQ_AUTO=y # FreeRTOS CONFIG_FREERTOS_UNICORE=y From 38022ddb2c44a14b24150f221e63459405531fac Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 28 Jan 2019 22:56:55 +1100 Subject: [PATCH 0022/1788] stm32/main: Make board-defined UART REPL use a static object and buffer. This way the UART REPL does not need the MicroPython heap and exists outside the MicroPython runtime, allowing characters to still be received during a soft reset. --- ports/stm32/main.c | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 5d6cbf236e..33cfe84eeb 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -73,6 +73,14 @@ STATIC pyb_thread_t pyb_thread_main; STATIC fs_user_mount_t fs_user_mount_flash; #endif +#if defined(MICROPY_HW_UART_REPL) +#ifndef MICROPY_HW_UART_REPL_RXBUF +#define MICROPY_HW_UART_REPL_RXBUF (64) +#endif +STATIC pyb_uart_obj_t pyb_uart_repl_obj; +STATIC uint8_t pyb_uart_repl_rxbuf[MICROPY_HW_UART_REPL_RXBUF]; +#endif + void flash_error(int n) { for (int i = 0; i < n; i++) { led_state(PYB_LED_RED, 1); @@ -541,6 +549,19 @@ void stm32_main(uint32_t reset_mode) { lwip_init(); #endif + #if defined(MICROPY_HW_UART_REPL) + // Set up a UART REPL using a statically allocated object + pyb_uart_repl_obj.base.type = &pyb_uart_type; + pyb_uart_repl_obj.uart_id = MICROPY_HW_UART_REPL; + pyb_uart_repl_obj.is_static = true; + pyb_uart_repl_obj.timeout = 0; + pyb_uart_repl_obj.timeout_char = 2; + uart_init(&pyb_uart_repl_obj, MICROPY_HW_UART_REPL_BAUD, UART_WORDLENGTH_8B, UART_PARITY_NONE, UART_STOPBITS_1, 0); + uart_set_rxbuf(&pyb_uart_repl_obj, sizeof(pyb_uart_repl_rxbuf), pyb_uart_repl_rxbuf); + uart_attach_to_repl(&pyb_uart_repl_obj, true); + MP_STATE_PORT(pyb_uart_obj_all)[MICROPY_HW_UART_REPL - 1] = &pyb_uart_repl_obj; + #endif + soft_reset: #if defined(MICROPY_HW_LED2) @@ -588,27 +609,17 @@ soft_reset: // we can run Python scripts (eg boot.py), but anything that is configurable // by boot.py must be set after boot.py is run. + #if defined(MICROPY_HW_UART_REPL) + MP_STATE_PORT(pyb_stdio_uart) = &pyb_uart_repl_obj; + #else + MP_STATE_PORT(pyb_stdio_uart) = NULL; + #endif + readline_init0(); pin_init0(); extint_init0(); timer_init0(); - // 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) - { - mp_obj_t args[2] = { - MP_OBJ_NEW_SMALL_INT(MICROPY_HW_UART_REPL), - 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; - #endif - #if MICROPY_HW_ENABLE_CAN can_init0(); #endif From 1fa8f977f5140a963698450220e308e1f28c16ab Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 21 Jan 2019 13:42:06 +1100 Subject: [PATCH 0023/1788] lib/utils/pyexec: Implement paste mode with event driven REPL. --- lib/utils/pyexec.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/lib/utils/pyexec.c b/lib/utils/pyexec.c index d8dc60bfe5..b7174c9a13 100644 --- a/lib/utils/pyexec.c +++ b/lib/utils/pyexec.c @@ -160,6 +160,7 @@ typedef struct _repl_t { // will be added later. //vstr_t line; bool cont_line; + bool paste_mode; } repl_t; repl_t repl; @@ -170,6 +171,7 @@ STATIC int pyexec_friendly_repl_process_char(int c); void pyexec_event_repl_init(void) { MP_STATE_VM(repl_line) = vstr_new(32); repl.cont_line = false; + repl.paste_mode = false; // no prompt before printing friendly REPL banner or entering raw REPL readline_init(MP_STATE_VM(repl_line), ""); if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { @@ -189,6 +191,7 @@ STATIC int pyexec_raw_repl_process_char(int c) { pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL; vstr_reset(MP_STATE_VM(repl_line)); repl.cont_line = false; + repl.paste_mode = false; pyexec_friendly_repl_process_char(CHAR_CTRL_B); return 0; } else if (c == CHAR_CTRL_C) { @@ -226,6 +229,32 @@ reset: } STATIC int pyexec_friendly_repl_process_char(int c) { + if (repl.paste_mode) { + if (c == CHAR_CTRL_C) { + // cancel everything + mp_hal_stdout_tx_str("\r\n"); + goto input_restart; + } else if (c == CHAR_CTRL_D) { + // end of input + mp_hal_stdout_tx_str("\r\n"); + int ret = parse_compile_execute(MP_STATE_VM(repl_line), MP_PARSE_FILE_INPUT, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL | EXEC_FLAG_SOURCE_IS_VSTR); + if (ret & PYEXEC_FORCED_EXIT) { + return ret; + } + goto input_restart; + } else { + // add char to buffer and echo + vstr_add_byte(MP_STATE_VM(repl_line), c); + if (c == '\r') { + mp_hal_stdout_tx_str("\r\n=== "); + } else { + char buf[1] = {c}; + mp_hal_stdout_tx_strn(buf, 1); + } + return 0; + } + } + int ret = readline_process_char(c); if (!repl.cont_line) { @@ -253,6 +282,12 @@ STATIC int pyexec_friendly_repl_process_char(int c) { mp_hal_stdout_tx_str("\r\n"); vstr_clear(MP_STATE_VM(repl_line)); return PYEXEC_FORCED_EXIT; + } else if (ret == CHAR_CTRL_E) { + // paste mode + mp_hal_stdout_tx_str("\r\npaste mode; Ctrl-C to cancel, Ctrl-D to finish\r\n=== "); + vstr_reset(MP_STATE_VM(repl_line)); + repl.paste_mode = true; + return 0; } if (ret < 0) { @@ -299,6 +334,7 @@ exec: ; input_restart: vstr_reset(MP_STATE_VM(repl_line)); repl.cont_line = false; + repl.paste_mode = false; readline_init(MP_STATE_VM(repl_line), ">>> "); return 0; } From dadee5fa2497807dbf3ce33e2432bc4bf39b4937 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 30 Jan 2019 12:40:50 +1100 Subject: [PATCH 0024/1788] esp32/modsocket: Fix crashes when connect/bind can't resolve given addr. Fixes issue #4441. --- ports/esp32/modsocket.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c index 92f9a35b56..9d14fd46a1 100644 --- a/ports/esp32/modsocket.c +++ b/ports/esp32/modsocket.c @@ -178,12 +178,16 @@ static int _socket_getaddrinfo2(const mp_obj_t host, const mp_obj_t portx, struc return res; } -int _socket_getaddrinfo(const mp_obj_t addrtuple, struct addrinfo **resp) { - mp_uint_t len = 0; +STATIC void _socket_getaddrinfo(const mp_obj_t addrtuple, struct addrinfo **resp) { mp_obj_t *elem; - mp_obj_get_array(addrtuple, &len, &elem); - if (len != 2) return -1; - return _socket_getaddrinfo2(elem[0], elem[1], resp); + mp_obj_get_array_fixed_n(addrtuple, 2, &elem); + int res = _socket_getaddrinfo2(elem[0], elem[1], resp); + if (res != 0) { + mp_raise_OSError(res); + } + if (*resp == NULL) { + mp_raise_OSError(-2); // name or service not known + } } STATIC mp_obj_t socket_bind(const mp_obj_t arg0, const mp_obj_t arg1) { From 8de17b3d96285a862c038f01c40cb0e7021ee76d Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 30 Jan 2019 13:00:26 +1100 Subject: [PATCH 0025/1788] esp32/modmachine: Rename machine.sleep to machine.lightsleep. While keeping machine.sleep as an alias for machine.lightsleep for backwards compatibility. --- ports/esp32/modmachine.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ports/esp32/modmachine.c b/ports/esp32/modmachine.c index ea733effff..be5f2eb0fd 100644 --- a/ports/esp32/modmachine.c +++ b/ports/esp32/modmachine.c @@ -119,10 +119,10 @@ STATIC mp_obj_t machine_sleep_helper(wake_type_t wake_type, size_t n_args, const 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) { +STATIC mp_obj_t machine_lightsleep(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { 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_DEFINE_CONST_FUN_OBJ_KW(machine_lightsleep_obj, 0, machine_lightsleep); 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); @@ -214,7 +214,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_sleep), MP_ROM_PTR(&machine_lightsleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_lightsleep), MP_ROM_PTR(&machine_lightsleep_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) }, From d7cc92383cf34878e89e01750368b158a2830812 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 30 Jan 2019 13:38:42 +1100 Subject: [PATCH 0026/1788] esp8266/modmachine: Implement optional time_ms arg to machine.deepsleep. --- ports/esp8266/modmachine.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/ports/esp8266/modmachine.c b/ports/esp8266/modmachine.c index 1c1d902e5e..ba49fda889 100644 --- a/ports/esp8266/modmachine.c +++ b/ports/esp8266/modmachine.c @@ -102,7 +102,7 @@ STATIC mp_obj_t machine_sleep(void) { } STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_sleep_obj, machine_sleep); -STATIC mp_obj_t machine_deepsleep(void) { +STATIC mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *args) { // default to sleep forever uint32_t sleep_us = 0; @@ -123,6 +123,18 @@ STATIC mp_obj_t machine_deepsleep(void) { } } + // if an argument is given then that's the maximum time to sleep for + if (n_args == 1) { + mp_int_t max_ms = mp_obj_get_int(args[0]); + if (max_ms <= 0) { + max_ms = 1; + } + uint32_t max_us = max_ms * 1000; + if (sleep_us == 0 || max_us < sleep_us) { + sleep_us = max_us; + } + } + // prepare for RTC reset at wake up rtc_prepare_deepsleep(sleep_us); // put the device in a deep-sleep state @@ -136,7 +148,7 @@ STATIC mp_obj_t machine_deepsleep(void) { return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_deepsleep_obj, machine_deepsleep); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_deepsleep_obj, 0, 1, machine_deepsleep); typedef struct _esp_timer_obj_t { mp_obj_base_t base; From 2911e3554a6cf3925961ff7dc17b80660892bff8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 30 Jan 2019 13:39:11 +1100 Subject: [PATCH 0027/1788] esp8266/modmachine: Rename machine.sleep to machine.lightsleep. While keeping machine.sleep as an alias for machine.lightsleep for backwards compatibility. --- ports/esp8266/modmachine.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ports/esp8266/modmachine.c b/ports/esp8266/modmachine.c index ba49fda889..dc17dbd608 100644 --- a/ports/esp8266/modmachine.c +++ b/ports/esp8266/modmachine.c @@ -96,11 +96,11 @@ STATIC mp_obj_t machine_idle(void) { } STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_idle_obj, machine_idle); -STATIC mp_obj_t machine_sleep(void) { +STATIC mp_obj_t machine_lightsleep(size_t n_args, const mp_obj_t *args) { printf("Warning: not yet implemented\n"); return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_sleep_obj, machine_sleep); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_lightsleep_obj, 0, 1, machine_lightsleep); STATIC mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *args) { // default to sleep forever @@ -298,7 +298,8 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_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_sleep), MP_ROM_PTR(&machine_sleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&machine_lightsleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_lightsleep), MP_ROM_PTR(&machine_lightsleep_obj) }, { MP_ROM_QSTR(MP_QSTR_deepsleep), MP_ROM_PTR(&machine_deepsleep_obj) }, { MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) }, From 808dc95ab80d2e6be9a0a602d65cdee35903fc25 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 30 Jan 2019 14:03:43 +1100 Subject: [PATCH 0028/1788] esp8266/modmachine: Implement simple machine.lightsleep function. Use of "waiti 0" reduces power consumption by about 3mA compared to a time.sleep_ms call. --- ports/esp8266/modmachine.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/ports/esp8266/modmachine.c b/ports/esp8266/modmachine.c index dc17dbd608..11fb19cd20 100644 --- a/ports/esp8266/modmachine.c +++ b/ports/esp8266/modmachine.c @@ -97,7 +97,19 @@ STATIC mp_obj_t machine_idle(void) { STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_idle_obj, machine_idle); STATIC mp_obj_t machine_lightsleep(size_t n_args, const mp_obj_t *args) { - printf("Warning: not yet implemented\n"); + uint32_t max_us = 0xffffffff; + if (n_args == 1) { + mp_int_t max_ms = mp_obj_get_int(args[0]); + if (max_ms < 0) { + max_ms = 0; + } + max_us = max_ms * 1000; + } + uint32_t start = system_get_time(); + while (system_get_time() - start <= max_us) { + ets_event_poll(); + asm("waiti 0"); + } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_lightsleep_obj, 0, 1, machine_lightsleep); From 0a954e0196a9090268f40ce775f4db3b0ef99aba Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 30 Jan 2019 14:15:08 +1100 Subject: [PATCH 0029/1788] cc3200/modmachine: Rename machine.sleep to machine.lightsleep. --- ports/cc3200/mods/modmachine.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ports/cc3200/mods/modmachine.c b/ports/cc3200/mods/modmachine.c index 6051497e30..1ae26f3be9 100644 --- a/ports/cc3200/mods/modmachine.c +++ b/ports/cc3200/mods/modmachine.c @@ -137,11 +137,11 @@ STATIC mp_obj_t machine_idle(void) { } STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_idle_obj, machine_idle); -STATIC mp_obj_t machine_sleep (void) { +STATIC mp_obj_t machine_lightsleep(void) { pyb_sleep_sleep(); return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_sleep_obj, machine_sleep); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_lightsleep_obj, machine_lightsleep); STATIC mp_obj_t machine_deepsleep (void) { pyb_sleep_deepsleep(); @@ -171,7 +171,8 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_main), MP_ROM_PTR(&machine_main_obj) }, { MP_ROM_QSTR(MP_QSTR_rng), MP_ROM_PTR(&machine_rng_get_obj) }, { MP_ROM_QSTR(MP_QSTR_idle), MP_ROM_PTR(&machine_idle_obj) }, - { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&machine_sleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&machine_lightsleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_lightsleep), MP_ROM_PTR(&machine_lightsleep_obj) }, { MP_ROM_QSTR(MP_QSTR_deepsleep), MP_ROM_PTR(&machine_deepsleep_obj) }, { MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) }, { MP_ROM_QSTR(MP_QSTR_wake_reason), MP_ROM_PTR(&machine_wake_reason_obj) }, From d5d060ead9a7c7c97c9f2492be5450139b7e006c Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 30 Jan 2019 14:15:38 +1100 Subject: [PATCH 0030/1788] nrf/modmachine: Rename machine.sleep to machine.lightsleep. --- ports/nrf/modules/machine/modmachine.c | 7 ++++--- ports/nrf/modules/machine/modmachine.h | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ports/nrf/modules/machine/modmachine.c b/ports/nrf/modules/machine/modmachine.c index fca86e8435..841e136d0d 100644 --- a/ports/nrf/modules/machine/modmachine.c +++ b/ports/nrf/modules/machine/modmachine.c @@ -149,11 +149,11 @@ STATIC mp_obj_t machine_soft_reset(void) { } MP_DEFINE_CONST_FUN_OBJ_0(machine_soft_reset_obj, machine_soft_reset); -STATIC mp_obj_t machine_sleep(void) { +STATIC mp_obj_t machine_lightsleep(void) { __WFE(); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_0(machine_sleep_obj, machine_sleep); +MP_DEFINE_CONST_FUN_OBJ_0(machine_lightsleep_obj, machine_lightsleep); STATIC mp_obj_t machine_deepsleep(void) { __WFI(); @@ -197,7 +197,8 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { #if MICROPY_HW_ENABLE_RNG { MP_ROM_QSTR(MP_QSTR_rng), MP_ROM_PTR(&random_module) }, #endif - { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&machine_sleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&machine_lightsleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_lightsleep), MP_ROM_PTR(&machine_lightsleep_obj) }, { MP_ROM_QSTR(MP_QSTR_deepsleep), MP_ROM_PTR(&machine_deepsleep_obj) }, { MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) }, { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pin_type) }, diff --git a/ports/nrf/modules/machine/modmachine.h b/ports/nrf/modules/machine/modmachine.h index 76b4ad7242..1ea6959eab 100644 --- a/ports/nrf/modules/machine/modmachine.h +++ b/ports/nrf/modules/machine/modmachine.h @@ -36,7 +36,7 @@ void machine_init(void); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_info_obj); MP_DECLARE_CONST_FUN_OBJ_0(machine_reset_obj); -MP_DECLARE_CONST_FUN_OBJ_0(machine_sleep_obj); +MP_DECLARE_CONST_FUN_OBJ_0(machine_lightsleep_obj); MP_DECLARE_CONST_FUN_OBJ_0(machine_deepsleep_obj); #endif // __MICROPY_INCLUDED_NRF5_MODMACHINE_H__ From 4dfcc255d5ebe8625b87e5b923db9e22166bb9b4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 30 Jan 2019 14:15:51 +1100 Subject: [PATCH 0031/1788] docs: Convert all cases of machine.sleep to machine.lightsleep. --- docs/esp32/quickref.rst | 2 +- docs/wipy/general.rst | 2 +- docs/wipy/quickref.rst | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst index 81b2a53b39..426d14e3ec 100644 --- a/docs/esp32/quickref.rst +++ b/docs/esp32/quickref.rst @@ -421,7 +421,7 @@ Note that TouchPads can be used to wake an ESP32 from sleep:: t = TouchPad(Pin(14)) t.config(500) # configure the threshold at which the pin is considered touched esp32.wake_on_touch(True) - machine.sleep() # put the MCU to sleep until a touchpad is touched + machine.lightsleep() # put the MCU to sleep until a touchpad is touched For more details on touchpads refer to `Espressif Touch Sensor `_. diff --git a/docs/wipy/general.rst b/docs/wipy/general.rst index 4dfab9c050..b1109c495a 100644 --- a/docs/wipy/general.rst +++ b/docs/wipy/general.rst @@ -178,7 +178,7 @@ Details on sleep modes * ``machine.idle()``: Power consumption: ~12mA (in WLAN STA mode). Wake sources: any hardware interrupt (including systick with period of 1ms), no special configuration required. -* ``machine.sleep()``: 950uA (in WLAN STA mode). Wake sources are ``Pin``, ``RTC`` +* ``machine.lightsleep()``: 950uA (in WLAN STA mode). Wake sources are ``Pin``, ``RTC`` and ``WLAN`` * ``machine.deepsleep()``: ~350uA. Wake sources are ``Pin`` and ``RTC``. diff --git a/docs/wipy/quickref.rst b/docs/wipy/quickref.rst index 1f34bdaa96..7aa832fd25 100644 --- a/docs/wipy/quickref.rst +++ b/docs/wipy/quickref.rst @@ -28,7 +28,7 @@ See the :mod:`machine` module:: machine.unique_id() # return the 6-byte unique id of the board (the WiPy's MAC address) machine.idle() # average current decreases to (~12mA), any interrupts wake it up - machine.sleep() # everything except for WLAN is powered down (~950uA avg. current) + machine.lightsleep() # everything except for WLAN is powered down (~950uA avg. current) # wakes from Pin, RTC or WLAN machine.deepsleep() # deepest sleep mode, MCU starts from reset. Wakes from Pin and RTC. @@ -163,7 +163,7 @@ See :ref:`machine.RTC ` :: rtc_i = rtc.irq(trigger=RTC.ALARM0, handler=alarm_handler, wake=machine.SLEEP) # go into suspended mode waiting for the RTC alarm to expire and wake us up - machine.sleep() + machine.lightsleep() SD card ------- @@ -199,7 +199,7 @@ See :ref:`network.WLAN ` and :mod:`machine`. :: # enable wake on WLAN wlan.irq(trigger=WLAN.ANY_EVENT, wake=machine.SLEEP) # go to sleep - machine.sleep() + machine.lightsleep() # now, connect to the FTP or the Telnet server and the WiPy will wake-up Telnet and FTP server From 3ff3e968656cd01144c0b92e2f0cf4195740255d Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 31 Jan 2019 00:05:00 +1100 Subject: [PATCH 0032/1788] esp8266/modmachine: In lightsleep, only waiti if wifi is turned off. Otherwise the STA interface can't do DTIM sleeping correctly and power consumption goes up. --- ports/esp8266/modmachine.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ports/esp8266/modmachine.c b/ports/esp8266/modmachine.c index 11fb19cd20..8c39051613 100644 --- a/ports/esp8266/modmachine.c +++ b/ports/esp8266/modmachine.c @@ -105,10 +105,14 @@ STATIC mp_obj_t machine_lightsleep(size_t n_args, const mp_obj_t *args) { } max_us = max_ms * 1000; } + uint32_t wifi_mode = wifi_get_opmode(); uint32_t start = system_get_time(); while (system_get_time() - start <= max_us) { ets_event_poll(); - asm("waiti 0"); + if (wifi_mode == NULL_MODE) { + // Can only idle if the wifi is off + asm("waiti 0"); + } } return mp_const_none; } From 4bed17e78615360c018103ef3c3c2e204a9c9a46 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 31 Jan 2019 01:02:42 +1100 Subject: [PATCH 0033/1788] stm32/boards/stm32f429_af.csv: Fix typos in UART defs Tx->TX and Rx->RX. Fixes issue #4445. --- ports/stm32/boards/stm32f429_af.csv | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ports/stm32/boards/stm32f429_af.csv b/ports/stm32/boards/stm32f429_af.csv index 4ee8edd703..002d634a20 100644 --- a/ports/stm32/boards/stm32f429_af.csv +++ b/ports/stm32/boards/stm32f429_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,,,,,,,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 From 2a7a307baaa8b5a1fbd30ccdd8fa393ec0341888 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 31 Jan 2019 11:22:03 +1100 Subject: [PATCH 0034/1788] extmod/modlwip: Add support for polling UDP sockets for writability. --- extmod/modlwip.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index 73f1679552..84a1bd3c17 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -1231,9 +1231,15 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ } } - // 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; + if (flags & MP_STREAM_POLL_WR) { + if (socket->type == MOD_NETWORK_SOCK_DGRAM && socket->pcb.udp != NULL) { + // UDP socket is writable + ret |= MP_STREAM_POLL_WR; + } else if (socket->pcb.tcp != NULL && tcp_sndbuf(socket->pcb.tcp) > 0) { + // TCP socket is writable + // Note: pcb.tcp==NULL if state<0, and in this case we can't call tcp_sndbuf + ret |= MP_STREAM_POLL_WR; + } } if (socket->state == STATE_NEW) { From e5509a910fce6724b0a15d194b9aa9527ea49df8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 31 Jan 2019 12:05:39 +1100 Subject: [PATCH 0035/1788] stm32/mboot: Add option to autodetect the USB port that DFU uses. Enable in mpconfigboard.h via #define MBOOT_USB_AUTODETECT_USB (1). Requires MICROPY_HW_USB_FS and MICROPY_HW_USB_HS to be enabled as well. --- ports/stm32/mboot/main.c | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/ports/stm32/mboot/main.c b/ports/stm32/mboot/main.c index 0fe366cd96..70ea512ba1 100644 --- a/ports/stm32/mboot/main.c +++ b/ports/stm32/mboot/main.c @@ -1063,6 +1063,28 @@ static const USBD_ClassTypeDef pyb_usbdd_class = { static pyb_usbdd_obj_t pyb_usbdd; +static int pyb_usbdd_detect_port(void) { + #if MBOOT_USB_AUTODETECT_PORT + mp_hal_pin_config(pin_A11, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_UP, 0); + mp_hal_pin_config(pin_A12, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_UP, 0); + int state = mp_hal_pin_read(pin_A11) == 0 && mp_hal_pin_read(pin_A12) == 0; + mp_hal_pin_config(pin_A11, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_NONE, 0); + mp_hal_pin_config(pin_A12, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_NONE, 0); + if (state) { + return USB_PHY_FS_ID; + } + mp_hal_pin_config(pin_B14, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_UP, 0); + mp_hal_pin_config(pin_B15, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_UP, 0); + state = mp_hal_pin_read(pin_B14) == 0 && mp_hal_pin_read(pin_B15) == 0; + mp_hal_pin_config(pin_B14, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_NONE, 0); + mp_hal_pin_config(pin_B15, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_NONE, 0); + if (state) { + return USB_PHY_HS_ID; + } + #endif + return MICROPY_HW_USB_MAIN_DEV; +} + static void pyb_usbdd_init(pyb_usbdd_obj_t *self, int phy_id) { self->started = false; USBD_HandleTypeDef *usbd = &self->hUSBDDevice; @@ -1235,7 +1257,7 @@ enter_bootloader: dfu_init(); - pyb_usbdd_init(&pyb_usbdd, MICROPY_HW_USB_MAIN_DEV); + pyb_usbdd_init(&pyb_usbdd, pyb_usbdd_detect_port()); pyb_usbdd_start(&pyb_usbdd); #if defined(MBOOT_I2C_SCL) @@ -1254,11 +1276,12 @@ enter_bootloader: #endif for (;;) { #if USE_USB_POLLING - #if MICROPY_HW_USB_MAIN_DEV == USB_PHY_FS_ID + #if MBOOT_USB_AUTODETECT_PORT || MICROPY_HW_USB_MAIN_DEV == USB_PHY_FS_ID if (USB_OTG_FS->GINTSTS & USB_OTG_FS->GINTMSK) { HAL_PCD_IRQHandler(&pcd_fs_handle); } - #else + #endif + #if MBOOT_USB_AUTODETECT_PORT || MICROPY_HW_USB_MAIN_DEV == USB_PHY_HS_ID if (USB_OTG_HS->GINTSTS & USB_OTG_HS->GINTMSK) { HAL_PCD_IRQHandler(&pcd_hs_handle); } @@ -1333,11 +1356,13 @@ void I2Cx_EV_IRQHandler(void) { #endif #if !USE_USB_POLLING -#if MICROPY_HW_USB_MAIN_DEV == USB_PHY_FS_ID +#if MBOOT_USB_AUTODETECT_PORT || MICROPY_HW_USB_MAIN_DEV == USB_PHY_FS_ID void OTG_FS_IRQHandler(void) { HAL_PCD_IRQHandler(&pcd_fs_handle); } -#else +#endif + +#if MBOOT_USB_AUTODETECT_PORT || MICROPY_HW_USB_MAIN_DEV == USB_PHY_HS_ID void OTG_HS_IRQHandler(void) { HAL_PCD_IRQHandler(&pcd_hs_handle); } From 86f06d6a874d4eb3d6c50deec0240942344c01ea Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 31 Jan 2019 12:49:48 +1100 Subject: [PATCH 0036/1788] stm32/sdcard: Don't use SD clock bypass on F7 MCUs. With clock bypass enabled the attached SD card is clocked at the maximum 48MHz. But some SD cards are unreliable at these rates. Although it's nice to have high speed transfers it's more important that the transfers are reliable for all cards. So disable this clock bypass option. --- ports/stm32/sdcard.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ports/stm32/sdcard.c b/ports/stm32/sdcard.c index 1d49016e7d..94bfc5cd86 100644 --- a/ports/stm32/sdcard.c +++ b/ports/stm32/sdcard.c @@ -222,10 +222,6 @@ bool sdcard_power_on(void) { } // configure the SD bus width for wide operation - #if defined(STM32F7) - // 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 2f5d113fad4ca2b22b084ccaf835c595cd6a7a4e Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 21 Dec 2018 14:20:55 +0300 Subject: [PATCH 0037/1788] py/warning: Support categories for warnings. Python defines warnings as belonging to categories, where category is a warning type (descending from exception type). This is useful, as e.g. allows to disable warnings selectively and provide user-defined warning types. So, implement this in MicroPython, except that categories are represented just with strings. However, enough hooks are left to implement categories differently per-port (e.g. as types), without need to patch each and every usage. --- extmod/modlwip.c | 2 +- ports/unix/mpconfigport_coverage.h | 1 + ports/zephyr/modusocket.c | 2 +- py/mpconfig.h | 16 ++++++++++++++++ py/obj.c | 2 +- py/runtime.h | 4 +++- py/vm.c | 2 +- py/warning.c | 11 ++++++++--- 8 files changed, 32 insertions(+), 8 deletions(-) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index 84a1bd3c17..d76fd1b1e4 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -1454,7 +1454,7 @@ STATIC mp_obj_t lwip_getaddrinfo(size_t n_args, const mp_obj_t *args) { && (type == 0 || type == MOD_NETWORK_SOCK_STREAM) && proto == 0 && flags == 0)) { - mp_warning("unsupported getaddrinfo constraints"); + mp_warning(MP_WARN_CAT(RuntimeWarning), "unsupported getaddrinfo constraints"); } } diff --git a/ports/unix/mpconfigport_coverage.h b/ports/unix/mpconfigport_coverage.h index 2519482b01..87bf8454ce 100644 --- a/ports/unix/mpconfigport_coverage.h +++ b/ports/unix/mpconfigport_coverage.h @@ -36,6 +36,7 @@ #define MICROPY_FLOAT_HIGH_QUALITY_HASH (1) #define MICROPY_ENABLE_SCHEDULER (1) #define MICROPY_READER_VFS (1) +#define MICROPY_WARNINGS_CATEGORY (1) #define MICROPY_MODULE_GETATTR (1) #define MICROPY_PY_DELATTR_SETATTR (1) #define MICROPY_PY_REVERSE_SPECIAL_METHODS (1) diff --git a/ports/zephyr/modusocket.c b/ports/zephyr/modusocket.c index 84d6fa7297..083083788a 100644 --- a/ports/zephyr/modusocket.c +++ b/ports/zephyr/modusocket.c @@ -288,7 +288,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recv_obj, socket_recv); STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) { (void)n_args; // always 4 - mp_warning("setsockopt() not implemented"); + mp_warning(MP_WARN_CAT(RuntimeWarning), "setsockopt() not implemented"); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt); diff --git a/py/mpconfig.h b/py/mpconfig.h index 48427c3e58..4fd08db230 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -598,6 +598,11 @@ typedef long long mp_longint_impl_t; #define MICROPY_WARNINGS (0) #endif +// Whether to support warning categories +#ifndef MICROPY_WARNINGS_CATEGORY +#define MICROPY_WARNINGS_CATEGORY (0) +#endif + // This macro is used when printing runtime warnings and errors #ifndef MICROPY_ERROR_PRINTER #define MICROPY_ERROR_PRINTER (&mp_plat_print) @@ -1508,4 +1513,15 @@ typedef double mp_float_t; #endif #endif +// Warning categories are by default implemented as strings, though +// hook is left for a port to define them as something else. +#if MICROPY_WARNINGS_CATEGORY +# ifndef MP_WARN_CAT +# define MP_WARN_CAT(x) #x +# endif +#else +# undef MP_WARN_CAT +# define MP_WARN_CAT(x) (NULL) +#endif + #endif // MICROPY_INCLUDED_PY_MPCONFIG_H diff --git a/py/obj.c b/py/obj.c index 47b7d15ae0..7007d5070e 100644 --- a/py/obj.c +++ b/py/obj.c @@ -202,7 +202,7 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) { str_cmp_err: #if MICROPY_PY_STR_BYTES_CMP_WARN if (MP_OBJ_IS_TYPE(o1, &mp_type_bytes) || MP_OBJ_IS_TYPE(o2, &mp_type_bytes)) { - mp_warning("Comparison between bytes and str"); + mp_warning(MP_WARN_CAT(BytesWarning), "Comparison between bytes and str"); } #endif return false; diff --git a/py/runtime.h b/py/runtime.h index dd4c9a984e..9811c1b5ae 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -179,7 +179,9 @@ void mp_native_raise(mp_obj_t o); #define mp_sys_argv (MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_sys_argv_obj))) #if MICROPY_WARNINGS -void mp_warning(const char *msg, ...); +#ifndef mp_warning +void mp_warning(const char *category, const char *msg, ...); +#endif #else #define mp_warning(...) #endif diff --git a/py/vm.c b/py/vm.c index f9f9a3d6ac..fce59349f0 100644 --- a/py/vm.c +++ b/py/vm.c @@ -1116,7 +1116,7 @@ unwind_return: mp_uint_t unum = *ip; mp_obj_t obj; if (unum == 2) { - mp_warning("exception chaining not supported"); + mp_warning(NULL, "exception chaining not supported"); // ignore (pop) "from" argument sp--; } diff --git a/py/warning.c b/py/warning.c index 12d0f9c99b..ebaf2d0783 100644 --- a/py/warning.c +++ b/py/warning.c @@ -32,10 +32,15 @@ #if MICROPY_WARNINGS -void mp_warning(const char *msg, ...) { +void mp_warning(const char *category, const char *msg, ...) { + if (category == NULL) { + category = "Warning"; + } + mp_print_str(MICROPY_ERROR_PRINTER, category); + mp_print_str(MICROPY_ERROR_PRINTER, ": "); + va_list args; va_start(args, msg); - mp_print_str(MICROPY_ERROR_PRINTER, "Warning: "); mp_vprintf(MICROPY_ERROR_PRINTER, msg, args); mp_print_str(MICROPY_ERROR_PRINTER, "\n"); va_end(args); @@ -43,7 +48,7 @@ void mp_warning(const char *msg, ...) { void mp_emitter_warning(pass_kind_t pass, const char *msg) { if (pass == MP_PASS_CODE_SIZE) { - mp_warning(msg, NULL); + mp_warning(NULL, msg); } } From a293fa3d6d675d5553bf8e13de16c8300ba7b4bf Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Thu, 2 Aug 2018 13:46:18 +0200 Subject: [PATCH 0038/1788] nrf/uart: Use formula instead of switch for baudrate calculation. This saves a bit of code: nrf51: -176 nrf52: -152 --- ports/nrf/modules/machine/uart.c | 61 ++++++++------------------------ 1 file changed, 14 insertions(+), 47 deletions(-) diff --git a/ports/nrf/modules/machine/uart.c b/ports/nrf/modules/machine/uart.c index c3f8ea9840..37c6c30a18 100644 --- a/ports/nrf/modules/machine/uart.c +++ b/ports/nrf/modules/machine/uart.c @@ -170,55 +170,22 @@ STATIC mp_obj_t machine_hard_uart_make_new(const mp_obj_type_t *type, size_t n_a config.interrupt_priority = 6; #endif - switch (args[ARG_baudrate].u_int) { - case 1200: - config.baudrate = NRF_UART_BAUDRATE_1200; - break; - case 2400: - config.baudrate = NRF_UART_BAUDRATE_2400; - break; - case 4800: - config.baudrate = NRF_UART_BAUDRATE_4800; - break; - case 9600: - config.baudrate = NRF_UART_BAUDRATE_9600; - break; - case 14400: - config.baudrate = NRF_UART_BAUDRATE_14400; - break; - case 19200: - config.baudrate = NRF_UART_BAUDRATE_19200; - break; - case 28800: - config.baudrate = NRF_UART_BAUDRATE_28800; - break; - case 38400: - config.baudrate = NRF_UART_BAUDRATE_38400; - break; - case 57600: - config.baudrate = NRF_UART_BAUDRATE_57600; - break; - case 76800: - config.baudrate = NRF_UART_BAUDRATE_76800; - break; - case 115200: - config.baudrate = NRF_UART_BAUDRATE_115200; - break; - case 230400: - config.baudrate = NRF_UART_BAUDRATE_230400; - break; - case 250000: - config.baudrate = NRF_UART_BAUDRATE_250000; - break; - case 1000000: - config.baudrate = NRF_UART_BAUDRATE_1000000; - break; - default: - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - "UART baudrate not supported, %u", args[ARG_baudrate].u_int)); - break; + // These baudrates are not supported, it seems. + if (args[ARG_baudrate].u_int < 1200 || args[ARG_baudrate].u_int > 1000000) { + mp_raise_ValueError("UART baudrate not supported"); } + // Magic: calculate 'baudrate' register from the input number. + // Every value listed in the datasheet will be converted to the + // correct register value, except for 192600. I believe the value + // listed in the nrf52 datasheet (0x0EBED000) is incorrectly rounded + // and should be 0x0EBEE000, as the nrf51 datasheet lists the + // nonrounded value 0x0EBEDFA4. + // Some background: + // https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values/2046#2046 + config.baudrate = args[ARG_baudrate].u_int / 400 * (uint32_t)(400ULL * (uint64_t)UINT32_MAX / 16000000ULL); + config.baudrate = (config.baudrate + 0x800) & 0xffffff000; // rounding + config.pseltxd = MICROPY_HW_UART1_TX; config.pselrxd = MICROPY_HW_UART1_RX; From 1ba962ff574a6befb2e7233e5669eaf25f36a1bb Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Thu, 2 Aug 2018 14:05:01 +0200 Subject: [PATCH 0039/1788] nrf/uart: Remove unused machine.UART() parameters. If needed these parameters can be added back and made functional one at a time. It's better to explicitly not support them than to silently allow but ignore them. --- ports/nrf/modules/machine/uart.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/ports/nrf/modules/machine/uart.c b/ports/nrf/modules/machine/uart.c index 37c6c30a18..2ddee79d13 100644 --- a/ports/nrf/modules/machine/uart.c +++ b/ports/nrf/modules/machine/uart.c @@ -118,29 +118,16 @@ STATIC void machine_hard_uart_print(const mp_print_t *print, mp_obj_t self_in, m -/// \method init(baudrate, bits=8, parity=None, stop=1, *, timeout=1000, timeout_char=0, read_buf_len=64) +/// \method init(id, baudrate) /// /// Initialise the UART bus with the given parameters: /// - `id`is bus id. /// - `baudrate` is the clock rate. -/// - `bits` is the number of bits per byte, 7, 8 or 9. -/// - `parity` is the parity, `None`, 0 (even) or 1 (odd). -/// - `stop` is the number of stop bits, 1 or 2. -/// - `timeout` is the timeout in milliseconds to wait for the first character. -/// - `timeout_char` is the timeout in milliseconds to wait between characters. -/// - `read_buf_len` is the character length of the read buffer (0 to disable). STATIC mp_obj_t machine_hard_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - enum { ARG_id, ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_flow, ARG_timeout, ARG_timeout_char, ARG_read_buf_len }; + enum { ARG_id, ARG_baudrate }; static const mp_arg_t allowed_args[] = { { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_baudrate, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 9600} }, - { MP_QSTR_bits, MP_ARG_INT, {.u_int = 8} }, - { MP_QSTR_parity, MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_stop, MP_ARG_INT, {.u_int = 1} }, - { MP_QSTR_flow, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000} }, - { MP_QSTR_timeout_char, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_read_buf_len, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} }, }; // parse args @@ -154,8 +141,6 @@ STATIC mp_obj_t machine_hard_uart_make_new(const mp_obj_type_t *type, size_t n_a nrfx_uart_config_t config; // flow control - config.hwfc = args[ARG_flow].u_int; - #if MICROPY_HW_UART1_HWFC config.hwfc = NRF_UART_HWFC_ENABLED; #else From 4e1c2fc8318480dded4a4a031a9986d8db578030 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Thu, 2 Aug 2018 15:42:24 +0200 Subject: [PATCH 0040/1788] nrf: Shrink " does not exist" error messages. Code size reductions: nrf51: -132 nrf52: -188 --- ports/nrf/modules/board/led.c | 2 +- ports/nrf/modules/machine/adc.c | 3 +-- ports/nrf/modules/machine/i2c.c | 3 +-- ports/nrf/modules/machine/pin.c | 2 +- ports/nrf/modules/machine/pwm.c | 6 ++---- ports/nrf/modules/machine/rtcounter.c | 3 +-- ports/nrf/modules/machine/spi.c | 6 ++---- ports/nrf/modules/machine/timer.c | 9 +++------ ports/nrf/modules/machine/uart.c | 3 +-- 9 files changed, 13 insertions(+), 24 deletions(-) diff --git a/ports/nrf/modules/board/led.c b/ports/nrf/modules/board/led.c index a576b7088f..687348cb86 100644 --- a/ports/nrf/modules/board/led.c +++ b/ports/nrf/modules/board/led.c @@ -105,7 +105,7 @@ STATIC mp_obj_t led_obj_make_new(const mp_obj_type_t *type, size_t n_args, size_ // check led number if (!(1 <= led_id && led_id <= NUM_LEDS)) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "LED(%d) does not exist", led_id)); + mp_raise_ValueError("LED doesn't exist"); } // return static led object diff --git a/ports/nrf/modules/machine/adc.c b/ports/nrf/modules/machine/adc.c index ce48056920..55b68c6b80 100644 --- a/ports/nrf/modules/machine/adc.c +++ b/ports/nrf/modules/machine/adc.c @@ -100,8 +100,7 @@ STATIC int adc_find(mp_obj_t id) { && machine_adc_obj[adc_idx].id != (uint8_t)-1) { return adc_idx; } - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - "ADC(%d) does not exist", adc_id)); + mp_raise_ValueError("ADC doesn't exist"); } /// \method __str__() diff --git a/ports/nrf/modules/machine/i2c.c b/ports/nrf/modules/machine/i2c.c index 15f024f0e4..8b79342a30 100644 --- a/ports/nrf/modules/machine/i2c.c +++ b/ports/nrf/modules/machine/i2c.c @@ -58,8 +58,7 @@ STATIC int i2c_find(mp_obj_t id) { if (i2c_id >= 0 && i2c_id < MP_ARRAY_SIZE(machine_hard_i2c_obj)) { return i2c_id; } - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - "I2C(%d) does not exist", i2c_id)); + mp_raise_ValueError("I2C doesn't exist"); } STATIC void machine_hard_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { diff --git a/ports/nrf/modules/machine/pin.c b/ports/nrf/modules/machine/pin.c index df4eb471e3..d3458d0aef 100644 --- a/ports/nrf/modules/machine/pin.c +++ b/ports/nrf/modules/machine/pin.c @@ -207,7 +207,7 @@ const pin_obj_t *pin_find(mp_obj_t user_obj) { return pin_obj; } - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin '%s' not a valid pin identifier", mp_obj_str_get_str(user_obj))); + mp_raise_ValueError("not a valid pin identifier"); } /// \method __str__() diff --git a/ports/nrf/modules/machine/pwm.c b/ports/nrf/modules/machine/pwm.c index ed4380656c..8e5c2e23fd 100644 --- a/ports/nrf/modules/machine/pwm.c +++ b/ports/nrf/modules/machine/pwm.c @@ -99,8 +99,7 @@ STATIC int hard_pwm_find(mp_obj_t id) { if (pwm_id >= 0 && pwm_id < MP_ARRAY_SIZE(machine_hard_pwm_obj)) { return pwm_id; } - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - "PWM(%d) does not exist", pwm_id)); + mp_raise_ValueError("PWM doesn't exist"); } return -1; } @@ -252,8 +251,7 @@ STATIC mp_obj_t machine_hard_pwm_make_new(mp_arg_val_t *args) { if (args[ARG_period].u_obj != MP_OBJ_NULL) { self->p_config->period = mp_obj_get_int(args[ARG_period].u_obj); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - "PWM period has to be within 16000 frequence cycles", self->p_config->period)); + mp_raise_ValueError("PWM period must be within 16000 cycles"); } if (args[ARG_duty].u_obj != MP_OBJ_NULL) { diff --git a/ports/nrf/modules/machine/rtcounter.c b/ports/nrf/modules/machine/rtcounter.c index ea4a17626d..0afdf5bd21 100644 --- a/ports/nrf/modules/machine/rtcounter.c +++ b/ports/nrf/modules/machine/rtcounter.c @@ -116,8 +116,7 @@ STATIC int rtc_find(mp_obj_t id) { if (rtc_id >= 0 && rtc_id < MP_ARRAY_SIZE(machine_rtc_obj)) { return rtc_id; } - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - "RTCounter(%d) does not exist", rtc_id)); + mp_raise_ValueError("RTCounter doesn't exist"); } STATIC void rtc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { diff --git a/ports/nrf/modules/machine/spi.c b/ports/nrf/modules/machine/spi.c index ce75b6cafe..95331e2414 100644 --- a/ports/nrf/modules/machine/spi.c +++ b/ports/nrf/modules/machine/spi.c @@ -140,16 +140,14 @@ STATIC int spi_find(mp_obj_t id) { return 1; #endif } - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - "SPI(%s) does not exist", port)); + mp_raise_ValueError("SPI doesn't exist"); } else { // given an integer id int spi_id = mp_obj_get_int(id); if (spi_id >= 0 && spi_id < MP_ARRAY_SIZE(machine_hard_spi_obj)) { return spi_id; } - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - "SPI(%d) does not exist", spi_id)); + mp_raise_ValueError("SPI doesn't exist"); } } diff --git a/ports/nrf/modules/machine/timer.c b/ports/nrf/modules/machine/timer.c index 07f1f496ec..e5e84a688d 100644 --- a/ports/nrf/modules/machine/timer.c +++ b/ports/nrf/modules/machine/timer.c @@ -75,8 +75,7 @@ STATIC int timer_find(mp_obj_t id) { if (timer_id >= 0 && timer_id < MP_ARRAY_SIZE(machine_timer_obj)) { return timer_id; } - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - "Timer(%d) does not exist", timer_id)); + mp_raise_ValueError("Timer doesn't exist"); } STATIC void timer_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) { @@ -113,15 +112,13 @@ STATIC mp_obj_t machine_timer_make_new(const mp_obj_type_t *type, size_t n_args, #if BLUETOOTH_SD if (timer_id == 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - "Timer(%d) reserved by Bluetooth LE stack.", timer_id)); + mp_raise_ValueError("Timer reserved by Bluetooth LE stack"); } #endif #if MICROPY_PY_MACHINE_SOFT_PWM if (timer_id == 1) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - "Timer(%d) reserved by ticker driver.", timer_id)); + mp_raise_ValueError("Timer reserved by ticker driver"); } #endif diff --git a/ports/nrf/modules/machine/uart.c b/ports/nrf/modules/machine/uart.c index 2ddee79d13..cef98fb07f 100644 --- a/ports/nrf/modules/machine/uart.c +++ b/ports/nrf/modules/machine/uart.c @@ -67,8 +67,7 @@ STATIC int uart_find(mp_obj_t id) { if (uart_id >= 0 && uart_id < MP_ARRAY_SIZE(machine_hard_uart_obj)) { return uart_id; } - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - "UART(%d) does not exist", uart_id)); + mp_raise_ValueError("UART doesn't exist"); } void uart_irq_handler(mp_uint_t uart_id) { From 2d293873a6be67b43c4315d70418138a95edb8ff Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Thu, 2 Aug 2018 18:51:34 +0200 Subject: [PATCH 0041/1788] nrf/pin: Cleanup Pin.__str__ to print relevant information. Code size change: nrf51: -44 nrf52: -52 --- ports/nrf/modules/machine/pin.c | 58 ++------------------------------- 1 file changed, 2 insertions(+), 56 deletions(-) diff --git a/ports/nrf/modules/machine/pin.c b/ports/nrf/modules/machine/pin.c index d3458d0aef..12bc9b0c62 100644 --- a/ports/nrf/modules/machine/pin.c +++ b/ports/nrf/modules/machine/pin.c @@ -215,62 +215,8 @@ const pin_obj_t *pin_find(mp_obj_t user_obj) { STATIC void pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { pin_obj_t *self = self_in; - // pin name - mp_printf(print, "Pin(Pin.cpu.%q, mode=Pin.", self->name); - mp_printf(print, "port=0x%x, ", self->pin / 32); - mp_printf(print, "pin=0x%x, ", self->pin); -/* - uint32_t mode = pin_get_mode(self); - - if (mode == GPIO_MODE_ANALOG) { - // analog - mp_print_str(print, "ANALOG)"); - - } else { - // IO mode - bool af = false; - qstr mode_qst; - if (mode == GPIO_MODE_INPUT) { - mode_qst = MP_QSTR_IN; - } else if (mode == GPIO_MODE_OUTPUT_PP) { - mode_qst = MP_QSTR_OUT; - } else if (mode == GPIO_MODE_OUTPUT_OD) { - mode_qst = MP_QSTR_OPEN_DRAIN; - } else { - af = true; - if (mode == GPIO_MODE_AF_PP) { - mode_qst = MP_QSTR_ALT; - } else { - mode_qst = MP_QSTR_ALT_OPEN_DRAIN; - } - } - mp_print_str(print, qstr_str(mode_qst)); - // pull mode - qstr pull_qst = MP_QSTR_NULL; - uint32_t pull = pin_get_pull(self); - if (pull == GPIO_PULLUP) { - pull_qst = MP_QSTR_PULL_UP; - } else if (pull == GPIO_PULLDOWN) { - pull_qst = MP_QSTR_PULL_DOWN; - } - if (pull_qst != MP_QSTR_NULL) { - mp_printf(print, ", pull=Pin.%q", pull_qst); - } - // AF mode - if (af) { - mp_uint_t af_idx = pin_get_af(self); - const pin_af_obj_t *af_obj = pin_find_af_by_index(self, af_idx); - if (af_obj == NULL) { - mp_printf(print, ", af=%d)", af_idx); - } else { - mp_printf(print, ", af=Pin.%q)", af_obj->name); - } - } else { -*/ - mp_print_str(print, ")"); - /* } - }*/ - + mp_printf(print, "Pin(%d, mode=%s)", self->pin, + (nrf_gpio_pin_dir_get(self->pin) == NRF_GPIO_PIN_DIR_OUTPUT) ? "OUT" : "IN"); } STATIC mp_obj_t pin_obj_init_helper(const pin_obj_t *pin, mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args); From 8faf17b93cfaee4f0150ee3a3086084f3340bcc6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 31 Jan 2019 17:37:26 +1100 Subject: [PATCH 0042/1788] lib/nrfx: Upgrade to nrfx v1.3.1. --- lib/nrfx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/nrfx b/lib/nrfx index 293f553ed9..d4ebe15f58 160000 --- a/lib/nrfx +++ b/lib/nrfx @@ -1 +1 @@ -Subproject commit 293f553ed9551c1fdfd05eac48e75bbdeb4e7290 +Subproject commit d4ebe15f58de1442e3eed93b40d13930e7785903 From e8678cd1c9e36f8a1175773b97ef2df5e5f8b673 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Thu, 2 Aug 2018 20:52:17 +0200 Subject: [PATCH 0043/1788] nrf/pin: Print pull information in Pin.__str__. --- ports/nrf/modules/machine/pin.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/ports/nrf/modules/machine/pin.c b/ports/nrf/modules/machine/pin.c index 12bc9b0c62..8a16dc4081 100644 --- a/ports/nrf/modules/machine/pin.c +++ b/ports/nrf/modules/machine/pin.c @@ -215,8 +215,22 @@ const pin_obj_t *pin_find(mp_obj_t user_obj) { STATIC void pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { pin_obj_t *self = self_in; - mp_printf(print, "Pin(%d, mode=%s)", self->pin, - (nrf_gpio_pin_dir_get(self->pin) == NRF_GPIO_PIN_DIR_OUTPUT) ? "OUT" : "IN"); + char *pull = "PULL_DISABLED"; + switch (nrf_gpio_pin_pull_get(self->pin)) { + case NRF_GPIO_PIN_PULLUP: + pull = "PULL_UP"; + break; + case NRF_GPIO_PIN_PULLDOWN: + pull = "PULL_DOWN"; + break; + default: + break; + } + + mp_printf(print, "Pin(%d, mode=%s, pull=%s)", + self->pin, + (nrf_gpio_pin_dir_get(self->pin) == NRF_GPIO_PIN_DIR_OUTPUT) ? "OUT" : "IN", + pull); } STATIC mp_obj_t pin_obj_init_helper(const pin_obj_t *pin, mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args); From 63eae33b7b37be00dcaa751c58bf2c3be7e6e460 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stig=20Bj=C3=B8rlykke?= Date: Tue, 25 Sep 2018 21:50:37 +0200 Subject: [PATCH 0044/1788] nrf/ticker: Remove duplicate NRFX_IRQ_PRIORITY_SET. --- ports/nrf/drivers/ticker.c | 1 - 1 file changed, 1 deletion(-) diff --git a/ports/nrf/drivers/ticker.c b/ports/nrf/drivers/ticker.c index 264ed8ee72..46cc783c48 100644 --- a/ports/nrf/drivers/ticker.c +++ b/ports/nrf/drivers/ticker.c @@ -64,7 +64,6 @@ void ticker_init0(void) { #endif NRFX_IRQ_PRIORITY_SET(SlowTicker_IRQn, 3); - NRFX_IRQ_PRIORITY_SET(SlowTicker_IRQn, 3); NRFX_IRQ_ENABLE(SlowTicker_IRQn); } From 67689bfd7e28df8d4fa23c8f25065aeb0b9d9658 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Fri, 14 Dec 2018 17:07:12 +1100 Subject: [PATCH 0045/1788] stm32/usb: Add flow control option for USB VCP data received from host. It's off by default and can be enabled at run-time with: pyb.USB_VCP().init(flow=pyb.USB_VCP.RTS) --- ports/stm32/usb.c | 25 +++++++++++++ ports/stm32/usbd_cdc_interface.c | 35 ++++++++++++++++--- ports/stm32/usbd_cdc_interface.h | 6 ++++ .../stm32/usbdev/class/src/usbd_cdc_msc_hid.c | 7 ++-- 4 files changed, 65 insertions(+), 8 deletions(-) diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index b73bfdc311..a5be6cd77d 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -410,6 +410,27 @@ STATIC mp_obj_t pyb_usb_vcp_make_new(const mp_obj_type_t *type, size_t n_args, s } } +// init(*, flow=-1) +STATIC mp_obj_t pyb_usb_vcp_init(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_flow }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_flow, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // flow control + if (args[ARG_flow].u_int != -1) { + self->cdc_itf->flow = args[ARG_flow].u_int; + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_usb_vcp_init_obj, 1, pyb_usb_vcp_init); + STATIC mp_obj_t pyb_usb_vcp_setinterrupt(mp_obj_t self_in, mp_obj_t int_chr_in) { mp_hal_set_interrupt_char(mp_obj_get_int(int_chr_in)); return mp_const_none; @@ -510,6 +531,7 @@ mp_obj_t pyb_usb_vcp___exit__(size_t n_args, const mp_obj_t *args) { STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_usb_vcp___exit___obj, 4, 4, pyb_usb_vcp___exit__); STATIC const mp_rom_map_elem_t pyb_usb_vcp_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_usb_vcp_init_obj) }, { MP_ROM_QSTR(MP_QSTR_setinterrupt), MP_ROM_PTR(&pyb_usb_vcp_setinterrupt_obj) }, { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&pyb_usb_vcp_isconnected_obj) }, { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&pyb_usb_vcp_any_obj) }, @@ -524,6 +546,9 @@ STATIC const mp_rom_map_elem_t pyb_usb_vcp_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_identity_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&pyb_usb_vcp___exit___obj) }, + + // class constants + { MP_ROM_QSTR(MP_QSTR_RTS), MP_ROM_INT(USBD_CDC_FLOWCONTROL_RTS) }, }; STATIC MP_DEFINE_CONST_DICT(pyb_usb_vcp_locals_dict, pyb_usb_vcp_locals_dict_table); diff --git a/ports/stm32/usbd_cdc_interface.c b/ports/stm32/usbd_cdc_interface.c index 149971bfb5..bc35ff50c9 100644 --- a/ports/stm32/usbd_cdc_interface.c +++ b/ports/stm32/usbd_cdc_interface.c @@ -69,6 +69,7 @@ uint8_t *usbd_cdc_init(usbd_cdc_state_t *cdc_in) { // be filled (by usbd_cdc_tx_always) before the USB device is connected. cdc->rx_buf_put = 0; cdc->rx_buf_get = 0; + cdc->rx_buf_full = false; cdc->tx_buf_ptr_out = 0; cdc->tx_buf_ptr_out_shadow = 0; cdc->tx_need_empty_packet = 0; @@ -236,6 +237,25 @@ void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) { } } +bool usbd_cdc_rx_buffer_full(usbd_cdc_itf_t *cdc) { + int get = cdc->rx_buf_get, put = cdc->rx_buf_put; + int remaining = (get - put) + (-((int) (get <= put)) & USBD_CDC_RX_DATA_SIZE); + return remaining < CDC_DATA_MAX_PACKET_SIZE + 1; +} + +void usbd_cdc_rx_check_resume(usbd_cdc_itf_t *cdc) { + uint32_t irq_state = disable_irq(); + if (cdc->rx_buf_full) { + if (!usbd_cdc_rx_buffer_full(cdc)) { + cdc->rx_buf_full = false; + enable_irq(irq_state); + USBD_CDC_ReceivePacket(&cdc->base, cdc->rx_packet_buf); + return; + } + } + enable_irq(irq_state); +} + // 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 @@ -257,10 +277,14 @@ int8_t usbd_cdc_receive(usbd_cdc_state_t *cdc_in, size_t len) { } } - // initiate next USB packet transfer - USBD_CDC_ReceivePacket(&cdc->base, cdc->rx_packet_buf); - - return USBD_OK; + if ((cdc->flow & USBD_CDC_FLOWCONTROL_RTS) && (usbd_cdc_rx_buffer_full(cdc))) { + cdc->rx_buf_full = true; + return USBD_BUSY; + } else { + // initiate next USB packet transfer + cdc->rx_buf_full = false; + return USBD_CDC_ReceivePacket(&cdc->base, cdc->rx_packet_buf); + } } int usbd_cdc_tx_half_empty(usbd_cdc_itf_t *cdc) { @@ -339,6 +363,7 @@ int usbd_cdc_rx_num(usbd_cdc_itf_t *cdc) { if (rx_waiting < 0) { rx_waiting += USBD_CDC_RX_DATA_SIZE; } + usbd_cdc_rx_check_resume(cdc); return rx_waiting; } @@ -359,6 +384,7 @@ int usbd_cdc_rx(usbd_cdc_itf_t *cdc, uint8_t *buf, uint32_t len, uint32_t timeou // IRQs disabled so buffer will never be filled; return immediately return i; } + usbd_cdc_rx_check_resume(cdc); __WFI(); // enter sleep mode, waiting for interrupt } @@ -366,6 +392,7 @@ int usbd_cdc_rx(usbd_cdc_itf_t *cdc, uint8_t *buf, uint32_t len, uint32_t timeou buf[i] = cdc->rx_user_buf[cdc->rx_buf_get]; cdc->rx_buf_get = (cdc->rx_buf_get + 1) & (USBD_CDC_RX_DATA_SIZE - 1); } + usbd_cdc_rx_check_resume(cdc); // Success, return number of bytes read return len; diff --git a/ports/stm32/usbd_cdc_interface.h b/ports/stm32/usbd_cdc_interface.h index fd69222f10..780d4816e8 100644 --- a/ports/stm32/usbd_cdc_interface.h +++ b/ports/stm32/usbd_cdc_interface.h @@ -39,6 +39,10 @@ #define USBD_CDC_CONNECT_STATE_CONNECTING (1) #define USBD_CDC_CONNECT_STATE_CONNECTED (2) +// Flow control settings +#define USBD_CDC_FLOWCONTROL_NONE (0) +#define USBD_CDC_FLOWCONTROL_RTS (1) + typedef struct _usbd_cdc_itf_t { usbd_cdc_state_t base; // state for the base CDC layer @@ -46,6 +50,7 @@ typedef struct _usbd_cdc_itf_t { 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 + uint8_t rx_buf_full; // rx from host will be blocked while this is true uint8_t tx_buf[USBD_CDC_TX_DATA_SIZE]; // data for USB IN endpoind is stored in this buffer uint16_t tx_buf_ptr_in; // increment this pointer modulo USBD_CDC_TX_DATA_SIZE when new data is available @@ -55,6 +60,7 @@ typedef struct _usbd_cdc_itf_t { volatile uint8_t connect_state; // indicates if we are connected uint8_t attached_to_repl; // indicates if interface is connected to REPL + uint8_t flow; // USBD_CDC_FLOWCONTROL_* setting flags } usbd_cdc_itf_t; // This is implemented in usb.c 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 fee1b23ea1..a576796e27 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -1128,14 +1128,13 @@ static uint8_t USBD_CDC_MSC_HID_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) /* USB data will be immediately processed, this allow next USB traffic being NAKed till the end of the application Xfer */ - usbd_cdc_receive(usbd->cdc, len); + return 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; + return usbd_cdc_receive(usbd->cdc2, len); + #endif } else if ((usbd->usbd_mode & USBD_MODE_MSC) && epnum == (MSC_OUT_EP & 0x7f)) { MSC_BOT_DataOut(pdev, epnum); From 98f790b03aeba3fca6b87716ecadd076bed0c506 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stig=20Bj=C3=B8rlykke?= Date: Tue, 25 Sep 2018 21:41:17 +0200 Subject: [PATCH 0046/1788] nrf/timer: Fix disabling Timer 1 when using soft PWM. Don't exclude the Timer instance 1 entry from machine_timer_obj[] when using soft PWM. The usage is already checked when creating the Timer, so just create an empty entry. --- ports/nrf/modules/machine/timer.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ports/nrf/modules/machine/timer.c b/ports/nrf/modules/machine/timer.c index e5e84a688d..4b7c995397 100644 --- a/ports/nrf/modules/machine/timer.c +++ b/ports/nrf/modules/machine/timer.c @@ -53,7 +53,9 @@ STATIC mp_obj_t machine_timer_callbacks[] = { STATIC const machine_timer_obj_t machine_timer_obj[] = { {{&machine_timer_type}, NRFX_TIMER_INSTANCE(0)}, -#if !defined(MICROPY_PY_MACHINE_SOFT_PWM) || (MICROPY_PY_MACHINE_SOFT_PWM == 0) +#if MICROPY_PY_MACHINE_SOFT_PWM + { }, +#else {{&machine_timer_type}, NRFX_TIMER_INSTANCE(1)}, #endif {{&machine_timer_type}, NRFX_TIMER_INSTANCE(2)}, From 6a95e74387725e77ea368769ff53e03042ce7869 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 29 Jan 2019 22:22:47 +1100 Subject: [PATCH 0047/1788] esp32: Use SPIRAM in mem-map mode so all of it can be used for uPy heap. Also enable CONFIG_SPIRAM_IGNORE_NOTFOUND to allow boards with faulty or missing SPIRAM to still boot. --- ports/esp32/boards/sdkconfig.spiram | 2 ++ ports/esp32/main.c | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/ports/esp32/boards/sdkconfig.spiram b/ports/esp32/boards/sdkconfig.spiram index 4154b5e42e..f2ed44c5de 100644 --- a/ports/esp32/boards/sdkconfig.spiram +++ b/ports/esp32/boards/sdkconfig.spiram @@ -13,6 +13,8 @@ CONFIG_LOG_BOOTLOADER_LEVEL_WARN=y # ESP32-specific CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y CONFIG_SPIRAM_SUPPORT=y +CONFIG_SPIRAM_IGNORE_NOTFOUND=y +CONFIG_SPIRAM_USE_MEMMAP=y CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=n CONFIG_ESP32_XTAL_FREQ_AUTO=y diff --git a/ports/esp32/main.c b/ports/esp32/main.c index 01d22d3e75..a304dcbccf 100644 --- a/ports/esp32/main.c +++ b/ports/esp32/main.c @@ -37,6 +37,7 @@ #include "esp_task.h" #include "soc/cpu.h" #include "esp_log.h" +#include "esp_spiram.h" #include "py/stackctrl.h" #include "py/nlr.h" @@ -69,9 +70,29 @@ void mp_task(void *pvParameter) { #endif uart_init(); + #if CONFIG_SPIRAM_SUPPORT + // Try to use the entire external SPIRAM directly for the heap + size_t mp_task_heap_size; + void *mp_task_heap = (void*)0x3f800000; + switch (esp_spiram_get_chip_size()) { + case ESP_SPIRAM_SIZE_16MBITS: + mp_task_heap_size = 2 * 1024 * 1024; + break; + case ESP_SPIRAM_SIZE_32MBITS: + case ESP_SPIRAM_SIZE_64MBITS: + mp_task_heap_size = 4 * 1024 * 1024; + break; + default: + // No SPIRAM, fallback to normal allocation + mp_task_heap_size = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT); + mp_task_heap = malloc(mp_task_heap_size); + break; + } + #else // 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); + #endif soft_reset: // initialise the stack pointer for the main thread From 8fea833e3fefe1af94562b2a72c0e154d42424c6 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 31 Jan 2019 11:55:21 +0300 Subject: [PATCH 0048/1788] py: Update my copyright info on some files. Based on git history. --- py/objstr.c | 2 +- py/objstringio.c | 2 +- py/objstrunicode.c | 2 +- py/objtuple.c | 1 + py/objtype.c | 2 +- py/runtime.c | 1 + py/stream.c | 4 ++-- py/vm.c | 2 +- py/warning.c | 1 + 9 files changed, 10 insertions(+), 7 deletions(-) diff --git a/py/objstr.c b/py/objstr.c index 1b12147fdd..5764c5ae32 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -4,7 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George - * Copyright (c) 2014 Paul Sokolovsky + * Copyright (c) 2014-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 diff --git a/py/objstringio.c b/py/objstringio.c index b405ee21e3..eca7ca9470 100644 --- a/py/objstringio.c +++ b/py/objstringio.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 diff --git a/py/objstrunicode.c b/py/objstrunicode.c index 13da922a80..eac7171175 100644 --- a/py/objstrunicode.c +++ b/py/objstrunicode.c @@ -4,7 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George - * Copyright (c) 2014 Paul Sokolovsky + * Copyright (c) 2014-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 diff --git a/py/objtuple.c b/py/objtuple.c index 34b7664ebb..e570a7fb16 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George + * 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 diff --git a/py/objtype.c b/py/objtype.c index fec73f16ee..68ee74cf5e 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -4,7 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013-2018 Damien P. George - * Copyright (c) 2014-2016 Paul Sokolovsky + * Copyright (c) 2014-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 diff --git a/py/runtime.c b/py/runtime.c index c1e0478135..5a9e383ff3 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014-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 diff --git a/py/stream.c b/py/stream.c index 2a9acdea77..762cd0fc08 100644 --- a/py/stream.c +++ b/py/stream.c @@ -3,8 +3,8 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George - * Copyright (c) 2014 Paul Sokolovsky + * Copyright (c) 2014 Damien P. George + * Copyright (c) 2014-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 diff --git a/py/vm.c b/py/vm.c index fce59349f0..d8d287f25a 100644 --- a/py/vm.c +++ b/py/vm.c @@ -4,7 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George - * Copyright (c) 2014 Paul Sokolovsky + * Copyright (c) 2014-2015 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 diff --git a/py/warning.c b/py/warning.c index ebaf2d0783..cba21ba6c9 100644 --- a/py/warning.c +++ b/py/warning.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2014 Damien P. George + * Copyright (c) 2015-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 From ec31438c545a0fadfe7b0107779d7fbc1a0eb646 Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Mon, 4 Feb 2019 23:23:15 +0200 Subject: [PATCH 0049/1788] py/builtinhelp: Only print help re FS modules if external import enabled --- py/builtinhelp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/py/builtinhelp.c b/py/builtinhelp.c index b36f4c9d33..3b0ad71e64 100644 --- a/py/builtinhelp.c +++ b/py/builtinhelp.c @@ -123,8 +123,10 @@ STATIC void mp_help_print_modules(void) { mp_print_str(MP_PYTHON_PRINTER, "\n"); } + #if MICROPY_ENABLE_EXTERNAL_IMPORT // let the user know there may be other modules available from the filesystem mp_print_str(MP_PYTHON_PRINTER, "Plus any modules on the filesystem\n"); + #endif } #endif From 343401c6dfdb92894d0364de53963bd98b3c4caf Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Sun, 3 Feb 2019 21:24:16 +0200 Subject: [PATCH 0050/1788] py/mpconfig.h: Fix comments mentioning dangling file and variable names. --- py/mpconfig.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/py/mpconfig.h b/py/mpconfig.h index 4fd08db230..95abacafdd 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -1331,17 +1331,17 @@ typedef double mp_float_t; /*****************************************************************************/ /* Hooks for a port to add builtins */ -// Additional builtin function definitions - see builtintables.c:builtin_object_table for format. +// Additional builtin function definitions - see modbuiltins.c:mp_module_builtins_globals_table for format. #ifndef MICROPY_PORT_BUILTINS #define MICROPY_PORT_BUILTINS #endif -// Additional builtin module definitions - see builtintables.c:builtin_module_table for format. +// Additional builtin module definitions - see objmodule.c:mp_builtin_module_table for format. #ifndef MICROPY_PORT_BUILTIN_MODULES #define MICROPY_PORT_BUILTIN_MODULES #endif -// Any module weak links - see builtintables.c:mp_builtin_module_weak_links_table. +// Any module weak links - see objmodule.c:mp_builtin_module_weak_links_table. #ifndef MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS #define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS #endif From 7bbde67cb2dc52c04bd7020689a1227bddfa1b06 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 6 Feb 2019 01:12:51 +1100 Subject: [PATCH 0051/1788] lib/utils/printf: Exclude __GI_vsnprintf alias for gcc 9 and above. See issue #4457. --- lib/utils/printf.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/utils/printf.c b/lib/utils/printf.c index 1ceeea39ff..0c21fc4c0a 100644 --- a/lib/utils/printf.c +++ b/lib/utils/printf.c @@ -99,9 +99,11 @@ STATIC void strn_print_strn(void *data, const char *str, size_t len) { strn_print_env->remain -= len; } -#if defined(__GNUC__) && !defined(__clang__) +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 9 // uClibc requires this alias to be defined, or there may be link errors // when linkings against it statically. +// GCC 9 gives a warning about missing attributes so it's excluded until +// uClibc+GCC9 support is needed. int __GI_vsnprintf(char *str, size_t size, const char *fmt, va_list ap) __attribute__((weak, alias ("vsnprintf"))); #endif From 02682d52cee5aa680ef6bb300f1b34c6f31fa167 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 6 Feb 2019 13:34:23 +1100 Subject: [PATCH 0052/1788] stm32/boards/make-pins.py: Add basic support for STM32H7 ADC periphs. --- ports/stm32/boards/make-pins.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/ports/stm32/boards/make-pins.py b/ports/stm32/boards/make-pins.py index a7051b7a2f..89c393217d 100755 --- a/ports/stm32/boards/make-pins.py +++ b/ports/stm32/boards/make-pins.py @@ -165,11 +165,28 @@ class Pin(object): def parse_adc(self, adc_str): if (adc_str[:3] != 'ADC'): return - (adc,channel) = adc_str.split('_') + + if adc_str.find('_INP') != -1: + # STM32H7xx, entries have the form: ADCxx_IN[PN]yy/... + # for now just pick the entry with the most ADC periphs + adc, channel = None, None + for ss in adc_str.split('/'): + if ss.find('_INP') != -1: + a, c = ss.split('_') + if adc is None or len(a) > len(adc): + adc, channel = a, c + if adc is None: + return + channel = channel[3:] + else: + # all other MCUs, entries have the form: ADCxx_INyy + adc, channel = adc_str.split('_') + channel = channel[2:] + for idx in range(3, len(adc)): adc_num = int(adc[idx]) # 1, 2, or 3 self.adc_num |= (1 << (adc_num - 1)) - self.adc_channel = int(channel[2:]) + self.adc_channel = int(channel) def parse_af(self, af_idx, af_strs_in): if len(af_strs_in) == 0: From b367c425e40f3792dba625a33a625e345cec723c Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 6 Feb 2019 13:34:53 +1100 Subject: [PATCH 0053/1788] stm32/boards/stm32h743_af.csv: Add ADC entries to pin capability table. --- ports/stm32/boards/stm32h743_af.csv | 64 ++++++++++++++--------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/ports/stm32/boards/stm32h743_af.csv b/ports/stm32/boards/stm32h743_af.csv index d008ba68b6..32e67e2bdc 100644 --- a/ports/stm32/boards/stm32h743_af.csv +++ b/ports/stm32/boards/stm32h743_af.csv @@ -1,13 +1,13 @@ Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15, ,,SYS,TIM1/2/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/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, -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,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,ADC1_INP16/ADC12_INN1/ADC12_INP0 +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,ADC1_INN16/ADC1_INP17/ADC12_INP1 +PortA,PA2,,TIM2_CH3,TIM5_CH3,LPTIM4_OUT,TIM15_CH1,,,USART2_TX,SAI2_SCK_B,,,ETH_MDIO,MDIOS_MDIO,,LCD_R1,EVENTOUT,ADC12_INP14 +PortA,PA3,,TIM2_CH4,TIM5_CH4,LPTIM5_OUT,TIM15_CH2,,,USART2_RX,,LCD_B2,OTG_HS_ULPI_D0,ETH_MII_COL,,,LCD_B5,EVENTOUT,ADC12_INP15 +PortA,PA4,,,TIM5_ETR,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART2_CK,SPI6_NSS,,,,OTG_HS_SOF,DCMI_HSYNC,LCD_VSYNC,EVENTOUT,ADC12_INP18 +PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK/I2S1_CK,,,SPI6_SCK,,OTG_HS_ULPI_CK,,,,LCD_R4,EVENTOUT,ADC12_INN18/ADC12_INP19 +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,ADC12_INP3 +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,ADC12_INN3/ADC12_INP7 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, @@ -16,8 +16,8 @@ PortA,PA12,,TIM1_ETR,HRTIM_CHD2,LPUART1_RTS,,SPI2_SCK/I2S2_CK,UART4_TX,USART1_RT 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,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,DFSDM_CKOUT,,UART4_CTS,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,LCD_G1,EVENTOUT,ADC12_INN5/ADC12_INP9 +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM_DATIN1,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,LCD_G0,EVENTOUT,ADC12_INP5 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, @@ -32,12 +32,12 @@ PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,DFSDM_DATIN1,USART3_CK,,CAN2_ 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, -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,PC0,,,,DFSDM_CKIN0,,,DFSDM_DATIN4,,SAI2_FS_B,,OTG_HS_ULPI_STP,,FMC_SDNWE,,LCD_R5,EVENTOUT,ADC123_INP10 +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,ADC123_INN10/ADC123_INP11 +PortC,PC2,,,,DFSDM_CKIN1,,SPI2_MISO/I2S2_SDI,DFSDM_CKOUT,,,,OTG_HS_ULPI_DIR,ETH_MII_TXD2,FMC_SDNE0,,,EVENTOUT,ADC123_INN11/ADC123_INP12/ADC3_INN1/ADC3_INP0 +PortC,PC3,,,,DFSDM_DATIN1,,SPI2_MOSI/I2S2_SDO,,,,,OTG_HS_ULPI_NXT,ETH_MII_TX_CLK,FMC_SDCKE0,,,EVENTOUT,ADC12_INN12/ADC12_INP13/ADC3_INP1 +PortC,PC4,,,,DFSDM_CKIN2,,I2S1_MCK,,,,SPDIFRX_IN2,,ETH_MII_RXD0/ETH_RMII_RXD0,FMC_SDNE0,,,EVENTOUT,ADC12_INP4 +PortC,PC5,,,SAI1_D3,DFSDM_DATIN2,,,,,,SPDIFRX_IN3,SAI4_D3,ETH_MII_RXD1/ETH_RMII_RXD1,FMC_SDCKE0,COMP_1_OUT,,EVENTOUT,ADC12_INN4/ADC12_INP8 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, @@ -83,18 +83,18 @@ PortE,PE15,,TIM1_BKIN,,,,HDMI__TIM1_BKIN,,,,,,,FMC_D12/FMC_DA12,TIM1_BKIN_COMP12 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,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT,ADC3_INP5 +PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT,ADC3_INN5/ADC3_INP9 +PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT,ADC3_INP4 +PortF,PF6,,TIM16_CH1,,,,SPI5_NSS,SAI1_SD_B,UART7_RX,SAI4_SD_B,QUADSPI_BK1_IO3,,,,,,EVENTOUT,ADC3_INN4/ADC3_INP8 +PortF,PF7,,TIM17_CH1,,,,SPI5_SCK,SAI1_MCLK_B,UART7_TX,SAI4_MCLK_B,QUADSPI_BK1_IO2,,,,,,EVENTOUT,ADC3_INP3 +PortF,PF8,,TIM16_CH1N,,,,SPI5_MISO,SAI1_SCK_B,UART7_RTS,SAI4_SCK_B,TIM13_CH1,QUADSPI_BK1_IO0,,,,,EVENTOUT,ADC3_INN3/ADC3_INP7 +PortF,PF9,,TIM17_CH1N,,,,SPI5_MOSI,SAI1_FS_B,UART7_CTS,SAI4_FS_B,TIM14_CH1,QUADSPI_BK1_IO1,,,,,EVENTOUT,ADC3_INP2 +PortF,PF10,,TIM16_BKIN,SAI1_D3,,,,,,,QUADSPI_CLK,SAI4_D3,,,DCMI_D11,LCD_DE,EVENTOUT,ADC3_INN2/ADC3_INP6 +PortF,PF11,,,,,,SPI5_MOSI,,,,,SAI2_SD_B,,FMC_SDNRAS,DCMI_D12,,EVENTOUT,ADC1_INP2 +PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT,ADC1_INN2/DC1_INP6 +PortF,PF13,,,,DFSDM_DATIN6,I2C4_SMBA,,,,,,,,FMC_A7,,,EVENTOUT,ACD2_INP2 +PortF,PF14,,,,DFSDM_CKIN6,I2C4_SCL,,,,,,,,FMC_A8,,,EVENTOUT,ADC2_INN2/ADC2_INP6 PortF,PF15,,,,,I2C4_SDA,,,,,,,,FMC_A9,,,EVENTOUT, PortG,PG0,,,,,,,,,,,,,FMC_A10,,,EVENTOUT, PortG,PG1,,,,,,,,,,,,,FMC_A11,,,EVENTOUT, @@ -114,10 +114,10 @@ PortG,PG14,TRACED1,LPTIM1_ETR,,,,SPI6_MOSI,,USART6_TX,,QUADSPI_BK2_IO3,,ETH_MII_ 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, -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,PH2,,LPTIM1_IN2,,,,,,,,QUADSPI_BK2_IO0,SAI2_SCK_B,ETH_MII_CRS,FMC_SDCKE0,,LCD_R0,EVENTOUT,ADC3_INP13 +PortH,PH3,,,,,,,,,,QUADSPI_BK2_IO1,SAI2_MCK_B,ETH_MII_COL,FMC_SDNE0,,LCD_R1,EVENTOUT,ADC3_INN13/ADC3_INP14 +PortH,PH4,,,,,I2C2_SCL,,,,,LCD_G5,OTG_HS_ULPI_NXT,,,,LCD_G4,EVENTOUT,ADC3_INN14/ADC3_INP15 +PortH,PH5,,,,,I2C2_SDA,SPI5_NSS,,,,,,,FMC_SDNWE,,,EVENTOUT,ADC3_INN15/ADC3_INP16 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, From 43a894fb4807ad9ec25569952c0dcd9fd5525a87 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 6 Feb 2019 13:35:28 +1100 Subject: [PATCH 0054/1788] stm32/adc: Add basic support for ADC on a pin on STM32H7 MCUs. --- ports/stm32/adc.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index 35a8ff7883..376b48d4ed 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -51,11 +51,17 @@ /// val = adc.read_core_vref() # read MCU VREF /* ADC defintions */ + #if defined(STM32H7) #define ADCx (ADC3) +#define PIN_ADC_MASK PIN_ADC3 +#define pin_adc_table pin_adc3 #else #define ADCx (ADC1) +#define PIN_ADC_MASK PIN_ADC1 +#define pin_adc_table pin_adc1 #endif + #define ADCx_CLK_ENABLE __HAL_RCC_ADC1_CLK_ENABLE #define ADC_NUM_CHANNELS (19) @@ -280,7 +286,7 @@ 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]; + const pin_obj_t *pin = pin_adc_table[adc_obj->channel]; mp_hal_pin_config(pin, MP_HAL_PIN_MODE_ADC, MP_HAL_PIN_PULL_NONE, 0); } @@ -393,7 +399,7 @@ STATIC mp_obj_t adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ channel = adc_get_internal_channel(mp_obj_get_int(pin_obj)); } else { const pin_obj_t *pin = pin_find(pin_obj); - if ((pin->adc_num & PIN_ADC1) == 0) { + if ((pin->adc_num & PIN_ADC_MASK) == 0) { // No ADC1 function on that pin nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin %q does not have ADC capabilities", pin->name)); } @@ -407,7 +413,7 @@ STATIC mp_obj_t adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ if (ADC_FIRST_GPIO_CHANNEL <= channel && channel <= ADC_LAST_GPIO_CHANNEL) { // these channels correspond to physical GPIO ports so make sure they exist - if (pin_adc1[channel] == NULL) { + if (pin_adc_table[channel] == NULL) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "channel %d not available on this board", channel)); } @@ -690,7 +696,7 @@ void adc_init_all(pyb_adc_all_obj_t *adc_all, uint32_t resolution, uint32_t en_m if (en_mask & (1 << channel)) { // Channels 0-16 correspond to real pins. Configure the GPIO pin in // ADC mode. - const pin_obj_t *pin = pin_adc1[channel]; + const pin_obj_t *pin = pin_adc_table[channel]; if (pin) { mp_hal_pin_config(pin, MP_HAL_PIN_MODE_ADC, MP_HAL_PIN_PULL_NONE, 0); } From 9570297dd11949e9510468555daf8acafeee51da Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 7 Feb 2019 16:03:18 +1100 Subject: [PATCH 0055/1788] stm32/mboot: Use USB HS as main USB device regardless of USB_HS_IN_FS. --- ports/stm32/mboot/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/mboot/main.c b/ports/stm32/mboot/main.c index 70ea512ba1..6113d80ef2 100644 --- a/ports/stm32/mboot/main.c +++ b/ports/stm32/mboot/main.c @@ -62,7 +62,7 @@ #if !defined(MICROPY_HW_USB_MAIN_DEV) #if MICROPY_HW_USB_FS #define MICROPY_HW_USB_MAIN_DEV (USB_PHY_FS_ID) -#elif MICROPY_HW_USB_HS && MICROPY_HW_USB_HS_IN_FS +#elif MICROPY_HW_USB_HS #define MICROPY_HW_USB_MAIN_DEV (USB_PHY_HS_ID) #else #error Unable to determine proper MICROPY_HW_USB_MAIN_DEV to use From 39eb1e9f81200422095b1dd1a56d0311e7300978 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 7 Feb 2019 16:04:06 +1100 Subject: [PATCH 0056/1788] stm32/mboot: Add support for STM32F769 MCUs. --- ports/stm32/mboot/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/mboot/main.c b/ports/stm32/mboot/main.c index 6113d80ef2..b040d4bac8 100644 --- a/ports/stm32/mboot/main.c +++ b/ports/stm32/mboot/main.c @@ -369,7 +369,7 @@ static const flash_layout_t flash_layout[] = { #endif }; -#elif defined(STM32F765xx) || defined(STM32F767xx) +#elif defined(STM32F765xx) || defined(STM32F767xx) || defined(STM32F769xx) #define FLASH_LAYOUT_STR "@Internal Flash /0x08000000/04*032Kg,01*128Kg,07*256Kg" MBOOT_SPIFLASH_LAYOUT MBOOT_SPIFLASH2_LAYOUT From a81cb3576bba0387365d4462e3f44ac7e099bf6d Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 7 Feb 2019 16:04:48 +1100 Subject: [PATCH 0057/1788] stm32/mboot: Add support for GPIO ports G, H, I and J. --- ports/stm32/mboot/mphalport.h | 68 +++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/ports/stm32/mboot/mphalport.h b/ports/stm32/mboot/mphalport.h index 2cf7c243e9..42b1dcc8b6 100644 --- a/ports/stm32/mboot/mphalport.h +++ b/ports/stm32/mboot/mphalport.h @@ -153,3 +153,71 @@ void mp_hal_pin_config_speed(uint32_t port_pin, uint32_t speed); #define pin_F13 (GPIOF_BASE | 13) #define pin_F14 (GPIOF_BASE | 14) #define pin_F15 (GPIOF_BASE | 15) + +#define pin_G0 (GPIOG_BASE | 0) +#define pin_G1 (GPIOG_BASE | 1) +#define pin_G2 (GPIOG_BASE | 2) +#define pin_G3 (GPIOG_BASE | 3) +#define pin_G4 (GPIOG_BASE | 4) +#define pin_G5 (GPIOG_BASE | 5) +#define pin_G6 (GPIOG_BASE | 6) +#define pin_G7 (GPIOG_BASE | 7) +#define pin_G8 (GPIOG_BASE | 8) +#define pin_G9 (GPIOG_BASE | 9) +#define pin_G10 (GPIOG_BASE | 10) +#define pin_G11 (GPIOG_BASE | 11) +#define pin_G12 (GPIOG_BASE | 12) +#define pin_G13 (GPIOG_BASE | 13) +#define pin_G14 (GPIOG_BASE | 14) +#define pin_G15 (GPIOG_BASE | 15) + +#define pin_H0 (GPIOH_BASE | 0) +#define pin_H1 (GPIOH_BASE | 1) +#define pin_H2 (GPIOH_BASE | 2) +#define pin_H3 (GPIOH_BASE | 3) +#define pin_H4 (GPIOH_BASE | 4) +#define pin_H5 (GPIOH_BASE | 5) +#define pin_H6 (GPIOH_BASE | 6) +#define pin_H7 (GPIOH_BASE | 7) +#define pin_H8 (GPIOH_BASE | 8) +#define pin_H9 (GPIOH_BASE | 9) +#define pin_H10 (GPIOH_BASE | 10) +#define pin_H11 (GPIOH_BASE | 11) +#define pin_H12 (GPIOH_BASE | 12) +#define pin_H13 (GPIOH_BASE | 13) +#define pin_H14 (GPIOH_BASE | 14) +#define pin_H15 (GPIOH_BASE | 15) + +#define pin_I0 (GPIOI_BASE | 0) +#define pin_I1 (GPIOI_BASE | 1) +#define pin_I2 (GPIOI_BASE | 2) +#define pin_I3 (GPIOI_BASE | 3) +#define pin_I4 (GPIOI_BASE | 4) +#define pin_I5 (GPIOI_BASE | 5) +#define pin_I6 (GPIOI_BASE | 6) +#define pin_I7 (GPIOI_BASE | 7) +#define pin_I8 (GPIOI_BASE | 8) +#define pin_I9 (GPIOI_BASE | 9) +#define pin_I10 (GPIOI_BASE | 10) +#define pin_I11 (GPIOI_BASE | 11) +#define pin_I12 (GPIOI_BASE | 12) +#define pin_I13 (GPIOI_BASE | 13) +#define pin_I14 (GPIOI_BASE | 14) +#define pin_I15 (GPIOI_BASE | 15) + +#define pin_J0 (GPIOJ_BASE | 0) +#define pin_J1 (GPIOJ_BASE | 1) +#define pin_J2 (GPIOJ_BASE | 2) +#define pin_J3 (GPIOJ_BASE | 3) +#define pin_J4 (GPIOJ_BASE | 4) +#define pin_J5 (GPIOJ_BASE | 5) +#define pin_J6 (GPIOJ_BASE | 6) +#define pin_J7 (GPIOJ_BASE | 7) +#define pin_J8 (GPIOJ_BASE | 8) +#define pin_J9 (GPIOJ_BASE | 9) +#define pin_J10 (GPIOJ_BASE | 10) +#define pin_J11 (GPIOJ_BASE | 11) +#define pin_J12 (GPIOJ_BASE | 12) +#define pin_J13 (GPIOJ_BASE | 13) +#define pin_J14 (GPIOJ_BASE | 14) +#define pin_J15 (GPIOJ_BASE | 15) From 03a8b1cc5033f78b9d7ed991a02cb5ab78cbeccc Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 7 Feb 2019 16:06:05 +1100 Subject: [PATCH 0058/1788] stm32/mboot: Allow deploying via deploy-stlink. --- ports/stm32/mboot/Makefile | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ports/stm32/mboot/Makefile b/ports/stm32/mboot/Makefile index e892f91408..fa8b2a3d8e 100644 --- a/ports/stm32/mboot/Makefile +++ b/ports/stm32/mboot/Makefile @@ -115,13 +115,17 @@ $(TOP)/lib/stm32lib/README.md: $(ECHO) "stm32lib submodule not found, fetching it now..." (cd $(TOP) && git submodule update --init lib/stm32lib) -.PHONY: deploy +.PHONY: deploy deploy-stlink + +FLASH_ADDR = 0x08000000 deploy: $(BUILD)/firmware.dfu $(ECHO) "Writing $< to the board" $(Q)$(PYTHON) $(PYDFU) -u $< -FLASH_ADDR = 0x08000000 +deploy-stlink: $(BUILD)/firmware.dfu + $(ECHO) "Writing $< to the board via ST-LINK" + $(Q)$(STFLASH) write $(BUILD)/firmware.bin $(FLASH_ADDR) $(BUILD)/firmware.dfu: $(BUILD)/firmware.elf $(ECHO) "Create $@" From 9f9c5c19b0a923741db342bf1e4505851554ee89 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 7 Feb 2019 16:09:08 +1100 Subject: [PATCH 0059/1788] stm32/usb: Use USB HS as main USB device regardless of USB_HS_IN_FS. --- 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 a5be6cd77d..1ff62b4ab5 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -48,7 +48,7 @@ #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) +#elif defined(MICROPY_HW_USB_HS) #define MICROPY_HW_USB_MAIN_DEV (USB_PHY_HS_ID) #else #error Unable to determine proper MICROPY_HW_USB_MAIN_DEV to use From ab423f29692b6fe9d1d7ae4c2a9ae1af81acfedb Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 7 Feb 2019 16:09:25 +1100 Subject: [PATCH 0060/1788] stm32/usbd_conf: Fully support USB HS with external PHY. --- ports/stm32/usbd_conf.c | 137 +++++++++++----------------------------- 1 file changed, 36 insertions(+), 101 deletions(-) diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c index 3068a822e3..48af633cb7 100644 --- a/ports/stm32/usbd_conf.c +++ b/ports/stm32/usbd_conf.c @@ -137,63 +137,21 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) { #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); + static const mp_hal_pin_obj_t usb_pins[] = { + pin_A5, pin_C0, pin_H4, pin_I11, // CLK, STP, NXT, DIR + pin_A3, pin_B0, pin_B1, pin_B5, pin_B10, pin_B11, pin_B12, pin_B13, // D0-D7 + }; + for (size_t i = 0; i < MP_ARRAY_SIZE(usb_pins); ++i) { + mp_hal_pin_config(usb_pins[i], MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, GPIO_AF10_OTG_HS); + mp_hal_pin_config_speed(usb_pins[i], GPIO_SPEED_FREQ_VERY_HIGH); + } // Enable USB HS Clocks - __USB_OTG_HS_CLK_ENABLE(); - __USB_OTG_HS_ULPI_CLK_ENABLE(); + __HAL_RCC_USB_OTG_HS_CLK_ENABLE(); + __HAL_RCC_USB_OTG_HS_CLK_SLEEP_ENABLE(); + __HAL_RCC_USB_OTG_HS_ULPI_CLK_ENABLE(); + __HAL_RCC_USB_OTG_HS_ULPI_CLK_SLEEP_ENABLE(); #endif // !MICROPY_HW_USB_HS_IN_FS @@ -419,8 +377,6 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { #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 = 6; @@ -430,23 +386,36 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { 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 - pcd_hs_handle.Init.phy_itface = PCD_PHY_EMBEDDED; - #endif pcd_hs_handle.Init.Sof_enable = 0; - if (high_speed) { - pcd_hs_handle.Init.speed = PCD_SPEED_HIGH; - } else { - pcd_hs_handle.Init.speed = PCD_SPEED_HIGH_IN_FULL; - } + pcd_hs_handle.Init.use_external_vbus = 0; + #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; + + #if MICROPY_HW_USB_HS_IN_FS + + #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 + + if (high_speed) { + pcd_hs_handle.Init.speed = PCD_SPEED_HIGH; + } else { + pcd_hs_handle.Init.speed = PCD_SPEED_HIGH_IN_FULL; + } + + #else + + // USB HS with external PHY + pcd_hs_handle.Init.phy_itface = PCD_PHY_ULPI; + pcd_hs_handle.Init.speed = PCD_SPEED_HIGH; + + #endif // Link The driver to the stack pcd_hs_handle.pData = pdev; @@ -463,40 +432,6 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { HAL_PCD_SetTxFiFo(&pcd_hs_handle, 3, 128); // CDC DATA HAL_PCD_SetTxFiFo(&pcd_hs_handle, 4, 8); // CDC2 CMD HAL_PCD_SetTxFiFo(&pcd_hs_handle, 5, 128); // CDC2 DATA - - #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 = 0; - 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 From b26046aca2f2abb357f454974f69bc4fa8e4afab Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 7 Feb 2019 16:13:57 +1100 Subject: [PATCH 0061/1788] stm32/modmachine: Make bootloader() enter custom loader if it's enabled. If a custom bootloader is enabled (eg mboot) then machine.bootloader() will now enter that loader. To get the original ST DFU loader pass any argument to the function, like machine.bootloader(1). --- ports/stm32/modmachine.c | 16 ++++++++++++++-- ports/stm32/modmachine.h | 2 +- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index e14753bfe9..3c60378ffd 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -247,7 +247,7 @@ STATIC mp_obj_t machine_soft_reset(void) { 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) { +STATIC NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args) { #if MICROPY_HW_ENABLE_USB pyb_usb_dev_deinit(); #endif @@ -263,6 +263,18 @@ STATIC NORETURN mp_obj_t machine_bootloader(void) { HAL_MPU_Disable(); #endif + #if MICROPY_HW_USES_BOOTLOADER + if (n_args == 0 || !mp_obj_is_true(args[0])) { + // By default, with no args given, we enter the custom bootloader (mboot) + #if __DCACHE_PRESENT == 1 + SCB_DisableICache(); + SCB_DisableDCache(); + #endif + __set_MSP(*(volatile uint32_t*)0x08000000); + ((void (*)(uint32_t)) *((volatile uint32_t*)(0x08000000 + 4)))(0x70ad0000); + } + #endif + #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. @@ -283,7 +295,7 @@ STATIC NORETURN mp_obj_t machine_bootloader(void) { while (1); } -MP_DEFINE_CONST_FUN_OBJ_0(machine_bootloader_obj, machine_bootloader); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_bootloader_obj, 0, 1, machine_bootloader); // get or set the MCU frequencies STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { diff --git a/ports/stm32/modmachine.h b/ports/stm32/modmachine.h index f105bbeec3..414e5b37c7 100644 --- a/ports/stm32/modmachine.h +++ b/ports/stm32/modmachine.h @@ -34,7 +34,7 @@ void machine_deinit(void); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_info_obj); MP_DECLARE_CONST_FUN_OBJ_0(machine_unique_id_obj); MP_DECLARE_CONST_FUN_OBJ_0(machine_reset_obj); -MP_DECLARE_CONST_FUN_OBJ_0(machine_bootloader_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_bootloader_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_freq_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_lightsleep_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_deepsleep_obj); From be1b1835c339bf67b177f64aab7479c07c2d3418 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 7 Feb 2019 16:26:46 +1100 Subject: [PATCH 0062/1788] stm32/boards/STM32F769DISC: Support the use of USB HS with external PHY. --- ports/stm32/boards/STM32F769DISC/mpconfigboard.h | 7 ++----- ports/stm32/boards/STM32F769DISC/pins.csv | 12 ++++++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h index d31a22b0c0..4f41a81f9e 100644 --- a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h @@ -73,11 +73,8 @@ #define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP) #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) +// USB config (CN15 - USB OTG HS with external PHY) +#define MICROPY_HW_USB_HS (1) #if 0 // Optional SDRAM configuration; requires SYSCLK <= 200MHz diff --git a/ports/stm32/boards/STM32F769DISC/pins.csv b/ports/stm32/boards/STM32F769DISC/pins.csv index 6b6308c9a0..f587d44c14 100644 --- a/ports/stm32/boards/STM32F769DISC/pins.csv +++ b/ports/stm32/boards/STM32F769DISC/pins.csv @@ -51,6 +51,18 @@ USB_VBUS,PJ12 USB_ID,PA8 USB_DM,PA11 USB_DP,PA12 +USB_HS_CLK,PA5 +USB_HS_STP,PC0 +USB_HS_NXT,PH4 +USB_HS_DIR,PI11 +USB_HS_D0,PA3 +USB_HS_D1,PB0 +USB_HS_D2,PB1 +USB_HS_D3,PB5 +USB_HS_D4,PB10 +USB_HS_D5,PB11 +USB_HS_D6,PB12 +USB_HS_D7,PB13 UART1_TX,PA9 UART1_RX,PA10 UART5_TX,PC12 From 1669e049de23cd52b27a5f201b26398590806a78 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 7 Feb 2019 16:28:01 +1100 Subject: [PATCH 0063/1788] stm32/boards/STM32F769DISC: Configure for use with mboot by default. This is a good board to demonstrate the use of Mboot because it only has a USB HS port exposed so the native ST DFU mode cannot be used. With Mboot this port can be used. --- ports/stm32/boards/STM32F769DISC/mpconfigboard.mk | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk index 873368ce5d..7a0dec07a6 100644 --- a/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk @@ -1,7 +1,18 @@ +# By default this board is configured to use mboot which must be deployed first +USE_MBOOT ?= 1 + MCU_SERIES = f7 CMSIS_MCU = STM32F769xx MICROPY_FLOAT_IMPL = double AF_FILE = boards/stm32f767_af.csv + +ifeq ($(USE_MBOOT),1) +# When using Mboot all the text goes together after the filesystem +LD_FILES = boards/stm32f769.ld boards/common_blifs.ld +TEXT0_ADDR = 0x08020000 +else +# When not using Mboot the ISR text goes first, then the rest after the filesystem LD_FILES = boards/stm32f769.ld boards/common_ifs.ld TEXT0_ADDR = 0x08000000 TEXT1_ADDR = 0x08020000 +endif From c33f53806630fcfa471dfc2c8338f79b5d820708 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 5 Feb 2019 23:26:01 +1100 Subject: [PATCH 0064/1788] esp32/modmachine: Add support for changing the CPU frequency. --- ports/esp32/Makefile | 1 + ports/esp32/boards/sdkconfig | 3 +++ ports/esp32/boards/sdkconfig.spiram | 3 +++ ports/esp32/modmachine.c | 23 ++++++++++++++++------- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 15073453ac..068757834e 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -292,6 +292,7 @@ ESPIDF_ESP32_O = $(addprefix $(ESPCOMP)/esp32/,\ hw_random.o \ phy_init.o \ pm_esp32.o \ + pm_locks.o \ intr_alloc.o \ dport_access.o \ wifi_init.o \ diff --git a/ports/esp32/boards/sdkconfig b/ports/esp32/boards/sdkconfig index 0453cccbf5..23fc8dead5 100644 --- a/ports/esp32/boards/sdkconfig +++ b/ports/esp32/boards/sdkconfig @@ -15,6 +15,9 @@ CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=n CONFIG_ESP32_XTAL_FREQ_AUTO=y +# Power Management +CONFIG_PM_ENABLE=y + # FreeRTOS CONFIG_FREERTOS_UNICORE=y CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=2 diff --git a/ports/esp32/boards/sdkconfig.spiram b/ports/esp32/boards/sdkconfig.spiram index f2ed44c5de..b34781a0d0 100644 --- a/ports/esp32/boards/sdkconfig.spiram +++ b/ports/esp32/boards/sdkconfig.spiram @@ -18,6 +18,9 @@ CONFIG_SPIRAM_USE_MEMMAP=y CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=n CONFIG_ESP32_XTAL_FREQ_AUTO=y +# Power Management +CONFIG_PM_ENABLE=y + # FreeRTOS CONFIG_FREERTOS_UNICORE=y CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=2 diff --git a/ports/esp32/modmachine.c b/ports/esp32/modmachine.c index be5f2eb0fd..bc459ee5c2 100644 --- a/ports/esp32/modmachine.c +++ b/ports/esp32/modmachine.c @@ -34,7 +34,8 @@ #include "freertos/task.h" #include "rom/ets_sys.h" #include "rom/rtc.h" -#include "esp_system.h" +#include "esp_clk.h" +#include "esp_pm.h" #include "driver/touch_pad.h" #include "py/obj.h" @@ -60,16 +61,24 @@ typedef enum { 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); + return mp_obj_new_int(esp_clk_cpu_freq()); } 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"); + if (freq != 20 && freq != 40 && freq != 80 && freq != 160 && freq != 240) { + mp_raise_ValueError("frequency must be 20MHz, 40MHz, 80Mhz, 160MHz or 240MHz"); + } + esp_pm_config_esp32_t pm; + pm.max_freq_mhz = freq; + pm.min_freq_mhz = freq; + pm.light_sleep_enable = false; + esp_err_t ret = esp_pm_configure(&pm); + if (ret != ESP_OK) { + mp_raise_ValueError(NULL); + } + while (esp_clk_cpu_freq() != freq * 1000000) { + vTaskDelay(1); } - /* - system_update_cpu_freq(freq); - */ return mp_const_none; } } From f024b2610f68109a3a5d8ec2680ca3bafc179344 Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Wed, 6 Feb 2019 00:08:25 +0200 Subject: [PATCH 0065/1788] extmod/moduhashlib: Include implementation of sha256 only when required. Previously crypto-algorithms impl was included even if MICROPY_SSL_MBEDTLS was in effect, thus we relied on the compiler/linker to cut out the unused functions. --- extmod/moduhashlib.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/extmod/moduhashlib.c b/extmod/moduhashlib.c index 50df7ca889..603cdb44a4 100644 --- a/extmod/moduhashlib.c +++ b/extmod/moduhashlib.c @@ -104,6 +104,8 @@ STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) { #else +#include "crypto-algorithms/sha256.c" + 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)); @@ -344,8 +346,4 @@ 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 From 5fbda53d3c43e94a18a66d49a4c315f0af86e204 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 3 Feb 2019 22:52:31 +1100 Subject: [PATCH 0066/1788] stm32/systick: Rename sys_tick_XXX functions to systick_XXX. --- ports/stm32/main.c | 4 ++-- ports/stm32/systick.c | 6 +++--- ports/stm32/systick.h | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 33cfe84eeb..ef0e1e791b 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -229,7 +229,7 @@ MP_NOINLINE STATIC bool init_flash_fs(uint reset_mode) { f_close(&fp); // keep LED on for at least 200ms - sys_tick_wait_at_least(start_tick, 200); + systick_wait_at_least(start_tick, 200); led_state(PYB_LED_GREEN, 0); } else if (res == FR_OK) { // mount sucessful @@ -273,7 +273,7 @@ MP_NOINLINE STATIC bool init_flash_fs(uint reset_mode) { f_close(&fp); // keep LED on for at least 200ms - sys_tick_wait_at_least(start_tick, 200); + systick_wait_at_least(start_tick, 200); led_state(PYB_LED_GREEN, 0); } diff --git a/ports/stm32/systick.c b/ports/stm32/systick.c index c07d0fabce..8b5efe0577 100644 --- a/ports/stm32/systick.c +++ b/ports/stm32/systick.c @@ -90,15 +90,15 @@ void mp_hal_delay_us(mp_uint_t usec) { } } -bool sys_tick_has_passed(uint32_t start_tick, uint32_t delay_ms) { +bool systick_has_passed(uint32_t start_tick, uint32_t delay_ms) { return HAL_GetTick() - start_tick >= delay_ms; } // waits until at least delay_ms milliseconds have passed from the sampling of // startTick. Handles overflow properly. Assumes stc was taken from // HAL_GetTick() some time before calling this function. -void sys_tick_wait_at_least(uint32_t start_tick, uint32_t delay_ms) { - while (!sys_tick_has_passed(start_tick, delay_ms)) { +void systick_wait_at_least(uint32_t start_tick, uint32_t delay_ms) { + while (!systick_has_passed(start_tick, delay_ms)) { __WFI(); // enter sleep mode, waiting for interrupt } } diff --git a/ports/stm32/systick.h b/ports/stm32/systick.h index 256a500c27..abb8729f54 100644 --- a/ports/stm32/systick.h +++ b/ports/stm32/systick.h @@ -26,7 +26,7 @@ #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); +void systick_wait_at_least(uint32_t stc, uint32_t delay_ms); +bool systick_has_passed(uint32_t stc, uint32_t delay_ms); #endif // MICROPY_INCLUDED_STM32_SYSTICK_H From 1bcf4afb10434e8b1e1b73e3e402c48c75f213fc Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 3 Feb 2019 23:00:44 +1100 Subject: [PATCH 0067/1788] stm32/systick: Make periodic systick callbacks use a cyclic func table. Instead of checking each callback (currently storage and dma) explicitly for each SysTick IRQ, use a simple circular function table indexed by the lower bits of the millisecond tick counter. This allows callbacks to be easily enabled/disabled at runtime, and scales well to a large number of callbacks. --- ports/stm32/dma.c | 23 +++++++++++++-- ports/stm32/dma.h | 14 --------- ports/stm32/stm32_it.c | 65 ------------------------------------------ ports/stm32/storage.c | 19 +++++++++++- ports/stm32/storage.h | 4 --- ports/stm32/systick.c | 33 +++++++++++++++++++++ ports/stm32/systick.h | 16 +++++++++++ 7 files changed, 88 insertions(+), 86 deletions(-) diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c index 9817bf6c15..b17c46068e 100644 --- a/ports/stm32/dma.c +++ b/ports/stm32/dma.c @@ -29,9 +29,16 @@ #include #include "py/obj.h" +#include "systick.h" #include "dma.h" #include "irq.h" +#define DMA_IDLE_ENABLED() (dma_idle.enabled != 0) +#define DMA_SYSTICK_LOG2 (3) +#define DMA_SYSTICK_MASK ((1 << DMA_SYSTICK_LOG2) - 1) +#define DMA_IDLE_TICK_MAX (8) // 8*8 = 64 msec +#define DMA_IDLE_TICK(tick) (((tick) & ~(SYSTICK_DISPATCH_NUM_SLOTS - 1) & DMA_SYSTICK_MASK) == 0) + typedef enum { dma_id_not_defined=-1, dma_id_0, @@ -52,6 +59,11 @@ typedef enum { dma_id_15, } dma_id_t; +typedef union { + uint16_t enabled; // Used to test if both counters are == 0 + uint8_t counter[2]; +} dma_idle_count_t; + struct _dma_descr_t { #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) DMA_Stream_TypeDef *instance; @@ -530,9 +542,12 @@ void DMA2_Channel7_IRQHandler(void) { IRQ_ENTER(DMA2_Channel7_IRQn); if (dma_han #endif +static void dma_idle_handler(uint32_t tick); + // Resets the idle counter for the DMA controller associated with dma_id. static void dma_tickle(dma_id_t dma_id) { dma_idle.counter[(dma_id < NSTREAMS_PER_CONTROLLER) ? 0 : 1] = 1; + systick_enable_dispatch(SYSTICK_DISPATCH_DMA, dma_idle_handler); } static void dma_enable_clock(dma_id_t dma_id) { @@ -681,12 +696,16 @@ void dma_invalidate_channel(const dma_descr_t *dma_descr) { // Called from the SysTick handler // We use LSB of tick to select which controller to process -void dma_idle_handler(int tick) { +static void dma_idle_handler(uint32_t tick) { + if (!DMA_IDLE_ENABLED() || !DMA_IDLE_TICK(tick)) { + return; + } + static const uint32_t controller_mask[] = { DMA1_ENABLE_MASK, DMA2_ENABLE_MASK }; { - int controller = tick & 1; + int controller = (tick >> DMA_SYSTICK_LOG2) & 1; if (dma_idle.counter[controller] == 0) { return; } diff --git a/ports/stm32/dma.h b/ports/stm32/dma.h index 84875374b2..73cb9c3282 100644 --- a/ports/stm32/dma.h +++ b/ports/stm32/dma.h @@ -81,23 +81,9 @@ extern const dma_descr_t dma_SDIO_0; #endif -typedef union { - uint16_t enabled; // Used to test if both counters are == 0 - uint8_t counter[2]; -} dma_idle_count_t; -extern volatile dma_idle_count_t dma_idle; -#define DMA_IDLE_ENABLED() (dma_idle.enabled != 0) - -#define DMA_SYSTICK_MASK 0x0e -#define DMA_MSECS_PER_SYSTICK (DMA_SYSTICK_MASK + 1) -#define DMA_IDLE_TICK_MAX (8) // 128 msec -#define DMA_IDLE_TICK(tick) (((tick) & DMA_SYSTICK_MASK) == 0) - - void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint32_t dir, void *data); void dma_init_handle(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint32_t dir, void *data); 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_STM32_DMA_H diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index 026082eb98..49b8ff1a8b 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -299,54 +299,6 @@ void PendSV_Handler(void) { pendsv_isr_handler(); } -/** - * @brief This function handles SysTick Handler. - * @param None - * @retval None - */ -void SysTick_Handler(void) { - // Instead of calling HAL_IncTick we do the increment here of the counter. - // This is purely for efficiency, since SysTick is called 1000 times per - // second at the highest interrupt priority. - // Note: we don't need uwTick to be declared volatile here because this is - // the only place where it can be modified, and the code is more efficient - // without the volatile specifier. - extern uint32_t uwTick; - uwTick += 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; - - // Right now we have the storage and DMA controllers to process during - // this interrupt and we use custom dispatch handlers. If this needs to - // 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); - } - - #if MICROPY_PY_THREAD - if (pyb_thread_enabled) { - if (pyb_thread_cur->timeslice == 0) { - if (pyb_thread_cur->run_next != pyb_thread_cur) { - SCB->ICSR = SCB_ICSR_PENDSVSET_Msk; - } - } else { - --pyb_thread_cur->timeslice; - } - } - #endif -} - /******************************************************************************/ /* STM32F4xx Peripherals Interrupt Handlers */ /* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */ @@ -465,23 +417,6 @@ void OTG_HS_WKUP_IRQHandler(void) { { }*/ -// Handle a flash (erase/program) interrupt. -void FLASH_IRQHandler(void) { - IRQ_ENTER(FLASH_IRQn); - // This calls the real flash IRQ handler, if needed - /* - uint32_t flash_cr = FLASH->CR; - if ((flash_cr & FLASH_IT_EOP) || (flash_cr & FLASH_IT_ERR)) { - 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); -} - /** * @brief These functions handle the EXTI interrupt requests. * @param None diff --git a/ports/stm32/storage.c b/ports/stm32/storage.c index 7724ae0f42..b150d73763 100644 --- a/ports/stm32/storage.c +++ b/ports/stm32/storage.c @@ -30,12 +30,16 @@ #include "py/runtime.h" #include "extmod/vfs_fat.h" +#include "systick.h" #include "led.h" #include "storage.h" #include "irq.h" #if MICROPY_HW_ENABLE_STORAGE +#define STORAGE_SYSTICK_MASK (0x1ff) // 512ms +#define STORAGE_IDLE_TICK(tick) (((tick) & ~(SYSTICK_DISPATCH_NUM_SLOTS - 1) & STORAGE_SYSTICK_MASK) == 0) + #define FLASH_PART1_START_BLOCK (0x100) #if defined(MICROPY_HW_BDEV2_IOCTL) @@ -44,10 +48,14 @@ static bool storage_is_initialised = false; +static void storage_systick_callback(uint32_t ticks_ms); + void storage_init(void) { if (!storage_is_initialised) { storage_is_initialised = true; + systick_enable_dispatch(SYSTICK_DISPATCH_STORAGE, storage_systick_callback); + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_INIT, 0); #if defined(MICROPY_HW_BDEV2_IOCTL) @@ -73,11 +81,20 @@ uint32_t storage_get_block_count(void) { #endif } -void storage_irq_handler(void) { +static void storage_systick_callback(uint32_t ticks_ms) { + if (STORAGE_IDLE_TICK(ticks_ms)) { + // Trigger a FLASH IRQ to execute at a lower priority + NVIC->STIR = FLASH_IRQn; + } +} + +void FLASH_IRQHandler(void) { + IRQ_ENTER(FLASH_IRQn); 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 + IRQ_EXIT(FLASH_IRQn); } void storage_flush(void) { diff --git a/ports/stm32/storage.h b/ports/stm32/storage.h index 7250b6dbf9..826b465a66 100644 --- a/ports/stm32/storage.h +++ b/ports/stm32/storage.h @@ -30,9 +30,6 @@ #define FLASH_BLOCK_SIZE (512) -#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, @@ -44,7 +41,6 @@ enum { void storage_init(void); uint32_t storage_get_block_size(void); uint32_t storage_get_block_count(void); -void storage_irq_handler(void); void storage_flush(void); bool storage_read_block(uint8_t *dest, uint32_t block); bool storage_write_block(const uint8_t *src, uint32_t block); diff --git a/ports/stm32/systick.c b/ports/stm32/systick.c index 8b5efe0577..d92f9d75dc 100644 --- a/ports/stm32/systick.c +++ b/ports/stm32/systick.c @@ -32,6 +32,39 @@ extern __IO uint32_t uwTick; +systick_dispatch_t systick_dispatch_table[SYSTICK_DISPATCH_NUM_SLOTS]; + +void SysTick_Handler(void) { + // Instead of calling HAL_IncTick we do the increment here of the counter. + // This is purely for efficiency, since SysTick is called 1000 times per + // second at the highest interrupt priority. + uint32_t uw_tick = uwTick + 1; + uwTick = uw_tick; + + // 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; + + // Dispatch to any registered handlers in a cycle + systick_dispatch_t f = systick_dispatch_table[uw_tick & (SYSTICK_DISPATCH_NUM_SLOTS - 1)]; + if (f != NULL) { + f(uw_tick); + } + + #if MICROPY_PY_THREAD + if (pyb_thread_enabled) { + if (pyb_thread_cur->timeslice == 0) { + if (pyb_thread_cur->run_next != pyb_thread_cur) { + SCB->ICSR = SCB_ICSR_PENDSVSET_Msk; + } + } else { + --pyb_thread_cur->timeslice; + } + } + #endif +} + // We provide our own version of HAL_Delay that calls __WFI while waiting, // and works when interrupts are disabled. This function is intended to be // used only by the ST HAL functions. diff --git a/ports/stm32/systick.h b/ports/stm32/systick.h index abb8729f54..d1b59c574b 100644 --- a/ports/stm32/systick.h +++ b/ports/stm32/systick.h @@ -26,6 +26,22 @@ #ifndef MICROPY_INCLUDED_STM32_SYSTICK_H #define MICROPY_INCLUDED_STM32_SYSTICK_H +#define SYSTICK_DISPATCH_NUM_SLOTS (2) +#define SYSTICK_DISPATCH_DMA (0) +#define SYSTICK_DISPATCH_STORAGE (1) + +typedef void (*systick_dispatch_t)(uint32_t); + +extern systick_dispatch_t systick_dispatch_table[SYSTICK_DISPATCH_NUM_SLOTS]; + +static inline void systick_enable_dispatch(size_t slot, systick_dispatch_t f) { + systick_dispatch_table[slot] = f; +} + +static inline void systick_disable_dispatch(size_t slot) { + systick_dispatch_table[slot] = NULL; +} + void systick_wait_at_least(uint32_t stc, uint32_t delay_ms); bool systick_has_passed(uint32_t stc, uint32_t delay_ms); From b178958c0799f16847a70c7a5c717a39528407ec Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 8 Feb 2019 01:03:51 +1100 Subject: [PATCH 0068/1788] stm32/pendsv: Clean up pendsv IRQ handler and eliminate duplicate code. --- ports/stm32/pendsv.c | 56 ++++++++++++++++++------------------------ ports/stm32/pendsv.h | 4 --- ports/stm32/stm32_it.c | 9 ------- 3 files changed, 24 insertions(+), 45 deletions(-) diff --git a/ports/stm32/pendsv.c b/ports/stm32/pendsv.c index b5fe42f70d..a6a9afc14e 100644 --- a/ports/stm32/pendsv.c +++ b/ports/stm32/pendsv.c @@ -61,11 +61,16 @@ void pendsv_kbd_intr(void) { } } -void pendsv_isr_handler(void) { - // re-jig the stack so that when we return from this interrupt handler +__attribute__((naked)) void PendSV_Handler(void) { + // Handle a PendSV interrupt + // + // For the case of an asynchronous exception, re-jig the + // stack so that when we return from this interrupt handler // it returns instead to nlr_jump with argument pendsv_object // note that stack has a different layout if DEBUG is enabled // + // For the case of a thread switch, swap stacks. + // // on entry to this (naked) function, stack has the following layout: // // stack layout with DEBUG disabled: @@ -88,20 +93,30 @@ void pendsv_isr_handler(void) { // sp[1]: 0xfffffff9 // sp[0]: ? -#if MICROPY_PY_THREAD __asm volatile ( + // Check if there is an active object to throw via nlr_jump "ldr r1, pendsv_object_ptr\n" "ldr r0, [r1]\n" "cmp r0, 0\n" "beq .no_obj\n" + #if defined(PENDSV_DEBUG) + "str r0, [sp, #8]\n" // store to r0 on stack + #else "str r0, [sp, #0]\n" // store to r0 on stack + #endif "mov r0, #0\n" "str r0, [r1]\n" // clear pendsv_object "ldr r0, nlr_jump_ptr\n" + #if defined(PENDSV_DEBUG) + "str r0, [sp, #32]\n" // store to pc on stack + #else "str r0, [sp, #24]\n" // store to pc on stack + #endif "bx lr\n" // return from interrupt; will return to nlr_jump - ".no_obj:\n" // pendsv_object==NULL + + #if MICROPY_PY_THREAD + // Do a thread context switch "push {r4-r11, lr}\n" "vpush {s16-s31}\n" "mrs r5, primask\n" // save PRIMASK in r5 @@ -115,37 +130,14 @@ void pendsv_isr_handler(void) { "vpop {s16-s31}\n" "pop {r4-r11, lr}\n" "bx lr\n" // return from interrupt; will return to new thread - ".align 2\n" - "pendsv_object_ptr: .word pendsv_object\n" - "nlr_jump_ptr: .word nlr_jump\n" - ); -#else - __asm volatile ( - "ldr r0, pendsv_object_ptr\n" - "ldr r0, [r0]\n" -#if defined(PENDSV_DEBUG) - "str r0, [sp, #8]\n" -#else - "str r0, [sp, #0]\n" -#endif - "ldr r0, nlr_jump_ptr\n" -#if defined(PENDSV_DEBUG) - "str r0, [sp, #32]\n" -#else - "str r0, [sp, #24]\n" -#endif + #else + // Spurious pendsv, just return "bx lr\n" + #endif + + // Data ".align 2\n" "pendsv_object_ptr: .word pendsv_object\n" "nlr_jump_ptr: .word nlr_jump\n" ); -#endif - - /* - uint32_t x[2] = {0x424242, 0xdeaddead}; - printf("PendSV: %p\n", x); - for (uint32_t *p = (uint32_t*)(((uint32_t)x - 15) & 0xfffffff0), i = 64; i > 0; p += 4, i -= 4) { - printf(" %p: %08x %08x %08x %08x\n", p, (uint)p[0], (uint)p[1], (uint)p[2], (uint)p[3]); - } - */ } diff --git a/ports/stm32/pendsv.h b/ports/stm32/pendsv.h index 0d9fde6878..52ce805366 100644 --- a/ports/stm32/pendsv.h +++ b/ports/stm32/pendsv.h @@ -29,8 +29,4 @@ void pendsv_init(void); void pendsv_kbd_intr(void); -// since we play tricks with the stack, the compiler must not generate a -// prelude for this function -void pendsv_isr_handler(void) __attribute__((naked)); - #endif // MICROPY_INCLUDED_STM32_PENDSV_H diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index 49b8ff1a8b..88e7f5bfec 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -290,15 +290,6 @@ void SVC_Handler(void) { void DebugMon_Handler(void) { } -/** - * @brief This function handles PendSVC exception. - * @param None - * @retval None - */ -void PendSV_Handler(void) { - pendsv_isr_handler(); -} - /******************************************************************************/ /* STM32F4xx Peripherals Interrupt Handlers */ /* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */ From 18cfa156d628873dfe0e12bcaad19bd802f32994 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 8 Feb 2019 01:11:21 +1100 Subject: [PATCH 0069/1788] stm32/pendsv: Add ability to schedule callbacks at pendsv IRQ level. --- ports/stm32/pendsv.c | 40 ++++++++++++++++++++++++++++++++++++++++ ports/stm32/pendsv.h | 5 +++++ 2 files changed, 45 insertions(+) diff --git a/ports/stm32/pendsv.c b/ports/stm32/pendsv.c index a6a9afc14e..6c6b3c7bff 100644 --- a/ports/stm32/pendsv.c +++ b/ports/stm32/pendsv.c @@ -38,7 +38,15 @@ // mp_kbd_exception which is in the root-pointer set. void *pendsv_object; +#if PENDSV_DISPATCH_NUM_SLOTS > 0 +uint32_t pendsv_dispatch_active; +pendsv_dispatch_t pendsv_dispatch_table[PENDSV_DISPATCH_NUM_SLOTS]; +#endif + void pendsv_init(void) { + #if PENDSV_DISPATCH_NUM_SLOTS > 0 + pendsv_dispatch_active = false; + #endif // set PendSV interrupt at lowest priority NVIC_SetPriority(PendSV_IRQn, IRQ_PRI_PENDSV); } @@ -61,6 +69,23 @@ void pendsv_kbd_intr(void) { } } +#if PENDSV_DISPATCH_NUM_SLOTS > 0 +void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f) { + pendsv_dispatch_table[slot] = f; + pendsv_dispatch_active = true; + SCB->ICSR = SCB_ICSR_PENDSVSET_Msk; +} + +void pendsv_dispatch_handler(void) { + for (size_t i = 0; i < PENDSV_DISPATCH_NUM_SLOTS; ++i) { + if (pendsv_dispatch_table[i] != NULL) { + pendsv_dispatch_table[i] = NULL; + pendsv_dispatch_table[i](); + } + } +} +#endif + __attribute__((naked)) void PendSV_Handler(void) { // Handle a PendSV interrupt // @@ -94,6 +119,18 @@ __attribute__((naked)) void PendSV_Handler(void) { // sp[0]: ? __asm volatile ( + #if PENDSV_DISPATCH_NUM_SLOTS > 0 + // Check if there are any pending calls to dispatch to + "ldr r1, pendsv_dispatch_active_ptr\n" + "ldr r0, [r1]\n" + "cmp r0, 0\n" + "beq .no_dispatch\n" + "mov r2, #0\n" + "str r2, [r1]\n" // clear pendsv_dispatch_active + "b pendsv_dispatch_handler\n" // jump to the handler + ".no_dispatch:\n" + #endif + // Check if there is an active object to throw via nlr_jump "ldr r1, pendsv_object_ptr\n" "ldr r0, [r1]\n" @@ -137,6 +174,9 @@ __attribute__((naked)) void PendSV_Handler(void) { // Data ".align 2\n" + #if PENDSV_DISPATCH_NUM_SLOTS > 0 + "pendsv_dispatch_active_ptr: .word pendsv_dispatch_active\n" + #endif "pendsv_object_ptr: .word pendsv_object\n" "nlr_jump_ptr: .word nlr_jump\n" ); diff --git a/ports/stm32/pendsv.h b/ports/stm32/pendsv.h index 52ce805366..c8cc64d762 100644 --- a/ports/stm32/pendsv.h +++ b/ports/stm32/pendsv.h @@ -26,7 +26,12 @@ #ifndef MICROPY_INCLUDED_STM32_PENDSV_H #define MICROPY_INCLUDED_STM32_PENDSV_H +#define PENDSV_DISPATCH_NUM_SLOTS (0) + +typedef void (*pendsv_dispatch_t)(void); + void pendsv_init(void); void pendsv_kbd_intr(void); +void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f); #endif // MICROPY_INCLUDED_STM32_PENDSV_H From 4d214edae89ce178765c63f83b67c099019ef5db Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 8 Feb 2019 15:10:13 +1100 Subject: [PATCH 0070/1788] stm32/systick: Provide better compile-time configurability of slots. --- ports/stm32/systick.h | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/ports/stm32/systick.h b/ports/stm32/systick.h index d1b59c574b..3ae6be7e02 100644 --- a/ports/stm32/systick.h +++ b/ports/stm32/systick.h @@ -26,9 +26,18 @@ #ifndef MICROPY_INCLUDED_STM32_SYSTICK_H #define MICROPY_INCLUDED_STM32_SYSTICK_H -#define SYSTICK_DISPATCH_NUM_SLOTS (2) -#define SYSTICK_DISPATCH_DMA (0) -#define SYSTICK_DISPATCH_STORAGE (1) +// Works for x between 0 and 16 inclusive +#define POW2_CEIL(x) ((((x) - 1) | ((x) - 1) >> 1 | ((x) - 1) >> 2 | ((x) - 1) >> 3) + 1) + +enum { + SYSTICK_DISPATCH_DMA = 0, + #if MICROPY_HW_ENABLE_STORAGE + SYSTICK_DISPATCH_STORAGE, + #endif + SYSTICK_DISPATCH_MAX +}; + +#define SYSTICK_DISPATCH_NUM_SLOTS POW2_CEIL(SYSTICK_DISPATCH_MAX) typedef void (*systick_dispatch_t)(uint32_t); From 800871c0cbae9d099cc8ec5e4aa11cb01a8aa4e8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 8 Feb 2019 15:52:56 +1100 Subject: [PATCH 0071/1788] stm32/modnetwork: Change lwIP polling to be based on background systick. --- ports/stm32/main.c | 1 + ports/stm32/modnetwork.c | 13 ++++++++++++- ports/stm32/modnetwork.h | 1 + ports/stm32/mpconfigport.h | 5 ----- ports/stm32/pendsv.c | 10 +++++----- ports/stm32/pendsv.h | 11 ++++++++++- ports/stm32/systick.h | 3 +++ 7 files changed, 32 insertions(+), 12 deletions(-) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index ef0e1e791b..1a00ef3a18 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -547,6 +547,7 @@ void stm32_main(uint32_t reset_mode) { // 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(); + systick_enable_dispatch(SYSTICK_DISPATCH_LWIP, mod_network_lwip_poll_wrapper); #endif #if defined(MICROPY_HW_UART_REPL) diff --git a/ports/stm32/modnetwork.c b/ports/stm32/modnetwork.c index dea23b4051..4fa3d8c05b 100644 --- a/ports/stm32/modnetwork.c +++ b/ports/stm32/modnetwork.c @@ -32,6 +32,8 @@ #include "py/runtime.h" #include "py/mphal.h" #include "lib/netutils/netutils.h" +#include "systick.h" +#include "pendsv.h" #include "modnetwork.h" #if MICROPY_PY_NETWORK @@ -43,11 +45,14 @@ #include "lwip/dns.h" #include "lwip/dhcp.h" +// Poll lwIP every 128ms +#define LWIP_TICK(tick) (((tick) & ~(SYSTICK_DISPATCH_NUM_SLOTS - 1) & 0x7f) == 0) + u32_t sys_now(void) { return mp_hal_ticks_ms(); } -void pyb_lwip_poll(void) { +STATIC 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) { @@ -59,6 +64,12 @@ void pyb_lwip_poll(void) { sys_check_timeouts(); } +void mod_network_lwip_poll_wrapper(uint32_t ticks_ms) { + if (LWIP_TICK(ticks_ms)) { + pendsv_schedule_dispatch(PENDSV_DISPATCH_LWIP, pyb_lwip_poll); + } +} + #endif /// \module network - network configuration diff --git a/ports/stm32/modnetwork.h b/ports/stm32/modnetwork.h index f45e00fbc2..dd8113ebf5 100644 --- a/ports/stm32/modnetwork.h +++ b/ports/stm32/modnetwork.h @@ -46,6 +46,7 @@ typedef struct _mod_network_nic_type_t { extern const mp_obj_type_t mod_network_nic_type_wiznet5k; +void mod_network_lwip_poll_wrapper(uint32_t ticks_ms); 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/mpconfigport.h b/ports/stm32/mpconfigport.h index 42e0bf3f13..7ae2ac77b0 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -213,17 +213,14 @@ extern const struct _mp_obj_module_t mp_module_onewire; // 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 @@ -339,7 +336,6 @@ 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(); \ @@ -355,7 +351,6 @@ static inline mp_uint_t disable_irq(void) { do { \ extern void mp_handle_pending(void); \ mp_handle_pending(); \ - SOCKET_POLL \ __WFI(); \ } while (0); diff --git a/ports/stm32/pendsv.c b/ports/stm32/pendsv.c index 6c6b3c7bff..a3d04a4ef9 100644 --- a/ports/stm32/pendsv.c +++ b/ports/stm32/pendsv.c @@ -38,13 +38,13 @@ // mp_kbd_exception which is in the root-pointer set. void *pendsv_object; -#if PENDSV_DISPATCH_NUM_SLOTS > 0 +#if defined(PENDSV_DISPATCH_NUM_SLOTS) uint32_t pendsv_dispatch_active; pendsv_dispatch_t pendsv_dispatch_table[PENDSV_DISPATCH_NUM_SLOTS]; #endif void pendsv_init(void) { - #if PENDSV_DISPATCH_NUM_SLOTS > 0 + #if defined(PENDSV_DISPATCH_NUM_SLOTS) pendsv_dispatch_active = false; #endif // set PendSV interrupt at lowest priority @@ -69,7 +69,7 @@ void pendsv_kbd_intr(void) { } } -#if PENDSV_DISPATCH_NUM_SLOTS > 0 +#if defined(PENDSV_DISPATCH_NUM_SLOTS) void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f) { pendsv_dispatch_table[slot] = f; pendsv_dispatch_active = true; @@ -119,7 +119,7 @@ __attribute__((naked)) void PendSV_Handler(void) { // sp[0]: ? __asm volatile ( - #if PENDSV_DISPATCH_NUM_SLOTS > 0 + #if defined(PENDSV_DISPATCH_NUM_SLOTS) // Check if there are any pending calls to dispatch to "ldr r1, pendsv_dispatch_active_ptr\n" "ldr r0, [r1]\n" @@ -174,7 +174,7 @@ __attribute__((naked)) void PendSV_Handler(void) { // Data ".align 2\n" - #if PENDSV_DISPATCH_NUM_SLOTS > 0 + #if defined(PENDSV_DISPATCH_NUM_SLOTS) "pendsv_dispatch_active_ptr: .word pendsv_dispatch_active\n" #endif "pendsv_object_ptr: .word pendsv_object\n" diff --git a/ports/stm32/pendsv.h b/ports/stm32/pendsv.h index c8cc64d762..18ae1d63e9 100644 --- a/ports/stm32/pendsv.h +++ b/ports/stm32/pendsv.h @@ -26,7 +26,16 @@ #ifndef MICROPY_INCLUDED_STM32_PENDSV_H #define MICROPY_INCLUDED_STM32_PENDSV_H -#define PENDSV_DISPATCH_NUM_SLOTS (0) +enum { + #if MICROPY_PY_NETWORK && MICROPY_PY_LWIP + PENDSV_DISPATCH_LWIP, + #endif + PENDSV_DISPATCH_MAX +}; + +#if MICROPY_PY_NETWORK && MICROPY_PY_LWIP +#define PENDSV_DISPATCH_NUM_SLOTS PENDSV_DISPATCH_MAX +#endif typedef void (*pendsv_dispatch_t)(void); diff --git a/ports/stm32/systick.h b/ports/stm32/systick.h index 3ae6be7e02..6a05a4990a 100644 --- a/ports/stm32/systick.h +++ b/ports/stm32/systick.h @@ -34,6 +34,9 @@ enum { #if MICROPY_HW_ENABLE_STORAGE SYSTICK_DISPATCH_STORAGE, #endif + #if MICROPY_PY_NETWORK && MICROPY_PY_LWIP + SYSTICK_DISPATCH_LWIP, + #endif SYSTICK_DISPATCH_MAX }; From b546e4b7e9558ea03f461ae1a54bf14e6606aecb Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 8 Feb 2019 16:36:09 +1100 Subject: [PATCH 0072/1788] stm32/pendsv: Fix NULL pointer when calling pendsv dispatch function. --- ports/stm32/pendsv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ports/stm32/pendsv.c b/ports/stm32/pendsv.c index a3d04a4ef9..ba383a7319 100644 --- a/ports/stm32/pendsv.c +++ b/ports/stm32/pendsv.c @@ -79,8 +79,9 @@ void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f) { void pendsv_dispatch_handler(void) { for (size_t i = 0; i < PENDSV_DISPATCH_NUM_SLOTS; ++i) { if (pendsv_dispatch_table[i] != NULL) { + pendsv_dispatch_t f = pendsv_dispatch_table[i]; pendsv_dispatch_table[i] = NULL; - pendsv_dispatch_table[i](); + f(); } } } From a0d60c574a96bb873b0e6822d009031fd5fa3a77 Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Thu, 7 Feb 2019 23:48:34 +0200 Subject: [PATCH 0073/1788] docs/ure: Fix match.group signature to indicate index param is required. --- docs/library/ure.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/library/ure.rst b/docs/library/ure.rst index d2615e37d8..ac5f02f9e8 100644 --- a/docs/library/ure.rst +++ b/docs/library/ure.rst @@ -175,7 +175,7 @@ Match objects Match objects as returned by `match()` and `search()` methods, and passed to the replacement function in `sub()`. -.. method:: match.group([index]) +.. method:: match.group(index) Return matching (sub)string. *index* is 0 for entire match, 1 and above for each capturing group. Only numeric groups are supported. From 775c7b86f017b81d31c3d463aec1b18088dbcdab Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 12 Feb 2019 10:55:48 +1100 Subject: [PATCH 0074/1788] travis: Update to use Ubuntu 16.04 Xenial for CI builds. --- .travis.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index e0a9de3be1..be81d6aa23 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ # global options +dist: xenial language: - c compiler: @@ -23,9 +24,10 @@ jobs: env: NAME="stm32 port build" install: # need newer gcc version for Cortex-M7 support - - sudo add-apt-repository -y ppa:terry.guo/gcc-arm-embedded + - sudo add-apt-repository -y ppa:team-gcc-arm-embedded/ppa - sudo apt-get update -qq || true - - sudo apt-get install --allow-unauthenticated gcc-arm-none-eabi + - sudo apt-get install gcc-arm-embedded + - sudo apt-get install libnewlib-arm-none-eabi - arm-none-eabi-gcc --version script: - make ${MAKEOPTS} -C mpy-cross @@ -38,12 +40,11 @@ jobs: - stage: test env: NAME="qemu-arm port build and tests" install: - # need newer gcc version for nano.specs - - sudo add-apt-repository -y ppa:terry.guo/gcc-arm-embedded - - sudo apt-get update -qq || true - - sudo apt-get install --allow-unauthenticated gcc-arm-none-eabi + - sudo apt-get install gcc-arm-none-eabi + - sudo apt-get install libnewlib-arm-none-eabi - sudo apt-get install qemu-system - arm-none-eabi-gcc --version + - qemu-system-arm --version script: - make ${MAKEOPTS} -C mpy-cross - make ${MAKEOPTS} -C ports/qemu-arm -f Makefile.test test @@ -54,8 +55,6 @@ jobs: - stage: test env: NAME="unix coverage build and tests" install: - # 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 - python3 --version @@ -117,10 +116,8 @@ jobs: - stage: test env: NAME="nrf port build" install: - # need newer gcc version to support variables in linker script - - sudo add-apt-repository -y ppa:team-gcc-arm-embedded/ppa - - sudo apt-get update -qq || true - - sudo apt-get install gcc-arm-embedded + - sudo apt-get install gcc-arm-none-eabi + - sudo apt-get install libnewlib-arm-none-eabi - arm-none-eabi-gcc --version script: - make ${MAKEOPTS} -C ports/nrf @@ -130,6 +127,7 @@ jobs: env: NAME="bare-arm and minimal ports build" install: - sudo apt-get install gcc-arm-none-eabi + - sudo apt-get install libnewlib-arm-none-eabi - arm-none-eabi-gcc --version script: - make ${MAKEOPTS} -C ports/bare-arm @@ -145,6 +143,7 @@ jobs: env: NAME="cc3200 port build" install: - sudo apt-get install gcc-arm-none-eabi + - sudo apt-get install libnewlib-arm-none-eabi script: - make ${MAKEOPTS} -C ports/cc3200 BTARGET=application BTYPE=release - make ${MAKEOPTS} -C ports/cc3200 BTARGET=bootloader BTYPE=release @@ -154,5 +153,6 @@ jobs: env: NAME="teensy port build" install: - sudo apt-get install gcc-arm-none-eabi + - sudo apt-get install libnewlib-arm-none-eabi script: - make ${MAKEOPTS} -C ports/teensy From e7332b05841549a41614e522285639dcaa7bd526 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 24 Sep 2018 12:09:28 +1000 Subject: [PATCH 0075/1788] qemu-arm: Rework to run bare-metal on boards with Cortex-M CPUs. Adds support for 3 Cortex-M boards, selectable via "BOARD" in the Makefile: - microbit, Cortex-M0 via nRF51822 - netduino2, Cortex-M3 via STM32F205 - mps2-an385, Cortex-M3 via FPGA netduino2 is the default board because it's supported by older qemu versions (down to at least 2.5.0). --- ports/qemu-arm/Makefile | 34 +++++++++++--- ports/qemu-arm/Makefile.test | 4 +- ports/qemu-arm/main.c | 2 +- ports/qemu-arm/mpconfigport.h | 5 +-- ports/qemu-arm/mphalport.h | 5 ++- ports/qemu-arm/mps2.ld | 38 ++++++++++++++++ ports/qemu-arm/nrf51.ld | 39 ++++++++++++++++ ports/qemu-arm/startup.c | 84 +++++++++++++++++++++++++++++++++++ ports/qemu-arm/stm32.ld | 39 ++++++++++++++++ ports/qemu-arm/test_main.c | 8 ++-- ports/qemu-arm/uart.c | 78 ++++++++++++++++++++++++++++++++ ports/qemu-arm/uart.h | 2 + 12 files changed, 320 insertions(+), 18 deletions(-) create mode 100644 ports/qemu-arm/mps2.ld create mode 100644 ports/qemu-arm/nrf51.ld create mode 100644 ports/qemu-arm/startup.c create mode 100644 ports/qemu-arm/stm32.ld create mode 100644 ports/qemu-arm/uart.c create mode 100644 ports/qemu-arm/uart.h diff --git a/ports/qemu-arm/Makefile b/ports/qemu-arm/Makefile index 95f349beba..b3d9cdf566 100644 --- a/ports/qemu-arm/Makefile +++ b/ports/qemu-arm/Makefile @@ -7,6 +7,27 @@ QSTR_DEFS = qstrdefsport.h # include py core make definitions include $(TOP)/py/py.mk +BOARD ?= netduino2 + +ifeq ($(BOARD),netduino2) +CFLAGS += -mthumb -mcpu=cortex-m3 -mfloat-abi=soft +CFLAGS += -DQEMU_SOC_STM32 +LDSCRIPT = stm32.ld +endif + +ifeq ($(BOARD),microbit) +CFLAGS += -mthumb -mcpu=cortex-m0 -mfloat-abi=soft +CFLAGS += -DQEMU_SOC_NRF51 +LDSCRIPT = nrf51.ld +QEMU_EXTRA = -global nrf51-soc.flash-size=1048576 -global nrf51-soc.sram-size=262144 +endif + +ifeq ($(BOARD),mps2-an385) +CFLAGS += -mthumb -mcpu=cortex-m3 -mfloat-abi=soft +CFLAGS += -DQEMU_SOC_MPS2 +LDSCRIPT = mps2.ld +endif + CROSS_COMPILE = arm-none-eabi- TINYTEST = $(TOP)/lib/tinytest @@ -16,8 +37,7 @@ INC += -I$(TOP) INC += -I$(BUILD) 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) \ +CFLAGS += $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 $(COPT) \ -ffunction-sections -fdata-sections #Debugging/Optimization @@ -34,9 +54,12 @@ endif ## else instead and according to the following files, this is what we need to pass to `$(CC). ## - gcc-arm-none-eabi-4_8-2014q1/share/gcc-arm-none-eabi/samples/src/makefile.conf ## - gcc-arm-none-eabi-4_8-2014q1/share/gcc-arm-none-eabi/samples/src/qemu/Makefile -LDFLAGS= --specs=nano.specs --specs=rdimon.specs -Wl,--gc-sections -Wl,-Map=$(@:.elf=.map) +LDFLAGS= -T $(LDSCRIPT) --gc-sections -Map=$(@:.elf=.map) +LIBS = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) SRC_COMMON_C = \ + startup.c \ + uart.c \ moduos.c \ modmachine.c \ @@ -47,6 +70,7 @@ SRC_TEST_C = \ test_main.c \ LIB_SRC_C += $(addprefix lib/,\ + libc/string0.c \ libm/math.c \ libm/fmodf.c \ libm/nearbyintf.c \ @@ -89,11 +113,11 @@ SRC_QSTR += $(SRC_COMMON_C) $(SRC_RUN_C) $(LIB_SRC_C) all: run run: $(BUILD)/firmware.elf - qemu-system-arm -machine integratorcp -cpu cortex-m3 -nographic -monitor null -serial null -semihosting -kernel $(BUILD)/firmware.elf + qemu-system-arm -machine $(BOARD) $(QEMU_EXTRA) -nographic -monitor null -semihosting -kernel $< ## `$(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)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS) $(Q)$(SIZE) $@ include $(TOP)/py/mkrules.mk diff --git a/ports/qemu-arm/Makefile.test b/ports/qemu-arm/Makefile.test index a9aace6d07..347c2fefd3 100644 --- a/ports/qemu-arm/Makefile.test +++ b/ports/qemu-arm/Makefile.test @@ -15,10 +15,10 @@ $(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)$(LD) $(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 + qemu-system-arm -machine $(BOARD) $(QEMU_EXTRA) -nographic -monitor null -semihosting -kernel $< > $(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/main.c b/ports/qemu-arm/main.c index d23ef576f9..4cdd148287 100644 --- a/ports/qemu-arm/main.c +++ b/ports/qemu-arm/main.c @@ -30,7 +30,7 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) { int main(int argc, char **argv) { mp_stack_ctrl_init(); mp_stack_set_limit(10240); - void *heap = malloc(16 * 1024); + uint32_t heap[16*1024 / 4]; gc_init(heap, (char*)heap + 16 * 1024); mp_init(); do_str("print('hello world!')", MP_PARSE_SINGLE_INPUT); diff --git a/ports/qemu-arm/mpconfigport.h b/ports/qemu-arm/mpconfigport.h index 5d86191988..3d4abd52ff 100644 --- a/ports/qemu-arm/mpconfigport.h +++ b/ports/qemu-arm/mpconfigport.h @@ -38,7 +38,7 @@ #define MICROPY_PY_UHASHLIB (1) #define MICROPY_PY_MACHINE (1) #define MICROPY_PY_MICROPYTHON_MEM_INFO (1) -#define MICROPY_USE_INTERNAL_PRINTF (0) +#define MICROPY_USE_INTERNAL_PRINTF (1) #define MICROPY_VFS (1) // type definitions for the specific machine @@ -54,9 +54,6 @@ 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; -#include -#define MP_PLAT_PRINT_STRN(str, len) write(1, str, len) - // extra built in names to add to the global namespace #define MICROPY_PORT_BUILTINS \ { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) }, diff --git a/ports/qemu-arm/mphalport.h b/ports/qemu-arm/mphalport.h index d996402ae4..29f080805f 100644 --- a/ports/qemu-arm/mphalport.h +++ b/ports/qemu-arm/mphalport.h @@ -1,2 +1,5 @@ +#include +#include "uart.h" + #define mp_hal_stdin_rx_chr() (0) -#define mp_hal_stdout_tx_strn_cooked(s, l) write(1, (s), (l)) +#define mp_hal_stdout_tx_strn_cooked(s, l) uart_tx_strn((s), (l)) diff --git a/ports/qemu-arm/mps2.ld b/ports/qemu-arm/mps2.ld new file mode 100644 index 0000000000..5c1aa21ca2 --- /dev/null +++ b/ports/qemu-arm/mps2.ld @@ -0,0 +1,38 @@ +MEMORY +{ + RAM : ORIGIN = 0x00000000, LENGTH = 4M +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); + +SECTIONS +{ + .text : { + . = ALIGN(4); + KEEP(*(.isr_vector)) + *(.text*) + *(.rodata*) + . = ALIGN(4); + _etext = .; + _sidata = _etext; + } > RAM + + .data : AT ( _sidata ) + { + . = ALIGN(4); + _sdata = .; + *(.data*) + . = ALIGN(4); + _edata = .; + } >RAM + + .bss : + { + . = ALIGN(4); + _sbss = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >RAM +} diff --git a/ports/qemu-arm/nrf51.ld b/ports/qemu-arm/nrf51.ld new file mode 100644 index 0000000000..70269773cb --- /dev/null +++ b/ports/qemu-arm/nrf51.ld @@ -0,0 +1,39 @@ +MEMORY +{ + ROM : ORIGIN = 0x00000000, LENGTH = 1M + RAM : ORIGIN = 0x20000000, LENGTH = 256K +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); + +SECTIONS +{ + .text : { + . = ALIGN(4); + KEEP(*(.isr_vector)) + *(.text*) + *(.rodata*) + . = ALIGN(4); + _etext = .; + _sidata = _etext; + } > ROM + + .data : AT ( _sidata ) + { + . = ALIGN(4); + _sdata = .; + *(.data*) + . = ALIGN(4); + _edata = .; + } >RAM + + .bss : + { + . = ALIGN(4); + _sbss = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >RAM +} diff --git a/ports/qemu-arm/startup.c b/ports/qemu-arm/startup.c new file mode 100644 index 0000000000..5198d089f9 --- /dev/null +++ b/ports/qemu-arm/startup.c @@ -0,0 +1,84 @@ +#include +#include + +#include "uart.h" + +extern uint32_t _estack, _sidata, _sdata, _edata, _sbss, _ebss; + +__attribute__((naked)) void Reset_Handler(void) { + // set stack pointer + __asm volatile ("ldr r0, =_estack"); + __asm volatile ("mov sp, r0"); + // copy .data section from flash to RAM + for (uint32_t *src = &_sidata, *dest = &_sdata; dest < &_edata;) { + *dest++ = *src++; + } + // zero out .bss section + for (uint32_t *dest = &_sbss; dest < &_ebss;) { + *dest++ = 0; + } + // jump to board initialisation + void _start(void); + _start(); +} + +void Default_Handler(void) { + for (;;) { + } +} + +const uint32_t isr_vector[] __attribute__((section(".isr_vector"))) = { + (uint32_t)&_estack, + (uint32_t)&Reset_Handler, + (uint32_t)&Default_Handler, // NMI_Handler + (uint32_t)&Default_Handler, // HardFault_Handler + (uint32_t)&Default_Handler, // MemManage_Handler + (uint32_t)&Default_Handler, // BusFault_Handler + (uint32_t)&Default_Handler, // UsageFault_Handler + 0, + 0, + 0, + 0, + (uint32_t)&Default_Handler, // SVC_Handler + (uint32_t)&Default_Handler, // DebugMon_Handler + 0, + (uint32_t)&Default_Handler, // PendSV_Handler + (uint32_t)&Default_Handler, // SysTick_Handler +}; + +void _start(void) { + // Enable the UART + uart_init(); + + // Now that we have a basic system up and running we can call main + extern int main(); + main(0, 0); + + // Finished + exit(0); +} + +__attribute__((naked)) void exit(int status) { + // Force qemu to exit using ARM Semihosting + __asm volatile ( + "mov r1, r0\n" + "cmp r1, #0\n" + "bne .notclean\n" + "ldr r1, =0x20026\n" // ADP_Stopped_ApplicationExit, a clean exit + ".notclean:\n" + "movs r0, #0x18\n" // SYS_EXIT + "bkpt 0xab\n" + ); + for (;;) { + } +} + +// The following are needed for tinytest + +#include + +int setvbuf(FILE *stream, char *buf, int mode, size_t size) { + return 0; +} + +struct _reent *_impure_ptr; diff --git a/ports/qemu-arm/stm32.ld b/ports/qemu-arm/stm32.ld new file mode 100644 index 0000000000..4e541526b7 --- /dev/null +++ b/ports/qemu-arm/stm32.ld @@ -0,0 +1,39 @@ +MEMORY +{ + ROM : ORIGIN = 0x00000000, LENGTH = 1M + RAM : ORIGIN = 0x20000000, LENGTH = 128K +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); + +SECTIONS +{ + .text : { + . = ALIGN(4); + KEEP(*(.isr_vector)) + *(.text*) + *(.rodata*) + . = ALIGN(4); + _etext = .; + _sidata = _etext; + } > ROM + + .data : AT ( _sidata ) + { + . = ALIGN(4); + _sdata = .; + *(.data*) + . = ALIGN(4); + _edata = .; + } >RAM + + .bss : + { + . = ALIGN(4); + _sbss = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >RAM +} diff --git a/ports/qemu-arm/test_main.c b/ports/qemu-arm/test_main.c index adbdf04e18..2cb9e73859 100644 --- a/ports/qemu-arm/test_main.c +++ b/ports/qemu-arm/test_main.c @@ -15,15 +15,14 @@ #include "tinytest.h" #include "tinytest_macros.h" -#define HEAP_SIZE (128 * 1024) -STATIC void *heap; +#define HEAP_SIZE (100 * 1024) #include "genhdr/tests.h" int main() { mp_stack_ctrl_init(); mp_stack_set_limit(10240); - heap = malloc(HEAP_SIZE); + static uint32_t heap[HEAP_SIZE / sizeof(uint32_t)]; upytest_set_heap(heap, (char*)heap + HEAP_SIZE); int r = tinytest_main(0, NULL, groups); printf("status: %d\n", r); @@ -34,8 +33,7 @@ void gc_collect(void) { gc_collect_start(); // get the registers and the sp - jmp_buf env; - setjmp(env); + // TODO get registers volatile mp_uint_t dummy; void *sp = (void*)&dummy; diff --git a/ports/qemu-arm/uart.c b/ports/qemu-arm/uart.c new file mode 100644 index 0000000000..a0ce737c06 --- /dev/null +++ b/ports/qemu-arm/uart.c @@ -0,0 +1,78 @@ +#include +#include + +#include "uart.h" + +#if defined(QEMU_SOC_STM32) + +typedef struct _UART_t { + volatile uint32_t SR; + volatile uint32_t DR; +} UART_t; + +#define UART0 ((UART_t*)(0x40011000)) + +void uart_init(void) { +} + +void uart_tx_strn(const char *buf, size_t len) { + for (size_t i = 0; i < len; ++i) { + UART0->DR = buf[i]; + } +} + +#elif defined(QEMU_SOC_NRF51) + +typedef struct _UART_t { + volatile uint32_t r0[2]; + volatile uint32_t STARTTX; // 0x008 + volatile uint32_t r1[(0x500 - 0x008) / 4 - 1]; + volatile uint32_t ENABLE; // 0x500 + volatile uint32_t r2[(0x51c - 0x500) / 4 - 1]; + volatile uint32_t TXD; // 0x51c +} UART_t; + +#define UART0 ((UART_t*)(0x40002000)) + +void uart_init(void) { + UART0->ENABLE = 4; + UART0->STARTTX = 1; +} + +void uart_tx_strn(const char *buf, size_t len) { + for (size_t i = 0; i < len; ++i) { + UART0->TXD = buf[i]; + } +} + +#elif defined(QEMU_SOC_MPS2) + +#define UART_STATE_TXFULL (1 << 0) + +#define UART_CTRL_TX_EN (1 << 0) +#define UART_CTRL_RX_EN (1 << 1) + +typedef struct _UART_t { + volatile uint32_t DATA; + volatile uint32_t STATE; + volatile uint32_t CTRL; + volatile uint32_t INTSTATUS; + volatile uint32_t BAUDDIV; +} UART_t; + +#define UART0 ((UART_t*)(0x40004000)) + +void uart_init(void) { + UART0->BAUDDIV = 16; + UART0->CTRL = UART_CTRL_TX_EN; +} + +void uart_tx_strn(const char *buf, size_t len) { + for (size_t i = 0; i < len; ++i) { + while (UART0->STATE & UART_STATE_TXFULL) { + } + UART0->DATA = buf[i]; + } +} + +#endif diff --git a/ports/qemu-arm/uart.h b/ports/qemu-arm/uart.h new file mode 100644 index 0000000000..a89e3f26e2 --- /dev/null +++ b/ports/qemu-arm/uart.h @@ -0,0 +1,2 @@ +void uart_init(void); +void uart_tx_strn(const char *buf, size_t len); From e6d97e8a0be1f7795f8c93b30ec7655c9ca09a7c Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 12 Feb 2019 14:11:21 +1100 Subject: [PATCH 0076/1788] stm32: Move gchelper assembler code to lib/utils for use by other ports. --- {ports/stm32 => lib/utils}/gchelper_m0.s | 0 ports/stm32/gchelper.s => lib/utils/gchelper_m3.s | 0 ports/stm32/Makefile | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) rename {ports/stm32 => lib/utils}/gchelper_m0.s (100%) rename ports/stm32/gchelper.s => lib/utils/gchelper_m3.s (100%) diff --git a/ports/stm32/gchelper_m0.s b/lib/utils/gchelper_m0.s similarity index 100% rename from ports/stm32/gchelper_m0.s rename to lib/utils/gchelper_m0.s diff --git a/ports/stm32/gchelper.s b/lib/utils/gchelper_m3.s similarity index 100% rename from ports/stm32/gchelper.s rename to lib/utils/gchelper_m3.s diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index ee4de61cc4..c7dc99fd7d 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -275,13 +275,13 @@ SRC_O = \ $(STARTUP_FILE) \ system_stm32f0.o \ resethandler_m0.o \ - gchelper_m0.o + lib/utils/gchelper_m0.o else SRC_O = \ $(STARTUP_FILE) \ system_stm32.o \ resethandler.o \ - gchelper.o + lib/utils/gchelper_m3.o endif SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ From 90e1303b2df1bc1967ae5403a0456512f10b3782 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 12 Feb 2019 14:16:24 +1100 Subject: [PATCH 0077/1788] lib/utils/gchelper_m3: Add license header and clean up code. This file generates the same code with the cortex-m3 and cortex-m4 assembler directive, so use cortex-m3 to support more CPUs. --- lib/utils/gchelper_m3.s | 73 +++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 40 deletions(-) diff --git a/lib/utils/gchelper_m3.s b/lib/utils/gchelper_m3.s index 6baedcdd0e..5220fa0883 100644 --- a/lib/utils/gchelper_m3.s +++ b/lib/utils/gchelper_m3.s @@ -1,14 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + .syntax unified - .cpu cortex-m4 + .cpu cortex-m3 .thumb - .text + + .section .text .align 2 -@ uint gc_helper_get_regs_and_sp(r0=uint regs[10]) .global gc_helper_get_regs_and_sp - .thumb - .thumb_func - .type gc_helper_get_regs_and_sp, %function + .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], #4 @@ -26,37 +52,4 @@ gc_helper_get_regs_and_sp: mov r0, sp bx lr - -@ this next function is now obsolete - - .size gc_helper_get_regs_and_clean_stack, .-gc_helper_get_regs_and_clean_stack -@ void gc_helper_get_regs_and_clean_stack(r0=uint regs[10], r1=heap_end) - .global gc_helper_get_regs_and_clean_stack - .thumb - .thumb_func - .type gc_helper_get_regs_and_clean_stack, %function -gc_helper_get_regs_and_clean_stack: - @ store registers into given array - str r4, [r0], #4 - str r5, [r0], #4 - str r6, [r0], #4 - str r7, [r0], #4 - str r8, [r0], #4 - str r9, [r0], #4 - str r10, [r0], #4 - str r11, [r0], #4 - str r12, [r0], #4 - str r13, [r0], #4 - - @ clean the stack from given pointer up to current sp - movs r0, #0 - mov r2, sp - b.n .entry -.loop: - str r0, [r1], #4 -.entry: - cmp r1, r2 - bcc.n .loop - bx lr - - .size gc_helper_get_regs_and_clean_stack, .-gc_helper_get_regs_and_clean_stack + .size gc_helper_get_regs_and_sp, .-gc_helper_get_regs_and_sp From f608f54ab0443910931380a0f735c81e1a8a3ffa Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 12 Feb 2019 14:37:01 +1100 Subject: [PATCH 0078/1788] lib/utils/gchelper_m3: Add gc_helper_get_sp() function. --- lib/utils/gchelper_m3.s | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/utils/gchelper_m3.s b/lib/utils/gchelper_m3.s index 5220fa0883..3aac0dedfd 100644 --- a/lib/utils/gchelper_m3.s +++ b/lib/utils/gchelper_m3.s @@ -31,6 +31,18 @@ .section .text .align 2 + .global gc_helper_get_sp + .type gc_helper_get_sp, %function + +@ uint gc_helper_get_sp(void) +gc_helper_get_sp: + @ return the sp + mov r0, sp + bx lr + + .size gc_helper_get_sp, .-gc_helper_get_sp + + .global gc_helper_get_regs_and_sp .type gc_helper_get_regs_and_sp, %function From 8d1275ec0f99805c14b594b84194a138b5a78fcd Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 12 Feb 2019 14:37:41 +1100 Subject: [PATCH 0079/1788] lib/utils/gchelper: Add gchelper.h header file for assembler functions. --- lib/utils/gchelper.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 lib/utils/gchelper.h diff --git a/lib/utils/gchelper.h b/lib/utils/gchelper.h new file mode 100644 index 0000000000..7149b6a72e --- /dev/null +++ b/lib/utils/gchelper.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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_LIB_UTILS_GCHELPER_H +#define MICROPY_INCLUDED_LIB_UTILS_GCHELPER_H + +#include + +uintptr_t gc_helper_get_sp(void); +uintptr_t gc_helper_get_regs_and_sp(uintptr_t *regs); + +#endif // MICROPY_INCLUDED_LIB_UTILS_GCHELPER_H From 3058d4689208a85fe7e56c126424027ebc61da30 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 12 Feb 2019 14:38:30 +1100 Subject: [PATCH 0080/1788] stm32/gccollect: Use gchelper.h header instead of explicit declaration. --- ports/stm32/gccollect.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ports/stm32/gccollect.c b/ports/stm32/gccollect.c index 50880e2891..d92fc5cef0 100644 --- a/ports/stm32/gccollect.c +++ b/ports/stm32/gccollect.c @@ -30,11 +30,10 @@ #include "py/obj.h" #include "py/gc.h" #include "py/mpthread.h" +#include "lib/utils/gchelper.h" #include "gccollect.h" #include "systick.h" -uintptr_t gc_helper_get_regs_and_sp(uintptr_t *regs); - void gc_collect(void) { // get current time, in case we want to time the GC #if 0 From c9ece68d063214da57b5eab00b97ff5121d3f00a Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 12 Feb 2019 14:41:48 +1100 Subject: [PATCH 0081/1788] cc3200: Use common gchelper_m3.s code from lib/utils. --- ports/cc3200/application.mk | 2 +- ports/cc3200/mptask.c | 2 +- ports/cc3200/util/gccollect.c | 2 +- ports/cc3200/util/gchelper.h | 33 ---------------------------- ports/cc3200/util/gchelper.s | 41 ----------------------------------- 5 files changed, 3 insertions(+), 77 deletions(-) delete mode 100644 ports/cc3200/util/gchelper.h delete mode 100644 ports/cc3200/util/gchelper.s diff --git a/ports/cc3200/application.mk b/ports/cc3200/application.mk index 19abe66163..7bfd43d626 100644 --- a/ports/cc3200/application.mk +++ b/ports/cc3200/application.mk @@ -128,7 +128,6 @@ APP_UTIL_SRC_C = $(addprefix util/,\ ) APP_UTIL_SRC_S = $(addprefix util/,\ - gchelper.s \ sleeprestore.s \ ) @@ -159,6 +158,7 @@ APP_STM_SRC_C = $(addprefix ports/stm32/,\ OBJ = $(PY_O) $(addprefix $(BUILD)/, $(APP_FATFS_SRC_C:.c=.o) $(APP_RTOS_SRC_C:.c=.o) $(APP_FTP_SRC_C:.c=.o) $(APP_HAL_SRC_C:.c=.o) $(APP_MISC_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(APP_MODS_SRC_C:.c=.o) $(APP_CC3100_SRC_C:.c=.o) $(APP_SL_SRC_C:.c=.o) $(APP_TELNET_SRC_C:.c=.o) $(APP_UTIL_SRC_C:.c=.o) $(APP_UTIL_SRC_S:.s=.o)) OBJ += $(addprefix $(BUILD)/, $(APP_MAIN_SRC_C:.c=.o) $(APP_LIB_SRC_C:.c=.o) $(APP_STM_SRC_C:.c=.o)) +OBJ += $(BUILD)/lib/utils/gchelper_m3.o OBJ += $(BUILD)/pins.o # List of sources for qstr extraction diff --git a/ports/cc3200/mptask.c b/ports/cc3200/mptask.c index 6143f72a7a..9b6169342c 100644 --- a/ports/cc3200/mptask.c +++ b/ports/cc3200/mptask.c @@ -50,8 +50,8 @@ #include "pybpin.h" #include "pybrtc.h" #include "lib/utils/pyexec.h" +#include "lib/utils/gchelper.h" #include "gccollect.h" -#include "gchelper.h" #include "mperror.h" #include "simplelink.h" #include "modnetwork.h" diff --git a/ports/cc3200/util/gccollect.c b/ports/cc3200/util/gccollect.c index 6e2a9081c8..65b2f1605a 100644 --- a/ports/cc3200/util/gccollect.c +++ b/ports/cc3200/util/gccollect.c @@ -30,8 +30,8 @@ #include "py/gc.h" #include "py/mpthread.h" +#include "lib/utils/gchelper.h" #include "gccollect.h" -#include "gchelper.h" /****************************************************************************** DECLARE PUBLIC FUNCTIONS diff --git a/ports/cc3200/util/gchelper.h b/ports/cc3200/util/gchelper.h deleted file mode 100644 index 48e81bc61d..0000000000 --- a/ports/cc3200/util/gchelper.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2013, 2014 Damien P. George - * Copyright (c) 2015 Daniel Campora - * - * 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_CC3200_UTIL_GCHELPER_H -#define MICROPY_INCLUDED_CC3200_UTIL_GCHELPER_H - -extern mp_uint_t gc_helper_get_sp(void); -extern mp_uint_t gc_helper_get_regs_and_sp(mp_uint_t *regs); - -#endif // MICROPY_INCLUDED_CC3200_UTIL_GCHELPER_H diff --git a/ports/cc3200/util/gchelper.s b/ports/cc3200/util/gchelper.s deleted file mode 100644 index aa8fb499e9..0000000000 --- a/ports/cc3200/util/gchelper.s +++ /dev/null @@ -1,41 +0,0 @@ - .syntax unified - .cpu cortex-m4 - .thumb - .text - .align 2 - - - -@ uint gc_helper_get_sp(void) - .global gc_helper_get_sp - .thumb - .thumb_func - .type gc_helper_get_sp, %function -gc_helper_get_sp: - @ return the sp - mov r0, sp - bx lr - - - -@ uint gc_helper_get_regs_and_sp(r0=uint regs[10]) - .global gc_helper_get_regs_and_sp - .thumb - .thumb_func - .type gc_helper_get_regs_and_sp, %function -gc_helper_get_regs_and_sp: - @ store registers into given array - str r4, [r0], #4 - str r5, [r0], #4 - str r6, [r0], #4 - str r7, [r0], #4 - str r8, [r0], #4 - str r9, [r0], #4 - str r10, [r0], #4 - str r11, [r0], #4 - str r12, [r0], #4 - str r13, [r0], #4 - - @ return the sp - mov r0, sp - bx lr From d53dc04903850fdad7b8c14351e2cf28616a0ead Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 12 Feb 2019 14:48:29 +1100 Subject: [PATCH 0082/1788] qemu-arm: Use gchelper code to get registers for GC scanning. --- ports/qemu-arm/Makefile | 4 ++++ ports/qemu-arm/test_main.c | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/ports/qemu-arm/Makefile b/ports/qemu-arm/Makefile index b3d9cdf566..03a8afe77e 100644 --- a/ports/qemu-arm/Makefile +++ b/ports/qemu-arm/Makefile @@ -13,6 +13,7 @@ ifeq ($(BOARD),netduino2) CFLAGS += -mthumb -mcpu=cortex-m3 -mfloat-abi=soft CFLAGS += -DQEMU_SOC_STM32 LDSCRIPT = stm32.ld +SRC_BOARD_O = lib/utils/gchelper_m3.o endif ifeq ($(BOARD),microbit) @@ -20,12 +21,14 @@ CFLAGS += -mthumb -mcpu=cortex-m0 -mfloat-abi=soft CFLAGS += -DQEMU_SOC_NRF51 LDSCRIPT = nrf51.ld QEMU_EXTRA = -global nrf51-soc.flash-size=1048576 -global nrf51-soc.sram-size=262144 +SRC_BOARD_O = lib/utils/gchelper_m0.o endif ifeq ($(BOARD),mps2-an385) CFLAGS += -mthumb -mcpu=cortex-m3 -mfloat-abi=soft CFLAGS += -DQEMU_SOC_MPS2 LDSCRIPT = mps2.ld +SRC_BOARD_O = lib/utils/gchelper_m3.o endif CROSS_COMPILE = arm-none-eabi- @@ -95,6 +98,7 @@ LIB_SRC_C += $(addprefix lib/,\ OBJ_COMMON = OBJ_COMMON += $(PY_O) OBJ_COMMON += $(addprefix $(BUILD)/, $(SRC_COMMON_C:.c=.o)) +OBJ_COMMON += $(addprefix $(BUILD)/, $(SRC_BOARD_O)) OBJ_COMMON += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) OBJ_RUN = diff --git a/ports/qemu-arm/test_main.c b/ports/qemu-arm/test_main.c index 2cb9e73859..3a85d65f38 100644 --- a/ports/qemu-arm/test_main.c +++ b/ports/qemu-arm/test_main.c @@ -11,6 +11,7 @@ #include "py/stackctrl.h" #include "py/gc.h" #include "py/mperrno.h" +#include "lib/utils/gchelper.h" #include "tinytest.h" #include "tinytest_macros.h" @@ -33,9 +34,8 @@ void gc_collect(void) { gc_collect_start(); // get the registers and the sp - // TODO get registers - volatile mp_uint_t dummy; - void *sp = (void*)&dummy; + uintptr_t regs[10]; + uintptr_t sp = gc_helper_get_regs_and_sp(regs); // trace the stack, including the registers (since they live on the stack in this function) gc_collect_root((void**)sp, ((uint32_t)MP_STATE_THREAD(stack_top) - (uint32_t)sp) / sizeof(uint32_t)); From 019433a17e82f22e8ee24ad1b53156403d4f4a67 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 12 Feb 2019 14:50:27 +1100 Subject: [PATCH 0083/1788] stm32/pendsv: Fix inline asm constant and prefix with # character. --- ports/stm32/pendsv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/stm32/pendsv.c b/ports/stm32/pendsv.c index ba383a7319..2979dc402c 100644 --- a/ports/stm32/pendsv.c +++ b/ports/stm32/pendsv.c @@ -124,7 +124,7 @@ __attribute__((naked)) void PendSV_Handler(void) { // Check if there are any pending calls to dispatch to "ldr r1, pendsv_dispatch_active_ptr\n" "ldr r0, [r1]\n" - "cmp r0, 0\n" + "cmp r0, #0\n" "beq .no_dispatch\n" "mov r2, #0\n" "str r2, [r1]\n" // clear pendsv_dispatch_active @@ -135,7 +135,7 @@ __attribute__((naked)) void PendSV_Handler(void) { // Check if there is an active object to throw via nlr_jump "ldr r1, pendsv_object_ptr\n" "ldr r0, [r1]\n" - "cmp r0, 0\n" + "cmp r0, #0\n" "beq .no_obj\n" #if defined(PENDSV_DEBUG) "str r0, [sp, #8]\n" // store to r0 on stack From eee1e8841a852f374b83e0a3e3b0ff7b66e54243 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 30 Jan 2019 18:49:52 +1100 Subject: [PATCH 0084/1788] py: Downcase all MP_OBJ_IS_xxx macros to make a more consistent C API. These macros could in principle be (inline) functions so it makes sense to have them lower case, to match the other C API functions. The remaining macros that are upper case are: - MP_OBJ_TO_PTR, MP_OBJ_FROM_PTR - MP_OBJ_NEW_SMALL_INT, MP_OBJ_SMALL_INT_VALUE - MP_OBJ_NEW_QSTR, MP_OBJ_QSTR_VALUE - MP_OBJ_FUN_MAKE_SIG - MP_DECLARE_CONST_xxx - MP_DEFINE_CONST_xxx These must remain macros because they are used when defining const data (at least, MP_OBJ_NEW_SMALL_INT is so it makes sense to have MP_OBJ_SMALL_INT_VALUE also a macro). For those macros that have been made lower case, compatibility macros are provided for the old names so that users do not need to change their code immediately. --- py/binary.c | 4 +-- py/builtinevex.c | 6 ++--- py/compile.c | 2 +- py/emitglue.c | 4 +-- py/map.c | 12 ++++----- py/modbuiltins.c | 4 +-- py/mpprint.c | 2 +- py/obj.c | 52 ++++++++++++++++++------------------- py/obj.h | 61 +++++++++++++++++++++++++------------------- py/objarray.c | 26 +++++++++---------- py/objcomplex.c | 10 ++++---- py/objdict.c | 30 +++++++++++----------- py/objenumerate.c | 2 +- py/objexcept.c | 4 +-- py/objfilter.c | 2 +- py/objfloat.c | 2 +- py/objfun.c | 18 ++++++------- py/objgenerator.c | 2 +- py/objint.c | 12 ++++----- py/objint_longlong.c | 16 ++++++------ py/objint_mpz.c | 26 +++++++++---------- py/objlist.c | 34 ++++++++++++------------ py/objmap.c | 2 +- py/objnamedtuple.c | 2 +- py/objobject.c | 2 +- py/objproperty.c | 2 +- py/objrange.c | 4 +-- py/objreversed.c | 2 +- py/objset.c | 14 +++++----- py/objslice.c | 2 +- py/objstr.c | 54 +++++++++++++++++++-------------------- py/objstr.h | 6 ++--- py/objstringio.c | 4 +-- py/objstrunicode.c | 4 +-- py/objtuple.c | 12 ++++----- py/objtype.c | 40 ++++++++++++++--------------- py/objzip.c | 2 +- py/parse.c | 10 ++++---- py/persistentcode.c | 8 +++--- py/runtime.c | 38 +++++++++++++-------------- py/vm.c | 6 ++--- 41 files changed, 277 insertions(+), 268 deletions(-) diff --git a/py/binary.c b/py/binary.c index f509ff0108..bb2b718ced 100644 --- a/py/binary.c +++ b/py/binary.c @@ -293,7 +293,7 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte ** #endif default: #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE - if (MP_OBJ_IS_TYPE(val_in, &mp_type_int)) { + if (mp_obj_is_type(val_in, &mp_type_int)) { mp_obj_int_to_bytes_impl(val_in, struct_type == '>', size, p); return; } else @@ -330,7 +330,7 @@ void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t v break; default: #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE - if (MP_OBJ_IS_TYPE(val_in, &mp_type_int)) { + if (mp_obj_is_type(val_in, &mp_type_int)) { size_t size = mp_binary_get_size('@', typecode, NULL); mp_obj_int_to_bytes_impl(val_in, MP_ENDIANNESS_BIG, size, (uint8_t*)p + index * size); diff --git a/py/builtinevex.c b/py/builtinevex.c index 846603f46b..819e3e1c63 100644 --- a/py/builtinevex.c +++ b/py/builtinevex.c @@ -52,7 +52,7 @@ STATIC mp_obj_t code_execute(mp_obj_code_t *self, mp_obj_dict_t *globals, mp_obj // a bit of a hack: fun_bc will re-set globals, so need to make sure it's // the correct one - if (MP_OBJ_IS_TYPE(self->module_fun, &mp_type_fun_bc)) { + if (mp_obj_is_type(self->module_fun, &mp_type_fun_bc)) { mp_obj_fun_bc_t *fun_bc = MP_OBJ_TO_PTR(self->module_fun); fun_bc->globals = globals; } @@ -114,7 +114,7 @@ STATIC mp_obj_t eval_exec_helper(size_t n_args, const mp_obj_t *args, mp_parse_i mp_obj_dict_t *locals = mp_locals_get(); for (size_t i = 1; i < 3 && i < n_args; ++i) { if (args[i] != mp_const_none) { - if (!MP_OBJ_IS_TYPE(args[i], &mp_type_dict)) { + if (!mp_obj_is_type(args[i], &mp_type_dict)) { mp_raise_TypeError(NULL); } locals = MP_OBJ_TO_PTR(args[i]); @@ -125,7 +125,7 @@ STATIC mp_obj_t eval_exec_helper(size_t n_args, const mp_obj_t *args, mp_parse_i } #if MICROPY_PY_BUILTINS_COMPILE - if (MP_OBJ_IS_TYPE(args[0], &mp_type_code)) { + if (mp_obj_is_type(args[0], &mp_type_code)) { return code_execute(MP_OBJ_TO_PTR(args[0]), globals, locals); } #endif diff --git a/py/compile.c b/py/compile.c index a5bdfa2af6..5b381e41d5 100644 --- a/py/compile.c +++ b/py/compile.c @@ -2939,7 +2939,7 @@ STATIC void check_for_doc_string(compiler_t *comp, mp_parse_node_t pn) { if ((MP_PARSE_NODE_IS_LEAF(pns->nodes[0]) && MP_PARSE_NODE_LEAF_KIND(pns->nodes[0]) == MP_PARSE_NODE_STRING) || (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_const_object) - && MP_OBJ_IS_STR(get_const_object((mp_parse_node_struct_t*)pns->nodes[0])))) { + && mp_obj_is_str(get_const_object((mp_parse_node_struct_t*)pns->nodes[0])))) { // compile the doc string compile_node(comp, pns->nodes[0]); // store the doc string diff --git a/py/emitglue.c b/py/emitglue.c index 064a838007..0e13fd6d1f 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -124,10 +124,10 @@ mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, mp_obj_t def_ar assert(rc != NULL); // def_args must be MP_OBJ_NULL or a tuple - assert(def_args == MP_OBJ_NULL || MP_OBJ_IS_TYPE(def_args, &mp_type_tuple)); + assert(def_args == MP_OBJ_NULL || mp_obj_is_type(def_args, &mp_type_tuple)); // def_kw_args must be MP_OBJ_NULL or a dict - assert(def_kw_args == MP_OBJ_NULL || MP_OBJ_IS_TYPE(def_kw_args, &mp_type_dict)); + assert(def_kw_args == MP_OBJ_NULL || mp_obj_is_type(def_kw_args, &mp_type_dict)); // make the function, depending on the raw code kind mp_obj_t fun; diff --git a/py/map.c b/py/map.c index fc5e1b1b75..fe08a9c6e2 100644 --- a/py/map.c +++ b/py/map.c @@ -150,9 +150,9 @@ mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t // Work out if we can compare just pointers bool compare_only_ptrs = map->all_keys_are_qstrs; if (compare_only_ptrs) { - if (MP_OBJ_IS_QSTR(index)) { + if (mp_obj_is_qstr(index)) { // Index is a qstr, so can just do ptr comparison. - } else if (MP_OBJ_IS_TYPE(index, &mp_type_str)) { + } else if (mp_obj_is_type(index, &mp_type_str)) { // Index is a non-interned string. // We can either intern the string, or force a full equality comparison. // We chose the latter, since interning costs time and potentially RAM, @@ -197,7 +197,7 @@ mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t } mp_map_elem_t *elem = map->table + map->used++; elem->key = index; - if (!MP_OBJ_IS_QSTR(index)) { + if (!mp_obj_is_qstr(index)) { map->all_keys_are_qstrs = 0; } return elem; @@ -218,7 +218,7 @@ mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t // get hash of index, with fast path for common case of qstr mp_uint_t hash; - if (MP_OBJ_IS_QSTR(index)) { + if (mp_obj_is_qstr(index)) { hash = qstr_hash(MP_OBJ_QSTR_VALUE(index)); } else { hash = MP_OBJ_SMALL_INT_VALUE(mp_unary_op(MP_UNARY_OP_HASH, index)); @@ -238,7 +238,7 @@ mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t } avail_slot->key = index; avail_slot->value = MP_OBJ_NULL; - if (!MP_OBJ_IS_QSTR(index)) { + if (!mp_obj_is_qstr(index)) { map->all_keys_are_qstrs = 0; } return avail_slot; @@ -278,7 +278,7 @@ mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t map->used++; avail_slot->key = index; avail_slot->value = MP_OBJ_NULL; - if (!MP_OBJ_IS_QSTR(index)) { + if (!mp_obj_is_qstr(index)) { map->all_keys_are_qstrs = 0; } return avail_slot; diff --git a/py/modbuiltins.c b/py/modbuiltins.c index f0d0421d6c..ac71bc1bb8 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -357,7 +357,7 @@ STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) { size_t 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)) { + if (mp_obj_is_str(o_in)) { len = utf8_charlen(str, len); if (len == 1) { return mp_obj_new_int(utf8_get_char(str)); @@ -471,7 +471,7 @@ 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)) { + if (mp_obj_is_int(o_in)) { if (n_args <= 1) { return o_in; } diff --git a/py/mpprint.c b/py/mpprint.c index c2e65301c9..82e78f62fa 100644 --- a/py/mpprint.c +++ b/py/mpprint.c @@ -207,7 +207,7 @@ int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, int base, int base_char // If needed this function could be generalised to handle other values. assert(base == 2 || base == 8 || base == 10 || base == 16); - if (!MP_OBJ_IS_INT(x)) { + if (!mp_obj_is_int(x)) { // This will convert booleans to int, or raise an error for // non-integer types. x = MP_OBJ_NEW_SMALL_INT(mp_obj_get_int(x)); diff --git a/py/obj.c b/py/obj.c index 7007d5070e..122f0ea624 100644 --- a/py/obj.c +++ b/py/obj.c @@ -38,9 +38,9 @@ #include "py/stream.h" // for mp_obj_print mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in) { - if (MP_OBJ_IS_SMALL_INT(o_in)) { + if (mp_obj_is_small_int(o_in)) { return (mp_obj_type_t*)&mp_type_int; - } else if (MP_OBJ_IS_QSTR(o_in)) { + } else if (mp_obj_is_qstr(o_in)) { return (mp_obj_type_t*)&mp_type_str; #if MICROPY_PY_BUILTINS_FLOAT } else if (mp_obj_is_float(o_in)) { @@ -112,7 +112,7 @@ bool mp_obj_is_true(mp_obj_t arg) { return 1; } else if (arg == mp_const_none) { return 0; - } else if (MP_OBJ_IS_SMALL_INT(arg)) { + } else if (mp_obj_is_small_int(arg)) { if (MP_OBJ_SMALL_INT_VALUE(arg) == 0) { return 0; } else { @@ -167,7 +167,7 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) { && !mp_obj_is_float(o1) #endif #if MICROPY_PY_BUILTINS_COMPLEX - && !MP_OBJ_IS_TYPE(o1, &mp_type_complex) + && !mp_obj_is_type(o1, &mp_type_complex) #endif ) { return true; @@ -177,8 +177,8 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) { } // fast path for small ints - if (MP_OBJ_IS_SMALL_INT(o1)) { - if (MP_OBJ_IS_SMALL_INT(o2)) { + if (mp_obj_is_small_int(o1)) { + if (mp_obj_is_small_int(o2)) { // both SMALL_INT, and not equal if we get here return false; } else { @@ -189,19 +189,19 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) { } // fast path for strings - if (MP_OBJ_IS_STR(o1)) { - if (MP_OBJ_IS_STR(o2)) { + if (mp_obj_is_str(o1)) { + if (mp_obj_is_str(o2)) { // both strings, use special function return mp_obj_str_equal(o1, o2); } else { // a string is never equal to anything else goto str_cmp_err; } - } else if (MP_OBJ_IS_STR(o2)) { + } else if (mp_obj_is_str(o2)) { // o1 is not a string (else caught above), so the objects are not equal str_cmp_err: #if MICROPY_PY_STR_BYTES_CMP_WARN - if (MP_OBJ_IS_TYPE(o1, &mp_type_bytes) || MP_OBJ_IS_TYPE(o2, &mp_type_bytes)) { + if (mp_obj_is_type(o1, &mp_type_bytes) || mp_obj_is_type(o2, &mp_type_bytes)) { mp_warning(MP_WARN_CAT(BytesWarning), "Comparison between bytes and str"); } #endif @@ -230,9 +230,9 @@ mp_int_t mp_obj_get_int(mp_const_obj_t arg) { return 0; } else if (arg == mp_const_true) { return 1; - } else if (MP_OBJ_IS_SMALL_INT(arg)) { + } else if (mp_obj_is_small_int(arg)) { return MP_OBJ_SMALL_INT_VALUE(arg); - } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) { + } else if (mp_obj_is_type(arg, &mp_type_int)) { return mp_obj_int_get_checked(arg); } else { mp_obj_t res = mp_unary_op(MP_UNARY_OP_INT, (mp_obj_t)arg); @@ -241,7 +241,7 @@ 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) { - if (MP_OBJ_IS_INT(arg)) { + if (mp_obj_is_int(arg)) { return mp_obj_int_get_truncated(arg); } else { return mp_obj_get_int(arg); @@ -256,9 +256,9 @@ bool mp_obj_get_int_maybe(mp_const_obj_t arg, mp_int_t *value) { *value = 0; } else if (arg == mp_const_true) { *value = 1; - } else if (MP_OBJ_IS_SMALL_INT(arg)) { + } else if (mp_obj_is_small_int(arg)) { *value = MP_OBJ_SMALL_INT_VALUE(arg); - } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) { + } else if (mp_obj_is_type(arg, &mp_type_int)) { *value = mp_obj_int_get_checked(arg); } else { return false; @@ -274,10 +274,10 @@ bool mp_obj_get_float_maybe(mp_obj_t arg, mp_float_t *value) { val = 0; } else if (arg == mp_const_true) { val = 1; - } else if (MP_OBJ_IS_SMALL_INT(arg)) { + } else if (mp_obj_is_small_int(arg)) { val = MP_OBJ_SMALL_INT_VALUE(arg); #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE - } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) { + } else if (mp_obj_is_type(arg, &mp_type_int)) { val = mp_obj_int_as_float_impl(arg); #endif } else if (mp_obj_is_float(arg)) { @@ -313,18 +313,18 @@ void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) { } else if (arg == mp_const_true) { *real = 1; *imag = 0; - } else if (MP_OBJ_IS_SMALL_INT(arg)) { + } else if (mp_obj_is_small_int(arg)) { *real = MP_OBJ_SMALL_INT_VALUE(arg); *imag = 0; #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE - } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) { + } else if (mp_obj_is_type(arg, &mp_type_int)) { *real = mp_obj_int_as_float_impl(arg); *imag = 0; #endif } else if (mp_obj_is_float(arg)) { *real = mp_obj_float_get(arg); *imag = 0; - } else if (MP_OBJ_IS_TYPE(arg, &mp_type_complex)) { + } else if (mp_obj_is_type(arg, &mp_type_complex)) { mp_obj_complex_get(arg, real, imag); } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { @@ -340,9 +340,9 @@ void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) { // note: returned value in *items may point to the interior of a GC block void mp_obj_get_array(mp_obj_t o, size_t *len, mp_obj_t **items) { - if (MP_OBJ_IS_TYPE(o, &mp_type_tuple)) { + if (mp_obj_is_type(o, &mp_type_tuple)) { mp_obj_tuple_get(o, len, items); - } else if (MP_OBJ_IS_TYPE(o, &mp_type_list)) { + } else if (mp_obj_is_type(o, &mp_type_list)) { mp_obj_list_get(o, len, items); } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { @@ -371,7 +371,7 @@ void mp_obj_get_array_fixed_n(mp_obj_t o, size_t len, mp_obj_t **items) { // is_slice determines whether the index is a slice index size_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool is_slice) { mp_int_t i; - if (MP_OBJ_IS_SMALL_INT(index)) { + if (mp_obj_is_small_int(index)) { i = MP_OBJ_SMALL_INT_VALUE(index); } else if (!mp_obj_get_int_maybe(index, &i)) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { @@ -409,7 +409,7 @@ size_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool mp_obj_t mp_obj_id(mp_obj_t o_in) { mp_int_t id = (mp_int_t)o_in; - if (!MP_OBJ_IS_OBJ(o_in)) { + if (!mp_obj_is_obj(o_in)) { return mp_obj_new_int(id); } else if (id >= 0) { // Many OSes and CPUs have affinity for putting "user" memories @@ -445,9 +445,9 @@ mp_obj_t mp_obj_len_maybe(mp_obj_t o_in) { if ( #if !MICROPY_PY_BUILTINS_STR_UNICODE // It's simple - unicode is slow, non-unicode is fast - MP_OBJ_IS_STR(o_in) || + mp_obj_is_str(o_in) || #endif - MP_OBJ_IS_TYPE(o_in, &mp_type_bytes)) { + mp_obj_is_type(o_in, &mp_type_bytes)) { GET_STR_LEN(o_in, l); return MP_OBJ_NEW_SMALL_INT(l); } else { diff --git a/py/obj.h b/py/obj.h index 5eed90b0ab..1ab4609cfc 100644 --- a/py/obj.h +++ b/py/obj.h @@ -81,12 +81,12 @@ typedef struct _mp_obj_base_t mp_obj_base_t; #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A -static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o) +static inline bool mp_obj_is_small_int(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 1) != 0); } #define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 1) #define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 1) | 1)) -static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) +static inline bool mp_obj_is_qstr(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 3) == 2); } #define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 2) #define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 2) | 2)) @@ -97,22 +97,22 @@ static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) extern const struct _mp_obj_float_t mp_const_float_e_obj; extern const struct _mp_obj_float_t mp_const_float_pi_obj; -#define mp_obj_is_float(o) MP_OBJ_IS_TYPE((o), &mp_type_float) +#define mp_obj_is_float(o) mp_obj_is_type((o), &mp_type_float) mp_float_t mp_obj_float_get(mp_obj_t self_in); mp_obj_t mp_obj_new_float(mp_float_t value); #endif -static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o) +static inline bool mp_obj_is_obj(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 3) == 0); } #elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B -static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o) +static inline bool mp_obj_is_small_int(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 3) == 1); } #define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 2) #define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 2) | 1)) -static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) +static inline bool mp_obj_is_qstr(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 3) == 3); } #define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 2) #define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 2) | 3)) @@ -123,17 +123,17 @@ static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) extern const struct _mp_obj_float_t mp_const_float_e_obj; extern const struct _mp_obj_float_t mp_const_float_pi_obj; -#define mp_obj_is_float(o) MP_OBJ_IS_TYPE((o), &mp_type_float) +#define mp_obj_is_float(o) mp_obj_is_type((o), &mp_type_float) mp_float_t mp_obj_float_get(mp_obj_t self_in); mp_obj_t mp_obj_new_float(mp_float_t value); #endif -static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o) +static inline bool mp_obj_is_obj(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 1) == 0); } #elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C -static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o) +static inline bool mp_obj_is_small_int(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 1) != 0); } #define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 1) #define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 1) | 1)) @@ -160,22 +160,22 @@ static inline mp_obj_t mp_obj_new_float(mp_float_t f) { } #endif -static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) +static inline bool mp_obj_is_qstr(mp_const_obj_t o) { return (((mp_uint_t)(o)) & 0xff800007) == 0x00000006; } #define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 3) #define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 3) | 0x00000006)) -static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o) +static inline bool mp_obj_is_obj(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 3) == 0); } #elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D -static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o) +static inline bool mp_obj_is_small_int(mp_const_obj_t o) { return ((((uint64_t)(o)) & 0xffff000000000000) == 0x0001000000000000); } #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) +static inline bool mp_obj_is_qstr(mp_const_obj_t o) { return ((((uint64_t)(o)) & 0xffff000000000000) == 0x0002000000000000); } #define MP_OBJ_QSTR_VALUE(o) ((((uint32_t)(o)) >> 1) & 0xffffffff) #define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 1) | 0x0002000000000001)) @@ -208,7 +208,7 @@ static inline mp_obj_t mp_obj_new_float(mp_float_t f) { } #endif -static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o) +static inline bool mp_obj_is_obj(mp_const_obj_t o) { return ((((uint64_t)(o)) & 0xffff000000000000) == 0x0000000000000000); } #define MP_OBJ_TO_PTR(o) ((void*)(uintptr_t)(o)) #define MP_OBJ_FROM_PTR(p) ((mp_obj_t)((uintptr_t)(p))) @@ -255,17 +255,6 @@ typedef struct _mp_rom_obj_t { mp_const_obj_t o; } mp_rom_obj_t; */ #endif -// 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)) -#define MP_OBJ_IS_STR(o) (MP_OBJ_IS_QSTR(o) || MP_OBJ_IS_TYPE(o, &mp_type_str)) -#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)) - // These macros are used to declare and define constant function objects // You can put "static" in front of the definitions to make them local @@ -625,6 +614,16 @@ extern const struct _mp_obj_exception_t mp_const_GeneratorExit_obj; // General API for objects +// These macros are derived from more primitive ones 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)) +#define mp_obj_is_str(o) (mp_obj_is_qstr(o) || mp_obj_is_type(o, &mp_type_str)) +#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)) + mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict); static inline mp_obj_t mp_obj_new_bool(mp_int_t x) { return x ? mp_const_true : mp_const_false; } mp_obj_t mp_obj_new_cell(mp_obj_t obj); @@ -677,7 +676,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 +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); @@ -864,4 +863,14 @@ mp_obj_t mp_seq_extract_slice(size_t len, const mp_obj_t *seq, mp_bound_slice_t memmove(((char*)dest) + (beg + slice_len) * (item_sz), ((char*)dest) + (end) * (item_sz), ((dest_len) + (len_adj) - ((beg) + (slice_len))) * (item_sz)); \ memmove(((char*)dest) + (beg) * (item_sz), slice, slice_len * (item_sz)); +// Provide translation for legacy API +#define MP_OBJ_IS_SMALL_INT mp_obj_is_small_int +#define MP_OBJ_IS_QSTR mp_obj_is_qstr +#define MP_OBJ_IS_OBJ mp_obj_is_obj +#define MP_OBJ_IS_INT mp_obj_is_int +#define MP_OBJ_IS_TYPE mp_obj_is_type +#define MP_OBJ_IS_STR mp_obj_is_str +#define MP_OBJ_IS_STR_OR_BYTES mp_obj_is_str_or_bytes +#define MP_OBJ_IS_FUN mp_obj_is_fun + #endif // MICROPY_INCLUDED_PY_OBJ_H diff --git a/py/objarray.c b/py/objarray.c index 6f857a9eda..4a8d0af3cc 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -119,8 +119,8 @@ STATIC mp_obj_t array_construct(char typecode, mp_obj_t initializer) { if (((MICROPY_PY_BUILTINS_BYTEARRAY && typecode == BYTEARRAY_TYPECODE) || (MICROPY_PY_ARRAY - && (MP_OBJ_IS_TYPE(initializer, &mp_type_bytes) - || (MICROPY_PY_BUILTINS_BYTEARRAY && MP_OBJ_IS_TYPE(initializer, &mp_type_bytearray))))) + && (mp_obj_is_type(initializer, &mp_type_bytes) + || (MICROPY_PY_BUILTINS_BYTEARRAY && mp_obj_is_type(initializer, &mp_type_bytearray))))) && mp_get_buffer(initializer, &bufinfo, MP_BUFFER_READ)) { // construct array from raw bytes // we round-down the len to make it a multiple of sz (CPython raises error) @@ -184,7 +184,7 @@ STATIC mp_obj_t bytearray_make_new(const mp_obj_type_t *type_in, size_t n_args, if (n_args == 0) { // no args: construct an empty bytearray return MP_OBJ_FROM_PTR(array_new(BYTEARRAY_TYPECODE, 0)); - } else if (MP_OBJ_IS_INT(args[0])) { + } else if (mp_obj_is_int(args[0])) { // 1 arg, an integer: construct a blank bytearray of that length mp_uint_t len = mp_obj_get_int(args[0]); mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, len); @@ -279,7 +279,7 @@ STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs mp_buffer_info_t lhs_bufinfo; mp_buffer_info_t rhs_bufinfo; if (mp_get_buffer(rhs_in, &rhs_bufinfo, MP_BUFFER_READ)) { - if (!MP_OBJ_IS_TYPE(lhs_in, &mp_type_bytearray)) { + if (!mp_obj_is_type(lhs_in, &mp_type_bytearray)) { return mp_const_false; } array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ); @@ -289,7 +289,7 @@ STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs #endif // Otherwise, can only look for a scalar numeric value in an array - if (MP_OBJ_IS_INT(rhs_in) || mp_obj_is_float(rhs_in)) { + if (mp_obj_is_int(rhs_in) || mp_obj_is_float(rhs_in)) { mp_raise_NotImplementedError(NULL); } @@ -314,8 +314,8 @@ STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs #if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg) { // self is not a memoryview, so we don't need to use (& TYPECODE_MASK) - assert((MICROPY_PY_BUILTINS_BYTEARRAY && MP_OBJ_IS_TYPE(self_in, &mp_type_bytearray)) - || (MICROPY_PY_ARRAY && MP_OBJ_IS_TYPE(self_in, &mp_type_array))); + assert((MICROPY_PY_BUILTINS_BYTEARRAY && mp_obj_is_type(self_in, &mp_type_bytearray)) + || (MICROPY_PY_ARRAY && mp_obj_is_type(self_in, &mp_type_array))); mp_obj_array_t *self = MP_OBJ_TO_PTR(self_in); if (self->free == 0) { @@ -335,8 +335,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(array_append_obj, array_append); STATIC mp_obj_t array_extend(mp_obj_t self_in, mp_obj_t arg_in) { // self is not a memoryview, so we don't need to use (& TYPECODE_MASK) - assert((MICROPY_PY_BUILTINS_BYTEARRAY && MP_OBJ_IS_TYPE(self_in, &mp_type_bytearray)) - || (MICROPY_PY_ARRAY && MP_OBJ_IS_TYPE(self_in, &mp_type_array))); + assert((MICROPY_PY_BUILTINS_BYTEARRAY && mp_obj_is_type(self_in, &mp_type_bytearray)) + || (MICROPY_PY_ARRAY && mp_obj_is_type(self_in, &mp_type_array))); mp_obj_array_t *self = MP_OBJ_TO_PTR(self_in); // allow to extend by anything that has the buffer protocol (extension to CPython) @@ -377,7 +377,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value mp_obj_array_t *o = MP_OBJ_TO_PTR(self_in); if (0) { #if MICROPY_PY_BUILTINS_SLICE - } else if (MP_OBJ_IS_TYPE(index_in, &mp_type_slice)) { + } else if (mp_obj_is_type(index_in, &mp_type_slice)) { mp_bound_slice_t slice; if (!mp_seq_get_fast_slice_indexes(o->len, index_in, &slice)) { mp_raise_NotImplementedError("only slices with step=1 (aka None) are supported"); @@ -388,7 +388,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value size_t src_len; void *src_items; size_t item_sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL); - if (MP_OBJ_IS_OBJ(value) && ((mp_obj_base_t*)MP_OBJ_TO_PTR(value))->type->subscr == array_subscr) { + if (mp_obj_is_obj(value) && ((mp_obj_base_t*)MP_OBJ_TO_PTR(value))->type->subscr == array_subscr) { // value is array, bytearray or memoryview mp_obj_array_t *src_slice = MP_OBJ_TO_PTR(value); if (item_sz != mp_binary_get_size('@', src_slice->typecode & TYPECODE_MASK, NULL)) { @@ -398,11 +398,11 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value src_len = src_slice->len; src_items = src_slice->items; #if MICROPY_PY_BUILTINS_MEMORYVIEW - if (MP_OBJ_IS_TYPE(value, &mp_type_memoryview)) { + if (mp_obj_is_type(value, &mp_type_memoryview)) { src_items = (uint8_t*)src_items + (src_slice->memview_offset * item_sz); } #endif - } else if (MP_OBJ_IS_TYPE(value, &mp_type_bytes)) { + } else if (mp_obj_is_type(value, &mp_type_bytes)) { if (item_sz != 1) { goto compat_error; } diff --git a/py/objcomplex.c b/py/objcomplex.c index 42b396da34..bf6fb51dc5 100644 --- a/py/objcomplex.c +++ b/py/objcomplex.c @@ -79,12 +79,12 @@ STATIC mp_obj_t complex_make_new(const mp_obj_type_t *type_in, size_t n_args, si return mp_obj_new_complex(0, 0); case 1: - if (MP_OBJ_IS_STR(args[0])) { + 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, true, true, NULL); - } else if (MP_OBJ_IS_TYPE(args[0], &mp_type_complex)) { + } else if (mp_obj_is_type(args[0], &mp_type_complex)) { // a complex, just return it return args[0]; } else { @@ -95,13 +95,13 @@ STATIC mp_obj_t complex_make_new(const mp_obj_type_t *type_in, size_t n_args, si case 2: default: { mp_float_t real, imag; - if (MP_OBJ_IS_TYPE(args[0], &mp_type_complex)) { + if (mp_obj_is_type(args[0], &mp_type_complex)) { mp_obj_complex_get(args[0], &real, &imag); } else { real = mp_obj_get_float(args[0]); imag = 0; } - if (MP_OBJ_IS_TYPE(args[1], &mp_type_complex)) { + if (mp_obj_is_type(args[1], &mp_type_complex)) { mp_float_t real2, imag2; mp_obj_complex_get(args[1], &real2, &imag2); real -= imag2; @@ -164,7 +164,7 @@ mp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag) { } void mp_obj_complex_get(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_complex)); + assert(mp_obj_is_type(self_in, &mp_type_complex)); mp_obj_complex_t *self = MP_OBJ_TO_PTR(self_in); *real = self->real; *imag = self->imag; diff --git a/py/objdict.c b/py/objdict.c index 92e837a881..de300f9989 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -31,7 +31,7 @@ #include "py/builtin.h" #include "py/objtype.h" -#define MP_OBJ_IS_DICT_TYPE(o) (MP_OBJ_IS_OBJ(o) && ((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type->make_new == dict_make_new) +#define mp_obj_is_dict_type(o) (mp_obj_is_obj(o) && ((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type->make_new == dict_make_new) STATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs); @@ -121,7 +121,7 @@ STATIC mp_obj_t dict_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_ } case MP_BINARY_OP_EQUAL: { #if MICROPY_PY_COLLECTIONS_ORDEREDDICT - if (MP_UNLIKELY(MP_OBJ_IS_TYPE(lhs_in, &mp_type_ordereddict) && MP_OBJ_IS_TYPE(rhs_in, &mp_type_ordereddict))) { + if (MP_UNLIKELY(mp_obj_is_type(lhs_in, &mp_type_ordereddict) && mp_obj_is_type(rhs_in, &mp_type_ordereddict))) { // Iterate through both dictionaries simultaneously and compare keys and values. mp_obj_dict_t *rhs = MP_OBJ_TO_PTR(rhs_in); size_t c1 = 0, c2 = 0; @@ -134,7 +134,7 @@ STATIC mp_obj_t dict_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_ return e1 == NULL && e2 == NULL ? mp_const_true : mp_const_false; } else #endif - if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_dict)) { + if (mp_obj_is_type(rhs_in, &mp_type_dict)) { mp_obj_dict_t *rhs = MP_OBJ_TO_PTR(rhs_in); if (o->map.used != rhs->map.used) { return mp_const_false; @@ -202,7 +202,7 @@ STATIC void mp_ensure_not_fixed(const mp_obj_dict_t *dict) { } STATIC mp_obj_t dict_clear(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_DICT_TYPE(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); @@ -213,7 +213,7 @@ STATIC mp_obj_t dict_clear(mp_obj_t self_in) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_clear_obj, dict_clear); STATIC mp_obj_t dict_copy(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); + mp_check_self(mp_obj_is_dict_type(self_in)); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t other_out = mp_obj_new_dict(self->map.alloc); mp_obj_dict_t *other = MP_OBJ_TO_PTR(other_out); @@ -260,7 +260,7 @@ STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(dict_fromkeys_obj, MP_ROM_PTR(&dict_fromk #endif 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_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); @@ -305,7 +305,7 @@ STATIC mp_obj_t dict_setdefault(size_t n_args, const mp_obj_t *args) { STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_setdefault_obj, 2, 3, dict_setdefault); STATIC mp_obj_t dict_popitem(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_DICT_TYPE(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; @@ -324,7 +324,7 @@ STATIC mp_obj_t dict_popitem(mp_obj_t self_in) { 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_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); @@ -333,7 +333,7 @@ STATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwarg if (n_args == 2) { // given a positional argument - if (MP_OBJ_IS_DICT_TYPE(args[1])) { + if (mp_obj_is_dict_type(args[1])) { // update from other dictionary (make sure other is not self) if (args[1] != args[0]) { size_t cur = 0; @@ -402,7 +402,7 @@ typedef struct _mp_obj_dict_view_t { } mp_obj_dict_view_t; STATIC mp_obj_t dict_view_it_iternext(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &dict_view_it_type)); + mp_check_self(mp_obj_is_type(self_in, &dict_view_it_type)); mp_obj_dict_view_it_t *self = MP_OBJ_TO_PTR(self_in); mp_map_elem_t *next = dict_iter_next(MP_OBJ_TO_PTR(self->dict), &self->cur); @@ -432,7 +432,7 @@ STATIC const mp_obj_type_t dict_view_it_type = { STATIC mp_obj_t dict_view_getiter(mp_obj_t view_in, mp_obj_iter_buf_t *iter_buf) { assert(sizeof(mp_obj_dict_view_it_t) <= sizeof(mp_obj_iter_buf_t)); - mp_check_self(MP_OBJ_IS_TYPE(view_in, &dict_view_type)); + mp_check_self(mp_obj_is_type(view_in, &dict_view_type)); mp_obj_dict_view_t *view = MP_OBJ_TO_PTR(view_in); mp_obj_dict_view_it_t *o = (mp_obj_dict_view_it_t*)iter_buf; o->base.type = &dict_view_it_type; @@ -444,7 +444,7 @@ STATIC mp_obj_t dict_view_getiter(mp_obj_t view_in, mp_obj_iter_buf_t *iter_buf) STATIC void dict_view_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; - mp_check_self(MP_OBJ_IS_TYPE(self_in, &dict_view_type)); + mp_check_self(mp_obj_is_type(self_in, &dict_view_type)); mp_obj_dict_view_t *self = MP_OBJ_TO_PTR(self_in); bool first = true; mp_print_str(print, mp_dict_view_names[self->kind]); @@ -491,7 +491,7 @@ STATIC mp_obj_t mp_obj_new_dict_view(mp_obj_t dict, mp_dict_view_kind_t kind) { } STATIC mp_obj_t dict_view(mp_obj_t self_in, mp_dict_view_kind_t kind) { - mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); + mp_check_self(mp_obj_is_dict_type(self_in)); return mp_obj_new_dict_view(self_in, kind); } @@ -515,7 +515,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_values_obj, dict_values); 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_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; @@ -592,7 +592,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_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; diff --git a/py/objenumerate.c b/py/objenumerate.c index 1a9d30f836..493e45c2a2 100644 --- a/py/objenumerate.c +++ b/py/objenumerate.c @@ -78,7 +78,7 @@ const mp_obj_type_t mp_type_enumerate = { }; STATIC mp_obj_t enumerate_iternext(mp_obj_t self_in) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_enumerate)); + assert(mp_obj_is_type(self_in, &mp_type_enumerate)); mp_obj_enumerate_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t next = mp_iternext(self->iter); if (next == MP_OBJ_STOP_ITERATION) { diff --git a/py/objexcept.c b/py/objexcept.c index 2a10aa99a4..5899b3427f 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -123,7 +123,7 @@ void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kin } else if (o->args->len == 1) { #if MICROPY_PY_UERRNO // try to provide a nice OSError error message - if (o->base.type == &mp_type_OSError && MP_OBJ_IS_SMALL_INT(o->args->items[0])) { + 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 " INT_FMT "] %q", MP_OBJ_SMALL_INT_VALUE(o->args->items[0]), qst); @@ -447,7 +447,7 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char // return true if the given object is an exception type bool mp_obj_is_exception_type(mp_obj_t self_in) { - if (MP_OBJ_IS_TYPE(self_in, &mp_type_type)) { + if (mp_obj_is_type(self_in, &mp_type_type)) { // optimisation when self_in is a builtin exception mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in); if (self->make_new == mp_obj_exception_make_new) { diff --git a/py/objfilter.c b/py/objfilter.c index cb965d8c32..41b2a3bc5f 100644 --- a/py/objfilter.c +++ b/py/objfilter.c @@ -44,7 +44,7 @@ STATIC mp_obj_t filter_make_new(const mp_obj_type_t *type, size_t n_args, size_t } STATIC mp_obj_t filter_iternext(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_filter)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_filter)); mp_obj_filter_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t next; while ((next = mp_iternext(self->iter)) != MP_OBJ_STOP_ITERATION) { diff --git a/py/objfloat.c b/py/objfloat.c index 4db1bb89e9..3da549bb25 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -174,7 +174,7 @@ STATIC mp_obj_t float_unary_op(mp_unary_op_t op, mp_obj_t o_in) { STATIC mp_obj_t float_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { mp_float_t lhs_val = mp_obj_float_get(lhs_in); #if MICROPY_PY_BUILTINS_COMPLEX - if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_complex)) { + if (mp_obj_is_type(rhs_in, &mp_type_complex)) { return mp_obj_complex_binary_op(op, lhs_val, 0, rhs_in); } else #endif diff --git a/py/objfun.c b/py/objfun.c index a05d446328..38a1a4c279 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -50,7 +50,7 @@ STATIC mp_obj_t fun_builtin_0_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { (void)args; - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_0)); + assert(mp_obj_is_type(self_in, &mp_type_fun_builtin_0)); mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in); mp_arg_check_num(n_args, n_kw, 0, 0, false); return self->fun._0(); @@ -64,7 +64,7 @@ const mp_obj_type_t mp_type_fun_builtin_0 = { }; STATIC mp_obj_t fun_builtin_1_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_1)); + assert(mp_obj_is_type(self_in, &mp_type_fun_builtin_1)); mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in); mp_arg_check_num(n_args, n_kw, 1, 1, false); return self->fun._1(args[0]); @@ -78,7 +78,7 @@ const mp_obj_type_t mp_type_fun_builtin_1 = { }; STATIC mp_obj_t fun_builtin_2_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_2)); + assert(mp_obj_is_type(self_in, &mp_type_fun_builtin_2)); mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in); mp_arg_check_num(n_args, n_kw, 2, 2, false); return self->fun._2(args[0], args[1]); @@ -92,7 +92,7 @@ const mp_obj_type_t mp_type_fun_builtin_2 = { }; STATIC mp_obj_t fun_builtin_3_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_3)); + assert(mp_obj_is_type(self_in, &mp_type_fun_builtin_3)); mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in); mp_arg_check_num(n_args, n_kw, 3, 3, false); return self->fun._3(args[0], args[1], args[2]); @@ -106,7 +106,7 @@ const mp_obj_type_t mp_type_fun_builtin_3 = { }; STATIC mp_obj_t fun_builtin_var_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_var)); + assert(mp_obj_is_type(self_in, &mp_type_fun_builtin_var)); mp_obj_fun_builtin_var_t *self = MP_OBJ_TO_PTR(self_in); // check number of arguments @@ -373,7 +373,7 @@ mp_obj_t mp_obj_new_fun_bc(mp_obj_t def_args_in, mp_obj_t def_kw_args, const byt size_t n_extra_args = 0; mp_obj_tuple_t *def_args = MP_OBJ_TO_PTR(def_args_in); if (def_args_in != MP_OBJ_NULL) { - assert(MP_OBJ_IS_TYPE(def_args_in, &mp_type_tuple)); + assert(mp_obj_is_type(def_args_in, &mp_type_tuple)); n_def_args = def_args->len; n_extra_args = def_args->len; } @@ -442,7 +442,7 @@ typedef mp_uint_t (*inline_asm_fun_4_t)(mp_uint_t, mp_uint_t, mp_uint_t, mp_uint // convert a MicroPython object to a sensible value for inline asm STATIC mp_uint_t convert_obj_for_inline_asm(mp_obj_t obj) { // TODO for byte_array, pass pointer to the array - if (MP_OBJ_IS_SMALL_INT(obj)) { + if (mp_obj_is_small_int(obj)) { return MP_OBJ_SMALL_INT_VALUE(obj); } else if (obj == mp_const_none) { return 0; @@ -450,9 +450,9 @@ STATIC mp_uint_t convert_obj_for_inline_asm(mp_obj_t obj) { return 0; } else if (obj == mp_const_true) { return 1; - } else if (MP_OBJ_IS_TYPE(obj, &mp_type_int)) { + } else if (mp_obj_is_type(obj, &mp_type_int)) { return mp_obj_int_get_truncated(obj); - } else if (MP_OBJ_IS_STR(obj)) { + } else if (mp_obj_is_str(obj)) { // pointer to the string (it's probably constant though!) size_t l; return (mp_uint_t)mp_obj_str_get_data(obj, &l); diff --git a/py/objgenerator.c b/py/objgenerator.c index 348d2d79df..c306bb0c58 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -131,7 +131,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_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) { // Trying to resume already stopped generator diff --git a/py/objint.c b/py/objint.c index d5d74dd558..6473767e41 100644 --- a/py/objint.c +++ b/py/objint.c @@ -49,10 +49,10 @@ STATIC mp_obj_t mp_obj_int_make_new(const mp_obj_type_t *type_in, size_t n_args, return MP_OBJ_NEW_SMALL_INT(0); case 1: - if (MP_OBJ_IS_INT(args[0])) { + if (mp_obj_is_int(args[0])) { // already an int (small or long), just return it return args[0]; - } else if (MP_OBJ_IS_STR_OR_BYTES(args[0])) { + } else if (mp_obj_is_str_or_bytes(args[0])) { // a string, parse it size_t l; const char *s = mp_obj_str_get_data(args[0], &l); @@ -224,11 +224,11 @@ char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_co // 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)) { + 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); } else { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); + assert(mp_obj_is_type(self_in, &mp_type_int)); // Not a small int. #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG const mp_obj_int_t *self = self_in; @@ -375,7 +375,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_OR_BYTES(rhs_in) || 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); } @@ -432,7 +432,7 @@ STATIC mp_obj_t int_to_bytes(size_t n_args, const mp_obj_t *args) { memset(data, 0, len); #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE - if (!MP_OBJ_IS_SMALL_INT(args[0])) { + if (!mp_obj_is_small_int(args[0])) { mp_obj_int_to_bytes_impl(args[0], big_endian, len, data); } else #endif diff --git a/py/objint_longlong.c b/py/objint_longlong.c index 485803cfc5..37e2d6b503 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -58,7 +58,7 @@ mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf } void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); + assert(mp_obj_is_type(self_in, &mp_type_int)); mp_obj_int_t *self = self_in; long long val = self->val; if (big_endian) { @@ -77,7 +77,7 @@ void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byt int mp_obj_int_sign(mp_obj_t self_in) { mp_longint_impl_t val; - if (MP_OBJ_IS_SMALL_INT(self_in)) { + if (mp_obj_is_small_int(self_in)) { val = MP_OBJ_SMALL_INT_VALUE(self_in); } else { mp_obj_int_t *self = self_in; @@ -122,16 +122,16 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i long long lhs_val; long long rhs_val; - if (MP_OBJ_IS_SMALL_INT(lhs_in)) { + if (mp_obj_is_small_int(lhs_in)) { lhs_val = MP_OBJ_SMALL_INT_VALUE(lhs_in); } else { - assert(MP_OBJ_IS_TYPE(lhs_in, &mp_type_int)); + 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)) { + if (mp_obj_is_small_int(rhs_in)) { rhs_val = MP_OBJ_SMALL_INT_VALUE(rhs_in); - } else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_int)) { + } else if (mp_obj_is_type(rhs_in, &mp_type_int)) { rhs_val = ((mp_obj_int_t*)rhs_in)->val; } else { // delegate to generic function to check for extra cases @@ -266,7 +266,7 @@ mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, uns } mp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in) { - if (MP_OBJ_IS_SMALL_INT(self_in)) { + if (mp_obj_is_small_int(self_in)) { return MP_OBJ_SMALL_INT_VALUE(self_in); } else { const mp_obj_int_t *self = self_in; @@ -281,7 +281,7 @@ mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) { #if MICROPY_PY_BUILTINS_FLOAT mp_float_t mp_obj_int_as_float_impl(mp_obj_t self_in) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); + assert(mp_obj_is_type(self_in, &mp_type_int)); mp_obj_int_t *self = self_in; return self->val; } diff --git a/py/objint_mpz.c b/py/objint_mpz.c index e59c123ed0..288e9f86d6 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -90,7 +90,7 @@ mp_obj_int_t *mp_obj_int_new_mpz(void) { // This particular routine should only be called for the mpz representation of the int. char *mp_obj_int_formatted_impl(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) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); + assert(mp_obj_is_type(self_in, &mp_type_int)); const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); size_t needed_size = mp_int_format_size(mpz_max_num_bits(&self->mpz), base, prefix, comma); @@ -112,14 +112,14 @@ mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf } void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); + assert(mp_obj_is_type(self_in, &mp_type_int)); mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); memset(buf, 0, len); mpz_as_bytes(&self->mpz, big_endian, len, buf); } int mp_obj_int_sign(mp_obj_t self_in) { - if (MP_OBJ_IS_SMALL_INT(self_in)) { + if (mp_obj_is_small_int(self_in)) { mp_int_t val = MP_OBJ_SMALL_INT_VALUE(self_in); if (val < 0) { return -1; @@ -167,25 +167,25 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i mpz_dig_t z_int_dig[MPZ_NUM_DIG_FOR_INT]; // lhs could be a small int (eg small-int + mpz) - if (MP_OBJ_IS_SMALL_INT(lhs_in)) { + 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 { - assert(MP_OBJ_IS_TYPE(lhs_in, &mp_type_int)); + 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) - if (MP_OBJ_IS_SMALL_INT(rhs_in)) { + if (mp_obj_is_small_int(rhs_in)) { mpz_init_fixed_from_int(&z_int, z_int_dig, MPZ_NUM_DIG_FOR_INT, MP_OBJ_SMALL_INT_VALUE(rhs_in)); zrhs = &z_int; - } else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_int)) { + } else if (mp_obj_is_type(rhs_in, &mp_type_int)) { zrhs = &((mp_obj_int_t*)MP_OBJ_TO_PTR(rhs_in))->mpz; #if MICROPY_PY_BUILTINS_FLOAT } else if (mp_obj_is_float(rhs_in)) { return mp_obj_float_binary_op(op, mpz_as_float(zlhs), rhs_in); #if MICROPY_PY_BUILTINS_COMPLEX - } else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_complex)) { + } else if (mp_obj_is_type(rhs_in, &mp_type_complex)) { return mp_obj_complex_binary_op(op, mpz_as_float(zlhs), 0, rhs_in); #endif #endif @@ -320,7 +320,7 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i #if MICROPY_PY_BUILTINS_POW3 STATIC mpz_t *mp_mpz_for_int(mp_obj_t arg, mpz_t *temp) { - if (MP_OBJ_IS_SMALL_INT(arg)) { + if (mp_obj_is_small_int(arg)) { mpz_init_from_int(temp, MP_OBJ_SMALL_INT_VALUE(arg)); return temp; } else { @@ -330,7 +330,7 @@ STATIC mpz_t *mp_mpz_for_int(mp_obj_t arg, mpz_t *temp) { } mp_obj_t mp_obj_int_pow3(mp_obj_t base, mp_obj_t exponent, mp_obj_t modulus) { - if (!MP_OBJ_IS_INT(base) || !MP_OBJ_IS_INT(exponent) || !MP_OBJ_IS_INT(modulus)) { + if (!mp_obj_is_int(base) || !mp_obj_is_int(exponent) || !mp_obj_is_int(modulus)) { mp_raise_TypeError("pow() with 3 arguments requires integers"); } else { mp_obj_t result = mp_obj_new_int_from_ull(0); // Use the _from_ull version as this forces an mpz int @@ -387,7 +387,7 @@ mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, uns } mp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in) { - if (MP_OBJ_IS_SMALL_INT(self_in)) { + if (mp_obj_is_small_int(self_in)) { return MP_OBJ_SMALL_INT_VALUE(self_in); } else { const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); @@ -397,7 +397,7 @@ mp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in) { } mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) { - if (MP_OBJ_IS_SMALL_INT(self_in)) { + if (mp_obj_is_small_int(self_in)) { return MP_OBJ_SMALL_INT_VALUE(self_in); } else { const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); @@ -413,7 +413,7 @@ mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) { #if MICROPY_PY_BUILTINS_FLOAT mp_float_t mp_obj_int_as_float_impl(mp_obj_t self_in) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); + assert(mp_obj_is_type(self_in, &mp_type_int)); mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); return mpz_as_float(&self->mpz); } diff --git a/py/objlist.c b/py/objlist.c index 1a18f937d6..ec9d57fc7b 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -104,7 +104,7 @@ STATIC mp_obj_t list_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { mp_obj_list_t *o = MP_OBJ_TO_PTR(lhs); switch (op) { case MP_BINARY_OP_ADD: { - if (!MP_OBJ_IS_TYPE(rhs, &mp_type_list)) { + if (!mp_obj_is_type(rhs, &mp_type_list)) { return MP_OBJ_NULL; // op not supported } mp_obj_list_t *p = MP_OBJ_TO_PTR(rhs); @@ -133,7 +133,7 @@ STATIC mp_obj_t list_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { case MP_BINARY_OP_LESS_EQUAL: case MP_BINARY_OP_MORE: case MP_BINARY_OP_MORE_EQUAL: { - if (!MP_OBJ_IS_TYPE(rhs, &mp_type_list)) { + if (!mp_obj_is_type(rhs, &mp_type_list)) { if (op == MP_BINARY_OP_EQUAL) { return mp_const_false; } @@ -154,7 +154,7 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { if (value == MP_OBJ_NULL) { // delete #if MICROPY_PY_BUILTINS_SLICE - if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + if (mp_obj_is_type(index, &mp_type_slice)) { mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); mp_bound_slice_t slice; if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) { @@ -178,7 +178,7 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { // load mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); #if MICROPY_PY_BUILTINS_SLICE - if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + if (mp_obj_is_type(index, &mp_type_slice)) { mp_bound_slice_t slice; if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) { return mp_seq_extract_slice(self->len, self->items, &slice); @@ -192,7 +192,7 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { return self->items[index_val]; } else { #if MICROPY_PY_BUILTINS_SLICE - if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + if (mp_obj_is_type(index, &mp_type_slice)) { mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); size_t value_len; mp_obj_t *value_items; mp_obj_get_array(value, &value_len, &value_items); @@ -232,7 +232,7 @@ STATIC mp_obj_t list_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) { } mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); if (self->len >= self->alloc) { self->items = m_renew(mp_obj_t, self->items, self->alloc, self->alloc * 2); @@ -244,8 +244,8 @@ mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg) { } STATIC mp_obj_t list_extend(mp_obj_t self_in, mp_obj_t arg_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); - if (MP_OBJ_IS_TYPE(arg_in, &mp_type_list)) { + mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); + if (mp_obj_is_type(arg_in, &mp_type_list)) { mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_list_t *arg = MP_OBJ_TO_PTR(arg_in); @@ -265,7 +265,7 @@ STATIC mp_obj_t list_extend(mp_obj_t self_in, mp_obj_t arg_in) { } STATIC mp_obj_t list_pop(size_t n_args, const mp_obj_t *args) { - mp_check_self(MP_OBJ_IS_TYPE(args[0], &mp_type_list)); + mp_check_self(mp_obj_is_type(args[0], &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(args[0]); if (self->len == 0) { mp_raise_msg(&mp_type_IndexError, "pop from empty list"); @@ -325,7 +325,7 @@ mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args); - mp_check_self(MP_OBJ_IS_TYPE(pos_args[0], &mp_type_list)); + mp_check_self(mp_obj_is_type(pos_args[0], &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(pos_args[0]); if (self->len > 1) { @@ -338,7 +338,7 @@ mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ } STATIC mp_obj_t list_clear(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); self->len = 0; self->items = m_renew(mp_obj_t, self->items, self->alloc, LIST_MIN_ALLOC); @@ -348,25 +348,25 @@ STATIC mp_obj_t list_clear(mp_obj_t self_in) { } STATIC mp_obj_t list_copy(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); return mp_obj_new_list(self->len, self->items); } STATIC mp_obj_t list_count(mp_obj_t self_in, mp_obj_t value) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); return mp_seq_count_obj(self->items, self->len, value); } STATIC mp_obj_t list_index(size_t n_args, const mp_obj_t *args) { - mp_check_self(MP_OBJ_IS_TYPE(args[0], &mp_type_list)); + mp_check_self(mp_obj_is_type(args[0], &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(args[0]); return mp_seq_index_obj(self->items, self->len, n_args, args); } STATIC mp_obj_t list_insert(mp_obj_t self_in, mp_obj_t idx, mp_obj_t obj) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); // insert has its own strange index logic mp_int_t index = MP_OBJ_SMALL_INT_VALUE(idx); @@ -391,7 +391,7 @@ STATIC mp_obj_t list_insert(mp_obj_t self_in, mp_obj_t idx, mp_obj_t obj) { } mp_obj_t mp_obj_list_remove(mp_obj_t self_in, mp_obj_t value) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); mp_obj_t args[] = {self_in, value}; args[1] = list_index(2, args); list_pop(2, args); @@ -400,7 +400,7 @@ mp_obj_t mp_obj_list_remove(mp_obj_t self_in, mp_obj_t value) { } STATIC mp_obj_t list_reverse(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); mp_int_t len = self->len; diff --git a/py/objmap.c b/py/objmap.c index 908c61507e..78c52c8925 100644 --- a/py/objmap.c +++ b/py/objmap.c @@ -49,7 +49,7 @@ STATIC mp_obj_t map_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ } STATIC mp_obj_t map_iternext(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_map)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_map)); mp_obj_map_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t *nextses = m_new(mp_obj_t, self->n_iters); diff --git a/py/objnamedtuple.c b/py/objnamedtuple.c index e7de899cf9..54d8493c37 100644 --- a/py/objnamedtuple.c +++ b/py/objnamedtuple.c @@ -172,7 +172,7 @@ STATIC mp_obj_t new_namedtuple_type(mp_obj_t name_in, mp_obj_t fields_in) { size_t n_fields; mp_obj_t *fields; #if MICROPY_CPYTHON_COMPAT - if (MP_OBJ_IS_STR(fields_in)) { + if (mp_obj_is_str(fields_in)) { fields_in = mp_obj_str_split(1, &fields_in); } #endif diff --git a/py/objobject.c b/py/objobject.c index 265fcfbf2b..45228347e9 100644 --- a/py/objobject.c +++ b/py/objobject.c @@ -49,7 +49,7 @@ STATIC mp_obj_t object___init__(mp_obj_t self) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(object___init___obj, object___init__); 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))) { + 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"); } // This executes only "__new__" part of instance creation. diff --git a/py/objproperty.c b/py/objproperty.c index b66d24a119..49cb9ca1b4 100644 --- a/py/objproperty.c +++ b/py/objproperty.c @@ -99,7 +99,7 @@ const mp_obj_type_t mp_type_property = { }; const mp_obj_t *mp_obj_property_get(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_property)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_property)); mp_obj_property_t *self = MP_OBJ_TO_PTR(self_in); return self->proxy; } diff --git a/py/objrange.c b/py/objrange.c index 86aa0ccfe6..6c3097abd4 100644 --- a/py/objrange.c +++ b/py/objrange.c @@ -140,7 +140,7 @@ 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) { + 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); @@ -162,7 +162,7 @@ STATIC mp_obj_t range_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { mp_obj_range_t *self = MP_OBJ_TO_PTR(self_in); mp_int_t len = range_len(self); #if MICROPY_PY_BUILTINS_SLICE - if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + if (mp_obj_is_type(index, &mp_type_slice)) { mp_bound_slice_t slice; mp_seq_get_fast_slice_indexes(len, index, &slice); mp_obj_range_t *o = m_new_obj(mp_obj_range_t); diff --git a/py/objreversed.c b/py/objreversed.c index e498b553de..4254668e75 100644 --- a/py/objreversed.c +++ b/py/objreversed.c @@ -56,7 +56,7 @@ STATIC mp_obj_t reversed_make_new(const mp_obj_type_t *type, size_t n_args, size } STATIC mp_obj_t reversed_iternext(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_reversed)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_reversed)); mp_obj_reversed_t *self = MP_OBJ_TO_PTR(self_in); // "raise" stop iteration if we are at the end (the start) of the sequence diff --git a/py/objset.c b/py/objset.c index 799ba9df04..d58adb1ffe 100644 --- a/py/objset.c +++ b/py/objset.c @@ -48,15 +48,15 @@ typedef struct _mp_obj_set_it_t { STATIC mp_obj_t set_it_iternext(mp_obj_t self_in); STATIC bool is_set_or_frozenset(mp_obj_t o) { - return MP_OBJ_IS_TYPE(o, &mp_type_set) + return mp_obj_is_type(o, &mp_type_set) #if MICROPY_PY_BUILTINS_FROZENSET - || MP_OBJ_IS_TYPE(o, &mp_type_frozenset) + || mp_obj_is_type(o, &mp_type_frozenset) #endif ; } // This macro is shorthand for mp_check_self to verify the argument is a set. -#define check_set(o) mp_check_self(MP_OBJ_IS_TYPE(o, &mp_type_set)) +#define check_set(o) mp_check_self(mp_obj_is_type(o, &mp_type_set)) // This macro is shorthand for mp_check_self to verify the argument is a // set or frozenset for methods that operate on both of these types. @@ -66,7 +66,7 @@ STATIC void set_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t (void)kind; mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); #if MICROPY_PY_BUILTINS_FROZENSET - bool is_frozen = MP_OBJ_IS_TYPE(self_in, &mp_type_frozenset); + bool is_frozen = mp_obj_is_type(self_in, &mp_type_frozenset); #endif if (self->set.used == 0) { #if MICROPY_PY_BUILTINS_FROZENSET @@ -434,7 +434,7 @@ STATIC mp_obj_t set_unary_op(mp_unary_op_t op, mp_obj_t self_in) { case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->set.used); #if MICROPY_PY_BUILTINS_FROZENSET case MP_UNARY_OP_HASH: - if (MP_OBJ_IS_TYPE(self_in, &mp_type_frozenset)) { + if (mp_obj_is_type(self_in, &mp_type_frozenset)) { // start hash with unique value mp_int_t hash = (mp_int_t)(uintptr_t)&mp_type_frozenset; size_t max = self->set.alloc; @@ -455,7 +455,7 @@ STATIC mp_obj_t set_unary_op(mp_unary_op_t op, mp_obj_t self_in) { STATIC mp_obj_t set_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { mp_obj_t args[] = {lhs, rhs}; #if MICROPY_PY_BUILTINS_FROZENSET - bool update = MP_OBJ_IS_TYPE(lhs, &mp_type_set); + bool update = mp_obj_is_type(lhs, &mp_type_set); #else bool update = true; #endif @@ -590,7 +590,7 @@ mp_obj_t mp_obj_new_set(size_t n_args, mp_obj_t *items) { } void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_set)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_set)); mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); } diff --git a/py/objslice.c b/py/objslice.c index e50aa07897..cfc819edcc 100644 --- a/py/objslice.c +++ b/py/objslice.c @@ -89,7 +89,7 @@ mp_obj_t mp_obj_new_slice(mp_obj_t ostart, mp_obj_t ostop, mp_obj_t ostep) { } void mp_obj_slice_get(mp_obj_t self_in, mp_obj_t *start, mp_obj_t *stop, mp_obj_t *step) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_slice)); + assert(mp_obj_is_type(self_in, &mp_type_slice)); mp_obj_slice_t *self = MP_OBJ_TO_PTR(self_in); *start = self->start; *stop = self->stop; diff --git a/py/objstr.c b/py/objstr.c index 5764c5ae32..1047ea94c9 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -118,7 +118,7 @@ STATIC void str_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t } #endif #if !MICROPY_PY_BUILTINS_STR_UNICODE - bool is_bytes = MP_OBJ_IS_TYPE(self_in, &mp_type_bytes); + bool is_bytes = mp_obj_is_type(self_in, &mp_type_bytes); #else bool is_bytes = true; #endif @@ -155,7 +155,7 @@ mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ default: // 2 or 3 args // TODO: validate 2nd/3rd args - if (MP_OBJ_IS_TYPE(args[0], &mp_type_bytes)) { + if (mp_obj_is_type(args[0], &mp_type_bytes)) { GET_STR_DATA_LEN(args[0], str_data, str_len); GET_STR_HASH(args[0], str_hash); if (str_hash == 0) { @@ -205,7 +205,7 @@ STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, size return mp_const_empty_bytes; } - if (MP_OBJ_IS_STR(args[0])) { + if (mp_obj_is_str(args[0])) { if (n_args < 2 || n_args > 3) { goto wrong_args; } @@ -224,7 +224,7 @@ STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, size goto wrong_args; } - if (MP_OBJ_IS_SMALL_INT(args[0])) { + if (mp_obj_is_small_int(args[0])) { mp_int_t len = MP_OBJ_SMALL_INT_VALUE(args[0]); if (len < 0) { mp_raise_ValueError(NULL); @@ -299,7 +299,7 @@ const byte *find_subbytes(const byte *haystack, size_t hlen, const byte *needle, // Note: this function is used to check if an object is a str or bytes, which // works because both those types use it as their binary_op method. Revisit -// MP_OBJ_IS_STR_OR_BYTES if this fact changes. +// mp_obj_is_str_or_bytes if this fact changes. mp_obj_t mp_obj_str_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { // check for modulo if (op == MP_BINARY_OP_MODULO) { @@ -307,10 +307,10 @@ mp_obj_t mp_obj_str_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i mp_obj_t *args = &rhs_in; size_t n_args = 1; mp_obj_t dict = MP_OBJ_NULL; - if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple)) { + if (mp_obj_is_type(rhs_in, &mp_type_tuple)) { // TODO: Support tuple subclasses? mp_obj_tuple_get(rhs_in, &n_args, &args); - } else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_dict)) { + } else if (mp_obj_is_type(rhs_in, &mp_type_dict)) { dict = rhs_in; } return str_modulo_format(lhs_in, n_args, args, dict); @@ -425,7 +425,7 @@ STATIC mp_obj_t bytes_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { if (value == MP_OBJ_SENTINEL) { // load #if MICROPY_PY_BUILTINS_SLICE - if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + if (mp_obj_is_type(index, &mp_type_slice)) { mp_bound_slice_t slice; if (!mp_seq_get_fast_slice_indexes(self_len, index, &slice)) { mp_raise_NotImplementedError("only slices with step=1 (aka None) are supported"); @@ -446,7 +446,7 @@ STATIC mp_obj_t bytes_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { } STATIC mp_obj_t str_join(mp_obj_t self_in, mp_obj_t arg) { - mp_check_self(MP_OBJ_IS_STR_OR_BYTES(self_in)); + mp_check_self(mp_obj_is_str_or_bytes(self_in)); const mp_obj_type_t *self_type = mp_obj_get_type(self_in); // get separation string @@ -456,7 +456,7 @@ STATIC mp_obj_t str_join(mp_obj_t self_in, mp_obj_t arg) { size_t seq_len; mp_obj_t *seq_items; - if (!MP_OBJ_IS_TYPE(arg, &mp_type_list) && !MP_OBJ_IS_TYPE(arg, &mp_type_tuple)) { + if (!mp_obj_is_type(arg, &mp_type_list) && !mp_obj_is_type(arg, &mp_type_tuple)) { // arg is not a list nor a tuple, try to convert it to a list // TODO: Try to optimize? arg = mp_type_list.make_new(&mp_type_list, 1, 0, &arg); @@ -686,7 +686,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rsplit_obj, 1, 3, str_rsplit); STATIC mp_obj_t str_finder(size_t n_args, const mp_obj_t *args, int direction, bool is_index) { const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); - mp_check_self(MP_OBJ_IS_STR_OR_BYTES(args[0])); + mp_check_self(mp_obj_is_str_or_bytes(args[0])); // check argument type if (mp_obj_get_type(args[1]) != self_type) { @@ -784,7 +784,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_endswith_obj, 2, 3, str_endswith); enum { LSTRIP, RSTRIP, STRIP }; STATIC mp_obj_t str_uni_strip(int type, size_t n_args, const mp_obj_t *args) { - mp_check_self(MP_OBJ_IS_STR_OR_BYTES(args[0])); + mp_check_self(mp_obj_is_str_or_bytes(args[0])); const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); const byte *chars_to_del; @@ -910,7 +910,7 @@ STATIC bool istype(char ch) { } STATIC bool arg_looks_integer(mp_obj_t arg) { - return MP_OBJ_IS_TYPE(arg, &mp_type_bool) || MP_OBJ_IS_INT(arg); + return mp_obj_is_type(arg, &mp_type_bool) || mp_obj_is_int(arg); } STATIC bool arg_looks_numeric(mp_obj_t arg) { @@ -1382,7 +1382,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar } mp_obj_t mp_obj_str_format(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { - mp_check_self(MP_OBJ_IS_STR_OR_BYTES(args[0])); + mp_check_self(mp_obj_is_str_or_bytes(args[0])); GET_STR_DATA_LEN(args[0], str, len); int arg_i = 0; @@ -1393,11 +1393,11 @@ MP_DEFINE_CONST_FUN_OBJ_KW(str_format_obj, 1, mp_obj_str_format); #if MICROPY_PY_BUILTINS_STR_OP_MODULO STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_t *args, mp_obj_t dict) { - mp_check_self(MP_OBJ_IS_STR_OR_BYTES(pattern)); + mp_check_self(mp_obj_is_str_or_bytes(pattern)); GET_STR_DATA_LEN(pattern, str, len); const byte *start_str = str; - bool is_bytes = MP_OBJ_IS_TYPE(pattern, &mp_type_bytes); + bool is_bytes = mp_obj_is_type(pattern, &mp_type_bytes); size_t arg_i = 0; vstr_t vstr; mp_print_t print; @@ -1501,7 +1501,7 @@ not_enough_args: } switch (*str) { case 'c': - if (MP_OBJ_IS_STR(arg)) { + if (mp_obj_is_str(arg)) { size_t slen; const char *s = mp_obj_str_get_data(arg, &slen); if (slen != 1) { @@ -1547,7 +1547,7 @@ not_enough_args: mp_print_t arg_print; vstr_init_print(&arg_vstr, 16, &arg_print); mp_print_kind_t print_kind = (*str == 'r' ? PRINT_REPR : PRINT_STR); - if (print_kind == PRINT_STR && is_bytes && MP_OBJ_IS_TYPE(arg, &mp_type_bytes)) { + if (print_kind == PRINT_STR && is_bytes && mp_obj_is_type(arg, &mp_type_bytes)) { // If we have something like b"%s" % b"1", bytes arg should be // printed undecorated. print_kind = PRINT_RAW; @@ -1592,7 +1592,7 @@ not_enough_args: // The implementation is optimized, returning the original string if there's // nothing to replace. STATIC mp_obj_t str_replace(size_t n_args, const mp_obj_t *args) { - mp_check_self(MP_OBJ_IS_STR_OR_BYTES(args[0])); + mp_check_self(mp_obj_is_str_or_bytes(args[0])); mp_int_t max_rep = -1; if (n_args == 4) { @@ -1700,7 +1700,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_replace_obj, 3, 4, str_replace); #if MICROPY_PY_BUILTINS_STR_COUNT STATIC mp_obj_t str_count(size_t n_args, const mp_obj_t *args) { const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); - mp_check_self(MP_OBJ_IS_STR_OR_BYTES(args[0])); + mp_check_self(mp_obj_is_str_or_bytes(args[0])); // check argument type if (mp_obj_get_type(args[1]) != self_type) { @@ -1742,7 +1742,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_count_obj, 2, 4, str_count); #if MICROPY_PY_BUILTINS_STR_PARTITION STATIC mp_obj_t str_partitioner(mp_obj_t self_in, mp_obj_t arg, int direction) { - mp_check_self(MP_OBJ_IS_STR_OR_BYTES(self_in)); + mp_check_self(mp_obj_is_str_or_bytes(self_in)); mp_obj_type_t *self_type = mp_obj_get_type(self_in); if (self_type != mp_obj_get_type(arg)) { bad_implicit_conversion(arg); @@ -2092,7 +2092,7 @@ mp_obj_t mp_obj_new_bytes(const byte* data, size_t len) { } bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2) { - if (MP_OBJ_IS_QSTR(s1) && MP_OBJ_IS_QSTR(s2)) { + if (mp_obj_is_qstr(s1) && mp_obj_is_qstr(s2)) { return s1 == s2; } else { GET_STR_HASH(s1, h1); @@ -2124,9 +2124,9 @@ STATIC NORETURN void bad_implicit_conversion(mp_obj_t self_in) { // use this if you will anyway convert the string to a qstr // will be more efficient for the case where it's already a qstr qstr mp_obj_str_get_qstr(mp_obj_t self_in) { - if (MP_OBJ_IS_QSTR(self_in)) { + if (mp_obj_is_qstr(self_in)) { return MP_OBJ_QSTR_VALUE(self_in); - } else if (MP_OBJ_IS_TYPE(self_in, &mp_type_str)) { + } else if (mp_obj_is_type(self_in, &mp_type_str)) { mp_obj_str_t *self = MP_OBJ_TO_PTR(self_in); return qstr_from_strn((char*)self->data, self->len); } else { @@ -2137,7 +2137,7 @@ qstr mp_obj_str_get_qstr(mp_obj_t self_in) { // only use this function if you need the str data to be zero terminated // at the moment all strings are zero terminated to help with C ASCIIZ compatibility const char *mp_obj_str_get_str(mp_obj_t self_in) { - if (MP_OBJ_IS_STR_OR_BYTES(self_in)) { + if (mp_obj_is_str_or_bytes(self_in)) { GET_STR_DATA_LEN(self_in, s, l); (void)l; // len unused return (const char*)s; @@ -2147,7 +2147,7 @@ const char *mp_obj_str_get_str(mp_obj_t self_in) { } const char *mp_obj_str_get_data(mp_obj_t self_in, size_t *len) { - if (MP_OBJ_IS_STR_OR_BYTES(self_in)) { + if (mp_obj_is_str_or_bytes(self_in)) { GET_STR_DATA_LEN(self_in, s, l); *len = l; return (const char*)s; @@ -2158,7 +2158,7 @@ const char *mp_obj_str_get_data(mp_obj_t self_in, size_t *len) { #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C const byte *mp_obj_str_get_data_no_check(mp_obj_t self_in, size_t *len) { - if (MP_OBJ_IS_QSTR(self_in)) { + if (mp_obj_is_qstr(self_in)) { return qstr_data(MP_OBJ_QSTR_VALUE(self_in), len); } else { *len = ((mp_obj_str_t*)self_in)->len; diff --git a/py/objstr.h b/py/objstr.h index 4e55cad091..a10d0df8be 100644 --- a/py/objstr.h +++ b/py/objstr.h @@ -41,12 +41,12 @@ typedef struct _mp_obj_str_t { // use this macro to extract the string hash // warning: the hash can be 0, meaning invalid, and must then be explicitly computed from the data #define GET_STR_HASH(str_obj_in, str_hash) \ - mp_uint_t str_hash; if (MP_OBJ_IS_QSTR(str_obj_in)) \ + mp_uint_t str_hash; if (mp_obj_is_qstr(str_obj_in)) \ { str_hash = qstr_hash(MP_OBJ_QSTR_VALUE(str_obj_in)); } else { str_hash = ((mp_obj_str_t*)MP_OBJ_TO_PTR(str_obj_in))->hash; } // use this macro to extract the string length #define GET_STR_LEN(str_obj_in, str_len) \ - size_t str_len; if (MP_OBJ_IS_QSTR(str_obj_in)) \ + size_t str_len; if (mp_obj_is_qstr(str_obj_in)) \ { str_len = qstr_len(MP_OBJ_QSTR_VALUE(str_obj_in)); } else { str_len = ((mp_obj_str_t*)MP_OBJ_TO_PTR(str_obj_in))->len; } // use this macro to extract the string data and length @@ -56,7 +56,7 @@ const byte *mp_obj_str_get_data_no_check(mp_obj_t self_in, size_t *len); size_t str_len; const byte *str_data = mp_obj_str_get_data_no_check(str_obj_in, &str_len); #else #define GET_STR_DATA_LEN(str_obj_in, str_data, str_len) \ - const byte *str_data; size_t str_len; if (MP_OBJ_IS_QSTR(str_obj_in)) \ + const byte *str_data; size_t str_len; if (mp_obj_is_qstr(str_obj_in)) \ { str_data = qstr_data(MP_OBJ_QSTR_VALUE(str_obj_in), &str_len); } \ else { str_len = ((mp_obj_str_t*)MP_OBJ_TO_PTR(str_obj_in))->len; str_data = ((mp_obj_str_t*)MP_OBJ_TO_PTR(str_obj_in))->data; } #endif diff --git a/py/objstringio.c b/py/objstringio.c index eca7ca9470..89b6790312 100644 --- a/py/objstringio.c +++ b/py/objstringio.c @@ -194,12 +194,12 @@ STATIC mp_obj_t stringio_make_new(const mp_obj_type_t *type_in, size_t n_args, s mp_obj_stringio_t *o = stringio_new(type_in); if (n_args > 0) { - if (MP_OBJ_IS_INT(args[0])) { + if (mp_obj_is_int(args[0])) { sz = mp_obj_get_int(args[0]); } else { mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ); - if (MP_OBJ_IS_STR_OR_BYTES(args[0])) { + if (mp_obj_is_str_or_bytes(args[0])) { o->vstr = m_new_obj(vstr_t); vstr_init_fixed_buf(o->vstr, bufinfo.len, bufinfo.buf); o->vstr->len = bufinfo.len; diff --git a/py/objstrunicode.c b/py/objstrunicode.c index eac7171175..78d0b5006e 100644 --- a/py/objstrunicode.c +++ b/py/objstrunicode.c @@ -126,7 +126,7 @@ const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, s // Copied from mp_get_index; I don't want bounds checking, just give me // the integer as-is. (I can't bounds-check without scanning the whole // string; an out-of-bounds index will be caught in the loops below.) - if (MP_OBJ_IS_SMALL_INT(index)) { + if (mp_obj_is_small_int(index)) { i = MP_OBJ_SMALL_INT_VALUE(index); } else if (!mp_obj_get_int_maybe(index, &i)) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "string indices must be integers, not %s", mp_obj_get_type_str(index))); @@ -182,7 +182,7 @@ STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { if (value == MP_OBJ_SENTINEL) { // load #if MICROPY_PY_BUILTINS_SLICE - if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + if (mp_obj_is_type(index, &mp_type_slice)) { mp_obj_t ostart, ostop, ostep; mp_obj_slice_get(index, &ostart, &ostop, &ostep); if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) { diff --git a/py/objtuple.c b/py/objtuple.c index e570a7fb16..39eb940236 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -71,7 +71,7 @@ STATIC mp_obj_t mp_obj_tuple_make_new(const mp_obj_type_t *type_in, size_t n_arg case 1: default: { // 1 argument, an iterable from which we make a new tuple - if (MP_OBJ_IS_TYPE(args[0], &mp_type_tuple)) { + if (mp_obj_is_type(args[0], &mp_type_tuple)) { return args[0]; } @@ -180,7 +180,7 @@ mp_obj_t mp_obj_tuple_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { // load mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); #if MICROPY_PY_BUILTINS_SLICE - if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + if (mp_obj_is_type(index, &mp_type_slice)) { mp_bound_slice_t slice; if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) { mp_raise_NotImplementedError("only slices with step=1 (aka None) are supported"); @@ -198,14 +198,14 @@ mp_obj_t mp_obj_tuple_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { } STATIC mp_obj_t tuple_count(mp_obj_t self_in, mp_obj_t value) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_tuple)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_tuple)); mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); return mp_seq_count_obj(self->items, self->len, value); } STATIC MP_DEFINE_CONST_FUN_OBJ_2(tuple_count_obj, tuple_count); STATIC mp_obj_t tuple_index(size_t n_args, const mp_obj_t *args) { - mp_check_self(MP_OBJ_IS_TYPE(args[0], &mp_type_tuple)); + mp_check_self(mp_obj_is_type(args[0], &mp_type_tuple)); mp_obj_tuple_t *self = MP_OBJ_TO_PTR(args[0]); return mp_seq_index_obj(self->items, self->len, n_args, args); } @@ -249,14 +249,14 @@ mp_obj_t mp_obj_new_tuple(size_t n, const mp_obj_t *items) { } void mp_obj_tuple_get(mp_obj_t self_in, size_t *len, mp_obj_t **items) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_tuple)); + assert(mp_obj_is_type(self_in, &mp_type_tuple)); mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); *len = self->len; *items = &self->items[0]; } void mp_obj_tuple_del(mp_obj_t self_in) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_tuple)); + assert(mp_obj_is_type(self_in, &mp_type_tuple)); mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); m_del_var(mp_obj_tuple_t, mp_obj_t, self->len, self); } diff --git a/py/objtype.c b/py/objtype.c index 68ee74cf5e..8628f482f5 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -72,7 +72,7 @@ STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_t const mp_obj_t *item = parent_tuple->items; const mp_obj_t *top = item + parent_tuple->len; for (; item < top; ++item) { - assert(MP_OBJ_IS_TYPE(*item, &mp_type_type)); + assert(mp_obj_is_type(*item, &mp_type_type)); const mp_obj_type_t *bt = (const mp_obj_type_t *)MP_OBJ_TO_PTR(*item); count += instance_count_native_bases(bt, last_native_base); } @@ -210,7 +210,7 @@ STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_ const mp_obj_t *item = parent_tuple->items; const mp_obj_t *top = item + parent_tuple->len - 1; for (; item < top; ++item) { - assert(MP_OBJ_IS_TYPE(*item, &mp_type_type)); + assert(mp_obj_is_type(*item, &mp_type_type)); mp_obj_type_t *bt = (mp_obj_type_t*)MP_OBJ_TO_PTR(*item); if (bt == &mp_type_object) { // Not a "real" type @@ -223,7 +223,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)); + assert(mp_obj_is_type(*item, &mp_type_type)); type = (mp_obj_type_t*)MP_OBJ_TO_PTR(*item); #endif } else { @@ -430,7 +430,7 @@ STATIC mp_obj_t instance_unary_op(mp_unary_op_t op, mp_obj_t self_in) { break; case MP_UNARY_OP_INT: // Must return int - if (!MP_OBJ_IS_INT(val)) { + if (!mp_obj_is_int(val)) { mp_raise_TypeError(NULL); } break; @@ -618,7 +618,7 @@ STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des } #if MICROPY_PY_BUILTINS_PROPERTY - if (MP_OBJ_IS_TYPE(member, &mp_type_property)) { + if (mp_obj_is_type(member, &mp_type_property)) { // object member is a property; delegate the load to the property // Note: This is an optimisation for code size and execution time. // The proper way to do it is have the functionality just below @@ -698,7 +698,7 @@ STATIC bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t val if (member[0] != MP_OBJ_NULL) { #if MICROPY_PY_BUILTINS_PROPERTY - if (MP_OBJ_IS_TYPE(member[0], &mp_type_property)) { + if (mp_obj_is_type(member[0], &mp_type_property)) { // attribute exists and is a property; delegate the store/delete // Note: This is an optimisation for code size and execution time. // The proper way to do it is have the functionality just below in @@ -933,7 +933,7 @@ STATIC bool check_for_special_accessors(mp_obj_t key, mp_obj_t value) { } #endif #if MICROPY_PY_BUILTINS_PROPERTY - if (MP_OBJ_IS_TYPE(value, &mp_type_property)) { + if (mp_obj_is_type(value, &mp_type_property)) { return true; } #endif @@ -1001,7 +1001,7 @@ STATIC mp_obj_t type_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp } STATIC void type_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_type)); + assert(mp_obj_is_type(self_in, &mp_type_type)); mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in); if (dest[0] == MP_OBJ_NULL) { @@ -1071,10 +1071,10 @@ 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) { // Verify input objects have expected type - if (!MP_OBJ_IS_TYPE(bases_tuple, &mp_type_tuple)) { + if (!mp_obj_is_type(bases_tuple, &mp_type_tuple)) { mp_raise_TypeError(NULL); } - if (!MP_OBJ_IS_TYPE(locals_dict, &mp_type_dict)) { + if (!mp_obj_is_type(locals_dict, &mp_type_dict)) { mp_raise_TypeError(NULL); } @@ -1086,7 +1086,7 @@ 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++) { - if (!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]); @@ -1167,7 +1167,7 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(MP_QSTR___new__), MP_MAP_LOOKUP); if (elem != NULL) { // __new__ slot exists; check if it is a function - if (MP_OBJ_IS_FUN(elem->value)) { + if (mp_obj_is_fun(elem->value)) { // __new__ is a function, wrap it in a staticmethod decorator elem->value = static_class_method_make_new(&mp_type_staticmethod, 1, 0, &elem->value); } @@ -1200,7 +1200,7 @@ 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)) { + 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); @@ -1214,10 +1214,10 @@ STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { return; } - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_super)); + assert(mp_obj_is_type(self_in, &mp_type_super)); mp_obj_super_t *self = MP_OBJ_TO_PTR(self_in); - assert(MP_OBJ_IS_TYPE(self->type, &mp_type_type)); + assert(mp_obj_is_type(self->type, &mp_type_type)); mp_obj_type_t *type = MP_OBJ_TO_PTR(self->type); @@ -1242,7 +1242,7 @@ STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { size_t len = parent_tuple->len; 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)); + 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. @@ -1301,7 +1301,7 @@ bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo) { // not equivalent classes, keep searching base classes // object should always be a type object, but just return false if it's not - if (!MP_OBJ_IS_TYPE(object, &mp_type_type)) { + if (!mp_obj_is_type(object, &mp_type_type)) { return false; } @@ -1337,10 +1337,10 @@ bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo) { STATIC mp_obj_t mp_obj_is_subclass(mp_obj_t object, mp_obj_t classinfo) { size_t len; mp_obj_t *items; - if (MP_OBJ_IS_TYPE(classinfo, &mp_type_type)) { + if (mp_obj_is_type(classinfo, &mp_type_type)) { len = 1; items = &classinfo; - } else if (MP_OBJ_IS_TYPE(classinfo, &mp_type_tuple)) { + } else if (mp_obj_is_type(classinfo, &mp_type_tuple)) { mp_obj_tuple_get(classinfo, &len, &items); } else { mp_raise_TypeError("issubclass() arg 2 must be a class or a tuple of classes"); @@ -1356,7 +1356,7 @@ STATIC mp_obj_t mp_obj_is_subclass(mp_obj_t object, mp_obj_t classinfo) { } STATIC mp_obj_t mp_builtin_issubclass(mp_obj_t object, mp_obj_t classinfo) { - if (!MP_OBJ_IS_TYPE(object, &mp_type_type)) { + if (!mp_obj_is_type(object, &mp_type_type)) { mp_raise_TypeError("issubclass() arg 1 must be a class"); } return mp_obj_is_subclass(object, classinfo); diff --git a/py/objzip.c b/py/objzip.c index 0183925e3c..4abc917c3f 100644 --- a/py/objzip.c +++ b/py/objzip.c @@ -49,7 +49,7 @@ STATIC mp_obj_t zip_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ } STATIC mp_obj_t zip_iternext(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_zip)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_zip)); mp_obj_zip_t *self = MP_OBJ_TO_PTR(self_in); if (self->n_iters == 0) { return MP_OBJ_STOP_ITERATION; diff --git a/py/parse.c b/py/parse.c index 6c5ebbeaf9..66110e7c3d 100644 --- a/py/parse.c +++ b/py/parse.c @@ -338,7 +338,7 @@ bool mp_parse_node_get_int_maybe(mp_parse_node_t pn, mp_obj_t *o) { #else *o = (mp_obj_t)pns->nodes[0]; #endif - return MP_OBJ_IS_INT(*o); + return mp_obj_is_int(*o); } else { return false; } @@ -477,7 +477,7 @@ STATIC void push_result_token(parser_t *parser, uint8_t rule_id) { mp_map_elem_t *elem; 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)) { + if (mp_obj_is_small_int(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); @@ -491,7 +491,7 @@ STATIC void push_result_token(parser_t *parser, uint8_t rule_id) { #endif } 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)) { + if (mp_obj_is_small_int(o)) { pn = mp_parse_node_new_small_int_checked(parser, o); } else { pn = make_node_const_object(parser, lex->tok_line, o); @@ -768,7 +768,7 @@ STATIC bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) { } mp_obj_t dest[2]; mp_load_method_maybe(elem->value, q_attr, dest); - if (!(dest[0] != MP_OBJ_NULL && MP_OBJ_IS_INT(dest[0]) && dest[1] == MP_OBJ_NULL)) { + if (!(dest[0] != MP_OBJ_NULL && mp_obj_is_int(dest[0]) && dest[1] == MP_OBJ_NULL)) { return false; } arg0 = dest[0]; @@ -783,7 +783,7 @@ STATIC bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) { for (size_t i = num_args; i > 0; i--) { pop_result(parser); } - if (MP_OBJ_IS_SMALL_INT(arg0)) { + if (mp_obj_is_small_int(arg0)) { push_result_node(parser, mp_parse_node_new_small_int_checked(parser, arg0)); } else { // TODO reuse memory for parse node struct? diff --git a/py/persistentcode.c b/py/persistentcode.c index 88e958d8ff..aff37036b3 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -272,9 +272,9 @@ STATIC void save_qstr(mp_print_t *print, qstr qst) { } STATIC void save_obj(mp_print_t *print, mp_obj_t o) { - if (MP_OBJ_IS_STR_OR_BYTES(o)) { + if (mp_obj_is_str_or_bytes(o)) { byte obj_type; - if (MP_OBJ_IS_STR(o)) { + if (mp_obj_is_str(o)) { obj_type = 's'; } else { obj_type = 'b'; @@ -291,10 +291,10 @@ STATIC void save_obj(mp_print_t *print, mp_obj_t o) { // we save numbers using a simplistic text representation // TODO could be improved byte obj_type; - if (MP_OBJ_IS_TYPE(o, &mp_type_int)) { + if (mp_obj_is_type(o, &mp_type_int)) { obj_type = 'i'; #if MICROPY_PY_BUILTINS_COMPLEX - } else if (MP_OBJ_IS_TYPE(o, &mp_type_complex)) { + } else if (mp_obj_is_type(o, &mp_type_complex)) { obj_type = 'c'; #endif } else { diff --git a/py/runtime.c b/py/runtime.c index 5a9e383ff3..c93d7d1930 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -223,7 +223,7 @@ mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) { if (op == MP_UNARY_OP_NOT) { // "not x" is the negative of whether "x" is true per Python semantics return mp_obj_new_bool(mp_obj_is_true(arg) == 0); - } else if (MP_OBJ_IS_SMALL_INT(arg)) { + } else if (mp_obj_is_small_int(arg)) { mp_int_t val = MP_OBJ_SMALL_INT_VALUE(arg); switch (op) { case MP_UNARY_OP_BOOL: @@ -253,7 +253,7 @@ mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) { assert(op == MP_UNARY_OP_INVERT); return MP_OBJ_NEW_SMALL_INT(~val); } - } else if (op == MP_UNARY_OP_HASH && MP_OBJ_IS_STR_OR_BYTES(arg)) { + } else if (op == MP_UNARY_OP_HASH && mp_obj_is_str_or_bytes(arg)) { // fast path for hashing str/bytes GET_STR_HASH(arg, h); if (h == 0) { @@ -333,7 +333,7 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { } else { return mp_const_false; } - } else if (MP_OBJ_IS_TYPE(rhs, &mp_type_tuple)) { + } else if (mp_obj_is_type(rhs, &mp_type_tuple)) { mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(rhs); for (size_t i = 0; i < tuple->len; i++) { rhs = tuple->items[i]; @@ -349,9 +349,9 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { goto unsupported_op; } - if (MP_OBJ_IS_SMALL_INT(lhs)) { + if (mp_obj_is_small_int(lhs)) { mp_int_t lhs_val = MP_OBJ_SMALL_INT_VALUE(lhs); - if (MP_OBJ_IS_SMALL_INT(rhs)) { + if (mp_obj_is_small_int(rhs)) { mp_int_t rhs_val = MP_OBJ_SMALL_INT_VALUE(rhs); // This is a binary operation: lhs_val op rhs_val // We need to be careful to handle overflow; see CERT INT32-C @@ -526,7 +526,7 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { return res; } #if MICROPY_PY_BUILTINS_COMPLEX - } else if (MP_OBJ_IS_TYPE(rhs, &mp_type_complex)) { + } else if (mp_obj_is_type(rhs, &mp_type_complex)) { mp_obj_t res = mp_obj_complex_binary_op(op, lhs_val, 0, rhs); if (res == MP_OBJ_NULL) { goto unsupported_op; @@ -673,7 +673,7 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ // Try to get a hint for the size of the kw_dict uint kw_dict_len = 0; - if (kw_dict != MP_OBJ_NULL && MP_OBJ_IS_TYPE(kw_dict, &mp_type_dict)) { + if (kw_dict != MP_OBJ_NULL && mp_obj_is_type(kw_dict, &mp_type_dict)) { kw_dict_len = mp_obj_dict_len(kw_dict); } @@ -695,7 +695,7 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ mp_seq_copy(args2 + args2_len, args, n_args, mp_obj_t); args2_len += n_args; - } else if (MP_OBJ_IS_TYPE(pos_seq, &mp_type_tuple) || MP_OBJ_IS_TYPE(pos_seq, &mp_type_list)) { + } else if (mp_obj_is_type(pos_seq, &mp_type_tuple) || mp_obj_is_type(pos_seq, &mp_type_list)) { // optimise the case of a tuple and list // get the items @@ -756,7 +756,7 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ // Note that it can be arbitrary iterator. if (kw_dict == MP_OBJ_NULL) { // pass - } else if (MP_OBJ_IS_TYPE(kw_dict, &mp_type_dict)) { + } else if (mp_obj_is_type(kw_dict, &mp_type_dict)) { // dictionary mp_map_t *map = mp_obj_dict_get_map(kw_dict); assert(args2_len + 2 * map->used <= args2_alloc); // should have enough, since kw_dict_len is in this case hinted correctly above @@ -764,7 +764,7 @@ 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_QSTR(key)) { + if (!mp_obj_is_qstr(key)) { key = mp_obj_str_intern_checked(key); } args2[args2_len++] = key; @@ -794,7 +794,7 @@ 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_QSTR(key)) { + if (!mp_obj_is_qstr(key)) { key = mp_obj_str_intern_checked(key); } @@ -829,7 +829,7 @@ mp_obj_t mp_call_method_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ob // unpacked items are stored in reverse order into the array pointed to by items void mp_unpack_sequence(mp_obj_t seq_in, size_t num, mp_obj_t *items) { size_t seq_len; - if (MP_OBJ_IS_TYPE(seq_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(seq_in, &mp_type_list)) { + if (mp_obj_is_type(seq_in, &mp_type_tuple) || mp_obj_is_type(seq_in, &mp_type_list)) { mp_obj_t *seq_items; mp_obj_get_array(seq_in, &seq_len, &seq_items); if (seq_len < num) { @@ -879,7 +879,7 @@ void mp_unpack_ex(mp_obj_t seq_in, size_t num_in, mp_obj_t *items) { size_t num_right = (num_in >> 8) & 0xff; DEBUG_OP_printf("unpack ex " UINT_FMT " " UINT_FMT "\n", num_left, num_right); size_t seq_len; - if (MP_OBJ_IS_TYPE(seq_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(seq_in, &mp_type_list)) { + if (mp_obj_is_type(seq_in, &mp_type_tuple) || mp_obj_is_type(seq_in, &mp_type_list)) { mp_obj_t *seq_items; mp_obj_get_array(seq_in, &seq_len, &seq_items); if (seq_len < num_left + num_right) { @@ -993,10 +993,10 @@ STATIC mp_obj_t mp_obj_new_checked_fun(const mp_obj_type_t *type, mp_obj_t fun) // Conversion means dealing with static/class methods, callables, and values. // see http://docs.python.org/3/howto/descriptor.html void mp_convert_member_lookup(mp_obj_t self, const mp_obj_type_t *type, mp_obj_t member, mp_obj_t *dest) { - if (MP_OBJ_IS_TYPE(member, &mp_type_staticmethod)) { + if (mp_obj_is_type(member, &mp_type_staticmethod)) { // return just the function dest[0] = ((mp_obj_static_class_method_t*)MP_OBJ_TO_PTR(member))->fun; - } else if (MP_OBJ_IS_TYPE(member, &mp_type_classmethod)) { + } else if (mp_obj_is_type(member, &mp_type_classmethod)) { // return a bound method, with self being the type of this object // this type should be the type of the original instance, not the base // type (which is what is passed in the 'type' argument to this function) @@ -1005,11 +1005,11 @@ void mp_convert_member_lookup(mp_obj_t self, const mp_obj_type_t *type, mp_obj_t } dest[0] = ((mp_obj_static_class_method_t*)MP_OBJ_TO_PTR(member))->fun; dest[1] = MP_OBJ_FROM_PTR(type); - } else if (MP_OBJ_IS_TYPE(member, &mp_type_type)) { + } else if (mp_obj_is_type(member, &mp_type_type)) { // Don't try to bind types (even though they're callable) dest[0] = member; - } else if (MP_OBJ_IS_FUN(member) - || (MP_OBJ_IS_OBJ(member) + } else if (mp_obj_is_fun(member) + || (mp_obj_is_obj(member) && (((mp_obj_base_t*)MP_OBJ_TO_PTR(member))->type->name == MP_QSTR_closure || ((mp_obj_base_t*)MP_OBJ_TO_PTR(member))->type->name == MP_QSTR_generator))) { // only functions, closures and generators objects can be bound to self @@ -1087,7 +1087,7 @@ void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) { mp_raise_msg(&mp_type_AttributeError, "no such attribute"); } else { // following CPython, we give a more detailed error message for type objects - if (MP_OBJ_IS_TYPE(base, &mp_type_type)) { + if (mp_obj_is_type(base, &mp_type_type)) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, "type object '%q' has no attribute '%q'", ((mp_obj_type_t*)MP_OBJ_TO_PTR(base))->name, attr)); diff --git a/py/vm.c b/py/vm.c index d8d287f25a..a0ee2e89a4 100644 --- a/py/vm.c +++ b/py/vm.c @@ -604,7 +604,7 @@ dispatch_loop: sp -= 2; mp_call_method_n_kw(3, 0, sp); SET_TOP(mp_const_none); - } else if (MP_OBJ_IS_SMALL_INT(TOP())) { + } else if (mp_obj_is_small_int(TOP())) { // 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)) @@ -699,7 +699,7 @@ unwind_jump:; // if TOS is an exception, reraises the exception if (TOP() == mp_const_none) { sp--; - } else if (MP_OBJ_IS_SMALL_INT(TOP())) { + } else if (mp_obj_is_small_int(TOP())) { // We finished "finally" coroutine and now dispatch back // to our caller, based on TOS value mp_int_t cause = MP_OBJ_SMALL_INT_VALUE(POP()); @@ -1150,7 +1150,7 @@ yield: ENTRY(MP_BC_YIELD_FROM): { MARK_EXC_IP_SELECTIVE(); -//#define EXC_MATCH(exc, type) MP_OBJ_IS_TYPE(exc, type) +//#define EXC_MATCH(exc, type) mp_obj_is_type(exc, type) #define EXC_MATCH(exc, type) mp_obj_exception_match(exc, type) #define GENERATOR_EXIT_IF_NEEDED(t) if (t != MP_OBJ_NULL && EXC_MATCH(t, MP_OBJ_FROM_PTR(&mp_type_GeneratorExit))) { mp_obj_t raise_t = mp_make_raise_obj(t); RAISE(raise_t); } mp_vm_return_kind_t ret_kind; From 054dd33ebad67f5c8f328036fd32c3871589a386 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 30 Jan 2019 21:57:29 +1100 Subject: [PATCH 0085/1788] py: Downcase MP_xxx_SLOT_IS_FILLED inline functions. --- py/builtinhelp.c | 2 +- py/map.c | 2 +- py/modbuiltins.c | 2 +- py/modthread.c | 2 +- py/obj.h | 6 ++++-- py/objdict.c | 4 ++-- py/objset.c | 6 +++--- py/objtype.c | 4 ++-- py/runtime.c | 4 ++-- 9 files changed, 17 insertions(+), 15 deletions(-) diff --git a/py/builtinhelp.c b/py/builtinhelp.c index 3b0ad71e64..a7fede00ac 100644 --- a/py/builtinhelp.c +++ b/py/builtinhelp.c @@ -58,7 +58,7 @@ STATIC void mp_help_print_info_about_object(mp_obj_t name_o, mp_obj_t value) { #if MICROPY_PY_BUILTINS_HELP_MODULES STATIC void mp_help_add_from_map(mp_obj_t list, const mp_map_t *map) { for (size_t i = 0; i < map->alloc; i++) { - if (MP_MAP_SLOT_IS_FILLED(map, i)) { + if (mp_map_slot_is_filled(map, i)) { mp_obj_list_append(list, map->table[i].key); } } diff --git a/py/map.c b/py/map.c index fe08a9c6e2..5f3c6e5473 100644 --- a/py/map.c +++ b/py/map.c @@ -395,7 +395,7 @@ mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t looku mp_obj_t mp_set_remove_first(mp_set_t *set) { for (size_t pos = 0; pos < set->alloc; pos++) { - if (MP_SET_SLOT_IS_FILLED(set, pos)) { + if (mp_set_slot_is_filled(set, pos)) { mp_obj_t elem = set->table[pos]; // delete element set->used--; diff --git a/py/modbuiltins.c b/py/modbuiltins.c index ac71bc1bb8..a65f3beecf 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -178,7 +178,7 @@ STATIC mp_obj_t mp_builtin_dir(size_t n_args, const mp_obj_t *args) { // 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)) { + if (mp_map_slot_is_filled(&dict->map, i)) { mp_obj_list_append(dir, dict->map.table[i].key); } } diff --git a/py/modthread.c b/py/modthread.c index 61ada50351..91237a72b3 100644 --- a/py/modthread.c +++ b/py/modthread.c @@ -242,7 +242,7 @@ STATIC mp_obj_t mod_thread_start_new_thread(size_t n_args, const mp_obj_t *args) th_args->n_kw = map->used; // copy across the keyword arguments for (size_t i = 0, n = pos_args_len; i < map->alloc; ++i) { - if (MP_MAP_SLOT_IS_FILLED(map, i)) { + if (mp_map_slot_is_filled(map, i)) { th_args->args[n++] = map->table[i].key; th_args->args[n++] = map->table[i].value; } diff --git a/py/obj.h b/py/obj.h index 1ab4609cfc..8fdcfc835a 100644 --- a/py/obj.h +++ b/py/obj.h @@ -362,7 +362,7 @@ typedef enum _mp_map_lookup_kind_t { extern const mp_map_t mp_const_empty_map; -static inline bool MP_MAP_SLOT_IS_FILLED(const mp_map_t *map, size_t pos) { return ((map)->table[pos].key != MP_OBJ_NULL && (map)->table[pos].key != MP_OBJ_SENTINEL); } +static inline bool mp_map_slot_is_filled(const mp_map_t *map, size_t pos) { return ((map)->table[pos].key != MP_OBJ_NULL && (map)->table[pos].key != MP_OBJ_SENTINEL); } void mp_map_init(mp_map_t *map, size_t n); void mp_map_init_fixed_table(mp_map_t *map, size_t n, const mp_obj_t *table); @@ -381,7 +381,7 @@ typedef struct _mp_set_t { mp_obj_t *table; } mp_set_t; -static inline bool MP_SET_SLOT_IS_FILLED(const mp_set_t *set, size_t pos) { return ((set)->table[pos] != MP_OBJ_NULL && (set)->table[pos] != MP_OBJ_SENTINEL); } +static inline bool mp_set_slot_is_filled(const mp_set_t *set, size_t pos) { return ((set)->table[pos] != MP_OBJ_NULL && (set)->table[pos] != MP_OBJ_SENTINEL); } void mp_set_init(mp_set_t *set, size_t n); mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t lookup_kind); @@ -872,5 +872,7 @@ mp_obj_t mp_seq_extract_slice(size_t len, const mp_obj_t *seq, mp_bound_slice_t #define MP_OBJ_IS_STR mp_obj_is_str #define MP_OBJ_IS_STR_OR_BYTES mp_obj_is_str_or_bytes #define MP_OBJ_IS_FUN mp_obj_is_fun +#define MP_MAP_SLOT_IS_FILLED mp_map_slot_is_filled +#define MP_SET_SLOT_IS_FILLED mp_set_slot_is_filled #endif // MICROPY_INCLUDED_PY_OBJ_H diff --git a/py/objdict.c b/py/objdict.c index de300f9989..015c2c72fe 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -43,7 +43,7 @@ STATIC mp_map_elem_t *dict_iter_next(mp_obj_dict_t *dict, size_t *cur) { mp_map_t *map = &dict->map; for (size_t i = *cur; i < max; i++) { - if (MP_MAP_SLOT_IS_FILLED(map, i)) { + if (mp_map_slot_is_filled(map, i)) { *cur = i + 1; return &(map->table[i]); } @@ -364,7 +364,7 @@ STATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwarg // update the dict with any keyword args for (size_t i = 0; i < kwargs->alloc; i++) { - if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) { + if (mp_map_slot_is_filled(kwargs, i)) { mp_map_lookup(&self->map, kwargs->table[i].key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = kwargs->table[i].value; } } diff --git a/py/objset.c b/py/objset.c index d58adb1ffe..88e9d5cc6f 100644 --- a/py/objset.c +++ b/py/objset.c @@ -85,7 +85,7 @@ STATIC void set_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t #endif mp_print_str(print, "{"); for (size_t i = 0; i < self->set.alloc; i++) { - if (MP_SET_SLOT_IS_FILLED(&self->set, i)) { + if (mp_set_slot_is_filled(&self->set, i)) { if (!first) { mp_print_str(print, ", "); } @@ -135,7 +135,7 @@ STATIC mp_obj_t set_it_iternext(mp_obj_t self_in) { mp_set_t *set = &self->set->set; for (size_t i = self->cur; i < max; i++) { - if (MP_SET_SLOT_IS_FILLED(set, i)) { + if (mp_set_slot_is_filled(set, i)) { self->cur = i + 1; return set->table[i]; } @@ -441,7 +441,7 @@ STATIC mp_obj_t set_unary_op(mp_unary_op_t op, mp_obj_t self_in) { mp_set_t *set = &self->set; for (size_t i = 0; i < max; i++) { - if (MP_SET_SLOT_IS_FILLED(set, i)) { + if (mp_set_slot_is_filled(set, i)) { hash += MP_OBJ_SMALL_INT_VALUE(mp_unary_op(MP_UNARY_OP_HASH, set->table[i])); } } diff --git a/py/objtype.c b/py/objtype.c index 8628f482f5..3e65a32f0c 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -594,7 +594,7 @@ STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des mp_map_t *map = &self->members; mp_obj_t attr_dict = mp_obj_new_dict(map->used); for (size_t i = 0; i < map->alloc; ++i) { - if (MP_MAP_SLOT_IS_FILLED(map, i)) { + if (mp_map_slot_is_filled(map, i)) { mp_obj_dict_store(attr_dict, map->table[i].key, map->table[i].value); } } @@ -1146,7 +1146,7 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) // 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)) { + 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; diff --git a/py/runtime.c b/py/runtime.c index c93d7d1930..7f8ff84e53 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -761,7 +761,7 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ mp_map_t *map = mp_obj_dict_get_map(kw_dict); assert(args2_len + 2 * map->used <= args2_alloc); // should have enough, since kw_dict_len is in this case hinted correctly above for (size_t i = 0; i < map->alloc; i++) { - if (MP_MAP_SLOT_IS_FILLED(map, i)) { + 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_qstr(key)) { @@ -1393,7 +1393,7 @@ void mp_import_all(mp_obj_t module) { // TODO: Support __all__ mp_map_t *map = &mp_obj_module_get_globals(module)->map; for (size_t i = 0; i < map->alloc; i++) { - if (MP_MAP_SLOT_IS_FILLED(map, i)) { + if (mp_map_slot_is_filled(map, i)) { // Entry in module global scope may be generated programmatically // (and thus be not a qstr for longer names). Avoid turning it in // qstr if it has '_' and was used exactly to save memory. From f03601779e7abe733a8411d62329098d47d9f215 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 30 Jan 2019 22:04:54 +1100 Subject: [PATCH 0086/1788] extmod: Convert legacy uppercase macro names to lowercase. --- extmod/machine_signal.c | 2 +- extmod/moductypes.c | 38 +++++++++++++++++++------------------- extmod/moduheapq.c | 2 +- extmod/moduselect.c | 8 ++++---- extmod/modutimeq.c | 2 +- extmod/vfs.c | 4 ++-- extmod/vfs_posix.c | 2 +- extmod/vfs_posix_file.c | 2 +- 8 files changed, 30 insertions(+), 30 deletions(-) diff --git a/extmod/machine_signal.c b/extmod/machine_signal.c index 3f9f5af947..c494490b60 100644 --- a/extmod/machine_signal.c +++ b/extmod/machine_signal.c @@ -49,7 +49,7 @@ STATIC mp_obj_t signal_make_new(const mp_obj_type_t *type, size_t n_args, size_t #if defined(MICROPY_PY_MACHINE_PIN_MAKE_NEW) mp_pin_p_t *pin_p = NULL; - if (MP_OBJ_IS_OBJ(pin)) { + if (mp_obj_is_obj(pin)) { mp_obj_base_t *pin_base = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]); pin_p = (mp_pin_p_t*)pin_base->type->protocol; } diff --git a/extmod/moductypes.c b/extmod/moductypes.c index 68cd5fca9e..9b46371f36 100644 --- a/extmod/moductypes.c +++ b/extmod/moductypes.c @@ -137,13 +137,13 @@ STATIC void uctypes_struct_print(const mp_print_t *print, mp_obj_t self_in, mp_p (void)kind; mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in); const char *typen = "unk"; - if (MP_OBJ_IS_TYPE(self->desc, &mp_type_dict) + if (mp_obj_is_type(self->desc, &mp_type_dict) #if MICROPY_PY_COLLECTIONS_ORDEREDDICT - || MP_OBJ_IS_TYPE(self->desc, &mp_type_ordereddict) + || mp_obj_is_type(self->desc, &mp_type_ordereddict) #endif ) { typen = "STRUCT"; - } else if (MP_OBJ_IS_TYPE(self->desc, &mp_type_tuple)) { + } else if (mp_obj_is_type(self->desc, &mp_type_tuple)) { mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc); mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]); uint agg_type = GET_TYPE(offset, AGG_TYPE_BITS); @@ -210,14 +210,14 @@ STATIC mp_uint_t uctypes_struct_agg_size(mp_obj_tuple_t *t, int layout_type, mp_ } STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, int layout_type, mp_uint_t *max_field_size) { - if (!MP_OBJ_IS_TYPE(desc_in, &mp_type_dict) + if (!mp_obj_is_type(desc_in, &mp_type_dict) #if MICROPY_PY_COLLECTIONS_ORDEREDDICT - && !MP_OBJ_IS_TYPE(desc_in, &mp_type_ordereddict) + && !mp_obj_is_type(desc_in, &mp_type_ordereddict) #endif ) { - if (MP_OBJ_IS_TYPE(desc_in, &mp_type_tuple)) { + if (mp_obj_is_type(desc_in, &mp_type_tuple)) { return uctypes_struct_agg_size((mp_obj_tuple_t*)MP_OBJ_TO_PTR(desc_in), layout_type, max_field_size); - } else if (MP_OBJ_IS_SMALL_INT(desc_in)) { + } else if (mp_obj_is_small_int(desc_in)) { // We allow sizeof on both type definitions and structures/structure fields, // but scalar structure field is lowered into native Python int, so all // type info is lost. So, we cannot say if it's scalar type description, @@ -231,9 +231,9 @@ STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, int layout_type, mp_uint_ mp_uint_t total_size = 0; for (mp_uint_t i = 0; i < d->map.alloc; i++) { - if (MP_MAP_SLOT_IS_FILLED(&d->map, i)) { + if (mp_map_slot_is_filled(&d->map, i)) { mp_obj_t v = d->map.table[i].value; - if (MP_OBJ_IS_SMALL_INT(v)) { + if (mp_obj_is_small_int(v)) { mp_uint_t offset = MP_OBJ_SMALL_INT_VALUE(v); mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS); offset &= VALUE_MASK(VAL_TYPE_BITS); @@ -248,7 +248,7 @@ STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, int layout_type, mp_uint_ total_size = offset + s; } } else { - if (!MP_OBJ_IS_TYPE(v, &mp_type_tuple)) { + if (!mp_obj_is_type(v, &mp_type_tuple)) { syntax_error(); } mp_obj_tuple_t *t = MP_OBJ_TO_PTR(v); @@ -272,13 +272,13 @@ STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, int layout_type, mp_uint_ STATIC mp_obj_t uctypes_struct_sizeof(size_t n_args, const mp_obj_t *args) { mp_obj_t obj_in = args[0]; mp_uint_t max_field_size = 0; - if (MP_OBJ_IS_TYPE(obj_in, &mp_type_bytearray)) { + if (mp_obj_is_type(obj_in, &mp_type_bytearray)) { return mp_obj_len(obj_in); } int layout_type = LAYOUT_NATIVE; // We can apply sizeof either to structure definition (a dict) // or to instantiated structure - if (MP_OBJ_IS_TYPE(obj_in, &uctypes_struct_type)) { + if (mp_obj_is_type(obj_in, &uctypes_struct_type)) { if (n_args != 1) { mp_raise_TypeError(NULL); } @@ -406,16 +406,16 @@ STATIC void set_aligned(uint val_type, void *p, mp_int_t index, mp_obj_t val) { STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set_val) { mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in); - if (!MP_OBJ_IS_TYPE(self->desc, &mp_type_dict) + if (!mp_obj_is_type(self->desc, &mp_type_dict) #if MICROPY_PY_COLLECTIONS_ORDEREDDICT - && !MP_OBJ_IS_TYPE(self->desc, &mp_type_ordereddict) + && !mp_obj_is_type(self->desc, &mp_type_ordereddict) #endif ) { mp_raise_TypeError("struct: no fields"); } mp_obj_t deref = mp_obj_dict_get(self->desc, MP_OBJ_NEW_QSTR(attr)); - if (MP_OBJ_IS_SMALL_INT(deref)) { + if (mp_obj_is_small_int(deref)) { mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(deref); mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS); offset &= VALUE_MASK(VAL_TYPE_BITS); @@ -476,7 +476,7 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set return MP_OBJ_NULL; } - if (!MP_OBJ_IS_TYPE(deref, &mp_type_tuple)) { + if (!mp_obj_is_type(deref, &mp_type_tuple)) { syntax_error(); } @@ -543,7 +543,7 @@ STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_ob return MP_OBJ_NULL; // op not supported } else { // load / store - if (!MP_OBJ_IS_TYPE(self->desc, &mp_type_tuple)) { + if (!mp_obj_is_type(self->desc, &mp_type_tuple)) { mp_raise_TypeError("struct: cannot index"); } @@ -594,7 +594,7 @@ STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_ob } else if (agg_type == PTR) { byte *p = *(void**)self->addr; - if (MP_OBJ_IS_SMALL_INT(t->items[1])) { + if (mp_obj_is_small_int(t->items[1])) { uint val_type = GET_TYPE(MP_OBJ_SMALL_INT_VALUE(t->items[1]), VAL_TYPE_BITS); return get_aligned(val_type, p, index); } else { @@ -618,7 +618,7 @@ STATIC mp_obj_t uctypes_struct_unary_op(mp_unary_op_t op, mp_obj_t self_in) { mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in); switch (op) { case MP_UNARY_OP_INT: - if (MP_OBJ_IS_TYPE(self->desc, &mp_type_tuple)) { + if (mp_obj_is_type(self->desc, &mp_type_tuple)) { mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc); mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]); uint agg_type = GET_TYPE(offset, AGG_TYPE_BITS); diff --git a/extmod/moduheapq.c b/extmod/moduheapq.c index 71c15368bf..bdaf191e94 100644 --- a/extmod/moduheapq.c +++ b/extmod/moduheapq.c @@ -32,7 +32,7 @@ // the algorithm here is modelled on CPython's heapq.py STATIC mp_obj_list_t *get_heap(mp_obj_t heap_in) { - if (!MP_OBJ_IS_TYPE(heap_in, &mp_type_list)) { + if (!mp_obj_is_type(heap_in, &mp_type_list)) { mp_raise_TypeError("heap must be a list"); } return MP_OBJ_TO_PTR(heap_in); diff --git a/extmod/moduselect.c b/extmod/moduselect.c index 582814b0b6..13bf5611e7 100644 --- a/extmod/moduselect.c +++ b/extmod/moduselect.c @@ -77,7 +77,7 @@ STATIC void poll_map_add(mp_map_t *poll_map, const mp_obj_t *obj, mp_uint_t obj_ STATIC mp_uint_t poll_map_poll(mp_map_t *poll_map, size_t *rwx_num) { mp_uint_t n_ready = 0; for (mp_uint_t i = 0; i < poll_map->alloc; ++i) { - if (!MP_MAP_SLOT_IS_FILLED(poll_map, i)) { + if (!mp_map_slot_is_filled(poll_map, i)) { continue; } @@ -155,7 +155,7 @@ STATIC mp_obj_t select_select(uint n_args, const mp_obj_t *args) { list_array[2] = mp_obj_new_list(rwx_len[2], NULL); rwx_len[0] = rwx_len[1] = rwx_len[2] = 0; for (mp_uint_t i = 0; i < poll_map.alloc; ++i) { - if (!MP_MAP_SLOT_IS_FILLED(&poll_map, i)) { + if (!mp_map_slot_is_filled(&poll_map, i)) { continue; } poll_obj_t *poll_obj = MP_OBJ_TO_PTR(poll_map.table[i].value); @@ -266,7 +266,7 @@ STATIC mp_obj_t poll_poll(size_t n_args, const mp_obj_t *args) { mp_obj_list_t *ret_list = MP_OBJ_TO_PTR(mp_obj_new_list(n_ready, NULL)); n_ready = 0; for (mp_uint_t i = 0; i < self->poll_map.alloc; ++i) { - if (!MP_MAP_SLOT_IS_FILLED(&self->poll_map, i)) { + if (!mp_map_slot_is_filled(&self->poll_map, i)) { continue; } poll_obj_t *poll_obj = MP_OBJ_TO_PTR(self->poll_map.table[i].value); @@ -309,7 +309,7 @@ STATIC mp_obj_t poll_iternext(mp_obj_t self_in) { for (mp_uint_t i = self->iter_idx; i < self->poll_map.alloc; ++i) { self->iter_idx++; - if (!MP_MAP_SLOT_IS_FILLED(&self->poll_map, i)) { + if (!mp_map_slot_is_filled(&self->poll_map, i)) { continue; } poll_obj_t *poll_obj = MP_OBJ_TO_PTR(self->poll_map.table[i].value); diff --git a/extmod/modutimeq.c b/extmod/modutimeq.c index 620e7484b9..26f5a78fae 100644 --- a/extmod/modutimeq.c +++ b/extmod/modutimeq.c @@ -145,7 +145,7 @@ STATIC mp_obj_t mod_utimeq_heappop(mp_obj_t heap_in, mp_obj_t list_ref) { nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "empty heap")); } mp_obj_list_t *ret = MP_OBJ_TO_PTR(list_ref); - if (!MP_OBJ_IS_TYPE(list_ref, &mp_type_list) || ret->len < 3) { + if (!mp_obj_is_type(list_ref, &mp_type_list) || ret->len < 3) { mp_raise_TypeError(NULL); } diff --git a/extmod/vfs.c b/extmod/vfs.c index fd7f2a4feb..f99be3098b 100644 --- a/extmod/vfs.c +++ b/extmod/vfs.c @@ -227,7 +227,7 @@ mp_obj_t mp_vfs_umount(mp_obj_t mnt_in) { mp_vfs_mount_t *vfs = NULL; size_t mnt_len; const char *mnt_str = NULL; - if (MP_OBJ_IS_STR(mnt_in)) { + if (mp_obj_is_str(mnt_in)) { mnt_str = mp_obj_str_get_data(mnt_in, &mnt_len); } for (mp_vfs_mount_t **vfsp = &MP_STATE_VM(vfs_mount_table); *vfsp != NULL; vfsp = &(*vfsp)->next) { @@ -270,7 +270,7 @@ mp_obj_t mp_vfs_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) #if MICROPY_VFS_POSIX // If the file is an integer then delegate straight to the POSIX handler - if (MP_OBJ_IS_SMALL_INT(args[ARG_file].u_obj)) { + if (mp_obj_is_small_int(args[ARG_file].u_obj)) { return mp_vfs_posix_file_open(&mp_type_textio, args[ARG_file].u_obj, args[ARG_mode].u_obj); } #endif diff --git a/extmod/vfs_posix.c b/extmod/vfs_posix.c index 4ca7f9b908..4ef761956c 100644 --- a/extmod/vfs_posix.c +++ b/extmod/vfs_posix.c @@ -130,7 +130,7 @@ STATIC mp_obj_t vfs_posix_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode && (strchr(mode, 'w') != NULL || strchr(mode, 'a') != NULL || strchr(mode, '+') != NULL)) { mp_raise_OSError(MP_EROFS); } - if (!MP_OBJ_IS_SMALL_INT(path_in)) { + 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); diff --git a/extmod/vfs_posix_file.c b/extmod/vfs_posix_file.c index 435ac65cd4..44cb85dcc7 100644 --- a/extmod/vfs_posix_file.c +++ b/extmod/vfs_posix_file.c @@ -94,7 +94,7 @@ mp_obj_t mp_vfs_posix_file_open(const mp_obj_type_t *type, mp_obj_t file_in, mp_ mp_obj_t fid = file_in; - if (MP_OBJ_IS_SMALL_INT(fid)) { + if (mp_obj_is_small_int(fid)) { o->fd = MP_OBJ_SMALL_INT_VALUE(fid); return MP_OBJ_FROM_PTR(o); } From 6e30f96b0b0ab14853085e5300d80d7c1a6f67c5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 30 Jan 2019 22:05:48 +1100 Subject: [PATCH 0087/1788] ports: Convert legacy uppercase macro names to lowercase. --- ports/cc3200/hal/cc3200_hal.c | 4 ++-- ports/cc3200/mods/modmachine.c | 2 +- ports/cc3200/mods/moduos.c | 2 +- ports/cc3200/mods/modwlan.c | 2 +- ports/cc3200/mods/pybpin.c | 2 +- ports/cc3200/mods/pybrtc.c | 2 +- ports/esp32/modnetwork.c | 4 ++-- ports/esp32/modsocket.c | 2 +- ports/esp8266/modesp.c | 2 +- ports/esp8266/modnetwork.c | 2 +- ports/nrf/boards/microbit/modules/microbitdisplay.c | 4 ++-- ports/nrf/boards/microbit/modules/microbitimage.c | 2 +- ports/nrf/modules/machine/pin.c | 6 +++--- ports/nrf/modules/machine/pwm.c | 2 +- ports/nrf/modules/machine/rtcounter.c | 2 +- ports/nrf/modules/machine/spi.c | 2 +- ports/nrf/modules/machine/timer.c | 2 +- ports/nrf/modules/music/modmusic.c | 2 +- ports/nrf/modules/ubluepy/ubluepy_characteristic.c | 2 +- ports/nrf/modules/ubluepy/ubluepy_peripheral.c | 4 ++-- ports/nrf/modules/ubluepy/ubluepy_service.c | 4 ++-- ports/nrf/modules/ubluepy/ubluepy_uuid.c | 6 +++--- ports/stm32/adc.c | 2 +- ports/stm32/bufhelper.c | 4 ++-- ports/stm32/can.c | 8 ++++---- ports/stm32/dac.c | 2 +- ports/stm32/extint.c | 4 ++-- ports/stm32/machine_i2c.c | 2 +- ports/stm32/machine_uart.c | 2 +- ports/stm32/main.c | 2 +- ports/stm32/pin.c | 4 ++-- ports/stm32/pyb_i2c.c | 2 +- ports/stm32/spi.c | 6 +++--- ports/stm32/timer.c | 6 +++--- ports/teensy/main.c | 6 +++--- ports/teensy/reg.c | 2 +- ports/teensy/timer.c | 4 ++-- ports/teensy/uart.c | 2 +- ports/unix/coverage.c | 2 +- ports/unix/file.c | 2 +- ports/unix/modffi.c | 8 ++++---- ports/unix/modjni.c | 4 ++-- ports/unix/modtermios.c | 2 +- ports/unix/moduselect.c | 4 ++-- ports/unix/modusocket.c | 10 +++++----- ports/zephyr/machine_pin.c | 2 +- 46 files changed, 77 insertions(+), 77 deletions(-) diff --git a/ports/cc3200/hal/cc3200_hal.c b/ports/cc3200/hal/cc3200_hal.c index 0285d05856..526874f33b 100644 --- a/ports/cc3200/hal/cc3200_hal.c +++ b/ports/cc3200/hal/cc3200_hal.c @@ -148,7 +148,7 @@ void mp_hal_stdout_tx_str(const char *str) { void mp_hal_stdout_tx_strn(const char *str, size_t len) { if (MP_STATE_PORT(os_term_dup_obj)) { - if (MP_OBJ_IS_TYPE(MP_STATE_PORT(os_term_dup_obj)->stream_o, &pyb_uart_type)) { + if (mp_obj_is_type(MP_STATE_PORT(os_term_dup_obj)->stream_o, &pyb_uart_type)) { uart_tx_strn(MP_STATE_PORT(os_term_dup_obj)->stream_o, str, len); } else { MP_STATE_PORT(os_term_dup_obj)->write[2] = mp_obj_new_str_of_type(&mp_type_str, (const byte *)str, len); @@ -184,7 +184,7 @@ int mp_hal_stdin_rx_chr(void) { if (telnet_rx_any()) { return telnet_rx_char(); } else if (MP_STATE_PORT(os_term_dup_obj)) { // then the stdio_dup - if (MP_OBJ_IS_TYPE(MP_STATE_PORT(os_term_dup_obj)->stream_o, &pyb_uart_type)) { + if (mp_obj_is_type(MP_STATE_PORT(os_term_dup_obj)->stream_o, &pyb_uart_type)) { if (uart_rx_any(MP_STATE_PORT(os_term_dup_obj)->stream_o)) { return uart_rx_char(MP_STATE_PORT(os_term_dup_obj)->stream_o); } diff --git a/ports/cc3200/mods/modmachine.c b/ports/cc3200/mods/modmachine.c index 1ae26f3be9..9e49e23436 100644 --- a/ports/cc3200/mods/modmachine.c +++ b/ports/cc3200/mods/modmachine.c @@ -122,7 +122,7 @@ STATIC mp_obj_t machine_unique_id(void) { STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id); STATIC mp_obj_t machine_main(mp_obj_t main) { - if (MP_OBJ_IS_STR(main)) { + if (mp_obj_is_str(main)) { MP_STATE_PORT(machine_config_main) = main; } else { mp_raise_ValueError(mpexception_value_invalid_arguments); diff --git a/ports/cc3200/mods/moduos.c b/ports/cc3200/mods/moduos.c index 7d99c8e80d..4c9d4a87a7 100644 --- a/ports/cc3200/mods/moduos.c +++ b/ports/cc3200/mods/moduos.c @@ -133,7 +133,7 @@ STATIC mp_obj_t os_dupterm(uint n_args, const mp_obj_t *args) { if (stream_o == mp_const_none) { MP_STATE_PORT(os_term_dup_obj) = MP_OBJ_NULL; } else { - if (!MP_OBJ_IS_TYPE(stream_o, &pyb_uart_type)) { + if (!mp_obj_is_type(stream_o, &pyb_uart_type)) { // must be a stream-like object providing at least read and write methods mp_load_method(stream_o, MP_QSTR_read, os_term_dup_obj.read); mp_load_method(stream_o, MP_QSTR_write, os_term_dup_obj.write); diff --git a/ports/cc3200/mods/modwlan.c b/ports/cc3200/mods/modwlan.c index 8acc89da38..d6f7638c70 100644 --- a/ports/cc3200/mods/modwlan.c +++ b/ports/cc3200/mods/modwlan.c @@ -1012,7 +1012,7 @@ STATIC mp_obj_t wlan_ifconfig(size_t n_args, const mp_obj_t *pos_args, mp_map_t }; return mp_obj_new_tuple(4, ifconfig); } else { // set the configuration - if (MP_OBJ_IS_TYPE(args[1].u_obj, &mp_type_tuple)) { + if (mp_obj_is_type(args[1].u_obj, &mp_type_tuple)) { // set a static ip mp_obj_t *items; mp_obj_get_array_fixed_n(args[1].u_obj, 4, &items); diff --git a/ports/cc3200/mods/pybpin.c b/ports/cc3200/mods/pybpin.c index 9e7526fa91..3872f70c5f 100644 --- a/ports/cc3200/mods/pybpin.c +++ b/ports/cc3200/mods/pybpin.c @@ -131,7 +131,7 @@ pin_obj_t *pin_find(mp_obj_t user_obj) { pin_obj_t *pin_obj; // if a pin was provided, use it - if (MP_OBJ_IS_TYPE(user_obj, &pin_type)) { + if (mp_obj_is_type(user_obj, &pin_type)) { pin_obj = user_obj; return pin_obj; } diff --git a/ports/cc3200/mods/pybrtc.c b/ports/cc3200/mods/pybrtc.c index e7b9cf258f..a8e001efb4 100644 --- a/ports/cc3200/mods/pybrtc.c +++ b/ports/cc3200/mods/pybrtc.c @@ -367,7 +367,7 @@ STATIC mp_obj_t pyb_rtc_alarm(size_t n_args, const mp_obj_t *pos_args, mp_map_t uint32_t f_seconds; uint16_t f_mseconds; bool repeat = args[2].u_bool; - if (MP_OBJ_IS_TYPE(args[1].u_obj, &mp_type_tuple)) { // datetime tuple given + if (mp_obj_is_type(args[1].u_obj, &mp_type_tuple)) { // datetime tuple given // repeat cannot be used with a datetime tuple if (repeat) { mp_raise_ValueError(mpexception_value_invalid_arguments); diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index e2e1560c1a..6342f336b0 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -461,7 +461,7 @@ STATIC mp_obj_t esp_ifconfig(size_t n_args, const mp_obj_t *args) { return mp_obj_new_tuple(4, tuple); } else { // set - if (MP_OBJ_IS_TYPE(args[1], &mp_type_tuple) || MP_OBJ_IS_TYPE(args[1], &mp_type_list)) { + if (mp_obj_is_type(args[1], &mp_type_tuple) || mp_obj_is_type(args[1], &mp_type_list)) { 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); @@ -518,7 +518,7 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs if (kwargs->used != 0) { for (size_t i = 0; i < kwargs->alloc; i++) { - if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) { + if (mp_map_slot_is_filled(kwargs, i)) { int req_if = -1; #define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x) diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c index 9d14fd46a1..49e48aaa31 100644 --- a/ports/esp32/modsocket.c +++ b/ports/esp32/modsocket.c @@ -157,7 +157,7 @@ static int _socket_getaddrinfo2(const mp_obj_t host, const mp_obj_t portx, struc }; mp_obj_t port = portx; - if (MP_OBJ_IS_SMALL_INT(port)) { + 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); diff --git a/ports/esp8266/modesp.c b/ports/esp8266/modesp.c index 46cd24c030..6c9fa9e131 100644 --- a/ports/esp8266/modesp.c +++ b/ports/esp8266/modesp.c @@ -87,7 +87,7 @@ STATIC mp_obj_t esp_flash_read(mp_obj_t offset_in, mp_obj_t len_or_buf_in) { mp_int_t len; byte *buf; - bool alloc_buf = MP_OBJ_IS_INT(len_or_buf_in); + bool alloc_buf = mp_obj_is_int(len_or_buf_in); if (alloc_buf) { len = mp_obj_get_int(len_or_buf_in); diff --git a/ports/esp8266/modnetwork.c b/ports/esp8266/modnetwork.c index 6ef2d315d6..c58aae1cbd 100644 --- a/ports/esp8266/modnetwork.c +++ b/ports/esp8266/modnetwork.c @@ -347,7 +347,7 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs if (kwargs->used != 0) { for (mp_uint_t i = 0; i < kwargs->alloc; i++) { - if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) { + if (mp_map_slot_is_filled(kwargs, i)) { #define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x) switch ((uintptr_t)kwargs->table[i].key) { case QS(MP_QSTR_mac): { diff --git a/ports/nrf/boards/microbit/modules/microbitdisplay.c b/ports/nrf/boards/microbit/modules/microbitdisplay.c index e8e7b2befb..11ec004d07 100644 --- a/ports/nrf/boards/microbit/modules/microbitdisplay.c +++ b/ports/nrf/boards/microbit/modules/microbitdisplay.c @@ -88,7 +88,7 @@ mp_obj_t microbit_display_show_func(mp_uint_t n_args, const mp_obj_t *pos_args, bool wait = args[3].u_bool; bool loop = args[4].u_bool; - if (MP_OBJ_IS_STR(image)) { + if (mp_obj_is_str(image)) { // arg is a string object mp_uint_t len; const char *str = mp_obj_str_get_data(image, &len); @@ -296,7 +296,7 @@ static void draw_object(mp_obj_t obj) { } } else if (mp_obj_get_type(obj) == µbit_image_type) { microbit_display_show(display, (microbit_image_obj_t *)obj); - } else if (MP_OBJ_IS_STR(obj)) { + } else if (mp_obj_is_str(obj)) { mp_uint_t len; const char *str = mp_obj_str_get_data(obj, &len); if (len == 1) { diff --git a/ports/nrf/boards/microbit/modules/microbitimage.c b/ports/nrf/boards/microbit/modules/microbitimage.c index 046b9255cf..aa519b4a2a 100644 --- a/ports/nrf/boards/microbit/modules/microbitimage.c +++ b/ports/nrf/boards/microbit/modules/microbitimage.c @@ -214,7 +214,7 @@ STATIC mp_obj_t microbit_image_make_new(const mp_obj_type_t *type_in, mp_uint_t } case 1: { - if (MP_OBJ_IS_STR(args[0])) { + if (mp_obj_is_str(args[0])) { // arg is a string object mp_uint_t len; const char *str = mp_obj_str_get_data(args[0], &len); diff --git a/ports/nrf/modules/machine/pin.c b/ports/nrf/modules/machine/pin.c index 8a16dc4081..d56abfd04e 100644 --- a/ports/nrf/modules/machine/pin.c +++ b/ports/nrf/modules/machine/pin.c @@ -126,7 +126,7 @@ void pin_init0(void) { const pin_obj_t *pin_find(mp_obj_t user_obj) { const pin_obj_t *pin_obj; // If pin is SMALL_INT - if (MP_OBJ_IS_SMALL_INT(user_obj)) { + if (mp_obj_is_small_int(user_obj)) { uint8_t value = MP_OBJ_SMALL_INT_VALUE(user_obj); for (uint8_t i = 0; i < machine_pin_num_of_pins; i++) { if (machine_pin_obj[i].pin == value) { @@ -136,7 +136,7 @@ const pin_obj_t *pin_find(mp_obj_t user_obj) { } // If a pin was provided, then use it - if (MP_OBJ_IS_TYPE(user_obj, &pin_type)) { + if (mp_obj_is_type(user_obj, &pin_type)) { pin_obj = user_obj; if (pin_class_debug) { printf("Pin map passed pin "); @@ -149,7 +149,7 @@ const pin_obj_t *pin_find(mp_obj_t user_obj) { if (MP_STATE_PORT(pin_class_mapper) != mp_const_none) { pin_obj = mp_call_function_1(MP_STATE_PORT(pin_class_mapper), user_obj); if (pin_obj != mp_const_none) { - if (!MP_OBJ_IS_TYPE(pin_obj, &pin_type)) { + if (!mp_obj_is_type(pin_obj, &pin_type)) { mp_raise_ValueError("Pin.mapper didn't return a Pin object"); } if (pin_class_debug) { diff --git a/ports/nrf/modules/machine/pwm.c b/ports/nrf/modules/machine/pwm.c index 8e5c2e23fd..e3b40930fd 100644 --- a/ports/nrf/modules/machine/pwm.c +++ b/ports/nrf/modules/machine/pwm.c @@ -93,7 +93,7 @@ void pwm_init0(void) { STATIC int hard_pwm_find(mp_obj_t id) { - if (MP_OBJ_IS_INT(id)) { + if (mp_obj_is_int(id)) { // given an integer id int pwm_id = mp_obj_get_int(id); if (pwm_id >= 0 && pwm_id < MP_ARRAY_SIZE(machine_hard_pwm_obj)) { diff --git a/ports/nrf/modules/machine/rtcounter.c b/ports/nrf/modules/machine/rtcounter.c index 0afdf5bd21..d51791905c 100644 --- a/ports/nrf/modules/machine/rtcounter.c +++ b/ports/nrf/modules/machine/rtcounter.c @@ -159,7 +159,7 @@ STATIC mp_obj_t machine_rtc_make_new(const mp_obj_type_t *type, size_t n_args, s if (args[ARG_callback].u_obj == mp_const_none) { config->callback = NULL; - } else if (MP_OBJ_IS_FUN(args[ARG_callback].u_obj)) { + } else if (mp_obj_is_fun(args[ARG_callback].u_obj)) { config->callback = args[ARG_callback].u_obj; } else { mp_raise_ValueError("callback must be a function"); diff --git a/ports/nrf/modules/machine/spi.c b/ports/nrf/modules/machine/spi.c index 95331e2414..1c401b76d2 100644 --- a/ports/nrf/modules/machine/spi.c +++ b/ports/nrf/modules/machine/spi.c @@ -131,7 +131,7 @@ void spi_init0(void) { } STATIC int spi_find(mp_obj_t id) { - if (MP_OBJ_IS_STR(id)) { + if (mp_obj_is_str(id)) { // given a string id const char *port = mp_obj_str_get_str(id); if (0) { diff --git a/ports/nrf/modules/machine/timer.c b/ports/nrf/modules/machine/timer.c index 4b7c995397..00a3591185 100644 --- a/ports/nrf/modules/machine/timer.c +++ b/ports/nrf/modules/machine/timer.c @@ -126,7 +126,7 @@ STATIC mp_obj_t machine_timer_make_new(const mp_obj_type_t *type, size_t n_args, machine_timer_obj_t *self = (machine_timer_obj_t*)&machine_timer_obj[timer_id]; - if (MP_OBJ_IS_FUN(args[ARG_callback].u_obj)) { + if (mp_obj_is_fun(args[ARG_callback].u_obj)) { machine_timer_callbacks[timer_id] = args[ARG_callback].u_obj; } else if (args[ARG_callback].u_obj == mp_const_none) { machine_timer_callbacks[timer_id] = NULL; diff --git a/ports/nrf/modules/music/modmusic.c b/ports/nrf/modules/music/modmusic.c index 71f6d3658b..84a014c12d 100644 --- a/ports/nrf/modules/music/modmusic.c +++ b/ports/nrf/modules/music/modmusic.c @@ -320,7 +320,7 @@ STATIC mp_obj_t microbit_music_play(mp_uint_t n_args, const mp_obj_t *pos_args, // get either a single note or a list of notes mp_uint_t len; mp_obj_t *items; - if (MP_OBJ_IS_STR_OR_BYTES(args[0].u_obj)) { + if (mp_obj_is_str_or_bytes(args[0].u_obj)) { len = 1; items = &args[0].u_obj; } else { diff --git a/ports/nrf/modules/ubluepy/ubluepy_characteristic.c b/ports/nrf/modules/ubluepy/ubluepy_characteristic.c index e271132cb4..2ca7f2f427 100644 --- a/ports/nrf/modules/ubluepy/ubluepy_characteristic.c +++ b/ports/nrf/modules/ubluepy/ubluepy_characteristic.c @@ -59,7 +59,7 @@ STATIC mp_obj_t ubluepy_characteristic_make_new(const mp_obj_type_t *type, size_ return MP_OBJ_FROM_PTR(s); } - if (MP_OBJ_IS_TYPE(uuid_obj, &ubluepy_uuid_type)) { + if (mp_obj_is_type(uuid_obj, &ubluepy_uuid_type)) { s->p_uuid = MP_OBJ_TO_PTR(uuid_obj); // (void)sd_characterstic_add(s); } else { diff --git a/ports/nrf/modules/ubluepy/ubluepy_peripheral.c b/ports/nrf/modules/ubluepy/ubluepy_peripheral.c index 48e4673748..3a45e56a07 100644 --- a/ports/nrf/modules/ubluepy/ubluepy_peripheral.c +++ b/ports/nrf/modules/ubluepy/ubluepy_peripheral.c @@ -193,7 +193,7 @@ STATIC mp_obj_t peripheral_advertise(mp_uint_t n_args, const mp_obj_t *pos_args, ubluepy_advertise_data_t adv_data; memset(&adv_data, 0, sizeof(ubluepy_advertise_data_t)); - if (device_name_obj != mp_const_none && MP_OBJ_IS_STR(device_name_obj)) { + if (device_name_obj != mp_const_none && mp_obj_is_str(device_name_obj)) { GET_STR_DATA_LEN(device_name_obj, str_data, str_len); adv_data.p_device_name = (uint8_t *)str_data; @@ -361,7 +361,7 @@ STATIC mp_obj_t peripheral_connect(mp_uint_t n_args, const mp_obj_t *pos_args, m ble_drv_gap_event_handler_set(MP_OBJ_FROM_PTR(self), gap_event_handler); - if (MP_OBJ_IS_STR(dev_addr)) { + if (mp_obj_is_str(dev_addr)) { GET_STR_DATA_LEN(dev_addr, str_data, str_len); if (str_len == 17) { // Example "11:22:33:aa:bb:cc" diff --git a/ports/nrf/modules/ubluepy/ubluepy_service.c b/ports/nrf/modules/ubluepy/ubluepy_service.c index e83ed1f223..e5bf42a09f 100644 --- a/ports/nrf/modules/ubluepy/ubluepy_service.c +++ b/ports/nrf/modules/ubluepy/ubluepy_service.c @@ -61,7 +61,7 @@ STATIC mp_obj_t ubluepy_service_make_new(const mp_obj_type_t *type, size_t n_arg return MP_OBJ_FROM_PTR(s); } - if (MP_OBJ_IS_TYPE(uuid_obj, &ubluepy_uuid_type)) { + if (mp_obj_is_type(uuid_obj, &ubluepy_uuid_type)) { s->p_uuid = MP_OBJ_TO_PTR(uuid_obj); uint8_t type = args[ARG_NEW_TYPE].u_int; @@ -124,7 +124,7 @@ STATIC mp_obj_t service_get_characteristic(mp_obj_t self_in, mp_obj_t uuid) { ubluepy_uuid_obj_t * p_uuid = MP_OBJ_TO_PTR(uuid); // validate that there is an UUID object passed in as parameter - if (!(MP_OBJ_IS_TYPE(uuid, &ubluepy_uuid_type))) { + if (!(mp_obj_is_type(uuid, &ubluepy_uuid_type))) { mp_raise_ValueError("Invalid UUID parameter"); } diff --git a/ports/nrf/modules/ubluepy/ubluepy_uuid.c b/ports/nrf/modules/ubluepy/ubluepy_uuid.c index 98dba912a7..cbcb100968 100644 --- a/ports/nrf/modules/ubluepy/ubluepy_uuid.c +++ b/ports/nrf/modules/ubluepy/ubluepy_uuid.c @@ -66,11 +66,11 @@ STATIC mp_obj_t ubluepy_uuid_make_new(const mp_obj_type_t *type, size_t n_args, return MP_OBJ_FROM_PTR(s); } - if (MP_OBJ_IS_INT(uuid_obj)) { + if (mp_obj_is_int(uuid_obj)) { s->type = UBLUEPY_UUID_16_BIT; s->value[1] = (((uint16_t)mp_obj_get_int(uuid_obj)) >> 8) & 0xFF; s->value[0] = ((uint8_t)mp_obj_get_int(uuid_obj)) & 0xFF; - } else if (MP_OBJ_IS_STR(uuid_obj)) { + } else if (mp_obj_is_str(uuid_obj)) { GET_STR_DATA_LEN(uuid_obj, str_data, str_len); if (str_len == 6) { // Assume hex digit prefixed with 0x s->type = UBLUEPY_UUID_16_BIT; @@ -124,7 +124,7 @@ STATIC mp_obj_t ubluepy_uuid_make_new(const mp_obj_type_t *type, size_t n_args, } else { mp_raise_ValueError("Invalid UUID string length"); } - } else if (MP_OBJ_IS_TYPE(uuid_obj, &ubluepy_uuid_type)) { + } else if (mp_obj_is_type(uuid_obj, &ubluepy_uuid_type)) { // deep copy instance ubluepy_uuid_obj_t * p_old = MP_OBJ_TO_PTR(uuid_obj); s->type = p_old->type; diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index 376b48d4ed..73588e4a3f 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -395,7 +395,7 @@ STATIC mp_obj_t adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ uint32_t channel; - if (MP_OBJ_IS_INT(pin_obj)) { + if (mp_obj_is_int(pin_obj)) { channel = adc_get_internal_channel(mp_obj_get_int(pin_obj)); } else { const pin_obj_t *pin = pin_find(pin_obj); diff --git a/ports/stm32/bufhelper.c b/ports/stm32/bufhelper.c index 79511969b7..5e9555f534 100644 --- a/ports/stm32/bufhelper.c +++ b/ports/stm32/bufhelper.c @@ -28,7 +28,7 @@ #include "bufhelper.h" void pyb_buf_get_for_send(mp_obj_t o, mp_buffer_info_t *bufinfo, byte *tmp_data) { - if (MP_OBJ_IS_INT(o)) { + if (mp_obj_is_int(o)) { tmp_data[0] = mp_obj_get_int(o); bufinfo->buf = tmp_data; bufinfo->len = 1; @@ -39,7 +39,7 @@ 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) { - if (MP_OBJ_IS_INT(o)) { + if (mp_obj_is_int(o)) { // allocate a new bytearray of given length vstr_init_len(vstr, mp_obj_get_int(o)); return MP_OBJ_NULL; diff --git a/ports/stm32/can.c b/ports/stm32/can.c index b92389aaf0..2293f94db8 100644 --- a/ports/stm32/can.c +++ b/ports/stm32/can.c @@ -409,7 +409,7 @@ STATIC mp_obj_t pyb_can_make_new(const mp_obj_type_t *type, size_t n_args, size_ // work out port mp_uint_t can_idx; - if (MP_OBJ_IS_STR(args[0])) { + if (mp_obj_is_str(args[0])) { const char *port = mp_obj_str_get_str(args[0]); if (0) { #ifdef MICROPY_HW_CAN1_NAME @@ -540,7 +540,7 @@ STATIC mp_obj_t pyb_can_info(size_t n_args, const mp_obj_t *args) { 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)) { + if (!mp_obj_is_type(args[1], &mp_type_list)) { mp_raise_TypeError(NULL); } list = MP_OBJ_TO_PTR(args[1]); @@ -709,7 +709,7 @@ STATIC mp_obj_t pyb_can_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t * items[3] = mp_obj_new_bytes(&rx_msg.Data[0], rx_msg.DLC); } else { // User should provide a list of length at least 4 to hold the values - if (!MP_OBJ_IS_TYPE(ret_obj, &mp_type_list)) { + 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); @@ -719,7 +719,7 @@ STATIC mp_obj_t pyb_can_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t * 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)) { + 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]); diff --git a/ports/stm32/dac.c b/ports/stm32/dac.c index 808e4d1bd1..3a92258ffb 100644 --- a/ports/stm32/dac.c +++ b/ports/stm32/dac.c @@ -238,7 +238,7 @@ STATIC mp_obj_t pyb_dac_make_new(const mp_obj_type_t *type, size_t n_args, size_ // get pin/channel to output on mp_int_t dac_id; - if (MP_OBJ_IS_INT(args[0])) { + if (mp_obj_is_int(args[0])) { dac_id = mp_obj_get_int(args[0]); } else { const pin_obj_t *pin = pin_find(args[0]); diff --git a/ports/stm32/extint.c b/ports/stm32/extint.c index b6e980101a..fedb60d139 100644 --- a/ports/stm32/extint.c +++ b/ports/stm32/extint.c @@ -163,7 +163,7 @@ uint extint_register(mp_obj_t pin_obj, uint32_t mode, uint32_t pull, mp_obj_t ca const pin_obj_t *pin = NULL; uint v_line; - if (MP_OBJ_IS_INT(pin_obj)) { + if (mp_obj_is_int(pin_obj)) { // If an integer is passed in, then use it to identify lines 16 thru 22 // We expect lines 0 thru 15 to be passed in as a pin, so that we can // get both the port number and line number. @@ -234,7 +234,7 @@ void extint_register_pin(const pin_obj_t *pin, uint32_t mode, bool hard_irq, mp_ // Check if the ExtInt line is already in use by another Pin/ExtInt mp_obj_t *cb = &MP_STATE_PORT(pyb_extint_callback)[line]; if (*cb != mp_const_none && MP_OBJ_FROM_PTR(pin) != pyb_extint_callback_arg[line]) { - if (MP_OBJ_IS_SMALL_INT(pyb_extint_callback_arg[line])) { + if (mp_obj_is_small_int(pyb_extint_callback_arg[line])) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "ExtInt vector %d is already in use", line)); } else { diff --git a/ports/stm32/machine_i2c.c b/ports/stm32/machine_i2c.c index b7a9ea69bf..940e98d715 100644 --- a/ports/stm32/machine_i2c.c +++ b/ports/stm32/machine_i2c.c @@ -197,7 +197,7 @@ mp_obj_t machine_hard_i2c_make_new(const mp_obj_type_t *type, size_t n_args, siz // work out i2c bus int i2c_id = 0; - if (MP_OBJ_IS_STR(args[ARG_id].u_obj)) { + if (mp_obj_is_str(args[ARG_id].u_obj)) { const char *port = mp_obj_str_get_str(args[ARG_id].u_obj); if (0) { #ifdef MICROPY_HW_I2C1_NAME diff --git a/ports/stm32/machine_uart.c b/ports/stm32/machine_uart.c index c453960467..c1e5948071 100644 --- a/ports/stm32/machine_uart.c +++ b/ports/stm32/machine_uart.c @@ -350,7 +350,7 @@ STATIC mp_obj_t pyb_uart_make_new(const mp_obj_type_t *type, size_t n_args, size // work out port int uart_id = 0; - if (MP_OBJ_IS_STR(args[0])) { + if (mp_obj_is_str(args[0])) { const char *port = mp_obj_str_get_str(args[0]); if (0) { #ifdef MICROPY_HW_UART1_NAME diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 1a00ef3a18..3028f907b6 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -132,7 +132,7 @@ STATIC mp_obj_t pyb_main(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_a { MP_QSTR_opt, MP_ARG_INT, {.u_int = 0} } }; - if (MP_OBJ_IS_STR(pos_args[0])) { + if (mp_obj_is_str(pos_args[0])) { MP_STATE_PORT(pyb_config_main) = pos_args[0]; // parse args diff --git a/ports/stm32/pin.c b/ports/stm32/pin.c index 58c01e22cf..a8068d8998 100644 --- a/ports/stm32/pin.c +++ b/ports/stm32/pin.c @@ -105,7 +105,7 @@ const pin_obj_t *pin_find(mp_obj_t user_obj) { const pin_obj_t *pin_obj; // If a pin was provided, then use it - if (MP_OBJ_IS_TYPE(user_obj, &pin_type)) { + if (mp_obj_is_type(user_obj, &pin_type)) { pin_obj = MP_OBJ_TO_PTR(user_obj); if (pin_class_debug) { printf("Pin map passed pin "); @@ -118,7 +118,7 @@ const pin_obj_t *pin_find(mp_obj_t user_obj) { if (MP_STATE_PORT(pin_class_mapper) != mp_const_none) { mp_obj_t o = mp_call_function_1(MP_STATE_PORT(pin_class_mapper), user_obj); if (o != mp_const_none) { - if (!MP_OBJ_IS_TYPE(o, &pin_type)) { + if (!mp_obj_is_type(o, &pin_type)) { mp_raise_ValueError("Pin.mapper didn't return a Pin object"); } if (pin_class_debug) { diff --git a/ports/stm32/pyb_i2c.c b/ports/stm32/pyb_i2c.c index d6b9ec6cc1..233cbba512 100644 --- a/ports/stm32/pyb_i2c.c +++ b/ports/stm32/pyb_i2c.c @@ -636,7 +636,7 @@ STATIC mp_obj_t pyb_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_ // work out i2c bus int i2c_id = 0; - if (MP_OBJ_IS_STR(args[0])) { + if (mp_obj_is_str(args[0])) { const char *port = mp_obj_str_get_str(args[0]); if (0) { #ifdef MICROPY_HW_I2C1_NAME diff --git a/ports/stm32/spi.c b/ports/stm32/spi.c index ae97d9ab40..b7298b4aaa 100644 --- a/ports/stm32/spi.c +++ b/ports/stm32/spi.c @@ -121,7 +121,7 @@ void spi_init0(void) { } int spi_find_index(mp_obj_t id) { - if (MP_OBJ_IS_STR(id)) { + if (mp_obj_is_str(id)) { // given a string id const char *port = mp_obj_str_get_str(id); if (0) { @@ -583,10 +583,10 @@ void spi_print(const mp_print_t *print, const spi_t *spi_obj, bool legacy) { } const spi_t *spi_from_mp_obj(mp_obj_t o) { - if (MP_OBJ_IS_TYPE(o, &pyb_spi_type)) { + if (mp_obj_is_type(o, &pyb_spi_type)) { pyb_spi_obj_t *self = MP_OBJ_TO_PTR(o); return self->spi; - } else if (MP_OBJ_IS_TYPE(o, &machine_hard_spi_type)) { + } else if (mp_obj_is_type(o, &machine_hard_spi_type)) { machine_hard_spi_obj_t *self = MP_OBJ_TO_PTR(o); return self->spi; } else { diff --git a/ports/stm32/timer.c b/ports/stm32/timer.c index 983f7cbc6f..28dc749b4e 100644 --- a/ports/stm32/timer.c +++ b/ports/stm32/timer.c @@ -275,7 +275,7 @@ STATIC uint32_t compute_prescaler_period_from_freq(pyb_timer_obj_t *self, mp_obj uint32_t period; if (0) { #if MICROPY_PY_BUILTINS_FLOAT - } else if (MP_OBJ_IS_TYPE(freq_in, &mp_type_float)) { + } else if (mp_obj_is_type(freq_in, &mp_type_float)) { float freq = mp_obj_get_float(freq_in); if (freq <= 0) { goto bad_freq; @@ -370,7 +370,7 @@ STATIC uint32_t compute_pwm_value_from_percent(uint32_t period, mp_obj_t percent uint32_t cmp; if (0) { #if MICROPY_PY_BUILTINS_FLOAT - } else if (MP_OBJ_IS_TYPE(percent_in, &mp_type_float)) { + } else if (mp_obj_is_type(percent_in, &mp_type_float)) { mp_float_t percent = mp_obj_get_float(percent_in); if (percent <= 0.0) { cmp = 0; @@ -988,7 +988,7 @@ STATIC mp_obj_t pyb_timer_channel(size_t n_args, const mp_obj_t *pos_args, mp_ma mp_obj_t pin_obj = args[2].u_obj; if (pin_obj != mp_const_none) { - if (!MP_OBJ_IS_TYPE(pin_obj, &pin_type)) { + if (!mp_obj_is_type(pin_obj, &pin_type)) { mp_raise_ValueError("pin argument needs to be be a Pin type"); } const pin_obj_t *pin = MP_OBJ_TO_PTR(pin_obj); diff --git a/ports/teensy/main.c b/ports/teensy/main.c index 3edaa28a06..3ae049883f 100644 --- a/ports/teensy/main.c +++ b/ports/teensy/main.c @@ -194,7 +194,7 @@ STATIC mp_obj_t pyb_config_main = MP_OBJ_NULL; STATIC mp_obj_t pyb_config_usb_mode = MP_OBJ_NULL; mp_obj_t pyb_source_dir(mp_obj_t source_dir) { - if (MP_OBJ_IS_STR(source_dir)) { + if (mp_obj_is_str(source_dir)) { pyb_config_source_dir = source_dir; } return mp_const_none; @@ -203,7 +203,7 @@ mp_obj_t pyb_source_dir(mp_obj_t source_dir) { MP_DEFINE_CONST_FUN_OBJ_1(pyb_source_dir_obj, pyb_source_dir); mp_obj_t pyb_main(mp_obj_t main) { - if (MP_OBJ_IS_STR(main)) { + if (mp_obj_is_str(main)) { pyb_config_main = main; } return mp_const_none; @@ -212,7 +212,7 @@ mp_obj_t pyb_main(mp_obj_t main) { MP_DEFINE_CONST_FUN_OBJ_1(pyb_main_obj, pyb_main); STATIC mp_obj_t pyb_usb_mode(mp_obj_t usb_mode) { - if (MP_OBJ_IS_STR(usb_mode)) { + if (mp_obj_is_str(usb_mode)) { pyb_config_usb_mode = usb_mode; } return mp_const_none; diff --git a/ports/teensy/reg.c b/ports/teensy/reg.c index cbc427d876..4f1fd52c29 100644 --- a/ports/teensy/reg.c +++ b/ports/teensy/reg.c @@ -18,7 +18,7 @@ mp_obj_t reg_cmd(void *base, reg_t *reg, mp_uint_t num_regs, uint n_args, const mp_uint_t addr = 0; - if (MP_OBJ_IS_STR(args[0])) { + if (mp_obj_is_str(args[0])) { const char *name = mp_obj_str_get_str(args[0]); mp_uint_t reg_idx; for (reg_idx = 0; reg_idx < num_regs; reg_idx++, reg++) { diff --git a/ports/teensy/timer.c b/ports/teensy/timer.c index b823e6c3b9..c958f5349f 100644 --- a/ports/teensy/timer.c +++ b/ports/teensy/timer.c @@ -142,7 +142,7 @@ STATIC uint32_t compute_pwm_value_from_percent(uint32_t period, mp_obj_t percent uint32_t cmp; if (0) { #if MICROPY_PY_BUILTINS_FLOAT - } else if (MP_OBJ_IS_TYPE(percent_in, &mp_type_float)) { + } else if (mp_obj_is_type(percent_in, &mp_type_float)) { float percent = mp_obj_get_float(percent_in); if (percent <= 0.0) { cmp = 0; @@ -496,7 +496,7 @@ STATIC mp_obj_t pyb_timer_channel(size_t n_args, const mp_obj_t *args, mp_map_t mp_obj_t pin_obj = vals[1].u_obj; if (pin_obj != mp_const_none) { - if (!MP_OBJ_IS_TYPE(pin_obj, &pin_type)) { + if (!mp_obj_is_type(pin_obj, &pin_type)) { mp_raise_ValueError("pin argument needs to be be a Pin type"); } const pin_obj_t *pin = pin_obj; diff --git a/ports/teensy/uart.c b/ports/teensy/uart.c index a8cfd63eac..ee0eae39ae 100644 --- a/ports/teensy/uart.c +++ b/ports/teensy/uart.c @@ -316,7 +316,7 @@ STATIC mp_obj_t pyb_uart_make_new(const mp_obj_type_t *type, uint n_args, uint n // work out port o->uart_id = 0; #if 0 - if (MP_OBJ_IS_STR(args[0])) { + if (mp_obj_is_str(args[0])) { const char *port = mp_obj_str_get_str(args[0]); if (0) { #if defined(PYBV10) diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index 7820f6d736..3c121a1538 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -250,7 +250,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)))); + mp_printf(&mp_plat_print, "%d\n", mp_obj_is_qstr(mp_obj_str_intern(mp_obj_new_str("intern me", 9)))); } // bytearray diff --git a/ports/unix/file.c b/ports/unix/file.c index a54d1d03df..bb841da209 100644 --- a/ports/unix/file.c +++ b/ports/unix/file.c @@ -192,7 +192,7 @@ STATIC mp_obj_t fdfile_open(const mp_obj_type_t *type, mp_arg_val_t *args) { mp_obj_t fid = args[0].u_obj; - if (MP_OBJ_IS_SMALL_INT(fid)) { + if (mp_obj_is_small_int(fid)) { o->fd = MP_OBJ_SMALL_INT_VALUE(fid); return MP_OBJ_FROM_PTR(o); } diff --git a/ports/unix/modffi.c b/ports/unix/modffi.c index c262721ebb..4dea887688 100644 --- a/ports/unix/modffi.c +++ b/ports/unix/modffi.c @@ -126,7 +126,7 @@ STATIC ffi_type *char2ffi_type(char c) STATIC ffi_type *get_ffi_type(mp_obj_t o_in) { - if (MP_OBJ_IS_STR(o_in)) { + if (mp_obj_is_str(o_in)) { const char *s = mp_obj_str_get_str(o_in); ffi_type *t = char2ffi_type(*s); if (t != NULL) { @@ -370,9 +370,9 @@ STATIC mp_obj_t ffifunc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const #endif } else if (a == mp_const_none) { values[i] = 0; - } else if (MP_OBJ_IS_INT(a)) { + } else if (mp_obj_is_int(a)) { values[i] = mp_obj_int_get_truncated(a); - } else if (MP_OBJ_IS_STR(a)) { + } else if (mp_obj_is_str(a)) { const char *s = mp_obj_str_get_str(a); values[i] = (ffi_arg)(intptr_t)s; } else if (((mp_obj_base_t*)MP_OBJ_TO_PTR(a))->type->buffer_p.get_buffer != NULL) { @@ -383,7 +383,7 @@ STATIC mp_obj_t ffifunc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const goto error; } values[i] = (ffi_arg)(intptr_t)bufinfo.buf; - } else if (MP_OBJ_IS_TYPE(a, &fficallback_type)) { + } else if (mp_obj_is_type(a, &fficallback_type)) { mp_obj_fficallback_t *p = MP_OBJ_TO_PTR(a); values[i] = (ffi_arg)(intptr_t)p->func; } else { diff --git a/ports/unix/modjni.c b/ports/unix/modjni.c index 9e8c232094..902c34f10b 100644 --- a/ports/unix/modjni.c +++ b/ports/unix/modjni.c @@ -658,12 +658,12 @@ STATIC mp_obj_t mod_jni_array(mp_obj_t type_in, mp_obj_t size_in) { mp_int_t size = mp_obj_get_int(size_in); jobject res = NULL; - if (MP_OBJ_IS_TYPE(type_in, &jclass_type)) { + if (mp_obj_is_type(type_in, &jclass_type)) { mp_obj_jclass_t *jcls = MP_OBJ_TO_PTR(type_in); res = JJ(NewObjectArray, size, jcls->cls, NULL); - } else if (MP_OBJ_IS_STR(type_in)) { + } else if (mp_obj_is_str(type_in)) { const char *type = mp_obj_str_get_str(type_in); switch (*type) { case 'Z': diff --git a/ports/unix/modtermios.c b/ports/unix/modtermios.c index fe19aac83c..7e46ba2f52 100644 --- a/ports/unix/modtermios.c +++ b/ports/unix/modtermios.c @@ -77,7 +77,7 @@ STATIC mp_obj_t mod_termios_tcsetattr(mp_obj_t fd_in, mp_obj_t when_in, mp_obj_t when = TCSANOW; } - assert(MP_OBJ_IS_TYPE(attrs_in, &mp_type_list)); + assert(mp_obj_is_type(attrs_in, &mp_type_list)); mp_obj_list_t *attrs = MP_OBJ_TO_PTR(attrs_in); term.c_iflag = mp_obj_get_int(attrs->items[0]); diff --git a/ports/unix/moduselect.c b/ports/unix/moduselect.c index a95663e31f..d9b02ddc62 100644 --- a/ports/unix/moduselect.c +++ b/ports/unix/moduselect.c @@ -66,7 +66,7 @@ typedef struct _mp_obj_poll_t { } mp_obj_poll_t; STATIC int get_fd(mp_obj_t fdlike) { - if (MP_OBJ_IS_OBJ(fdlike)) { + if (mp_obj_is_obj(fdlike)) { const mp_stream_p_t *stream_p = mp_get_stream_raise(fdlike, MP_STREAM_OP_IOCTL); int err; mp_uint_t res = stream_p->ioctl(fdlike, MP_STREAM_GET_FILENO, 0, &err); @@ -80,7 +80,7 @@ STATIC int get_fd(mp_obj_t fdlike) { /// \method register(obj[, eventmask]) STATIC mp_obj_t poll_register(size_t n_args, const mp_obj_t *args) { mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]); - bool is_fd = MP_OBJ_IS_INT(args[1]); + bool is_fd = mp_obj_is_int(args[1]); int fd = get_fd(args[1]); mp_uint_t flags; diff --git a/ports/unix/modusocket.c b/ports/unix/modusocket.c index 61402e001d..fd4092a622 100644 --- a/ports/unix/modusocket.c +++ b/ports/unix/modusocket.c @@ -299,7 +299,7 @@ STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) { const void *optval; socklen_t optlen; int val; - if (MP_OBJ_IS_INT(args[3])) { + if (mp_obj_is_int(args[3])) { val = mp_obj_int_get_truncated(args[3]); optval = &val; optlen = sizeof(val); @@ -391,13 +391,13 @@ STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type_in, size_t n_args, siz int proto = 0; if (n_args > 0) { - assert(MP_OBJ_IS_SMALL_INT(args[0])); + assert(mp_obj_is_small_int(args[0])); family = MP_OBJ_SMALL_INT_VALUE(args[0]); if (n_args > 1) { - assert(MP_OBJ_IS_SMALL_INT(args[1])); + assert(mp_obj_is_small_int(args[1])); type = MP_OBJ_SMALL_INT_VALUE(args[1]); if (n_args > 2) { - assert(MP_OBJ_IS_SMALL_INT(args[2])); + assert(mp_obj_is_small_int(args[2])); proto = MP_OBJ_SMALL_INT_VALUE(args[2]); } } @@ -494,7 +494,7 @@ STATIC mp_obj_t mod_socket_getaddrinfo(size_t n_args, const mp_obj_t *args) { memset(&hints, 0, sizeof(hints)); // getaddrinfo accepts port in string notation, so however // it may seem stupid, we need to convert int to str - if (MP_OBJ_IS_SMALL_INT(args[1])) { + if (mp_obj_is_small_int(args[1])) { unsigned port = (unsigned short)MP_OBJ_SMALL_INT_VALUE(args[1]); snprintf(buf, sizeof(buf), "%u", port); serv = buf; diff --git a/ports/zephyr/machine_pin.c b/ports/zephyr/machine_pin.c index 4dcd956cf8..c4ea328a2a 100644 --- a/ports/zephyr/machine_pin.c +++ b/ports/zephyr/machine_pin.c @@ -84,7 +84,7 @@ mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); // get the wanted port - if (!MP_OBJ_IS_TYPE(args[0], &mp_type_tuple)) { + if (!mp_obj_is_type(args[0], &mp_type_tuple)) { mp_raise_ValueError("Pin id must be tuple of (\"GPIO_x\", pin#)"); } mp_obj_t *items; From 5368210e36f1d05efb0ea2c09661ebc80688880b Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 31 Jan 2019 18:22:12 +1100 Subject: [PATCH 0088/1788] py/mkenv.mk: Change default PYTHON variable from "python" to "python3". This change makes it so that python3 is required by default to build MicroPython. Python 2 can be used by specifying make PYTHON=python2. This comes about due to a recent-ish change to PEP 394 that makes the python command more optional than before (even with Python 2 installed); see https://github.com/python/peps/commit/cd59ec03c8ff1e75089d5872520cd0706774b35b#diff-1d22f7bd72cbc900670f058b1107d426 Since the command python is no longer required to be provided by a distribution we need to use either python2 or python3 as commands. And python3 seems the obvious choice. --- README.md | 4 +++- py/mkenv.mk | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5a62472c38..843511a60b 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,9 @@ Additional components: The subdirectories above may include READMEs with additional info. "make" is used to build the components, or "gmake" on BSD-based systems. -You will also need bash, gcc, and Python (at least 2.7 or 3.3). +You will also need bash, gcc, and Python 3.3+ available as the command `python3` +(if your system only has Python 2.7 then invoke make with the additional option +`PYTHON=python2`). The Unix version ---------------- diff --git a/py/mkenv.mk b/py/mkenv.mk index 2c9c86a7ae..87e92ec6f9 100644 --- a/py/mkenv.mk +++ b/py/mkenv.mk @@ -42,7 +42,7 @@ ECHO = @echo CP = cp MKDIR = mkdir SED = sed -PYTHON = python +PYTHON = python3 AS = $(CROSS_COMPILE)as CC = $(CROSS_COMPILE)gcc From d976e4f5e805ae7678dac9553846b738f80ba79e Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 12 Feb 2019 15:12:24 +1100 Subject: [PATCH 0089/1788] teensy/Makefile: Use common gchelper_m3.s code from lib/utils. --- ports/teensy/Makefile | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ports/teensy/Makefile b/ports/teensy/Makefile index 08ecf0f913..663a86fabd 100644 --- a/ports/teensy/Makefile +++ b/ports/teensy/Makefile @@ -98,10 +98,6 @@ STM_SRC_C = $(addprefix ports/stm32/,\ pin_named_pins.c \ ) -STM_SRC_S = $(addprefix ports/stm32/,\ - gchelper.s \ - ) - LIB_SRC_C = $(addprefix lib/,\ libc/string0.c \ mp-readline/readline.c \ @@ -120,8 +116,9 @@ SRC_TEENSY = $(addprefix core/,\ yield.c \ ) -OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(STM_SRC_C:.c=.o) $(STM_SRC_S:.s=.o) $(SRC_TEENSY:.c=.o)) +OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(STM_SRC_C:.c=.o) $(SRC_TEENSY:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) +OBJ += $(BUILD)/lib/utils/gchelper_m3.o OBJ += $(BUILD)/pins_gen.o all: hex From 812969d615e130bef7e525553dbb7b01c27191ea Mon Sep 17 00:00:00 2001 From: Mike Causer Date: Sun, 3 Dec 2017 22:42:50 +1100 Subject: [PATCH 0090/1788] all: Change PYB message prefix to MPY. Replaces "PYB: soft reboot" with "MPY: soft reboot", etc. Having a consistent prefix across ports reduces the difference between ports, which is a general goal. And this change won't break pyboard.py because that tool only looks for "soft reboot". --- docs/pyboard/tutorial/repl.rst | 4 ++-- docs/reference/repl.rst | 4 ++-- docs/wipy/tutorial/repl.rst | 2 +- lib/utils/pyexec.c | 2 +- ports/cc3200/mptask.c | 2 +- ports/esp32/main.c | 2 +- ports/esp8266/main.c | 2 +- ports/pic16bit/main.c | 2 +- ports/stm32/main.c | 10 +++++----- ports/teensy/main.c | 2 +- 10 files changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/pyboard/tutorial/repl.rst b/docs/pyboard/tutorial/repl.rst index 646ecbc237..3853b15785 100644 --- a/docs/pyboard/tutorial/repl.rst +++ b/docs/pyboard/tutorial/repl.rst @@ -96,8 +96,8 @@ If something goes wrong, you can reset the board in two ways. The first is to pr at the MicroPython prompt, which performs a soft reset. You will see a message something like :: >>> - PYB: sync filesystems - PYB: soft reboot + MPY: sync filesystems + MPY: soft reboot Micro Python v1.0 on 2014-05-03; PYBv1.0 with STM32F405RG Type "help()" for more information. >>> diff --git a/docs/reference/repl.rst b/docs/reference/repl.rst index 1eccb9a88a..0c6f04b7c5 100644 --- a/docs/reference/repl.rst +++ b/docs/reference/repl.rst @@ -174,8 +174,8 @@ variables no longer exist: .. code-block:: python - PYB: sync filesystems - PYB: soft reboot + MPY: sync filesystems + MPY: soft reboot MicroPython v1.5-51-g6f70283-dirty on 2015-10-30; PYBv1.0 with STM32F405RG Type "help()" for more information. >>> dir() diff --git a/docs/wipy/tutorial/repl.rst b/docs/wipy/tutorial/repl.rst index e25e0472c5..8c60e2c1d1 100644 --- a/docs/wipy/tutorial/repl.rst +++ b/docs/wipy/tutorial/repl.rst @@ -120,7 +120,7 @@ If something goes wrong, you can reset the board in two ways. The first is to pr at the MicroPython prompt, which performs a soft reset. You will see a message something like:: >>> - PYB: soft reboot + MPY: soft reboot MicroPython v1.4.6-146-g1d8b5e5 on 2015-10-21; WiPy with CC3200 Type "help()" for more information. >>> diff --git a/lib/utils/pyexec.c b/lib/utils/pyexec.c index b7174c9a13..f4e6856e50 100644 --- a/lib/utils/pyexec.c +++ b/lib/utils/pyexec.c @@ -450,7 +450,7 @@ friendly_repl_reset: // do the user a favor and reenable interrupts. if (query_irq() == IRQ_STATE_DISABLED) { enable_irq(IRQ_STATE_ENABLED); - mp_hal_stdout_tx_str("PYB: enabling IRQs\r\n"); + mp_hal_stdout_tx_str("MPY: enabling IRQs\r\n"); } } #endif diff --git a/ports/cc3200/mptask.c b/ports/cc3200/mptask.c index 9b6169342c..9390978474 100644 --- a/ports/cc3200/mptask.c +++ b/ports/cc3200/mptask.c @@ -234,7 +234,7 @@ soft_reset_exit: // soft reset pyb_sleep_signal_soft_reset(); - mp_printf(&mp_plat_print, "PYB: soft reboot\n"); + mp_printf(&mp_plat_print, "MPY: soft reboot\n"); // disable all callbacks to avoid undefined behaviour // when coming out of a soft reset diff --git a/ports/esp32/main.c b/ports/esp32/main.c index a304dcbccf..188fb5e70d 100644 --- a/ports/esp32/main.c +++ b/ports/esp32/main.c @@ -138,7 +138,7 @@ soft_reset: gc_sweep_all(); - mp_hal_stdout_tx_str("PYB: soft reboot\r\n"); + mp_hal_stdout_tx_str("MPY: soft reboot\r\n"); // deinitialise peripherals machine_pins_deinit(); diff --git a/ports/esp8266/main.c b/ports/esp8266/main.c index 923e4530fc..67157ce18c 100644 --- a/ports/esp8266/main.c +++ b/ports/esp8266/main.c @@ -86,7 +86,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_stdout_tx_str("MPY: soft reboot\r\n"); mp_hal_delay_us(10000); // allow UART to flush output mp_reset(); #if MICROPY_REPL_EVENT_DRIVEN diff --git a/ports/pic16bit/main.c b/ports/pic16bit/main.c index 47ba00f48f..c96ac54ea4 100644 --- a/ports/pic16bit/main.c +++ b/ports/pic16bit/main.c @@ -87,7 +87,7 @@ soft_reset: } } - printf("PYB: soft reboot\n"); + printf("MPY: soft reboot\n"); mp_deinit(); goto soft_reset; } diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 3028f907b6..8a65188ed1 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -203,7 +203,7 @@ MP_NOINLINE STATIC bool init_flash_fs(uint reset_mode) { if (res == FR_OK) { // success creating fresh LFS } else { - printf("PYB: can't create flash filesystem\n"); + printf("MPY: can't create flash filesystem\n"); return false; } @@ -235,7 +235,7 @@ MP_NOINLINE STATIC bool init_flash_fs(uint reset_mode) { // mount sucessful } else { fail: - printf("PYB: can't mount flash\n"); + printf("MPY: can't mount flash\n"); return false; } @@ -349,7 +349,7 @@ STATIC bool init_sdcard_fs(void) { } if (first_part) { - printf("PYB: can't mount SD card\n"); + printf("MPY: can't mount SD card\n"); return false; } else { return true; @@ -763,11 +763,11 @@ soft_reset_exit: // soft reset #if MICROPY_HW_ENABLE_STORAGE - printf("PYB: sync filesystems\n"); + printf("MPY: sync filesystems\n"); storage_flush(); #endif - printf("PYB: soft reboot\n"); + printf("MPY: soft reboot\n"); #if MICROPY_PY_NETWORK mod_network_deinit(); #endif diff --git a/ports/teensy/main.c b/ports/teensy/main.c index 3ae049883f..ad98a43644 100644 --- a/ports/teensy/main.c +++ b/ports/teensy/main.c @@ -343,7 +343,7 @@ soft_reset: } } - printf("PYB: soft reboot\n"); + printf("MPY: soft reboot\n"); // first_soft_reset = false; goto soft_reset; From 66f0afc91d22bb414d8247b795ce37743bd3f39d Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Sun, 10 Feb 2019 00:36:08 +0200 Subject: [PATCH 0091/1788] unix/modmachine: Handle repeated /dev/mem open errors. If opening of /dev/mem has failed an `OSError` is appropriately raised, but the next time `mem8/16/32` is accessed the invalid file descriptor is used and the program gets a SIGSEGV. --- ports/unix/modmachine.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ports/unix/modmachine.c b/ports/unix/modmachine.c index 48dddec0ae..e2c44f94c2 100644 --- a/ports/unix/modmachine.c +++ b/ports/unix/modmachine.c @@ -57,10 +57,11 @@ uintptr_t mod_machine_mem_get_addr(mp_obj_t addr_o, uint align) { static uintptr_t last_base = (uintptr_t)-1; static uintptr_t map_page; if (!fd) { - fd = open("/dev/mem", O_RDWR | O_SYNC); - if (fd == -1) { + int _fd = open("/dev/mem", O_RDWR | O_SYNC); + if (_fd == -1) { mp_raise_OSError(errno); } + fd = _fd; } uintptr_t cur_base = addr & ~MICROPY_PAGE_MASK; From 26a1ae295f883a7dc146a07c0f382cfac9568bf1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 14 Feb 2019 00:01:14 +1100 Subject: [PATCH 0092/1788] stm32/mboot/Makefile: Support specifying BOARD_DIR for custom board. --- ports/stm32/mboot/Makefile | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/ports/stm32/mboot/Makefile b/ports/stm32/mboot/Makefile index fa8b2a3d8e..87a530a3c8 100644 --- a/ports/stm32/mboot/Makefile +++ b/ports/stm32/mboot/Makefile @@ -1,15 +1,20 @@ # 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) +# Allow the directory containing the board configuration to be specified +BOARD_DIR ?= $(abspath ../boards/$(BOARD)) + +# Sanity check that the board configuration directory exists +ifeq ($(wildcard $(BOARD_DIR)/.),) +$(error Invalid BOARD specified: $(BOARD_DIR)) +endif + include ../../../py/mkenv.mk -include ../boards/$(BOARD)/mpconfigboard.mk +include $(BOARD_DIR)/mpconfigboard.mk CMSIS_DIR=$(TOP)/lib/stm32lib/CMSIS/STM32$(MCU_SERIES_UPPER)xx/Include MCU_SERIES_UPPER = $(shell echo $(MCU_SERIES) | tr '[:lower:]' '[:upper:]') @@ -45,7 +50,7 @@ CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 -nostdlib $(CFLAGS_MOD) CFLAGS += -D$(CMSIS_MCU) CFLAGS += $(CFLAGS_MCU_$(MCU_SERIES)) CFLAGS += $(COPT) -CFLAGS += -I../boards/$(BOARD) +CFLAGS += -I$(BOARD_DIR) CFLAGS += -DSTM32_HAL_H='' CFLAGS += -DBOARD_$(BOARD) CFLAGS += -DAPPLICATION_ADDR=$(TEXT0_ADDR) @@ -79,7 +84,7 @@ SRC_C = \ ports/stm32/flashbdev.c \ ports/stm32/spibdev.c \ ports/stm32/usbd_conf.c \ - $(patsubst $(TOP)/%,%,$(wildcard $(TOP)/ports/stm32/boards/$(BOARD)/*.c)) + $(wildcard $(BOARD_DIR)/*.c) SRC_O = \ ports/stm32/boards/startup_stm32$(MCU_SERIES).o \ From d1acca3c71780545e067e85b444b495cc9801b2b Mon Sep 17 00:00:00 2001 From: Jolatomme Date: Tue, 12 Feb 2019 23:52:35 +0100 Subject: [PATCH 0093/1788] stm32/boards/NUCLEO_L476RG: Add support for RNG, DAC and CAN1. PLLQ is changed to get CAN working, and I2C1 pins are changed to those prescribed by the board. --- .../stm32/boards/NUCLEO_L476RG/mpconfigboard.h | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h index 0d5dab3945..05298253ae 100644 --- a/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h @@ -3,15 +3,17 @@ #define MICROPY_HW_HAS_SWITCH (1) #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_HW_ENABLE_DAC (1) // MSI is used and is 4MHz #define MICROPY_HW_CLK_PLLM (1) #define MICROPY_HW_CLK_PLLN (40) -#define MICROPY_HW_CLK_PLLR (2) -#define MICROPY_HW_CLK_PLLP (7) -#define MICROPY_HW_CLK_PLLQ (4) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV7) +#define MICROPY_HW_CLK_PLLQ (RCC_PLLQ_DIV2) +#define MICROPY_HW_CLK_PLLR (RCC_PLLR_DIV2) // UART config #define MICROPY_HW_UART2_TX (pin_A2) @@ -23,8 +25,8 @@ #define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_4 // I2C busses -#define MICROPY_HW_I2C1_SCL (pin_B6) -#define MICROPY_HW_I2C1_SDA (pin_B7) +#define MICROPY_HW_I2C1_SCL (pin_B8) +#define MICROPY_HW_I2C1_SDA (pin_B9) #define MICROPY_HW_I2C2_SCL (pin_B10) #define MICROPY_HW_I2C2_SDA (pin_B11) #define MICROPY_HW_I2C3_SCL (pin_C0) @@ -40,6 +42,10 @@ #define MICROPY_HW_SPI2_MISO (pin_B14) #define MICROPY_HW_SPI2_MOSI (pin_B15) +// CAN bus +#define MICROPY_HW_CAN1_TX (pin_A12) +#define MICROPY_HW_CAN1_RX (pin_A11) + // 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) @@ -47,7 +53,7 @@ #define MICROPY_HW_USRSW_PRESSED (0) // LEDs -#define MICROPY_HW_LED1 (pin_A5) // Green LD2 LED on Nucleo +#define MICROPY_HW_LED1 (pin_A5) // Green 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)) From bc4f8b438b56cf1b4f6b44febcd0d83599cbbd68 Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Sun, 10 Feb 2019 22:35:18 +0200 Subject: [PATCH 0094/1788] extmod/moduwebsocket: Refactor `websocket` to `uwebsocket`. As mentioned in #4450, `websocket` was experimental with a single intended user, `webrepl`. Therefore, we'll make this change without a weak link `websocket` -> `uwebsocket`. --- extmod/{modwebsocket.c => moduwebsocket.c} | 16 ++++++++-------- extmod/moduwebsocket.h | 10 ++++++++++ extmod/modwebrepl.c | 2 +- extmod/modwebsocket.h | 10 ---------- ports/esp32/mpconfigport.h | 2 +- ports/esp8266/modules/webrepl.py | 4 ++-- ports/esp8266/mpconfigport.h | 2 +- ports/unix/mpconfigport.h | 2 +- py/builtin.h | 2 +- py/mpconfig.h | 4 ++-- py/objmodule.c | 4 ++-- py/py.mk | 2 +- tests/extmod/websocket_basic.py | 12 ++++++------ 13 files changed, 36 insertions(+), 36 deletions(-) rename extmod/{modwebsocket.c => moduwebsocket.c} (96%) create mode 100644 extmod/moduwebsocket.h delete mode 100644 extmod/modwebsocket.h diff --git a/extmod/modwebsocket.c b/extmod/moduwebsocket.c similarity index 96% rename from extmod/modwebsocket.c rename to extmod/moduwebsocket.c index c556f2b770..eb5e20c6e3 100644 --- a/extmod/modwebsocket.c +++ b/extmod/moduwebsocket.c @@ -30,9 +30,9 @@ #include "py/runtime.h" #include "py/stream.h" -#include "extmod/modwebsocket.h" +#include "extmod/moduwebsocket.h" -#if MICROPY_PY_WEBSOCKET +#if MICROPY_PY_UWEBSOCKET enum { FRAME_HEADER, FRAME_OPT, PAYLOAD, CONTROL }; @@ -299,16 +299,16 @@ STATIC const mp_obj_type_t websocket_type = { .locals_dict = (void*)&websocket_locals_dict, }; -STATIC const mp_rom_map_elem_t websocket_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_websocket) }, +STATIC const mp_rom_map_elem_t uwebsocket_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uwebsocket) }, { MP_ROM_QSTR(MP_QSTR_websocket), MP_ROM_PTR(&websocket_type) }, }; -STATIC MP_DEFINE_CONST_DICT(websocket_module_globals, websocket_module_globals_table); +STATIC MP_DEFINE_CONST_DICT(uwebsocket_module_globals, uwebsocket_module_globals_table); -const mp_obj_module_t mp_module_websocket = { +const mp_obj_module_t mp_module_uwebsocket = { .base = { &mp_type_module }, - .globals = (mp_obj_dict_t*)&websocket_module_globals, + .globals = (mp_obj_dict_t*)&uwebsocket_module_globals, }; -#endif // MICROPY_PY_WEBSOCKET +#endif // MICROPY_PY_UWEBSOCKET diff --git a/extmod/moduwebsocket.h b/extmod/moduwebsocket.h new file mode 100644 index 0000000000..c1ea291ed7 --- /dev/null +++ b/extmod/moduwebsocket.h @@ -0,0 +1,10 @@ +#ifndef MICROPY_INCLUDED_EXTMOD_MODUWEBSOCKET_H +#define MICROPY_INCLUDED_EXTMOD_MODUWEBSOCKET_H + +#define FRAME_OPCODE_MASK 0x0f +enum { + FRAME_CONT, FRAME_TXT, FRAME_BIN, + FRAME_CLOSE = 0x8, FRAME_PING, FRAME_PONG +}; + +#endif // MICROPY_INCLUDED_EXTMOD_MODUWEBSOCKET_H diff --git a/extmod/modwebrepl.c b/extmod/modwebrepl.c index 3c33ee1502..bf0c1654ba 100644 --- a/extmod/modwebrepl.c +++ b/extmod/modwebrepl.c @@ -34,7 +34,7 @@ #ifdef MICROPY_PY_WEBREPL_DELAY #include "py/mphal.h" #endif -#include "extmod/modwebsocket.h" +#include "extmod/moduwebsocket.h" #if MICROPY_PY_WEBREPL diff --git a/extmod/modwebsocket.h b/extmod/modwebsocket.h deleted file mode 100644 index 2720147dfd..0000000000 --- a/extmod/modwebsocket.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef MICROPY_INCLUDED_EXTMOD_MODWEBSOCKET_H -#define MICROPY_INCLUDED_EXTMOD_MODWEBSOCKET_H - -#define FRAME_OPCODE_MASK 0x0f -enum { - FRAME_CONT, FRAME_TXT, FRAME_BIN, - FRAME_CLOSE = 0x8, FRAME_PING, FRAME_PONG -}; - -#endif // MICROPY_INCLUDED_EXTMOD_MODWEBSOCKET_H diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index a70f6d3180..01b23de05f 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -146,7 +146,7 @@ #define MICROPY_PY_USSL (1) #define MICROPY_SSL_MBEDTLS (1) #define MICROPY_PY_USSL_FINALISER (1) -#define MICROPY_PY_WEBSOCKET (1) +#define MICROPY_PY_UWEBSOCKET (1) #define MICROPY_PY_WEBREPL (1) #define MICROPY_PY_FRAMEBUF (1) #define MICROPY_PY_USOCKET_EVENTS (MICROPY_PY_WEBREPL) diff --git a/ports/esp8266/modules/webrepl.py b/ports/esp8266/modules/webrepl.py index aa156d1487..bbf8bdb320 100644 --- a/ports/esp8266/modules/webrepl.py +++ b/ports/esp8266/modules/webrepl.py @@ -2,7 +2,7 @@ import socket import uos import network -import websocket +import uwebsocket import websocket_helper import _webrepl @@ -40,7 +40,7 @@ def accept_conn(listen_sock): print("\nWebREPL connection from:", remote_addr) client_s = cl websocket_helper.server_handshake(cl) - ws = websocket.websocket(cl, True) + ws = uwebsocket.websocket(cl, True) ws = _webrepl._webrepl(ws) cl.setblocking(False) # notify REPL on socket incoming data diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h index b2a05e6791..c6bd4c87d8 100644 --- a/ports/esp8266/mpconfigport.h +++ b/ports/esp8266/mpconfigport.h @@ -87,7 +87,7 @@ #define MICROPY_PY_MACHINE_I2C (1) #define MICROPY_PY_MACHINE_SPI (1) #define MICROPY_PY_MACHINE_SPI_MAKE_NEW machine_hspi_make_new -#define MICROPY_PY_WEBSOCKET (1) +#define MICROPY_PY_UWEBSOCKET (1) #define MICROPY_PY_WEBREPL (1) #define MICROPY_PY_WEBREPL_DELAY (20) #define MICROPY_PY_FRAMEBUF (1) diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h index d0cc9e396e..2614af8392 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -136,7 +136,7 @@ #ifndef MICROPY_PY_USELECT_POSIX #define MICROPY_PY_USELECT_POSIX (1) #endif -#define MICROPY_PY_WEBSOCKET (1) +#define MICROPY_PY_UWEBSOCKET (1) #define MICROPY_PY_MACHINE (1) #define MICROPY_PY_MACHINE_PULSE (1) #define MICROPY_MACHINE_MEM_GET_READ_ADDR mod_machine_mem_get_addr diff --git a/py/builtin.h b/py/builtin.h index 2066c06173..a5e0f5f2d0 100644 --- a/py/builtin.h +++ b/py/builtin.h @@ -118,7 +118,7 @@ extern const mp_obj_module_t mp_module_ussl; extern const mp_obj_module_t mp_module_utimeq; extern const mp_obj_module_t mp_module_machine; extern const mp_obj_module_t mp_module_lwip; -extern const mp_obj_module_t mp_module_websocket; +extern const mp_obj_module_t mp_module_uwebsocket; extern const mp_obj_module_t mp_module_webrepl; extern const mp_obj_module_t mp_module_framebuf; extern const mp_obj_module_t mp_module_btree; diff --git a/py/mpconfig.h b/py/mpconfig.h index 95abacafdd..47638fb0a4 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -1316,8 +1316,8 @@ typedef double mp_float_t; #define MICROPY_PY_USSL_FINALISER (0) #endif -#ifndef MICROPY_PY_WEBSOCKET -#define MICROPY_PY_WEBSOCKET (0) +#ifndef MICROPY_PY_UWEBSOCKET +#define MICROPY_PY_UWEBSOCKET (0) #endif #ifndef MICROPY_PY_FRAMEBUF diff --git a/py/objmodule.c b/py/objmodule.c index 3a00b7ddc1..9ba617707a 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -211,8 +211,8 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = { #if MICROPY_PY_LWIP { MP_ROM_QSTR(MP_QSTR_lwip), MP_ROM_PTR(&mp_module_lwip) }, #endif -#if MICROPY_PY_WEBSOCKET - { MP_ROM_QSTR(MP_QSTR_websocket), MP_ROM_PTR(&mp_module_websocket) }, +#if MICROPY_PY_UWEBSOCKET + { MP_ROM_QSTR(MP_QSTR_uwebsocket), MP_ROM_PTR(&mp_module_uwebsocket) }, #endif #if MICROPY_PY_WEBREPL { MP_ROM_QSTR(MP_QSTR__webrepl), MP_ROM_PTR(&mp_module_webrepl) }, diff --git a/py/py.mk b/py/py.mk index 759c7e6ce0..a6eeaa4b87 100644 --- a/py/py.mk +++ b/py/py.mk @@ -256,7 +256,7 @@ PY_EXTMOD_O_BASENAME = \ extmod/modussl_mbedtls.o \ extmod/modurandom.o \ extmod/moduselect.o \ - extmod/modwebsocket.o \ + extmod/moduwebsocket.o \ extmod/modwebrepl.o \ extmod/modframebuf.o \ extmod/vfs.o \ diff --git a/tests/extmod/websocket_basic.py b/tests/extmod/websocket_basic.py index 9a80503a03..6cc6f0fd15 100644 --- a/tests/extmod/websocket_basic.py +++ b/tests/extmod/websocket_basic.py @@ -1,20 +1,20 @@ try: import uio import uerrno - import websocket + import uwebsocket except ImportError: print("SKIP") raise SystemExit # put raw data in the stream and do a websocket read def ws_read(msg, sz): - ws = websocket.websocket(uio.BytesIO(msg)) + ws = uwebsocket.websocket(uio.BytesIO(msg)) return ws.read(sz) # do a websocket write and then return the raw data from the stream def ws_write(msg, sz): s = uio.BytesIO() - ws = websocket.websocket(s) + ws = uwebsocket.websocket(s) ws.write(msg) s.seek(0) return s.read(sz) @@ -36,7 +36,7 @@ print(ws_read(b"\x81\x84maskmask", 4)) # close control frame s = uio.BytesIO(b'\x88\x00') # FRAME_CLOSE -ws = websocket.websocket(s) +ws = uwebsocket.websocket(s) print(ws.read(1)) s.seek(2) print(s.read(4)) @@ -46,11 +46,11 @@ print(ws_read(b"\x89\x00\x81\x04ping", 4)) # FRAME_PING print(ws_read(b"\x8a\x00\x81\x04pong", 4)) # FRAME_PONG # close method -ws = websocket.websocket(uio.BytesIO()) +ws = uwebsocket.websocket(uio.BytesIO()) ws.close() # ioctl -ws = websocket.websocket(uio.BytesIO()) +ws = uwebsocket.websocket(uio.BytesIO()) print(ws.ioctl(8)) # GET_DATA_OPTS print(ws.ioctl(9, 2)) # SET_DATA_OPTS print(ws.ioctl(9)) From 7b2dc9625116936a00e299e31ae2fe0314a3a144 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 14 Feb 2019 13:35:39 +1100 Subject: [PATCH 0095/1788] stm32/boards/make-pins.py: Add cmdline options to support use by mboot. --- ports/stm32/Makefile | 6 +++- ports/stm32/boards/make-pins.py | 49 +++++++++++++++++++++++---------- 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index c7dc99fd7d..20a26f2344 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -573,7 +573,11 @@ main.c: $(GEN_CDCINF_HEADER) # both pins_$(BOARD).c and pins.h $(BUILD)/%_$(BOARD).c $(HEADER_BUILD)/%.h $(HEADER_BUILD)/%_af_const.h $(HEADER_BUILD)/%_af_defs.h $(BUILD)/%_qstr.h: $(BOARD_DIR)/%.csv $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE) | $(HEADER_BUILD) $(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-defs $(GEN_PINS_AF_DEFS) --af-py $(GEN_PINS_AF_PY) > $(GEN_PINS_SRC) + $(Q)$(PYTHON) $(MAKE_PINS) --board $(BOARD_PINS) --af $(AF_FILE) \ + --prefix $(PREFIX_FILE) --hdr $(GEN_PINS_HDR) --hdr-obj-decls \ + --qstr $(GEN_PINS_QSTR) --af-const $(GEN_PINS_AF_CONST) \ + --af-defs $(GEN_PINS_AF_DEFS) --af-defs-cmp-strings \ + --af-py $(GEN_PINS_AF_PY) > $(GEN_PINS_SRC) $(BUILD)/pins_$(BOARD).o: $(BUILD)/pins_$(BOARD).c $(call compile_c) diff --git a/ports/stm32/boards/make-pins.py b/ports/stm32/boards/make-pins.py index 89c393217d..ed112e05f0 100755 --- a/ports/stm32/boards/make-pins.py +++ b/ports/stm32/boards/make-pins.py @@ -341,15 +341,16 @@ class Pins(object): print('};') - def print_header(self, hdr_filename): + def print_header(self, hdr_filename, obj_decls): with open(hdr_filename, 'wt') as hdr_file: - for named_pin in self.cpu_pins: - pin = named_pin.pin() - if pin.is_board_pin(): - pin.print_header(hdr_file) - hdr_file.write('extern const pin_obj_t * const pin_adc1[];\n') - hdr_file.write('extern const pin_obj_t * const pin_adc2[];\n') - hdr_file.write('extern const pin_obj_t * const pin_adc3[];\n') + if obj_decls: + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if pin.is_board_pin(): + pin.print_header(hdr_file) + hdr_file.write('extern const pin_obj_t * const pin_adc1[];\n') + hdr_file.write('extern const pin_obj_t * const pin_adc2[];\n') + hdr_file.write('extern const pin_obj_t * const pin_adc3[];\n') # provide #define's mapping board to cpu name for named_pin in self.board_pins: hdr_file.write("#define pyb_pin_{:s} pin_{:s}\n".format(named_pin.name(), named_pin.pin().cpu_pin_name())) @@ -396,7 +397,7 @@ class Pins(object): file=af_const_file) print_conditional_endif(cond_var, file=af_const_file) - def print_af_defs(self, af_defs_filename): + def print_af_defs(self, af_defs_filename, cmp_strings): with open(af_defs_filename, 'wt') as af_defs_file: STATIC_AF_TOKENS = {} @@ -407,11 +408,17 @@ class Pins(object): tok = "#define STATIC_AF_%s_%s(pin_obj) ( \\" % (func, pin_type) if tok not in STATIC_AF_TOKENS: STATIC_AF_TOKENS[tok] = [] - STATIC_AF_TOKENS[tok].append( - ' ((strcmp( #pin_obj , "(&pin_%s_obj)") & strcmp( #pin_obj , "((&pin_%s_obj))")) == 0) ? (%d) : \\' % ( - named_pin.pin().cpu_pin_name(), named_pin.pin().cpu_pin_name(), af.idx + if cmp_strings: + pin_name = named_pin.pin().cpu_pin_name() + cmp_str = ' ((strcmp( #pin_obj , "(&pin_%s_obj)") ' \ + ' & strcmp( #pin_obj , "((&pin_%s_obj))")) == 0) ? (%d) : \\' % ( + pin_name, pin_name, af.idx ) - ) + else: + cmp_str = ' ((pin_obj) == (pin_%s)) ? (%d) : \\' % ( + named_pin.pin().cpu_pin_name(), af.idx + ) + STATIC_AF_TOKENS[tok].append(cmp_str) for tok, pins in STATIC_AF_TOKENS.items(): print(tok, file=af_defs_file) @@ -460,6 +467,12 @@ def main(): help="Specifies the filename for the alternate function defines.", default="build/pins_af_defs.h" ) + parser.add_argument( + "--af-defs-cmp-strings", + dest="af_defs_cmp_strings", + help="Whether to compare pin name strings for the alternate function defines instead of object values", + action="store_true", + ) parser.add_argument( "-b", "--board", dest="board_filename", @@ -483,6 +496,12 @@ def main(): help="Specifies name of generated pin header file", default="build/pins.h" ) + parser.add_argument( + "--hdr-obj-decls", + dest="hdr_obj_decls", + help="Whether to include declarations for pin objects in pin header file", + action="store_true" + ) args = parser.parse_args(sys.argv[1:]) pins = Pins() @@ -506,11 +525,11 @@ def main(): pins.print_adc(1) pins.print_adc(2) pins.print_adc(3) - pins.print_header(args.hdr_filename) + pins.print_header(args.hdr_filename, args.hdr_obj_decls) pins.print_qstr(args.qstr_filename) pins.print_af_hdr(args.af_const_filename) pins.print_af_py(args.af_py_filename) - pins.print_af_defs(args.af_defs_filename) + pins.print_af_defs(args.af_defs_filename, args.af_defs_cmp_strings) if __name__ == "__main__": From f38397ba8dff31bd0013b21ad07a9a37b221713f Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 14 Feb 2019 13:36:32 +1100 Subject: [PATCH 0096/1788] stm32/mboot/Makefile: Generate all pin header files from board pins.csv. --- ports/stm32/mboot/Makefile | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/ports/stm32/mboot/Makefile b/ports/stm32/mboot/Makefile index 87a530a3c8..445287b5a3 100644 --- a/ports/stm32/mboot/Makefile +++ b/ports/stm32/mboot/Makefile @@ -146,6 +146,36 @@ $(BUILD)/firmware.elf: $(OBJ) $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS) $(Q)$(SIZE) $@ +######################################### +# Rules to generate header files + +MAKE_PINS = ../boards/make-pins.py +PREFIX_FILE = ../boards/stm32f4xx_prefix.c +BOARD_PINS = $(BOARD_DIR)/pins.csv +HEADER_BUILD = $(BUILD)/genhdr +GEN_QSTRDEFS_GENERATED = $(HEADER_BUILD)/qstrdefs.generated.h +GEN_PINS_SRC = $(BUILD)/pins_$(BOARD).c +GEN_PINS_HDR = $(HEADER_BUILD)/pins.h +GEN_PINS_QSTR = $(HEADER_BUILD)/pins_qstr.h +GEN_PINS_AF_CONST = $(HEADER_BUILD)/pins_af_const.h +GEN_PINS_AF_DEFS = $(HEADER_BUILD)/pins_af_defs.h +GEN_PINS_AF_PY = $(BUILD)/pins_af.py + +$(BUILD)/main.o: $(GEN_QSTRDEFS_GENERATED) $(GEN_PINS_AF_DEFS) + +$(HEADER_BUILD): + $(MKDIR) -p $(BUILD)/genhdr + +$(GEN_QSTRDEFS_GENERATED): | $(HEADER_BUILD) + $(Q)echo "// empty" > $@ + +$(GEN_PINS_AF_DEFS): $(BOARD_PINS) $(MAKE_PINS) ../$(AF_FILE) $(PREFIX_FILE) | $(HEADER_BUILD) + $(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-defs $(GEN_PINS_AF_DEFS) \ + --af-py $(GEN_PINS_AF_PY) > $(GEN_PINS_SRC) + ######################################### vpath %.S . $(TOP) @@ -190,10 +220,4 @@ 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) From be4e5b1f872c29b5a3a64397e5ec50d2b0880382 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 14 Feb 2019 13:39:13 +1100 Subject: [PATCH 0097/1788] stm32/mboot/mphalport.h: Include genhdr/pins.h for access to pin names. So that mboot configuration can use names like pyb_pin_X1. --- ports/stm32/mboot/mphalport.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/stm32/mboot/mphalport.h b/ports/stm32/mboot/mphalport.h index 42b1dcc8b6..d3ed18a998 100644 --- a/ports/stm32/mboot/mphalport.h +++ b/ports/stm32/mboot/mphalport.h @@ -26,6 +26,8 @@ #include +#include "genhdr/pins.h" + #define mp_hal_delay_us_fast(us) mp_hal_delay_us(us) #define MP_HAL_PIN_MODE_INPUT (0) From 4daee317064c855669942329f1136dec1b053ecf Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Mon, 11 Feb 2019 17:22:37 +1100 Subject: [PATCH 0098/1788] stm32/qspi: Use static af functions for pin configuration. This allows qspi pin configuration to work on any supported platform. --- ports/stm32/qspi.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/ports/stm32/qspi.c b/ports/stm32/qspi.c index a7cbbde014..986206891c 100644 --- a/ports/stm32/qspi.c +++ b/ports/stm32/qspi.c @@ -29,17 +29,18 @@ #include "py/mperrno.h" #include "py/mphal.h" #include "qspi.h" +#include "pin_static_af.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); + mp_hal_pin_config_alt_static(MICROPY_HW_QSPIFLASH_CS, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_QUADSPI_BK1_NCS); + mp_hal_pin_config_alt_static(MICROPY_HW_QSPIFLASH_SCK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_QUADSPI_CLK); + mp_hal_pin_config_alt_static(MICROPY_HW_QSPIFLASH_IO0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_QUADSPI_BK1_IO0); + mp_hal_pin_config_alt_static(MICROPY_HW_QSPIFLASH_IO1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_QUADSPI_BK1_IO1); + mp_hal_pin_config_alt_static(MICROPY_HW_QSPIFLASH_IO2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_QUADSPI_BK1_IO2); + mp_hal_pin_config_alt_static(MICROPY_HW_QSPIFLASH_IO3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_QUADSPI_BK1_IO3); // Bring up the QSPI peripheral From ff04b78ffda4273c9bfde67524f5233ccc9bab4d Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 15 Feb 2019 14:31:48 +1100 Subject: [PATCH 0099/1788] stm32/mboot: Add support for loading gzip'd firmware from a filesystem. This adds support to mboot to load and program application firmware from a .dfu.gz file on the board's filesystem. See mboot/README.md for details. --- ports/stm32/mboot/Makefile | 15 +- ports/stm32/mboot/README.md | 55 +++++- ports/stm32/mboot/diskio.c | 80 ++++++++ ports/stm32/mboot/elem.c | 44 +++++ ports/stm32/mboot/ffconf.h | 63 +++++++ ports/stm32/mboot/fsload.c | 291 +++++++++++++++++++++++++++++ ports/stm32/mboot/main.c | 42 ++++- ports/stm32/mboot/mboot.h | 58 ++++++ ports/stm32/mboot/stm32_generic.ld | 4 +- 9 files changed, 636 insertions(+), 16 deletions(-) create mode 100644 ports/stm32/mboot/diskio.c create mode 100644 ports/stm32/mboot/elem.c create mode 100644 ports/stm32/mboot/ffconf.h create mode 100644 ports/stm32/mboot/fsload.c create mode 100644 ports/stm32/mboot/mboot.h diff --git a/ports/stm32/mboot/Makefile b/ports/stm32/mboot/Makefile index 445287b5a3..a59a210823 100644 --- a/ports/stm32/mboot/Makefile +++ b/ports/stm32/mboot/Makefile @@ -54,6 +54,7 @@ CFLAGS += -I$(BOARD_DIR) CFLAGS += -DSTM32_HAL_H='' CFLAGS += -DBOARD_$(BOARD) CFLAGS += -DAPPLICATION_ADDR=$(TEXT0_ADDR) +CFLAGS += -DFFCONF_H=\"ports/stm32/mboot/ffconf.h\" LDFLAGS = -nostdlib -L . -T stm32_generic.ld -Map=$(@:.elf=.map) --cref LIBS = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) @@ -70,12 +71,20 @@ else COPT += -Os -DNDEBUG endif -SRC_LIB = $(addprefix lib/,\ - libc/string0.c \ - ) +SRC_LIB = \ + lib/libc/string0.c \ + lib/oofatfs/ff.c \ + lib/oofatfs/option/unicode.c \ + extmod/uzlib/crc32.c \ + extmod/uzlib/adler32.c \ + extmod/uzlib/tinflate.c \ + extmod/uzlib/tinfgzip.c SRC_C = \ main.c \ + elem.c \ + fsload.c \ + diskio.c \ drivers/bus/softspi.c \ drivers/bus/softqspi.c \ drivers/memory/spiflash.c \ diff --git a/ports/stm32/mboot/README.md b/ports/stm32/mboot/README.md index 0abb5051d5..14bfc66f9c 100644 --- a/ports/stm32/mboot/README.md +++ b/ports/stm32/mboot/README.md @@ -4,7 +4,9 @@ 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. +interface. It can also load and program firmware in .dfu.gz format from a +filesystem. It can fit in 16k of flash space, but all features enabled requires +32k. How to use ---------- @@ -57,6 +59,10 @@ How to use second one use the same configuration names as above but with `SPIFLASH2`, ie `MBOOT_SPIFLASH2_ADDR` etc. + To enable loading firmware from a filesystem use: + + #define MBOOT_FSLOAD (1) + 2. Build the board's main application firmware as usual. 3. Build mboot via: @@ -77,6 +83,53 @@ How to use to communicate with the I2C boot loader interface. It should be run on a pyboard connected via I2C to the target board. +Entering Mboot from application code +------------------------------------ + +To enter Mboot from a running application do the following: + +1. Make sure I and D caches are disabled. + +2. Load register r0 with the value 0x70ad0000. The lower 7 bits can be + optionally or'd with the desired I2C address. + +3. Load the MSP with the value held at 0x08000000. + +4. Jump to the value held at 0x08000004. + +Additional data can be passed to Mboot from application code by storing this +data in a special region of RAM. This region begins at the address held at +location 0x08000000 (which will point to just after Mboot's stack). A +maximum of 1024 bytes can be stored here. To indicate to Mboot that this +region is valid load register r0 with 0x70ad0080 (instead of step 2 above), +optionally or'd with the desired I2C address. + +Data in this region is a sequence of elements. Each element has the form: + + + +where `type` and `len` are bytes (designated by `u8`) and `payload` is 0 or +more bytes. `len` must be the number of bytes in `payload`. + +The last element in the data sequence must be the end element: + +* END: type=1, len=0 + +Loading firmware from a filesystem +---------------------------------- + +To get Mboot to load firmware from a filesystem and automatically program it +requires passing data elements (see above) which tell where the filesystems +are located and what filename to program. The elements to use are: + +* MOUNT: type=2, len=10, payload=( ) + +* FSLOAD: type=3, len=1+n, payload=( ) + +`u32` means unsigned 32-bit little-endian integer. + +The firmware to load must be a gzip'd DfuSe file (.dfu.gz). + Example: Mboot on PYBv1.x ------------------------- diff --git a/ports/stm32/mboot/diskio.c b/ports/stm32/mboot/diskio.c new file mode 100644 index 0000000000..2426f9329a --- /dev/null +++ b/ports/stm32/mboot/diskio.c @@ -0,0 +1,80 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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 "lib/oofatfs/ff.h" +#include "lib/oofatfs/diskio.h" +#include "mboot.h" + +#if MBOOT_FSLOAD + +#if _MAX_SS == _MIN_SS +#define SECSIZE (_MIN_SS) +#else +#error Unsupported +#endif + +DRESULT disk_read(void *pdrv, BYTE *buf, DWORD sector, UINT count) { + fsload_bdev_t *bdev = pdrv; + + if (0 <= sector && sector < bdev->byte_len / 512) { + do_read(bdev->base_addr + sector * SECSIZE, count * SECSIZE, buf); + return RES_OK; + } + + return RES_PARERR; +} + +DRESULT disk_ioctl(void *pdrv, BYTE cmd, void *buf) { + fsload_bdev_t *bdev = pdrv; + + switch (cmd) { + case CTRL_SYNC: + return RES_OK; + + case GET_SECTOR_COUNT: + *((DWORD*)buf) = bdev->byte_len / SECSIZE; + return RES_OK; + + case GET_SECTOR_SIZE: + *((WORD*)buf) = SECSIZE; + return RES_OK; + + case GET_BLOCK_SIZE: + *((DWORD*)buf) = 1; // erase block size in units of sector size + return RES_OK; + + case IOCTL_INIT: + case IOCTL_STATUS: + *((DSTATUS*)buf) = STA_PROTECT; + return RES_OK; + + default: + return RES_PARERR; + } +} + +#endif // MBOOT_FSLOAD diff --git a/ports/stm32/mboot/elem.c b/ports/stm32/mboot/elem.c new file mode 100644 index 0000000000..a8484e6573 --- /dev/null +++ b/ports/stm32/mboot/elem.c @@ -0,0 +1,44 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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 "mboot.h" + +// Elements are of the form: (type:u8, len:u8, payload) + +const uint8_t *elem_search(const uint8_t *elem, uint8_t elem_id) { + while (elem + 2 + elem[1] <= ELEM_DATA_MAX) { + if (elem[0] == elem_id) { + // Found element, return a pointer to the element data + return elem + 2; + } + if (elem[0] == ELEM_TYPE_END) { + // End of elements + return NULL; + } + elem += 2 + elem[1]; + } + return NULL; +} diff --git a/ports/stm32/mboot/ffconf.h b/ports/stm32/mboot/ffconf.h new file mode 100644 index 0000000000..7c45266a05 --- /dev/null +++ b/ports/stm32/mboot/ffconf.h @@ -0,0 +1,63 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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. + */ + +#define _FFCONF 68020 + +#define _FS_READONLY 1 +#define _FS_MINIMIZE 0 +#define _USE_STRFUNC 0 + +#define _USE_FIND 0 +#define _USE_MKFS 0 +#define _USE_FASTSEEK 0 +#define _USE_EXPAND 0 +#define _USE_CHMOD 0 +#define _USE_LABEL 0 +#define _USE_FORWARD 0 + +#define _CODE_PAGE 437 +#define _USE_LFN 1 +#define _MAX_LFN 255 +#define _LFN_UNICODE 0 +#define _STRF_ENCODE 3 +#define _FS_RPATH 0 + +#define _VOLUMES 1 +#define _STR_VOLUME_ID 0 +#define _MULTI_PARTITION 0 +#define _MIN_SS 512 +#define _MAX_SS 512 +#define _USE_TRIM 0 +#define _FS_NOFSINFO 0 + +#define _FS_TINY 1 +#define _FS_EXFAT 0 +#define _FS_NORTC 1 +#define _NORTC_MON 1 +#define _NORTC_MDAY 1 +#define _NORTC_YEAR 2019 +#define _FS_LOCK 0 +#define _FS_REENTRANT 0 diff --git a/ports/stm32/mboot/fsload.c b/ports/stm32/mboot/fsload.c new file mode 100644 index 0000000000..5e7d968425 --- /dev/null +++ b/ports/stm32/mboot/fsload.c @@ -0,0 +1,291 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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/mphal.h" +#include "lib/oofatfs/ff.h" +#include "extmod/uzlib/uzlib.h" +#include "mboot.h" + +#if MBOOT_FSLOAD + +#define DICT_SIZE (1 << 15) + +typedef struct _gz_stream_t { + FIL fp; + TINF_DATA tinf; + uint8_t buf[512]; + uint8_t dict[DICT_SIZE]; +} gz_stream_t; + +static gz_stream_t gz_stream; + +static int gz_stream_read_src(TINF_DATA *tinf) { + UINT n; + FRESULT res = f_read(&gz_stream.fp, gz_stream.buf, sizeof(gz_stream.buf), &n); + if (res != FR_OK) { + return -1; + } + if (n == 0) { + return -1; + } + tinf->source = gz_stream.buf + 1; + tinf->source_limit = gz_stream.buf + n; + return gz_stream.buf[0]; +} + +static int gz_stream_open(FATFS *fatfs, const char *filename) { + FRESULT res = f_open(fatfs, &gz_stream.fp, filename, FA_READ); + if (res != FR_OK) { + return -1; + } + memset(&gz_stream.tinf, 0, sizeof(gz_stream.tinf)); + gz_stream.tinf.readSource = gz_stream_read_src; + + int st = uzlib_gzip_parse_header(&gz_stream.tinf); + if (st != TINF_OK) { + f_close(&gz_stream.fp); + return -1; + } + + uzlib_uncompress_init(&gz_stream.tinf, gz_stream.dict, DICT_SIZE); + + return 0; +} + +static int gz_stream_read(size_t len, uint8_t *buf) { + gz_stream.tinf.dest = buf; + gz_stream.tinf.dest_limit = buf + len; + int st = uzlib_uncompress_chksum(&gz_stream.tinf); + if (st == TINF_DONE) { + return 0; + } + if (st < 0) { + return st; + } + return gz_stream.tinf.dest - buf; +} + +static int fsload_program_file(FATFS *fatfs, const char *filename, bool write_to_flash) { + int res = gz_stream_open(fatfs, filename); + if (res != 0) { + return res; + } + + // Parse DFU + uint8_t buf[512]; + size_t file_offset; + + // Read file header, <5sBIB + res = gz_stream_read(11, buf); + if (res != 11) { + return -1; + } + file_offset = 11; + + // Validate header, version 1 + if (memcmp(buf, "DfuSe\x01", 6) != 0) { + return -1; + } + + // Must have only 1 target + if (buf[10] != 1) { + return -2; + } + + // Get total size + uint32_t total_size = get_le32(buf + 6); + + // Read target header, <6sBi255sII + res = gz_stream_read(274, buf); + if (res != 274) { + return -1; + } + file_offset += 274; + + // Validate target header, with alt being 0 + if (memcmp(buf, "Target\x00", 7) != 0) { + return -1; + } + + // Get target size and number of elements + uint32_t target_size = get_le32(buf + 266); + uint32_t num_elems = get_le32(buf + 270); + + size_t file_offset_target = file_offset; + + // Parse each element + for (size_t elem = 0; elem < num_elems; ++elem) { + // Read element header, sizeof(buf)) { + l = sizeof(buf); + } + res = gz_stream_read(l, buf); + if (res != l) { + return -1; + } + if (write_to_flash) { + res = do_write(elem_addr, buf, l); + if (res != 0) { + return -1; + } + elem_addr += l; + } + s -= l; + } + + file_offset += elem_size; + } + + if (target_size != file_offset - file_offset_target) { + return -1; + } + + if (total_size != file_offset) { + return -1; + } + + // Read trailing info + res = gz_stream_read(16, buf); + if (res != 16) { + return -1; + } + + // TODO validate CRC32 + + return 0; +} + +static int fsload_process_fatfs(uint32_t base_addr, uint32_t byte_len, size_t fname_len, const char *fname) { + fsload_bdev_t bdev = {base_addr, byte_len}; + FATFS fatfs; + fatfs.drv = &bdev; + FRESULT res = f_mount(&fatfs); + if (res != FR_OK) { + return -1; + } + + FF_DIR dp; + res = f_opendir(&fatfs, &dp, "/"); + if (res != FR_OK) { + return -1; + } + + // Search for firmware file with correct name + int r; + for (;;) { + FILINFO fno; + res = f_readdir(&dp, &fno); + char *fn = fno.fname; + if (res != FR_OK || fn[0] == 0) { + // Finished listing dir, no firmware found + r = -1; + break; + } + if (memcmp(fn, fname, fname_len) == 0 && fn[fname_len] == '\0') { + // Found firmware + led_state_all(2); + r = fsload_program_file(&fatfs, fn, false); + if (r == 0) { + // Firmware is valid, program it + led_state_all(4); + r = fsload_program_file(&fatfs, fn, true); + } + break; + } + } + + return r; +} + +int fsload_process(void) { + const uint8_t *elem = elem_search(ELEM_DATA_START, ELEM_TYPE_FSLOAD); + if (elem == NULL || elem[-1] < 2) { + return -1; + } + + uint8_t mount_point = elem[0]; + uint8_t fname_len = elem[-1] - 1; + const char *fname = (const char*)&elem[1]; + + elem = ELEM_DATA_START; + for (;;) { + elem = elem_search(elem, ELEM_TYPE_MOUNT); + if (elem == NULL || elem[-1] != 10) { + // End of elements, or invalid MOUNT element + return -1; + } + if (elem[0] == mount_point) { + uint32_t base_addr = get_le32(&elem[2]); + uint32_t byte_len = get_le32(&elem[6]); + if (elem[1] == ELEM_MOUNT_FAT) { + int ret = fsload_process_fatfs(base_addr, byte_len, fname_len, fname); + // Flash LEDs based on success/failure of update + for (int i = 0; i < 4; ++i) { + if (ret == 0) { + led_state_all(7); + } else { + led_state_all(1); + } + mp_hal_delay_ms(100); + led_state_all(0); + mp_hal_delay_ms(100); + } + return ret; + } + // Unknown filesystem type + return -1; + } + elem += elem[-1]; + } +} + +#endif // MBOOT_FSLOAD diff --git a/ports/stm32/mboot/main.c b/ports/stm32/mboot/main.c index b040d4bac8..0d39b7153b 100644 --- a/ports/stm32/mboot/main.c +++ b/ports/stm32/mboot/main.c @@ -32,6 +32,7 @@ #include "usbd_core.h" #include "storage.h" #include "i2cslave.h" +#include "mboot.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 @@ -76,7 +77,7 @@ static void do_reset(void); -static uint32_t get_le32(const uint8_t *b) { +uint32_t get_le32(const uint8_t *b) { return b[0] | b[1] << 8 | b[2] << 16 | b[3] << 24; } @@ -382,7 +383,7 @@ static const flash_layout_t flash_layout[] = { #endif -static uint32_t flash_get_sector_index(uint32_t addr) { +static uint32_t flash_get_sector_index(uint32_t addr, uint32_t *sector_size) { if (addr >= flash_layout[0].base_address) { uint32_t sector_index = 0; for (int i = 0; i < MP_ARRAY_SIZE(flash_layout); ++i) { @@ -390,6 +391,7 @@ static uint32_t flash_get_sector_index(uint32_t addr) { uint32_t sector_start_next = flash_layout[i].base_address + (j + 1) * flash_layout[i].sector_size; if (addr < sector_start_next) { + *sector_size = flash_layout[i].sector_size; return sector_index; } ++sector_index; @@ -404,13 +406,16 @@ static int flash_mass_erase(void) { return -1; } -static int flash_page_erase(uint32_t addr) { - uint32_t sector = flash_get_sector_index(addr); +static int flash_page_erase(uint32_t addr, uint32_t *next_addr) { + uint32_t sector_size = 0; + uint32_t sector = flash_get_sector_index(addr, §or_size); if (sector == 0) { // Don't allow to erase the sector with this bootloader in it return -1; } + *next_addr = addr + sector_size; + HAL_FLASH_Unlock(); // Clear pending flags (if any) @@ -484,11 +489,12 @@ static int spiflash_page_erase(mp_spiflash_t *spif, uint32_t addr, uint32_t n_bl } #endif -static int do_page_erase(uint32_t addr) { +int do_page_erase(uint32_t addr, uint32_t *next_addr) { led_state(LED0, 1); #if defined(MBOOT_SPIFLASH_ADDR) if (MBOOT_SPIFLASH_ADDR <= addr && addr < MBOOT_SPIFLASH_ADDR + MBOOT_SPIFLASH_BYTE_SIZE) { + *next_addr = addr + MBOOT_SPIFLASH_ERASE_BLOCKS_PER_PAGE * MP_SPIFLASH_ERASE_BLOCK_SIZE; return spiflash_page_erase(MBOOT_SPIFLASH_SPIFLASH, addr - MBOOT_SPIFLASH_ADDR, MBOOT_SPIFLASH_ERASE_BLOCKS_PER_PAGE); } @@ -496,15 +502,16 @@ static int do_page_erase(uint32_t addr) { #if defined(MBOOT_SPIFLASH2_ADDR) if (MBOOT_SPIFLASH2_ADDR <= addr && addr < MBOOT_SPIFLASH2_ADDR + MBOOT_SPIFLASH2_BYTE_SIZE) { + *next_addr = addr + MBOOT_SPIFLASH2_ERASE_BLOCKS_PER_PAGE * MP_SPIFLASH_ERASE_BLOCK_SIZE; return spiflash_page_erase(MBOOT_SPIFLASH2_SPIFLASH, addr - MBOOT_SPIFLASH2_ADDR, MBOOT_SPIFLASH2_ERASE_BLOCKS_PER_PAGE); } #endif - return flash_page_erase(addr); + return flash_page_erase(addr, next_addr); } -static void do_read(uint32_t addr, int len, uint8_t *buf) { +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); @@ -522,7 +529,7 @@ static void do_read(uint32_t addr, int len, uint8_t *buf) { memcpy(buf, (void*)addr, len); } -static int do_write(uint32_t addr, const uint8_t *src8, size_t len) { +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); @@ -634,7 +641,8 @@ void i2c_slave_process_rx_end(void) { } 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)); + uint32_t next_addr; + len = do_page_erase(get_le32(buf + 1), &next_addr); } else if (buf[0] == I2C_CMD_SETRDADDR && len == 4) { i2c_obj.cmd_rdaddr = get_le32(buf + 1); len = 0; @@ -764,7 +772,8 @@ static int dfu_process_dnload(void) { ret = do_mass_erase(); } else if (dfu_state.wLength == 5) { // erase page - ret = do_page_erase(get_le32(&dfu_state.buf[1])); + uint32_t next_addr; + ret = do_page_erase(get_le32(&dfu_state.buf[1]), &next_addr); } } else if (dfu_state.wLength >= 1 && dfu_state.buf[0] == 0x21) { if (dfu_state.wLength == 5) { @@ -1255,6 +1264,19 @@ enter_bootloader: mp_spiflash_init(MBOOT_SPIFLASH2_SPIFLASH); #endif + #if MBOOT_FSLOAD + if ((initial_r0 & 0xffffff80) == 0x70ad0080) { + // Application passed through elements, validate then process them + const uint8_t *elem_end = elem_search(ELEM_DATA_START, ELEM_TYPE_END); + if (elem_end != NULL && elem_end[-1] == 0) { + fsload_process(); + } + // Always reset because the application is expecting to resume + led_state_all(0); + NVIC_SystemReset(); + } + #endif + dfu_init(); pyb_usbdd_init(&pyb_usbdd, pyb_usbdd_detect_port()); diff --git a/ports/stm32/mboot/mboot.h b/ports/stm32/mboot/mboot.h new file mode 100644 index 0000000000..f3b8f1ec8f --- /dev/null +++ b/ports/stm32/mboot/mboot.h @@ -0,0 +1,58 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#define ELEM_DATA_START (&_estack) +#define ELEM_DATA_MAX (ELEM_DATA_START + 1024) + +enum { + ELEM_TYPE_END = 1, + ELEM_TYPE_MOUNT, + ELEM_TYPE_FSLOAD, +}; + +enum { + ELEM_MOUNT_FAT = 1, +}; + +typedef struct _fsload_bdev_t { + uint32_t base_addr; + uint32_t byte_len; +} fsload_bdev_t; + +extern uint8_t _estack; + +uint32_t get_le32(const uint8_t *b); +void led_state_all(unsigned int mask); + +int do_page_erase(uint32_t addr, uint32_t *next_addr); +void do_read(uint32_t addr, int len, uint8_t *buf); +int do_write(uint32_t addr, const uint8_t *src8, size_t len); + +const uint8_t *elem_search(const uint8_t *elem, uint8_t elem_id); +int fsload_process(void); diff --git a/ports/stm32/mboot/stm32_generic.ld b/ports/stm32/mboot/stm32_generic.ld index 8585c68734..4b1522e7ba 100644 --- a/ports/stm32/mboot/stm32_generic.ld +++ b/ports/stm32/mboot/stm32_generic.ld @@ -5,8 +5,8 @@ /* Specify the memory areas */ MEMORY { - FLASH_BL (rx) : ORIGIN = 0x08000000, LENGTH = 16K /* sector 0 (can be 32K) */ - RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K + FLASH_BL (rx) : ORIGIN = 0x08000000, LENGTH = 32K /* sector 0 (can be 32K) */ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K } /* produce a link error if there is not this amount of RAM for these sections */ From 3d0c31e60ed6fe5a104bf282cbe42caca3150146 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 15 Feb 2019 14:59:24 +1100 Subject: [PATCH 0100/1788] stm32/mboot: Move some BSS vars to new section that isn't zeroed out. Zeroing out data on startup takes time and is not necessary for certain variables. So provide a declaration for such variables and use it. --- ports/stm32/mboot/fsload.c | 2 +- ports/stm32/mboot/main.c | 5 +++-- ports/stm32/mboot/mboot.h | 3 +++ ports/stm32/mboot/stm32_generic.ld | 11 +++++++++-- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/ports/stm32/mboot/fsload.c b/ports/stm32/mboot/fsload.c index 5e7d968425..64eb2a3a5b 100644 --- a/ports/stm32/mboot/fsload.c +++ b/ports/stm32/mboot/fsload.c @@ -42,7 +42,7 @@ typedef struct _gz_stream_t { uint8_t dict[DICT_SIZE]; } gz_stream_t; -static gz_stream_t gz_stream; +static gz_stream_t gz_stream SECTION_NOZERO_BSS; static int gz_stream_read_src(TINF_DATA *tinf) { UINT n; diff --git a/ports/stm32/mboot/main.c b/ports/stm32/mboot/main.c index 0d39b7153b..aaad61cf54 100644 --- a/ports/stm32/mboot/main.c +++ b/ports/stm32/mboot/main.c @@ -754,7 +754,7 @@ typedef struct _dfu_state_t { uint8_t buf[DFU_XFER_SIZE] __attribute__((aligned(4))); } dfu_state_t; -static dfu_state_t dfu_state; +static dfu_state_t dfu_state SECTION_NOZERO_BSS; static void dfu_init(void) { dfu_state.status = DFU_STATUS_IDLE; @@ -1070,7 +1070,7 @@ static const USBD_ClassTypeDef pyb_usbdd_class = { pyb_usbdd_GetDeviceQualifierDescriptor, }; -static pyb_usbdd_obj_t pyb_usbdd; +static pyb_usbdd_obj_t pyb_usbdd SECTION_NOZERO_BSS; static int pyb_usbdd_detect_port(void) { #if MBOOT_USB_AUTODETECT_PORT @@ -1096,6 +1096,7 @@ static int pyb_usbdd_detect_port(void) { static void pyb_usbdd_init(pyb_usbdd_obj_t *self, int phy_id) { self->started = false; + self->tx_pending = false; USBD_HandleTypeDef *usbd = &self->hUSBDDevice; usbd->id = phy_id; usbd->dev_state = USBD_STATE_DEFAULT; diff --git a/ports/stm32/mboot/mboot.h b/ports/stm32/mboot/mboot.h index f3b8f1ec8f..54b3dc7298 100644 --- a/ports/stm32/mboot/mboot.h +++ b/ports/stm32/mboot/mboot.h @@ -27,6 +27,9 @@ #include #include +// Use this to tag global static data in RAM that doesn't need to be zeroed on startup +#define SECTION_NOZERO_BSS __attribute__((section(".nozero_bss"))) + #define ELEM_DATA_START (&_estack) #define ELEM_DATA_MAX (ELEM_DATA_START + 1024) diff --git a/ports/stm32/mboot/stm32_generic.ld b/ports/stm32/mboot/stm32_generic.ld index 4b1522e7ba..0504d6d6ae 100644 --- a/ports/stm32/mboot/stm32_generic.ld +++ b/ports/stm32/mboot/stm32_generic.ld @@ -53,18 +53,25 @@ SECTIONS _edata = .; } >RAM AT> FLASH_BL - /* Uninitialized data section */ + /* Zeroed-out data section */ .bss : { . = ALIGN(4); _sbss = .; *(.bss*) *(COMMON) - . = ALIGN(4); _ebss = .; } >RAM + /* Uninitialized data section */ + .nozero_bss (NOLOAD) : + { + . = ALIGN(4); + *(.nozero_bss*) + . = ALIGN(4); + } >RAM + /* this just checks there is enough RAM for the stack */ .stack : { From 3669198403e48e5b2001a10d791260b505d8ed5d Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 15 Feb 2019 15:05:53 +1100 Subject: [PATCH 0101/1788] stm32/mboot: Add support script which can program mboot and application. --- ports/stm32/mboot/fwupdate.py | 172 ++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 ports/stm32/mboot/fwupdate.py diff --git a/ports/stm32/mboot/fwupdate.py b/ports/stm32/mboot/fwupdate.py new file mode 100644 index 0000000000..b2690e8cda --- /dev/null +++ b/ports/stm32/mboot/fwupdate.py @@ -0,0 +1,172 @@ +# Update Mboot or MicroPython from a .dfu.gz file on the board's filesystem +# MIT license; Copyright (c) 2019 Damien P. George + +import struct, time +import uzlib, machine, stm + + +FLASH_KEY1 = 0x45670123 +FLASH_KEY2 = 0xcdef89ab + + +def check_mem_contains(addr, buf): + mem8 = stm.mem8 + r = range(len(buf)) + for off in r: + if mem8[addr + off] != buf[off]: + return False + return True + +def check_mem_erased(addr, size): + mem16 = stm.mem16 + r = range(0, size, 2) + for off in r: + if mem16[addr + off] != 0xffff: + return False + return True + +def dfu_read(filename): + f = open(filename, 'rb') + + hdr = f.read(3) + f.seek(0) + if hdr == b'Dfu': + pass + elif hdr == b'\x1f\x8b\x08': + f = uzlib.DecompIO(f, 16 + 15) + else: + print('Invalid firmware', filename) + return None + + elems = [] + + hdr = f.read(11) + sig, ver, size, num_targ = struct.unpack('<5sBIB', hdr) + + file_offset = 11 + + for i in range(num_targ): + hdr = f.read(274) + sig, alt, has_name, name, t_size, num_elem = struct.unpack('<6sBi255sII', hdr) + + file_offset += 274 + file_offset_t = file_offset + for j in range(num_elem): + hdr = f.read(8) + addr, e_size = struct.unpack(' 16 * 1024 and not check_mem_erased(mboot_addr + 16 * 1024, 16 * 1024): + flash_erase_sector(1) + flash_write(mboot_addr, mboot_fw) + flash_lock() + machine.enable_irq(irq) + + print('New Mboot programmed.') + + if check_mem_contains(mboot_addr, mboot_fw): + print('Verification of new Mboot succeeded.') + else: + print('Verification of new Mboot FAILED! Try rerunning.') + + print('Programming finished, can now reset or turn off.') + +def update_mpy(filename, fs_base, fs_len): + # Check firmware is of .dfu.gz type + try: + with open(filename, 'rb') as f: + hdr = uzlib.DecompIO(f, 16 + 15).read(6) + except Exception: + hdr = None + if hdr != b'DfuSe\x01': + print('Firmware must be a .dfu.gz file.') + return + + ELEM_TYPE_END = 1 + ELEM_TYPE_MOUNT = 2 + ELEM_TYPE_FSLOAD = 3 + ELEM_MOUNT_FAT = 1 + mount_point = 1 + mount = struct.pack(' Date: Fri, 15 Feb 2019 15:07:53 +1100 Subject: [PATCH 0102/1788] stm32/modmachine: Add ability to pass through user data to mboot. --- ports/stm32/modmachine.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index 3c60378ffd..f7b84bae67 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -30,6 +30,7 @@ #include "modmachine.h" #include "py/gc.h" #include "py/runtime.h" +#include "py/objstr.h" #include "py/mperrno.h" #include "py/mphal.h" #include "extmod/machine_mem.h" @@ -273,6 +274,20 @@ STATIC NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args) __set_MSP(*(volatile uint32_t*)0x08000000); ((void (*)(uint32_t)) *((volatile uint32_t*)(0x08000000 + 4)))(0x70ad0000); } + + if (n_args == 1 && mp_obj_is_str_or_bytes(args[0])) { + // With a string/bytes given, pass its data to the custom bootloader + size_t len; + const char *data = mp_obj_str_get_data(args[0], &len); + void *mboot_region = (void*)*((volatile uint32_t*)0x08000000); + memmove(mboot_region, data, len); + #if __DCACHE_PRESENT == 1 + SCB_DisableICache(); + SCB_DisableDCache(); + #endif + __set_MSP(*(volatile uint32_t*)0x08000000); + ((void (*)(uint32_t)) *((volatile uint32_t*)(0x08000000 + 4)))(0x70ad0080); + } #endif #if defined(STM32F7) || defined(STM32H7) From c551169bd8221a8c750ab0d0ca0eb3e9bde58530 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 15 Feb 2019 15:34:05 +1100 Subject: [PATCH 0103/1788] stm32/mboot: Add hook to run board-specific code early on startup. --- ports/stm32/mboot/main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/stm32/mboot/main.c b/ports/stm32/mboot/main.c index aaad61cf54..838c5fe08a 100644 --- a/ports/stm32/mboot/main.c +++ b/ports/stm32/mboot/main.c @@ -1211,6 +1211,10 @@ void stm32_main(int initial_r0) { SCB_EnableDCache(); #endif + #if defined(MBOOT_BOARD_EARLY_INIT) + MBOOT_BOARD_EARLY_INIT(); + #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) { From 7ef9482b8af5bdc2fd1dea0ae1fad5fc9539cc14 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 15 Feb 2019 16:07:24 +1100 Subject: [PATCH 0104/1788] extmod/modlwip: Change #ifdef to #if for check of MICROPY_PY_LWIP. Otherwise this code will be included if MICROPY_PY_LWIP is defined to 0. --- extmod/modlwip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index d76fd1b1e4..36516803fc 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -1500,7 +1500,7 @@ STATIC mp_obj_t lwip_print_pcbs() { } MP_DEFINE_CONST_FUN_OBJ_0(lwip_print_pcbs_obj, lwip_print_pcbs); -#ifdef MICROPY_PY_LWIP +#if MICROPY_PY_LWIP STATIC const mp_rom_map_elem_t mp_module_lwip_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_lwip) }, From ed09e13943e29ab63ffaaae3bbb2812178def811 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 18 Feb 2019 12:38:38 +1100 Subject: [PATCH 0105/1788] esp32/modsocket: Fix usocket.send to accept anything with buffer proto. --- ports/esp32/modsocket.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c index 49e48aaa31..2bb717fda0 100644 --- a/ports/esp32/modsocket.c +++ b/ports/esp32/modsocket.c @@ -466,9 +466,9 @@ int _socket_send(socket_obj_t *sock, const char *data, size_t datalen) { 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); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(arg1, &bufinfo, MP_BUFFER_READ); + int r = _socket_send(sock, bufinfo.buf, bufinfo.len); return mp_obj_new_int(r); } STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_send_obj, socket_send); From c65e5c88b8ec805d40a4b040a56569f8b1aa8bab Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 18 Feb 2019 13:18:59 +1100 Subject: [PATCH 0106/1788] stm32/boards/stm32f429.ld: Increase uPy heap size by 64k for F429 MCU. The F429 has 256k total RAM, with 64k already set aside for flash write cache, so the uPy heap can be increased this much. --- ports/stm32/boards/stm32f429.ld | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/boards/stm32f429.ld b/ports/stm32/boards/stm32f429.ld index d80f7f5416..d91f625ef6 100644 --- a/ports/stm32/boards/stm32f429.ld +++ b/ports/stm32/boards/stm32f429.ld @@ -26,4 +26,4 @@ _estack = ORIGIN(RAM) + LENGTH(RAM); _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); _heap_start = _ebss; /* heap starts just after statically allocated memory */ -_heap_end = 0x2001c000; /* tunable */ +_heap_end = 0x2002c000; /* tunable */ From 42c0e440b9635fb33c0b2a162f5bfe3122dce079 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 18 Feb 2019 14:23:35 +1100 Subject: [PATCH 0107/1788] extmod/modlwip: Fix bug when polling listening socket with backlog=1. The bug polling for readability was: if alloc==0 and tcp.item==NULL then the code would incorrectly check tcp.array[iget] which is an invalid dereference when alloc==0. This patch refactors the code to use a helper function lwip_socket_incoming_array() to return the correct pointer for the incomming connection array. Fixes issue #4511. --- extmod/modlwip.c | 41 ++++++++++++++++------------------------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index 36516803fc..bd952111d6 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2013-2019 Damien P. George * Copyright (c) 2015 Galen Hazelwood * Copyright (c) 2015-2017 Paul Sokolovsky * @@ -308,6 +308,14 @@ static inline void poll_sockets(void) { #endif } +STATIC struct tcp_pcb *volatile *lwip_socket_incoming_array(lwip_socket_obj_t *socket) { + if (socket->incoming.connection.alloc == 0) { + return &socket->incoming.connection.tcp.item; + } else { + return &socket->incoming.connection.tcp.array[0]; + } +} + /*******************************************************************************/ // Callback functions for the lwIP raw API. @@ -381,15 +389,10 @@ STATIC err_t _lwip_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err) { tcp_recv(newpcb, _lwip_tcp_recv_unaccepted); // Search for an empty slot to store the new connection - struct tcp_pcb *volatile *tcp_array; - if (socket->incoming.connection.alloc == 0) { - tcp_array = &socket->incoming.connection.tcp.item; - } else { - tcp_array = socket->incoming.connection.tcp.array; - } - if (tcp_array[socket->incoming.connection.iput] == NULL) { + struct tcp_pcb *volatile *slot = &lwip_socket_incoming_array(socket)[socket->incoming.connection.iput]; + if (*slot == NULL) { // Have an empty slot to store waiting connection - tcp_array[socket->incoming.connection.iput] = newpcb; + *slot = newpcb; if (++socket->incoming.connection.iput >= socket->incoming.connection.alloc) { socket->incoming.connection.iput = 0; } @@ -782,12 +785,7 @@ STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) { } // accept incoming connection - struct tcp_pcb *volatile *incoming_connection; - if (socket->incoming.connection.alloc == 0) { - incoming_connection = &socket->incoming.connection.tcp.item; - } else { - incoming_connection = &socket->incoming.connection.tcp.array[socket->incoming.connection.iget]; - } + struct tcp_pcb *volatile *incoming_connection = &lwip_socket_incoming_array(socket)[socket->incoming.connection.iget]; if (*incoming_connection == NULL) { if (socket->timeout == 0) { mp_raise_OSError(MP_EAGAIN); @@ -1218,10 +1216,8 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ if (flags & MP_STREAM_POLL_RD) { if (socket->state == STATE_LISTENING) { // Listening TCP socket may have one or multiple connections waiting - if ((socket->incoming.connection.alloc == 0 - && socket->incoming.connection.tcp.item != NULL) - || socket->incoming.connection.tcp.array[socket->incoming.connection.iget] != NULL) { - ret |= MP_STREAM_POLL_RD; + if (lwip_socket_incoming_array(socket)[socket->incoming.connection.iget] != NULL) { + ret |= MP_STREAM_POLL_RD; } } else { // Otherwise there is just one slot for incoming data @@ -1292,12 +1288,7 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ } } else { uint8_t alloc = socket->incoming.connection.alloc; - struct tcp_pcb *volatile *tcp_array; - if (alloc == 0) { - tcp_array = &socket->incoming.connection.tcp.item; - } else { - tcp_array = socket->incoming.connection.tcp.array; - } + struct tcp_pcb *volatile *tcp_array = lwip_socket_incoming_array(socket); for (uint8_t i = 0; i < alloc; ++i) { // Deregister callback and abort if (tcp_array[i] != NULL) { From 303f27f6568a8e5ba386a2b31c692548c07a4acf Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 18 Feb 2019 23:20:13 +1100 Subject: [PATCH 0108/1788] esp32/modsocket: Change socket.socket to be socket type rather than fun. To make all ports consistent. Addresses issue #4514. --- ports/esp32/modsocket.c | 58 +++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c index 2bb717fda0..1d7aec5efa 100644 --- a/ports/esp32/modsocket.c +++ b/ports/esp32/modsocket.c @@ -190,6 +190,34 @@ STATIC void _socket_getaddrinfo(const mp_obj_t addrtuple, struct addrinfo **resp } } +STATIC mp_obj_t socket_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, 3, false); + + socket_obj_t *sock = m_new_obj_with_finaliser(socket_obj_t); + sock->base.type = type_in; + 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) { + 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_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; @@ -622,37 +650,11 @@ STATIC const mp_stream_p_t socket_stream_p = { STATIC const mp_obj_type_t socket_type = { { &mp_type_type }, .name = MP_QSTR_socket, + .make_new = socket_make_new, .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; - sock->peer_closed = false; - 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(size_t n_args, const mp_obj_t *args) { // TODO support additional args beyond the first two @@ -703,7 +705,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_socket_initialize_obj, esp_socket_initializ 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_socket), MP_ROM_PTR(&socket_type) }, { MP_ROM_QSTR(MP_QSTR_getaddrinfo), MP_ROM_PTR(&esp_socket_getaddrinfo_obj) }, { MP_ROM_QSTR(MP_QSTR_AF_INET), MP_ROM_INT(AF_INET) }, From 363900be5d964479a345f5e07da769330734886d Mon Sep 17 00:00:00 2001 From: Dave Hylands Date: Wed, 13 Feb 2019 11:41:54 -0800 Subject: [PATCH 0109/1788] stm32/extint: Fix ExtInt to work with non-GPIO pins. --- ports/stm32/extint.c | 83 ++++++++++++++++++++++++++++++-------------- ports/stm32/extint.h | 1 + 2 files changed, 57 insertions(+), 27 deletions(-) diff --git a/ports/stm32/extint.c b/ports/stm32/extint.c index fedb60d139..cdfa1a1e18 100644 --- a/ports/stm32/extint.c +++ b/ports/stm32/extint.c @@ -93,18 +93,24 @@ // 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. -#define EXTI_Mode_Interrupt offsetof(EXTI_TypeDef, IMR1) -#define EXTI_Mode_Event offsetof(EXTI_TypeDef, EMR1) +#define EXTI_Mode_Interrupt offsetof(EXTI_TypeDef, IMR1) +#define EXTI_Mode_Event offsetof(EXTI_TypeDef, EMR1) +#define EXTI_Trigger_Rising offsetof(EXTI_TypeDef, RTSR1) +#define EXTI_Trigger_Falling offsetof(EXTI_TypeDef, FTSR1) #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_Mode_Interrupt offsetof(EXTI_Core_TypeDef, IMR1) +#define EXTI_Mode_Event offsetof(EXTI_Core_TypeDef, EMR1) +#define EXTI_Trigger_Rising offsetof(EXTI_Core_TypeDef, RTSR1) +#define EXTI_Trigger_Falling offsetof(EXTI_Core_TypeDef, FTSR1) #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) +#define EXTI_Mode_Interrupt offsetof(EXTI_TypeDef, IMR) +#define EXTI_Mode_Event offsetof(EXTI_TypeDef, EMR) +#define EXTI_Trigger_Rising offsetof(EXTI_TypeDef, RTSR) +#define EXTI_Trigger_Falling offsetof(EXTI_TypeDef, FTSR) #define EXTI_RTSR EXTI->RTSR #define EXTI_FTSR EXTI->FTSR #endif @@ -210,15 +216,21 @@ uint extint_register(mp_obj_t pin_obj, uint32_t mode, uint32_t pull, mp_obj_t ca pyb_extint_hard_irq[v_line] = true; pyb_extint_callback_arg[v_line] = MP_OBJ_NEW_SMALL_INT(v_line); - mp_hal_gpio_clock_enable(pin->gpio); - GPIO_InitTypeDef exti; - exti.Pin = pin->pin_mask; - exti.Mode = mode; - exti.Pull = pull; - exti.Speed = GPIO_SPEED_FREQ_HIGH; - HAL_GPIO_Init(pin->gpio, &exti); + if (pin == NULL) { + // pin will be NULL for non GPIO EXTI lines + extint_trigger_mode(v_line, mode); + extint_enable(v_line); + } else { + mp_hal_gpio_clock_enable(pin->gpio); + GPIO_InitTypeDef exti; + exti.Pin = pin->pin_mask; + exti.Mode = mode; + exti.Pull = pull; + exti.Speed = GPIO_SPEED_FREQ_HIGH; + HAL_GPIO_Init(pin->gpio, &exti); - // Calling HAL_GPIO_Init does an implicit extint_enable + // Calling HAL_GPIO_Init does an implicit extint_enable + } /* Enable and set NVIC Interrupt to the lowest priority */ NVIC_SetPriority(IRQn_NONNEG(nvic_irq_channel[v_line]), IRQ_PRI_EXTINT); @@ -262,19 +274,7 @@ void extint_register_pin(const pin_obj_t *pin, uint32_t mode, bool hard_irq, mp_ (SYSCFG->EXTICR[line >> 2] & ~(0x0f << (4 * (line & 0x03)))) | ((uint32_t)(GPIO_GET_INDEX(pin->gpio)) << (4 * (line & 0x03))); - // Enable or disable the rising detector - if ((mode & GPIO_MODE_IT_RISING) == GPIO_MODE_IT_RISING) { - EXTI_RTSR |= 1 << line; - } else { - EXTI_RTSR &= ~(1 << line); - } - - // Enable or disable the falling detector - if ((mode & GPIO_MODE_IT_FALLING) == GPIO_MODE_IT_FALLING) { - EXTI_FTSR |= 1 << line; - } else { - EXTI_FTSR &= ~(1 << line); - } + extint_trigger_mode(line, mode); // Configure the NVIC NVIC_SetPriority(IRQn_NONNEG(nvic_irq_channel[line]), IRQ_PRI_EXTINT); @@ -353,6 +353,35 @@ void extint_swint(uint line) { #endif } +void extint_trigger_mode(uint line, uint32_t mode) { + if (line >= EXTI_NUM_VECTORS) { + return; + } + #if defined(STM32F0) || defined(STM32F7) || defined(STM32H7) + // The Cortex-M7 doesn't have bitband support. + mp_uint_t irq_state = disable_irq(); + // Enable or disable the rising detector + if ((mode & GPIO_MODE_IT_RISING) == GPIO_MODE_IT_RISING) { + EXTI_RTSR |= (1 << line); + } else { + EXTI_RTSR &= ~(1 << line); + } + // Enable or disable the falling detector + if ((mode & GPIO_MODE_IT_FALLING) == GPIO_MODE_IT_FALLING) { + EXTI_FTSR |= 1 << line; + } else { + EXTI_FTSR &= ~(1 << line); + } + enable_irq(irq_state); + #else + // Since manipulating FTSR/RTSR is a read-modify-write, and we want this to + // be atomic, we use the bit-band area to just affect the bit we're + // interested in. + EXTI_MODE_BB(EXTI_Trigger_Rising, line) = (mode & GPIO_MODE_IT_RISING) == GPIO_MODE_IT_RISING; + EXTI_MODE_BB(EXTI_Trigger_Falling, line) = (mode & GPIO_MODE_IT_FALLING) == GPIO_MODE_IT_FALLING; + #endif +} + /// \method line() /// Return the line number that the pin is mapped to. STATIC mp_obj_t extint_obj_line(mp_obj_t self_in) { diff --git a/ports/stm32/extint.h b/ports/stm32/extint.h index 7646df731c..924b48a8bf 100644 --- a/ports/stm32/extint.h +++ b/ports/stm32/extint.h @@ -69,6 +69,7 @@ void extint_register_pin(const pin_obj_t *pin, uint32_t mode, bool hard_irq, mp_ void extint_enable(uint line); void extint_disable(uint line); void extint_swint(uint line); +void extint_trigger_mode(uint line, uint32_t mode); void Handle_EXTI_Irq(uint32_t line); From 9441f4b682b29b0a03e68e5e57567a81ce05afa7 Mon Sep 17 00:00:00 2001 From: Dave Hylands Date: Thu, 14 Feb 2019 09:42:44 -0800 Subject: [PATCH 0110/1788] stm32/extint: Fix RTC Alarm/FS USB EXTI constants for L4. --- ports/stm32/extint.c | 5 +++++ ports/stm32/extint.h | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/ports/stm32/extint.c b/ports/stm32/extint.c index cdfa1a1e18..c67caeb798 100644 --- a/ports/stm32/extint.c +++ b/ports/stm32/extint.c @@ -154,8 +154,13 @@ STATIC const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = { #else PVD_IRQn, #endif + #if defined(STM32L4) + OTG_FS_WKUP_IRQn, + RTC_Alarm_IRQn, + #else RTC_Alarm_IRQn, OTG_FS_WKUP_IRQn, + #endif ETH_WKUP_IRQn, OTG_HS_WKUP_IRQn, TAMP_STAMP_IRQn, diff --git a/ports/stm32/extint.h b/ports/stm32/extint.h index 924b48a8bf..abe9597123 100644 --- a/ports/stm32/extint.h +++ b/ports/stm32/extint.h @@ -34,8 +34,13 @@ // Use the following constants for the internal sources: #define EXTI_PVD_OUTPUT (16) +#if defined(STM32L4) +#define EXTI_RTC_ALARM (18) +#define EXTI_USB_OTG_FS_WAKEUP (17) +#else #define EXTI_RTC_ALARM (17) #define EXTI_USB_OTG_FS_WAKEUP (18) +#endif #define EXTI_ETH_WAKEUP (19) #define EXTI_USB_OTG_HS_WAKEUP (20) #if defined(STM32F0) || defined(STM32L4) From 92fec603d0a72e8b962fddca42af075117c36395 Mon Sep 17 00:00:00 2001 From: Dave Hylands Date: Thu, 14 Feb 2019 11:56:02 -0800 Subject: [PATCH 0111/1788] stm32/make-stmconst.py: Improve regex to parse more constants. A few RTC constants weren't being parsed properly due to whitespace differences, and this patch makes certain whitespace optional. Changes made: - allow for no space between /*!< and EXTI, eg for: __IO uint32_t IMR; /*![A-Z][A-Za-z0-9_]+)_(?P([A-Za-z0-9_]+)?)TypeDef;$')), - ('IO reg', re.compile(re_io_reg + r'; +/\*!< ' + re_comment + r', +' + re_addr_offset + r' *\*/')), - ('IO reg array', re.compile(re_io_reg + r'\[(?P[2-8])\]; +/\*!< ' + re_comment + r', +' + re_addr_offset + r'-(0x[0-9A-Z]{2,3}) *\*/')), + ('IO reg', re.compile(re_io_reg + r'; */\*!< *' + re_comment + r', +' + re_addr_offset + r' *\*/')), + ('IO reg array', re.compile(re_io_reg + r'\[(?P[2-8])\]; */\*!< *' + re_comment + r', +' + re_addr_offset + r'-(0x[0-9A-Z]{2,3}) *\*/')), ) def __init__(self, filename): From 3d17d9b57850ba6ddc28c2830bb6642b6b048981 Mon Sep 17 00:00:00 2001 From: Dave Hylands Date: Thu, 14 Feb 2019 12:36:54 -0800 Subject: [PATCH 0112/1788] stm32/extint: Add non-GPIO EXTI IRQ sources for F0. --- ports/stm32/extint.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ports/stm32/extint.c b/ports/stm32/extint.c index c67caeb798..59b20d5bd9 100644 --- a/ports/stm32/extint.c +++ b/ports/stm32/extint.c @@ -144,6 +144,13 @@ STATIC const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = { 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, + PVD_VDDIO2_IRQn, + RTC_IRQn, + 0, // internal USB wakeup event + RTC_IRQn, + RTC_IRQn, + ADC1_COMP_IRQn, + ADC1_COMP_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, From 67b326d97e6363906b9e8dca8b86130bece69d3a Mon Sep 17 00:00:00 2001 From: Dave Hylands Date: Thu, 14 Feb 2019 12:37:30 -0800 Subject: [PATCH 0113/1788] stm32/extint: Remove unused (and incorrect) EXTI defines. --- ports/stm32/extint.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/ports/stm32/extint.h b/ports/stm32/extint.h index abe9597123..d275087c9e 100644 --- a/ports/stm32/extint.h +++ b/ports/stm32/extint.h @@ -59,13 +59,6 @@ #define EXTI_NUM_VECTORS (PYB_EXTI_NUM_VECTORS) -#define EXTI_MODE_INTERRUPT (offsetof(EXTI_TypeDef, IMR)) -#define EXTI_MODE_EVENT (offsetof(EXTI_TypeDef, EMR)) - -#define EXTI_TRIGGER_RISING (offsetof(EXTI_TypeDef, RTSR)) -#define EXTI_TRIGGER_FALLING (offsetof(EXTI_TypeDef, FTSR)) -#define EXTI_TRIGGER_RISING_FALLING (EXTI_TRIGGER_RISING + EXTI_TRIGGER_FALLING) // just different from RISING or FALLING - void extint_init0(void); uint extint_register(mp_obj_t pin_obj, uint32_t mode, uint32_t pull, mp_obj_t callback_obj, bool override_callback_obj); From a270cf280b22a969581a7f1ca1ad6ba071bad299 Mon Sep 17 00:00:00 2001 From: Dave Hylands Date: Thu, 14 Feb 2019 12:38:48 -0800 Subject: [PATCH 0114/1788] stm32/stm32_it: Fix RTC IRQ handler to handle all EXTI IRQs on F0 MCUs. --- ports/stm32/stm32_it.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index 88e7f5bfec..0f2be4c68d 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -509,8 +509,18 @@ void RTC_WKUP_IRQHandler(void) { void RTC_IRQHandler(void) { IRQ_ENTER(RTC_IRQn); - RTC->ISR &= ~RTC_ISR_WUTF; // clear wakeup interrupt flag - Handle_EXTI_Irq(EXTI_RTC_WAKEUP); // clear EXTI flag and execute optional callback + if (RTC->ISR & RTC_ISR_WUTF) { + RTC->ISR &= ~RTC_ISR_WUTF; // clear wakeup interrupt flag + Handle_EXTI_Irq(EXTI_RTC_WAKEUP); // clear EXTI flag and execute optional callback + } + if (RTC->ISR & RTC_ISR_ALRAF) { + RTC->ISR &= ~RTC_ISR_ALRAF; // clear Alarm A flag + Handle_EXTI_Irq(EXTI_RTC_ALARM); // clear EXTI flag and execute optional callback + } + if (RTC->ISR & RTC_ISR_TSF) { + RTC->ISR &= ~RTC_ISR_TSF; // clear timestamp flag + Handle_EXTI_Irq(EXTI_RTC_TIMESTAMP); // clear EXTI flag and execute optional callback + } IRQ_EXIT(RTC_IRQn); } From 2b575418b6c0b97966d77fc1b093c5ed34d92670 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 Feb 2019 23:44:01 +1100 Subject: [PATCH 0115/1788] py/qstr: Evaluate find_qstr only once then pass to Q_GET_HASH macro. Q_GET_HASH may evaluate its argument more than once. --- py/qstr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/py/qstr.c b/py/qstr.c index a06b84f153..e6f86401a0 100644 --- a/py/qstr.c +++ b/py/qstr.c @@ -251,7 +251,8 @@ qstr qstr_from_strn(const char *str, size_t len) { } mp_uint_t qstr_hash(qstr q) { - return Q_GET_HASH(find_qstr(q)); + const byte *qd = find_qstr(q); + return Q_GET_HASH(qd); } size_t qstr_len(qstr q) { From bf352047de5a670b7e3addc3b63ddbb9fa478b48 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 20 Feb 2019 13:06:35 +1100 Subject: [PATCH 0116/1788] py/obj.h: Remove obsolete mp_obj_new_fun_viper() declaration. --- py/obj.h | 1 - 1 file changed, 1 deletion(-) diff --git a/py/obj.h b/py/obj.h index 8fdcfc835a..8ac46039bf 100644 --- a/py/obj.h +++ b/py/obj.h @@ -649,7 +649,6 @@ mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!) mp_obj_t mp_obj_new_fun_bc(mp_obj_t def_args, mp_obj_t def_kw_args, const byte *code, const mp_uint_t *const_table); mp_obj_t mp_obj_new_fun_native(mp_obj_t def_args_in, mp_obj_t def_kw_args, const void *fun_data, const mp_uint_t *const_table); -mp_obj_t mp_obj_new_fun_viper(size_t n_args, void *fun_data, mp_uint_t type_sig); mp_obj_t mp_obj_new_fun_asm(size_t n_args, void *fun_data, mp_uint_t type_sig); mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun); mp_obj_t mp_obj_new_closure(mp_obj_t fun, size_t n_closed, const mp_obj_t *closed); From 7bc71f5446aa4928d05db13dac4eeb819be4b073 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 20 Feb 2019 13:08:42 +1100 Subject: [PATCH 0117/1788] py/objfun: Make fun_data arg of mp_obj_new_fun_asm() a const pointer. --- py/obj.h | 2 +- py/objfun.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/py/obj.h b/py/obj.h index 8ac46039bf..e8575dbd10 100644 --- a/py/obj.h +++ b/py/obj.h @@ -649,7 +649,7 @@ mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!) mp_obj_t mp_obj_new_fun_bc(mp_obj_t def_args, mp_obj_t def_kw_args, const byte *code, const mp_uint_t *const_table); mp_obj_t mp_obj_new_fun_native(mp_obj_t def_args_in, mp_obj_t def_kw_args, const void *fun_data, const mp_uint_t *const_table); -mp_obj_t mp_obj_new_fun_asm(size_t n_args, void *fun_data, mp_uint_t type_sig); +mp_obj_t mp_obj_new_fun_asm(size_t n_args, const void *fun_data, mp_uint_t type_sig); mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun); mp_obj_t mp_obj_new_closure(mp_obj_t fun, size_t n_closed, const mp_obj_t *closed); mp_obj_t mp_obj_new_tuple(size_t n, const mp_obj_t *items); diff --git a/py/objfun.c b/py/objfun.c index 38a1a4c279..159d67e5ea 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -429,7 +429,7 @@ mp_obj_t mp_obj_new_fun_native(mp_obj_t def_args_in, mp_obj_t def_kw_args, const typedef struct _mp_obj_fun_asm_t { mp_obj_base_t base; size_t n_args; - void *fun_data; // GC must be able to trace this pointer + const void *fun_data; // GC must be able to trace this pointer mp_uint_t type_sig; } mp_obj_fun_asm_t; @@ -488,7 +488,7 @@ STATIC mp_obj_t fun_asm_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_arg_check_num(n_args, n_kw, self->n_args, self->n_args, false); - void *fun = MICROPY_MAKE_POINTER_CALLABLE(self->fun_data); + const void *fun = MICROPY_MAKE_POINTER_CALLABLE(self->fun_data); mp_uint_t ret; if (n_args == 0) { @@ -520,7 +520,7 @@ STATIC const mp_obj_type_t mp_type_fun_asm = { .unary_op = mp_generic_unary_op, }; -mp_obj_t mp_obj_new_fun_asm(size_t n_args, void *fun_data, mp_uint_t type_sig) { +mp_obj_t mp_obj_new_fun_asm(size_t n_args, const void *fun_data, mp_uint_t type_sig) { mp_obj_fun_asm_t *o = m_new_obj(mp_obj_fun_asm_t); o->base.type = &mp_type_fun_asm; o->n_args = n_args; From 8ed4a28dae80fb369ceee5ab81fb5302a8a09050 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Tue, 19 Feb 2019 11:11:41 +1100 Subject: [PATCH 0118/1788] stm32/sdram: Increase GPIO speed for SDRAM interface to "very high". Currently all usages of mp_hal_pin_config_alt_static() set the pin speed to "high" (50Mhz). The SDRAM interface typically runs much faster than this so should be set to the maximum pin speed. This commit adds mp_hal_pin_config_alt_static_speed() which allows setting the pin speed along with the other alternate function details. --- ports/stm32/mphalport.h | 4 ++ ports/stm32/pin_static_af.h | 4 ++ ports/stm32/sdram.c | 118 ++++++++++++++++++------------------ 3 files changed, 67 insertions(+), 59 deletions(-) diff --git a/ports/stm32/mphalport.h b/ports/stm32/mphalport.h index 72413c04c7..a60365087e 100644 --- a/ports/stm32/mphalport.h +++ b/ports/stm32/mphalport.h @@ -52,6 +52,10 @@ static inline mp_uint_t mp_hal_ticks_cpu(void) { #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_SPEED_LOW (GPIO_SPEED_FREQ_LOW) +#define MP_HAL_PIN_SPEED_MEDIUM (GPIO_SPEED_FREQ_MEDIUM) +#define MP_HAL_PIN_SPEED_HIGH (GPIO_SPEED_FREQ_HIGH) +#define MP_HAL_PIN_SPEED_VERY_HIGH (GPIO_SPEED_FREQ_VERY_HIGH) #define mp_hal_pin_obj_t const pin_obj_t* #define mp_hal_get_pin_obj(o) pin_find(o) diff --git a/ports/stm32/pin_static_af.h b/ports/stm32/pin_static_af.h index b73944d6f8..f5f4e6fd4d 100644 --- a/ports/stm32/pin_static_af.h +++ b/ports/stm32/pin_static_af.h @@ -41,6 +41,10 @@ #define mp_hal_pin_config_alt_static(pin_obj, mode, pull, fn_type) \ mp_hal_pin_config(pin_obj, mode, pull, fn_type(pin_obj)) /* Overflow Error => alt func not found */ +#define mp_hal_pin_config_alt_static_speed(pin_obj, mode, pull, speed, fn_type) \ + mp_hal_pin_config(pin_obj, mode, pull, fn_type(pin_obj)); /* Overflow Error => alt func not found */ \ + mp_hal_pin_config_speed(pin_obj, speed) + #endif #endif // MICROPY_INCLUDED_STM32_PIN_STATIC_AF_H diff --git a/ports/stm32/sdram.c b/ports/stm32/sdram.c index 6350b1d954..e2b29c56e2 100644 --- a/ports/stm32/sdram.c +++ b/ports/stm32/sdram.c @@ -53,74 +53,74 @@ bool sdram_init(void) { __HAL_RCC_FMC_CLK_ENABLE(); #if defined(MICROPY_HW_FMC_SDCKE0) - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_SDCKE0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_SDCKE0); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_SDNE0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_SDNE0); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_SDCKE0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_SDCKE0); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_SDNE0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_SDNE0); #elif defined(MICROPY_HW_FMC_SDCKE1) - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_SDCKE1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_SDCKE1); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_SDNE1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_SDNE1); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_SDCKE1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_SDCKE1); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_SDNE1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_SDNE1); #endif - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_SDCLK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_SDCLK); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_SDNCAS, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_SDNCAS); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_SDNRAS, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_SDNRAS); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_SDNWE, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_SDNWE); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_BA0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_BA0); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_BA1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_BA1); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_NBL0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_NBL0); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_NBL1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_NBL1); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_SDCLK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_SDCLK); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_SDNCAS, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_SDNCAS); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_SDNRAS, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_SDNRAS); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_SDNWE, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_SDNWE); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_BA0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_BA0); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_BA1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_BA1); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_NBL0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_NBL0); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_NBL1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_NBL1); #ifdef MICROPY_HW_FMC_NBL2 - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_NBL2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_NBL2); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_NBL3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_NBL3); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_NBL2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_NBL2); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_NBL3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_NBL3); #endif - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_A0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_A0); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_A1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_A1); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_A2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_A2); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_A3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_A3); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_A4, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_A4); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_A5, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_A5); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_A6, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_A6); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_A7, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_A7); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_A8, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_A8); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_A9, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_A9); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_A10, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_A10); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_A11, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_A11); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_A0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_A0); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_A1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_A1); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_A2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_A2); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_A3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_A3); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_A4, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_A4); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_A5, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_A5); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_A6, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_A6); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_A7, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_A7); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_A8, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_A8); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_A9, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_A9); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_A10, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_A10); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_A11, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_A11); #ifdef MICROPY_HW_FMC_A12 - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_A12, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_A12); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_A12, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_A12); #endif - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D0); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D1); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D2); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D3); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D4, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D4); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D5, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D5); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D6, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D6); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D7, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D7); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D8, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D8); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D9, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D9); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D10, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D10); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D11, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D11); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D12, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D12); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D13, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D13); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D14, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D14); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D15, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D15); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D0); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D1); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D2); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D3); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D4, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D4); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D5, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D5); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D6, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D6); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D7, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D7); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D8, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D8); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D9, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D9); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D10, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D10); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D11, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D11); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D12, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D12); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D13, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D13); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D14, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D14); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D15, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D15); #ifdef MICROPY_HW_FMC_D16 - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D16, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D16); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D17, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D17); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D18, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D18); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D19, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D19); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D20, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D20); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D21, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D21); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D22, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D22); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D23, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D23); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D24, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D24); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D25, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D25); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D26, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D26); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D27, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D27); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D28, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D28); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D29, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D29); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D30, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D30); - mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D31, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D31); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D16, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D16); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D17, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D17); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D18, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D18); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D19, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D19); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D20, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D20); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D21, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D21); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D22, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D22); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D23, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D23); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D24, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D24); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D25, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D25); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D26, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D26); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D27, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D27); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D28, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D28); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D29, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D29); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D30, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D30); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_D31, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_D31); #endif /* SDRAM device configuration */ From ee3a01f25cb2c5de00f9bd5d915a66c142be2e5f Mon Sep 17 00:00:00 2001 From: Glenn Ruben Bakke Date: Mon, 18 Feb 2019 20:12:35 +0100 Subject: [PATCH 0119/1788] nrf/readme: Update link to nrfjprog download. After new layout of nordicsemi.com the direct links to command line tools (nrfjprog) has changed to become dynamic. This patch removes the old direct links to each specific OS variant and is replaced with one single link to the download landing page instead. --- ports/nrf/README.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/ports/nrf/README.md b/ports/nrf/README.md index 20170e4ae2..32907f2871 100644 --- a/ports/nrf/README.md +++ b/ports/nrf/README.md @@ -114,13 +114,7 @@ Install the necessary tools to flash and debug using Segger: [JLink Download](https://www.segger.com/downloads/jlink#) -[nrfjprog linux-32bit Download](https://www.nordicsemi.com/eng/nordic/Products/nRF52840/nRF5x-Command-Line-Tools-Linux32/58857) - -[nrfjprog linux-64bit Download](https://www.nordicsemi.com/eng/nordic/Products/nRF52840/nRF5x-Command-Line-Tools-Linux64/58852) - -[nrfjprog osx Download](https://www.nordicsemi.com/eng/nordic/Products/nRF52840/nRF5x-Command-Line-Tools-OSX/58855) - -[nrfjprog win32 Download](https://www.nordicsemi.com/eng/nordic/Products/nRF52840/nRF5x-Command-Line-Tools-Win32/58850) +[nrfjprog Download](https://www.nordicsemi.com/Software-and-Tools/Development-Tools/nRF5-Command-Line-Tools/Download#infotabs) note: On Linux it might be required to link SEGGER's `libjlinkarm.so` inside nrfjprog's folder. From 0c6f5bc5293dc7292654f373cbc94c505b069492 Mon Sep 17 00:00:00 2001 From: Glenn Ruben Bakke Date: Tue, 19 Feb 2019 20:48:50 +0100 Subject: [PATCH 0120/1788] nrf/bluetooth: Improve advertisment behavior for nrf52 targets. This patch makes sure that advertisment data is located in persistent static RAM memory throughout the advertisment. Also, setting m_adv_handle to predifined BLE_GAP_ADV_SET_HANDLE_NOT_SET value to indicate first time usage of the handle. Upon first advertisment configuration this will be populated with a handle value returned by the stack (s132/s140). --- ports/nrf/drivers/bluetooth/ble_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/nrf/drivers/bluetooth/ble_drv.c b/ports/nrf/drivers/bluetooth/ble_drv.c index f18a571564..be2f6138ee 100644 --- a/ports/nrf/drivers/bluetooth/ble_drv.c +++ b/ports/nrf/drivers/bluetooth/ble_drv.c @@ -109,7 +109,7 @@ static mp_obj_t mp_gattc_char_data_observer; #define BLE_GAP_ADV_MAX_SIZE 31 #define BLE_DRV_CONN_CONFIG_TAG 1 -static uint8_t m_adv_handle; +static uint8_t m_adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET; static uint8_t m_scan_buffer[BLE_GAP_SCAN_BUFFER_MIN]; nrf_nvic_state_t nrf_nvic_state = {0}; @@ -407,7 +407,7 @@ bool ble_drv_advertise_data(ubluepy_advertise_data_t * p_adv_params) { uint8_t byte_pos = 0; - uint8_t adv_data[BLE_GAP_ADV_MAX_SIZE]; + static uint8_t adv_data[BLE_GAP_ADV_MAX_SIZE]; if (p_adv_params->device_name_len > 0) { ble_gap_conn_sec_mode_t sec_mode; From ca2bb66127f108f2dd29eba4d101957d5c38fb26 Mon Sep 17 00:00:00 2001 From: Glenn Ruben Bakke Date: Tue, 19 Feb 2019 20:51:33 +0100 Subject: [PATCH 0121/1788] nrf/bluetooth: Resolve compilation warning in ble_drv.c. This patch makes sure that the char_data.props is first assigned a value before other flags are OR'd in. Resolves compilation warning on possible unitialized variable. --- ports/nrf/drivers/bluetooth/ble_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/nrf/drivers/bluetooth/ble_drv.c b/ports/nrf/drivers/bluetooth/ble_drv.c index be2f6138ee..ff3c885c15 100644 --- a/ports/nrf/drivers/bluetooth/ble_drv.c +++ b/ports/nrf/drivers/bluetooth/ble_drv.c @@ -1088,7 +1088,7 @@ static void ble_evt_handler(ble_evt_t * p_ble_evt) { char_data.decl_handle = p_char->handle_decl; char_data.value_handle = p_char->handle_value; - char_data.props |= (p_char->char_props.broadcast) ? UBLUEPY_PROP_BROADCAST : 0; + char_data.props = (p_char->char_props.broadcast) ? UBLUEPY_PROP_BROADCAST : 0; char_data.props |= (p_char->char_props.read) ? UBLUEPY_PROP_READ : 0; char_data.props |= (p_char->char_props.write_wo_resp) ? UBLUEPY_PROP_WRITE_WO_RESP : 0; char_data.props |= (p_char->char_props.write) ? UBLUEPY_PROP_WRITE : 0; From 6ca03fe8bd948352cba04a5fa1e308e000611a9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stig=20Bj=C3=B8rlykke?= Date: Wed, 20 Feb 2019 21:17:42 +0100 Subject: [PATCH 0122/1788] nrf/readme: Update make flash command when defining board. Update the "make flash" command sample to include BOARD parameter when building for a specific target board. --- ports/nrf/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/nrf/README.md b/ports/nrf/README.md index 32907f2871..6c77774888 100644 --- a/ports/nrf/README.md +++ b/ports/nrf/README.md @@ -54,7 +54,7 @@ By default, the PCA10040 (nrf52832) is used as compile target. To build and flas Alternatively the target board could be defined: make BOARD=pca10040 - make flash + make BOARD=pca10040 flash ## Compile and Flash with Bluetooth Stack From c72391c4ce7b07e03ac8969815b5e5c8ea626dda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stig=20Bj=C3=B8rlykke?= Date: Wed, 20 Feb 2019 21:29:26 +0100 Subject: [PATCH 0123/1788] nrf/pwm: Remove superfluous NULL in machine_hard_pwm_instances. Remove unneeded NULL entry in machine_hard_pwm_instances[] when not building for NRF52_SERIES. --- ports/nrf/modules/machine/pwm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/ports/nrf/modules/machine/pwm.c b/ports/nrf/modules/machine/pwm.c index e3b40930fd..cf8749302b 100644 --- a/ports/nrf/modules/machine/pwm.c +++ b/ports/nrf/modules/machine/pwm.c @@ -70,8 +70,6 @@ STATIC const nrfx_pwm_t machine_hard_pwm_instances[] = { #if NRF52840 NRFX_PWM_INSTANCE(3), #endif -#else - NULL #endif }; From be41d6d6f95a7dc5874e2c6e13443bcc39d5dea8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 21 Feb 2019 16:22:41 +1100 Subject: [PATCH 0124/1788] tests/basics: Add tests for try-except-else and try-except-else-finally. --- tests/basics/try_else.py | 76 ++++++++++++++++++++++++++ tests/basics/try_else_finally.py | 94 ++++++++++++++++++++++++++++++++ 2 files changed, 170 insertions(+) create mode 100644 tests/basics/try_else.py create mode 100644 tests/basics/try_else_finally.py diff --git a/tests/basics/try_else.py b/tests/basics/try_else.py new file mode 100644 index 0000000000..677707ecd6 --- /dev/null +++ b/tests/basics/try_else.py @@ -0,0 +1,76 @@ +# test try-else statement + +# base case +try: + print(1) +except: + print(2) +else: + print(3) + +# basic case that should skip else +try: + print(1) + raise Exception +except: + print(2) +else: + print(3) + +# uncaught exception should skip else +try: + try: + print(1) + raise ValueError + except TypeError: + print(2) + else: + print(3) +except: + print('caught') + +# nested within outer try +try: + print(1) + try: + print(2) + raise Exception + except: + print(3) + else: + print(4) +except: + print(5) +else: + print(6) + +# nested within outer except, one else should be skipped +try: + print(1) + raise Exception +except: + print(2) + try: + print(3) + except: + print(4) + else: + print(5) +else: + print(6) + +# nested within outer except, both else should be skipped +try: + print(1) + raise Exception +except: + print(2) + try: + print(3) + raise Exception + except: + print(4) + else: + print(5) +else: + print(6) diff --git a/tests/basics/try_else_finally.py b/tests/basics/try_else_finally.py new file mode 100644 index 0000000000..87d98bbdaf --- /dev/null +++ b/tests/basics/try_else_finally.py @@ -0,0 +1,94 @@ +# test try-else-finally statement + +# base case +try: + print(1) +except: + print(2) +else: + print(3) +finally: + print(4) + +# basic case that should skip else +try: + print(1) + raise Exception +except: + print(2) +else: + print(3) +finally: + print(4) + +# uncaught exception should skip else +try: + try: + print(1) + raise ValueError + except TypeError: + print(2) + else: + print(3) + finally: + print(4) +except: + print('caught') + +# nested within outer try +try: + print(1) + try: + print(2) + raise Exception + except: + print(3) + else: + print(4) + finally: + print(5) +except: + print(6) +else: + print(7) +finally: + print(8) + +# nested within outer except, one else should be skipped +try: + print(1) + raise Exception +except: + print(2) + try: + print(3) + except: + print(4) + else: + print(5) + finally: + print(6) +else: + print(7) +finally: + print(8) + +# nested within outer except, both else should be skipped +try: + print(1) + raise Exception +except: + print(2) + try: + print(3) + raise Exception + except: + print(4) + else: + print(5) + finally: + print(6) +else: + print(7) +finally: + print(8) From 7d8c71c222ed7793c99792eb15966504e039dae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Krac=C3=ADk?= Date: Sun, 17 Feb 2019 11:46:23 +0100 Subject: [PATCH 0125/1788] esp32/network_lan: Add arg to constructor to set clock mode for ETH PHY. This optional parameter for network.LAN clock_mode can be used for cases where the clock source is different from the default GPIO0. Fixes #4502. --- ports/esp32/modnetwork.c | 9 +++++++++ ports/esp32/network_lan.c | 16 +++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index 6342f336b0..1048a487f4 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -41,6 +41,7 @@ #include "py/mphal.h" #include "py/mperrno.h" #include "netutils.h" +#include "esp_eth.h" #include "esp_wifi.h" #include "esp_wifi_types.h" #include "esp_log.h" @@ -697,6 +698,14 @@ STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_PHY_LAN8720), MP_ROM_INT(PHY_LAN8720) }, { MP_ROM_QSTR(MP_QSTR_PHY_TLK110), MP_ROM_INT(PHY_TLK110) }, + // ETH Clock modes from ESP-IDF + { MP_ROM_QSTR(MP_QSTR_ETH_CLOCK_GPIO0_IN), MP_ROM_INT(ETH_CLOCK_GPIO0_IN) }, + // Disabled at Aug 22nd 2018, reenabled Jan 28th 2019 in ESP-IDF + // Because we use older SDK, it's currently disabled + //{ MP_ROM_QSTR(MP_QSTR_ETH_CLOCK_GPIO0_OUT), MP_ROM_INT(ETH_CLOCK_GPIO0_OUT) }, + { MP_ROM_QSTR(MP_QSTR_ETH_CLOCK_GPIO16_OUT), MP_ROM_INT(ETH_CLOCK_GPIO16_OUT) }, + { MP_ROM_QSTR(MP_QSTR_ETH_CLOCK_GPIO17_OUT), MP_ROM_INT(ETH_CLOCK_GPIO17_OUT) }, + { MP_ROM_QSTR(MP_QSTR_STAT_IDLE), MP_ROM_INT(STAT_IDLE)}, { MP_ROM_QSTR(MP_QSTR_STAT_CONNECTING), MP_ROM_INT(STAT_CONNECTING)}, { MP_ROM_QSTR(MP_QSTR_STAT_GOT_IP), MP_ROM_INT(STAT_GOT_IP)}, diff --git a/ports/esp32/network_lan.c b/ports/esp32/network_lan.c index fba4de73ab..d2dcbad9ed 100644 --- a/ports/esp32/network_lan.c +++ b/ports/esp32/network_lan.c @@ -94,7 +94,7 @@ STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar return MP_OBJ_FROM_PTR(&lan_obj); } - enum { ARG_id, ARG_mdc, ARG_mdio, ARG_power, ARG_phy_addr, ARG_phy_type }; + enum { ARG_id, ARG_mdc, ARG_mdio, ARG_power, ARG_phy_addr, ARG_phy_type, ARG_clock_mode }; 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 }, @@ -102,6 +102,7 @@ STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar { 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_QSTR_clock_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -125,6 +126,15 @@ STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar mp_raise_ValueError("invalid phy type"); } + if (args[ARG_clock_mode].u_int != -1 && + args[ARG_clock_mode].u_int != ETH_CLOCK_GPIO0_IN && + // Disabled due ESP-IDF (see modnetwork.c note) + //args[ARG_clock_mode].u_int != ETH_CLOCK_GPIO0_OUT && + args[ARG_clock_mode].u_int != ETH_CLOCK_GPIO16_OUT && + args[ARG_clock_mode].u_int != ETH_CLOCK_GPIO17_OUT) { + mp_raise_ValueError("invalid clock mode"); + } + eth_config_t config; switch (args[ARG_phy_type].u_int) { @@ -146,6 +156,10 @@ STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar config.gpio_config = init_lan_rmii; config.tcpip_input = tcpip_adapter_eth_input; + if (args[ARG_clock_mode].u_int != -1) { + config.clock_mode = args[ARG_clock_mode].u_int; + } + if (esp_eth_init(&config) == ESP_OK) { self->active = false; self->initialized = true; From 01c1432e327df91c6850c7f18fa2e18c89e88203 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Krac=C3=ADk?= Date: Sun, 17 Feb 2019 11:47:09 +0100 Subject: [PATCH 0126/1788] esp32/modnetwork: Catch and report Ethernet events. --- ports/esp32/modnetwork.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index 1048a487f4..c09a668dd7 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -190,6 +190,24 @@ static esp_err_t event_handler(void *ctx, system_event_t *event) { } break; } + case SYSTEM_EVENT_GOT_IP6: + ESP_LOGI("network", "Got IPv6"); + break; + case SYSTEM_EVENT_ETH_START: + ESP_LOGI("ethernet", "start"); + break; + case SYSTEM_EVENT_ETH_STOP: + ESP_LOGI("ethernet", "stop"); + break; + case SYSTEM_EVENT_ETH_CONNECTED: + ESP_LOGI("ethernet", "LAN cable connected"); + break; + case SYSTEM_EVENT_ETH_DISCONNECTED: + ESP_LOGI("ethernet", "LAN cable disconnected"); + break; + case SYSTEM_EVENT_ETH_GOT_IP: + ESP_LOGI("ethernet", "Got IP"); + break; default: ESP_LOGI("network", "event %d", event->event_id); break; From 5801a003f055a9db6d569fbb0ffc3018dcaa8c3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Krac=C3=ADk?= Date: Sun, 17 Feb 2019 14:02:02 +0100 Subject: [PATCH 0127/1788] esp32/network_lan: Make power arg to constructor optional. A value of None for this argument is already supported, so the argument can be made optional. --- ports/esp32/network_lan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/esp32/network_lan.c b/ports/esp32/network_lan.c index d2dcbad9ed..10f17ebcf8 100644 --- a/ports/esp32/network_lan.c +++ b/ports/esp32/network_lan.c @@ -99,7 +99,7 @@ STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar { 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_power, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, { 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_QSTR_clock_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, From 4ee2c2a4cd1914a06175919cc2fb6403ad668318 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 25 Feb 2019 14:52:36 +1100 Subject: [PATCH 0128/1788] py: Eliminate warnings about unused arguments when debugging disabled. --- py/compile.c | 2 ++ py/emitnative.c | 1 + py/modio.c | 2 ++ 3 files changed, 5 insertions(+) diff --git a/py/compile.c b/py/compile.c index 5b381e41d5..4aaa68e6ce 100644 --- a/py/compile.c +++ b/py/compile.c @@ -2776,6 +2776,8 @@ STATIC int compile_viper_type_annotation(compiler_t *comp, mp_parse_node_t pn_an #endif STATIC void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_kind_t pn_name, pn_kind_t pn_star, pn_kind_t pn_dbl_star) { + (void)pn_dbl_star; + // check that **kw is last if ((comp->scope_cur->scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) { compile_syntax_error(comp, pn, "invalid syntax"); diff --git a/py/emitnative.c b/py/emitnative.c index a198ffb085..8b7ebe5301 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -2574,6 +2574,7 @@ STATIC void emit_native_return_value(emit_t *emit) { } STATIC void emit_native_raise_varargs(emit_t *emit, mp_uint_t n_args) { + (void)n_args; assert(n_args == 1); vtype_kind_t vtype_exc; emit_pre_pop_reg(emit, &vtype_exc, REG_ARG_1); // arg1 = object to raise diff --git a/py/modio.c b/py/modio.c index b4d033238f..0f4a4326ca 100644 --- a/py/modio.c +++ b/py/modio.c @@ -147,6 +147,7 @@ STATIC mp_uint_t bufwriter_write(mp_obj_t self_in, const void *buf, mp_uint_t si buf = (byte*)buf + rem; size -= rem; mp_uint_t out_sz = mp_stream_write_exactly(self->stream, self->buf, self->alloc, errcode); + (void)out_sz; if (*errcode != 0) { return MP_STREAM_ERROR; } @@ -165,6 +166,7 @@ STATIC mp_obj_t bufwriter_flush(mp_obj_t self_in) { if (self->len != 0) { int err; mp_uint_t out_sz = mp_stream_write_exactly(self->stream, self->buf, self->len, &err); + (void)out_sz; // TODO: try to recover from a case of non-blocking stream, e.g. move // remaining chunk to the beginning of buffer. assert(out_sz == self->len); From 55ff562c70825aa198c62cda73387946803a8805 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 25 Feb 2019 14:53:17 +1100 Subject: [PATCH 0129/1788] unix/modffi: Eliminate unused-argument warning when debugging disabled. --- ports/unix/modffi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/unix/modffi.c b/ports/unix/modffi.c index 4dea887688..0f8551e0a0 100644 --- a/ports/unix/modffi.c +++ b/ports/unix/modffi.c @@ -349,6 +349,7 @@ STATIC void ffifunc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki } STATIC mp_obj_t ffifunc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void)n_kw; mp_obj_ffifunc_t *self = MP_OBJ_TO_PTR(self_in); assert(n_kw == 0); assert(n_args == self->cif.nargs); From 21f9329d5d69516064f0ad77af311ac31a6dd009 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Krac=C3=ADk?= Date: Thu, 21 Feb 2019 22:02:09 +0100 Subject: [PATCH 0130/1788] esp32/modnetwork: Fix wifi.isconnected to return False after disconnect. esp_wifi_connect will return ESP_OK for the normal path of execution which just means the reconnect is started, not that it is actually reconnected. In such a case wifi.isconnected() should return False until the reconnection is complete. After reconnect a GOT_IP event is called and it will change wifi_sta_connected back to True. --- ports/esp32/modnetwork.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index c09a668dd7..3754b293f1 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -169,7 +169,7 @@ static esp_err_t event_handler(void *ctx, system_event_t *event) { } ESP_LOGI("wifi", "STA_DISCONNECTED, reason:%d%s", disconn->reason, message); - bool reconnected = false; + wifi_sta_connected = false; if (wifi_sta_connect_requested) { wifi_mode_t mode; if (esp_wifi_get_mode(&mode) == ESP_OK) { @@ -178,16 +178,10 @@ 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; } case SYSTEM_EVENT_GOT_IP6: From 9521399044e128b0d3692d110c26b1ff6a27330e Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Sun, 24 Feb 2019 00:13:51 +0200 Subject: [PATCH 0131/1788] docs/uos: Document extra requirements on stream objs passed to dupterm. This is only correct for the extmod/uos_dupterm.c implementation however, as e.g cc3200 implementation does the mp_load_method() itself, and anyway requires `read` instead of `readinto`. --- docs/library/uos.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/library/uos.rst b/docs/library/uos.rst index c073f079d7..c7460134b1 100644 --- a/docs/library/uos.rst +++ b/docs/library/uos.rst @@ -115,7 +115,8 @@ Terminal redirection and duplication .. function:: dupterm(stream_object, index=0) Duplicate or switch the MicroPython terminal (the REPL) on the given `stream`-like - object. The *stream_object* argument must implement the ``readinto()`` and + object. The *stream_object* argument must be a native stream object, or derive + from ``uio.IOBase`` and 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. From 75a35448e1dd44a7165de006d6f3ea0c16ac7dd2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 22 Feb 2019 21:53:07 +1100 Subject: [PATCH 0132/1788] stm32/boards/NUCLEO_F767ZI: Fix up comments about HCLK computation. --- ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h index 3f23d77d48..8c7a34339e 100644 --- a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h @@ -16,20 +16,12 @@ #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 -// USB/SDMMC/RNG Clock = VCOClock / PLLQ = 432 MHz / 9 = 48 MHz +// HSE is 8MHz #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 +#define MICROPY_HW_FLASH_LATENCY (FLASH_LATENCY_7) // 210-216 MHz needs 7 wait states // UART config #define MICROPY_HW_UART2_TX (pin_D5) From cc63e19332bb8bf4134ef27116deeb1935ddf365 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 22 Feb 2019 21:53:41 +1100 Subject: [PATCH 0133/1788] stm32/mphalport: Add mp_hal_get_mac() helper function. --- ports/stm32/mphalport.c | 11 +++++++++++ ports/stm32/mphalport.h | 9 +++++++++ 2 files changed, 20 insertions(+) diff --git a/ports/stm32/mphalport.c b/ports/stm32/mphalport.c index 206221721b..9e59eb6138 100644 --- a/ports/stm32/mphalport.c +++ b/ports/stm32/mphalport.c @@ -162,3 +162,14 @@ void mp_hal_pin_config_speed(mp_hal_pin_obj_t pin_obj, uint32_t speed) { uint32_t pin = pin_obj->pin; gpio->OSPEEDR = (gpio->OSPEEDR & ~(3 << (2 * pin))) | (speed << (2 * pin)); } + +MP_WEAK void mp_hal_get_mac(int idx, uint8_t buf[6]) { + // Generate a random locally administered MAC address (LAA) + uint8_t *id = (uint8_t *)MP_HAL_UNIQUE_ID_ADDRESS; + buf[0] = 0x02; // LAA range + buf[1] = (id[11] << 4) | (id[10] & 0xf); + buf[2] = (id[9] << 4) | (id[8] & 0xf); + buf[3] = (id[7] << 4) | (id[6] & 0xf); + buf[4] = id[2]; + buf[5] = (id[0] << 2) | idx; +} diff --git a/ports/stm32/mphalport.h b/ports/stm32/mphalport.h index a60365087e..d828bb9dd4 100644 --- a/ports/stm32/mphalport.h +++ b/ports/stm32/mphalport.h @@ -79,3 +79,12 @@ 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); + +enum { + MP_HAL_MAC_WLAN0 = 0, + MP_HAL_MAC_WLAN1, + MP_HAL_MAC_BDADDR, + MP_HAL_MAC_ETH0, +}; + +void mp_hal_get_mac(int idx, uint8_t buf[6]); From 39ea132e1daf851b962780cf122f41800b9e9a33 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 22 Feb 2019 21:54:58 +1100 Subject: [PATCH 0134/1788] extmod/modlwip: Add concurrency protection macros. Some users of this module may require the LwIP stack to run at an elevated priority, to protect against concurrency issues with processing done by the underlying network interface. Since LwIP doesn't provide such protection it must be done here (the other option is to run LwIP in a separate thread, and use thread protection mechanisms, but that is a more heavyweight solution). --- extmod/modlwip.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index bd952111d6..83104a487f 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -447,9 +447,12 @@ STATIC mp_uint_t lwip_udp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui len = 0xffff; } + MICROPY_PY_LWIP_ENTER + // FIXME: maybe PBUF_ROM? struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); if (p == NULL) { + MICROPY_PY_LWIP_EXIT *_errno = MP_ENOMEM; return -1; } @@ -467,6 +470,8 @@ STATIC mp_uint_t lwip_udp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui pbuf_free(p); + MICROPY_PY_LWIP_EXIT + // udp_sendto can return 1 on occasion for ESP8266 port. It's not known why // but it seems that the send actually goes through without error in this case. // So we treat such cases as a success until further investigation. @@ -505,10 +510,14 @@ STATIC mp_uint_t lwip_udp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_ struct pbuf *p = socket->incoming.pbuf; + MICROPY_PY_LWIP_ENTER + u16_t result = pbuf_copy_partial(p, buf, ((p->tot_len > len) ? len : p->tot_len), 0); pbuf_free(p); socket->incoming.pbuf = NULL; + MICROPY_PY_LWIP_EXIT + return (mp_uint_t) result; } @@ -526,11 +535,14 @@ STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui // Check for any pending errors STREAM_ERROR_CHECK(socket); + MICROPY_PY_LWIP_ENTER + u16_t available = tcp_sndbuf(socket->pcb.tcp); if (available == 0) { // Non-blocking socket if (socket->timeout == 0) { + MICROPY_PY_LWIP_EXIT *_errno = MP_EAGAIN; return MP_STREAM_ERROR; } @@ -543,11 +555,13 @@ STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui // reset) by error callback. // Avoid sending too small packets, so wait until at least 16 bytes available while (socket->state >= STATE_CONNECTED && (available = tcp_sndbuf(socket->pcb.tcp)) < 16) { + MICROPY_PY_LWIP_EXIT if (socket->timeout != -1 && mp_hal_ticks_ms() - start > socket->timeout) { *_errno = MP_ETIMEDOUT; return MP_STREAM_ERROR; } poll_sockets(); + MICROPY_PY_LWIP_REENTER } // While we waited, something could happen @@ -563,6 +577,8 @@ STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui err = tcp_output(socket->pcb.tcp); } + MICROPY_PY_LWIP_EXIT + if (err != ERR_OK) { *_errno = error_lookup_table[-err]; return MP_STREAM_ERROR; @@ -608,6 +624,8 @@ STATIC mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_ } } + MICROPY_PY_LWIP_ENTER + assert(socket->pcb.tcp != NULL); struct pbuf *p = socket->incoming.pbuf; @@ -633,6 +651,8 @@ STATIC mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_ } tcp_recved(socket->pcb.tcp, len); + MICROPY_PY_LWIP_EXIT + return len; } @@ -865,16 +885,21 @@ STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { mp_raise_OSError(MP_EALREADY); } } + // Register our receive callback. + MICROPY_PY_LWIP_ENTER tcp_recv(socket->pcb.tcp, _lwip_tcp_recv); socket->state = STATE_CONNECTING; err = tcp_connect(socket->pcb.tcp, &dest, port, _lwip_tcp_connected); if (err != ERR_OK) { + MICROPY_PY_LWIP_EXIT socket->state = STATE_NEW; mp_raise_OSError(error_lookup_table[-err]); } socket->peer_port = (mp_uint_t)port; memcpy(socket->peer, &dest, sizeof(socket->peer)); + MICROPY_PY_LWIP_EXIT + // And now we wait... if (socket->timeout != -1) { for (mp_uint_t retries = socket->timeout / 100; retries--;) { @@ -1209,6 +1234,8 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in); mp_uint_t ret; + MICROPY_PY_LWIP_ENTER + if (request == MP_STREAM_POLL) { uintptr_t flags = arg; ret = 0; @@ -1259,6 +1286,7 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ bool socket_is_listener = false; if (socket->pcb.tcp == NULL) { + MICROPY_PY_LWIP_EXIT return 0; } @@ -1305,6 +1333,8 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ ret = MP_STREAM_ERROR; } + MICROPY_PY_LWIP_EXIT + return ret; } @@ -1452,7 +1482,10 @@ STATIC mp_obj_t lwip_getaddrinfo(size_t n_args, const mp_obj_t *args) { getaddrinfo_state_t state; state.status = 0; + MICROPY_PY_LWIP_ENTER err_t ret = dns_gethostbyname(host, (ip_addr_t*)&state.ipaddr, lwip_getaddrinfo_cb, &state); + MICROPY_PY_LWIP_EXIT + switch (ret) { case ERR_OK: // cached From b6791ffbbef5ecf7e7d42ee19d87ff3253a44eda Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 22 Feb 2019 22:11:26 +1100 Subject: [PATCH 0135/1788] lib/netutils: Add function to print tracing info for Ethernet frames. --- lib/netutils/netutils.h | 6 ++ lib/netutils/trace.c | 150 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 lib/netutils/trace.c diff --git a/lib/netutils/netutils.h b/lib/netutils/netutils.h index 4befc90db0..9261337858 100644 --- a/lib/netutils/netutils.h +++ b/lib/netutils/netutils.h @@ -29,6 +29,10 @@ #define NETUTILS_IPV4ADDR_BUFSIZE 4 +#define NETUTILS_TRACE_IS_TX (0x0001) +#define NETUTILS_TRACE_PAYLOAD (0x0002) +#define NETUTILS_TRACE_NEWLINE (0x0004) + typedef enum _netutils_endian_t { NETUTILS_LITTLE, NETUTILS_BIG, @@ -47,4 +51,6 @@ void netutils_parse_ipv4_addr(mp_obj_t addr_in, uint8_t *out_ip, netutils_endian // puts IP in out_ip (which must take at least IPADDR_BUF_SIZE bytes). mp_uint_t netutils_parse_inet_addr(mp_obj_t addr_in, uint8_t *out_ip, netutils_endian_t endian); +void netutils_ethernet_trace(const mp_print_t *print, size_t len, const uint8_t *buf, unsigned int flags); + #endif // MICROPY_INCLUDED_LIB_NETUTILS_NETUTILS_H diff --git a/lib/netutils/trace.c b/lib/netutils/trace.c new file mode 100644 index 0000000000..7c79713b32 --- /dev/null +++ b/lib/netutils/trace.c @@ -0,0 +1,150 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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 "lib/netutils/netutils.h" + +static uint32_t get_be16(const uint8_t *buf) { + return buf[0] << 8 | buf[1]; +} + +static uint32_t get_be32(const uint8_t *buf) { + return buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; +} + +static void dump_hex_bytes(const mp_print_t *print, size_t len, const uint8_t *buf) { + for (size_t i = 0; i < len; ++i) { + mp_printf(print, " %02x", buf[i]); + } +} + +static const char *ethertype_str(uint16_t type) { + // A value between 0x0000 - 0x05dc (inclusive) indicates a length, not type + switch (type) { + case 0x0800: return "IPv4"; + case 0x0806: return "ARP"; + case 0x86dd: return "IPv6"; + default: return NULL; + } +} + +void netutils_ethernet_trace(const mp_print_t *print, size_t len, const uint8_t *buf, unsigned int flags) { + mp_printf(print, "[% 8d] ETH%cX len=%u", mp_hal_ticks_ms(), flags & NETUTILS_TRACE_IS_TX ? 'T' : 'R', len); + mp_printf(print, " dst=%02x:%02x:%02x:%02x:%02x:%02x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); + mp_printf(print, " src=%02x:%02x:%02x:%02x:%02x:%02x", buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]); + + const char *ethertype = ethertype_str(buf[12] << 8 | buf[13]); + if (ethertype) { + mp_printf(print, " type=%s", ethertype); + } else { + mp_printf(print, " type=0x%04x", buf[12] << 8 | buf[13]); + } + if (len > 14) { + len -= 14; + buf += 14; + if (buf[-2] == 0x08 && buf[-1] == 0x00 && buf[0] == 0x45) { + // IPv4 packet + len = get_be16(buf + 2); + mp_printf(print, " srcip=%u.%u.%u.%u dstip=%u.%u.%u.%u", + buf[12], buf[13], buf[14], buf[15], + buf[16], buf[17], buf[18], buf[19]); + uint8_t prot = buf[9]; + buf += 20; + len -= 20; + if (prot == 6) { + // TCP packet + uint16_t srcport = get_be16(buf); + uint16_t dstport = get_be16(buf + 2); + uint32_t seqnum = get_be32(buf + 4); + uint32_t acknum = get_be32(buf + 8); + uint16_t dataoff_flags = get_be16(buf + 12); + uint16_t winsz = get_be16(buf + 14); + mp_printf(print, " TCP srcport=%u dstport=%u seqnum=%u acknum=%u dataoff=%u flags=%x winsz=%u", + srcport, dstport, (unsigned)seqnum, (unsigned)acknum, dataoff_flags >> 12, dataoff_flags & 0x1ff, winsz); + buf += 20; + len -= 20; + if (dataoff_flags >> 12 > 5) { + mp_printf(print, " opts="); + size_t opts_len = ((dataoff_flags >> 12) - 5) * 4; + dump_hex_bytes(print, opts_len, buf); + buf += opts_len; + len -= opts_len; + } + } else if (prot == 17) { + // UDP packet + uint16_t srcport = get_be16(buf); + uint16_t dstport = get_be16(buf + 2); + mp_printf(print, " UDP srcport=%u dstport=%u", srcport, dstport); + len = get_be16(buf + 4); + buf += 8; + if ((srcport == 67 && dstport == 68) || (srcport == 68 && dstport == 67)) { + // DHCP + if (srcport == 67) { + mp_printf(print, " DHCPS"); + } else { + mp_printf(print, " DHCPC"); + } + dump_hex_bytes(print, 12 + 16 + 16 + 64, buf); + size_t n = 12 + 16 + 16 + 64 + 128; + len -= n; + buf += n; + mp_printf(print, " opts:"); + switch (buf[6]) { + case 1: mp_printf(print, " DISCOVER"); break; + case 2: mp_printf(print, " OFFER"); break; + case 3: mp_printf(print, " REQUEST"); break; + case 4: mp_printf(print, " DECLINE"); break; + case 5: mp_printf(print, " ACK"); break; + case 6: mp_printf(print, " NACK"); break; + case 7: mp_printf(print, " RELEASE"); break; + case 8: mp_printf(print, " INFORM"); break; + } + } + } else { + // Non-UDP packet + mp_printf(print, " prot=%u", prot); + } + } else if (buf[-2] == 0x86 && buf[-1] == 0xdd && (buf[0] >> 4) == 6) { + // IPv6 packet + uint32_t h = get_be32(buf); + uint16_t l = get_be16(buf + 4); + mp_printf(print, " tclass=%u flow=%u len=%u nexthdr=%u hoplimit=%u", (unsigned)((h >> 20) & 0xff), (unsigned)(h & 0xfffff), l, buf[6], buf[7]); + mp_printf(print, " srcip="); + dump_hex_bytes(print, 16, buf + 8); + mp_printf(print, " dstip="); + dump_hex_bytes(print, 16, buf + 24); + buf += 40; + len -= 40; + } + if (flags & NETUTILS_TRACE_PAYLOAD) { + mp_printf(print, " data="); + dump_hex_bytes(print, len, buf); + } + } + if (flags & NETUTILS_TRACE_NEWLINE) { + mp_printf(print, "\n"); + } +} From c950a1a35db0bee6ee2d1da514021885496c4a45 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 22 Feb 2019 22:20:48 +1100 Subject: [PATCH 0136/1788] stm32/eth: Add low-level Ethernet MAC driver. --- ports/stm32/Makefile | 2 + ports/stm32/eth.c | 613 ++++++++++++++++++++++++++++++++ ports/stm32/eth.h | 39 ++ ports/stm32/lwip_inc/lwipopts.h | 1 + 4 files changed, 655 insertions(+) create mode 100644 ports/stm32/eth.c create mode 100644 ports/stm32/eth.h diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 20a26f2344..f509246682 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -110,6 +110,7 @@ SRC_LIB = $(addprefix lib/,\ oofatfs/option/unicode.c \ mp-readline/readline.c \ netutils/netutils.c \ + netutils/trace.c \ timeutils/timeutils.c \ utils/pyexec.c \ utils/interrupt_char.c \ @@ -240,6 +241,7 @@ SRC_C = \ can.c \ usb.c \ wdt.c \ + eth.c \ gccollect.c \ help.c \ machine_i2c.c \ diff --git a/ports/stm32/eth.c b/ports/stm32/eth.c new file mode 100644 index 0000000000..c3a18bde77 --- /dev/null +++ b/ports/stm32/eth.c @@ -0,0 +1,613 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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/mphal.h" +#include "py/mperrno.h" +#include "lib/netutils/netutils.h" +#include "lwip/etharp.h" +#include "lwip/dns.h" +#include "lwip/dhcp.h" +#include "netif/ethernet.h" +#include "pin_static_af.h" +#include "modnetwork.h" +#include "eth.h" + +#if defined(MICROPY_HW_ETH_MDC) + +// ETH PHY register definitions (for LAN8742) + +#undef PHY_BCR +#define PHY_BCR (0x0000) +#define PHY_BCR_SOFT_RESET (0x8000) +#define PHY_BCR_AUTONEG_EN (0x1000) + +#undef PHY_BSR +#define PHY_BSR (0x0001) +#define PHY_BSR_LINK_STATUS (0x0004) +#define PHY_BSR_AUTONEG_DONE (0x0020) + +#define PHY_SCSR (0x001f) +#define PHY_SCSR_SPEED_Pos (2) +#define PHY_SCSR_SPEED_Msk (7 << PHY_SCSR_SPEED_Pos) +#define PHY_SCSR_SPEED_10HALF (1 << PHY_SCSR_SPEED_Pos) +#define PHY_SCSR_SPEED_10FULL (5 << PHY_SCSR_SPEED_Pos) +#define PHY_SCSR_SPEED_100HALF (2 << PHY_SCSR_SPEED_Pos) +#define PHY_SCSR_SPEED_100FULL (6 << PHY_SCSR_SPEED_Pos) + +// ETH DMA RX and TX descriptor definitions + +#define RX_DESCR_0_OWN_Pos (31) +#define RX_DESCR_0_FL_Pos (16) +#define RX_DESCR_0_FL_Msk (0x3fff << RX_DESCR_0_FL_Pos) +#define RX_DESCR_1_RER_Pos (15) +#define RX_DESCR_1_RCH_Pos (14) +#define RX_DESCR_1_RBS2_Pos (16) +#define RX_DESCR_1_RBS1_Pos (0) + +#define TX_DESCR_0_OWN_Pos (31) +#define TX_DESCR_0_LS_Pos (29) +#define TX_DESCR_0_FS_Pos (28) +#define TX_DESCR_0_DP_Pos (26) +#define TX_DESCR_0_CIC_Pos (22) +#define TX_DESCR_0_TER_Pos (21) +#define TX_DESCR_0_TCH_Pos (20) +#define TX_DESCR_1_TBS1_Pos (0) + +// Configuration values + +#define PHY_INIT_TIMEOUT_MS (10000) + +#define RX_BUF_SIZE (1524) // includes 4-byte CRC at end +#define TX_BUF_SIZE (1524) + +#define RX_BUF_NUM (5) +#define TX_BUF_NUM (5) + +typedef struct _eth_dma_rx_descr_t { + volatile uint32_t rdes0, rdes1, rdes2, rdes3; +} eth_dma_rx_descr_t; + +typedef struct _eth_dma_tx_descr_t { + volatile uint32_t tdes0, tdes1, tdes2, tdes3; +} eth_dma_tx_descr_t; + +typedef struct _eth_dma_t { + eth_dma_rx_descr_t rx_descr[RX_BUF_NUM]; + eth_dma_tx_descr_t tx_descr[TX_BUF_NUM]; + uint8_t rx_buf[RX_BUF_NUM * RX_BUF_SIZE] __attribute__((aligned(4))); + uint8_t tx_buf[TX_BUF_NUM * TX_BUF_SIZE] __attribute__((aligned(4))); + size_t rx_descr_idx; + size_t tx_descr_idx; + uint8_t padding[16384 - 15408]; +} eth_dma_t; + +typedef struct _eth_t { + mod_network_nic_type_t base; + uint32_t trace_flags; + struct netif netif; + struct dhcp dhcp_struct; +} eth_t; + +static eth_dma_t eth_dma __attribute__((aligned(16384))); + +eth_t eth_instance; + +STATIC void eth_mac_deinit(eth_t *self); +STATIC void eth_process_frame(eth_t *self, size_t len, const uint8_t *buf); + +STATIC void eth_phy_write(uint32_t reg, uint32_t val) { + while (ETH->MACMIIAR & ETH_MACMIIAR_MB) { + } + ETH->MACMIIDR = val; + uint32_t ar = ETH->MACMIIAR; + ar = reg << ETH_MACMIIAR_MR_Pos | (ar & ETH_MACMIIAR_CR_Msk) | ETH_MACMIIAR_MW | ETH_MACMIIAR_MB; + ETH->MACMIIAR = ar; + while (ETH->MACMIIAR & ETH_MACMIIAR_MB) { + } +} + +STATIC uint32_t eth_phy_read(uint32_t reg) { + while (ETH->MACMIIAR & ETH_MACMIIAR_MB) { + } + uint32_t ar = ETH->MACMIIAR; + ar = reg << ETH_MACMIIAR_MR_Pos | (ar & ETH_MACMIIAR_CR_Msk) | ETH_MACMIIAR_MB; + ETH->MACMIIAR = ar; + while (ETH->MACMIIAR & ETH_MACMIIAR_MB) { + } + return ETH->MACMIIDR; +} + +STATIC void mpu_config(uint32_t region, uint32_t base_addr, uint32_t size) { + __DMB(); + + // Disable MPU + SCB->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk; + MPU->CTRL = 0; + + // Config MPU region + MPU->RNR = region; + MPU->RBAR = base_addr; + MPU->RASR = + MPU_INSTRUCTION_ACCESS_DISABLE << MPU_RASR_XN_Pos + | MPU_REGION_FULL_ACCESS << MPU_RASR_AP_Pos + | MPU_TEX_LEVEL1 << MPU_RASR_TEX_Pos + | MPU_ACCESS_SHAREABLE << MPU_RASR_S_Pos + | MPU_ACCESS_NOT_CACHEABLE << MPU_RASR_C_Pos + | MPU_ACCESS_NOT_BUFFERABLE << MPU_RASR_B_Pos + | 0x00 << MPU_RASR_SRD_Pos + | size << MPU_RASR_SIZE_Pos + | MPU_REGION_ENABLE << MPU_RASR_ENABLE_Pos; + + // Enable MPU + MPU->CTRL = MPU_PRIVILEGED_DEFAULT | MPU_CTRL_ENABLE_Msk; + SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk; + + __DSB(); + __ISB(); +} + +void eth_init(eth_t *self, int mac_idx) { + mp_hal_get_mac(mac_idx, &self->netif.hwaddr[0]); + self->netif.hwaddr_len = 6; +} + +void eth_set_trace(eth_t *self, uint32_t value) { + self->trace_flags = value; +} + +STATIC int eth_mac_init(eth_t *self) { + // Configure MPU + mpu_config(MPU_REGION_NUMBER0, (uint32_t)ð_dma, MPU_REGION_SIZE_16KB); + + // Configure GPIO + mp_hal_pin_config_alt_static(MICROPY_HW_ETH_MDC, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_MDC); + mp_hal_pin_config_alt_static(MICROPY_HW_ETH_MDIO, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_MDIO); + mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RMII_REF_CLK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_RMII_REF_CLK); + mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RMII_CRS_DV, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_RMII_CRS_DV); + mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RMII_RXD0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_RMII_RXD0); + mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RMII_RXD1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_RMII_RXD1); + mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RMII_TX_EN, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_RMII_TX_EN); + mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RMII_TXD0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_RMII_TXD0); + mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RMII_TXD1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_RMII_TXD1); + + __HAL_RCC_ETH_CLK_ENABLE(); + __HAL_RCC_ETHMAC_FORCE_RESET(); + + // Select RMII interface + __HAL_RCC_SYSCFG_CLK_ENABLE(); + SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL; + + __HAL_RCC_ETHMAC_RELEASE_RESET(); + + __HAL_RCC_ETHMAC_CLK_SLEEP_ENABLE(); + __HAL_RCC_ETHMACTX_CLK_SLEEP_ENABLE(); + __HAL_RCC_ETHMACRX_CLK_SLEEP_ENABLE(); + + // Do a soft reset of the MAC core + ETH->DMABMR = ETH_DMABMR_SR; + mp_hal_delay_ms(2); + + // Wait for soft reset to finish + uint32_t t0 = mp_hal_ticks_ms(); + while (ETH->DMABMR & ETH_DMABMR_SR) { + if (mp_hal_ticks_ms() - t0 > 1000) { + return -MP_ETIMEDOUT; + } + } + + // Set MII clock range + uint32_t hclk = HAL_RCC_GetHCLKFreq(); + uint32_t cr_div; + if (hclk < 35000000) { + cr_div = ETH_MACMIIAR_CR_Div16; + } else if (hclk < 60000000) { + cr_div = ETH_MACMIIAR_CR_Div26; + } else if (hclk < 100000000) { + cr_div = ETH_MACMIIAR_CR_Div42; + } else if (hclk < 150000000) { + cr_div = ETH_MACMIIAR_CR_Div62; + } else { + cr_div = ETH_MACMIIAR_CR_Div102; + } + ETH->MACMIIAR = cr_div; + + // Reset the PHY + eth_phy_write(PHY_BCR, PHY_BCR_SOFT_RESET); + mp_hal_delay_ms(50); + + // Wait for the PHY link to be established + int phy_state = 0; + t0 = mp_hal_ticks_ms(); + while (phy_state != 3) { + if (mp_hal_ticks_ms() - t0 > PHY_INIT_TIMEOUT_MS) { + eth_mac_deinit(self); + return -MP_ETIMEDOUT; + } + uint16_t bcr = eth_phy_read(0); + uint16_t bsr = eth_phy_read(1); + switch (phy_state) { + case 0: + if (!(bcr & PHY_BCR_SOFT_RESET)) { + phy_state = 1; + } + break; + case 1: + if (bsr & PHY_BSR_LINK_STATUS) { + eth_phy_write(PHY_BCR, PHY_BCR_AUTONEG_EN); + phy_state = 2; + } + break; + case 2: + if ((bsr & (PHY_BSR_AUTONEG_DONE | PHY_BSR_LINK_STATUS)) + == (PHY_BSR_AUTONEG_DONE | PHY_BSR_LINK_STATUS)) { + phy_state = 3; + } + break; + } + mp_hal_delay_ms(2); + } + + // Get register with link status + uint16_t phy_scsr = eth_phy_read(PHY_SCSR); + + // Burst mode configuration + ETH->DMABMR = 0; + mp_hal_delay_ms(2); + + // Select DMA interrupts + ETH->DMAIER = + ETH_DMAIER_NISE // enable normal interrupts + | ETH_DMAIER_RIE // enable RX interrupt + ; + + // Configure RX descriptor lists + for (size_t i = 0; i < RX_BUF_NUM; ++i) { + eth_dma.rx_descr[i].rdes0 = 1 << RX_DESCR_0_OWN_Pos; + eth_dma.rx_descr[i].rdes1 = + 1 << RX_DESCR_1_RCH_Pos // chained + | RX_BUF_SIZE << RX_DESCR_1_RBS1_Pos + ; + eth_dma.rx_descr[i].rdes2 = (uint32_t)ð_dma.rx_buf[i * RX_BUF_SIZE]; + eth_dma.rx_descr[i].rdes3 = (uint32_t)ð_dma.rx_descr[(i + 1) % RX_BUF_NUM]; + } + ETH->DMARDLAR = (uint32_t)ð_dma.rx_descr[0]; + eth_dma.rx_descr_idx = 0; + + // Configure TX descriptor lists + for (size_t i = 0; i < TX_BUF_NUM; ++i) { + eth_dma.tx_descr[i].tdes0 = 1 << TX_DESCR_0_TCH_Pos; + eth_dma.tx_descr[i].tdes1 = 0; + eth_dma.tx_descr[i].tdes2 = 0; + eth_dma.tx_descr[i].tdes3 = (uint32_t)ð_dma.tx_descr[(i + 1) % TX_BUF_NUM]; + } + ETH->DMATDLAR = (uint32_t)ð_dma.tx_descr[0]; + eth_dma.tx_descr_idx = 0; + + // Configure DMA + ETH->DMAOMR = + ETH_DMAOMR_RSF // read from RX FIFO after a full frame is written + | ETH_DMAOMR_TSF // transmit when a full frame is in TX FIFO (needed by errata) + ; + mp_hal_delay_ms(2); + + // Select MAC filtering options + ETH->MACFFR = + ETH_MACFFR_RA // pass all frames up + ; + mp_hal_delay_ms(2); + + // Set MAC address + u8_t *mac = &self->netif.hwaddr[0]; + ETH->MACA0HR = mac[5] << 8 | mac[4]; + mp_hal_delay_ms(2); + ETH->MACA0LR = mac[3] << 24 | mac[2] << 16 | mac[1] << 8 | mac[0]; + mp_hal_delay_ms(2); + + // Set main MAC control register + ETH->MACCR = + (phy_scsr & PHY_SCSR_SPEED_Msk) == PHY_SCSR_SPEED_10FULL ? ETH_MACCR_DM + : (phy_scsr & PHY_SCSR_SPEED_Msk) == PHY_SCSR_SPEED_100HALF ? ETH_MACCR_FES + : (phy_scsr & PHY_SCSR_SPEED_Msk) == PHY_SCSR_SPEED_100FULL ? (ETH_MACCR_FES | ETH_MACCR_DM) + : 0 + ; + mp_hal_delay_ms(2); + + // Start MAC layer + ETH->MACCR |= + ETH_MACCR_TE // enable TX + | ETH_MACCR_RE // enable RX + ; + mp_hal_delay_ms(2); + + // Start DMA layer + ETH->DMAOMR |= + ETH_DMAOMR_ST // start TX + | ETH_DMAOMR_SR // start RX + ; + mp_hal_delay_ms(2); + + // Enable interrupts + NVIC_SetPriority(ETH_IRQn, IRQ_PRI_PENDSV); + HAL_NVIC_EnableIRQ(ETH_IRQn); + + return 0; +} + +STATIC void eth_mac_deinit(eth_t *self) { + (void)self; + HAL_NVIC_DisableIRQ(ETH_IRQn); + __HAL_RCC_ETHMAC_FORCE_RESET(); + __HAL_RCC_ETHMAC_RELEASE_RESET(); + __HAL_RCC_ETH_CLK_DISABLE(); +} + +STATIC int eth_tx_buf_get(size_t len, uint8_t **buf) { + if (len > TX_BUF_SIZE) { + return -MP_EINVAL; + } + + // Wait for DMA to release the current TX descriptor (if it has it) + eth_dma_tx_descr_t *tx_descr = ð_dma.tx_descr[eth_dma.tx_descr_idx]; + uint32_t t0 = mp_hal_ticks_ms(); + for (;;) { + if (!(tx_descr->tdes0 & (1 << TX_DESCR_0_OWN_Pos))) { + break; + } + if (mp_hal_ticks_ms() - t0 > 1000) { + return -MP_ETIMEDOUT; + } + } + + // Update TX descriptor with length, buffer pointer and linked list pointer + *buf = ð_dma.tx_buf[eth_dma.tx_descr_idx * TX_BUF_SIZE]; + tx_descr->tdes1 = len << TX_DESCR_1_TBS1_Pos; + tx_descr->tdes2 = (uint32_t)*buf; + tx_descr->tdes3 = (uint32_t)ð_dma.tx_descr[(eth_dma.tx_descr_idx + 1) % TX_BUF_NUM]; + + return 0; +} + +STATIC int eth_tx_buf_send(void) { + // Get TX descriptor and move to next one + eth_dma_tx_descr_t *tx_descr = ð_dma.tx_descr[eth_dma.tx_descr_idx]; + eth_dma.tx_descr_idx = (eth_dma.tx_descr_idx + 1) % TX_BUF_NUM; + + // Schedule to send next outgoing frame + tx_descr->tdes0 = + 1 << TX_DESCR_0_OWN_Pos // owned by DMA + | 1 << TX_DESCR_0_LS_Pos // last segment + | 1 << TX_DESCR_0_FS_Pos // first segment + | 3 << TX_DESCR_0_CIC_Pos // enable all checksums inserted by hardware + | 1 << TX_DESCR_0_TCH_Pos // TX descriptor is chained + ; + + // Notify ETH DMA that there is a new TX descriptor for sending + __DMB(); + if (ETH->DMASR & ETH_DMASR_TBUS) { + ETH->DMASR = ETH_DMASR_TBUS; + ETH->DMATPDR = 0; + } + + return 0; +} + +STATIC void eth_dma_rx_free(void) { + // Get RX descriptor, RX buffer and move to next one + eth_dma_rx_descr_t *rx_descr = ð_dma.rx_descr[eth_dma.rx_descr_idx]; + uint8_t *buf = ð_dma.rx_buf[eth_dma.rx_descr_idx * RX_BUF_SIZE]; + eth_dma.rx_descr_idx = (eth_dma.rx_descr_idx + 1) % RX_BUF_NUM; + + // Schedule to get next incoming frame + rx_descr->rdes1 = + 1 << RX_DESCR_1_RCH_Pos // RX descriptor is chained + | RX_BUF_SIZE << RX_DESCR_1_RBS1_Pos // maximum buffer length + ; + rx_descr->rdes2 = (uint32_t)buf; + rx_descr->rdes3 = (uint32_t)ð_dma.rx_descr[eth_dma.rx_descr_idx]; + rx_descr->rdes0 = 1 << RX_DESCR_0_OWN_Pos; // owned by DMA + + // Notify ETH DMA that there is a new RX descriptor available + __DMB(); + ETH->DMARPDR = 0; +} + +void ETH_IRQHandler(void) { + uint32_t sr = ETH->DMASR; + ETH->DMASR = ETH_DMASR_NIS; + if (sr & ETH_DMASR_RS) { + ETH->DMASR = ETH_DMASR_RS; + for (;;) { + eth_dma_rx_descr_t *rx_descr = ð_dma.rx_descr[eth_dma.rx_descr_idx]; + if (rx_descr->rdes0 & (1 << RX_DESCR_0_OWN_Pos)) { + // No more RX descriptors ready to read + break; + } + + // Get RX buffer containing new frame + size_t len = (rx_descr->rdes0 & RX_DESCR_0_FL_Msk) >> RX_DESCR_0_FL_Pos; + len -= 4; // discard CRC at end + uint8_t *buf = (uint8_t*)rx_descr->rdes2; + + // Process frame + eth_process_frame(ð_instance, len, buf); + eth_dma_rx_free(); + } + } +} + +/*******************************************************************************/ +// ETH-LwIP bindings + +#define TRACE_ASYNC_EV (0x0001) +#define TRACE_ETH_TX (0x0002) +#define TRACE_ETH_RX (0x0004) +#define TRACE_ETH_FULL (0x0008) + +STATIC void eth_trace(eth_t *self, size_t len, const void *data, unsigned int flags) { + if (((flags & NETUTILS_TRACE_IS_TX) && (self->trace_flags & TRACE_ETH_TX)) + || (!(flags & NETUTILS_TRACE_IS_TX) && (self->trace_flags & TRACE_ETH_RX))) { + const uint8_t *buf; + if (len == (size_t)-1) { + // data is a pbuf + const struct pbuf *pbuf = data; + buf = pbuf->payload; + len = pbuf->len; // restricted to print only the first chunk of the pbuf + } else { + // data is actual data buffer + buf = data; + } + if (self->trace_flags & TRACE_ETH_FULL) { + flags |= NETUTILS_TRACE_PAYLOAD; + } + netutils_ethernet_trace(MP_PYTHON_PRINTER, len, buf, flags); + } +} + +STATIC err_t eth_netif_output(struct netif *netif, struct pbuf *p) { + // This function should always be called from a context where PendSV-level IRQs are disabled + + LINK_STATS_INC(link.xmit); + eth_trace(netif->state, (size_t)-1, p, NETUTILS_TRACE_IS_TX | NETUTILS_TRACE_NEWLINE); + + uint8_t *buf; + int ret = eth_tx_buf_get(p->tot_len, &buf); + if (ret == 0) { + pbuf_copy_partial(p, buf, p->tot_len, 0); + ret = eth_tx_buf_send(); + } + + return ret ? ERR_BUF : ERR_OK; +} + +STATIC err_t eth_netif_init(struct netif *netif) { + netif->linkoutput = eth_netif_output; + netif->output = etharp_output; + netif->mtu = 1500; + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP; + // Checksums only need to be checked on incoming frames, not computed on outgoing frames + NETIF_SET_CHECKSUM_CTRL(netif, + NETIF_CHECKSUM_CHECK_IP + | NETIF_CHECKSUM_CHECK_UDP + | NETIF_CHECKSUM_CHECK_TCP + | NETIF_CHECKSUM_CHECK_ICMP + | NETIF_CHECKSUM_CHECK_ICMP6); + return ERR_OK; +} + +STATIC void eth_lwip_init(eth_t *self) { + ip_addr_t ipconfig[4]; + IP4_ADDR(&ipconfig[0], 0, 0, 0, 0); + IP4_ADDR(&ipconfig[2], 192, 168, 0, 1); + IP4_ADDR(&ipconfig[1], 255, 255, 255, 0); + IP4_ADDR(&ipconfig[3], 8, 8, 8, 8); + + MICROPY_PY_LWIP_ENTER + + struct netif *n = &self->netif; + n->name[0] = 'e'; + n->name[1] = '0'; + netif_add(n, &ipconfig[0], &ipconfig[1], &ipconfig[2], self, eth_netif_init, ethernet_input); + netif_set_hostname(n, "MPY"); + netif_set_default(n); + netif_set_up(n); + + dns_setserver(0, &ipconfig[3]); + dhcp_set_struct(n, &self->dhcp_struct); + dhcp_start(n); + + netif_set_link_up(n); + + MICROPY_PY_LWIP_EXIT +} + +STATIC void eth_lwip_deinit(eth_t *self) { + MICROPY_PY_LWIP_ENTER + for (struct netif *netif = netif_list; netif != NULL; netif = netif->next) { + if (netif == &self->netif) { + netif_remove(netif); + netif->ip_addr.addr = 0; + netif->flags = 0; + } + } + MICROPY_PY_LWIP_EXIT +} + +STATIC void eth_process_frame(eth_t *self, size_t len, const uint8_t *buf) { + eth_trace(self, len, buf, NETUTILS_TRACE_NEWLINE); + + struct netif *netif = &self->netif; + if (netif->flags & NETIF_FLAG_LINK_UP) { + struct pbuf *p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); + if (p != NULL) { + pbuf_take(p, buf, len); + if (netif->input(p, netif) != ERR_OK) { + pbuf_free(p); + } + } + } +} + +struct netif *eth_netif(eth_t *self) { + return &self->netif; +} + +int eth_link_status(eth_t *self) { + struct netif *netif = &self->netif; + if ((netif->flags & (NETIF_FLAG_UP | NETIF_FLAG_LINK_UP)) + == (NETIF_FLAG_UP | NETIF_FLAG_LINK_UP)) { + if (netif->ip_addr.addr != 0) { + return 3; // link up + } else { + return 2; // link no-ip; + } + } else { + int s = eth_phy_read(0) | eth_phy_read(0x10) << 16; + if (s == 0) { + return 0; // link down + } else { + return 1; // link join + } + } +} + +int eth_start(eth_t *self) { + eth_lwip_deinit(self); + int ret = eth_mac_init(self); + if (ret < 0) { + return ret; + } + eth_lwip_init(self); + return 0; +} + +int eth_stop(eth_t *self) { + eth_lwip_deinit(self); + eth_mac_deinit(self); + return 0; +} + +#endif // defined(MICROPY_HW_ETH_MDC) diff --git a/ports/stm32/eth.h b/ports/stm32/eth.h new file mode 100644 index 0000000000..fd46c7fa7c --- /dev/null +++ b/ports/stm32/eth.h @@ -0,0 +1,39 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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_ETH_H +#define MICROPY_INCLUDED_STM32_ETH_H + +typedef struct _eth_t eth_t; +extern eth_t eth_instance; + +void eth_init(eth_t *self, int mac_idx); +void eth_set_trace(eth_t *self, uint32_t value); +struct netif *eth_netif(eth_t *self); +int eth_link_status(eth_t *self); +int eth_start(eth_t *self); +int eth_stop(eth_t *self); + +#endif // MICROPY_INCLUDED_STM32_ETH_H diff --git a/ports/stm32/lwip_inc/lwipopts.h b/ports/stm32/lwip_inc/lwipopts.h index b8ab8a2ab0..64ff104f71 100644 --- a/ports/stm32/lwip_inc/lwipopts.h +++ b/ports/stm32/lwip_inc/lwipopts.h @@ -8,6 +8,7 @@ #define MEM_ALIGNMENT 4 #define LWIP_CHKSUM_ALGORITHM 3 +#define LWIP_CHECKSUM_CTRL_PER_NETIF 1 #define LWIP_ARP 1 #define LWIP_ETHERNET 1 From c55709bf29f59a3a82f33975eabf1afac153edb2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 22 Feb 2019 22:24:01 +1100 Subject: [PATCH 0137/1788] stm32/network_lan: Add high-level network.LAN interface to ETH driver. --- ports/stm32/Makefile | 1 + ports/stm32/modnetwork.c | 4 + ports/stm32/modnetwork.h | 1 + ports/stm32/network_lan.c | 164 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 170 insertions(+) create mode 100644 ports/stm32/network_lan.c diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index f509246682..1a75bf0504 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -253,6 +253,7 @@ SRC_C = \ moduos.c \ modutime.c \ modusocket.c \ + network_lan.c \ modnetwork.c \ extint.c \ usrsw.c \ diff --git a/ports/stm32/modnetwork.c b/ports/stm32/modnetwork.c index 4fa3d8c05b..0a0cd0e4a5 100644 --- a/ports/stm32/modnetwork.c +++ b/ports/stm32/modnetwork.c @@ -114,6 +114,10 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(network_route_obj, network_route); STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_network) }, + #if defined(MICROPY_HW_ETH_MDC) + { MP_ROM_QSTR(MP_QSTR_LAN), MP_ROM_PTR(&network_lan_type) }, + #endif + #if MICROPY_PY_WIZNET5K { MP_ROM_QSTR(MP_QSTR_WIZNET5K), MP_ROM_PTR(&mod_network_nic_type_wiznet5k) }, #endif diff --git a/ports/stm32/modnetwork.h b/ports/stm32/modnetwork.h index dd8113ebf5..41a0017dab 100644 --- a/ports/stm32/modnetwork.h +++ b/ports/stm32/modnetwork.h @@ -44,6 +44,7 @@ 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 network_lan_type; extern const mp_obj_type_t mod_network_nic_type_wiznet5k; void mod_network_lwip_poll_wrapper(uint32_t ticks_ms); diff --git a/ports/stm32/network_lan.c b/ports/stm32/network_lan.c new file mode 100644 index 0000000000..8c210802ce --- /dev/null +++ b/ports/stm32/network_lan.c @@ -0,0 +1,164 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/mphal.h" +#include "lwip/netif.h" +#include "modnetwork.h" +#include "eth.h" + +#if defined(MICROPY_HW_ETH_MDC) + +typedef struct _network_lan_obj_t { + mp_obj_base_t base; + eth_t *eth; +} network_lan_obj_t; + +STATIC const network_lan_obj_t network_lan_eth0 = { { &network_lan_type }, ð_instance }; + +STATIC void network_lan_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + network_lan_obj_t *self = MP_OBJ_TO_PTR(self_in); + struct netif *netif = eth_netif(self->eth); + int status = eth_link_status(self->eth); + mp_printf(print, "", + status, + netif->ip_addr.addr & 0xff, + netif->ip_addr.addr >> 8 & 0xff, + netif->ip_addr.addr >> 16 & 0xff, + netif->ip_addr.addr >> 24 + ); +} + +STATIC mp_obj_t network_lan_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, 0, false); + const network_lan_obj_t *self = &network_lan_eth0; + eth_init(self->eth, MP_HAL_MAC_ETH0); + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t network_lan_active(size_t n_args, const mp_obj_t *args) { + network_lan_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args == 1) { + return mp_obj_new_bool(eth_link_status(self->eth)); + } else { + int ret; + if (mp_obj_is_true(args[1])) { + ret = eth_start(self->eth); + } else { + ret = eth_stop(self->eth); + } + if (ret < 0) { + mp_raise_OSError(-ret); + } + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_lan_active_obj, 1, 2, network_lan_active); + +STATIC mp_obj_t network_lan_isconnected(mp_obj_t self_in) { + network_lan_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bool(eth_link_status(self->eth) == 3); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_lan_isconnected_obj, network_lan_isconnected); + +STATIC mp_obj_t network_lan_ifconfig(size_t n_args, const mp_obj_t *args) { + network_lan_obj_t *self = MP_OBJ_TO_PTR(args[0]); + return mod_network_nic_ifconfig(eth_netif(self->eth), n_args - 1, args + 1); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_lan_ifconfig_obj, 1, 2, network_lan_ifconfig); + +STATIC mp_obj_t network_lan_status(size_t n_args, const mp_obj_t *args) { + network_lan_obj_t *self = MP_OBJ_TO_PTR(args[0]); + (void)self; + + if (n_args == 1) { + // No arguments: return link status + return MP_OBJ_NEW_SMALL_INT(eth_link_status(self->eth)); + } + + mp_raise_ValueError("unknown status param"); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_lan_status_obj, 1, 2, network_lan_status); + +STATIC mp_obj_t network_lan_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + network_lan_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: { + return mp_obj_new_bytes(ð_netif(self->eth)->hwaddr[0], 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"); + } + + for (size_t i = 0; i < kwargs->alloc; ++i) { + if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) { + mp_map_elem_t *e = &kwargs->table[i]; + switch (mp_obj_str_get_qstr(e->key)) { + case MP_QSTR_trace: { + eth_set_trace(self->eth, mp_obj_get_int(e->value)); + break; + } + default: + mp_raise_ValueError("unknown config param"); + } + } + } + + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(network_lan_config_obj, 1, network_lan_config); + +STATIC const mp_rom_map_elem_t network_lan_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&network_lan_active_obj) }, + { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&network_lan_isconnected_obj) }, + { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&network_lan_ifconfig_obj) }, + { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&network_lan_status_obj) }, + { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&network_lan_config_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(network_lan_locals_dict, network_lan_locals_dict_table); + +const mp_obj_type_t network_lan_type = { + { &mp_type_type }, + .name = MP_QSTR_LAN, + .print = network_lan_print, + .make_new = network_lan_make_new, + .locals_dict = (mp_obj_dict_t*)&network_lan_locals_dict, +}; + +#endif // defined(MICROPY_HW_ETH_MDC) From 08a24c5f41adab401e51c3b8c4886d8fa91d256f Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 22 Feb 2019 22:24:36 +1100 Subject: [PATCH 0138/1788] stm32/mpconfigport.h: Enable lwIP concurrency protection mechanism. --- ports/stm32/mpconfigport.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 7ae2ac77b0..712697c80e 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -357,6 +357,11 @@ static inline mp_uint_t disable_irq(void) { #define MICROPY_THREAD_YIELD() #endif +// The LwIP interface must run at a raised IRQ priority +#define MICROPY_PY_LWIP_ENTER uint32_t irq_state = raise_irq_pri(IRQ_PRI_PENDSV); +#define MICROPY_PY_LWIP_REENTER irq_state = raise_irq_pri(IRQ_PRI_PENDSV); +#define MICROPY_PY_LWIP_EXIT restore_irq_pri(irq_state); + // We need an implementation of the log2 function which is not a macro #define MP_NEED_LOG2 (1) From ac3e2f380df95cf48228f2314b8d0bcd76855f50 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 22 Feb 2019 22:25:06 +1100 Subject: [PATCH 0139/1788] stm32/modnetwork: Don't call NIC callback if it's NULL. --- ports/stm32/modnetwork.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ports/stm32/modnetwork.c b/ports/stm32/modnetwork.c index 0a0cd0e4a5..ea43f75573 100644 --- a/ports/stm32/modnetwork.c +++ b/ports/stm32/modnetwork.c @@ -57,7 +57,9 @@ STATIC void pyb_lwip_poll(void) { 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); + if (nic->poll_callback) { + nic->poll_callback(nic, netif); + } } } // Run the lwIP internal updates From 8daec241684b3c3fed7effb032c0971a7c022013 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 22 Feb 2019 22:26:54 +1100 Subject: [PATCH 0140/1788] stm32/boards/NUCLEO_F767ZI: Enable lwIP and Ethernet peripheral. --- ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h | 13 +++++++++++++ ports/stm32/boards/NUCLEO_F767ZI/pins.csv | 9 +++++++++ 2 files changed, 22 insertions(+) diff --git a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h index 8c7a34339e..e3f255de4d 100644 --- a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h @@ -6,6 +6,8 @@ #define MICROPY_HW_BOARD_NAME "NUCLEO-F767ZI" #define MICROPY_HW_MCU_NAME "STM32F767" +#define MICROPY_PY_LWIP (1) + #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_ENABLE_RNG (1) @@ -70,3 +72,14 @@ void NUCLEO_F767ZI_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) + +// Ethernet via RMII +#define MICROPY_HW_ETH_MDC (pin_C1) +#define MICROPY_HW_ETH_MDIO (pin_A2) +#define MICROPY_HW_ETH_RMII_REF_CLK (pin_A1) +#define MICROPY_HW_ETH_RMII_CRS_DV (pin_A7) +#define MICROPY_HW_ETH_RMII_RXD0 (pin_C4) +#define MICROPY_HW_ETH_RMII_RXD1 (pin_C5) +#define MICROPY_HW_ETH_RMII_TX_EN (pin_G11) +#define MICROPY_HW_ETH_RMII_TXD0 (pin_G13) +#define MICROPY_HW_ETH_RMII_TXD1 (pin_B13) diff --git a/ports/stm32/boards/NUCLEO_F767ZI/pins.csv b/ports/stm32/boards/NUCLEO_F767ZI/pins.csv index 3cae615dab..d84f8e9d19 100644 --- a/ports/stm32/boards/NUCLEO_F767ZI/pins.csv +++ b/ports/stm32/boards/NUCLEO_F767ZI/pins.csv @@ -70,3 +70,12 @@ UART6_RX,PG9 SPI_B_NSS,PA4 SPI_B_SCK,PB3 SPI_B_MOSI,PB5 +ETH_MDC,PC1 +ETH_MDIO,PA2 +ETH_RMII_REF_CLK,PA1 +ETH_RMII_CRS_DV,PA7 +ETH_RMII_RXD0,PC4 +ETH_RMII_RXD1,PC5 +ETH_RMII_TX_EN,PG11 +ETH_RMII_TXD0,PG13 +ETH_RMII_TXD1,PB13 From b3513f54d344b431c2975b2ece992ee2b6a5a7d6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 22 Feb 2019 22:27:24 +1100 Subject: [PATCH 0141/1788] stm32/boards/STM32F7DISC: Enable lwIP and Ethernet peripheral. --- ports/stm32/boards/STM32F7DISC/mpconfigboard.h | 14 ++++++++++++++ ports/stm32/boards/STM32F7DISC/pins.csv | 10 ++++++++++ 2 files changed, 24 insertions(+) diff --git a/ports/stm32/boards/STM32F7DISC/mpconfigboard.h b/ports/stm32/boards/STM32F7DISC/mpconfigboard.h index 792206c400..ff135b8a75 100644 --- a/ports/stm32/boards/STM32F7DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F7DISC/mpconfigboard.h @@ -1,6 +1,8 @@ #define MICROPY_HW_BOARD_NAME "F7DISC" #define MICROPY_HW_MCU_NAME "STM32F746" +#define MICROPY_PY_LWIP (1) + #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_HAS_SDCARD (1) @@ -81,6 +83,18 @@ void STM32F7DISC_board_early_init(void); /*#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_J12)*/ #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) +// Ethernet via RMII +#define MICROPY_HW_ETH_MDC (pin_C1) +#define MICROPY_HW_ETH_MDIO (pin_A2) +#define MICROPY_HW_ETH_RMII_REF_CLK (pin_A1) +#define MICROPY_HW_ETH_RMII_CRS_DV (pin_A7) +#define MICROPY_HW_ETH_RMII_RXD0 (pin_C4) +#define MICROPY_HW_ETH_RMII_RXD1 (pin_C5) +#define MICROPY_HW_ETH_RMII_RXER (pin_G2) +#define MICROPY_HW_ETH_RMII_TX_EN (pin_G11) +#define MICROPY_HW_ETH_RMII_TXD0 (pin_G13) +#define MICROPY_HW_ETH_RMII_TXD1 (pin_G14) + // SDRAM #define MICROPY_HW_SDRAM_SIZE (64 / 8 * 1024 * 1024) // 64 Mbit #define MICROPY_HW_SDRAM_STARTUP_TEST (1) diff --git a/ports/stm32/boards/STM32F7DISC/pins.csv b/ports/stm32/boards/STM32F7DISC/pins.csv index dfafe67f52..99fa969322 100644 --- a/ports/stm32/boards/STM32F7DISC/pins.csv +++ b/ports/stm32/boards/STM32F7DISC/pins.csv @@ -53,6 +53,16 @@ VCP_TX,PA9 VCP_RX,PB7 CAN_TX,PB13 CAN_RX,PB12 +ETH_MDC,PC1 +ETH_MDIO,PA2 +ETH_RMII_REF_CLK,PA1 +ETH_RMII_CRS_DV,PA7 +ETH_RMII_RXD0,PC4 +ETH_RMII_RXD1,PC5 +ETH_RMII_RXER,PG2 +ETH_RMII_TX_EN,PG11 +ETH_RMII_TXD0,PG13 +ETH_RMII_TXD1,PG14 SDRAM_SDCKE0,PC3 SDRAM_SDNE0,PH3 SDRAM_SDCLK,PG8 From ed0a5306140014b87711140aa8c6e2d229a4e46e Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 22 Feb 2019 22:27:48 +1100 Subject: [PATCH 0142/1788] stm32/boards/STM32F769DISC: Enable lwIP and Ethernet peripheral. --- ports/stm32/boards/STM32F769DISC/mpconfigboard.h | 13 +++++++++++++ ports/stm32/boards/STM32F769DISC/pins.csv | 9 +++++++++ 2 files changed, 22 insertions(+) diff --git a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h index 4f41a81f9e..fac7c98fd8 100644 --- a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h @@ -5,6 +5,8 @@ #define MICROPY_HW_BOARD_NAME "F769DISC" #define MICROPY_HW_MCU_NAME "STM32F769" +#define MICROPY_PY_LWIP (1) + #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_HAS_SDCARD (1) @@ -76,6 +78,17 @@ // USB config (CN15 - USB OTG HS with external PHY) #define MICROPY_HW_USB_HS (1) +// Ethernet via RMII +#define MICROPY_HW_ETH_MDC (pin_C1) +#define MICROPY_HW_ETH_MDIO (pin_A2) +#define MICROPY_HW_ETH_RMII_REF_CLK (pin_A1) +#define MICROPY_HW_ETH_RMII_CRS_DV (pin_A7) +#define MICROPY_HW_ETH_RMII_RXD0 (pin_C4) +#define MICROPY_HW_ETH_RMII_RXD1 (pin_C5) +#define MICROPY_HW_ETH_RMII_TX_EN (pin_G11) +#define MICROPY_HW_ETH_RMII_TXD0 (pin_G13) +#define MICROPY_HW_ETH_RMII_TXD1 (pin_G14) + #if 0 // Optional SDRAM configuration; requires SYSCLK <= 200MHz #define MICROPY_HW_SDRAM_SIZE (128 * 1024 * 1024 / 8) // 128 Mbit diff --git a/ports/stm32/boards/STM32F769DISC/pins.csv b/ports/stm32/boards/STM32F769DISC/pins.csv index f587d44c14..2dcc374419 100644 --- a/ports/stm32/boards/STM32F769DISC/pins.csv +++ b/ports/stm32/boards/STM32F769DISC/pins.csv @@ -69,6 +69,15 @@ UART5_TX,PC12 UART5_RX,PD2 CAN2_TX,PB13 CAN2_RX,PB12 +ETH_REF_CLK,PA1 +ETH_MDIO,PA2 +ETH_CRS_DV,PA7 +ETH_MDC,PC1 +ETH_RXD0,PC4 +ETH_RXD1,PC5 +ETH_TX_EN,PG11 +ETH_TXD0,PG13 +ETH_TXD1,PG14 FMC_SDCKE0,PH2 FMC_SDNE0,PH3 FMC_SDCLK,PG8 From 823b31e5287ee96c96620dac81cfeafc889a69fd Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 25 Feb 2019 16:45:53 +1100 Subject: [PATCH 0143/1788] stm32/boards/NUCLEO_F429ZI: Enable lwIP and Ethernet peripheral. --- ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h | 13 +++++++++++++ ports/stm32/boards/NUCLEO_F429ZI/pins.csv | 9 +++++++++ 2 files changed, 22 insertions(+) diff --git a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h index 17883a1920..3d58743556 100644 --- a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h @@ -1,6 +1,8 @@ #define MICROPY_HW_BOARD_NAME "NUCLEO-F429ZI" #define MICROPY_HW_MCU_NAME "STM32F429" +#define MICROPY_PY_LWIP (1) + #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_ENABLE_RNG (1) @@ -81,3 +83,14 @@ #define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) + +// Ethernet via RMII +#define MICROPY_HW_ETH_MDC (pin_C1) +#define MICROPY_HW_ETH_MDIO (pin_A2) +#define MICROPY_HW_ETH_RMII_REF_CLK (pin_A1) +#define MICROPY_HW_ETH_RMII_CRS_DV (pin_A7) +#define MICROPY_HW_ETH_RMII_RXD0 (pin_C4) +#define MICROPY_HW_ETH_RMII_RXD1 (pin_C5) +#define MICROPY_HW_ETH_RMII_TX_EN (pin_G11) +#define MICROPY_HW_ETH_RMII_TXD0 (pin_G13) +#define MICROPY_HW_ETH_RMII_TXD1 (pin_B13) diff --git a/ports/stm32/boards/NUCLEO_F429ZI/pins.csv b/ports/stm32/boards/NUCLEO_F429ZI/pins.csv index 8a892d3c2f..c8fe3355d3 100644 --- a/ports/stm32/boards/NUCLEO_F429ZI/pins.csv +++ b/ports/stm32/boards/NUCLEO_F429ZI/pins.csv @@ -115,3 +115,12 @@ PG2,PG2 SW,PA0 LED_GREEN,PG13 LED_RED,PG14 +ETH_MDC,PC1 +ETH_MDIO,PA2 +ETH_RMII_REF_CLK,PA1 +ETH_RMII_CRS_DV,PA7 +ETH_RMII_RXD0,PC4 +ETH_RMII_RXD1,PC5 +ETH_RMII_TX_EN,PG11 +ETH_RMII_TXD0,PG13 +ETH_RMII_TXD1,PB13 From 12ce9f268909435b49f558d1d3c15ad7591d6fe8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 26 Feb 2019 13:47:14 +1100 Subject: [PATCH 0144/1788] py/compile: Fix handling of unwinding BaseException in async with. All exceptions that unwind through the async-with must be caught and BaseException is the top-level class, which includes Exception and others. Fixes issue #4552. --- py/compile.c | 2 +- tests/basics/async_with.py | 10 ++++++++++ tests/basics/async_with.py.exp | 3 +++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/py/compile.c b/py/compile.c index 4aaa68e6ce..e660e668c4 100644 --- a/py/compile.c +++ b/py/compile.c @@ -1830,7 +1830,7 @@ STATIC void compile_async_with_stmt_helper(compiler_t *comp, int n, mp_parse_nod // Detect if TOS an exception or not EMIT(dup_top); - EMIT_LOAD_GLOBAL(MP_QSTR_Exception); + EMIT_LOAD_GLOBAL(MP_QSTR_BaseException); EMIT_ARG(binary_op, MP_BINARY_OP_EXCEPTION_MATCH); EMIT_ARG(pop_jump_if, false, l_ret_unwind_jump); // if not an exception then we have case 3 diff --git a/tests/basics/async_with.py b/tests/basics/async_with.py index 5af0c5d955..f7774055cf 100644 --- a/tests/basics/async_with.py +++ b/tests/basics/async_with.py @@ -27,3 +27,13 @@ try: o.send(None) except ValueError: print('ValueError') + +# test raising BaseException to make sure it is handled by the async-with +async def h(): + async with AContext(): + raise BaseException +o = h() +try: + o.send(None) +except BaseException: + print('BaseException') diff --git a/tests/basics/async_with.py.exp b/tests/basics/async_with.py.exp index d00b18c969..6bbf84cb4b 100644 --- a/tests/basics/async_with.py.exp +++ b/tests/basics/async_with.py.exp @@ -6,3 +6,6 @@ enter 1 exit error ValueError +enter +exit +BaseException From ed1a88e26380de240f9018984d4291ba57a2f52a Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 27 Feb 2019 10:27:56 +1100 Subject: [PATCH 0145/1788] extmod/modlwip: Don't require a port to define concurrency macros. --- extmod/modlwip.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index 83104a487f..1b8caa8944 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -69,6 +69,13 @@ #define ip_reset_option(pcb, opt) ((pcb)->so_options &= ~(opt)) #endif +// A port can define these hooks to provide concurrency protection +#ifndef MICROPY_PY_LWIP_ENTER +#define MICROPY_PY_LWIP_ENTER +#define MICROPY_PY_LWIP_REENTER +#define MICROPY_PY_LWIP_EXIT +#endif + #ifdef MICROPY_PY_LWIP_SLIP #include "netif/slipif.h" #include "lwip/sio.h" From 9b2a97a903f0841a75947d86d49f0056d43f81b0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 28 Feb 2019 15:30:48 +1100 Subject: [PATCH 0146/1788] extmod/modwebrepl: Fix logic to handle a put of file of size 0. Fixes issue #4499. --- extmod/modwebrepl.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/extmod/modwebrepl.c b/extmod/modwebrepl.c index bf0c1654ba..c9ef774340 100644 --- a/extmod/modwebrepl.c +++ b/extmod/modwebrepl.c @@ -108,6 +108,15 @@ STATIC mp_obj_t webrepl_make_new(const mp_obj_type_t *type, size_t n_args, size_ return o; } +STATIC void check_file_op_finished(mp_obj_webrepl_t *self) { + if (self->data_to_recv == 0) { + mp_stream_close(self->cur_file); + self->hdr_to_recv = sizeof(struct webrepl_file); + DEBUG_printf("webrepl: Finished file operation %d\n", self->hdr.type); + write_webrepl_resp(self->sock, 0); + } +} + STATIC int write_file_chunk(mp_obj_webrepl_t *self) { const mp_stream_p_t *file_stream = mp_get_stream(self->cur_file); byte readbuf[2 + 256]; @@ -160,6 +169,7 @@ STATIC void handle_op(mp_obj_webrepl_t *self) { if (self->hdr.type == PUT_FILE) { self->data_to_recv = self->hdr.size; + check_file_op_finished(self); } else if (self->hdr.type == GET_FILE) { self->data_to_recv = 1; } @@ -266,12 +276,7 @@ STATIC mp_uint_t _webrepl_read(mp_obj_t self_in, void *buf, mp_uint_t size, int } } - if (self->data_to_recv == 0) { - mp_stream_close(self->cur_file); - self->hdr_to_recv = sizeof(struct webrepl_file); - DEBUG_printf("webrepl: Finished file operation %d\n", self->hdr.type); - write_webrepl_resp(self->sock, 0); - } + check_file_op_finished(self); #ifdef MICROPY_PY_WEBREPL_DELAY // Some platforms may have broken drivers and easily gets From 8ce22662feadeb6b564f1087134346cb287251f0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 28 Feb 2019 15:44:37 +1100 Subject: [PATCH 0147/1788] esp8266/modmachine: Call ets_event_poll after waiti in machine.idle. Because "waiti 0" may have waited for a while (eg 500ms) and the internal WDT may need to be fed immediately. Fixes issue #4459. --- ports/esp8266/modmachine.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/esp8266/modmachine.c b/ports/esp8266/modmachine.c index 8c39051613..58368b8f0b 100644 --- a/ports/esp8266/modmachine.c +++ b/ports/esp8266/modmachine.c @@ -92,6 +92,7 @@ STATIC mp_obj_t machine_idle(void) { uint32_t t = mp_hal_ticks_cpu(); asm("waiti 0"); t = mp_hal_ticks_cpu() - t; + ets_event_poll(); // handle any events after possibly a long wait (eg feed WDT) return MP_OBJ_NEW_SMALL_INT(t); } STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_idle_obj, machine_idle); From 0779693c23fcc55993a06e4e0adf30a3d41f90f5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 27 Feb 2019 00:10:04 +1100 Subject: [PATCH 0148/1788] py/compile: Add optimisation to compile OrderedDict inplace. This optimisation eliminates the need to create a temporary normal dict. The optimisation is enabled via MICROPY_COMP_CONST_LITERAL which is enabled by default (although only has an effect if OrderdDict is enabled). Thanks to @pfalcon for the initial idea and implementation. --- py/compile.c | 33 +++++++++++++++++++++++++++++---- py/mpconfig.h | 5 +++++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/py/compile.c b/py/compile.c index e660e668c4..42222528e2 100644 --- a/py/compile.c +++ b/py/compile.c @@ -164,6 +164,7 @@ STATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, const cha STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_arglist, bool is_method_call, int n_positional_extra); STATIC void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_kind_t kind); +STATIC void compile_atom_brace_helper(compiler_t *comp, mp_parse_node_struct_t *pns, bool create_map); STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn); STATIC uint comp_next_label(compiler_t *comp) { @@ -2247,6 +2248,20 @@ STATIC void compile_atom_expr_normal(compiler_t *comp, mp_parse_node_struct_t *p EMIT_ARG(call_function, 2, 0, 0); i = 1; } + + #if MICROPY_COMP_CONST_LITERAL && MICROPY_PY_COLLECTIONS_ORDEREDDICT + // handle special OrderedDict constructor + } else if (MP_PARSE_NODE_IS_ID(pns->nodes[0]) + && MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]) == MP_QSTR_OrderedDict + && MP_PARSE_NODE_STRUCT_KIND(pns_trail[0]) == PN_trailer_paren + && MP_PARSE_NODE_IS_STRUCT_KIND(pns_trail[0]->nodes[0], PN_atom_brace)) { + // at this point we have matched "OrderedDict({...})" + + EMIT_ARG(call_function, 0, 0, 0); + mp_parse_node_struct_t *pns_dict = (mp_parse_node_struct_t*)pns_trail[0]->nodes[0]; + compile_atom_brace_helper(comp, pns_dict, false); + i = 1; + #endif } // compile the remaining trailers @@ -2455,16 +2470,20 @@ STATIC void compile_atom_bracket(compiler_t *comp, mp_parse_node_struct_t *pns) } } -STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) { +STATIC void compile_atom_brace_helper(compiler_t *comp, mp_parse_node_struct_t *pns, bool create_map) { mp_parse_node_t pn = pns->nodes[0]; if (MP_PARSE_NODE_IS_NULL(pn)) { // empty dict - EMIT_ARG(build, 0, MP_EMIT_BUILD_MAP); + if (create_map) { + 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, 1, MP_EMIT_BUILD_MAP); + if (create_map) { + 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) { @@ -2481,7 +2500,9 @@ 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, 1 + n, MP_EMIT_BUILD_MAP); + if (create_map) { + EMIT_ARG(build, 1 + n, MP_EMIT_BUILD_MAP); + } compile_node(comp, pns->nodes[0]); EMIT(store_map); is_dict = true; @@ -2551,6 +2572,10 @@ STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) { } } +STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) { + compile_atom_brace_helper(comp, pns, true); +} + STATIC void compile_trailer_paren(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_trailer_paren_helper(comp, pns->nodes[0], false, 0); } diff --git a/py/mpconfig.h b/py/mpconfig.h index 47638fb0a4..c4b62dd847 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -356,6 +356,11 @@ #define MICROPY_COMP_CONST_FOLDING (1) #endif +// Whether to enable optimisations for constant literals, eg OrderedDict +#ifndef MICROPY_COMP_CONST_LITERAL +#define MICROPY_COMP_CONST_LITERAL (1) +#endif + // Whether to enable lookup of constants in modules; eg module.CONST #ifndef MICROPY_COMP_MODULE_CONST #define MICROPY_COMP_MODULE_CONST (0) From 47e551ba59b1bb8393b649b4a5f51f1c83d889b6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 1 Mar 2019 15:21:06 +1100 Subject: [PATCH 0149/1788] cc3200/mpconfigport.h: Disable compiler optimisation of OrderedDict. This port would rather keep the code size as RAM. --- ports/cc3200/mpconfigport.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/cc3200/mpconfigport.h b/ports/cc3200/mpconfigport.h index b1c68a2dc3..17de4a2f65 100644 --- a/ports/cc3200/mpconfigport.h +++ b/ports/cc3200/mpconfigport.h @@ -39,6 +39,7 @@ #define MICROPY_PERSISTENT_CODE_LOAD (1) #define MICROPY_EMIT_THUMB (0) #define MICROPY_EMIT_INLINE_THUMB (0) +#define MICROPY_COMP_CONST_LITERAL (0) #define MICROPY_COMP_MODULE_CONST (1) #define MICROPY_ENABLE_GC (1) #define MICROPY_ENABLE_FINALISER (1) From f8f2724297b2c3e87e074feddfac26f3ce46ae92 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 1 Mar 2019 16:15:14 +1100 Subject: [PATCH 0150/1788] stm32/qspi: Enable sample shift and disable timeout counter. This makes the QSPI more robust, in particular the timeout counter should not be used with memory mapped mode (see F7 errata). --- ports/stm32/qspi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ports/stm32/qspi.c b/ports/stm32/qspi.c index 986206891c..469858c683 100644 --- a/ports/stm32/qspi.c +++ b/ports/stm32/qspi.c @@ -55,8 +55,8 @@ void qspi_init(void) { #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_SSHIFT_Pos // do sample shift + | 0 << QUADSPI_CR_TCEN_Pos // timeout counter disabled (see F7 errata) | 1 << QUADSPI_CR_EN_Pos // enable the peripheral ; @@ -71,7 +71,6 @@ 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 From 2d644ac45530bac21785fddbd9efa3466204ff26 Mon Sep 17 00:00:00 2001 From: Tom Collins Date: Fri, 1 Mar 2019 19:57:07 -0500 Subject: [PATCH 0151/1788] py/objexcept: Fix hash of exc str created in mp_obj_new_exception_msg. --- py/objexcept.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/objexcept.c b/py/objexcept.c index 5899b3427f..d9258f9b5f 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -348,9 +348,9 @@ mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg // Create the string object and call mp_obj_exception_make_new to create the exception o_str->base.type = &mp_type_str; - o_str->hash = qstr_compute_hash(o_str->data, o_str->len); o_str->len = strlen(msg); o_str->data = (const byte*)msg; + o_str->hash = qstr_compute_hash(o_str->data, o_str->len); mp_obj_t arg = MP_OBJ_FROM_PTR(o_str); return mp_obj_exception_make_new(exc_type, 1, 0, &arg); } From c8bbf2c170760625862666ea2e7556cee4b26c46 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 4 Mar 2019 22:26:55 +1100 Subject: [PATCH 0152/1788] stm32/Makefile: Allow a board to specify its linker sections for FW. A board can now use the make variables TEXT0_SECTIONS and TEXT1_SECTIONS to specify the linker sections that should go in its firmware. Defaults are provided which give the existing behaviour. --- ports/stm32/Makefile | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 1a75bf0504..03c7915330 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -490,6 +490,8 @@ TEXT0_ADDR ?= 0x08000000 ifeq ($(TEXT1_ADDR),) # No TEXT1_ADDR given so put all firmware at TEXT0_ADDR location +TEXT0_SECTIONS ?= .isr_vector .text .data + deploy-stlink: $(BUILD)/firmware.dfu $(ECHO) "Writing $(BUILD)/firmware.bin to the board via ST-LINK" $(Q)$(STFLASH) write $(BUILD)/firmware.bin $(TEXT0_ADDR) @@ -500,12 +502,15 @@ deploy-openocd: $(BUILD)/firmware.dfu $(BUILD)/firmware.dfu: $(BUILD)/firmware.elf $(ECHO) "Create $@" - $(Q)$(OBJCOPY) -O binary -j .isr_vector -j .text -j .data $^ $(BUILD)/firmware.bin + $(Q)$(OBJCOPY) -O binary $(addprefix -j ,$(TEXT0_SECTIONS)) $^ $(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 +TEXT0_SECTIONS ?= .isr_vector +TEXT1_SECTIONS ?= .text .data + deploy-stlink: $(BUILD)/firmware.dfu $(ECHO) "Writing $(BUILD)/firmware0.bin to the board via ST-LINK" $(Q)$(STFLASH) write $(BUILD)/firmware0.bin $(TEXT0_ADDR) @@ -518,8 +523,8 @@ deploy-openocd: $(BUILD)/firmware.dfu $(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)$(OBJCOPY) -O binary $(addprefix -j ,$(TEXT0_SECTIONS)) $^ $(BUILD)/firmware0.bin + $(Q)$(OBJCOPY) -O binary $(addprefix -j ,$(TEXT1_SECTIONS)) $^ $(BUILD)/firmware1.bin $(Q)$(PYTHON) $(DFU) -b $(TEXT0_ADDR):$(BUILD)/firmware0.bin -b $(TEXT1_ADDR):$(BUILD)/firmware1.bin $@ endif From 84479569de7db32ddc9bfb48c0e3a31b605a8638 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 4 Mar 2019 22:32:44 +1100 Subject: [PATCH 0153/1788] stm32/boards/STM32F769DISC: Use external QSPI flash to store some code. This demonstrates how to use external QSPI flash in XIP (execute in place) mode. The default configuration has all extmod/ code placed into external QSPI flash, but other code can easily be put there by modifying the custom f769_qspi.ld script. --- ports/stm32/boards/STM32F769DISC/board_init.c | 20 ++++ ports/stm32/boards/STM32F769DISC/f769_qspi.ld | 108 ++++++++++++++++++ .../boards/STM32F769DISC/mpconfigboard.h | 25 ++++ .../boards/STM32F769DISC/mpconfigboard.mk | 22 +++- ports/stm32/boards/STM32F769DISC/pins.csv | 6 + 5 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 ports/stm32/boards/STM32F769DISC/board_init.c create mode 100644 ports/stm32/boards/STM32F769DISC/f769_qspi.ld diff --git a/ports/stm32/boards/STM32F769DISC/board_init.c b/ports/stm32/boards/STM32F769DISC/board_init.c new file mode 100644 index 0000000000..b75a00c970 --- /dev/null +++ b/ports/stm32/boards/STM32F769DISC/board_init.c @@ -0,0 +1,20 @@ +#include "drivers/memory/spiflash.h" +#include "qspi.h" + +// This configuration is needed for mboot to be able to write to the external QSPI flash + +const mp_spiflash_config_t spiflash_config = { + .bus_kind = MP_SPIFLASH_BUS_QSPI, + .bus.u_qspi.data = NULL, + .bus.u_qspi.proto = &qspi_proto, + .cache = NULL, +}; + +mp_spiflash_t spiflash_instance; + +// This init function is needed to memory map the QSPI flash early in the boot process + +void board_early_init(void) { + qspi_init(); + qspi_memory_map(); +} diff --git a/ports/stm32/boards/STM32F769DISC/f769_qspi.ld b/ports/stm32/boards/STM32F769DISC/f769_qspi.ld new file mode 100644 index 0000000000..eb2cf783eb --- /dev/null +++ b/ports/stm32/boards/STM32F769DISC/f769_qspi.ld @@ -0,0 +1,108 @@ +/* + Custom linker script for STM32F769DISC board with external memory-mapped QSPI flash + + Memory layout: + + FLASH_QSPI .text_qspi + + FLASH_APP .isr_vector + FLASH_APP .text + FLASH_APP .data + + RAM .data + RAM .bss + RAM .heap + RAM .stack +*/ + +MEMORY +{ + FLASH_APP (rx) : ORIGIN = 0x08020000, LENGTH = 2016K /* sectors 1-11 3x32K 1*128K 7*256K */ + FLASH_QSPI (rx) : ORIGIN = 0x90000000, LENGTH = 64M /* external QSPI flash in XIP mode */ + DTCM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K /* Used for storage cache */ + RAM (xrw) : ORIGIN = 0x20020000, LENGTH = 384K /* SRAM1 = 368K, SRAM2 = 16K */ +} + +/* 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 */ +_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 = 0x20078000; /* tunable */ + +ENTRY(Reset_Handler) + +SECTIONS +{ + /* Define the code that goes in QSPI flash */ + .text_qspi : + { + . = ALIGN(4); + *extmod/*(.text* .rodata*) + . = ALIGN(4); + } >FLASH_QSPI + + /* The startup code goes first into main flash */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) + . = ALIGN(4); + } >FLASH_APP + + /* The program code and other data goes into flash */ + .text : + { + . = ALIGN(4); + *(.text*) + *(.rodata*) + . = ALIGN(4); + _etext = .; + } >FLASH_APP + + /* Used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* The initialized data section */ + .data : + { + . = ALIGN(4); + _sdata = .; + *(.data*) + . = ALIGN(4); + _edata = .; + } >RAM AT> FLASH_APP + + /* The uninitialized (zeroed) data section */ + .bss : + { + . = ALIGN(4); + _sbss = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >RAM + + /* Define the start of the heap, and make sure we have a minimum size */ + .heap : + { + . = ALIGN(4); + . = . + _minimum_heap_size; + . = ALIGN(4); + } >RAM + + /* Just checks there is enough RAM for the stack */ + .stack : + { + . = ALIGN(4); + . = . + _minimum_stack_size; + . = ALIGN(4); + } >RAM +} diff --git a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h index fac7c98fd8..155b14741f 100644 --- a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h @@ -14,6 +14,9 @@ #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_BOARD_EARLY_INIT board_early_init +void 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 @@ -25,6 +28,15 @@ #define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_7 // 210-216 MHz needs 7 wait states +// 512MBit external QSPI flash, to be memory mapped +#define MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2 (29) +#define MICROPY_HW_QSPIFLASH_CS (pin_B6) +#define MICROPY_HW_QSPIFLASH_SCK (pin_B2) +#define MICROPY_HW_QSPIFLASH_IO0 (pin_C9) +#define MICROPY_HW_QSPIFLASH_IO1 (pin_C10) +#define MICROPY_HW_QSPIFLASH_IO2 (pin_E2) +#define MICROPY_HW_QSPIFLASH_IO3 (pin_D13) + // UART config #define MICROPY_HW_UART1_TX (pin_A9) #define MICROPY_HW_UART1_RX (pin_A10) @@ -177,3 +189,16 @@ #define MICROPY_HW_FMC_D30 (pyb_pin_FMC_D30) #define MICROPY_HW_FMC_D31 (pyb_pin_FMC_D31) #endif + +/******************************************************************************/ +// Bootloader configuration + +// Give Mboot access to the external QSPI flash +extern const struct _mp_spiflash_config_t spiflash_config; +extern struct _mp_spiflash_t spiflash_instance; +#define MBOOT_SPIFLASH_ADDR (0x90000000) +#define MBOOT_SPIFLASH_BYTE_SIZE (512 * 128 * 1024) +#define MBOOT_SPIFLASH_LAYOUT "/0x90000000/512*128Kg" +#define MBOOT_SPIFLASH_ERASE_BLOCKS_PER_PAGE (128 / 4) // 128k page, 4k erase block +#define MBOOT_SPIFLASH_CONFIG (&spiflash_config) +#define MBOOT_SPIFLASH_SPIFLASH (&spiflash_instance) diff --git a/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk index 7a0dec07a6..06a9adcebe 100644 --- a/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk @@ -1,18 +1,38 @@ # By default this board is configured to use mboot which must be deployed first USE_MBOOT ?= 1 +# By default this board puts some code into external QSPI flash set in XIP mode +# USE_MBOOT must be enabled; see f769_qspi.ld for code that goes in QSPI flash +USE_QSPI ?= 1 + +# MCU settings MCU_SERIES = f7 CMSIS_MCU = STM32F769xx MICROPY_FLOAT_IMPL = double AF_FILE = boards/stm32f767_af.csv ifeq ($(USE_MBOOT),1) -# When using Mboot all the text goes together after the filesystem +ifeq ($(USE_QSPI),1) + +# When using Mboot and QSPI the text is split between internal and external flash +LD_FILES = boards/STM32F769DISC/f769_qspi.ld +TEXT0_ADDR = 0x08020000 +TEXT1_ADDR = 0x90000000 +TEXT0_SECTIONS = .isr_vector .text .data +TEXT1_SECTIONS = .text_qspi + +else + +# When using Mboot but not QSPI all the text goes together after the filesystem LD_FILES = boards/stm32f769.ld boards/common_blifs.ld TEXT0_ADDR = 0x08020000 + +endif else + # When not using Mboot the ISR text goes first, then the rest after the filesystem LD_FILES = boards/stm32f769.ld boards/common_ifs.ld TEXT0_ADDR = 0x08000000 TEXT1_ADDR = 0x08020000 + endif diff --git a/ports/stm32/boards/STM32F769DISC/pins.csv b/ports/stm32/boards/STM32F769DISC/pins.csv index 2dcc374419..9d6ccacbad 100644 --- a/ports/stm32/boards/STM32F769DISC/pins.csv +++ b/ports/stm32/boards/STM32F769DISC/pins.csv @@ -69,6 +69,12 @@ UART5_TX,PC12 UART5_RX,PD2 CAN2_TX,PB13 CAN2_RX,PB12 +QSPI_CS,PB6 +QSPI_CLK,PB2 +QSPI_D0,PC9 +QSPI_D1,PC10 +QSPI_D2,PE2 +QSPI_D3,PD13 ETH_REF_CLK,PA1 ETH_MDIO,PA2 ETH_CRS_DV,PA7 From 871954d75cb249421337b79e0ff67b78f799edd5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 4 Mar 2019 23:29:01 +1100 Subject: [PATCH 0154/1788] py/py.mk: Update lwip build config to work with latest lwip version. Also, to make it possible for ports to provide their own lwipopts.h, the default include directory of extmod/lwip-include is no longer added and instead a port should now make sure the correct include directory is included in the list (can still use extmod/lwip-include). --- py/py.mk | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/py/py.mk b/py/py.mk index a6eeaa4b87..b85d94fee7 100644 --- a/py/py.mk +++ b/py/py.mk @@ -51,19 +51,19 @@ LDFLAGS_MOD += -L$(TOP)/lib/mbedtls/library -lmbedx509 -lmbedtls -lmbedcrypto endif endif -#ifeq ($(MICROPY_PY_LWIP),1) -#CFLAGS_MOD += -DMICROPY_PY_LWIP=1 -I../lib/lwip/src/include -I../lib/lwip/src/include/ipv4 -I../extmod/lwip-include -#endif - ifeq ($(MICROPY_PY_LWIP),1) +# A port should add an include path where lwipopts.h can be found (eg extmod/lwip-include) LWIP_DIR = lib/lwip/src -INC += -I$(TOP)/lib/lwip/src/include -I$(TOP)/lib/lwip/src/include/ipv4 -I$(TOP)/extmod/lwip-include +INC += -I$(TOP)/$(LWIP_DIR)/include CFLAGS_MOD += -DMICROPY_PY_LWIP=1 +$(BUILD)/$(LWIP_DIR)/core/ipv4/dhcp.o: CFLAGS_MOD += -Wno-address SRC_MOD += extmod/modlwip.c lib/netutils/netutils.c 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 \ @@ -74,16 +74,26 @@ SRC_MOD += $(addprefix $(LWIP_DIR)/,\ core/tcp.c \ core/tcp_in.c \ core/tcp_out.c \ - core/timers.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/inet.c \ - core/ipv4/inet_chksum.c \ - core/ipv4/ip_addr.c \ - core/ipv4/ip.c \ - core/ipv4/ip_frag.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 \ ) ifeq ($(MICROPY_PY_LWIP_SLIP),1) CFLAGS_MOD += -DMICROPY_PY_LWIP_SLIP=1 From 78fe979d7da2e45913cfe7a1264e081b185089b1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 4 Mar 2019 23:33:02 +1100 Subject: [PATCH 0155/1788] stm32: Use global lwip build config and support building without lwip. --- ports/stm32/Makefile | 43 +-------------------------------------- ports/stm32/eth.c | 9 ++++---- ports/stm32/main.c | 5 ++++- ports/stm32/network_lan.c | 3 ++- 4 files changed, 12 insertions(+), 48 deletions(-) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 03c7915330..a4f3cb2d0b 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -52,6 +52,7 @@ INC += -I$(CMSIS_DIR)/ INC += -I$(TOP)/$(HAL_DIR)/Inc INC += -I$(USBDEV_DIR)/core/inc -I$(USBDEV_DIR)/class/inc #INC += -I$(USBHOST_DIR) +INC += -Ilwip_inc # Basic Cortex-M flags CFLAGS_CORTEX_M = -mthumb @@ -199,7 +200,6 @@ endif endif EXTMOD_SRC_C = $(addprefix extmod/,\ - modlwip.c \ modonewire.c \ ) @@ -383,47 +383,6 @@ 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/eth.c b/ports/stm32/eth.c index c3a18bde77..665495c174 100644 --- a/ports/stm32/eth.c +++ b/ports/stm32/eth.c @@ -28,16 +28,17 @@ #include "py/mphal.h" #include "py/mperrno.h" #include "lib/netutils/netutils.h" -#include "lwip/etharp.h" -#include "lwip/dns.h" -#include "lwip/dhcp.h" -#include "netif/ethernet.h" #include "pin_static_af.h" #include "modnetwork.h" #include "eth.h" #if defined(MICROPY_HW_ETH_MDC) +#include "lwip/etharp.h" +#include "lwip/dns.h" +#include "lwip/dhcp.h" +#include "netif/ethernet.h" + // ETH PHY register definitions (for LAN8742) #undef PHY_BCR diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 8a65188ed1..c7b189dabf 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -34,10 +34,13 @@ #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" +#if MICROPY_PY_LWIP +#include "lwip/init.h" +#endif + #include "systick.h" #include "pendsv.h" #include "pybthread.h" diff --git a/ports/stm32/network_lan.c b/ports/stm32/network_lan.c index 8c210802ce..d89c23765c 100644 --- a/ports/stm32/network_lan.c +++ b/ports/stm32/network_lan.c @@ -26,12 +26,13 @@ #include "py/runtime.h" #include "py/mphal.h" -#include "lwip/netif.h" #include "modnetwork.h" #include "eth.h" #if defined(MICROPY_HW_ETH_MDC) +#include "lwip/netif.h" + typedef struct _network_lan_obj_t { mp_obj_base_t base; eth_t *eth; From e61862d063b7a19f5baba8e0d1234d648826a616 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 4 Mar 2019 23:34:03 +1100 Subject: [PATCH 0156/1788] stm32/boards: Update to use new build config for lwip component. --- ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h | 2 -- ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk | 3 +++ ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h | 2 -- ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk | 3 +++ ports/stm32/boards/STM32F769DISC/mpconfigboard.h | 2 -- ports/stm32/boards/STM32F769DISC/mpconfigboard.mk | 3 +++ ports/stm32/boards/STM32F7DISC/mpconfigboard.h | 2 -- ports/stm32/boards/STM32F7DISC/mpconfigboard.mk | 3 +++ 8 files changed, 12 insertions(+), 8 deletions(-) diff --git a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h index 3d58743556..05c98e113f 100644 --- a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h @@ -1,8 +1,6 @@ #define MICROPY_HW_BOARD_NAME "NUCLEO-F429ZI" #define MICROPY_HW_MCU_NAME "STM32F429" -#define MICROPY_PY_LWIP (1) - #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_ENABLE_RNG (1) diff --git a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk index d19a35c316..e542d1c998 100644 --- a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk @@ -4,3 +4,6 @@ AF_FILE = boards/stm32f429_af.csv LD_FILES = boards/stm32f429.ld boards/common_ifs.ld TEXT0_ADDR = 0x08000000 TEXT1_ADDR = 0x08020000 + +# MicroPython settings +MICROPY_PY_LWIP = 1 diff --git a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h index e3f255de4d..1ee73c303b 100644 --- a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h @@ -6,8 +6,6 @@ #define MICROPY_HW_BOARD_NAME "NUCLEO-F767ZI" #define MICROPY_HW_MCU_NAME "STM32F767" -#define MICROPY_PY_LWIP (1) - #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_ENABLE_RNG (1) diff --git a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk index b79ee7da20..c3f12998c3 100644 --- a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk @@ -5,3 +5,6 @@ AF_FILE = boards/stm32f767_af.csv LD_FILES = boards/stm32f767.ld boards/common_ifs.ld TEXT0_ADDR = 0x08000000 TEXT1_ADDR = 0x08020000 + +# MicroPython settings +MICROPY_PY_LWIP = 1 diff --git a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h index 155b14741f..58cf707892 100644 --- a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h @@ -5,8 +5,6 @@ #define MICROPY_HW_BOARD_NAME "F769DISC" #define MICROPY_HW_MCU_NAME "STM32F769" -#define MICROPY_PY_LWIP (1) - #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_HAS_SDCARD (1) diff --git a/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk index 06a9adcebe..49b318d30b 100644 --- a/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk @@ -36,3 +36,6 @@ TEXT0_ADDR = 0x08000000 TEXT1_ADDR = 0x08020000 endif + +# MicroPython settings +MICROPY_PY_LWIP = 1 diff --git a/ports/stm32/boards/STM32F7DISC/mpconfigboard.h b/ports/stm32/boards/STM32F7DISC/mpconfigboard.h index ff135b8a75..609d908bba 100644 --- a/ports/stm32/boards/STM32F7DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F7DISC/mpconfigboard.h @@ -1,8 +1,6 @@ #define MICROPY_HW_BOARD_NAME "F7DISC" #define MICROPY_HW_MCU_NAME "STM32F746" -#define MICROPY_PY_LWIP (1) - #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_HAS_SDCARD (1) diff --git a/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk index 160218fd33..4f88a139e7 100644 --- a/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk @@ -4,3 +4,6 @@ AF_FILE = boards/stm32f746_af.csv LD_FILES = boards/stm32f746.ld boards/common_ifs.ld TEXT0_ADDR = 0x08000000 TEXT1_ADDR = 0x08020000 + +# MicroPython settings +MICROPY_PY_LWIP = 1 From f938e70c6905474b08f7b5e6df3da9c1b0dcf01a Mon Sep 17 00:00:00 2001 From: "Francisco J. Manno" Date: Sun, 3 Mar 2019 23:50:23 +0000 Subject: [PATCH 0157/1788] stm32: Add compile-time option to use HSI as clock source. To use HSI instead of HSE define MICROPY_HW_CLK_USE_HSI as 1 in the board configuration file. The default is to use HSE. HSI has been made the default for the NUCLEO_F401RE board to serve as an example, and because early revisions of this board need a hardware modification to get HSE working. --- .../boards/NUCLEO_F401RE/mpconfigboard.h | 11 ++++++- ports/stm32/mpconfigboard_common.h | 25 ++++++++++++--- ports/stm32/powerctrl.c | 15 +++++---- ports/stm32/stm32_it.c | 13 +++++--- ports/stm32/system_stm32.c | 32 ++++++++++--------- 5 files changed, 65 insertions(+), 31 deletions(-) diff --git a/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.h index a843d3c35f..babf63c7a1 100644 --- a/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.h @@ -5,8 +5,17 @@ #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_ENABLE_RTC (1) -// HSE is 8MHz, CPU freq set to 84MHz +// HSE is 8MHz, HSI is 16MHz CPU freq set to 84MHz +// Default source for the clock is HSI. +// For revisions of the board greater than C-01, HSE can be used as a +// clock source by removing the #define MICROPY_HW_CLK_USE_HSE line +#define MICROPY_HW_CLK_USE_HSI (1) + +#if MICROPY_HW_CLK_USE_HSI +#define MICROPY_HW_CLK_PLLM (16) +#else #define MICROPY_HW_CLK_PLLM (8) +#endif #define MICROPY_HW_CLK_PLLN (336) #define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV4) #define MICROPY_HW_CLK_PLLQ (7) diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index d4e7c20145..e208f2238a 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -181,11 +181,28 @@ #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) +#if MICROPY_HW_CLK_USE_HSI +// Use HSI as clock source +#define MICROPY_HW_CLK_VALUE (HSI_VALUE) +#define MICROPY_HW_RCC_OSCILLATOR_TYPE (RCC_OSCILLATORTYPE_HSI) +#define MICROPY_HW_RCC_PLL_SRC (RCC_PLLSOURCE_HSI) +#define MICROPY_HW_RCC_CR_HSxON (RCC_CR_HSION) +#define MICROPY_HW_RCC_HSI_STATE (RCC_HSI_ON) +#define MICROPY_HW_RCC_FLAG_HSxRDY (RCC_FLAG_HSIRDY) +#define MICROPY_HW_RCC_HSE_STATE (RCC_HSE_OFF) #else -#define MICROPY_HW_CLK_HSE_STATE (RCC_HSE_ON) +// Use HSE as a clock source (bypass or oscillator) +#define MICROPY_HW_CLK_VALUE (HSE_VALUE) +#define MICROPY_HW_RCC_OSCILLATOR_TYPE (RCC_OSCILLATORTYPE_HSE) +#define MICROPY_HW_RCC_PLL_SRC (RCC_PLLSOURCE_HSE) +#define MICROPY_HW_RCC_CR_HSxON (RCC_CR_HSEON) +#define MICROPY_HW_RCC_HSI_STATE (RCC_HSI_OFF) +#define MICROPY_HW_RCC_FLAG_HSxRDY (RCC_FLAG_HSERDY) +#if MICROPY_HW_CLK_USE_BYPASS +#define MICROPY_HW_RCC_HSE_STATE (RCC_HSE_BYPASS) +#else +#define MICROPY_HW_RCC_HSE_STATE (RCC_HSE_ON) +#endif #endif #if MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c index fe4d580017..165919977f 100644 --- a/ports/stm32/powerctrl.c +++ b/ports/stm32/powerctrl.c @@ -215,10 +215,10 @@ set_clk: // Re-configure PLL // 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 = MICROPY_HW_CLK_HSE_STATE; + RCC_OscInitStruct.OscillatorType = MICROPY_HW_RCC_OSCILLATOR_TYPE; + RCC_OscInitStruct.HSEState = MICROPY_HW_RCC_HSE_STATE; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; - RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; + RCC_OscInitStruct.PLL.PLLSource = MICROPY_HW_RCC_PLL_SRC; RCC_OscInitStruct.PLL.PLLM = m; RCC_OscInitStruct.PLL.PLLN = n; RCC_OscInitStruct.PLL.PLLP = p; @@ -297,9 +297,12 @@ void powerctrl_enter_stop_mode(void) { #else #if !defined(STM32L4) - // enable HSE - __HAL_RCC_HSE_CONFIG(MICROPY_HW_CLK_HSE_STATE); - while (!__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY)) { + // enable clock + __HAL_RCC_HSE_CONFIG(MICROPY_HW_RCC_HSE_STATE); + #if MICROPY_HW_CLK_USE_HSI + __HAL_RCC_HSI_ENABLE(); + #endif + while (!__HAL_RCC_GET_FLAG(MICROPY_HW_RCC_FLAG_HSxRDY)) { } #endif diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index 0f2be4c68d..004e0f974d 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -329,13 +329,16 @@ STATIC void OTG_CMD_WKUP_Handler(PCD_HandleTypeDef *pcd_handle) { /* Reset SLEEPDEEP bit of Cortex System Control Register */ SCB->SCR &= (uint32_t)~((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk)); - /* 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) */ + /* Configures system clock after wake-up from STOP: enable HSE/HSI, PLL and select + PLL as system clock source (HSE/HSI and PLL are disabled in STOP mode) */ - __HAL_RCC_HSE_CONFIG(MICROPY_HW_CLK_HSE_STATE); + __HAL_RCC_HSE_CONFIG(MICROPY_HW_RCC_HSE_STATE); + #if MICROPY_HW_CLK_USE_HSI + __HAL_RCC_HSI_ENABLE(); + #endif - /* Wait till HSE is ready */ - while(__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET) + /* Wait till HSE/HSI is ready */ + while(__HAL_RCC_GET_FLAG(MICROPY_HW_RCC_FLAG_HSxRDY) == RESET) {} /* Enable the main PLL. */ diff --git a/ports/stm32/system_stm32.c b/ports/stm32/system_stm32.c index e0e27cef09..e0f0545006 100644 --- a/ports/stm32/system_stm32.c +++ b/ports/stm32/system_stm32.c @@ -111,7 +111,7 @@ void __fatal_error(const char *msg); #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_CR_2ND (MICROPY_HW_RCC_CR_HSxON | RCC_CR_CSSON | RCC_CR_PLLON) #define CONFIG_RCC_PLLCFGR (0x24003010) #if defined(STM32F4) @@ -222,7 +222,7 @@ void SystemInit(void) /* Reset CFGR register */ RCC->CFGR = 0x00000000; - /* Reset HSEON, CSSON and PLLON bits */ + /* Reset HSxON, CSSON and PLLON bits */ RCC->CR &= ~ CONFIG_RCC_CR_2ND; /* Reset PLLCFGR register */ @@ -295,16 +295,17 @@ void SystemInit(void) * @brief System Clock Configuration * * The system Clock is configured for F4/F7 as follows: - * System Clock source = PLL (HSE) + * (HSx should be read as HSE or HSI depending on the value of MICROPY_HW_CLK_USE_HSI) + * System Clock source = PLL (HSx) * SYSCLK(Hz) = 168000000 * HCLK(Hz) = 168000000 * AHB Prescaler = 1 * APB1 Prescaler = 4 * APB2 Prescaler = 2 - * HSE Frequency(Hz) = HSE_VALUE - * PLL_M = HSE_VALUE/1000000 + * HSx Frequency(Hz) = HSx_VALUE + * PLL_M = HSx_VALUE/1000000 * PLL_N = 336 - * PLL_P = 2 + * PLL_P = 4 * PLL_Q = 7 * VDD(V) = 3.3 * Main regulator output voltage = Scale1 mode @@ -331,16 +332,16 @@ void SystemInit(void) * PLL is configured as follows: * * VCO_IN - * F4/F7 = HSE / M + * F4/F7 = HSx / M * L4 = MSI / M * VCO_OUT - * F4/F7 = HSE / M * N + * F4/F7 = HSx / M * N * L4 = MSI / M * N * PLLCLK - * F4/F7 = HSE / M * N / P + * F4/F7 = HSx / M * N / P * L4 = MSI / M * N / R * PLL48CK - * F4/F7 = HSE / M * N / Q + * F4/F7 = HSx / M * N / Q * L4 = MSI / M * N / Q USB Clock is obtained over PLLSAI1 * * SYSCLK = PLLCLK @@ -352,6 +353,7 @@ void SystemInit(void) * VCO_IN between 1MHz and 2MHz (2MHz recommended) * VCO_OUT between 192MHz and 432MHz * HSE = 8MHz + * HSI = 16MHz * M = 2 .. 63 (inclusive) * N = 192 ... 432 (inclusive) * P = 2, 4, 6, 8 @@ -411,13 +413,13 @@ 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 = MICROPY_HW_CLK_HSE_STATE; - RCC_OscInitStruct.HSIState = RCC_HSI_OFF; + RCC_OscInitStruct.OscillatorType = MICROPY_HW_RCC_OSCILLATOR_TYPE; + RCC_OscInitStruct.HSEState = MICROPY_HW_RCC_HSE_STATE; + RCC_OscInitStruct.HSIState = MICROPY_HW_RCC_HSI_STATE; #if defined(STM32H7) RCC_OscInitStruct.CSIState = RCC_CSI_OFF; #endif - RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; + RCC_OscInitStruct.PLL.PLLSource = MICROPY_HW_RCC_PLL_SRC; #elif defined(STM32L4) RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE|RCC_OSCILLATORTYPE_MSI; RCC_OscInitStruct.LSEState = RCC_LSE_ON; @@ -538,7 +540,7 @@ void SystemClock_Config(void) } #endif - uint32_t vco_out = RCC_OscInitStruct.PLL.PLLN * (HSE_VALUE / 1000000) / RCC_OscInitStruct.PLL.PLLM; + uint32_t vco_out = RCC_OscInitStruct.PLL.PLLN * (MICROPY_HW_CLK_VALUE / 1000000) / RCC_OscInitStruct.PLL.PLLM; uint32_t sysclk_mhz = vco_out / RCC_OscInitStruct.PLL.PLLP; bool need_pllsai = vco_out % 48 != 0; if (powerctrl_rcc_clock_config_pll(&RCC_ClkInitStruct, sysclk_mhz, need_pllsai) != 0) { From 1a24bac6cb3dcb7418c20040149ca19050913109 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 25 Feb 2019 23:41:51 +1100 Subject: [PATCH 0158/1788] lib/oofatfs: Update oofatfs library to R0.13c working branch. From https://github.com/micropython/oofatfs, branch work-R0.13c, commit cb05c9486d3b48ffd6bd7542d8dbbab4b1caf790. Large code pages (932, 936, 949, 950) have been removed from ffunicode.c because they were not included in previous versions here. --- lib/oofatfs/diskio.h | 12 +- lib/oofatfs/ff.c | 3815 ++++++++++-------- lib/oofatfs/ff.h | 220 +- lib/oofatfs/{option/ccsbcs.c => ffunicode.c} | 577 ++- lib/oofatfs/option/unicode.c | 17 - 5 files changed, 2617 insertions(+), 2024 deletions(-) rename lib/oofatfs/{option/ccsbcs.c => ffunicode.c} (58%) delete mode 100644 lib/oofatfs/option/unicode.c diff --git a/lib/oofatfs/diskio.h b/lib/oofatfs/diskio.h index 8deb68ecea..d886bdd9cc 100644 --- a/lib/oofatfs/diskio.h +++ b/lib/oofatfs/diskio.h @@ -13,8 +13,6 @@ extern "C" { #endif - - /* Status of Disk Functions */ typedef BYTE DSTATUS; @@ -47,11 +45,11 @@ DRESULT disk_ioctl (void *drv, BYTE cmd, void* buff); /* Command code for disk_ioctrl fucntion */ /* Generic command (Used by FatFs) */ -#define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */ -#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */ -#define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */ -#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */ -#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */ +#define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */ +#define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */ +#define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */ +#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */ +#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */ #define IOCTL_INIT 5 #define IOCTL_STATUS 6 diff --git a/lib/oofatfs/ff.c b/lib/oofatfs/ff.c index b0984756bf..c7c79a1dd6 100644 --- a/lib/oofatfs/ff.c +++ b/lib/oofatfs/ff.c @@ -3,15 +3,15 @@ */ /*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT file system module R0.12b / +/ FatFs - Generic FAT Filesystem Module R0.13c / /-----------------------------------------------------------------------------/ / -/ Copyright (C) 2016, ChaN, all right reserved. +/ Copyright (C) 2018, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided / that the following condition is met: - +/ / 1. Redistributions of source code must retain the above copyright notice, / this condition and the following disclaimer. / @@ -19,6 +19,7 @@ / and any warranties related to this software are DISCLAIMED. / The copyright owner or contributors be NOT LIABLE for any damages caused / by use of this software. +/ /----------------------------------------------------------------------------*/ @@ -36,343 +37,43 @@ ---------------------------------------------------------------------------*/ -#if _FATFS != 68020 /* Revision ID */ +#if FF_DEFINED != 86604 /* Revision ID */ #error Wrong include file (ff.h). #endif -#define ABORT(fs, res) { fp->err = (BYTE)(res); LEAVE_FF(fs, res); } - - -/* Reentrancy related */ -#if _FS_REENTRANT -#if _USE_LFN == 1 -#error Static LFN work area cannot be used at thread-safe configuration -#endif -#define ENTER_FF(fs) { if (!lock_fs(fs)) return FR_TIMEOUT; } -#define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; } -#else -#define ENTER_FF(fs) -#define LEAVE_FF(fs, res) return res -#endif - - - -/* Definitions of sector size */ -#if (_MAX_SS < _MIN_SS) || (_MAX_SS != 512 && _MAX_SS != 1024 && _MAX_SS != 2048 && _MAX_SS != 4096) || (_MIN_SS != 512 && _MIN_SS != 1024 && _MIN_SS != 2048 && _MIN_SS != 4096) -#error Wrong sector size configuration -#endif -#if _MAX_SS == _MIN_SS -#define SS(fs) ((UINT)_MAX_SS) /* Fixed sector size */ -#else -#define SS(fs) ((fs)->ssize) /* Variable sector size */ -#endif - - -/* Timestamp */ -#if _FS_NORTC == 1 -#if _NORTC_YEAR < 1980 || _NORTC_YEAR > 2107 || _NORTC_MON < 1 || _NORTC_MON > 12 || _NORTC_MDAY < 1 || _NORTC_MDAY > 31 -#error Invalid _FS_NORTC settings -#endif -#define GET_FATTIME() ((DWORD)(_NORTC_YEAR - 1980) << 25 | (DWORD)_NORTC_MON << 21 | (DWORD)_NORTC_MDAY << 16) -#else -#define GET_FATTIME() get_fattime() -#endif - - -/* File lock controls */ -#if _FS_LOCK != 0 -#if _FS_READONLY -#error _FS_LOCK must be 0 at read-only configuration -#endif -typedef struct { - FATFS *fs; /* Object ID 1, volume (NULL:blank entry) */ - DWORD clu; /* Object ID 2, directory (0:root) */ - DWORD ofs; /* Object ID 3, directory offset */ - WORD ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ -} FILESEM; -#endif - - - -/* DBCS code ranges and SBCS upper conversion tables */ - -#if _CODE_PAGE == 932 /* Japanese Shift-JIS */ -#define _DF1S 0x81 /* DBC 1st byte range 1 start */ -#define _DF1E 0x9F /* DBC 1st byte range 1 end */ -#define _DF2S 0xE0 /* DBC 1st byte range 2 start */ -#define _DF2E 0xFC /* DBC 1st byte range 2 end */ -#define _DS1S 0x40 /* DBC 2nd byte range 1 start */ -#define _DS1E 0x7E /* DBC 2nd byte range 1 end */ -#define _DS2S 0x80 /* DBC 2nd byte range 2 start */ -#define _DS2E 0xFC /* DBC 2nd byte range 2 end */ - -#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */ -#define _DF1S 0x81 -#define _DF1E 0xFE -#define _DS1S 0x40 -#define _DS1E 0x7E -#define _DS2S 0x80 -#define _DS2E 0xFE - -#elif _CODE_PAGE == 949 /* Korean */ -#define _DF1S 0x81 -#define _DF1E 0xFE -#define _DS1S 0x41 -#define _DS1E 0x5A -#define _DS2S 0x61 -#define _DS2E 0x7A -#define _DS3S 0x81 -#define _DS3E 0xFE - -#elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */ -#define _DF1S 0x81 -#define _DF1E 0xFE -#define _DS1S 0x40 -#define _DS1E 0x7E -#define _DS2S 0xA1 -#define _DS2E 0xFE - -#elif _CODE_PAGE == 437 /* U.S. */ -#define _DF1S 0 -#define _EXCVT {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ - 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ - 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 720 /* Arabic */ -#define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ - 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ - 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 737 /* Greek */ -#define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ - 0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \ - 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xEF,0xF5,0xF0,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ - 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 771 /* KBL */ -#define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ - 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDC,0xDE,0xDE, \ - 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFE,0xFF} - -#elif _CODE_PAGE == 775 /* Baltic */ -#define _DF1S 0 -#define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F, \ - 0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ - 0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF, \ - 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 850 /* Latin 1 */ -#define _DF1S 0 -#define _EXCVT {0x43,0x55,0x45,0x41,0x41,0x41,0x41,0x43,0x45,0x45,0x45,0x49,0x49,0x49,0x41,0x41, \ - 0x45,0x92,0x92,0x4F,0x4F,0x4F,0x55,0x55,0x59,0x4F,0x55,0x4F,0x9C,0x4F,0x9E,0x9F, \ - 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0x41,0x41,0x41,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0x41,0x41,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD1,0xD1,0x45,0x45,0x45,0x49,0x49,0x49,0x49,0xD9,0xDA,0xDB,0xDC,0xDD,0x49,0xDF, \ - 0x4F,0xE1,0x4F,0x4F,0x4F,0x4F,0xE6,0xE8,0xE8,0x55,0x55,0x55,0x59,0x59,0xEE,0xEF, \ - 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 852 /* Latin 2 */ -#define _DF1S 0 -#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F, \ - 0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0xAC, \ - 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF, \ - 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF} - -#elif _CODE_PAGE == 855 /* Cyrillic */ -#define _DF1S 0 -#define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F, \ - 0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \ - 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \ - 0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF, \ - 0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 857 /* Turkish */ -#define _DF1S 0 -#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x49,0x8E,0x8F, \ - 0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \ - 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD0,0xD1,0xD2,0xD3,0xD4,0x49,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0xED,0xEE,0xEF, \ - 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 860 /* Portuguese */ -#define _DF1S 0 -#define _EXCVT {0x80,0x9A,0x90,0x8F,0x8E,0x91,0x86,0x80,0x89,0x89,0x92,0x8B,0x8C,0x98,0x8E,0x8F, \ - 0x90,0x91,0x92,0x8C,0x99,0xA9,0x96,0x9D,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0x86,0x8B,0x9F,0x96,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ - 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 861 /* Icelandic */ -#define _DF1S 0 -#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x8B,0x8B,0x8D,0x8E,0x8F, \ - 0x90,0x92,0x92,0x4F,0x99,0x8D,0x55,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ - 0xA4,0xA5,0xA6,0xA7,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ - 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 862 /* Hebrew */ -#define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ - 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ - 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 863 /* Canadian-French */ -#define _DF1S 0 -#define _EXCVT {0x43,0x55,0x45,0x41,0x41,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x41,0x8F, \ - 0x45,0x45,0x45,0x4F,0x45,0x49,0x55,0x55,0x98,0x4F,0x55,0x9B,0x9C,0x55,0x55,0x9F, \ - 0xA0,0xA1,0x4F,0x55,0xA4,0xA5,0xA6,0xA7,0x49,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ - 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 864 /* Arabic */ -#define _DF1S 0 -#define _EXCVT {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ - 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ - 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 865 /* Nordic */ -#define _DF1S 0 -#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ - 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ - 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 866 /* Russian */ -#define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ - 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 869 /* Greek 2 */ -#define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ - 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x86,0x9C,0x8D,0x8F,0x90, \ - 0x91,0x90,0x92,0x95,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xA4,0xA5,0xA6,0xD9,0xDA,0xDB,0xDC,0xA7,0xA8,0xDF, \ - 0xA9,0xAA,0xAC,0xAD,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xCF,0xCF,0xD0,0xEF, \ - 0xF0,0xF1,0xD1,0xD2,0xD3,0xF5,0xD4,0xF7,0xF8,0xF9,0xD5,0x96,0x95,0x98,0xFE,0xFF} - -#elif _CODE_PAGE == 1 /* ASCII (for only non-LFN cfg) */ -#if _USE_LFN != 0 -#error Cannot enable LFN without valid code page. -#endif -#define _DF1S 0 - -#else -#error Unknown code page - -#endif +/* Limits and boundaries */ +#define MAX_DIR 0x200000 /* Max size of FAT directory */ +#define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */ +#define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but right for real DOS/Windows behavior) */ +#define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but right for real DOS/Windows behavior) */ +#define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */ +#define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */ /* Character code support macros */ -#define IsUpper(c) (((c)>='A')&&((c)<='Z')) -#define IsLower(c) (((c)>='a')&&((c)<='z')) -#define IsDigit(c) (((c)>='0')&&((c)<='9')) - -#if _DF1S != 0 /* Code page is DBCS */ - -#ifdef _DF2S /* Two 1st byte areas */ -#define IsDBCS1(c) (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E)) -#else /* One 1st byte area */ -#define IsDBCS1(c) ((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) -#endif - -#ifdef _DS3S /* Three 2nd byte areas */ -#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E) || ((BYTE)(c) >= _DS3S && (BYTE)(c) <= _DS3E)) -#else /* Two 2nd byte areas */ -#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E)) -#endif - -#else /* Code page is SBCS */ - -#define IsDBCS1(c) 0 -#define IsDBCS2(c) 0 - -#endif /* _DF1S */ +#define IsUpper(c) ((c) >= 'A' && (c) <= 'Z') +#define IsLower(c) ((c) >= 'a' && (c) <= 'z') +#define IsDigit(c) ((c) >= '0' && (c) <= '9') +#define IsSurrogate(c) ((c) >= 0xD800 && (c) <= 0xDFFF) +#define IsSurrogateH(c) ((c) >= 0xD800 && (c) <= 0xDBFF) +#define IsSurrogateL(c) ((c) >= 0xDC00 && (c) <= 0xDFFF) -/* File attribute bits (internal use) */ -#define AM_VOL 0x08 /* Volume label */ -#define AM_LFN 0x0F /* LFN entry */ -#define AM_MASK 0x3F /* Mask of defined bits */ - - -/* File access control and file status flags (internal use) */ +/* Additional file access control and file status flags for internal use */ #define FA_SEEKEND 0x20 /* Seek to end of the file on file open */ #define FA_MODIFIED 0x40 /* File has been modified */ #define FA_DIRTY 0x80 /* FIL.buf[] needs to be written-back */ -/* Name status flags */ -#define NSFLAG 11 /* Index of name status byte in fn[] */ +/* Additional file attribute bits for internal use */ +#define AM_VOL 0x08 /* Volume label */ +#define AM_LFN 0x0F /* LFN entry */ +#define AM_MASK 0x3F /* Mask of defined bits */ + + +/* Name status flags in fn[11] */ +#define NSFLAG 11 /* Index of the name status byte */ #define NS_LOSS 0x01 /* Out of 8.3 format */ #define NS_LFN 0x02 /* Force to create LFN entry */ #define NS_LAST 0x04 /* Last segment */ @@ -383,18 +84,17 @@ typedef struct { #define NS_NONAME 0x80 /* Not followed */ -/* Limits and boundaries (differ from specs but correct for real DOS/Windows) */ -#define MAX_FAT12 0xFF5 /* Maximum number of FAT12 clusters */ -#define MAX_FAT16 0xFFF5 /* Maximum number of FAT16 clusters */ -#define MAX_FAT32 0xFFFFFF5 /* Maximum number of FAT32 clusters */ -#define MAX_EXFAT 0x7FFFFFFD /* Maximum number of exFAT clusters (limited by implementation) */ -#define MAX_DIR 0x200000 /* Maximum size of FAT directory */ -#define MAX_DIR_EX 0x10000000 /* Maximum size of exFAT directory */ +/* exFAT directory entry types */ +#define ET_BITMAP 0x81 /* Allocation bitmap */ +#define ET_UPCASE 0x82 /* Up-case table */ +#define ET_VLABEL 0x83 /* Volume label */ +#define ET_FILEDIR 0x85 /* File and directory */ +#define ET_STREAM 0xC0 /* Stream extension */ +#define ET_FILENAME 0xC1 /* Name extension */ -/* FatFs refers the members in the FAT structures as byte array instead of -/ structure members because the structure is not binary compatible between -/ different platforms */ +/* FatFs refers the FAT structure as simple byte array instead of structure member +/ because the C structure is not binary compatible between different platforms */ #define BS_JmpBoot 0 /* x86 jump instruction (3-byte) */ #define BS_OEMName 3 /* OEM name (8-byte) */ @@ -402,26 +102,26 @@ typedef struct { #define BPB_SecPerClus 13 /* Cluster size [sector] (BYTE) */ #define BPB_RsvdSecCnt 14 /* Size of reserved area [sector] (WORD) */ #define BPB_NumFATs 16 /* Number of FATs (BYTE) */ -#define BPB_RootEntCnt 17 /* Size of root directory area for FAT12/16 [entry] (WORD) */ +#define BPB_RootEntCnt 17 /* Size of root directory area for FAT [entry] (WORD) */ #define BPB_TotSec16 19 /* Volume size (16-bit) [sector] (WORD) */ #define BPB_Media 21 /* Media descriptor byte (BYTE) */ #define BPB_FATSz16 22 /* FAT size (16-bit) [sector] (WORD) */ -#define BPB_SecPerTrk 24 /* Track size for int13h [sector] (WORD) */ +#define BPB_SecPerTrk 24 /* Number of sectors per track for int13h [sector] (WORD) */ #define BPB_NumHeads 26 /* Number of heads for int13h (WORD) */ #define BPB_HiddSec 28 /* Volume offset from top of the drive (DWORD) */ #define BPB_TotSec32 32 /* Volume size (32-bit) [sector] (DWORD) */ #define BS_DrvNum 36 /* Physical drive number for int13h (BYTE) */ -#define BS_NTres 37 /* Error flag (BYTE) */ +#define BS_NTres 37 /* WindowsNT error flag (BYTE) */ #define BS_BootSig 38 /* Extended boot signature (BYTE) */ #define BS_VolID 39 /* Volume serial number (DWORD) */ #define BS_VolLab 43 /* Volume label string (8-byte) */ -#define BS_FilSysType 54 /* File system type string (8-byte) */ +#define BS_FilSysType 54 /* Filesystem type string (8-byte) */ #define BS_BootCode 62 /* Boot code (448-byte) */ #define BS_55AA 510 /* Signature word (WORD) */ #define BPB_FATSz32 36 /* FAT32: FAT size [sector] (DWORD) */ #define BPB_ExtFlags32 40 /* FAT32: Extended flags (WORD) */ -#define BPB_FSVer32 42 /* FAT32: File system version (WORD) */ +#define BPB_FSVer32 42 /* FAT32: Filesystem version (WORD) */ #define BPB_RootClus32 44 /* FAT32: Root directory cluster (DWORD) */ #define BPB_FSInfo32 48 /* FAT32: Offset of FSINFO sector (WORD) */ #define BPB_BkBootSec32 50 /* FAT32: Offset of backup boot sector (WORD) */ @@ -430,7 +130,7 @@ typedef struct { #define BS_BootSig32 66 /* FAT32: Extended boot signature (BYTE) */ #define BS_VolID32 67 /* FAT32: Volume serial number (DWORD) */ #define BS_VolLab32 71 /* FAT32: Volume label string (8-byte) */ -#define BS_FilSysType32 82 /* FAT32: File system type string (8-byte) */ +#define BS_FilSysType32 82 /* FAT32: Filesystem type string (8-byte) */ #define BS_BootCode32 90 /* FAT32: Boot code (420-byte) */ #define BPB_ZeroedEx 11 /* exFAT: MBZ field (53-byte) */ @@ -440,19 +140,60 @@ typedef struct { #define BPB_FatSzEx 84 /* exFAT: FAT size [sector] (DWORD) */ #define BPB_DataOfsEx 88 /* exFAT: Data offset from top of the volume [sector] (DWORD) */ #define BPB_NumClusEx 92 /* exFAT: Number of clusters (DWORD) */ -#define BPB_RootClusEx 96 /* exFAT: Root directory cluster (DWORD) */ +#define BPB_RootClusEx 96 /* exFAT: Root directory start cluster (DWORD) */ #define BPB_VolIDEx 100 /* exFAT: Volume serial number (DWORD) */ -#define BPB_FSVerEx 104 /* exFAT: File system version (WORD) */ -#define BPB_VolFlagEx 106 /* exFAT: Volume flags (BYTE) */ -#define BPB_ActFatEx 107 /* exFAT: Active FAT flags (BYTE) */ -#define BPB_BytsPerSecEx 108 /* exFAT: Log2 of sector size in byte (BYTE) */ -#define BPB_SecPerClusEx 109 /* exFAT: Log2 of cluster size in sector (BYTE) */ +#define BPB_FSVerEx 104 /* exFAT: Filesystem version (WORD) */ +#define BPB_VolFlagEx 106 /* exFAT: Volume flags (WORD) */ +#define BPB_BytsPerSecEx 108 /* exFAT: Log2 of sector size in unit of byte (BYTE) */ +#define BPB_SecPerClusEx 109 /* exFAT: Log2 of cluster size in unit of sector (BYTE) */ #define BPB_NumFATsEx 110 /* exFAT: Number of FATs (BYTE) */ #define BPB_DrvNumEx 111 /* exFAT: Physical drive number for int13h (BYTE) */ #define BPB_PercInUseEx 112 /* exFAT: Percent in use (BYTE) */ #define BPB_RsvdEx 113 /* exFAT: Reserved (7-byte) */ #define BS_BootCodeEx 120 /* exFAT: Boot code (390-byte) */ +#define DIR_Name 0 /* Short file name (11-byte) */ +#define DIR_Attr 11 /* Attribute (BYTE) */ +#define DIR_NTres 12 /* Lower case flag (BYTE) */ +#define DIR_CrtTime10 13 /* Created time sub-second (BYTE) */ +#define DIR_CrtTime 14 /* Created time (DWORD) */ +#define DIR_LstAccDate 18 /* Last accessed date (WORD) */ +#define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (WORD) */ +#define DIR_ModTime 22 /* Modified time (DWORD) */ +#define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (WORD) */ +#define DIR_FileSize 28 /* File size (DWORD) */ +#define LDIR_Ord 0 /* LFN: LFN order and LLE flag (BYTE) */ +#define LDIR_Attr 11 /* LFN: LFN attribute (BYTE) */ +#define LDIR_Type 12 /* LFN: Entry type (BYTE) */ +#define LDIR_Chksum 13 /* LFN: Checksum of the SFN (BYTE) */ +#define LDIR_FstClusLO 26 /* LFN: MBZ field (WORD) */ +#define XDIR_Type 0 /* exFAT: Type of exFAT directory entry (BYTE) */ +#define XDIR_NumLabel 1 /* exFAT: Number of volume label characters (BYTE) */ +#define XDIR_Label 2 /* exFAT: Volume label (11-WORD) */ +#define XDIR_CaseSum 4 /* exFAT: Sum of case conversion table (DWORD) */ +#define XDIR_NumSec 1 /* exFAT: Number of secondary entries (BYTE) */ +#define XDIR_SetSum 2 /* exFAT: Sum of the set of directory entries (WORD) */ +#define XDIR_Attr 4 /* exFAT: File attribute (WORD) */ +#define XDIR_CrtTime 8 /* exFAT: Created time (DWORD) */ +#define XDIR_ModTime 12 /* exFAT: Modified time (DWORD) */ +#define XDIR_AccTime 16 /* exFAT: Last accessed time (DWORD) */ +#define XDIR_CrtTime10 20 /* exFAT: Created time subsecond (BYTE) */ +#define XDIR_ModTime10 21 /* exFAT: Modified time subsecond (BYTE) */ +#define XDIR_CrtTZ 22 /* exFAT: Created timezone (BYTE) */ +#define XDIR_ModTZ 23 /* exFAT: Modified timezone (BYTE) */ +#define XDIR_AccTZ 24 /* exFAT: Last accessed timezone (BYTE) */ +#define XDIR_GenFlags 33 /* exFAT: General secondary flags (BYTE) */ +#define XDIR_NumName 35 /* exFAT: Number of file name characters (BYTE) */ +#define XDIR_NameHash 36 /* exFAT: Hash of file name (WORD) */ +#define XDIR_ValidFileSize 40 /* exFAT: Valid file size (QWORD) */ +#define XDIR_FstClus 52 /* exFAT: First cluster of the file data (DWORD) */ +#define XDIR_FileSize 56 /* exFAT: File/Directory size (QWORD) */ + +#define SZDIRE 32 /* Size of a directory entry */ +#define DDEM 0xE5 /* Deleted directory entry mark set to DIR_Name[0] */ +#define RDDEM 0x05 /* Replacement of the character collides with DDEM */ +#define LLEF 0x40 /* Last long entry flag in LDIR_Ord */ + #define FSI_LeadSig 0 /* FAT32 FSI: Leading signature (DWORD) */ #define FSI_StrucSig 484 /* FAT32 FSI: Structure signature (DWORD) */ #define FSI_Free_Count 488 /* FAT32 FSI: Number of free clusters (DWORD) */ @@ -471,49 +212,216 @@ typedef struct { #define PTE_StLba 8 /* MBR PTE: Start in LBA */ #define PTE_SizLba 12 /* MBR PTE: Size in LBA */ -#define DIR_Name 0 /* Short file name (11-byte) */ -#define DIR_Attr 11 /* Attribute (BYTE) */ -#define DIR_NTres 12 /* Lower case flag (BYTE) */ -#define DIR_CrtTime10 13 /* Created time sub-second (BYTE) */ -#define DIR_CrtTime 14 /* Created time (DWORD) */ -#define DIR_LstAccDate 18 /* Last accessed date (WORD) */ -#define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (WORD) */ -#define DIR_ModTime 22 /* Modified time (DWORD) */ -#define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (WORD) */ -#define DIR_FileSize 28 /* File size (DWORD) */ -#define LDIR_Ord 0 /* LFN entry order and LLE flag (BYTE) */ -#define LDIR_Attr 11 /* LFN attribute (BYTE) */ -#define LDIR_Type 12 /* LFN type (BYTE) */ -#define LDIR_Chksum 13 /* Checksum of the SFN entry (BYTE) */ -#define LDIR_FstClusLO 26 /* Must be zero (WORD) */ -#define XDIR_Type 0 /* Type of exFAT directory entry (BYTE) */ -#define XDIR_NumLabel 1 /* Number of volume label characters (BYTE) */ -#define XDIR_Label 2 /* Volume label (11-WORD) */ -#define XDIR_CaseSum 4 /* Sum of case conversion table (DWORD) */ -#define XDIR_NumSec 1 /* Number of secondary entries (BYTE) */ -#define XDIR_SetSum 2 /* Sum of the set of directory entries (WORD) */ -#define XDIR_Attr 4 /* File attribute (WORD) */ -#define XDIR_CrtTime 8 /* Created time (DWORD) */ -#define XDIR_ModTime 12 /* Modified time (DWORD) */ -#define XDIR_AccTime 16 /* Last accessed time (DWORD) */ -#define XDIR_CrtTime10 20 /* Created time subsecond (BYTE) */ -#define XDIR_ModTime10 21 /* Modified time subsecond (BYTE) */ -#define XDIR_CrtTZ 22 /* Created timezone (BYTE) */ -#define XDIR_ModTZ 23 /* Modified timezone (BYTE) */ -#define XDIR_AccTZ 24 /* Last accessed timezone (BYTE) */ -#define XDIR_GenFlags 33 /* Gneral secondary flags (WORD) */ -#define XDIR_NumName 35 /* Number of file name characters (BYTE) */ -#define XDIR_NameHash 36 /* Hash of file name (WORD) */ -#define XDIR_ValidFileSize 40 /* Valid file size (QWORD) */ -#define XDIR_FstClus 52 /* First cluster of the file data (DWORD) */ -#define XDIR_FileSize 56 /* File/Directory size (QWORD) */ -#define SZDIRE 32 /* Size of a directory entry */ -#define LLEF 0x40 /* Last long entry flag in LDIR_Ord */ -#define DDEM 0xE5 /* Deleted directory entry mark set to DIR_Name[0] */ -#define RDDEM 0x05 /* Replacement of the character collides with DDEM */ +/* Post process on fatal error in the file operations */ +#define ABORT(fs, res) { fp->err = (BYTE)(res); LEAVE_FF(fs, res); } +/* Re-entrancy related */ +#if FF_FS_REENTRANT +#if FF_USE_LFN == 1 +#error Static LFN work area cannot be used at thread-safe configuration +#endif +#define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; } +#else +#define LEAVE_FF(fs, res) return res +#endif + + +/* Definitions of volume - physical location conversion */ +#if FF_MULTI_PARTITION +#define LD2PT(fs) (fs->part) /* Get partition index */ +#else +#define LD2PT(fs) 0 /* Find first valid partition or in SFD */ +#endif + + +/* Definitions of sector size */ +#if (FF_MAX_SS < FF_MIN_SS) || (FF_MAX_SS != 512 && FF_MAX_SS != 1024 && FF_MAX_SS != 2048 && FF_MAX_SS != 4096) || (FF_MIN_SS != 512 && FF_MIN_SS != 1024 && FF_MIN_SS != 2048 && FF_MIN_SS != 4096) +#error Wrong sector size configuration +#endif +#if FF_MAX_SS == FF_MIN_SS +#define SS(fs) ((UINT)FF_MAX_SS) /* Fixed sector size */ +#else +#define SS(fs) ((fs)->ssize) /* Variable sector size */ +#endif + + +/* Timestamp */ +#if FF_FS_NORTC == 1 +#if FF_NORTC_YEAR < 1980 || FF_NORTC_YEAR > 2107 || FF_NORTC_MON < 1 || FF_NORTC_MON > 12 || FF_NORTC_MDAY < 1 || FF_NORTC_MDAY > 31 +#error Invalid FF_FS_NORTC settings +#endif +#define GET_FATTIME() ((DWORD)(FF_NORTC_YEAR - 1980) << 25 | (DWORD)FF_NORTC_MON << 21 | (DWORD)FF_NORTC_MDAY << 16) +#else +#define GET_FATTIME() get_fattime() +#endif + + +/* File lock controls */ +#if FF_FS_LOCK != 0 +#if FF_FS_READONLY +#error FF_FS_LOCK must be 0 at read-only configuration +#endif +typedef struct { + FATFS *fs; /* Object ID 1, volume (NULL:blank entry) */ + DWORD clu; /* Object ID 2, containing directory (0:root) */ + DWORD ofs; /* Object ID 3, offset in the directory */ + WORD ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ +} FILESEM; +#endif + + +/* SBCS up-case tables (\x80-\xFF) */ +#define TBL_CT437 {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ + 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT720 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT737 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \ + 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xEF,0xF5,0xF0,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT771 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDC,0xDE,0xDE, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFE,0xFF} +#define TBL_CT775 {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F, \ + 0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT850 {0x43,0x55,0x45,0x41,0x41,0x41,0x41,0x43,0x45,0x45,0x45,0x49,0x49,0x49,0x41,0x41, \ + 0x45,0x92,0x92,0x4F,0x4F,0x4F,0x55,0x55,0x59,0x4F,0x55,0x4F,0x9C,0x4F,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0x41,0x41,0x41,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0x41,0x41,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD1,0xD1,0x45,0x45,0x45,0x49,0x49,0x49,0x49,0xD9,0xDA,0xDB,0xDC,0xDD,0x49,0xDF, \ + 0x4F,0xE1,0x4F,0x4F,0x4F,0x4F,0xE6,0xE8,0xE8,0x55,0x55,0x55,0x59,0x59,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT852 {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0xAC, \ + 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF} +#define TBL_CT855 {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F, \ + 0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \ + 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \ + 0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF, \ + 0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT857 {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x49,0x8E,0x8F, \ + 0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \ + 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0x49,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT860 {0x80,0x9A,0x90,0x8F,0x8E,0x91,0x86,0x80,0x89,0x89,0x92,0x8B,0x8C,0x98,0x8E,0x8F, \ + 0x90,0x91,0x92,0x8C,0x99,0xA9,0x96,0x9D,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x86,0x8B,0x9F,0x96,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT861 {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x8B,0x8B,0x8D,0x8E,0x8F, \ + 0x90,0x92,0x92,0x4F,0x99,0x8D,0x55,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ + 0xA4,0xA5,0xA6,0xA7,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT862 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT863 {0x43,0x55,0x45,0x41,0x41,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x41,0x8F, \ + 0x45,0x45,0x45,0x4F,0x45,0x49,0x55,0x55,0x98,0x4F,0x55,0x9B,0x9C,0x55,0x55,0x9F, \ + 0xA0,0xA1,0x4F,0x55,0xA4,0xA5,0xA6,0xA7,0x49,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT864 {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ + 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT865 {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ + 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT866 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT869 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x86,0x9C,0x8D,0x8F,0x90, \ + 0x91,0x90,0x92,0x95,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xA4,0xA5,0xA6,0xD9,0xDA,0xDB,0xDC,0xA7,0xA8,0xDF, \ + 0xA9,0xAA,0xAC,0xAD,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xCF,0xCF,0xD0,0xEF, \ + 0xF0,0xF1,0xD1,0xD2,0xD3,0xF5,0xD4,0xF7,0xF8,0xF9,0xD5,0x96,0x95,0x98,0xFE,0xFF} + + +/* DBCS code range |----- 1st byte -----| |----------- 2nd byte -----------| */ +#define TBL_DC932 {0x81, 0x9F, 0xE0, 0xFC, 0x40, 0x7E, 0x80, 0xFC, 0x00, 0x00} +#define TBL_DC936 {0x81, 0xFE, 0x00, 0x00, 0x40, 0x7E, 0x80, 0xFE, 0x00, 0x00} +#define TBL_DC949 {0x81, 0xFE, 0x00, 0x00, 0x41, 0x5A, 0x61, 0x7A, 0x81, 0xFE} +#define TBL_DC950 {0x81, 0xFE, 0x00, 0x00, 0x40, 0x7E, 0xA1, 0xFE, 0x00, 0x00} + + +/* Macros for table definitions */ +#define MERGE_2STR(a, b) a ## b +#define MKCVTBL(hd, cp) MERGE_2STR(hd, cp) + @@ -522,71 +430,140 @@ typedef struct { Module Private Work Area ---------------------------------------------------------------------------*/ - -/* Remark: Variables here without initial value shall be guaranteed zero/null -/ at start-up. If not, either the linker or start-up routine being used is +/* Remark: Variables defined here without initial value shall be guaranteed +/ zero/null at start-up. If not, the linker option or start-up routine is / not compliance with C standard. */ -#if _VOLUMES < 1 || _VOLUMES > 9 -#error Wrong _VOLUMES setting -#endif -static WORD Fsid; /* File system mount ID */ +/*--------------------------------*/ +/* File/Volume controls */ +/*--------------------------------*/ -#if _FS_LOCK != 0 -static FILESEM Files[_FS_LOCK]; /* Open object lock semaphores */ +#if FF_VOLUMES < 1 || FF_VOLUMES > 10 +#error Wrong FF_VOLUMES setting +#endif +static WORD Fsid; /* Filesystem mount ID */ + +#if FF_FS_LOCK != 0 +static FILESEM Files[FF_FS_LOCK]; /* Open object lock semaphores */ #endif -#if _USE_LFN == 0 /* Non-LFN configuration */ +#if FF_STR_VOLUME_ID +#ifdef FF_VOLUME_STRS +static const char* const VolumeStr[FF_VOLUMES] = {FF_VOLUME_STRS}; /* Pre-defined volume ID */ +#endif +#endif + + +/*--------------------------------*/ +/* LFN/Directory working buffer */ +/*--------------------------------*/ + +#if FF_USE_LFN == 0 /* Non-LFN configuration */ +#if FF_FS_EXFAT +#error LFN must be enabled when enable exFAT +#endif #define DEF_NAMBUF #define INIT_NAMBUF(fs) #define FREE_NAMBUF() -#else -#if _MAX_LFN < 12 || _MAX_LFN > 255 -#error Wrong _MAX_LFN setting -#endif +#define LEAVE_MKFS(res) return res -#if _USE_LFN == 1 /* LFN enabled with static working buffer */ -#if _FS_EXFAT -static BYTE DirBuf[SZDIRE*19]; /* Directory entry block scratchpad buffer (19 entries in size) */ +#else /* LFN configurations */ +#if FF_MAX_LFN < 12 || FF_MAX_LFN > 255 +#error Wrong setting of FF_MAX_LFN #endif -static WCHAR LfnBuf[_MAX_LFN+1]; /* LFN enabled with static working buffer */ +#if FF_LFN_BUF < FF_SFN_BUF || FF_SFN_BUF < 12 +#error Wrong setting of FF_LFN_BUF or FF_SFN_BUF +#endif +#if FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3 +#error Wrong setting of FF_LFN_UNICODE +#endif +static const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* FAT: Offset of LFN characters in the directory entry */ +#define MAXDIRB(nc) ((nc + 44U) / 15 * SZDIRE) /* exFAT: Size of directory entry block scratchpad buffer needed for the name length */ + +#if FF_USE_LFN == 1 /* LFN enabled with static working buffer */ +#if FF_FS_EXFAT +static BYTE DirBuf[MAXDIRB(FF_MAX_LFN)]; /* Directory entry block scratchpad buffer */ +#endif +static WCHAR LfnBuf[FF_MAX_LFN + 1]; /* LFN working buffer */ #define DEF_NAMBUF #define INIT_NAMBUF(fs) #define FREE_NAMBUF() +#define LEAVE_MKFS(res) return res -#elif _USE_LFN == 2 /* LFN enabled with dynamic working buffer on the stack */ -#if _FS_EXFAT -#define DEF_NAMBUF WCHAR lbuf[_MAX_LFN+1]; BYTE dbuf[SZDIRE*19]; +#elif FF_USE_LFN == 2 /* LFN enabled with dynamic working buffer on the stack */ +#if FF_FS_EXFAT +#define DEF_NAMBUF WCHAR lbuf[FF_MAX_LFN+1]; BYTE dbuf[MAXDIRB(FF_MAX_LFN)]; /* LFN working buffer and directory entry block scratchpad buffer */ #define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; (fs)->dirbuf = dbuf; } #define FREE_NAMBUF() #else -#define DEF_NAMBUF WCHAR lbuf[_MAX_LFN+1]; +#define DEF_NAMBUF WCHAR lbuf[FF_MAX_LFN+1]; /* LFN working buffer */ #define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; } #define FREE_NAMBUF() #endif +#define LEAVE_MKFS(res) return res -#elif _USE_LFN == 3 /* LFN enabled with dynamic working buffer on the heap */ -#if _FS_EXFAT -#define DEF_NAMBUF WCHAR *lfn; -#define INIT_NAMBUF(fs) { lfn = ff_memalloc((_MAX_LFN+1)*2 + SZDIRE*19); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; (fs)->dirbuf = (BYTE*)(lfn+_MAX_LFN+1); } +#elif FF_USE_LFN == 3 /* LFN enabled with dynamic working buffer on the heap */ +#if FF_FS_EXFAT +#define DEF_NAMBUF WCHAR *lfn; /* Pointer to LFN working buffer and directory entry block scratchpad buffer */ +#define INIT_NAMBUF(fs) { lfn = ff_memalloc((FF_MAX_LFN+1)*2 + MAXDIRB(FF_MAX_LFN)); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; (fs)->dirbuf = (BYTE*)(lfn+FF_MAX_LFN+1); } #define FREE_NAMBUF() ff_memfree(lfn) #else -#define DEF_NAMBUF WCHAR *lfn; -#define INIT_NAMBUF(fs) { lfn = ff_memalloc((_MAX_LFN+1)*2); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; } +#define DEF_NAMBUF WCHAR *lfn; /* Pointer to LFN working buffer */ +#define INIT_NAMBUF(fs) { lfn = ff_memalloc((FF_MAX_LFN+1)*2); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; } #define FREE_NAMBUF() ff_memfree(lfn) #endif +#define LEAVE_MKFS(res) { if (!work) ff_memfree(buf); return res; } +#define MAX_MALLOC 0x8000 /* Must be >=FF_MAX_SS */ #else -#error Wrong _USE_LFN setting -#endif -#endif +#error Wrong setting of FF_USE_LFN -#ifdef _EXCVT -static const BYTE ExCvt[] = _EXCVT; /* Upper conversion table for SBCS extended characters */ -#endif +#endif /* FF_USE_LFN == 1 */ +#endif /* FF_USE_LFN == 0 */ +/*--------------------------------*/ +/* Code conversion tables */ +/*--------------------------------*/ + +#if FF_CODE_PAGE == 0 /* Run-time code page configuration */ +#define CODEPAGE CodePage +static WORD CodePage; /* Current code page */ +static const BYTE *ExCvt, *DbcTbl; /* Pointer to current SBCS up-case table and DBCS code range table below */ + +static const BYTE Ct437[] = TBL_CT437; +static const BYTE Ct720[] = TBL_CT720; +static const BYTE Ct737[] = TBL_CT737; +static const BYTE Ct771[] = TBL_CT771; +static const BYTE Ct775[] = TBL_CT775; +static const BYTE Ct850[] = TBL_CT850; +static const BYTE Ct852[] = TBL_CT852; +static const BYTE Ct855[] = TBL_CT855; +static const BYTE Ct857[] = TBL_CT857; +static const BYTE Ct860[] = TBL_CT860; +static const BYTE Ct861[] = TBL_CT861; +static const BYTE Ct862[] = TBL_CT862; +static const BYTE Ct863[] = TBL_CT863; +static const BYTE Ct864[] = TBL_CT864; +static const BYTE Ct865[] = TBL_CT865; +static const BYTE Ct866[] = TBL_CT866; +static const BYTE Ct869[] = TBL_CT869; +static const BYTE Dc932[] = TBL_DC932; +static const BYTE Dc936[] = TBL_DC936; +static const BYTE Dc949[] = TBL_DC949; +static const BYTE Dc950[] = TBL_DC950; + +#elif FF_CODE_PAGE < 900 /* Static code page configuration (SBCS) */ +#define CODEPAGE FF_CODE_PAGE +static const BYTE ExCvt[] = MKCVTBL(TBL_CT, FF_CODE_PAGE); + +#else /* Static code page configuration (DBCS) */ +#define CODEPAGE FF_CODE_PAGE +static const BYTE DbcTbl[] = MKCVTBL(TBL_DC, FF_CODE_PAGE); + +#endif + @@ -601,8 +578,7 @@ static const BYTE ExCvt[] = _EXCVT; /* Upper conversion table for SBCS extended /* Load/Store multi-byte word in the FAT structure */ /*-----------------------------------------------------------------------*/ -static -WORD ld_word (const BYTE* ptr) /* Load a 2-byte little-endian word */ +static WORD ld_word (const BYTE* ptr) /* Load a 2-byte little-endian word */ { WORD rv; @@ -611,8 +587,7 @@ WORD ld_word (const BYTE* ptr) /* Load a 2-byte little-endian word */ return rv; } -static -DWORD ld_dword (const BYTE* ptr) /* Load a 4-byte little-endian word */ +static DWORD ld_dword (const BYTE* ptr) /* Load a 4-byte little-endian word */ { DWORD rv; @@ -623,9 +598,8 @@ DWORD ld_dword (const BYTE* ptr) /* Load a 4-byte little-endian word */ return rv; } -#if _FS_EXFAT -static -QWORD ld_qword (const BYTE* ptr) /* Load an 8-byte little-endian word */ +#if FF_FS_EXFAT +static QWORD ld_qword (const BYTE* ptr) /* Load an 8-byte little-endian word */ { QWORD rv; @@ -641,16 +615,14 @@ QWORD ld_qword (const BYTE* ptr) /* Load an 8-byte little-endian word */ } #endif -#if !_FS_READONLY -static -void st_word (BYTE* ptr, WORD val) /* Store a 2-byte word in little-endian */ +#if !FF_FS_READONLY +static void st_word (BYTE* ptr, WORD val) /* Store a 2-byte word in little-endian */ { *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; } -static -void st_dword (BYTE* ptr, DWORD val) /* Store a 4-byte word in little-endian */ +static void st_dword (BYTE* ptr, DWORD val) /* Store a 4-byte word in little-endian */ { *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; @@ -658,9 +630,8 @@ void st_dword (BYTE* ptr, DWORD val) /* Store a 4-byte word in little-endian *ptr++ = (BYTE)val; } -#if _FS_EXFAT -static -void st_qword (BYTE* ptr, QWORD val) /* Store an 8-byte word in little-endian */ +#if FF_FS_EXFAT +static void st_qword (BYTE* ptr, QWORD val) /* Store an 8-byte word in little-endian */ { *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; @@ -672,7 +643,7 @@ void st_qword (BYTE* ptr, QWORD val) /* Store an 8-byte word in little-endian *ptr++ = (BYTE)val; } #endif -#endif /* !_FS_READONLY */ +#endif /* !FF_FS_READONLY */ @@ -687,32 +658,232 @@ void st_qword (BYTE* ptr, QWORD val) /* Store an 8-byte word in little-endian #define mem_set memset #define mem_cmp memcmp + /* Check if chr is contained in the string */ -static -int chk_chr (const char* str, int chr) { /* NZ:contained, ZR:not contained */ +static int chk_chr (const char* str, int chr) /* NZ:contained, ZR:not contained */ +{ while (*str && *str != chr) str++; return *str; } +/* Test if the character is DBC 1st byte */ +static int dbc_1st (BYTE c) +{ +#if FF_CODE_PAGE == 0 /* Variable code page */ + if (DbcTbl && c >= DbcTbl[0]) { + if (c <= DbcTbl[1]) return 1; /* 1st byte range 1 */ + if (c >= DbcTbl[2] && c <= DbcTbl[3]) return 1; /* 1st byte range 2 */ + } +#elif FF_CODE_PAGE >= 900 /* DBCS fixed code page */ + if (c >= DbcTbl[0]) { + if (c <= DbcTbl[1]) return 1; + if (c >= DbcTbl[2] && c <= DbcTbl[3]) return 1; + } +#else /* SBCS fixed code page */ + if (c != 0) return 0; /* Always false */ +#endif + return 0; +} -#if _FS_REENTRANT +/* Test if the character is DBC 2nd byte */ +static int dbc_2nd (BYTE c) +{ +#if FF_CODE_PAGE == 0 /* Variable code page */ + if (DbcTbl && c >= DbcTbl[4]) { + if (c <= DbcTbl[5]) return 1; /* 2nd byte range 1 */ + if (c >= DbcTbl[6] && c <= DbcTbl[7]) return 1; /* 2nd byte range 2 */ + if (c >= DbcTbl[8] && c <= DbcTbl[9]) return 1; /* 2nd byte range 3 */ + } +#elif FF_CODE_PAGE >= 900 /* DBCS fixed code page */ + if (c >= DbcTbl[4]) { + if (c <= DbcTbl[5]) return 1; + if (c >= DbcTbl[6] && c <= DbcTbl[7]) return 1; + if (c >= DbcTbl[8] && c <= DbcTbl[9]) return 1; + } +#else /* SBCS fixed code page */ + if (c != 0) return 0; /* Always false */ +#endif + return 0; +} + + +#if FF_USE_LFN + +/* Get a character from TCHAR string in defined API encodeing */ +static DWORD tchar2uni ( /* Returns character in UTF-16 encoding (>=0x10000 on double encoding unit, 0xFFFFFFFF on decode error) */ + const TCHAR** str /* Pointer to pointer to TCHAR string in configured encoding */ +) +{ + DWORD uc; + const TCHAR *p = *str; + +#if FF_LFN_UNICODE == 1 /* UTF-16 input */ + WCHAR wc; + + uc = *p++; /* Get a unit */ + if (IsSurrogate(uc)) { /* Surrogate? */ + wc = *p++; /* Get low surrogate */ + if (!IsSurrogateH(uc) || !IsSurrogateL(wc)) return 0xFFFFFFFF; /* Wrong surrogate? */ + uc = uc << 16 | wc; + } + +#elif FF_LFN_UNICODE == 2 /* UTF-8 input */ + BYTE b; + int nf; + + uc = (BYTE)*p++; /* Get a unit */ + if (uc & 0x80) { /* Multiple byte code? */ + if ((uc & 0xE0) == 0xC0) { /* 2-byte sequence? */ + uc &= 0x1F; nf = 1; + } else { + if ((uc & 0xF0) == 0xE0) { /* 3-byte sequence? */ + uc &= 0x0F; nf = 2; + } else { + if ((uc & 0xF8) == 0xF0) { /* 4-byte sequence? */ + uc &= 0x07; nf = 3; + } else { /* Wrong sequence */ + return 0xFFFFFFFF; + } + } + } + do { /* Get trailing bytes */ + b = (BYTE)*p++; + if ((b & 0xC0) != 0x80) return 0xFFFFFFFF; /* Wrong sequence? */ + uc = uc << 6 | (b & 0x3F); + } while (--nf != 0); + if (uc < 0x80 || IsSurrogate(uc) || uc >= 0x110000) return 0xFFFFFFFF; /* Wrong code? */ + if (uc >= 0x010000) uc = 0xD800DC00 | ((uc - 0x10000) << 6 & 0x3FF0000) | (uc & 0x3FF); /* Make a surrogate pair if needed */ + } + +#elif FF_LFN_UNICODE == 3 /* UTF-32 input */ + uc = (TCHAR)*p++; /* Get a unit */ + if (uc >= 0x110000) return 0xFFFFFFFF; /* Wrong code? */ + if (uc >= 0x010000) uc = 0xD800DC00 | ((uc - 0x10000) << 6 & 0x3FF0000) | (uc & 0x3FF); /* Make a surrogate pair if needed */ + +#else /* ANSI/OEM input */ + BYTE b; + WCHAR wc; + + wc = (BYTE)*p++; /* Get a byte */ + if (dbc_1st((BYTE)wc)) { /* Is it a DBC 1st byte? */ + b = (BYTE)*p++; /* Get 2nd byte */ + if (!dbc_2nd(b)) return 0xFFFFFFFF; /* Invalid code? */ + wc = (wc << 8) + b; /* Make a DBC */ + } + if (wc != 0) { + wc = ff_oem2uni(wc, CODEPAGE); /* ANSI/OEM ==> Unicode */ + if (wc == 0) return 0xFFFFFFFF; /* Invalid code? */ + } + uc = wc; + +#endif + *str = p; /* Next read pointer */ + return uc; +} + + +/* Output a TCHAR string in defined API encoding */ +static BYTE put_utf ( /* Returns number of encoding units written (0:buffer overflow or wrong encoding) */ + DWORD chr, /* UTF-16 encoded character (Double encoding unit char if >=0x10000) */ + TCHAR* buf, /* Output buffer */ + UINT szb /* Size of the buffer */ +) +{ +#if FF_LFN_UNICODE == 1 /* UTF-16 output */ + WCHAR hs, wc; + + hs = (WCHAR)(chr >> 16); + wc = (WCHAR)chr; + if (hs == 0) { /* Single encoding unit? */ + if (szb < 1 || IsSurrogate(wc)) return 0; /* Buffer overflow or wrong code? */ + *buf = wc; + return 1; + } + if (szb < 2 || !IsSurrogateH(hs) || !IsSurrogateL(wc)) return 0; /* Buffer overflow or wrong surrogate? */ + *buf++ = hs; + *buf++ = wc; + return 2; + +#elif FF_LFN_UNICODE == 2 /* UTF-8 output */ + DWORD hc; + + if (chr < 0x80) { /* Single byte code? */ + if (szb < 1) return 0; /* Buffer overflow? */ + *buf = (TCHAR)chr; + return 1; + } + if (chr < 0x800) { /* 2-byte sequence? */ + if (szb < 2) return 0; /* Buffer overflow? */ + *buf++ = (TCHAR)(0xC0 | (chr >> 6 & 0x1F)); + *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F)); + return 2; + } + if (chr < 0x10000) { /* 3-byte sequence? */ + if (szb < 3 || IsSurrogate(chr)) return 0; /* Buffer overflow or wrong code? */ + *buf++ = (TCHAR)(0xE0 | (chr >> 12 & 0x0F)); + *buf++ = (TCHAR)(0x80 | (chr >> 6 & 0x3F)); + *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F)); + return 3; + } + /* 4-byte sequence */ + if (szb < 4) return 0; /* Buffer overflow? */ + hc = ((chr & 0xFFFF0000) - 0xD8000000) >> 6; /* Get high 10 bits */ + chr = (chr & 0xFFFF) - 0xDC00; /* Get low 10 bits */ + if (hc >= 0x100000 || chr >= 0x400) return 0; /* Wrong surrogate? */ + chr = (hc | chr) + 0x10000; + *buf++ = (TCHAR)(0xF0 | (chr >> 18 & 0x07)); + *buf++ = (TCHAR)(0x80 | (chr >> 12 & 0x3F)); + *buf++ = (TCHAR)(0x80 | (chr >> 6 & 0x3F)); + *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F)); + return 4; + +#elif FF_LFN_UNICODE == 3 /* UTF-32 output */ + DWORD hc; + + if (szb < 1) return 0; /* Buffer overflow? */ + if (chr >= 0x10000) { /* Out of BMP? */ + hc = ((chr & 0xFFFF0000) - 0xD8000000) >> 6; /* Get high 10 bits */ + chr = (chr & 0xFFFF) - 0xDC00; /* Get low 10 bits */ + if (hc >= 0x100000 || chr >= 0x400) return 0; /* Wrong surrogate? */ + chr = (hc | chr) + 0x10000; + } + *buf++ = (TCHAR)chr; + return 1; + +#else /* ANSI/OEM output */ + WCHAR wc; + + wc = ff_uni2oem(chr, CODEPAGE); + if (wc >= 0x100) { /* Is this a DBC? */ + if (szb < 2) return 0; + *buf++ = (char)(wc >> 8); /* Store DBC 1st byte */ + *buf++ = (TCHAR)wc; /* Store DBC 2nd byte */ + return 2; + } + if (wc == 0 || szb < 1) return 0; /* Invalid char or buffer overflow? */ + *buf++ = (TCHAR)wc; /* Store the character */ + return 1; +#endif +} +#endif /* FF_USE_LFN */ + + +#if FF_FS_REENTRANT /*-----------------------------------------------------------------------*/ /* Request/Release grant to access the volume */ /*-----------------------------------------------------------------------*/ -static -int lock_fs ( - FATFS* fs /* File system object */ +static int lock_fs ( /* 1:Ok, 0:timeout */ + FATFS* fs /* Filesystem object */ ) { return ff_req_grant(fs->sobj); } -static -void unlock_fs ( - FATFS* fs, /* File system object */ +static void unlock_fs ( + FATFS* fs, /* Filesystem object */ FRESULT res /* Result code to be returned */ ) { @@ -725,50 +896,48 @@ void unlock_fs ( -#if _FS_LOCK != 0 +#if FF_FS_LOCK != 0 /*-----------------------------------------------------------------------*/ /* File lock control functions */ /*-----------------------------------------------------------------------*/ -static -FRESULT chk_lock ( /* Check if the file can be accessed */ +static FRESULT chk_lock ( /* Check if the file can be accessed */ DIR* dp, /* Directory object pointing the file to be checked */ - int acc /* Desired access type (0:Read, 1:Write, 2:Delete/Rename) */ + int acc /* Desired access type (0:Read mode open, 1:Write mode open, 2:Delete or rename) */ ) { UINT i, be; - /* Search file semaphore table */ - for (i = be = 0; i < _FS_LOCK; i++) { + /* Search open object table for the object */ + be = 0; + for (i = 0; i < FF_FS_LOCK; i++) { if (Files[i].fs) { /* Existing entry */ - if (Files[i].fs == dp->obj.fs && /* Check if the object matched with an open object */ + if (Files[i].fs == dp->obj.fs && /* Check if the object matches with an open object */ Files[i].clu == dp->obj.sclust && Files[i].ofs == dp->dptr) break; } else { /* Blank entry */ be = 1; } } - if (i == _FS_LOCK) { /* The object is not opened */ - return (be || acc == 2) ? FR_OK : FR_TOO_MANY_OPEN_FILES; /* Is there a blank entry for new object? */ + if (i == FF_FS_LOCK) { /* The object has not been opened */ + return (!be && acc != 2) ? FR_TOO_MANY_OPEN_FILES : FR_OK; /* Is there a blank entry for new object? */ } - /* The object has been opened. Reject any open against writing file and all write mode open */ - return (acc || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK; + /* The object was opened. Reject any open against writing file and all write mode open */ + return (acc != 0 || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK; } -static -int enq_lock (void) /* Check if an entry is available for a new object */ +static int enq_lock (void) /* Check if an entry is available for a new object */ { UINT i; - for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ; - return (i == _FS_LOCK) ? 0 : 1; + for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; + return (i == FF_FS_LOCK) ? 0 : 1; } -static -UINT inc_lock ( /* Increment object open counter and returns its index (0:Internal error) */ +static UINT inc_lock ( /* Increment object open counter and returns its index (0:Internal error) */ DIR* dp, /* Directory object pointing the file to register or increment */ int acc /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */ ) @@ -776,31 +945,30 @@ UINT inc_lock ( /* Increment object open counter and returns its index (0:Intern UINT i; - for (i = 0; i < _FS_LOCK; i++) { /* Find the object */ + for (i = 0; i < FF_FS_LOCK; i++) { /* Find the object */ if (Files[i].fs == dp->obj.fs && Files[i].clu == dp->obj.sclust && Files[i].ofs == dp->dptr) break; } - if (i == _FS_LOCK) { /* Not opened. Register it as new. */ - for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ; - if (i == _FS_LOCK) return 0; /* No free entry to register (int err) */ + if (i == FF_FS_LOCK) { /* Not opened. Register it as new. */ + for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; + if (i == FF_FS_LOCK) return 0; /* No free entry to register (int err) */ Files[i].fs = dp->obj.fs; Files[i].clu = dp->obj.sclust; Files[i].ofs = dp->dptr; Files[i].ctr = 0; } - if (acc && Files[i].ctr) return 0; /* Access violation (int err) */ + if (acc >= 1 && Files[i].ctr) return 0; /* Access violation (int err) */ Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1; /* Set semaphore value */ - return i + 1; + return i + 1; /* Index number origin from 1 */ } -static -FRESULT dec_lock ( /* Decrement object open counter */ +static FRESULT dec_lock ( /* Decrement object open counter */ UINT i /* Semaphore index (1..) */ ) { @@ -808,7 +976,7 @@ FRESULT dec_lock ( /* Decrement object open counter */ FRESULT res; - if (--i < _FS_LOCK) { /* Shift index number origin from 0 */ + if (--i < FF_FS_LOCK) { /* Index number origin from 0 */ n = Files[i].ctr; if (n == 0x100) n = 0; /* If write mode open, delete the entry */ if (n > 0) n--; /* Decrement read mode open count */ @@ -822,48 +990,40 @@ FRESULT dec_lock ( /* Decrement object open counter */ } -static -void clear_lock ( /* Clear lock entries of the volume */ +static void clear_lock ( /* Clear lock entries of the volume */ FATFS *fs ) { UINT i; - for (i = 0; i < _FS_LOCK; i++) { + for (i = 0; i < FF_FS_LOCK; i++) { if (Files[i].fs == fs) Files[i].fs = 0; } } -#endif /* _FS_LOCK != 0 */ +#endif /* FF_FS_LOCK != 0 */ /*-----------------------------------------------------------------------*/ -/* Move/Flush disk access window in the file system object */ +/* Move/Flush disk access window in the filesystem object */ /*-----------------------------------------------------------------------*/ -#if !_FS_READONLY -static -FRESULT sync_window ( /* Returns FR_OK or FR_DISK_ERROR */ - FATFS* fs /* File system object */ +#if !FF_FS_READONLY +static FRESULT sync_window ( /* Returns FR_OK or FR_DISK_ERR */ + FATFS* fs /* Filesystem object */ ) { - DWORD wsect; - UINT nf; FRESULT res = FR_OK; - if (fs->wflag) { /* Write back the sector if it is dirty */ - wsect = fs->winsect; /* Current sector number */ - if (disk_write(fs->drv, fs->win, wsect, 1) != RES_OK) { - res = FR_DISK_ERR; - } else { - fs->wflag = 0; - if (wsect - fs->fatbase < fs->fsize) { /* Is it in the FAT area? */ - for (nf = fs->n_fats; nf >= 2; nf--) { /* Reflect the change to all FAT copies */ - wsect += fs->fsize; - disk_write(fs->drv, fs->win, wsect, 1); - } + if (fs->wflag) { /* Is the disk access window dirty */ + if (disk_write(fs->drv, fs->win, fs->winsect, 1) == RES_OK) { /* Write back the window */ + fs->wflag = 0; /* Clear window dirty flag */ + if (fs->winsect - fs->fatbase < fs->fsize) { /* Is it in the 1st FAT? */ + if (fs->n_fats == 2) disk_write(fs->drv, fs->win, fs->winsect + fs->fsize, 1); /* Reflect it to 2nd FAT if needed */ } + } else { + res = FR_DISK_ERR; } } return res; @@ -871,9 +1031,8 @@ FRESULT sync_window ( /* Returns FR_OK or FR_DISK_ERROR */ #endif -static -FRESULT move_window ( /* Returns FR_OK or FR_DISK_ERROR */ - FATFS* fs, /* File system object */ +static FRESULT move_window ( /* Returns FR_OK or FR_DISK_ERR */ + FATFS* fs, /* Filesystem object */ DWORD sector /* Sector number to make appearance in the fs->win[] */ ) { @@ -881,12 +1040,12 @@ FRESULT move_window ( /* Returns FR_OK or FR_DISK_ERROR */ if (sector != fs->winsect) { /* Window offset changed? */ -#if !_FS_READONLY +#if !FF_FS_READONLY res = sync_window(fs); /* Write-back changes */ #endif if (res == FR_OK) { /* Fill sector window with new data */ if (disk_read(fs->drv, fs->win, sector, 1) != RES_OK) { - sector = 0xFFFFFFFF; /* Invalidate window if data is not reliable */ + sector = 0xFFFFFFFF; /* Invalidate window if read data is not valid */ res = FR_DISK_ERR; } fs->winsect = sector; @@ -898,14 +1057,13 @@ FRESULT move_window ( /* Returns FR_OK or FR_DISK_ERROR */ -#if !_FS_READONLY +#if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ -/* Synchronize file system and strage device */ +/* Synchronize filesystem and data on the storage */ /*-----------------------------------------------------------------------*/ -static -FRESULT sync_fs ( /* FR_OK:succeeded, !=0:error */ - FATFS* fs /* File system object */ +static FRESULT sync_fs ( /* Returns FR_OK or FR_DISK_ERR */ + FATFS* fs /* Filesystem object */ ) { FRESULT res; @@ -913,10 +1071,9 @@ FRESULT sync_fs ( /* FR_OK:succeeded, !=0:error */ res = sync_window(fs); if (res == FR_OK) { - /* Update FSInfo sector if needed */ - if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { + if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { /* FAT32: Update FSInfo sector if needed */ /* Create FSInfo structure */ - mem_set(fs->win, 0, SS(fs)); + mem_set(fs->win, 0, sizeof fs->win); st_word(fs->win + BS_55AA, 0xAA55); st_dword(fs->win + FSI_LeadSig, 0x41615252); st_dword(fs->win + FSI_StrucSig, 0x61417272); @@ -927,7 +1084,7 @@ FRESULT sync_fs ( /* FR_OK:succeeded, !=0:error */ disk_write(fs->drv, fs->win, fs->winsect, 1); fs->fsi_flag = 0; } - /* Make sure that no pending write process in the physical drive */ + /* Make sure that no pending write process in the lower layer */ if (disk_ioctl(fs->drv, CTRL_SYNC, 0) != RES_OK) res = FR_DISK_ERR; } @@ -939,18 +1096,17 @@ FRESULT sync_fs ( /* FR_OK:succeeded, !=0:error */ /*-----------------------------------------------------------------------*/ -/* Get sector# from cluster# */ +/* Get physical sector number from cluster number */ /*-----------------------------------------------------------------------*/ -static -DWORD clust2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */ - FATFS* fs, /* File system object */ +static DWORD clst2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */ + FATFS* fs, /* Filesystem object */ DWORD clst /* Cluster# to be converted */ ) { - clst -= 2; - if (clst >= fs->n_fatent - 2) return 0; /* Invalid cluster# */ - return clst * fs->csize + fs->database; + clst -= 2; /* Cluster number is origin from 2 */ + if (clst >= fs->n_fatent - 2) return 0; /* Is it invalid cluster number? */ + return fs->database + fs->csize * clst; /* Start sector number of the cluster */ } @@ -960,10 +1116,9 @@ DWORD clust2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */ /* FAT access - Read value of a FAT entry */ /*-----------------------------------------------------------------------*/ -static -DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluster status */ - _FDID* obj, /* Corresponding object */ - DWORD clst /* Cluster number to get the value */ +static DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluster status */ + FFOBJID* obj, /* Corresponding object */ + DWORD clst /* Cluster number to get the value */ ) { UINT wc, bc; @@ -981,44 +1136,46 @@ DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluste case FS_FAT12 : bc = (UINT)clst; bc += bc / 2; if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break; - wc = fs->win[bc++ % SS(fs)]; + wc = fs->win[bc++ % SS(fs)]; /* Get 1st byte of the entry */ if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break; - wc |= fs->win[bc % SS(fs)] << 8; - val = (clst & 1) ? (wc >> 4) : (wc & 0xFFF); + wc |= fs->win[bc % SS(fs)] << 8; /* Merge 2nd byte of the entry */ + val = (clst & 1) ? (wc >> 4) : (wc & 0xFFF); /* Adjust bit position */ break; case FS_FAT16 : if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))) != FR_OK) break; - val = ld_word(fs->win + clst * 2 % SS(fs)); + val = ld_word(fs->win + clst * 2 % SS(fs)); /* Simple WORD array */ break; case FS_FAT32 : if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; - val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x0FFFFFFF; + val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x0FFFFFFF; /* Simple DWORD array but mask out upper 4 bits */ break; -#if _FS_EXFAT +#if FF_FS_EXFAT case FS_EXFAT : - if (obj->objsize) { + if ((obj->objsize != 0 && obj->sclust != 0) || obj->stat == 0) { /* Object except root dir must have valid data length */ DWORD cofs = clst - obj->sclust; /* Offset from start cluster */ DWORD clen = (DWORD)((obj->objsize - 1) / SS(fs)) / fs->csize; /* Number of clusters - 1 */ - if (obj->stat == 2) { /* Is there no valid chain on the FAT? */ - if (cofs <= clen) { - val = (cofs == clen) ? 0x7FFFFFFF : clst + 1; /* Generate the value */ - break; - } + if (obj->stat == 2 && cofs <= clen) { /* Is it a contiguous chain? */ + val = (cofs == clen) ? 0x7FFFFFFF : clst + 1; /* No data on the FAT, generate the value */ + break; } - if (obj->stat == 3 && cofs < obj->n_cont) { /* Is it in the contiguous part? */ + if (obj->stat == 3 && cofs < obj->n_cont) { /* Is it in the 1st fragment? */ val = clst + 1; /* Generate the value */ break; } if (obj->stat != 2) { /* Get value from FAT if FAT chain is valid */ - if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; - val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x7FFFFFFF; + if (obj->n_frag != 0) { /* Is it on the growing edge? */ + val = 0x7FFFFFFF; /* Generate EOC */ + } else { + if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; + val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x7FFFFFFF; + } break; } } - /* go next */ + /* go to default */ #endif default: val = 1; /* Internal error */ @@ -1031,14 +1188,13 @@ DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluste -#if !_FS_READONLY +#if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* FAT access - Change value of a FAT entry */ /*-----------------------------------------------------------------------*/ -static -FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ - FATFS* fs, /* Corresponding file system object */ +static FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ + FATFS* fs, /* Corresponding filesystem object */ DWORD clst, /* FAT index number (cluster number) to be changed */ DWORD val /* New value to be set to the entry */ ) @@ -1050,34 +1206,34 @@ FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ if (clst >= 2 && clst < fs->n_fatent) { /* Check if in valid range */ switch (fs->fs_type) { - case FS_FAT12 : /* Bitfield items */ - bc = (UINT)clst; bc += bc / 2; + case FS_FAT12 : + bc = (UINT)clst; bc += bc / 2; /* bc: byte offset of the entry */ res = move_window(fs, fs->fatbase + (bc / SS(fs))); if (res != FR_OK) break; p = fs->win + bc++ % SS(fs); - *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val; + *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val; /* Put 1st byte */ fs->wflag = 1; res = move_window(fs, fs->fatbase + (bc / SS(fs))); if (res != FR_OK) break; p = fs->win + bc % SS(fs); - *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F)); + *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F)); /* Put 2nd byte */ fs->wflag = 1; break; - case FS_FAT16 : /* WORD aligned items */ + case FS_FAT16 : res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))); if (res != FR_OK) break; - st_word(fs->win + clst * 2 % SS(fs), (WORD)val); + st_word(fs->win + clst * 2 % SS(fs), (WORD)val); /* Simple WORD array */ fs->wflag = 1; break; - case FS_FAT32 : /* DWORD aligned items */ -#if _FS_EXFAT + case FS_FAT32 : +#if FF_FS_EXFAT case FS_EXFAT : #endif res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))); if (res != FR_OK) break; - if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) { + if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { val = (val & 0x0FFFFFFF) | (ld_dword(fs->win + clst * 4 % SS(fs)) & 0xF0000000); } st_dword(fs->win + clst * 4 % SS(fs), val); @@ -1088,23 +1244,22 @@ FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ return res; } -#endif /* !_FS_READONLY */ +#endif /* !FF_FS_READONLY */ -#if _FS_EXFAT && !_FS_READONLY +#if FF_FS_EXFAT && !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* exFAT: Accessing FAT and Allocation Bitmap */ /*-----------------------------------------------------------------------*/ -/*---------------------------------------------*/ -/* exFAT: Find a contiguous free cluster block */ -/*---------------------------------------------*/ +/*--------------------------------------*/ +/* Find a contiguous free cluster block */ +/*--------------------------------------*/ -static -DWORD find_bitmap ( /* 0:No free cluster, 2..:Free cluster found, 0xFFFFFFFF:Disk error */ - FATFS* fs, /* File system object */ +static DWORD find_bitmap ( /* 0:Not found, 2..:Cluster block found, 0xFFFFFFFF:Disk error */ + FATFS* fs, /* Filesystem object */ DWORD clst, /* Cluster number to scan from */ DWORD ncl /* Number of contiguous clusters to find (1..) */ ) @@ -1118,34 +1273,33 @@ DWORD find_bitmap ( /* 0:No free cluster, 2..:Free cluster found, 0xFFFFFFFF:Dis if (clst >= fs->n_fatent - 2) clst = 0; scl = val = clst; ctr = 0; for (;;) { - if (move_window(fs, fs->database + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; /* (assuming bitmap is located top of the cluster heap) */ + if (move_window(fs, fs->bitbase + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; i = val / 8 % SS(fs); bm = 1 << (val % 8); do { do { bv = fs->win[i] & bm; bm <<= 1; /* Get bit value */ if (++val >= fs->n_fatent - 2) { /* Next cluster (with wrap-around) */ - val = 0; bm = 0; i = 4096; + val = 0; bm = 0; i = SS(fs); } - if (!bv) { /* Is it a free cluster? */ - if (++ctr == ncl) return scl + 2; /* Check run length */ + if (bv == 0) { /* Is it a free cluster? */ + if (++ctr == ncl) return scl + 2; /* Check if run length is sufficient for required */ } else { - scl = val; ctr = 0; /* Encountered a live cluster, restart to scan */ + scl = val; ctr = 0; /* Encountered a cluster in-use, restart to scan */ } if (val == clst) return 0; /* All cluster scanned? */ - } while (bm); + } while (bm != 0); bm = 1; } while (++i < SS(fs)); } } -/*------------------------------------*/ -/* exFAT: Set/Clear a block of bitmap */ -/*------------------------------------*/ +/*----------------------------------------*/ +/* Set/Clear a block of allocation bitmap */ +/*----------------------------------------*/ -static -FRESULT change_bitmap ( - FATFS* fs, /* File system object */ +static FRESULT change_bitmap ( + FATFS* fs, /* Filesystem object */ DWORD clst, /* Cluster number to change from */ DWORD ncl, /* Number of clusters to be changed */ int bv /* bit value to be set (0 or 1) */ @@ -1157,9 +1311,9 @@ FRESULT change_bitmap ( clst -= 2; /* The first bit corresponds to cluster #2 */ - sect = fs->database + clst / 8 / SS(fs); /* Sector address (assuming bitmap is located top of the cluster heap) */ - i = clst / 8 % SS(fs); /* Byte offset in the sector */ - bm = 1 << (clst % 8); /* Bit mask in the byte */ + sect = fs->bitbase + clst / 8 / SS(fs); /* Sector address */ + i = clst / 8 % SS(fs); /* Byte offset in the sector */ + bm = 1 << (clst % 8); /* Bit mask in the byte */ for (;;) { if (move_window(fs, sect++) != FR_OK) return FR_DISK_ERR; do { @@ -1177,18 +1331,18 @@ FRESULT change_bitmap ( /*---------------------------------------------*/ -/* Complement contiguous part of the FAT chain */ +/* Fill the first fragment of the FAT chain */ /*---------------------------------------------*/ -static -FRESULT fill_fat_chain ( - _FDID* obj /* Pointer to the corresponding object */ +static FRESULT fill_first_frag ( + FFOBJID* obj /* Pointer to the corresponding object */ ) { FRESULT res; DWORD cl, n; - if (obj->stat == 3) { /* Has the object been changed 'fragmented'? */ + + if (obj->stat == 3) { /* Has the object been changed 'fragmented' in this session? */ for (cl = obj->sclust, n = obj->n_cont; n; cl++, n--) { /* Create cluster chain on the FAT */ res = put_fat(obj->fs, cl, cl + 1); if (res != FR_OK) return res; @@ -1198,35 +1352,57 @@ FRESULT fill_fat_chain ( return FR_OK; } -#endif /* _FS_EXFAT && !_FS_READONLY */ + +/*---------------------------------------------*/ +/* Fill the last fragment of the FAT chain */ +/*---------------------------------------------*/ + +static FRESULT fill_last_frag ( + FFOBJID* obj, /* Pointer to the corresponding object */ + DWORD lcl, /* Last cluster of the fragment */ + DWORD term /* Value to set the last FAT entry */ +) +{ + FRESULT res; + + + while (obj->n_frag > 0) { /* Create the chain of last fragment */ + res = put_fat(obj->fs, lcl - obj->n_frag + 1, (obj->n_frag > 1) ? lcl - obj->n_frag + 2 : term); + if (res != FR_OK) return res; + obj->n_frag--; + } + return FR_OK; +} + +#endif /* FF_FS_EXFAT && !FF_FS_READONLY */ -#if !_FS_READONLY +#if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* FAT handling - Remove a cluster chain */ /*-----------------------------------------------------------------------*/ -static -FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ - _FDID* obj, /* Corresponding object */ + +static FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ + FFOBJID* obj, /* Corresponding object */ DWORD clst, /* Cluster to remove a chain from */ - DWORD pclst /* Previous cluster of clst (0:an entire chain) */ + DWORD pclst /* Previous cluster of clst (0 if entire chain) */ ) { FRESULT res = FR_OK; DWORD nxt; FATFS *fs = obj->fs; -#if _FS_EXFAT || _USE_TRIM +#if FF_FS_EXFAT || FF_USE_TRIM DWORD scl = clst, ecl = clst; #endif -#if _USE_TRIM +#if FF_USE_TRIM DWORD rt[2]; #endif if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR; /* Check if in valid range */ /* Mark the previous cluster 'EOC' on the FAT if it exists */ - if (pclst && (!_FS_EXFAT || fs->fs_type != FS_EXFAT || obj->stat != 2)) { + if (pclst != 0 && (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT || obj->stat != 2)) { res = put_fat(fs, pclst, 0xFFFFFFFF); if (res != FR_OK) return res; } @@ -1237,7 +1413,7 @@ FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ if (nxt == 0) break; /* Empty cluster? */ if (nxt == 1) return FR_INT_ERR; /* Internal error? */ if (nxt == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error? */ - if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) { + if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { res = put_fat(fs, clst, 0); /* Mark the cluster 'free' on the FAT */ if (res != FR_OK) return res; } @@ -1245,20 +1421,20 @@ FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ fs->free_clst++; fs->fsi_flag |= 1; } -#if _FS_EXFAT || _USE_TRIM +#if FF_FS_EXFAT || FF_USE_TRIM if (ecl + 1 == nxt) { /* Is next cluster contiguous? */ ecl = nxt; } else { /* End of contiguous cluster block */ -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { res = change_bitmap(fs, scl, ecl - scl + 1, 0); /* Mark the cluster block 'free' on the bitmap */ if (res != FR_OK) return res; } #endif -#if _USE_TRIM - rt[0] = clust2sect(fs, scl); /* Start sector */ - rt[1] = clust2sect(fs, ecl) + fs->csize - 1; /* End sector */ - disk_ioctl(fs->drv, CTRL_TRIM, rt); /* Inform device the block can be erased */ +#if FF_USE_TRIM + rt[0] = clst2sect(fs, scl); /* Start of data area freed */ + rt[1] = clst2sect(fs, ecl) + fs->csize - 1; /* End of data area freed */ + disk_ioctl(fs->drv, CTRL_TRIM, rt); /* Inform device the data in the block is no longer needed */ #endif scl = ecl = nxt; } @@ -1266,13 +1442,28 @@ FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ clst = nxt; /* Next cluster */ } while (clst < fs->n_fatent); /* Repeat while not the last link */ -#if _FS_EXFAT +#if FF_FS_EXFAT + /* Some post processes for chain status */ if (fs->fs_type == FS_EXFAT) { - if (pclst == 0) { /* Does object have no chain? */ - obj->stat = 0; /* Change the object status 'initial' */ + if (pclst == 0) { /* Has the entire chain been removed? */ + obj->stat = 0; /* Change the chain status 'initial' */ } else { - if (obj->stat == 3 && pclst >= obj->sclust && pclst <= obj->sclust + obj->n_cont) { /* Did the chain got contiguous? */ - obj->stat = 2; /* Change the object status 'contiguous' */ + if (obj->stat == 0) { /* Is it a fragmented chain from the beginning of this session? */ + clst = obj->sclust; /* Follow the chain to check if it gets contiguous */ + while (clst != pclst) { + nxt = get_fat(obj, clst); + if (nxt < 2) return FR_INT_ERR; + if (nxt == 0xFFFFFFFF) return FR_DISK_ERR; + if (nxt != clst + 1) break; /* Not contiguous? */ + clst++; + } + if (clst == pclst) { /* Has the chain got contiguous again? */ + obj->stat = 2; /* Change the chain status 'contiguous' */ + } + } else { + if (obj->stat == 3 && pclst >= obj->sclust && pclst <= obj->sclust + obj->n_cont) { /* Was the chain fragmented in this session and got contiguous again? */ + obj->stat = 2; /* Change the chain status 'contiguous' */ + } } } } @@ -1286,9 +1477,9 @@ FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ /*-----------------------------------------------------------------------*/ /* FAT handling - Stretch a chain or Create a new chain */ /*-----------------------------------------------------------------------*/ -static -DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */ - _FDID* obj, /* Corresponding object */ + +static DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */ + FFOBJID* obj, /* Corresponding object */ DWORD clst /* Cluster# to stretch, 0:Create a new chain */ ) { @@ -1298,18 +1489,19 @@ DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk if (clst == 0) { /* Create a new chain */ - scl = fs->last_clst; /* Get suggested cluster to start from */ + scl = fs->last_clst; /* Suggested cluster to start to find */ if (scl == 0 || scl >= fs->n_fatent) scl = 1; } - else { /* Stretch current chain */ + else { /* Stretch a chain */ cs = get_fat(obj, clst); /* Check the cluster status */ - if (cs < 2) return 1; /* Invalid value */ - if (cs == 0xFFFFFFFF) return cs; /* A disk error occurred */ + if (cs < 2) return 1; /* Test for insanity */ + if (cs == 0xFFFFFFFF) return cs; /* Test for disk error */ if (cs < fs->n_fatent) return cs; /* It is already followed by next cluster */ - scl = clst; + scl = clst; /* Cluster to start to find */ } + if (fs->free_clst == 0) return 0; /* No free cluster */ -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ ncl = find_bitmap(fs, scl, 1); /* Find a free cluster */ if (ncl == 0 || ncl == 0xFFFFFFFF) return ncl; /* No free cluster or hard error? */ @@ -1317,62 +1509,79 @@ DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk if (res == FR_INT_ERR) return 1; if (res == FR_DISK_ERR) return 0xFFFFFFFF; if (clst == 0) { /* Is it a new chain? */ - obj->stat = 2; /* Set status 'contiguous chain' */ - } else { /* This is a stretched chain */ + obj->stat = 2; /* Set status 'contiguous' */ + } else { /* It is a stretched chain */ if (obj->stat == 2 && ncl != scl + 1) { /* Is the chain got fragmented? */ obj->n_cont = scl - obj->sclust; /* Set size of the contiguous part */ obj->stat = 3; /* Change status 'just fragmented' */ } } + if (obj->stat != 2) { /* Is the file non-contiguous? */ + if (ncl == clst + 1) { /* Is the cluster next to previous one? */ + obj->n_frag = obj->n_frag ? obj->n_frag + 1 : 2; /* Increment size of last framgent */ + } else { /* New fragment */ + if (obj->n_frag == 0) obj->n_frag = 1; + res = fill_last_frag(obj, clst, ncl); /* Fill last fragment on the FAT and link it to new one */ + if (res == FR_OK) obj->n_frag = 1; + } + } } else #endif - { /* On the FAT12/16/32 volume */ - ncl = scl; /* Start cluster */ - for (;;) { - ncl++; /* Next cluster */ - if (ncl >= fs->n_fatent) { /* Check wrap-around */ - ncl = 2; - if (ncl > scl) return 0; /* No free cluster */ + { /* On the FAT/FAT32 volume */ + ncl = 0; + if (scl == clst) { /* Stretching an existing chain? */ + ncl = scl + 1; /* Test if next cluster is free */ + if (ncl >= fs->n_fatent) ncl = 2; + cs = get_fat(obj, ncl); /* Get next cluster status */ + if (cs == 1 || cs == 0xFFFFFFFF) return cs; /* Test for error */ + if (cs != 0) { /* Not free? */ + cs = fs->last_clst; /* Start at suggested cluster if it is valid */ + if (cs >= 2 && cs < fs->n_fatent) scl = cs; + ncl = 0; } - cs = get_fat(obj, ncl); /* Get the cluster status */ - if (cs == 0) break; /* Found a free cluster */ - if (cs == 1 || cs == 0xFFFFFFFF) return cs; /* An error occurred */ - if (ncl == scl) return 0; /* No free cluster */ } - } - - if (_FS_EXFAT && fs->fs_type == FS_EXFAT && obj->stat == 2) { /* Is it a contiguous chain? */ - res = FR_OK; /* FAT does not need to be written */ - } else { - res = put_fat(fs, ncl, 0xFFFFFFFF); /* Mark the new cluster 'EOC' */ - if (res == FR_OK && clst) { - res = put_fat(fs, clst, ncl); /* Link it from the previous one if needed */ + if (ncl == 0) { /* The new cluster cannot be contiguous and find another fragment */ + ncl = scl; /* Start cluster */ + for (;;) { + ncl++; /* Next cluster */ + if (ncl >= fs->n_fatent) { /* Check wrap-around */ + ncl = 2; + if (ncl > scl) return 0; /* No free cluster found? */ + } + cs = get_fat(obj, ncl); /* Get the cluster status */ + if (cs == 0) break; /* Found a free cluster? */ + if (cs == 1 || cs == 0xFFFFFFFF) return cs; /* Test for error */ + if (ncl == scl) return 0; /* No free cluster found? */ + } + } + res = put_fat(fs, ncl, 0xFFFFFFFF); /* Mark the new cluster 'EOC' */ + if (res == FR_OK && clst != 0) { + res = put_fat(fs, clst, ncl); /* Link it from the previous one if needed */ } } if (res == FR_OK) { /* Update FSINFO if function succeeded. */ fs->last_clst = ncl; - if (fs->free_clst < fs->n_fatent - 2) fs->free_clst--; + if (fs->free_clst <= fs->n_fatent - 2) fs->free_clst--; fs->fsi_flag |= 1; } else { - ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; /* Failed. Create error status */ + ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; /* Failed. Generate error status */ } return ncl; /* Return new cluster number or error status */ } -#endif /* !_FS_READONLY */ +#endif /* !FF_FS_READONLY */ -#if _USE_FASTSEEK +#if FF_USE_FASTSEEK /*-----------------------------------------------------------------------*/ /* FAT handling - Convert offset into cluster with link map table */ /*-----------------------------------------------------------------------*/ -static -DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ +static DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ FIL* fp, /* Pointer to the file object */ FSIZE_t ofs /* File offset to be converted to cluster# */ ) @@ -1392,7 +1601,47 @@ DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ return cl + *tbl; /* Return the cluster number */ } -#endif /* _USE_FASTSEEK */ +#endif /* FF_USE_FASTSEEK */ + + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Fill a cluster with zeros */ +/*-----------------------------------------------------------------------*/ + +#if !FF_FS_READONLY +static FRESULT dir_clear ( /* Returns FR_OK or FR_DISK_ERR */ + FATFS *fs, /* Filesystem object */ + DWORD clst /* Directory table to clear */ +) +{ + DWORD sect; + UINT n, szb; + BYTE *ibuf; + + + if (sync_window(fs) != FR_OK) return FR_DISK_ERR; /* Flush disk access window */ + sect = clst2sect(fs, clst); /* Top of the cluster */ + fs->winsect = sect; /* Set window to top of the cluster */ + mem_set(fs->win, 0, sizeof fs->win); /* Clear window buffer */ +#if FF_USE_LFN == 3 /* Quick table clear by using multi-secter write */ + /* Allocate a temporary buffer */ + for (szb = ((DWORD)fs->csize * SS(fs) >= MAX_MALLOC) ? MAX_MALLOC : fs->csize * SS(fs), ibuf = 0; szb > SS(fs) && (ibuf = ff_memalloc(szb)) == 0; szb /= 2) ; + if (szb > SS(fs)) { /* Buffer allocated? */ + mem_set(ibuf, 0, szb); + szb /= SS(fs); /* Bytes -> Sectors */ + for (n = 0; n < fs->csize && disk_write(fs->drv, ibuf, sect + n, szb) == RES_OK; n += szb) ; /* Fill the cluster with 0 */ + ff_memfree(ibuf); + } else +#endif + { + ibuf = fs->win; szb = 1; /* Use window buffer (many single-sector writes may take a time) */ + for (n = 0; n < fs->csize && disk_write(fs->drv, ibuf, sect + n, szb) == RES_OK; n += szb) ; /* Fill the cluster with 0 */ + } + return (n == fs->csize) ? FR_OK : FR_DISK_ERR; +} +#endif /* !FF_FS_READONLY */ @@ -1401,8 +1650,7 @@ DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ /* Directory handling - Set directory index */ /*-----------------------------------------------------------------------*/ -static -FRESULT dir_sdi ( /* FR_OK(0):succeeded, !=0:error */ +static FRESULT dir_sdi ( /* FR_OK(0):succeeded, !=0:error */ DIR* dp, /* Pointer to directory object */ DWORD ofs /* Offset of directory table */ ) @@ -1411,21 +1659,21 @@ FRESULT dir_sdi ( /* FR_OK(0):succeeded, !=0:error */ FATFS *fs = dp->obj.fs; - if (ofs >= (DWORD)((_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR) || ofs % SZDIRE) { /* Check range of offset and alignment */ + if (ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR) || ofs % SZDIRE) { /* Check range of offset and alignment */ return FR_INT_ERR; } dp->dptr = ofs; /* Set current offset */ clst = dp->obj.sclust; /* Table start cluster (0:root) */ if (clst == 0 && fs->fs_type >= FS_FAT32) { /* Replace cluster# 0 with root cluster# */ clst = fs->dirbase; - if (_FS_EXFAT) dp->obj.stat = 0; /* exFAT: Root dir has an FAT chain */ + if (FF_FS_EXFAT) dp->obj.stat = 0; /* exFAT: Root dir has an FAT chain */ } - if (clst == 0) { /* Static table (root-directory in FAT12/16) */ - if (ofs / SZDIRE >= fs->n_rootdir) return FR_INT_ERR; /* Is index out of range? */ + if (clst == 0) { /* Static table (root-directory on the FAT volume) */ + if (ofs / SZDIRE >= fs->n_rootdir) return FR_INT_ERR; /* Is index out of range? */ dp->sect = fs->dirbase; - } else { /* Dynamic table (sub-directory or root-directory in FAT32+) */ + } else { /* Dynamic table (sub-directory or root-directory on the FAT32/exFAT volume) */ csz = (DWORD)fs->csize * SS(fs); /* Bytes per cluster */ while (ofs >= csz) { /* Follow cluster chain */ clst = get_fat(&dp->obj, clst); /* Get next cluster */ @@ -1433,10 +1681,10 @@ FRESULT dir_sdi ( /* FR_OK(0):succeeded, !=0:error */ if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR; /* Reached to end of table or internal error */ ofs -= csz; } - dp->sect = clust2sect(fs, clst); + dp->sect = clst2sect(fs, clst); } dp->clust = clst; /* Current cluster# */ - if (!dp->sect) return FR_INT_ERR; + if (dp->sect == 0) return FR_INT_ERR; dp->sect += ofs / SS(fs); /* Sector# of the directory entry */ dp->dir = fs->win + (ofs % SS(fs)); /* Pointer to the entry in the win[] */ @@ -1450,36 +1698,34 @@ FRESULT dir_sdi ( /* FR_OK(0):succeeded, !=0:error */ /* Directory handling - Move directory table index next */ /*-----------------------------------------------------------------------*/ -static -FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */ - DIR* dp, /* Pointer to the directory object */ - int stretch /* 0: Do not stretch table, 1: Stretch table if needed */ +static FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */ + DIR* dp, /* Pointer to the directory object */ + int stretch /* 0: Do not stretch table, 1: Stretch table if needed */ ) { DWORD ofs, clst; FATFS *fs = dp->obj.fs; -#if !_FS_READONLY - UINT n; -#endif + ofs = dp->dptr + SZDIRE; /* Next entry */ - if (!dp->sect || ofs >= (DWORD)((_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR)) return FR_NO_FILE; /* Report EOT when offset has reached max value */ + if (ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR)) dp->sect = 0; /* Disable it if the offset reached the max value */ + if (dp->sect == 0) return FR_NO_FILE; /* Report EOT if it has been disabled */ if (ofs % SS(fs) == 0) { /* Sector changed? */ dp->sect++; /* Next sector */ - if (!dp->clust) { /* Static table */ + if (dp->clust == 0) { /* Static table */ if (ofs / SZDIRE >= fs->n_rootdir) { /* Report EOT if it reached end of static table */ dp->sect = 0; return FR_NO_FILE; } } else { /* Dynamic table */ - if ((ofs / SS(fs) & (fs->csize - 1)) == 0) { /* Cluster changed? */ - clst = get_fat(&dp->obj, dp->clust); /* Get next cluster */ - if (clst <= 1) return FR_INT_ERR; /* Internal error */ - if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ - if (clst >= fs->n_fatent) { /* Reached end of dynamic table */ -#if !_FS_READONLY + if ((ofs / SS(fs) & (fs->csize - 1)) == 0) { /* Cluster changed? */ + clst = get_fat(&dp->obj, dp->clust); /* Get next cluster */ + if (clst <= 1) return FR_INT_ERR; /* Internal error */ + if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ + if (clst >= fs->n_fatent) { /* It reached end of dynamic table */ +#if !FF_FS_READONLY if (!stretch) { /* If no stretch, report EOT */ dp->sect = 0; return FR_NO_FILE; } @@ -1487,22 +1733,15 @@ FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Co if (clst == 0) return FR_DENIED; /* No free cluster */ if (clst == 1) return FR_INT_ERR; /* Internal error */ if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ - /* Clean-up the stretched table */ - if (_FS_EXFAT) dp->obj.stat |= 4; /* The directory needs to be updated */ - if (sync_window(fs) != FR_OK) return FR_DISK_ERR; /* Flush disk access window */ - mem_set(fs->win, 0, SS(fs)); /* Clear window buffer */ - for (n = 0, fs->winsect = clust2sect(fs, clst); n < fs->csize; n++, fs->winsect++) { /* Fill the new cluster with 0 */ - fs->wflag = 1; - if (sync_window(fs) != FR_OK) return FR_DISK_ERR; - } - fs->winsect -= n; /* Restore window offset */ + if (dir_clear(fs, clst) != FR_OK) return FR_DISK_ERR; /* Clean up the stretched table */ + if (FF_FS_EXFAT) dp->obj.stat |= 4; /* exFAT: The directory has been stretched */ #else - if (!stretch) dp->sect = 0; /* If no stretch, report EOT (this is to suppress warning) */ + if (!stretch) dp->sect = 0; /* (this line is to suppress compiler warning) */ dp->sect = 0; return FR_NO_FILE; /* Report EOT */ #endif } dp->clust = clst; /* Initialize data for new cluster */ - dp->sect = clust2sect(fs, clst); + dp->sect = clst2sect(fs, clst); } } } @@ -1515,15 +1754,14 @@ FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Co -#if !_FS_READONLY +#if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Directory handling - Reserve a block of directory entries */ /*-----------------------------------------------------------------------*/ -static -FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */ - DIR* dp, /* Pointer to the directory object */ - UINT nent /* Number of contiguous entries to allocate */ +static FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */ + DIR* dp, /* Pointer to the directory object */ + UINT nent /* Number of contiguous entries to allocate */ ) { FRESULT res; @@ -1537,7 +1775,7 @@ FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */ do { res = move_window(fs, dp->sect); if (res != FR_OK) break; -#if _FS_EXFAT +#if FF_FS_EXFAT if ((fs->fs_type == FS_EXFAT) ? (int)((dp->dir[XDIR_Type] & 0x80) == 0) : (int)(dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0)) { #else if (dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0) { @@ -1554,7 +1792,7 @@ FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */ return res; } -#endif /* !_FS_READONLY */ +#endif /* !FF_FS_READONLY */ @@ -1563,10 +1801,9 @@ FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */ /* FAT: Directory handling - Load/Store start cluster number */ /*-----------------------------------------------------------------------*/ -static -DWORD ld_clust ( /* Returns the top cluster value of the SFN entry */ - FATFS* fs, /* Pointer to the fs object */ - const BYTE* dir /* Pointer to the key entry */ +static DWORD ld_clust ( /* Returns the top cluster value of the SFN entry */ + FATFS* fs, /* Pointer to the fs object */ + const BYTE* dir /* Pointer to the key entry */ ) { DWORD cl; @@ -1580,9 +1817,8 @@ DWORD ld_clust ( /* Returns the top cluster value of the SFN entry */ } -#if !_FS_READONLY -static -void st_clust ( +#if !FF_FS_READONLY +static void st_clust ( FATFS* fs, /* Pointer to the fs object */ BYTE* dir, /* Pointer to the key entry */ DWORD cl /* Value to be set */ @@ -1597,19 +1833,12 @@ void st_clust ( -#if _USE_LFN != 0 -/*------------------------------------------------------------------------*/ -/* FAT-LFN: LFN handling */ -/*------------------------------------------------------------------------*/ -static -const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* Offset of LFN characters in the directory entry */ - - +#if FF_USE_LFN /*--------------------------------------------------------*/ /* FAT-LFN: Compare a part of file name with an LFN entry */ /*--------------------------------------------------------*/ -static -int cmp_lfn ( /* 1:matched, 0:not matched */ + +static int cmp_lfn ( /* 1:matched, 0:not matched */ const WCHAR* lfnbuf, /* Pointer to the LFN working buffer to be compared */ BYTE* dir /* Pointer to the directory entry containing the part of LFN */ ) @@ -1624,8 +1853,8 @@ int cmp_lfn ( /* 1:matched, 0:not matched */ for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ - if (wc) { - if (i >= _MAX_LFN || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */ + if (wc != 0) { + if (i >= FF_MAX_LFN + 1 || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */ return 0; /* Not matched */ } wc = uc; @@ -1640,12 +1869,12 @@ int cmp_lfn ( /* 1:matched, 0:not matched */ } -#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 || _USE_LABEL || _FS_EXFAT +#if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 || FF_USE_LABEL || FF_FS_EXFAT /*-----------------------------------------------------*/ /* FAT-LFN: Pick a part of file name from an LFN entry */ /*-----------------------------------------------------*/ -static -int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */ + +static int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */ WCHAR* lfnbuf, /* Pointer to the LFN working buffer */ BYTE* dir /* Pointer to the LFN entry */ ) @@ -1654,22 +1883,22 @@ int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry * WCHAR wc, uc; - if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */ + if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO is 0 */ - i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ + i = ((dir[LDIR_Ord] & ~LLEF) - 1) * 13; /* Offset in the LFN buffer */ for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ - if (wc) { - if (i >= _MAX_LFN) return 0; /* Buffer overflow? */ + if (wc != 0) { + if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */ lfnbuf[i++] = wc = uc; /* Store it */ } else { if (uc != 0xFFFF) return 0; /* Check filler */ } } - if (dir[LDIR_Ord] & LLEF) { /* Put terminator if it is the last LFN part */ - if (i >= _MAX_LFN) return 0; /* Buffer overflow? */ + if (dir[LDIR_Ord] & LLEF && wc != 0) { /* Put terminator if it is the last LFN part and not terminated */ + if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */ lfnbuf[i] = 0; } @@ -1678,12 +1907,12 @@ int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry * #endif -#if !_FS_READONLY +#if !FF_FS_READONLY /*-----------------------------------------*/ /* FAT-LFN: Create an entry of LFN entries */ /*-----------------------------------------*/ -static -void put_lfn ( + +static void put_lfn ( const WCHAR* lfn, /* Pointer to the LFN */ BYTE* dir, /* Pointer to the LFN entry to be created */ BYTE ord, /* LFN order (1-20) */ @@ -1710,18 +1939,17 @@ void put_lfn ( dir[LDIR_Ord] = ord; /* Set the LFN order */ } -#endif /* !_FS_READONLY */ -#endif /* _USE_LFN != 0 */ +#endif /* !FF_FS_READONLY */ +#endif /* FF_USE_LFN */ -#if _USE_LFN != 0 && !_FS_READONLY +#if FF_USE_LFN && !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* FAT-LFN: Create a Numbered SFN */ /*-----------------------------------------------------------------------*/ -static -void gen_numname ( +static void gen_numname ( BYTE* dst, /* Pointer to the buffer to store numbered SFN */ const BYTE* src, /* Pointer to SFN */ const WCHAR* lfn, /* Pointer to LFN */ @@ -1738,7 +1966,7 @@ void gen_numname ( if (seq > 5) { /* In case of many collisions, generate a hash number instead of sequential number */ sr = seq; - while (*lfn) { /* Create a CRC */ + while (*lfn) { /* Create a CRC as hash value */ wc = *lfn++; for (i = 0; i < 16; i++) { sr = (sr << 1) + (wc & 1); @@ -1759,9 +1987,9 @@ void gen_numname ( } while (seq); ns[i] = '~'; - /* Append the number */ + /* Append the number to the SFN body */ for (j = 0; j < i && dst[j] != ' '; j++) { - if (IsDBCS1(dst[j])) { + if (dbc_1st(dst[j])) { if (j == i - 1) break; j++; } @@ -1770,38 +1998,38 @@ void gen_numname ( dst[j++] = (i < 8) ? ns[i++] : ' '; } while (j < 8); } -#endif /* _USE_LFN != 0 && !_FS_READONLY */ +#endif /* FF_USE_LFN && !FF_FS_READONLY */ -#if _USE_LFN != 0 +#if FF_USE_LFN /*-----------------------------------------------------------------------*/ /* FAT-LFN: Calculate checksum of an SFN entry */ /*-----------------------------------------------------------------------*/ -static -BYTE sum_sfn ( +static BYTE sum_sfn ( const BYTE* dir /* Pointer to the SFN entry */ ) { BYTE sum = 0; UINT n = 11; - do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n); + do { + sum = (sum >> 1) + (sum << 7) + *dir++; + } while (--n); return sum; } -#endif /* _USE_LFN != 0 */ +#endif /* FF_USE_LFN */ -#if _FS_EXFAT +#if FF_FS_EXFAT /*-----------------------------------------------------------------------*/ /* exFAT: Checksum */ /*-----------------------------------------------------------------------*/ -static -WORD xdir_sum ( /* Get checksum of the directoly block */ +static WORD xdir_sum ( /* Get checksum of the directoly entry block */ const BYTE* dir /* Directory entry block to be calculated */ ) { @@ -1809,9 +2037,9 @@ WORD xdir_sum ( /* Get checksum of the directoly block */ WORD sum; - szblk = (dir[XDIR_NumSec] + 1) * SZDIRE; + szblk = (dir[XDIR_NumSec] + 1) * SZDIRE; /* Number of bytes of the entry block */ for (i = sum = 0; i < szblk; i++) { - if (i == XDIR_SetSum) { /* Skip sum field */ + if (i == XDIR_SetSum) { /* Skip 2-byte sum field */ i++; } else { sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + dir[i]; @@ -1822,8 +2050,7 @@ WORD xdir_sum ( /* Get checksum of the directoly block */ -static -WORD xname_sum ( /* Get check sum (to be used as hash) of the name */ +static WORD xname_sum ( /* Get check sum (to be used as hash) of the file name */ const WCHAR* name /* File name to be calculated */ ) { @@ -1832,7 +2059,7 @@ WORD xname_sum ( /* Get check sum (to be used as hash) of the name */ while ((chr = *name++) != 0) { - chr = ff_wtoupper(chr); /* File name needs to be ignored case */ + chr = (WCHAR)ff_wtoupper(chr); /* File name needs to be up-case converted */ sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr & 0xFF); sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr >> 8); } @@ -1840,11 +2067,10 @@ WORD xname_sum ( /* Get check sum (to be used as hash) of the name */ } -#if !_FS_READONLY && _USE_MKFS -static -DWORD xsum32 ( - BYTE dat, /* Data to be sumed */ - DWORD sum /* Previous value */ +#if !FF_FS_READONLY && FF_USE_MKFS +static DWORD xsum32 ( /* Returns 32-bit checksum */ + BYTE dat, /* Byte to be calculated (byte-by-byte processing) */ + DWORD sum /* Previous sum value */ ) { sum = ((sum & 1) ? 0x80000000 : 0) + (sum >> 1) + dat; @@ -1853,130 +2079,137 @@ DWORD xsum32 ( #endif -#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 +#if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 /*------------------------------------------------------*/ /* exFAT: Get object information from a directory block */ /*------------------------------------------------------*/ -static -void get_xdir_info ( +static void get_xfileinfo ( BYTE* dirb, /* Pointer to the direcotry entry block 85+C0+C1s */ FILINFO* fno /* Buffer to store the extracted file information */ ) { - UINT di, si; - WCHAR w; -#if !_LFN_UNICODE - UINT nc; -#endif + WCHAR wc, hs; + UINT di, si, nc; - /* Get file name */ -#if _LFN_UNICODE - if (dirb[XDIR_NumName] <= _MAX_LFN) { - for (si = SZDIRE * 2, di = 0; di < dirb[XDIR_NumName]; si += 2, di++) { - if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ - w = ld_word(dirb + si); /* Get a character */ - fno->fname[di] = w; /* Store it */ + /* Get file name from the entry block */ + si = SZDIRE * 2; /* 1st C1 entry */ + nc = 0; hs = 0; di = 0; + while (nc < dirb[XDIR_NumName]) { + if (si >= MAXDIRB(FF_MAX_LFN)) { di = 0; break; } /* Truncated directory block? */ + if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ + wc = ld_word(dirb + si); si += 2; nc++; /* Get a character */ + if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ + hs = wc; continue; /* Get low surrogate */ } - } else { - di = 0; /* Buffer overflow and inaccessible object */ + wc = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in API encoding */ + if (wc == 0) { di = 0; break; } /* Buffer overflow or wrong encoding? */ + di += wc; + hs = 0; } -#else - for (si = SZDIRE * 2, di = nc = 0; nc < dirb[XDIR_NumName]; si += 2, nc++) { - if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ - w = ld_word(dirb + si); /* Get a character */ - w = ff_convert(w, 0); /* Unicode -> OEM */ - if (w == 0) { di = 0; break; } /* Could not be converted and inaccessible object */ - if (_DF1S && w >= 0x100) { /* Put 1st byte if it is a DBC (always false at SBCS cfg) */ - fno->fname[di++] = (char)(w >> 8); - } - if (di >= _MAX_LFN) { di = 0; break; } /* Buffer overflow and inaccessible object */ - fno->fname[di++] = (char)w; - } -#endif - if (di == 0) fno->fname[di++] = '?'; /* Inaccessible object? */ - fno->fname[di] = 0; /* Terminate file name */ + if (hs != 0) di = 0; /* Broken surrogate pair? */ + if (di == 0) fno->fname[di++] = '?'; /* Inaccessible object name? */ + fno->fname[di] = 0; /* Terminate the name */ + fno->altname[0] = 0; /* exFAT does not support SFN */ - fno->altname[0] = 0; /* No SFN */ - fno->fattrib = dirb[XDIR_Attr]; /* Attribute */ + fno->fattrib = dirb[XDIR_Attr]; /* Attribute */ fno->fsize = (fno->fattrib & AM_DIR) ? 0 : ld_qword(dirb + XDIR_FileSize); /* Size */ fno->ftime = ld_word(dirb + XDIR_ModTime + 0); /* Time */ fno->fdate = ld_word(dirb + XDIR_ModTime + 2); /* Date */ } -#endif /* _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 */ +#endif /* FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 */ /*-----------------------------------*/ /* exFAT: Get a directry entry block */ /*-----------------------------------*/ -static -FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ - DIR* dp /* Pointer to the reading direcotry object pointing the 85 entry */ +static FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ + DIR* dp /* Reading direcotry object pointing top of the entry block to load */ ) { FRESULT res; - UINT i, nent; + UINT i, sz_ent; BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory direcotry entry block 85+C0+C1s */ - /* Load 85 entry */ + /* Load file-directory entry */ res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; - if (dp->dir[XDIR_Type] != 0x85) return FR_INT_ERR; - mem_cpy(dirb, dp->dir, SZDIRE); - nent = dirb[XDIR_NumSec] + 1; + if (dp->dir[XDIR_Type] != ET_FILEDIR) return FR_INT_ERR; /* Invalid order */ + mem_cpy(dirb + 0 * SZDIRE, dp->dir, SZDIRE); + sz_ent = (dirb[XDIR_NumSec] + 1) * SZDIRE; + if (sz_ent < 3 * SZDIRE || sz_ent > 19 * SZDIRE) return FR_INT_ERR; - /* Load C0 entry */ + /* Load stream-extension entry */ res = dir_next(dp, 0); + if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */ if (res != FR_OK) return res; res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; - if (dp->dir[XDIR_Type] != 0xC0) return FR_INT_ERR; - mem_cpy(dirb + SZDIRE, dp->dir, SZDIRE); + if (dp->dir[XDIR_Type] != ET_STREAM) return FR_INT_ERR; /* Invalid order */ + mem_cpy(dirb + 1 * SZDIRE, dp->dir, SZDIRE); + if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR; - /* Load C1 entries */ - if (nent < 3 || nent > 19) return FR_NO_FILE; - i = SZDIRE * 2; nent *= SZDIRE; + /* Load file-name entries */ + i = 2 * SZDIRE; /* Name offset to load */ do { res = dir_next(dp, 0); + if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */ if (res != FR_OK) return res; res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; - if (dp->dir[XDIR_Type] != 0xC1) return FR_INT_ERR; - mem_cpy(dirb + i, dp->dir, SZDIRE); - i += SZDIRE; - } while (i < nent); - - /* Sanity check */ - if (xdir_sum(dirb) != ld_word(dirb + XDIR_SetSum)) return FR_INT_ERR; + if (dp->dir[XDIR_Type] != ET_FILENAME) return FR_INT_ERR; /* Invalid order */ + if (i < MAXDIRB(FF_MAX_LFN)) mem_cpy(dirb + i, dp->dir, SZDIRE); + } while ((i += SZDIRE) < sz_ent); + /* Sanity check (do it for only accessible object) */ + if (i <= MAXDIRB(FF_MAX_LFN)) { + if (xdir_sum(dirb) != ld_word(dirb + XDIR_SetSum)) return FR_INT_ERR; + } return FR_OK; } -#if !_FS_READONLY || _FS_RPATH != 0 +/*------------------------------------------------------------------*/ +/* exFAT: Initialize object allocation info with loaded entry block */ +/*------------------------------------------------------------------*/ + +static void init_alloc_info ( + FATFS* fs, /* Filesystem object */ + FFOBJID* obj /* Object allocation information to be initialized */ +) +{ + obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Start cluster */ + obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize); /* Size */ + obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; /* Allocation status */ + obj->n_frag = 0; /* No last fragment info */ +} + + + +#if !FF_FS_READONLY || FF_FS_RPATH != 0 /*------------------------------------------------*/ /* exFAT: Load the object's directory entry block */ /*------------------------------------------------*/ -static -FRESULT load_obj_dir ( + +static FRESULT load_obj_xdir ( DIR* dp, /* Blank directory object to be used to access containing direcotry */ - const _FDID* obj /* Object with containing directory information */ + const FFOBJID* obj /* Object with its containing directory information */ ) { FRESULT res; - /* Open object containing directory */ dp->obj.fs = obj->fs; dp->obj.sclust = obj->c_scl; dp->obj.stat = (BYTE)obj->c_size; dp->obj.objsize = obj->c_size & 0xFFFFFF00; + dp->obj.n_frag = 0; dp->blk_ofs = obj->c_ofs; - res = dir_sdi(dp, dp->blk_ofs); /* Goto the block location */ + res = dir_sdi(dp, dp->blk_ofs); /* Goto object's entry block */ if (res == FR_OK) { res = load_xdir(dp); /* Load the object's entry block */ } @@ -1985,12 +2218,12 @@ FRESULT load_obj_dir ( #endif -#if !_FS_READONLY -/*-----------------------------------------------*/ -/* exFAT: Store the directory block to the media */ -/*-----------------------------------------------*/ -static -FRESULT store_xdir ( +#if !FF_FS_READONLY +/*----------------------------------------*/ +/* exFAT: Store the directory entry block */ +/*----------------------------------------*/ + +static FRESULT store_xdir ( DIR* dp /* Pointer to the direcotry object */ ) { @@ -2002,7 +2235,7 @@ FRESULT store_xdir ( st_word(dirb + XDIR_SetSum, xdir_sum(dirb)); nent = dirb[XDIR_NumSec] + 1; - /* Store the set of directory to the volume */ + /* Store the direcotry entry block to the directory */ res = dir_sdi(dp, dp->blk_ofs); while (res == FR_OK) { res = move_window(dp->obj.fs, dp->sect); @@ -2022,71 +2255,77 @@ FRESULT store_xdir ( /* exFAT: Create a new directory enrty block */ /*-------------------------------------------*/ -static -void create_xdir ( +static void create_xdir ( BYTE* dirb, /* Pointer to the direcotry entry block buffer */ - const WCHAR* lfn /* Pointer to the nul terminated file name */ + const WCHAR* lfn /* Pointer to the object name */ ) { UINT i; - BYTE nb, nc; - WCHAR chr; + BYTE nc1, nlen; + WCHAR wc; - mem_set(dirb, 0, 2 * SZDIRE); /* Initialize 85+C0 entry */ - dirb[XDIR_Type] = 0x85; - dirb[XDIR_Type + SZDIRE] = 0xC0; - st_word(dirb + XDIR_NameHash, xname_sum(lfn)); /* Set name hash */ + /* Create file-directory and stream-extension entry */ + mem_set(dirb, 0, 2 * SZDIRE); + dirb[0 * SZDIRE + XDIR_Type] = ET_FILEDIR; + dirb[1 * SZDIRE + XDIR_Type] = ET_STREAM; - i = SZDIRE * 2; /* C1 offset */ - nc = 0; nb = 1; chr = 1; + /* Create file-name entries */ + i = SZDIRE * 2; /* Top of file_name entries */ + nlen = nc1 = 0; wc = 1; do { - dirb[i++] = 0xC1; dirb[i++] = 0; /* Entry type C1 */ + dirb[i++] = ET_FILENAME; dirb[i++] = 0; do { /* Fill name field */ - if (chr && (chr = lfn[nc]) != 0) nc++; /* Get a character if exist */ - st_word(dirb + i, chr); i += 2; /* Store it */ - } while (i % SZDIRE); - nb++; - } while (lfn[nc]); /* Fill next entry if any char follows */ + if (wc != 0 && (wc = lfn[nlen]) != 0) nlen++; /* Get a character if exist */ + st_word(dirb + i, wc); /* Store it */ + i += 2; + } while (i % SZDIRE != 0); + nc1++; + } while (lfn[nlen]); /* Fill next entry if any char follows */ - dirb[XDIR_NumName] = nc; /* Set name length */ - dirb[XDIR_NumSec] = nb; /* Set number of C0+C1s */ + dirb[XDIR_NumName] = nlen; /* Set name length */ + dirb[XDIR_NumSec] = 1 + nc1; /* Set secondary count (C0 + C1s) */ + st_word(dirb + XDIR_NameHash, xname_sum(lfn)); /* Set name hash */ } -#endif /* !_FS_READONLY */ -#endif /* _FS_EXFAT */ +#endif /* !FF_FS_READONLY */ +#endif /* FF_FS_EXFAT */ -#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 || _USE_LABEL || _FS_EXFAT +#if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 || FF_USE_LABEL || FF_FS_EXFAT /*-----------------------------------------------------------------------*/ /* Read an object from the directory */ /*-----------------------------------------------------------------------*/ -static -FRESULT dir_read ( +#define DIR_READ_FILE(dp) dir_read(dp, 0) +#define DIR_READ_LABEL(dp) dir_read(dp, 1) + +static FRESULT dir_read ( DIR* dp, /* Pointer to the directory object */ int vol /* Filtered by 0:file/directory or 1:volume label */ ) { FRESULT res = FR_NO_FILE; FATFS *fs = dp->obj.fs; - BYTE a, c; -#if _USE_LFN != 0 + BYTE attr, b; +#if FF_USE_LFN BYTE ord = 0xFF, sum = 0xFF; #endif while (dp->sect) { res = move_window(fs, dp->sect); if (res != FR_OK) break; - c = dp->dir[DIR_Name]; /* Test for the entry type */ - if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of the directory */ -#if _FS_EXFAT + b = dp->dir[DIR_Name]; /* Test for the entry type */ + if (b == 0) { + res = FR_NO_FILE; break; /* Reached to end of the directory */ + } +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ - if (_USE_LABEL && vol) { - if (c == 0x83) break; /* Volume label entry? */ + if (FF_USE_LABEL && vol) { + if (b == ET_VLABEL) break; /* Volume label entry? */ } else { - if (c == 0x85) { /* Start of the file entry block? */ + if (b == ET_FILEDIR) { /* Start of the file entry block? */ dp->blk_ofs = dp->dptr; /* Get location of the block */ res = load_xdir(dp); /* Load the entry block */ if (res == FR_OK) { @@ -2097,29 +2336,29 @@ FRESULT dir_read ( } } else #endif - { /* On the FAT12/16/32 volume */ - dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */ -#if _USE_LFN != 0 /* LFN configuration */ - if (c == DDEM || c == '.' || (int)((a & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ + { /* On the FAT/FAT32 volume */ + dp->obj.attr = attr = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */ +#if FF_USE_LFN /* LFN configuration */ + if (b == DDEM || b == '.' || (int)((attr & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ ord = 0xFF; } else { - if (a == AM_LFN) { /* An LFN entry is found */ - if (c & LLEF) { /* Is it start of an LFN sequence? */ + if (attr == AM_LFN) { /* An LFN entry is found */ + if (b & LLEF) { /* Is it start of an LFN sequence? */ sum = dp->dir[LDIR_Chksum]; - c &= (BYTE)~LLEF; ord = c; + b &= (BYTE)~LLEF; ord = b; dp->blk_ofs = dp->dptr; } /* Check LFN validity and capture it */ - ord = (c == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; + ord = (b == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; } else { /* An SFN entry is found */ - if (ord || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */ + if (ord != 0 || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */ dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */ } break; } } #else /* Non LFN configuration */ - if (c != DDEM && c != '.' && a != AM_LFN && (int)((a & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */ + if (b != DDEM && b != '.' && attr != AM_LFN && (int)((attr & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */ break; } #endif @@ -2132,7 +2371,7 @@ FRESULT dir_read ( return res; } -#endif /* _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2 */ +#endif /* FF_FS_MINIMIZE <= 1 || FF_USE_LABEL || FF_FS_RPATH >= 2 */ @@ -2140,28 +2379,30 @@ FRESULT dir_read ( /* Directory handling - Find an object in the directory */ /*-----------------------------------------------------------------------*/ -static -FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ - DIR* dp /* Pointer to the directory object with the file name */ +static FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ + DIR* dp /* Pointer to the directory object with the file name */ ) { FRESULT res; FATFS *fs = dp->obj.fs; BYTE c; -#if _USE_LFN != 0 +#if FF_USE_LFN BYTE a, ord, sum; #endif res = dir_sdi(dp, 0); /* Rewind directory object */ if (res != FR_OK) return res; -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ BYTE nc; UINT di, ni; WORD hash = xname_sum(fs->lfnbuf); /* Hash value of the name to find */ - while ((res = dir_read(dp, 0)) == FR_OK) { /* Read an item */ - if (ld_word(fs->dirbuf + XDIR_NameHash) != hash) continue; /* Skip the comparison if hash value mismatched */ + while ((res = DIR_READ_FILE(dp)) == FR_OK) { /* Read an item */ +#if FF_MAX_LFN < 255 + if (fs->dirbuf[XDIR_NumName] > FF_MAX_LFN) continue; /* Skip comparison if inaccessible object name */ +#endif + if (ld_word(fs->dirbuf + XDIR_NameHash) != hash) continue; /* Skip comparison if hash mismatched */ for (nc = fs->dirbuf[XDIR_NumName], di = SZDIRE * 2, ni = 0; nc; nc--, di += 2, ni++) { /* Compare the name */ if ((di % SZDIRE) == 0) di += 2; if (ff_wtoupper(ld_word(fs->dirbuf + di)) != ff_wtoupper(fs->lfnbuf[ni])) break; @@ -2171,8 +2412,8 @@ FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ return res; } #endif - /* On the FAT12/16/32 volume */ -#if _USE_LFN != 0 + /* On the FAT/FAT32 volume */ +#if FF_USE_LFN ord = sum = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ #endif do { @@ -2180,7 +2421,7 @@ FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ if (res != FR_OK) break; c = dp->dir[DIR_Name]; if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ -#if _USE_LFN != 0 /* LFN configuration */ +#if FF_USE_LFN /* LFN configuration */ dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; if (c == DDEM || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */ ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ @@ -2196,7 +2437,7 @@ FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ ord = (c == ord && sum == dp->dir[LDIR_Chksum] && cmp_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; } } else { /* An SFN entry is found */ - if (!ord && sum == sum_sfn(dp->dir)) break; /* LFN matched? */ + if (ord == 0 && sum == sum_sfn(dp->dir)) break; /* LFN matched? */ if (!(dp->fn[NSFLAG] & NS_LOSS) && !mem_cmp(dp->dir, dp->fn, 11)) break; /* SFN matched? */ ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ } @@ -2214,19 +2455,18 @@ FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ -#if !_FS_READONLY +#if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Register an object to the directory */ /*-----------------------------------------------------------------------*/ -static -FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many SFN collision, FR_DISK_ERR:disk error */ - DIR* dp /* Target directory with object name to be created */ +static FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many SFN collision, FR_DISK_ERR:disk error */ + DIR* dp /* Target directory with object name to be created */ ) { FRESULT res; FATFS *fs = dp->obj.fs; -#if _USE_LFN != 0 /* LFN configuration */ +#if FF_USE_LFN /* LFN configuration */ UINT n, nlen, nent; BYTE sn[12], sum; @@ -2234,34 +2474,38 @@ FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many if (dp->fn[NSFLAG] & (NS_DOT | NS_NONAME)) return FR_INVALID_NAME; /* Check name validity */ for (nlen = 0; fs->lfnbuf[nlen]; nlen++) ; /* Get lfn length */ -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ - DIR dj; - nent = (nlen + 14) / 15 + 2; /* Number of entries to allocate (85+C0+C1s) */ - res = dir_alloc(dp, nent); /* Allocate entries */ + res = dir_alloc(dp, nent); /* Allocate directory entries */ if (res != FR_OK) return res; - dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set block position */ + dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set the allocated entry block offset */ - if (dp->obj.sclust != 0 && (dp->obj.stat & 4)) { /* Has the sub-directory been stretched? */ - dp->obj.stat &= 3; - dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase object size by cluster size */ - res = fill_fat_chain(&dp->obj); /* Complement FAT chain if needed */ + if (dp->obj.stat & 4) { /* Has the directory been stretched by new allocation? */ + dp->obj.stat &= ~4; + res = fill_first_frag(&dp->obj); /* Fill the first fragment on the FAT if needed */ if (res != FR_OK) return res; - res = load_obj_dir(&dj, &dp->obj); - if (res != FR_OK) return res; /* Load the object status */ - st_qword(fs->dirbuf + XDIR_FileSize, dp->obj.objsize); /* Update the allocation status */ - st_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize); - fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1; - res = store_xdir(&dj); /* Store the object status */ + res = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF); /* Fill the last fragment on the FAT if needed */ if (res != FR_OK) return res; + if (dp->obj.sclust != 0) { /* Is it a sub-directory? */ + DIR dj; + + res = load_obj_xdir(&dj, &dp->obj); /* Load the object status */ + if (res != FR_OK) return res; + dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase the directory size by cluster size */ + st_qword(fs->dirbuf + XDIR_FileSize, dp->obj.objsize); /* Update the allocation status */ + st_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize); + fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1; + res = store_xdir(&dj); /* Store the object status */ + if (res != FR_OK) return res; + } } create_xdir(fs->dirbuf, fs->lfnbuf); /* Create on-memory directory block to be written later */ return FR_OK; } #endif - /* On the FAT12/16/32 volume */ + /* On the FAT/FAT32 volume */ mem_cpy(sn, dp->fn, 12); if (sn[NSFLAG] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */ dp->fn[NSFLAG] = NS_NOLFN; /* Find only SFN */ @@ -2303,7 +2547,7 @@ FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many if (res == FR_OK) { mem_set(dp->dir, 0, SZDIRE); /* Clean the entry */ mem_cpy(dp->dir + DIR_Name, dp->fn, 11); /* Put SFN */ -#if _USE_LFN != 0 +#if FF_USE_LFN dp->dir[DIR_NTres] = dp->fn[NSFLAG] & (NS_BODY | NS_EXT); /* Put NT flag */ #endif fs->wflag = 1; @@ -2313,23 +2557,22 @@ FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many return res; } -#endif /* !_FS_READONLY */ +#endif /* !FF_FS_READONLY */ -#if !_FS_READONLY && _FS_MINIMIZE == 0 +#if !FF_FS_READONLY && FF_FS_MINIMIZE == 0 /*-----------------------------------------------------------------------*/ /* Remove an object from the directory */ /*-----------------------------------------------------------------------*/ -static -FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ - DIR* dp /* Directory object pointing the entry to be removed */ +static FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ + DIR* dp /* Directory object pointing the entry to be removed */ ) { FRESULT res; FATFS *fs = dp->obj.fs; -#if _USE_LFN != 0 /* LFN configuration */ +#if FF_USE_LFN /* LFN configuration */ DWORD last = dp->dptr; res = (dp->blk_ofs == 0xFFFFFFFF) ? FR_OK : dir_sdi(dp, dp->blk_ofs); /* Goto top of the entry block if LFN is exist */ @@ -2337,11 +2580,10 @@ FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ do { res = move_window(fs, dp->sect); if (res != FR_OK) break; - /* Mark an entry 'deleted' */ - if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ - dp->dir[XDIR_Type] &= 0x7F; - } else { /* On the FAT12/16/32 volume */ - dp->dir[DIR_Name] = DDEM; + if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + dp->dir[XDIR_Type] &= 0x7F; /* Clear the entry InUse flag. */ + } else { /* On the FAT/FAT32 volume */ + dp->dir[DIR_Name] = DDEM; /* Mark the entry 'deleted'. */ } fs->wflag = 1; if (dp->dptr >= last) break; /* If reached last entry then all entries of the object has been deleted. */ @@ -2353,7 +2595,7 @@ FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ res = move_window(fs, dp->sect); if (res == FR_OK) { - dp->dir[DIR_Name] = DDEM; + dp->dir[DIR_Name] = DDEM; /* Mark the entry 'deleted'.*/ fs->wflag = 1; } #endif @@ -2361,143 +2603,153 @@ FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ return res; } -#endif /* !_FS_READONLY && _FS_MINIMIZE == 0 */ +#endif /* !FF_FS_READONLY && FF_FS_MINIMIZE == 0 */ -#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 +#if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 /*-----------------------------------------------------------------------*/ /* Get file information from directory entry */ /*-----------------------------------------------------------------------*/ -static -void get_fileinfo ( /* No return code */ +static void get_fileinfo ( DIR* dp, /* Pointer to the directory object */ FILINFO* fno /* Pointer to the file information to be filled */ ) { - UINT i, j; - TCHAR c; - DWORD tm; -#if _USE_LFN != 0 - WCHAR w, lfv; + UINT si, di; +#if FF_USE_LFN + BYTE lcf; + WCHAR wc, hs; FATFS *fs = dp->obj.fs; +#else + TCHAR c; #endif - fno->fname[0] = 0; /* Invaidate file info */ - if (!dp->sect) return; /* Exit if read pointer has reached end of directory */ + fno->fname[0] = 0; /* Invaidate file info */ + if (dp->sect == 0) return; /* Exit if read pointer has reached end of directory */ -#if _USE_LFN != 0 /* LFN configuration */ -#if _FS_EXFAT +#if FF_USE_LFN /* LFN configuration */ +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ - get_xdir_info(fs->dirbuf, fno); + get_xfileinfo(fs->dirbuf, fno); return; } else #endif - { /* On the FAT12/16/32 volume */ + { /* On the FAT/FAT32 volume */ if (dp->blk_ofs != 0xFFFFFFFF) { /* Get LFN if available */ - i = j = 0; - while ((w = fs->lfnbuf[j++]) != 0) { /* Get an LFN character */ -#if !_LFN_UNICODE - w = ff_convert(w, 0); /* Unicode -> OEM */ - if (w == 0) { i = 0; break; } /* No LFN if it could not be converted */ - if (_DF1S && w >= 0x100) { /* Put 1st byte if it is a DBC (always false at SBCS cfg) */ - fno->fname[i++] = (char)(w >> 8); + si = di = hs = 0; + while (fs->lfnbuf[si] != 0) { + wc = fs->lfnbuf[si++]; /* Get an LFN character (UTF-16) */ + if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ + hs = wc; continue; /* Get low surrogate */ } -#endif - if (i >= _MAX_LFN) { i = 0; break; } /* No LFN if buffer overflow */ - fno->fname[i++] = (TCHAR)w; + wc = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in UTF-16 or UTF-8 encoding */ + if (wc == 0) { di = 0; break; } /* Invalid char or buffer overflow? */ + di += wc; + hs = 0; } - fno->fname[i] = 0; /* Terminate the LFN */ + if (hs != 0) di = 0; /* Broken surrogate pair? */ + fno->fname[di] = 0; /* Terminate the LFN (null string means LFN is invalid) */ } } - i = j = 0; - lfv = fno->fname[i]; /* LFN is exist if non-zero */ - while (i < 11) { /* Copy name body and extension */ - c = (TCHAR)dp->dir[i++]; - if (c == ' ') continue; /* Skip padding spaces */ - if (c == RDDEM) c = (TCHAR)DDEM; /* Restore replaced DDEM character */ - if (i == 9) { /* Insert a . if extension is exist */ - if (!lfv) fno->fname[j] = '.'; - fno->altname[j++] = '.'; + si = di = 0; + while (si < 11) { /* Get SFN from SFN entry */ + wc = dp->dir[si++]; /* Get a char */ + if (wc == ' ') continue; /* Skip padding spaces */ + if (wc == RDDEM) wc = DDEM; /* Restore replaced DDEM character */ + if (si == 9 && di < FF_SFN_BUF) fno->altname[di++] = '.'; /* Insert a . if extension is exist */ +#if FF_LFN_UNICODE >= 1 /* Unicode output */ + if (dbc_1st((BYTE)wc) && si != 8 && si != 11 && dbc_2nd(dp->dir[si])) { /* Make a DBC if needed */ + wc = wc << 8 | dp->dir[si++]; } -#if _LFN_UNICODE - if (IsDBCS1(c) && i != 8 && i != 11 && IsDBCS2(dp->dir[i])) { - c = c << 8 | dp->dir[i++]; - } - c = ff_convert(c, 1); /* OEM -> Unicode */ - if (!c) c = '?'; + wc = ff_oem2uni(wc, CODEPAGE); /* ANSI/OEM -> Unicode */ + if (wc == 0) { di = 0; break; } /* Wrong char in the current code page? */ + wc = put_utf(wc, &fno->altname[di], FF_SFN_BUF - di); /* Store it in Unicode */ + if (wc == 0) { di = 0; break; } /* Buffer overflow? */ + di += wc; +#else /* ANSI/OEM output */ + fno->altname[di++] = (TCHAR)wc; /* Store it without any conversion */ #endif - fno->altname[j] = c; - if (!lfv) { - if (IsUpper(c) && (dp->dir[DIR_NTres] & (i >= 9 ? NS_EXT : NS_BODY))) { - c += 0x20; /* To lower */ + } + fno->altname[di] = 0; /* Terminate the SFN (null string means SFN is invalid) */ + + if (fno->fname[0] == 0) { /* If LFN is invalid, altname[] needs to be copied to fname[] */ + if (di == 0) { /* If LFN and SFN both are invalid, this object is inaccesible */ + fno->fname[di++] = '?'; + } else { + for (si = di = 0, lcf = NS_BODY; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */ + wc = (WCHAR)fno->altname[si]; + if (wc == '.') lcf = NS_EXT; + if (IsUpper(wc) && (dp->dir[DIR_NTres] & lcf)) wc += 0x20; + fno->fname[di] = (TCHAR)wc; } - fno->fname[j] = c; } - j++; + fno->fname[di] = 0; /* Terminate the LFN */ + if (!dp->dir[DIR_NTres]) fno->altname[0] = 0; /* Altname is not needed if neither LFN nor case info is exist. */ } - if (!lfv) { - fno->fname[j] = 0; - if (!dp->dir[DIR_NTres]) j = 0; /* Altname is no longer needed if neither LFN nor case info is exist. */ - } - fno->altname[j] = 0; /* Terminate the SFN */ #else /* Non-LFN configuration */ - i = j = 0; - while (i < 11) { /* Copy name body and extension */ - c = (TCHAR)dp->dir[i++]; - if (c == ' ') continue; /* Skip padding spaces */ - if (c == RDDEM) c = (TCHAR)DDEM; /* Restore replaced DDEM character */ - if (i == 9) fno->fname[j++] = '.'; /* Insert a . if extension is exist */ - fno->fname[j++] = c; + si = di = 0; + while (si < 11) { /* Copy name body and extension */ + c = (TCHAR)dp->dir[si++]; + if (c == ' ') continue; /* Skip padding spaces */ + if (c == RDDEM) c = DDEM; /* Restore replaced DDEM character */ + if (si == 9) fno->fname[di++] = '.';/* Insert a . if extension is exist */ + fno->fname[di++] = c; } - fno->fname[j] = 0; + fno->fname[di] = 0; #endif - fno->fattrib = dp->dir[DIR_Attr]; /* Attribute */ - fno->fsize = ld_dword(dp->dir + DIR_FileSize); /* Size */ - tm = ld_dword(dp->dir + DIR_ModTime); /* Timestamp */ - fno->ftime = (WORD)tm; fno->fdate = (WORD)(tm >> 16); + fno->fattrib = dp->dir[DIR_Attr]; /* Attribute */ + fno->fsize = ld_dword(dp->dir + DIR_FileSize); /* Size */ + fno->ftime = ld_word(dp->dir + DIR_ModTime + 0); /* Time */ + fno->fdate = ld_word(dp->dir + DIR_ModTime + 2); /* Date */ } -#endif /* _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 */ +#endif /* FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 */ -#if _USE_FIND && _FS_MINIMIZE <= 1 +#if FF_USE_FIND && FF_FS_MINIMIZE <= 1 /*-----------------------------------------------------------------------*/ /* Pattern matching */ /*-----------------------------------------------------------------------*/ -static -WCHAR get_achar ( /* Get a character and advances ptr 1 or 2 */ - const TCHAR** ptr /* Pointer to pointer to the SBCS/DBCS/Unicode string */ +static DWORD get_achar ( /* Get a character and advances ptr */ + const TCHAR** ptr /* Pointer to pointer to the ANSI/OEM or Unicode string */ ) { -#if !_LFN_UNICODE - WCHAR chr; + DWORD chr; - chr = (BYTE)*(*ptr)++; /* Get a byte */ - if (IsLower(chr)) chr -= 0x20; /* To upper ASCII char */ -#ifdef _EXCVT + +#if FF_USE_LFN && FF_LFN_UNICODE >= 1 /* Unicode input */ + chr = tchar2uni(ptr); + if (chr == 0xFFFFFFFF) chr = 0; /* Wrong UTF encoding is recognized as end of the string */ + chr = ff_wtoupper(chr); + +#else /* ANSI/OEM input */ + chr = (BYTE)*(*ptr)++; /* Get a byte */ + if (IsLower(chr)) chr -= 0x20; /* To upper ASCII char */ +#if FF_CODE_PAGE == 0 + if (ExCvt && chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ +#elif FF_CODE_PAGE < 900 if (chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ -#else - if (IsDBCS1(chr) && IsDBCS2(**ptr)) { /* Get DBC 2nd byte if needed */ - chr = chr << 8 | (BYTE)*(*ptr)++; +#endif +#if FF_CODE_PAGE == 0 || FF_CODE_PAGE >= 900 + if (dbc_1st((BYTE)chr)) { /* Get DBC 2nd byte if needed */ + chr = dbc_2nd((BYTE)**ptr) ? chr << 8 | (BYTE)*(*ptr)++ : 0; } #endif - return chr; -#else - return ff_wtoupper(*(*ptr)++); /* Get a word and to upper */ + #endif + return chr; } -static -int pattern_matching ( /* 0:not matched, 1:matched */ +static int pattern_matching ( /* 0:not matched, 1:matched */ const TCHAR* pat, /* Matching pattern */ const TCHAR* nam, /* String to be tested */ int skip, /* Number of pre-skip chars (number of ?s) */ @@ -2505,21 +2757,21 @@ int pattern_matching ( /* 0:not matched, 1:matched */ ) { const TCHAR *pp, *np; - WCHAR pc, nc; + DWORD pc, nc; int nm, nx; while (skip--) { /* Pre-skip name chars */ if (!get_achar(&nam)) return 0; /* Branch mismatched if less name chars */ } - if (!*pat && inf) return 1; /* (short circuit) */ + if (*pat == 0 && inf) return 1; /* (short circuit) */ do { pp = pat; np = nam; /* Top of pattern and name to match */ for (;;) { if (*pp == '?' || *pp == '*') { /* Wildcard? */ nm = nx = 0; - do { /* Analyze the wildcard chars */ + do { /* Analyze the wildcard block */ if (*pp++ == '?') nm++; else nx = 1; } while (*pp == '?' || *pp == '*'); if (pattern_matching(pp, np, nm, nx)) return 1; /* Test new branch (recurs upto number of wildcard blocks in the pattern) */ @@ -2536,7 +2788,7 @@ int pattern_matching ( /* 0:not matched, 1:matched */ return 0; } -#endif /* _USE_FIND && _FS_MINIMIZE <= 1 */ +#endif /* FF_USE_FIND && FF_FS_MINIMIZE <= 1 */ @@ -2544,131 +2796,133 @@ int pattern_matching ( /* 0:not matched, 1:matched */ /* Pick a top segment and create the object name in directory form */ /*-----------------------------------------------------------------------*/ -static -FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ - DIR* dp, /* Pointer to the directory object */ - const TCHAR** path /* Pointer to pointer to the segment in the path string */ +static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ + DIR* dp, /* Pointer to the directory object */ + const TCHAR** path /* Pointer to pointer to the segment in the path string */ ) { -#if _USE_LFN != 0 /* LFN configuration */ +#if FF_USE_LFN /* LFN configuration */ BYTE b, cf; - WCHAR w, *lfn; + WCHAR wc, *lfn; + DWORD uc; UINT i, ni, si, di; const TCHAR *p; - /* Create LFN in Unicode */ - p = *path; lfn = dp->obj.fs->lfnbuf; si = di = 0; + + /* Create LFN into LFN working buffer */ + p = *path; lfn = dp->obj.fs->lfnbuf; di = 0; for (;;) { - w = p[si++]; /* Get a character */ - if (w < ' ') break; /* Break if end of the path name */ - if (w == '/' || w == '\\') { /* Break if a separator is found */ - while (p[si] == '/' || p[si] == '\\') si++; /* Skip duplicated separator if exist */ - break; - } - if (di >= _MAX_LFN) return FR_INVALID_NAME; /* Reject too long name */ -#if !_LFN_UNICODE - w &= 0xFF; - if (IsDBCS1(w)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */ - b = (BYTE)p[si++]; /* Get 2nd byte */ - w = (w << 8) + b; /* Create a DBC */ - if (!IsDBCS2(b)) return FR_INVALID_NAME; /* Reject invalid sequence */ - } - w = ff_convert(w, 1); /* Convert ANSI/OEM to Unicode */ - if (!w) return FR_INVALID_NAME; /* Reject invalid code */ -#endif - if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) return FR_INVALID_NAME; /* Reject illegal characters for LFN */ - lfn[di++] = w; /* Store the Unicode character */ + uc = tchar2uni(&p); /* Get a character */ + if (uc == 0xFFFFFFFF) return FR_INVALID_NAME; /* Invalid code or UTF decode error */ + if (uc >= 0x10000) lfn[di++] = (WCHAR)(uc >> 16); /* Store high surrogate if needed */ + wc = (WCHAR)uc; + if (wc < ' ' || wc == '/' || wc == '\\') break; /* Break if end of the path or a separator is found */ + if (wc < 0x80 && chk_chr("\"*:<>\?|\x7F", wc)) return FR_INVALID_NAME; /* Reject illegal characters for LFN */ + if (di >= FF_MAX_LFN) return FR_INVALID_NAME; /* Reject too long name */ + lfn[di++] = wc; /* Store the Unicode character */ } - *path = &p[si]; /* Return pointer to the next segment */ - cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ -#if _FS_RPATH != 0 + while (*p == '/' || *p == '\\') p++; /* Skip duplicated separators if exist */ + *path = p; /* Return pointer to the next segment */ + cf = (wc < ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ + +#if FF_FS_RPATH != 0 if ((di == 1 && lfn[di - 1] == '.') || (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { /* Is this segment a dot name? */ lfn[di] = 0; - for (i = 0; i < 11; i++) /* Create dot name for SFN entry */ + for (i = 0; i < 11; i++) { /* Create dot name for SFN entry */ dp->fn[i] = (i < di) ? '.' : ' '; + } dp->fn[i] = cf | NS_DOT; /* This is a dot entry */ return FR_OK; } #endif while (di) { /* Snip off trailing spaces and dots if exist */ - w = lfn[di - 1]; - if (w != ' ' && w != '.') break; + wc = lfn[di - 1]; + if (wc != ' ' && wc != '.') break; di--; } - lfn[di] = 0; /* LFN is created */ - if (di == 0) return FR_INVALID_NAME; /* Reject nul name */ + lfn[di] = 0; /* LFN is created into the working buffer */ + if (di == 0) return FR_INVALID_NAME; /* Reject null name */ /* Create SFN in directory form */ - mem_set(dp->fn, ' ', 11); - for (si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++) ; /* Strip leading spaces and dots */ - if (si) cf |= NS_LOSS | NS_LFN; - while (di && lfn[di - 1] != '.') di--; /* Find extension (di<=si: no extension) */ + for (si = 0; lfn[si] == ' '; si++) ; /* Remove leading spaces */ + if (si > 0 || lfn[si] == '.') cf |= NS_LOSS | NS_LFN; /* Is there any leading space or dot? */ + while (di > 0 && lfn[di - 1] != '.') di--; /* Find last dot (di<=si: no extension) */ + mem_set(dp->fn, ' ', 11); i = b = 0; ni = 8; for (;;) { - w = lfn[si++]; /* Get an LFN character */ - if (!w) break; /* Break on end of the LFN */ - if (w == ' ' || (w == '.' && si != di)) { /* Remove spaces and dots */ - cf |= NS_LOSS | NS_LFN; continue; + wc = lfn[si++]; /* Get an LFN character */ + if (wc == 0) break; /* Break on end of the LFN */ + if (wc == ' ' || (wc == '.' && si != di)) { /* Remove embedded spaces and dots */ + cf |= NS_LOSS | NS_LFN; + continue; } - if (i >= ni || si == di) { /* Extension or end of SFN */ - if (ni == 11) { /* Long extension */ - cf |= NS_LOSS | NS_LFN; break; + if (i >= ni || si == di) { /* End of field? */ + if (ni == 11) { /* Name extension overflow? */ + cf |= NS_LOSS | NS_LFN; + break; } - if (si != di) cf |= NS_LOSS | NS_LFN; /* Out of 8.3 format */ - if (si > di) break; /* No extension */ - si = di; i = 8; ni = 11; /* Enter extension section */ - b <<= 2; continue; + if (si != di) cf |= NS_LOSS | NS_LFN; /* Name body overflow? */ + if (si > di) break; /* No name extension? */ + si = di; i = 8; ni = 11; b <<= 2; /* Enter name extension */ + continue; } - if (w >= 0x80) { /* Non ASCII character */ -#ifdef _EXCVT - w = ff_convert(w, 0); /* Unicode -> OEM code */ - if (w) w = ExCvt[w - 0x80]; /* Convert extended character to upper (SBCS) */ -#else - w = ff_convert(ff_wtoupper(w), 0); /* Upper converted Unicode -> OEM code */ + if (wc >= 0x80) { /* Is this a non-ASCII character? */ + cf |= NS_LFN; /* LFN entry needs to be created */ +#if FF_CODE_PAGE == 0 + if (ExCvt) { /* At SBCS */ + wc = ff_uni2oem(wc, CODEPAGE); /* Unicode ==> ANSI/OEM code */ + if (wc & 0x80) wc = ExCvt[wc & 0x7F]; /* Convert extended character to upper (SBCS) */ + } else { /* At DBCS */ + wc = ff_uni2oem(ff_wtoupper(wc), CODEPAGE); /* Unicode ==> Upper convert ==> ANSI/OEM code */ + } +#elif FF_CODE_PAGE < 900 /* SBCS cfg */ + wc = ff_uni2oem(wc, CODEPAGE); /* Unicode ==> ANSI/OEM code */ + if (wc & 0x80) wc = ExCvt[wc & 0x7F]; /* Convert extended character to upper (SBCS) */ +#else /* DBCS cfg */ + wc = ff_uni2oem(ff_wtoupper(wc), CODEPAGE); /* Unicode ==> Upper convert ==> ANSI/OEM code */ #endif - cf |= NS_LFN; /* Force create LFN entry */ } - if (_DF1S && w >= 0x100) { /* Is this DBC? (always false at SBCS cfg) */ - if (i >= ni - 1) { - cf |= NS_LOSS | NS_LFN; i = ni; continue; + if (wc >= 0x100) { /* Is this a DBC? */ + if (i >= ni - 1) { /* Field overflow? */ + cf |= NS_LOSS | NS_LFN; + i = ni; continue; /* Next field */ } - dp->fn[i++] = (BYTE)(w >> 8); + dp->fn[i++] = (BYTE)(wc >> 8); /* Put 1st byte */ } else { /* SBC */ - if (!w || chk_chr("+,;=[]", w)) { /* Replace illegal characters for SFN */ - w = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */ + if (wc == 0 || chk_chr("+,;=[]", wc)) { /* Replace illegal characters for SFN if needed */ + wc = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */ } else { - if (IsUpper(w)) { /* ASCII large capital */ + if (IsUpper(wc)) { /* ASCII upper case? */ b |= 2; - } else { - if (IsLower(w)) { /* ASCII small capital */ - b |= 1; w -= 0x20; - } + } + if (IsLower(wc)) { /* ASCII lower case? */ + b |= 1; wc -= 0x20; } } } - dp->fn[i++] = (BYTE)w; + dp->fn[i++] = (BYTE)wc; } if (dp->fn[0] == DDEM) dp->fn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */ - if (ni == 8) b <<= 2; - if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) cf |= NS_LFN; /* Create LFN entry when there are composite capitals */ - if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended character, NT flags are created */ - if ((b & 0x03) == 0x01) cf |= NS_EXT; /* NT flag (Extension has only small capital) */ - if ((b & 0x0C) == 0x04) cf |= NS_BODY; /* NT flag (Filename has only small capital) */ + if (ni == 8) b <<= 2; /* Shift capital flags if no extension */ + if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) cf |= NS_LFN; /* LFN entry needs to be created if composite capitals */ + if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended character, NT flags are created */ + if (b & 0x01) cf |= NS_EXT; /* NT flag (Extension has small capital letters only) */ + if (b & 0x04) cf |= NS_BODY; /* NT flag (Body has small capital letters only) */ } - dp->fn[NSFLAG] = cf; /* SFN is created */ + dp->fn[NSFLAG] = cf; /* SFN is created into dp->fn[] */ return FR_OK; -#else /* _USE_LFN != 0 : Non-LFN configuration */ +#else /* FF_USE_LFN : Non-LFN configuration */ BYTE c, d, *sfn; UINT ni, si, i; const char *p; @@ -2677,7 +2931,7 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create p = *path; sfn = dp->fn; mem_set(sfn, ' ', 11); si = i = 0; ni = 8; -#if _FS_RPATH != 0 +#if FF_FS_RPATH != 0 if (p[si] == '.') { /* Is this a dot entry? */ for (;;) { c = (BYTE)p[si++]; @@ -2691,29 +2945,29 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create } #endif for (;;) { - c = (BYTE)p[si++]; + c = (BYTE)p[si++]; /* Get a byte */ if (c <= ' ') break; /* Break if end of the path name */ if (c == '/' || c == '\\') { /* Break if a separator is found */ while (p[si] == '/' || p[si] == '\\') si++; /* Skip duplicated separator if exist */ break; } - if (c == '.' || i >= ni) { /* End of body or over size? */ - if (ni == 11 || c != '.') return FR_INVALID_NAME; /* Over size or invalid dot */ - i = 8; ni = 11; /* Goto extension */ + if (c == '.' || i >= ni) { /* End of body or field overflow? */ + if (ni == 11 || c != '.') return FR_INVALID_NAME; /* Field overflow or invalid dot? */ + i = 8; ni = 11; /* Enter file extension field */ continue; } - if (c >= 0x80) { /* Extended character? */ -#ifdef _EXCVT - c = ExCvt[c - 0x80]; /* To upper extended characters (SBCS cfg) */ -#else -#if !_DF1S - return FR_INVALID_NAME; /* Reject extended characters (ASCII only cfg) */ -#endif -#endif +#if FF_CODE_PAGE == 0 + if (ExCvt && c >= 0x80) { /* Is SBC extended character? */ + c = ExCvt[c & 0x7F]; /* To upper SBC extended character */ } - if (IsDBCS1(c)) { /* Check if it is a DBC 1st byte (always false at SBCS cfg.) */ +#elif FF_CODE_PAGE < 900 + if (c >= 0x80) { /* Is SBC extended character? */ + c = ExCvt[c & 0x7F]; /* To upper SBC extended character */ + } +#endif + if (dbc_1st(c)) { /* Check if it is a DBC 1st byte */ d = (BYTE)p[si++]; /* Get 2nd byte */ - if (!IsDBCS2(d) || i >= ni - 1) return FR_INVALID_NAME; /* Reject invalid DBC */ + if (!dbc_2nd(d) || i >= ni - 1) return FR_INVALID_NAME; /* Reject invalid DBC */ sfn[i++] = c; sfn[i++] = d; } else { /* SBC */ @@ -2729,7 +2983,7 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create sfn[NSFLAG] = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ return FR_OK; -#endif /* _USE_LFN != 0 */ +#endif /* FF_USE_LFN */ } @@ -2739,39 +2993,40 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create /* Follow a file path */ /*-----------------------------------------------------------------------*/ -static -FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ - DIR* dp, /* Directory object to return last directory and found object */ - const TCHAR* path /* Full-path string to find a file or directory */ +static FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ + DIR* dp, /* Directory object to return last directory and found object */ + const TCHAR* path /* Full-path string to find a file or directory */ ) { FRESULT res; BYTE ns; - _FDID *obj = &dp->obj; - FATFS *fs = obj->fs; + FATFS *fs = dp->obj.fs; -#if _FS_RPATH != 0 +#if FF_FS_RPATH != 0 if (*path != '/' && *path != '\\') { /* Without heading separator */ - obj->sclust = fs->cdir; /* Start from the current directory */ + dp->obj.sclust = fs->cdir; /* Start from current directory */ } else #endif { /* With heading separator */ while (*path == '/' || *path == '\\') path++; /* Strip heading separator */ - obj->sclust = 0; /* Start from the root directory */ + dp->obj.sclust = 0; /* Start from root directory */ } -#if _FS_EXFAT && _FS_RPATH != 0 - if (fs->fs_type == FS_EXFAT && obj->sclust) { /* Retrieve the sub-directory status if needed */ +#if FF_FS_EXFAT + dp->obj.n_frag = 0; /* Invalidate last fragment counter of the object */ +#if FF_FS_RPATH != 0 + if (fs->fs_type == FS_EXFAT && dp->obj.sclust) { /* exFAT: Retrieve the sub-directory's status */ DIR dj; - obj->c_scl = fs->cdc_scl; - obj->c_size = fs->cdc_size; - obj->c_ofs = fs->cdc_ofs; - res = load_obj_dir(&dj, obj); + dp->obj.c_scl = fs->cdc_scl; + dp->obj.c_size = fs->cdc_size; + dp->obj.c_ofs = fs->cdc_ofs; + res = load_obj_xdir(&dj, &dp->obj); if (res != FR_OK) return res; - obj->objsize = ld_dword(fs->dirbuf + XDIR_FileSize); - obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; + dp->obj.objsize = ld_dword(fs->dirbuf + XDIR_FileSize); + dp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; } +#endif #endif if ((UINT)*path < ' ') { /* Null path name is the origin directory itself */ @@ -2786,7 +3041,7 @@ FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ ns = dp->fn[NSFLAG]; if (res != FR_OK) { /* Failed to find the object */ if (res == FR_NO_FILE) { /* Object is not found */ - if (_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, stay there */ + if (FF_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, stay there */ if (!(ns & NS_LAST)) continue; /* Continue to follow if not last segment */ dp->fn[NSFLAG] = NS_NONAME; res = FR_OK; @@ -2798,21 +3053,19 @@ FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ } if (ns & NS_LAST) break; /* Last segment matched. Function completed. */ /* Get into the sub-directory */ - if (!(obj->attr & AM_DIR)) { /* It is not a sub-directory and cannot follow */ + if (!(dp->obj.attr & AM_DIR)) { /* It is not a sub-directory and cannot follow */ res = FR_NO_PATH; break; } -#if _FS_EXFAT - if (fs->fs_type == FS_EXFAT) { - obj->c_scl = obj->sclust; /* Save containing directory information for next dir */ - obj->c_size = ((DWORD)obj->objsize & 0xFFFFFF00) | obj->stat; - obj->c_ofs = dp->blk_ofs; - obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Open next directory */ - obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; - obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize); +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* Save containing directory information for next dir */ + dp->obj.c_scl = dp->obj.sclust; + dp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat; + dp->obj.c_ofs = dp->blk_ofs; + init_alloc_info(fs, &dp->obj); /* Open next directory */ } else #endif { - obj->sclust = ld_clust(fs, fs->win + dp->dptr % SS(fs)); /* Open next directory */ + dp->obj.sclust = ld_clust(fs, fs->win + dp->dptr % SS(fs)); /* Open next directory */ } } } @@ -2824,41 +3077,39 @@ FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ /*-----------------------------------------------------------------------*/ -/* Load a sector and check if it is an FAT boot sector */ +/* Load a sector and check if it is an FAT VBR */ /*-----------------------------------------------------------------------*/ -static -BYTE check_fs ( /* 0:FAT, 1:exFAT, 2:Valid BS but not FAT, 3:Not a BS, 4:Disk error */ - FATFS* fs, /* File system object */ - DWORD sect /* Sector# (lba) to check if it is an FAT-VBR or not */ +static BYTE check_fs ( /* 0:FAT, 1:exFAT, 2:Valid BS but not FAT, 3:Not a BS, 4:Disk error */ + FATFS* fs, /* Filesystem object */ + DWORD sect /* Sector# (lba) to load and check if it is an FAT-VBR or not */ ) { fs->wflag = 0; fs->winsect = 0xFFFFFFFF; /* Invaidate window */ if (move_window(fs, sect) != FR_OK) return 4; /* Load boot record */ - if (ld_word(fs->win + BS_55AA) != 0xAA55) return 3; /* Check boot record signature (always placed at offset 510 even if the sector size is >512) */ + if (ld_word(fs->win + BS_55AA) != 0xAA55) return 3; /* Check boot record signature (always here regardless of the sector size) */ - if (fs->win[BS_JmpBoot] == 0xE9 || (fs->win[BS_JmpBoot] == 0xEB && fs->win[BS_JmpBoot + 2] == 0x90)) { - if ((ld_dword(fs->win + BS_FilSysType) & 0xFFFFFF) == 0x544146) return 0; /* Check "FAT" string */ - if (ld_dword(fs->win + BS_FilSysType32) == 0x33544146) return 0; /* Check "FAT3" string */ - } -#if _FS_EXFAT - if (!mem_cmp(fs->win + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11)) return 1; +#if FF_FS_EXFAT + if (!mem_cmp(fs->win + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11)) return 1; /* Check if exFAT VBR */ #endif - return 2; + if (fs->win[BS_JmpBoot] == 0xE9 || fs->win[BS_JmpBoot] == 0xEB || fs->win[BS_JmpBoot] == 0xE8) { /* Valid JumpBoot code? */ + if (!mem_cmp(fs->win + BS_FilSysType, "FAT", 3)) return 0; /* Is it an FAT VBR? */ + if (!mem_cmp(fs->win + BS_FilSysType32, "FAT32", 5)) return 0; /* Is it an FAT32 VBR? */ + } + return 2; /* Valid BS but not FAT */ } /*-----------------------------------------------------------------------*/ -/* Find logical drive and check if the volume is mounted */ +/* Determine logical drive number and mount the volume if needed */ /*-----------------------------------------------------------------------*/ -static -FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ - FATFS* fs, /* Pointer to the file system object */ - BYTE mode /* !=0: Check write protection for write access */ +static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */ + FATFS *fs, /* Pointer to the file system object */ + BYTE mode /* !=0: Check write protection for write access */ ) { BYTE fmt, *pt; @@ -2868,65 +3119,70 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ UINT i; - ENTER_FF(fs); /* Lock the volume */ +#if FF_FS_REENTRANT + if (!lock_fs(fs)) return FR_TIMEOUT; /* Lock the volume */ +#endif mode &= (BYTE)~FA_READ; /* Desired access mode, write access or not */ - if (fs->fs_type) { /* If the volume has been mounted */ + if (fs->fs_type != 0) { /* If the volume has been mounted */ disk_ioctl(fs->drv, IOCTL_STATUS, &stat); if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized */ - if (!_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check write protection if needed */ + if (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check write protection if needed */ return FR_WRITE_PROTECTED; } - return FR_OK; /* The file system object is valid */ + return FR_OK; /* The filesystem object is valid */ } } - /* The file system object is not valid. */ - /* Following code attempts to mount the volume. (analyze BPB and initialize the fs object) */ + /* The filesystem object is not valid. */ + /* Following code attempts to mount the volume. (analyze BPB and initialize the filesystem object) */ - fs->fs_type = 0; /* Clear the file system object */ + fs->fs_type = 0; /* Clear the filesystem object */ disk_ioctl(fs->drv, IOCTL_INIT, &stat); /* Initialize the physical drive */ if (stat & STA_NOINIT) { /* Check if the initialization succeeded */ return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */ } - if (!_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check disk write protection if needed */ + if (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check disk write protection if needed */ return FR_WRITE_PROTECTED; } -#if _MAX_SS != _MIN_SS /* Get sector size (multiple sector size cfg only) */ +#if FF_MAX_SS != FF_MIN_SS /* Get sector size (multiple sector size cfg only) */ if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK) return FR_DISK_ERR; - if (SS(fs) > _MAX_SS || SS(fs) < _MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR; + if (SS(fs) > FF_MAX_SS || SS(fs) < FF_MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR; #endif - /* Find an FAT partition on the drive. Supports only generic partitioning, FDISK and SFD. */ + + /* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK (MBR) and SFD (w/o partition). */ bsect = 0; fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT-VBR as SFD */ if (fmt == 2 || (fmt < 2 && LD2PT(fs) != 0)) { /* Not an FAT-VBR or forced partition number */ - for (i = 0; i < 4; i++) { /* Get partition offset */ + for (i = 0; i < 4; i++) { /* Get partition offset */ pt = fs->win + (MBR_Table + i * SZ_PTE); br[i] = pt[PTE_System] ? ld_dword(pt + PTE_StLba) : 0; } - i = LD2PT(fs); /* Partition number: 0:auto, 1-4:forced */ - if (i) i--; - do { /* Find an FAT volume */ + i = LD2PT(fs); /* Partition number: 0:auto, 1-4:forced */ + if (i != 0) i--; + do { /* Find an FAT volume */ bsect = br[i]; fmt = bsect ? check_fs(fs, bsect) : 3; /* Check the partition */ - } while (!LD2PT(fs) && fmt >= 2 && ++i < 4); + } while (LD2PT(fs) == 0 && fmt >= 2 && ++i < 4); } if (fmt == 4) return FR_DISK_ERR; /* An error occured in the disk I/O layer */ if (fmt >= 2) return FR_NO_FILESYSTEM; /* No FAT volume is found */ - /* An FAT volume is found. Following code initializes the file system object */ + /* An FAT volume is found (bsect). Following code initializes the filesystem object */ -#if _FS_EXFAT +#if FF_FS_EXFAT if (fmt == 1) { QWORD maxlba; + DWORD so, cv, bcl; for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */ if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM; - if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM; /* Check exFAT revision (Must be 1.0) */ + if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM; /* Check exFAT version (must be version 1.0) */ - if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) /* (BPB_BytsPerSecEx must be equal to the physical sector size) */ + if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) { /* (BPB_BytsPerSecEx must be equal to the physical sector size) */ return FR_NO_FILESYSTEM; + } maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Last LBA + 1 of the volume */ if (maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */ @@ -2950,106 +3206,123 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */ fs->dirbase = ld_dword(fs->win + BPB_RootClusEx); - /* Check if bitmap location is in assumption (at the first cluster) */ - if (move_window(fs, clust2sect(fs, fs->dirbase)) != FR_OK) return FR_DISK_ERR; - for (i = 0; i < SS(fs); i += SZDIRE) { - if (fs->win[i] == 0x81 && ld_dword(fs->win + i + 20) == 2) break; /* 81 entry with cluster #2? */ + /* Get bitmap location and check if it is contiguous (implementation assumption) */ + so = i = 0; + for (;;) { /* Find the bitmap entry in the root directory (in only first cluster) */ + if (i == 0) { + if (so >= fs->csize) return FR_NO_FILESYSTEM; /* Not found? */ + if (move_window(fs, clst2sect(fs, fs->dirbase) + so) != FR_OK) return FR_DISK_ERR; + so++; + } + if (fs->win[i] == ET_BITMAP) break; /* Is it a bitmap entry? */ + i = (i + SZDIRE) % SS(fs); /* Next entry */ } - if (i == SS(fs)) return FR_NO_FILESYSTEM; -#if !_FS_READONLY + bcl = ld_dword(fs->win + i + 20); /* Bitmap cluster */ + if (bcl < 2 || bcl >= fs->n_fatent) return FR_NO_FILESYSTEM; + fs->bitbase = fs->database + fs->csize * (bcl - 2); /* Bitmap sector */ + for (;;) { /* Check if bitmap is contiguous */ + if (move_window(fs, fs->fatbase + bcl / (SS(fs) / 4)) != FR_OK) return FR_DISK_ERR; + cv = ld_dword(fs->win + bcl % (SS(fs) / 4) * 4); + if (cv == 0xFFFFFFFF) break; /* Last link? */ + if (cv != ++bcl) return FR_NO_FILESYSTEM; /* Fragmented? */ + } + +#if !FF_FS_READONLY fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ #endif fmt = FS_EXFAT; /* FAT sub-type */ } else -#endif /* _FS_EXFAT */ +#endif /* FF_FS_EXFAT */ { if (ld_word(fs->win + BPB_BytsPerSec) != SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_BytsPerSec must be equal to the physical sector size) */ - fasize = ld_word(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ + fasize = ld_word(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ if (fasize == 0) fasize = ld_dword(fs->win + BPB_FATSz32); fs->fsize = fasize; - fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */ + fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */ if (fs->n_fats != 1 && fs->n_fats != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */ - fasize *= fs->n_fats; /* Number of sectors for FAT area */ + fasize *= fs->n_fats; /* Number of sectors for FAT area */ - fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */ + fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */ if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */ fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt); /* Number of root directory entries */ if (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM; /* (Must be sector aligned) */ - tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ + tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32); - nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ - if (nrsv == 0) return FR_NO_FILESYSTEM; /* (Must not be 0) */ + nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ + if (nrsv == 0) return FR_NO_FILESYSTEM; /* (Must not be 0) */ /* Determine the FAT sub type */ sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); /* RSV + FAT + DIR */ - if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ - nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ - if (nclst == 0) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ - fmt = FS_FAT32; + if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ + nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ + if (nclst == 0) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ + fmt = 0; + if (nclst <= MAX_FAT32) fmt = FS_FAT32; if (nclst <= MAX_FAT16) fmt = FS_FAT16; if (nclst <= MAX_FAT12) fmt = FS_FAT12; + if (fmt == 0) return FR_NO_FILESYSTEM; /* Boundaries and Limits */ - fs->n_fatent = nclst + 2; /* Number of FAT entries */ - fs->volbase = bsect; /* Volume start sector */ - fs->fatbase = bsect + nrsv; /* FAT start sector */ - fs->database = bsect + sysect; /* Data start sector */ + fs->n_fatent = nclst + 2; /* Number of FAT entries */ + fs->volbase = bsect; /* Volume start sector */ + fs->fatbase = bsect + nrsv; /* FAT start sector */ + fs->database = bsect + sysect; /* Data start sector */ if (fmt == FS_FAT32) { if (ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */ - if (fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ + if (fs->n_rootdir != 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ fs->dirbase = ld_dword(fs->win + BPB_RootClus32); /* Root directory start cluster */ - szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ + szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ } else { - if (fs->n_rootdir == 0) return FR_NO_FILESYSTEM;/* (BPB_RootEntCnt must not be 0) */ - fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ - szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */ + if (fs->n_rootdir == 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */ + fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ + szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */ fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1); } if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_FATSz must not be less than the size needed) */ -#if !_FS_READONLY - /* Get FSINFO if available */ +#if !FF_FS_READONLY + /* Get FSInfo if available */ fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ fs->fsi_flag = 0x80; -#if (_FS_NOFSINFO & 3) != 3 - if (fmt == FS_FAT32 /* Enable FSINFO only if FAT32 and BPB_FSInfo32 == 1 */ +#if (FF_FS_NOFSINFO & 3) != 3 + if (fmt == FS_FAT32 /* Allow to update FSInfo only if BPB_FSInfo32 == 1 */ && ld_word(fs->win + BPB_FSInfo32) == 1 && move_window(fs, bsect + 1) == FR_OK) { fs->fsi_flag = 0; - if (ld_word(fs->win + BS_55AA) == 0xAA55 /* Load FSINFO data if available */ + if (ld_word(fs->win + BS_55AA) == 0xAA55 /* Load FSInfo data if available */ && ld_dword(fs->win + FSI_LeadSig) == 0x41615252 && ld_dword(fs->win + FSI_StrucSig) == 0x61417272) { -#if (_FS_NOFSINFO & 1) == 0 +#if (FF_FS_NOFSINFO & 1) == 0 fs->free_clst = ld_dword(fs->win + FSI_Free_Count); #endif -#if (_FS_NOFSINFO & 2) == 0 +#if (FF_FS_NOFSINFO & 2) == 0 fs->last_clst = ld_dword(fs->win + FSI_Nxt_Free); #endif } } -#endif /* (_FS_NOFSINFO & 3) != 3 */ -#endif /* !_FS_READONLY */ +#endif /* (FF_FS_NOFSINFO & 3) != 3 */ +#endif /* !FF_FS_READONLY */ } - fs->fs_type = fmt; /* FAT sub-type */ - fs->id = ++Fsid; /* File system mount ID */ -#if _USE_LFN == 1 + fs->fs_type = fmt; /* FAT sub-type */ + fs->id = ++Fsid; /* Volume mount ID */ +#if FF_USE_LFN == 1 fs->lfnbuf = LfnBuf; /* Static LFN working buffer */ -#if _FS_EXFAT - fs->dirbuf = DirBuf; /* Static directory block working buuffer */ +#if FF_FS_EXFAT + fs->dirbuf = DirBuf; /* Static directory block scratchpad buuffer */ #endif #endif -#if _FS_RPATH != 0 - fs->cdir = 0; /* Initialize current directory */ +#if FF_FS_RPATH != 0 + fs->cdir = 0; /* Initialize current directory */ #endif -#if _FS_LOCK != 0 /* Clear file lock semaphores */ +#if FF_FS_LOCK != 0 /* Clear file lock semaphores */ clear_lock(fs); #endif return FR_OK; @@ -3062,24 +3335,33 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ /* Check if the file/directory object is valid or not */ /*-----------------------------------------------------------------------*/ -static -FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ - _FDID* obj, /* Pointer to the _OBJ, the 1st member in the FIL/DIR object, to check validity */ - FATFS** fs /* Pointer to pointer to the owner file system object to return */ +static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ + FFOBJID* obj, /* Pointer to the FFOBJID, the 1st member in the FIL/DIR object, to check validity */ + FATFS** rfs /* Pointer to pointer to the owner filesystem object to return */ ) { - FRESULT res; + FRESULT res = FR_INVALID_OBJECT; DSTATUS stat; - if (!obj || !obj->fs || !obj->fs->fs_type || obj->fs->id != obj->id || disk_ioctl(obj->fs->drv, IOCTL_STATUS, &stat) != RES_OK || (stat & STA_NOINIT)) { - *fs = 0; /* The object is invalid */ - res = FR_INVALID_OBJECT; - } else { - *fs = obj->fs; /* Owner file sytem object */ - ENTER_FF(obj->fs); /* Lock file system */ - res = FR_OK; + if (obj && obj->fs && obj->fs->fs_type && obj->id == obj->fs->id) { /* Test if the object is valid */ +#if FF_FS_REENTRANT + if (lock_fs(obj->fs)) { /* Obtain the filesystem object */ + if (disk_ioctl(obj->fs->drv, IOCTL_STATUS, &stat) == RES_OK && !(stat & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ + res = FR_OK; + } else { + unlock_fs(obj->fs, FR_OK); + } + } else { + res = FR_TIMEOUT; + } +#else + if (disk_ioctl(obj->fs->drv, IOCTL_STATUS, &stat) == RES_OK && (!stat & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ + res = FR_OK; + } +#endif } + *rfs = (res == FR_OK) ? obj->fs : 0; /* Corresponding filesystem object */ return res; } @@ -3105,7 +3387,7 @@ FRESULT f_mount ( FRESULT res; fs->fs_type = 0; /* Clear new fs object */ -#if _FS_REENTRANT /* Create sync object for the new volume */ +#if FF_FS_REENTRANT /* Create sync object for the new volume */ if (!ff_cre_syncobj(fs, &fs->sobj)) return FR_INT_ERR; #endif @@ -3118,10 +3400,10 @@ FRESULT f_umount ( FATFS* fs /* Pointer to the file system object to unmount */ ) { -#if _FS_LOCK +#if FF_FS_LOCK clear_lock(fs); #endif -#if _FS_REENTRANT /* Discard sync object of the current volume */ +#if FF_FS_REENTRANT /* Discard sync object of the current volume */ if (!ff_del_syncobj(fs->sobj)) return FR_INT_ERR; #endif fs->fs_type = 0; /* Clear old fs object */ @@ -3143,7 +3425,7 @@ FRESULT f_open ( { FRESULT res; DIR dj; -#if !_FS_READONLY +#if !FF_FS_READONLY DWORD dw, cl, bcs, clst, sc; FSIZE_t ofs; #endif @@ -3152,79 +3434,71 @@ FRESULT f_open ( if (!fp) return FR_INVALID_OBJECT; - /* Get logical drive */ - mode &= _FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND | FA_SEEKEND; + /* Get logical drive number */ + mode &= FF_FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND; res = find_volume(fs, mode); if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ -#if !_FS_READONLY /* R/W configuration */ +#if !FF_FS_READONLY /* Read/Write configuration */ if (res == FR_OK) { if (dj.fn[NSFLAG] & NS_NONAME) { /* Origin directory itself? */ res = FR_INVALID_NAME; } -#if _FS_LOCK != 0 +#if FF_FS_LOCK != 0 else { - res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0); + res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0); /* Check if the file can be used */ } #endif } /* Create or Open a file */ if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) { if (res != FR_OK) { /* No file, create new */ - if (res == FR_NO_FILE) /* There is no file to open, create a new entry */ -#if _FS_LOCK != 0 + if (res == FR_NO_FILE) { /* There is no file to open, create a new entry */ +#if FF_FS_LOCK != 0 res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; #else res = dir_register(&dj); #endif + } mode |= FA_CREATE_ALWAYS; /* File is created */ } - else { /* Any object is already existing */ + else { /* Any object with the same name is already existing */ if (dj.obj.attr & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or DIR) */ res = FR_DENIED; } else { if (mode & FA_CREATE_NEW) res = FR_EXIST; /* Cannot create as new file */ } } - if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */ - dw = GET_FATTIME(); -#if _FS_EXFAT + if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate the file if overwrite mode */ +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* Get current allocation info */ fp->obj.fs = fs; - fp->obj.sclust = ld_dword(fs->dirbuf + XDIR_FstClus); - fp->obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize); - fp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; - /* Initialize directory entry block */ - st_dword(fs->dirbuf + XDIR_CrtTime, dw); /* Set created time */ - fs->dirbuf[XDIR_CrtTime10] = 0; - st_dword(fs->dirbuf + XDIR_ModTime, dw); /* Set modified time */ - fs->dirbuf[XDIR_ModTime10] = 0; - fs->dirbuf[XDIR_Attr] = AM_ARC; /* Reset attribute */ - st_dword(fs->dirbuf + XDIR_FstClus, 0); /* Reset file allocation info */ - st_qword(fs->dirbuf + XDIR_FileSize, 0); - st_qword(fs->dirbuf + XDIR_ValidFileSize, 0); + init_alloc_info(fs, &fp->obj); + /* Set directory entry block initial state */ + mem_set(fs->dirbuf + 2, 0, 30); /* Clear 85 entry except for NumSec */ + mem_set(fs->dirbuf + 38, 0, 26); /* Clear C0 entry except for NumName and NameHash */ + fs->dirbuf[XDIR_Attr] = AM_ARC; + st_dword(fs->dirbuf + XDIR_CrtTime, GET_FATTIME()); fs->dirbuf[XDIR_GenFlags] = 1; res = store_xdir(&dj); - if (res == FR_OK && fp->obj.sclust) { /* Remove the cluster chain if exist */ + if (res == FR_OK && fp->obj.sclust != 0) { /* Remove the cluster chain if exist */ res = remove_chain(&fp->obj, fp->obj.sclust, 0); fs->last_clst = fp->obj.sclust - 1; /* Reuse the cluster hole */ } } else #endif { - /* Clean directory info */ - st_dword(dj.dir + DIR_CrtTime, dw); /* Set created time */ - st_dword(dj.dir + DIR_ModTime, dw); /* Set modified time */ + /* Set directory entry initial state */ + cl = ld_clust(fs, dj.dir); /* Get current cluster chain */ + st_dword(dj.dir + DIR_CrtTime, GET_FATTIME()); /* Set created time */ dj.dir[DIR_Attr] = AM_ARC; /* Reset attribute */ - cl = ld_clust(fs, dj.dir); /* Get cluster chain */ st_clust(fs, dj.dir, 0); /* Reset file allocation info */ st_dword(dj.dir + DIR_FileSize, 0); fs->wflag = 1; - - if (cl) { /* Remove the cluster chain if exist */ + if (cl != 0) { /* Remove the cluster chain if exist */ dw = fs->winsect; res = remove_chain(&dj.obj, cl, 0); if (res == FR_OK) { @@ -3236,32 +3510,31 @@ FRESULT f_open ( } } else { /* Open an existing file */ - if (res == FR_OK) { /* Following succeeded */ - if (dj.obj.attr & AM_DIR) { /* It is a directory */ + if (res == FR_OK) { /* Is the object exsiting? */ + if (dj.obj.attr & AM_DIR) { /* File open against a directory */ res = FR_NO_FILE; } else { - if ((mode & FA_WRITE) && (dj.obj.attr & AM_RDO)) { /* R/O violation */ + if ((mode & FA_WRITE) && (dj.obj.attr & AM_RDO)) { /* Write mode open against R/O file */ res = FR_DENIED; } } } } if (res == FR_OK) { - if (mode & FA_CREATE_ALWAYS) /* Set file change flag if created or overwritten */ - mode |= FA_MODIFIED; + if (mode & FA_CREATE_ALWAYS) mode |= FA_MODIFIED; /* Set file change flag if created or overwritten */ fp->dir_sect = fs->winsect; /* Pointer to the directory entry */ fp->dir_ptr = dj.dir; -#if _FS_LOCK != 0 - fp->obj.lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0); - if (!fp->obj.lockid) res = FR_INT_ERR; +#if FF_FS_LOCK != 0 + fp->obj.lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0); /* Lock the file for this session */ + if (fp->obj.lockid == 0) res = FR_INT_ERR; #endif } #else /* R/O configuration */ if (res == FR_OK) { - if (dj.fn[NSFLAG] & NS_NONAME) { /* Origin directory itself? */ + if (dj.fn[NSFLAG] & NS_NONAME) { /* Is it origin directory itself? */ res = FR_INVALID_NAME; } else { - if (dj.obj.attr & AM_DIR) { /* It is a directory */ + if (dj.obj.attr & AM_DIR) { /* Is it a directory? */ res = FR_NO_FILE; } } @@ -3269,21 +3542,19 @@ FRESULT f_open ( #endif if (res == FR_OK) { -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { - fp->obj.sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Get allocation info */ - fp->obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize); - fp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; - fp->obj.c_scl = dj.obj.sclust; + fp->obj.c_scl = dj.obj.sclust; /* Get containing directory info */ fp->obj.c_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; fp->obj.c_ofs = dj.blk_ofs; + init_alloc_info(fs, &fp->obj); } else #endif { - fp->obj.sclust = ld_clust(fs, dj.dir); /* Get allocation info */ + fp->obj.sclust = ld_clust(fs, dj.dir); /* Get object allocation info */ fp->obj.objsize = ld_dword(dj.dir + DIR_FileSize); } -#if _USE_FASTSEEK +#if FF_USE_FASTSEEK fp->cltbl = 0; /* Disable fast seek mode */ #endif fp->obj.fs = fs; /* Validate the file object */ @@ -3292,9 +3563,9 @@ FRESULT f_open ( fp->err = 0; /* Clear error flag */ fp->sect = 0; /* Invalidate current data sector */ fp->fptr = 0; /* Set file pointer top of the file */ -#if !_FS_READONLY -#if !_FS_TINY - mem_set(fp->buf, 0, _MAX_SS); /* Clear sector buffer */ +#if !FF_FS_READONLY +#if !FF_FS_TINY + mem_set(fp->buf, 0, sizeof fp->buf); /* Clear sector buffer */ #endif if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) { /* Seek to end of file if FA_OPEN_APPEND is specified */ fp->fptr = fp->obj.objsize; /* Offset to seek */ @@ -3307,11 +3578,11 @@ FRESULT f_open ( } fp->clust = clst; if (res == FR_OK && ofs % SS(fs)) { /* Fill sector buffer if not on the sector boundary */ - if ((sc = clust2sect(fs, clst)) == 0) { + if ((sc = clst2sect(fs, clst)) == 0) { res = FR_INT_ERR; } else { fp->sect = sc + (DWORD)(ofs / SS(fs)); -#if !_FS_TINY +#if !FF_FS_TINY if (disk_read(fs->drv, fp->buf, fp->sect, 1) != RES_OK) res = FR_DISK_ERR; #endif } @@ -3357,15 +3628,15 @@ FRESULT f_read ( remain = fp->obj.objsize - fp->fptr; if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ - for ( ; btr; /* Repeat until all data read */ - rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) { + for ( ; btr; /* Repeat until btr bytes read */ + btr -= rcnt, *br += rcnt, rbuff += rcnt, fp->fptr += rcnt) { if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ if (csect == 0) { /* On the cluster boundary? */ if (fp->fptr == 0) { /* On the top of the file? */ clst = fp->obj.sclust; /* Follow cluster chain from the origin */ } else { /* Middle or end of the file */ -#if _USE_FASTSEEK +#if FF_USE_FASTSEEK if (fp->cltbl) { clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ } else @@ -3378,17 +3649,17 @@ FRESULT f_read ( if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); fp->clust = clst; /* Update current cluster */ } - sect = clust2sect(fs, fp->clust); /* Get current sector */ - if (!sect) ABORT(fs, FR_INT_ERR); + sect = clst2sect(fs, fp->clust); /* Get current sector */ + if (sect == 0) ABORT(fs, FR_INT_ERR); sect += csect; cc = btr / SS(fs); /* When remaining bytes >= sector size, */ - if (cc) { /* Read maximum contiguous sectors directly */ + if (cc > 0) { /* Read maximum contiguous sectors directly */ if (csect + cc > fs->csize) { /* Clip at cluster boundary */ cc = fs->csize - csect; } if (disk_read(fs->drv, rbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR); -#if !_FS_READONLY && _FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */ -#if _FS_TINY +#if !FF_FS_READONLY && FF_FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */ +#if FF_FS_TINY if (fs->wflag && fs->winsect - sect < cc) { mem_cpy(rbuff + ((fs->winsect - sect) * SS(fs)), fs->win, SS(fs)); } @@ -3401,22 +3672,22 @@ FRESULT f_read ( rcnt = SS(fs) * cc; /* Number of bytes transferred */ continue; } -#if !_FS_TINY +#if !FF_FS_TINY if (fp->sect != sect) { /* Load data sector if not in cache */ -#if !_FS_READONLY +#if !FF_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif - if (disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ + if (disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ } #endif fp->sect = sect; } rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ if (rcnt > btr) rcnt = btr; /* Clip it by btr if needed */ -#if _FS_TINY +#if FF_FS_TINY if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ mem_cpy(rbuff, fs->win + fp->fptr % SS(fs), rcnt); /* Extract partial sector */ #else @@ -3430,7 +3701,7 @@ FRESULT f_read ( -#if !_FS_READONLY +#if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Write File */ /*-----------------------------------------------------------------------*/ @@ -3454,13 +3725,13 @@ FRESULT f_write ( if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ - /* Check fptr wrap-around (file size cannot reach 4GiB on FATxx) */ - if ((!_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) { + /* Check fptr wrap-around (file size cannot reach 4 GiB at FAT volume) */ + if ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) { btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr); } for ( ; btw; /* Repeat until all data written */ - wbuff += wcnt, fp->fptr += wcnt, fp->obj.objsize = (fp->fptr > fp->obj.objsize) ? fp->fptr : fp->obj.objsize, *bw += wcnt, btw -= wcnt) { + btw -= wcnt, *bw += wcnt, wbuff += wcnt, fp->fptr += wcnt, fp->obj.objsize = (fp->fptr > fp->obj.objsize) ? fp->fptr : fp->obj.objsize) { if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ csect = (UINT)(fp->fptr / SS(fs)) & (fs->csize - 1); /* Sector offset in the cluster */ if (csect == 0) { /* On the cluster boundary? */ @@ -3470,7 +3741,7 @@ FRESULT f_write ( clst = create_chain(&fp->obj, 0); /* create a new cluster chain */ } } else { /* On the middle or end of the file */ -#if _USE_FASTSEEK +#if FF_USE_FASTSEEK if (fp->cltbl) { clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ } else @@ -3485,7 +3756,7 @@ FRESULT f_write ( fp->clust = clst; /* Update current cluster */ if (fp->obj.sclust == 0) fp->obj.sclust = clst; /* Set start cluster if the first write */ } -#if _FS_TINY +#if FF_FS_TINY if (fs->winsect == fp->sect && sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Write-back sector cache */ #else if (fp->flag & FA_DIRTY) { /* Write-back sector cache */ @@ -3493,17 +3764,17 @@ FRESULT f_write ( fp->flag &= (BYTE)~FA_DIRTY; } #endif - sect = clust2sect(fs, fp->clust); /* Get current sector */ - if (!sect) ABORT(fs, FR_INT_ERR); + sect = clst2sect(fs, fp->clust); /* Get current sector */ + if (sect == 0) ABORT(fs, FR_INT_ERR); sect += csect; cc = btw / SS(fs); /* When remaining bytes >= sector size, */ - if (cc) { /* Write maximum contiguous sectors directly */ + if (cc > 0) { /* Write maximum contiguous sectors directly */ if (csect + cc > fs->csize) { /* Clip at cluster boundary */ cc = fs->csize - csect; } if (disk_write(fs->drv, wbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR); -#if _FS_MINIMIZE <= 2 -#if _FS_TINY +#if FF_FS_MINIMIZE <= 2 +#if FF_FS_TINY if (fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ mem_cpy(fs->win, wbuff + ((fs->winsect - sect) * SS(fs)), SS(fs)); fs->wflag = 0; @@ -3518,7 +3789,7 @@ FRESULT f_write ( wcnt = SS(fs) * cc; /* Number of bytes transferred */ continue; } -#if _FS_TINY +#if FF_FS_TINY if (fp->fptr >= fp->obj.objsize) { /* Avoid silly cache filling on the growing edge */ if (sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); fs->winsect = sect; @@ -3534,7 +3805,7 @@ FRESULT f_write ( } wcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ if (wcnt > btw) wcnt = btw; /* Clip it by btw if needed */ -#if _FS_TINY +#if FF_FS_TINY if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ mem_cpy(fs->win + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */ fs->wflag = 1; @@ -3564,15 +3835,12 @@ FRESULT f_sync ( FATFS *fs; DWORD tm; BYTE *dir; -#if _FS_EXFAT - DEF_NAMBUF -#endif res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res == FR_OK) { if (fp->flag & FA_MODIFIED) { /* Is there any change to the file? */ -#if !_FS_TINY +#if !FF_FS_TINY if (fp->flag & FA_DIRTY) { /* Write-back cached data if needed */ if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) LEAVE_FF(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; @@ -3580,17 +3848,21 @@ FRESULT f_sync ( #endif /* Update the directory entry */ tm = GET_FATTIME(); /* Modified time */ -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { - res = fill_fat_chain(&fp->obj); /* Create FAT chain if needed */ + res = fill_first_frag(&fp->obj); /* Fill first fragment on the FAT if needed */ + if (res == FR_OK) { + res = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */ + } if (res == FR_OK) { DIR dj; + DEF_NAMBUF INIT_NAMBUF(fs); - res = load_obj_dir(&dj, &fp->obj); /* Load directory entry block */ + res = load_obj_xdir(&dj, &fp->obj); /* Load directory entry block */ if (res == FR_OK) { - fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive bit */ - fs->dirbuf[XDIR_GenFlags] = fp->obj.stat | 1; /* Update file allocation info */ + fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive attribute to indicate that the file has been changed */ + fs->dirbuf[XDIR_GenFlags] = fp->obj.stat | 1; /* Update file allocation information */ st_dword(fs->dirbuf + XDIR_FstClus, fp->obj.sclust); st_qword(fs->dirbuf + XDIR_FileSize, fp->obj.objsize); st_qword(fs->dirbuf + XDIR_ValidFileSize, fp->obj.objsize); @@ -3611,8 +3883,8 @@ FRESULT f_sync ( res = move_window(fs, fp->dir_sect); if (res == FR_OK) { dir = fp->dir_ptr; - dir[DIR_Attr] |= AM_ARC; /* Set archive bit */ - st_clust(fp->obj.fs, dir, fp->obj.sclust); /* Update file allocation info */ + dir[DIR_Attr] |= AM_ARC; /* Set archive attribute to indicate that the file has been changed */ + st_clust(fp->obj.fs, dir, fp->obj.sclust); /* Update file allocation information */ st_dword(dir + DIR_FileSize, (DWORD)fp->obj.objsize); /* Update file size */ st_dword(dir + DIR_ModTime, tm); /* Update modified time */ st_word(dir + DIR_LstAccDate, 0); @@ -3627,7 +3899,7 @@ FRESULT f_sync ( LEAVE_FF(fs, res); } -#endif /* !_FS_READONLY */ +#endif /* !FF_FS_READONLY */ @@ -3643,21 +3915,20 @@ FRESULT f_close ( FRESULT res; FATFS *fs; -#if !_FS_READONLY +#if !FF_FS_READONLY res = f_sync(fp); /* Flush cached data */ if (res == FR_OK) #endif { res = validate(&fp->obj, &fs); /* Lock volume */ if (res == FR_OK) { -#if _FS_LOCK != 0 - res = dec_lock(fp->obj.lockid); /* Decrement file open counter */ - if (res == FR_OK) +#if FF_FS_LOCK != 0 + res = dec_lock(fp->obj.lockid); /* Decrement file open counter */ + if (res == FR_OK) fp->obj.fs = 0; /* Invalidate file object */ +#else + fp->obj.fs = 0; /* Invalidate file object */ #endif - { - fp->obj.fs = 0; /* Invalidate file object */ - } -#if _FS_REENTRANT +#if FF_FS_REENTRANT unlock_fs(fs, FR_OK); /* Unlock volume */ #endif } @@ -3668,7 +3939,7 @@ FRESULT f_close ( -#if _FS_RPATH >= 1 +#if FF_FS_RPATH >= 1 /*-----------------------------------------------------------------------*/ /* Change Current Directory or Current Drive, Get Current Directory */ /*-----------------------------------------------------------------------*/ @@ -3678,10 +3949,14 @@ FRESULT f_chdir ( const TCHAR* path /* Pointer to the directory path */ ) { +#if FF_STR_VOLUME_ID == 2 + UINT i; +#endif FRESULT res; DIR dj; DEF_NAMBUF + /* Get logical drive */ res = find_volume(fs, 0); if (res == FR_OK) { @@ -3689,9 +3964,9 @@ FRESULT f_chdir ( INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the path */ if (res == FR_OK) { /* Follow completed */ - if (dj.fn[NSFLAG] & NS_NONAME) { - fs->cdir = dj.obj.sclust; /* It is the start directory itself */ -#if _FS_EXFAT + if (dj.fn[NSFLAG] & NS_NONAME) { /* Is it the start directory itself? */ + fs->cdir = dj.obj.sclust; +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { fs->cdc_scl = dj.obj.c_scl; fs->cdc_size = dj.obj.c_size; @@ -3700,7 +3975,7 @@ FRESULT f_chdir ( #endif } else { if (dj.obj.attr & AM_DIR) { /* It is a sub-directory */ -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { fs->cdir = ld_dword(fs->dirbuf + XDIR_FstClus); /* Sub-directory cluster */ fs->cdc_scl = dj.obj.sclust; /* Save containing directory information */ @@ -3718,36 +3993,50 @@ FRESULT f_chdir ( } FREE_NAMBUF(); if (res == FR_NO_FILE) res = FR_NO_PATH; +#if FF_STR_VOLUME_ID == 2 /* Also current drive is changed at Unix style volume ID */ + if (res == FR_OK) { + for (i = FF_VOLUMES - 1; i && fs != FatFs[i]; i--) ; /* Set current drive */ + CurrVol = (BYTE)i; + } +#endif } LEAVE_FF(fs, res); } -#if _FS_RPATH >= 2 +#if FF_FS_RPATH >= 2 FRESULT f_getcwd ( FATFS *fs, TCHAR* buff, /* Pointer to the directory path */ - UINT len /* Size of path */ + UINT len /* Size of buff in unit of TCHAR */ ) { FRESULT res; DIR dj; UINT i, n; DWORD ccl; - TCHAR *tp; + TCHAR *tp = buff; +#if FF_VOLUMES >= 2 + UINT vl; +#endif +#if FF_STR_VOLUME_ID + const char *vp; +#endif FILINFO fno; DEF_NAMBUF - *buff = 0; /* Get logical drive */ - res = find_volume(fs, 0); /* Get current volume */ + buff[0] = 0; /* Set null string to get current volume */ + res = find_volume(fs, 0); /* Get current volume */ if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); + + /* Follow parent directories and create the path */ i = len; /* Bottom of buffer (directory stack base) */ - if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* (Cannot do getcwd on exFAT and returns root path) */ + if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* (Cannot do getcwd on exFAT and returns root path) */ dj.obj.sclust = fs->cdir; /* Start to follow upper directory from current directory */ while ((ccl = dj.obj.sclust) != 0) { /* Repeat while current directory is a sub-directory */ res = dir_sdi(&dj, 1 * SZDIRE); /* Get parent directory */ @@ -3758,7 +4047,7 @@ FRESULT f_getcwd ( res = dir_sdi(&dj, 0); if (res != FR_OK) break; do { /* Find the entry links to the child directory */ - res = dir_read(&dj, 0); + res = DIR_READ_FILE(&dj); if (res != FR_OK) break; if (ccl == ld_clust(fs, dj.dir)) break; /* Found the entry */ res = dir_next(&dj, 0); @@ -3766,39 +4055,55 @@ FRESULT f_getcwd ( if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */ if (res != FR_OK) break; get_fileinfo(&dj, &fno); /* Get the directory name and push it to the buffer */ - for (n = 0; fno.fname[n]; n++) ; - if (i < n + 3) { + for (n = 0; fno.fname[n]; n++) ; /* Name length */ + if (i < n + 1) { /* Insufficient space to store the path name? */ res = FR_NOT_ENOUGH_CORE; break; } - while (n) buff[--i] = fno.fname[--n]; + while (n) buff[--i] = fno.fname[--n]; /* Stack the name */ buff[--i] = '/'; } } - tp = buff; if (res == FR_OK) { - if (i == len) { /* Root-directory */ - *tp++ = '/'; - } else { /* Sub-directroy */ - do /* Add stacked path str */ - *tp++ = buff[i++]; - while (i < len); + if (i == len) buff[--i] = '/'; /* Is it the root-directory? */ +#if FF_VOLUMES >= 2 /* Put drive prefix */ + vl = 0; +#if FF_STR_VOLUME_ID >= 1 /* String volume ID */ + for (n = 0, vp = (const char*)VolumeStr[CurrVol]; vp[n]; n++) ; + if (i >= n + 2) { + if (FF_STR_VOLUME_ID == 2) *tp++ = (TCHAR)'/'; + for (vl = 0; vl < n; *tp++ = (TCHAR)vp[vl], vl++) ; + if (FF_STR_VOLUME_ID == 1) *tp++ = (TCHAR)':'; + vl++; + } +#else /* Numeric volume ID */ + if (i >= 3) { + *tp++ = (TCHAR)'0' + CurrVol; + *tp++ = (TCHAR)':'; + vl = 2; + } +#endif + if (vl == 0) res = FR_NOT_ENOUGH_CORE; +#endif + /* Add current directory path */ + if (res == FR_OK) { + do *tp++ = buff[i++]; while (i < len); /* Copy stacked path string */ } } - *tp = 0; FREE_NAMBUF(); } + *tp = 0; LEAVE_FF(fs, res); } -#endif /* _FS_RPATH >= 2 */ -#endif /* _FS_RPATH >= 1 */ +#endif /* FF_FS_RPATH >= 2 */ +#endif /* FF_FS_RPATH >= 1 */ -#if _FS_MINIMIZE <= 2 +#if FF_FS_MINIMIZE <= 2 /*-----------------------------------------------------------------------*/ -/* Seek File R/W Pointer */ +/* Seek File Read/Write Pointer */ /*-----------------------------------------------------------------------*/ FRESULT f_lseek ( @@ -3810,19 +4115,26 @@ FRESULT f_lseek ( FATFS *fs; DWORD clst, bcs, nsect; FSIZE_t ifptr; -#if _USE_FASTSEEK +#if FF_USE_FASTSEEK DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl; #endif res = validate(&fp->obj, &fs); /* Check validity of the file object */ - if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ -#if _USE_FASTSEEK + if (res == FR_OK) res = (FRESULT)fp->err; +#if FF_FS_EXFAT && !FF_FS_READONLY + if (res == FR_OK && fs->fs_type == FS_EXFAT) { + res = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */ + } +#endif + if (res != FR_OK) LEAVE_FF(fs, res); + +#if FF_USE_FASTSEEK if (fp->cltbl) { /* Fast seek */ if (ofs == CREATE_LINKMAP) { /* Create CLMT */ tbl = fp->cltbl; tlen = *tbl++; ulen = 2; /* Given table size and required table size */ cl = fp->obj.sclust; /* Origin of the chain */ - if (cl) { + if (cl != 0) { do { /* Get a fragment */ tcl = cl; ncl = 0; ulen += 2; /* Top, length and used items */ @@ -3846,20 +4158,20 @@ FRESULT f_lseek ( } else { /* Fast seek */ if (ofs > fp->obj.objsize) ofs = fp->obj.objsize; /* Clip offset at the file size */ fp->fptr = ofs; /* Set file pointer */ - if (ofs) { + if (ofs > 0) { fp->clust = clmt_clust(fp, ofs - 1); - dsc = clust2sect(fs, fp->clust); - if (!dsc) ABORT(fs, FR_INT_ERR); + dsc = clst2sect(fs, fp->clust); + if (dsc == 0) ABORT(fs, FR_INT_ERR); dsc += (DWORD)((ofs - 1) / SS(fs)) & (fs->csize - 1); if (fp->fptr % SS(fs) && dsc != fp->sect) { /* Refill sector cache if needed */ -#if !_FS_TINY -#if !_FS_READONLY +#if !FF_FS_TINY +#if !FF_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif - if (disk_read(fs->drv, fp->buf, dsc, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Load current sector */ + if (disk_read(fs->drv, fp->buf, dsc, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Load current sector */ #endif fp->sect = dsc; } @@ -3870,15 +4182,15 @@ FRESULT f_lseek ( /* Normal Seek */ { -#if _FS_EXFAT - if (fs->fs_type != FS_EXFAT && ofs >= 0x100000000) ofs = 0xFFFFFFFF; /* Clip at 4GiB-1 if at FATxx */ +#if FF_FS_EXFAT + if (fs->fs_type != FS_EXFAT && ofs >= 0x100000000) ofs = 0xFFFFFFFF; /* Clip at 4 GiB - 1 if at FATxx */ #endif - if (ofs > fp->obj.objsize && (_FS_READONLY || !(fp->flag & FA_WRITE))) { /* In read-only mode, clip offset with the file size */ + if (ofs > fp->obj.objsize && (FF_FS_READONLY || !(fp->flag & FA_WRITE))) { /* In read-only mode, clip offset with the file size */ ofs = fp->obj.objsize; } ifptr = fp->fptr; fp->fptr = nsect = 0; - if (ofs) { + if (ofs > 0) { bcs = (DWORD)fs->csize * SS(fs); /* Cluster size (byte) */ if (ifptr > 0 && (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */ @@ -3887,7 +4199,7 @@ FRESULT f_lseek ( clst = fp->clust; } else { /* When seek to back cluster, */ clst = fp->obj.sclust; /* start from the first cluster */ -#if !_FS_READONLY +#if !FF_FS_READONLY if (clst == 0) { /* If no cluster chain, create a new chain */ clst = create_chain(&fp->obj, 0); if (clst == 1) ABORT(fs, FR_INT_ERR); @@ -3900,9 +4212,9 @@ FRESULT f_lseek ( if (clst != 0) { while (ofs > bcs) { /* Cluster following loop */ ofs -= bcs; fp->fptr += bcs; -#if !_FS_READONLY +#if !FF_FS_READONLY if (fp->flag & FA_WRITE) { /* Check if in write mode or not */ - if (_FS_EXFAT && fp->fptr > fp->obj.objsize) { /* No FAT chain object needs correct objsize to generate FAT value */ + if (FF_FS_EXFAT && fp->fptr > fp->obj.objsize) { /* No FAT chain object needs correct objsize to generate FAT value */ fp->obj.objsize = fp->fptr; fp->flag |= FA_MODIFIED; } @@ -3921,25 +4233,25 @@ FRESULT f_lseek ( } fp->fptr += ofs; if (ofs % SS(fs)) { - nsect = clust2sect(fs, clst); /* Current sector */ - if (!nsect) ABORT(fs, FR_INT_ERR); + nsect = clst2sect(fs, clst); /* Current sector */ + if (nsect == 0) ABORT(fs, FR_INT_ERR); nsect += (DWORD)(ofs / SS(fs)); } } } - if (!_FS_READONLY && fp->fptr > fp->obj.objsize) { /* Set file change flag if the file size is extended */ + if (!FF_FS_READONLY && fp->fptr > fp->obj.objsize) { /* Set file change flag if the file size is extended */ fp->obj.objsize = fp->fptr; fp->flag |= FA_MODIFIED; } if (fp->fptr % SS(fs) && nsect != fp->sect) { /* Fill sector cache if needed */ -#if !_FS_TINY -#if !_FS_READONLY +#if !FF_FS_TINY +#if !FF_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif - if (disk_read(fs->drv, fp->buf, nsect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ + if (disk_read(fs->drv, fp->buf, nsect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ #endif fp->sect = nsect; } @@ -3950,7 +4262,7 @@ FRESULT f_lseek ( -#if _FS_MINIMIZE <= 1 +#if FF_FS_MINIMIZE <= 1 /*-----------------------------------------------------------------------*/ /* Create a Directory Object */ /*-----------------------------------------------------------------------*/ @@ -3962,49 +4274,45 @@ FRESULT f_opendir ( ) { FRESULT res; - _FDID *obj; DEF_NAMBUF if (!dp) return FR_INVALID_OBJECT; /* Get logical drive */ - obj = &dp->obj; res = find_volume(fs, 0); if (res == FR_OK) { - obj->fs = fs; + dp->obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(dp, path); /* Follow the path to the directory */ if (res == FR_OK) { /* Follow completed */ if (!(dp->fn[NSFLAG] & NS_NONAME)) { /* It is not the origin directory itself */ - if (obj->attr & AM_DIR) { /* This object is a sub-directory */ -#if _FS_EXFAT + if (dp->obj.attr & AM_DIR) { /* This object is a sub-directory */ +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { - obj->c_scl = obj->sclust; /* Save containing directory inforamation */ - obj->c_size = ((DWORD)obj->objsize & 0xFFFFFF00) | obj->stat; - obj->c_ofs = dp->blk_ofs; - obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Get object location and status */ - obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize); - obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; + dp->obj.c_scl = dp->obj.sclust; /* Get containing directory inforamation */ + dp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat; + dp->obj.c_ofs = dp->blk_ofs; + init_alloc_info(fs, &dp->obj); /* Get object allocation info */ } else #endif { - obj->sclust = ld_clust(fs, dp->dir); /* Get object location */ + dp->obj.sclust = ld_clust(fs, dp->dir); /* Get object allocation info */ } } else { /* This object is a file */ res = FR_NO_PATH; } } if (res == FR_OK) { - obj->id = fs->id; + dp->obj.id = fs->id; res = dir_sdi(dp, 0); /* Rewind directory */ -#if _FS_LOCK != 0 +#if FF_FS_LOCK != 0 if (res == FR_OK) { - if (obj->sclust) { - obj->lockid = inc_lock(dp, 0); /* Lock the sub directory */ - if (!obj->lockid) res = FR_TOO_MANY_OPEN_FILES; + if (dp->obj.sclust != 0) { + dp->obj.lockid = inc_lock(dp, 0); /* Lock the sub directory */ + if (!dp->obj.lockid) res = FR_TOO_MANY_OPEN_FILES; } else { - obj->lockid = 0; /* Root directory need not to be locked */ + dp->obj.lockid = 0; /* Root directory need not to be locked */ } } #endif @@ -4013,7 +4321,7 @@ FRESULT f_opendir ( FREE_NAMBUF(); if (res == FR_NO_FILE) res = FR_NO_PATH; } - if (res != FR_OK) obj->fs = 0; /* Invalidate the directory object if function faild */ + if (res != FR_OK) dp->obj.fs = 0; /* Invalidate the directory object if function faild */ LEAVE_FF(fs, res); } @@ -4033,18 +4341,15 @@ FRESULT f_closedir ( FATFS *fs; - res = validate(&dp->obj, &fs); /* Check validity of the file object */ + res = validate(&dp->obj, &fs); /* Check validity of the file object */ if (res == FR_OK) { -#if _FS_LOCK != 0 - if (dp->obj.lockid) { /* Decrement sub-directory open counter */ - res = dec_lock(dp->obj.lockid); - } - if (res == FR_OK) +#if FF_FS_LOCK != 0 + if (dp->obj.lockid) res = dec_lock(dp->obj.lockid); /* Decrement sub-directory open counter */ + if (res == FR_OK) dp->obj.fs = 0; /* Invalidate directory object */ +#else + dp->obj.fs = 0; /* Invalidate directory object */ #endif - { - dp->obj.fs = 0; /* Invalidate directory object */ - } -#if _FS_REENTRANT +#if FF_FS_REENTRANT unlock_fs(fs, FR_OK); /* Unlock volume */ #endif } @@ -4074,7 +4379,7 @@ FRESULT f_readdir ( res = dir_sdi(dp, 0); /* Rewind the directory object */ } else { INIT_NAMBUF(fs); - res = dir_read(dp, 0); /* Read an item */ + res = DIR_READ_FILE(dp); /* Read an item */ if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory */ if (res == FR_OK) { /* A valid entry is found */ get_fileinfo(dp, fno); /* Get the object information */ @@ -4089,7 +4394,7 @@ FRESULT f_readdir ( -#if _USE_FIND +#if FF_USE_FIND /*-----------------------------------------------------------------------*/ /* Find Next File */ /*-----------------------------------------------------------------------*/ @@ -4106,7 +4411,7 @@ FRESULT f_findnext ( res = f_readdir(dp, fno); /* Get a directory item */ if (res != FR_OK || !fno || !fno->fname[0]) break; /* Terminate if any error or end of directory */ if (pattern_matching(dp->pat, fno->fname, 0, 0)) break; /* Test for the file name */ -#if _USE_LFN != 0 && _USE_FIND == 2 +#if FF_USE_LFN && FF_USE_FIND == 2 if (pattern_matching(dp->pat, fno->altname, 0, 0)) break; /* Test for alternative name if exist */ #endif } @@ -4137,11 +4442,11 @@ FRESULT f_findfirst ( return res; } -#endif /* _USE_FIND */ +#endif /* FF_USE_FIND */ -#if _FS_MINIMIZE == 0 +#if FF_FS_MINIMIZE == 0 /*-----------------------------------------------------------------------*/ /* Get File Status */ /*-----------------------------------------------------------------------*/ @@ -4178,7 +4483,7 @@ FRESULT f_stat ( -#if !_FS_READONLY +#if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Get Number of Free Clusters */ /*-----------------------------------------------------------------------*/ @@ -4191,20 +4496,19 @@ FRESULT f_getfree ( FRESULT res; DWORD nfree, clst, sect, stat; UINT i; - BYTE *p; - _FDID obj; + FFOBJID obj; /* Get logical drive */ res = find_volume(fs, 0); if (res == FR_OK) { - /* If free_clst is valid, return it without full cluster scan */ + /* If free_clst is valid, return it without full FAT scan */ if (fs->free_clst <= fs->n_fatent - 2) { *nclst = fs->free_clst; } else { - /* Get number of free clusters */ + /* Scan FAT to obtain number of free clusters */ nfree = 0; - if (fs->fs_type == FS_FAT12) { /* FAT12: Sector unalighed FAT entries */ + if (fs->fs_type == FS_FAT12) { /* FAT12: Scan bit field FAT entries */ clst = 2; obj.fs = fs; do { stat = get_fat(&obj, clst); @@ -4213,16 +4517,19 @@ FRESULT f_getfree ( if (stat == 0) nfree++; } while (++clst < fs->n_fatent); } else { -#if _FS_EXFAT - if (fs->fs_type == FS_EXFAT) { /* exFAT: Scan bitmap table */ +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* exFAT: Scan allocation bitmap */ BYTE bm; UINT b; - clst = fs->n_fatent - 2; - sect = fs->database; - i = 0; - do { - if (i == 0 && (res = move_window(fs, sect++)) != FR_OK) break; + clst = fs->n_fatent - 2; /* Number of clusters */ + sect = fs->bitbase; /* Bitmap sector */ + i = 0; /* Offset in the sector */ + do { /* Counts numbuer of bits with zero in the bitmap */ + if (i == 0) { + res = move_window(fs, sect++); + if (res != FR_OK) break; + } for (b = 8, bm = fs->win[i]; b && clst; b--, clst--) { if (!(bm & 1)) nfree++; bm >>= 1; @@ -4231,29 +4538,29 @@ FRESULT f_getfree ( } while (clst); } else #endif - { /* FAT16/32: Sector alighed FAT entries */ - clst = fs->n_fatent; sect = fs->fatbase; - i = 0; p = 0; - do { + { /* FAT16/32: Scan WORD/DWORD FAT entries */ + clst = fs->n_fatent; /* Number of entries */ + sect = fs->fatbase; /* Top of the FAT */ + i = 0; /* Offset in the sector */ + do { /* Counts numbuer of entries with zero in the FAT */ if (i == 0) { res = move_window(fs, sect++); if (res != FR_OK) break; - p = fs->win; - i = SS(fs); } if (fs->fs_type == FS_FAT16) { - if (ld_word(p) == 0) nfree++; - p += 2; i -= 2; + if (ld_word(fs->win + i) == 0) nfree++; + i += 2; } else { - if ((ld_dword(p) & 0x0FFFFFFF) == 0) nfree++; - p += 4; i -= 4; + if ((ld_dword(fs->win + i) & 0x0FFFFFFF) == 0) nfree++; + i += 4; } + i %= SS(fs); } while (--clst); } } *nclst = nfree; /* Return the free clusters */ fs->free_clst = nfree; /* Now free_clst is valid */ - fs->fsi_flag |= 1; /* FSInfo is to be updated */ + fs->fsi_flag |= 1; /* FAT32: FSInfo is to be updated */ } } @@ -4280,7 +4587,7 @@ FRESULT f_truncate ( if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ - if (fp->obj.objsize > fp->fptr) { + if (fp->fptr < fp->obj.objsize) { /* Process when fptr is not on the eof */ if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */ res = remove_chain(&fp->obj, fp->obj.sclust, 0); fp->obj.sclust = 0; @@ -4293,9 +4600,9 @@ FRESULT f_truncate ( res = remove_chain(&fp->obj, ncl, fp->clust); } } - fp->obj.objsize = fp->fptr; /* Set file size to current R/W point */ + fp->obj.objsize = fp->fptr; /* Set file size to current read/write point */ fp->flag |= FA_MODIFIED; -#if !_FS_TINY +#if !FF_FS_TINY if (res == FR_OK && (fp->flag & FA_DIRTY)) { if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) { res = FR_DISK_ERR; @@ -4325,22 +4632,22 @@ FRESULT f_unlink ( FRESULT res; DIR dj, sdj; DWORD dclst = 0; -#if _FS_EXFAT - _FDID obj; +#if FF_FS_EXFAT + FFOBJID obj; #endif DEF_NAMBUF /* Get logical drive */ res = find_volume(fs, FA_WRITE); - dj.obj.fs = fs; if (res == FR_OK) { + dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ - if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) { + if (FF_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) { res = FR_INVALID_NAME; /* Cannot remove dot entry */ } -#if _FS_LOCK != 0 +#if FF_FS_LOCK != 0 if (res == FR_OK) res = chk_lock(&dj, 2); /* Check if it is an open object */ #endif if (res == FR_OK) { /* The object is accessible */ @@ -4352,27 +4659,26 @@ FRESULT f_unlink ( } } if (res == FR_OK) { -#if _FS_EXFAT +#if FF_FS_EXFAT obj.fs = fs; if (fs->fs_type == FS_EXFAT) { - obj.sclust = dclst = ld_dword(fs->dirbuf + XDIR_FstClus); - obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize); - obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; + init_alloc_info(fs, &obj); + dclst = obj.sclust; } else #endif { dclst = ld_clust(fs, dj.dir); } - if (dj.obj.attr & AM_DIR) { /* Is it a sub-directory ? */ -#if _FS_RPATH != 0 - if (dclst == fs->cdir) { /* Is it the current directory? */ + if (dj.obj.attr & AM_DIR) { /* Is it a sub-directory? */ +#if FF_FS_RPATH != 0 + if (dclst == fs->cdir) { /* Is it the current directory? */ res = FR_DENIED; } else #endif { - sdj.obj.fs = fs; /* Open the sub-directory */ + sdj.obj.fs = fs; /* Open the sub-directory */ sdj.obj.sclust = dclst; -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { sdj.obj.objsize = obj.objsize; sdj.obj.stat = obj.stat; @@ -4380,7 +4686,7 @@ FRESULT f_unlink ( #endif res = dir_sdi(&sdj, 0); if (res == FR_OK) { - res = dir_read(&sdj, 0); /* Read an item */ + res = DIR_READ_FILE(&sdj); /* Test if the directory is empty */ if (res == FR_OK) res = FR_DENIED; /* Not empty? */ if (res == FR_NO_FILE) res = FR_OK; /* Empty? */ } @@ -4389,8 +4695,8 @@ FRESULT f_unlink ( } if (res == FR_OK) { res = dir_remove(&dj); /* Remove the directory entry */ - if (res == FR_OK && dclst) { /* Remove the cluster chain if exist */ -#if _FS_EXFAT + if (res == FR_OK && dclst != 0) { /* Remove the cluster chain if exist */ +#if FF_FS_EXFAT res = remove_chain(&obj, dclst, 0); #else res = remove_chain(&dj.obj, dclst, 0); @@ -4419,77 +4725,68 @@ FRESULT f_mkdir ( { FRESULT res; DIR dj; - BYTE *dir; - UINT n; - DWORD dsc, dcl, pcl, tm; + FFOBJID sobj; + DWORD dcl, pcl, tm; DEF_NAMBUF - /* Get logical drive */ - res = find_volume(fs, FA_WRITE); - dj.obj.fs = fs; + res = find_volume(fs, FA_WRITE); /* Get logical drive */ if (res == FR_OK) { + dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ - if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */ - if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { + if (res == FR_OK) res = FR_EXIST; /* Name collision? */ + if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { /* Invalid name? */ res = FR_INVALID_NAME; } - if (res == FR_NO_FILE) { /* Can create a new directory */ - dcl = create_chain(&dj.obj, 0); /* Allocate a cluster for the new directory table */ - dj.obj.objsize = (DWORD)fs->csize * SS(fs); + if (res == FR_NO_FILE) { /* It is clear to create a new directory */ + sobj.fs = fs; /* New object id to create a new chain */ + dcl = create_chain(&sobj, 0); /* Allocate a cluster for the new directory */ res = FR_OK; - if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */ - if (dcl == 1) res = FR_INT_ERR; - if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; - if (res == FR_OK) res = sync_window(fs); /* Flush FAT */ + if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster? */ + if (dcl == 1) res = FR_INT_ERR; /* Any insanity? */ + if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; /* Disk error? */ tm = GET_FATTIME(); - if (res == FR_OK) { /* Initialize the new directory table */ - dsc = clust2sect(fs, dcl); - dir = fs->win; - mem_set(dir, 0, SS(fs)); - if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) { - mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */ - dir[DIR_Name] = '.'; - dir[DIR_Attr] = AM_DIR; - st_dword(dir + DIR_ModTime, tm); - st_clust(fs, dir, dcl); - mem_cpy(dir + SZDIRE, dir, SZDIRE); /* Create ".." entry */ - dir[SZDIRE + 1] = '.'; pcl = dj.obj.sclust; - if (fs->fs_type == FS_FAT32 && pcl == fs->dirbase) pcl = 0; - st_clust(fs, dir + SZDIRE, pcl); - } - for (n = fs->csize; n; n--) { /* Write dot entries and clear following sectors */ - fs->winsect = dsc++; - fs->wflag = 1; - res = sync_window(fs); - if (res != FR_OK) break; - mem_set(dir, 0, SS(fs)); + if (res == FR_OK) { + res = dir_clear(fs, dcl); /* Clean up the new table */ + if (res == FR_OK) { + if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* Create dot entries (FAT only) */ + mem_set(fs->win + DIR_Name, ' ', 11); /* Create "." entry */ + fs->win[DIR_Name] = '.'; + fs->win[DIR_Attr] = AM_DIR; + st_dword(fs->win + DIR_ModTime, tm); + st_clust(fs, fs->win, dcl); + mem_cpy(fs->win + SZDIRE, fs->win, SZDIRE); /* Create ".." entry */ + fs->win[SZDIRE + 1] = '.'; pcl = dj.obj.sclust; + st_clust(fs, fs->win + SZDIRE, pcl); + fs->wflag = 1; + } + res = dir_register(&dj); /* Register the object to the parent directoy */ } } - if (res == FR_OK) res = dir_register(&dj); /* Register the object to the directoy */ if (res == FR_OK) { -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* Initialize directory entry block */ st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Created time */ st_dword(fs->dirbuf + XDIR_FstClus, dcl); /* Table start cluster */ - st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)dj.obj.objsize); /* File size needs to be valid */ - st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)dj.obj.objsize); - fs->dirbuf[XDIR_GenFlags] = 3; /* Initialize the object flag (contiguous) */ + st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)fs->csize * SS(fs)); /* File size needs to be valid */ + st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)fs->csize * SS(fs)); + fs->dirbuf[XDIR_GenFlags] = 3; /* Initialize the object flag */ fs->dirbuf[XDIR_Attr] = AM_DIR; /* Attribute */ res = store_xdir(&dj); } else #endif { - dir = dj.dir; - st_dword(dir + DIR_ModTime, tm); /* Created time */ - st_clust(fs, dir, dcl); /* Table start cluster */ - dir[DIR_Attr] = AM_DIR; /* Attribute */ + st_dword(dj.dir + DIR_ModTime, tm); /* Created time */ + st_clust(fs, dj.dir, dcl); /* Table start cluster */ + dj.dir[DIR_Attr] = AM_DIR; /* Attribute */ fs->wflag = 1; } - if (res == FR_OK) res = sync_fs(fs); + if (res == FR_OK) { + res = sync_fs(fs); + } } else { - remove_chain(&dj.obj, dcl, 0); /* Could not register, remove cluster chain */ + remove_chain(&sobj, dcl, 0); /* Could not register, remove the allocated cluster */ } } FREE_NAMBUF(); @@ -4513,23 +4810,25 @@ FRESULT f_rename ( { FRESULT res; DIR djo, djn; - BYTE buf[_FS_EXFAT ? SZDIRE * 2 : 24], *dir; + BYTE buf[FF_FS_EXFAT ? SZDIRE * 2 : SZDIRE], *dir; DWORD dw; DEF_NAMBUF - res = find_volume(fs, FA_WRITE); + res = find_volume(fs, FA_WRITE); /* Get logical drive of the old object */ if (res == FR_OK) { djo.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&djo, path_old); /* Check old object */ if (res == FR_OK && (djo.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check validity of name */ -#if _FS_LOCK != 0 - if (res == FR_OK) res = chk_lock(&djo, 2); +#if FF_FS_LOCK != 0 + if (res == FR_OK) { + res = chk_lock(&djo, 2); + } #endif if (res == FR_OK) { /* Object to be renamed is found */ -#if _FS_EXFAT - if (fs->fs_type == FS_EXFAT) { /* At exFAT */ +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* At exFAT volume */ BYTE nf, nn; WORD nh; @@ -4544,17 +4843,18 @@ FRESULT f_rename ( if (res == FR_OK) { nf = fs->dirbuf[XDIR_NumSec]; nn = fs->dirbuf[XDIR_NumName]; nh = ld_word(fs->dirbuf + XDIR_NameHash); - mem_cpy(fs->dirbuf, buf, SZDIRE * 2); + mem_cpy(fs->dirbuf, buf, SZDIRE * 2); /* Restore 85+C0 entry */ fs->dirbuf[XDIR_NumSec] = nf; fs->dirbuf[XDIR_NumName] = nn; st_word(fs->dirbuf + XDIR_NameHash, nh); -/* Start of critical section where any interruption can cause a cross-link */ + if (!(fs->dirbuf[XDIR_Attr] & AM_DIR)) fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive attribute if it is a file */ +/* Start of critical section where an interruption can cause a cross-link */ res = store_xdir(&djn); } } } else #endif - { /* At FAT12/FAT16/FAT32 */ - mem_cpy(buf, djo.dir + DIR_Attr, 21); /* Save information about the object except name */ + { /* At FAT/FAT32 volume */ + mem_cpy(buf, djo.dir, SZDIRE); /* Save directory entry of the object */ mem_cpy(&djn, &djo, sizeof (DIR)); /* Duplicate the directory object */ res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ if (res == FR_OK) { /* Is new name already in use by any other object? */ @@ -4563,16 +4863,17 @@ FRESULT f_rename ( if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ res = dir_register(&djn); /* Register the new entry */ if (res == FR_OK) { - dir = djn.dir; /* Copy information about object except name */ - mem_cpy(dir + 13, buf + 2, 19); - dir[DIR_Attr] = buf[0] | AM_ARC; + dir = djn.dir; /* Copy directory entry of the object except name */ + mem_cpy(dir + 13, buf + 13, SZDIRE - 13); + dir[DIR_Attr] = buf[DIR_Attr]; + if (!(dir[DIR_Attr] & AM_DIR)) dir[DIR_Attr] |= AM_ARC; /* Set archive attribute if it is a file */ fs->wflag = 1; if ((dir[DIR_Attr] & AM_DIR) && djo.obj.sclust != djn.obj.sclust) { /* Update .. entry in the sub-directory if needed */ - dw = clust2sect(fs, ld_clust(fs, dir)); - if (!dw) { + dw = clst2sect(fs, ld_clust(fs, dir)); + if (dw == 0) { res = FR_INT_ERR; } else { -/* Start of critical section where any interruption can cause a cross-link */ +/* Start of critical section where an interruption can cause a cross-link */ res = move_window(fs, dw); dir = fs->win + SZDIRE * 1; /* Ptr to .. entry */ if (res == FR_OK && dir[1] == '.') { @@ -4590,7 +4891,7 @@ FRESULT f_rename ( res = sync_fs(fs); } } -/* End of critical section */ +/* End of the critical section */ } FREE_NAMBUF(); } @@ -4598,14 +4899,14 @@ FRESULT f_rename ( LEAVE_FF(fs, res); } -#endif /* !_FS_READONLY */ -#endif /* _FS_MINIMIZE == 0 */ -#endif /* _FS_MINIMIZE <= 1 */ -#endif /* _FS_MINIMIZE <= 2 */ +#endif /* !FF_FS_READONLY */ +#endif /* FF_FS_MINIMIZE == 0 */ +#endif /* FF_FS_MINIMIZE <= 1 */ +#endif /* FF_FS_MINIMIZE <= 2 */ -#if _USE_CHMOD && !_FS_READONLY +#if FF_USE_CHMOD && !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Change Attribute */ /*-----------------------------------------------------------------------*/ @@ -4623,14 +4924,14 @@ FRESULT f_chmod ( res = find_volume(fs, FA_WRITE); /* Get logical drive */ - dj.obj.fs = fs; if (res == FR_OK) { + dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ if (res == FR_OK) { mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */ -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { fs->dirbuf[XDIR_Attr] = (attr & mask) | (fs->dirbuf[XDIR_Attr] & (BYTE)~mask); /* Apply attribute change */ res = store_xdir(&dj); @@ -4640,7 +4941,9 @@ FRESULT f_chmod ( dj.dir[DIR_Attr] = (attr & mask) | (dj.dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */ fs->wflag = 1; } - if (res == FR_OK) res = sync_fs(fs); + if (res == FR_OK) { + res = sync_fs(fs); + } } FREE_NAMBUF(); } @@ -4658,7 +4961,7 @@ FRESULT f_chmod ( FRESULT f_utime ( FATFS *fs, const TCHAR* path, /* Pointer to the file/directory name */ - const FILINFO* fno /* Pointer to the time stamp to be set */ + const FILINFO* fno /* Pointer to the timestamp to be set */ ) { FRESULT res; @@ -4667,13 +4970,13 @@ FRESULT f_utime ( res = find_volume(fs, FA_WRITE); /* Get logical drive */ - dj.obj.fs = fs; if (res == FR_OK) { + dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ if (res == FR_OK) { -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { st_dword(fs->dirbuf + XDIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); res = store_xdir(&dj); @@ -4683,7 +4986,9 @@ FRESULT f_utime ( st_dword(dj.dir + DIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); fs->wflag = 1; } - if (res == FR_OK) res = sync_fs(fs); + if (res == FR_OK) { + res = sync_fs(fs); + } } FREE_NAMBUF(); } @@ -4691,27 +4996,25 @@ FRESULT f_utime ( LEAVE_FF(fs, res); } -#endif /* _USE_CHMOD && !_FS_READONLY */ +#endif /* FF_USE_CHMOD && !FF_FS_READONLY */ -#if _USE_LABEL +#if FF_USE_LABEL /*-----------------------------------------------------------------------*/ /* Get Volume Label */ /*-----------------------------------------------------------------------*/ FRESULT f_getlabel ( FATFS *fs, - TCHAR* label, /* Pointer to a buffer to return the volume label */ - DWORD* vsn /* Pointer to a variable to return the volume serial number */ + TCHAR* label, /* Buffer to store the volume label */ + DWORD* vsn /* Variable to store the volume serial number */ ) { FRESULT res; DIR dj; UINT si, di; -#if _LFN_UNICODE || _FS_EXFAT - WCHAR w; -#endif + WCHAR wc; /* Get logical drive */ res = find_volume(fs, 0); @@ -4721,37 +5024,40 @@ FRESULT f_getlabel ( dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ res = dir_sdi(&dj, 0); if (res == FR_OK) { - res = dir_read(&dj, 1); /* Find a volume label entry */ + res = DIR_READ_LABEL(&dj); /* Find a volume label entry */ if (res == FR_OK) { -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { - for (si = di = 0; si < dj.dir[XDIR_NumLabel]; si++) { /* Extract volume label from 83 entry */ - w = ld_word(dj.dir + XDIR_Label + si * 2); -#if _LFN_UNICODE - label[di++] = w; -#else - w = ff_convert(w, 0); /* Unicode -> OEM */ - if (w == 0) w = '?'; /* Replace wrong character */ - if (_DF1S && w >= 0x100) label[di++] = (char)(w >> 8); - label[di++] = (char)w; -#endif + WCHAR hs; + + for (si = di = hs = 0; si < dj.dir[XDIR_NumLabel]; si++) { /* Extract volume label from 83 entry */ + wc = ld_word(dj.dir + XDIR_Label + si * 2); + if (hs == 0 && IsSurrogate(wc)) { /* Is the code a surrogate? */ + hs = wc; continue; + } + wc = put_utf((DWORD)hs << 16 | wc, &label[di], 4); + if (wc == 0) { di = 0; break; } + di += wc; + hs = 0; } + if (hs != 0) di = 0; /* Broken surrogate pair? */ label[di] = 0; } else #endif { - si = di = 0; /* Extract volume label from AM_VOL entry with code comversion */ - do { -#if _LFN_UNICODE - w = (si < 11) ? dj.dir[si++] : ' '; - if (IsDBCS1(w) && si < 11 && IsDBCS2(dj.dir[si])) { - w = w << 8 | dj.dir[si++]; - } - label[di++] = ff_convert(w, 1); /* OEM -> Unicode */ -#else - label[di++] = dj.dir[si++]; + si = di = 0; /* Extract volume label from AM_VOL entry */ + while (si < 11) { + wc = dj.dir[si++]; +#if FF_USE_LFN && FF_LFN_UNICODE >= 1 /* Unicode output */ + if (dbc_1st((BYTE)wc) && si < 11) wc = wc << 8 | dj.dir[si++]; /* Is it a DBC? */ + wc = ff_oem2uni(wc, CODEPAGE); /* Convert it into Unicode */ + if (wc != 0) wc = put_utf(wc, &label[di], 4); /* Put it in Unicode */ + if (wc == 0) { di = 0; break; } + di += wc; +#else /* ANSI/OEM output */ + label[di++] = (TCHAR)wc; #endif - } while (di < 11); + } do { /* Truncate trailing spaces */ label[di] = 0; if (di == 0) break; @@ -4770,9 +5076,14 @@ FRESULT f_getlabel ( res = move_window(fs, fs->volbase); if (res == FR_OK) { switch (fs->fs_type) { - case FS_EXFAT: di = BPB_VolIDEx; break; - case FS_FAT32: di = BS_VolID32; break; - default: di = BS_VolID; + case FS_EXFAT: + di = BPB_VolIDEx; break; + + case FS_FAT32: + di = BS_VolID32; break; + + default: + di = BS_VolID; } *vsn = ld_dword(fs->win + di); } @@ -4783,95 +5094,88 @@ FRESULT f_getlabel ( -#if !_FS_READONLY +#if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Set Volume Label */ /*-----------------------------------------------------------------------*/ FRESULT f_setlabel ( FATFS *fs, - const TCHAR* label /* Pointer to the volume label to set */ + const TCHAR* label /* Volume label to set with heading logical drive number */ ) { FRESULT res; DIR dj; BYTE dirvn[22]; - UINT i, j, slen; - WCHAR w; - static const char badchr[] = "\"*+,.:;<=>\?[]|\x7F"; - + UINT di; + WCHAR wc; + static const char badchr[] = "+.,;=[]/\\\"*:<>\?|\x7F"; /* [0..] for FAT, [7..] for exFAT */ +#if FF_USE_LFN + DWORD dc; +#endif /* Get logical drive */ res = find_volume(fs, FA_WRITE); if (res != FR_OK) LEAVE_FF(fs, res); - dj.obj.fs = fs; - /* Get length of given volume label */ - for (slen = 0; (UINT)label[slen] >= ' '; slen++) { } /* Get name length */ - -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ - for (i = j = 0; i < slen; ) { /* Create volume label in directory form */ - w = label[i++]; -#if !_LFN_UNICODE - if (IsDBCS1(w)) { - w = (i < slen && IsDBCS2(label[i])) ? w << 8 | (BYTE)label[i++] : 0; + mem_set(dirvn, 0, 22); + di = 0; + while ((UINT)*label >= ' ') { /* Create volume label */ + dc = tchar2uni(&label); /* Get a Unicode character */ + if (dc >= 0x10000) { + if (dc == 0xFFFFFFFF || di >= 10) { /* Wrong surrogate or buffer overflow */ + dc = 0; + } else { + st_word(dirvn + di * 2, (WCHAR)(dc >> 16)); di++; + } } - w = ff_convert(w, 1); -#endif - if (w == 0 || chk_chr(badchr, w) || j == 22) { /* Check validity check validity of the volume label */ + if (dc == 0 || chk_chr(badchr + 7, (int)dc) || di >= 11) { /* Check validity of the volume label */ LEAVE_FF(fs, FR_INVALID_NAME); } - st_word(dirvn + j, w); j += 2; + st_word(dirvn + di * 2, (WCHAR)dc); di++; } - slen = j; } else #endif - { /* On the FAT12/16/32 volume */ - for ( ; slen && label[slen - 1] == ' '; slen--) ; /* Remove trailing spaces */ - if (slen) { /* Is there a volume label to be set? */ - dirvn[0] = 0; i = j = 0; /* Create volume label in directory form */ - do { -#if _LFN_UNICODE - w = ff_convert(ff_wtoupper(label[i++]), 0); -#else - w = (BYTE)label[i++]; - if (IsDBCS1(w)) { - w = (j < 10 && i < slen && IsDBCS2(label[i])) ? w << 8 | (BYTE)label[i++] : 0; - } -#if _USE_LFN != 0 - w = ff_convert(ff_wtoupper(ff_convert(w, 1)), 0); -#else - if (IsLower(w)) w -= 0x20; /* To upper ASCII characters */ -#ifdef _EXCVT - if (w >= 0x80) w = ExCvt[w - 0x80]; /* To upper extended characters (SBCS cfg) */ -#else - if (!_DF1S && w >= 0x80) w = 0; /* Reject extended characters (ASCII cfg) */ + { /* On the FAT/FAT32 volume */ + mem_set(dirvn, ' ', 11); + di = 0; + while ((UINT)*label >= ' ') { /* Create volume label */ +#if FF_USE_LFN + dc = tchar2uni(&label); + wc = (dc < 0x10000) ? ff_uni2oem(ff_wtoupper(dc), CODEPAGE) : 0; +#else /* ANSI/OEM input */ + wc = (BYTE)*label++; + if (dbc_1st((BYTE)wc)) wc = dbc_2nd((BYTE)*label) ? wc << 8 | (BYTE)*label++ : 0; + if (IsLower(wc)) wc -= 0x20; /* To upper ASCII characters */ +#if FF_CODE_PAGE == 0 + if (ExCvt && wc >= 0x80) wc = ExCvt[wc - 0x80]; /* To upper extended characters (SBCS cfg) */ +#elif FF_CODE_PAGE < 900 + if (wc >= 0x80) wc = ExCvt[wc - 0x80]; /* To upper extended characters (SBCS cfg) */ #endif #endif -#endif - if (w == 0 || chk_chr(badchr, w) || j >= (UINT)((w >= 0x100) ? 10 : 11)) { /* Reject invalid characters for volume label */ - LEAVE_FF(fs, FR_INVALID_NAME); - } - if (w >= 0x100) dirvn[j++] = (BYTE)(w >> 8); - dirvn[j++] = (BYTE)w; - } while (i < slen); - while (j < 11) dirvn[j++] = ' '; /* Fill remaining name field */ - if (dirvn[0] == DDEM) LEAVE_FF(fs, FR_INVALID_NAME); /* Reject illegal name (heading DDEM) */ + if (wc == 0 || chk_chr(badchr + 0, (int)wc) || di >= (UINT)((wc >= 0x100) ? 10 : 11)) { /* Reject invalid characters for volume label */ + LEAVE_FF(fs, FR_INVALID_NAME); + } + if (wc >= 0x100) dirvn[di++] = (BYTE)(wc >> 8); + dirvn[di++] = (BYTE)wc; } + if (dirvn[0] == DDEM) LEAVE_FF(fs, FR_INVALID_NAME); /* Reject illegal name (heading DDEM) */ + while (di && dirvn[di - 1] == ' ') di--; /* Snip trailing spaces */ } /* Set volume label */ - dj.obj.sclust = 0; /* Open root directory */ + dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ res = dir_sdi(&dj, 0); if (res == FR_OK) { - res = dir_read(&dj, 1); /* Get volume label entry */ + res = DIR_READ_LABEL(&dj); /* Get volume label entry */ if (res == FR_OK) { - if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { - dj.dir[XDIR_NumLabel] = (BYTE)(slen / 2); /* Change the volume label */ - mem_cpy(dj.dir + XDIR_Label, dirvn, slen); + if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { + dj.dir[XDIR_NumLabel] = (BYTE)di; /* Change the volume label */ + mem_cpy(dj.dir + XDIR_Label, dirvn, 22); } else { - if (slen) { + if (di != 0) { mem_cpy(dj.dir, dirvn, 11); /* Change the volume label */ } else { dj.dir[DIR_Name] = DDEM; /* Remove the volume label */ @@ -4879,17 +5183,17 @@ FRESULT f_setlabel ( } fs->wflag = 1; res = sync_fs(fs); - } else { /* No volume label entry is found or error */ + } else { /* No volume label entry or an error */ if (res == FR_NO_FILE) { res = FR_OK; - if (slen) { /* Create a volume label entry */ + if (di != 0) { /* Create a volume label entry */ res = dir_alloc(&dj, 1); /* Allocate an entry */ if (res == FR_OK) { - mem_set(dj.dir, 0, SZDIRE); /* Clear the entry */ - if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { - dj.dir[XDIR_Type] = 0x83; /* Create 83 entry */ - dj.dir[XDIR_NumLabel] = (BYTE)(slen / 2); - mem_cpy(dj.dir + XDIR_Label, dirvn, slen); + mem_set(dj.dir, 0, SZDIRE); /* Clean the entry */ + if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { + dj.dir[XDIR_Type] = ET_VLABEL; /* Create volume label entry */ + dj.dir[XDIR_NumLabel] = (BYTE)di; + mem_cpy(dj.dir + XDIR_Label, dirvn, 22); } else { dj.dir[DIR_Attr] = AM_VOL; /* Create volume label entry */ mem_cpy(dj.dir, dirvn, 11); @@ -4905,12 +5209,12 @@ FRESULT f_setlabel ( LEAVE_FF(fs, res); } -#endif /* !_FS_READONLY */ -#endif /* _USE_LABEL */ +#endif /* !FF_FS_READONLY */ +#endif /* FF_USE_LABEL */ -#if _USE_EXPAND && !_FS_READONLY +#if FF_USE_EXPAND && !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Allocate a Contiguous Blocks to the File */ /*-----------------------------------------------------------------------*/ @@ -4929,7 +5233,7 @@ FRESULT f_expand ( res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); if (fsz == 0 || fp->obj.objsize != 0 || !(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type != FS_EXFAT && fsz >= 0x100000000) LEAVE_FF(fs, FR_DENIED); /* Check if in size limit */ #endif n = (DWORD)fs->csize * SS(fs); /* Cluster size */ @@ -4937,16 +5241,16 @@ FRESULT f_expand ( stcl = fs->last_clst; lclst = 0; if (stcl < 2 || stcl >= fs->n_fatent) stcl = 2; -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { scl = find_bitmap(fs, stcl, tcl); /* Find a contiguous cluster block */ if (scl == 0) res = FR_DENIED; /* No contiguous cluster block was found */ if (scl == 0xFFFFFFFF) res = FR_DISK_ERR; - if (res == FR_OK) { - if (opt) { + if (res == FR_OK) { /* A contiguous free area is found */ + if (opt) { /* Allocate it now */ res = change_bitmap(fs, scl, tcl, 1); /* Mark the cluster block 'in use' */ lclst = scl + tcl - 1; - } else { + } else { /* Set it as suggested point for next allocation */ lclst = scl - 1; } } @@ -4966,14 +5270,14 @@ FRESULT f_expand ( } if (clst == stcl) { res = FR_DENIED; break; } /* No contiguous cluster? */ } - if (res == FR_OK) { - if (opt) { + if (res == FR_OK) { /* A contiguous free area is found */ + if (opt) { /* Allocate it now */ for (clst = scl, n = tcl; n; clst++, n--) { /* Create a cluster chain on the FAT */ res = put_fat(fs, clst, (n == 1) ? 0xFFFFFFFF : clst + 1); if (res != FR_OK) break; lclst = clst; } - } else { + } else { /* Set it as suggested point for next allocation */ lclst = scl - 1; } } @@ -4981,12 +5285,12 @@ FRESULT f_expand ( if (res == FR_OK) { fs->last_clst = lclst; /* Set suggested start cluster to start next */ - if (opt) { + if (opt) { /* Is it allocated now? */ fp->obj.sclust = scl; /* Update object allocation information */ fp->obj.objsize = fsz; - if (_FS_EXFAT) fp->obj.stat = 2; /* Set status 'contiguous chain' */ + if (FF_FS_EXFAT) fp->obj.stat = 2; /* Set status 'contiguous chain' */ fp->flag |= FA_MODIFIED; - if (fs->free_clst < fs->n_fatent - 2) { /* Update FSINFO */ + if (fs->free_clst <= fs->n_fatent - 2) { /* Update FSINFO */ fs->free_clst -= tcl; fs->fsi_flag |= 1; } @@ -4996,13 +5300,13 @@ FRESULT f_expand ( LEAVE_FF(fs, res); } -#endif /* _USE_EXPAND && !_FS_READONLY */ +#endif /* FF_USE_EXPAND && !FF_FS_READONLY */ -#if _USE_FORWARD +#if FF_USE_FORWARD /*-----------------------------------------------------------------------*/ -/* Forward data to the stream directly */ +/* Forward Data to the Stream Directly */ /*-----------------------------------------------------------------------*/ FRESULT f_forward ( @@ -5040,15 +5344,15 @@ FRESULT f_forward ( fp->clust = clst; /* Update current cluster */ } } - sect = clust2sect(fs, fp->clust); /* Get current data sector */ - if (!sect) ABORT(fs, FR_INT_ERR); + sect = clst2sect(fs, fp->clust); /* Get current data sector */ + if (sect == 0) ABORT(fs, FR_INT_ERR); sect += csect; -#if _FS_TINY +#if FF_FS_TINY if (move_window(fs, sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window to the file data */ dbuf = fs->win; #else if (fp->sect != sect) { /* Fill sector cache with file data */ -#if !_FS_READONLY +#if !FF_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; @@ -5062,40 +5366,40 @@ FRESULT f_forward ( rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ if (rcnt > btf) rcnt = btf; /* Clip it by btr if needed */ rcnt = (*func)(dbuf + ((UINT)fp->fptr % SS(fs)), rcnt); /* Forward the file data */ - if (!rcnt) ABORT(fs, FR_INT_ERR); + if (rcnt == 0) ABORT(fs, FR_INT_ERR); } LEAVE_FF(fs, FR_OK); } -#endif /* _USE_FORWARD */ +#endif /* FF_USE_FORWARD */ -#if _USE_MKFS && !_FS_READONLY +#if FF_USE_MKFS && !FF_FS_READONLY /*-----------------------------------------------------------------------*/ -/* Create FAT file system on the logical drive */ +/* Create an FAT/exFAT volume */ /*-----------------------------------------------------------------------*/ FRESULT f_mkfs ( FATFS *fs, BYTE opt, /* Format option */ - DWORD au, /* Size of allocation unit [byte] */ - void* work, /* Pointer to working buffer */ - UINT len /* Size of working buffer */ + DWORD au, /* Size of allocation unit (cluster) [byte] */ + void* work, /* Pointer to working buffer (null: use heap memory) */ + UINT len /* Size of working buffer [byte] */ ) { - const UINT n_fats = 1; /* Number of FATs for FAT12/16/32 volume (1 or 2) */ - const UINT n_rootdir = 512; /* Number of root directory entries for FAT12/16 volume */ - static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT12/16 volume (4Ks unit) */ + const UINT n_fats = 1; /* Number of FATs for FAT/FAT32 volume (1 or 2) */ + const UINT n_rootdir = 512; /* Number of root directory entries for FAT volume */ + static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT volume (4Ks unit) */ static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128Ks unit) */ BYTE fmt, sys, *buf, *pte, part; void *pdrv; - WORD ss; + WORD ss; /* Sector size */ DWORD szb_buf, sz_buf, sz_blk, n_clst, pau, sect, nsect, n; DWORD b_vol, b_fat, b_data; /* Base LBA for volume, fat, data */ DWORD sz_vol, sz_rsv, sz_fat, sz_dir; /* Size for volume, fat, dir, data */ UINT i; DSTATUS stat; -#if _USE_TRIM || _FS_EXFAT +#if FF_USE_TRIM || FF_FS_EXFAT DWORD tbl[3]; #endif @@ -5110,70 +5414,78 @@ FRESULT f_mkfs ( if (stat & STA_NOINIT) return FR_NOT_READY; if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk) != RES_OK || !sz_blk || sz_blk > 32768 || (sz_blk & (sz_blk - 1))) sz_blk = 1; /* Erase block to align data area */ -#if _MAX_SS != _MIN_SS /* Get sector size of the medium */ +#if FF_MAX_SS != FF_MIN_SS /* Get sector size of the medium if variable sector size cfg. */ if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR; - if (ss > _MAX_SS || ss < _MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR; + if (ss > FF_MAX_SS || ss < FF_MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR; #else - ss = _MAX_SS; + ss = FF_MAX_SS; #endif if ((au != 0 && au < ss) || au > 0x1000000 || (au & (au - 1))) return FR_INVALID_PARAMETER; /* Check if au is valid */ au /= ss; /* Cluster size in unit of sector */ /* Get working buffer */ - buf = (BYTE*)work; /* Working buffer */ - sz_buf = len / ss; /* Size of working buffer (sector) */ - szb_buf = sz_buf * ss; /* Size of working buffer (byte) */ - if (!szb_buf) return FR_MKFS_ABORTED; +#if FF_USE_LFN == 3 + if (!work) { /* Use heap memory for working buffer */ + for (szb_buf = MAX_MALLOC, buf = 0; szb_buf >= ss && (buf = ff_memalloc(szb_buf)) == 0; szb_buf /= 2) ; + sz_buf = szb_buf / ss; /* Size of working buffer (sector) */ + } else +#endif + { + buf = (BYTE*)work; /* Working buffer */ + sz_buf = len / ss; /* Size of working buffer (sector) */ + szb_buf = sz_buf * ss; /* Size of working buffer (byte) */ + } + if (!buf || sz_buf == 0) return FR_NOT_ENOUGH_CORE; /* Determine where the volume to be located (b_vol, sz_vol) */ - if (_MULTI_PARTITION && part != 0) { + if (FF_MULTI_PARTITION && part != 0) { /* Get partition information from partition table in the MBR */ - if (disk_read(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Load MBR */ - if (ld_word(buf + BS_55AA) != 0xAA55) return FR_MKFS_ABORTED; /* Check if MBR is valid */ + if (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Load MBR */ + if (ld_word(buf + BS_55AA) != 0xAA55) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if MBR is valid */ pte = buf + (MBR_Table + (part - 1) * SZ_PTE); - if (!pte[PTE_System]) return FR_MKFS_ABORTED; /* No partition? */ + if (pte[PTE_System] == 0) LEAVE_MKFS(FR_MKFS_ABORTED); /* No partition? */ b_vol = ld_dword(pte + PTE_StLba); /* Get volume start sector */ sz_vol = ld_dword(pte + PTE_SizLba); /* Get volume size */ } else { /* Create a single-partition in this function */ - if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) return FR_DISK_ERR; + if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); b_vol = (opt & FM_SFD) ? 0 : 63; /* Volume start sector */ - if (sz_vol < b_vol) return FR_MKFS_ABORTED; + if (sz_vol < b_vol) LEAVE_MKFS(FR_MKFS_ABORTED); sz_vol -= b_vol; /* Volume size */ } - if (sz_vol < 50) return FR_MKFS_ABORTED; /* Check if volume size is >=50s */ + if (sz_vol < 22) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if volume size is >=22s (minimum for ss=4096) */ /* Pre-determine the FAT type */ do { - if (_FS_EXFAT && (opt & FM_EXFAT)) { /* exFAT possible? */ + if (FF_FS_EXFAT && (opt & FM_EXFAT)) { /* exFAT possible? */ if ((opt & FM_ANY) == FM_EXFAT || sz_vol >= 0x4000000 || au > 128) { /* exFAT only, vol >= 64Ms or au > 128s ? */ fmt = FS_EXFAT; break; } } - if (au > 128) return FR_INVALID_PARAMETER; /* Too large au for FAT/FAT32 */ + if (au > 128) LEAVE_MKFS(FR_INVALID_PARAMETER); /* Too large au for FAT/FAT32 */ if (opt & FM_FAT32) { /* FAT32 possible? */ if ((opt & FM_ANY) == FM_FAT32 || !(opt & FM_FAT)) { /* FAT32 only or no-FAT? */ fmt = FS_FAT32; break; } } - if (!(opt & FM_FAT)) return FR_INVALID_PARAMETER; /* no-FAT? */ + if (!(opt & FM_FAT)) LEAVE_MKFS(FR_INVALID_PARAMETER); /* no-FAT? */ fmt = FS_FAT16; } while (0); -#if _FS_EXFAT +#if FF_FS_EXFAT if (fmt == FS_EXFAT) { /* Create an exFAT volume */ DWORD szb_bit, szb_case, sum, nb, cl; WCHAR ch, si; UINT j, st; BYTE b; - if (sz_vol < 0x1000) return FR_MKFS_ABORTED; /* Too small volume? */ -#if _USE_TRIM - tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area can be erased */ + if (sz_vol < 0x1000) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ +#if FF_USE_TRIM + tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area may be erased */ disk_ioctl(pdrv, CTRL_TRIM, tbl); #endif /* Determine FAT location, data location and number of clusters */ - if (!au) { /* au auto-selection */ + if (au == 0) { /* au auto-selection */ au = 8; if (sz_vol >= 0x80000) au = 64; /* >= 512Ks */ if (sz_vol >= 0x4000000) au = 256; /* >= 64Ms */ @@ -5181,10 +5493,10 @@ FRESULT f_mkfs ( b_fat = b_vol + 32; /* FAT start at offset 32 */ sz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */ b_data = (b_fat + sz_fat + sz_blk - 1) & ~(sz_blk - 1); /* Align data area to the erase block boundary */ - if (b_data >= sz_vol / 2) return FR_MKFS_ABORTED; /* Too small volume? */ + if (b_data - b_vol >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ n_clst = (sz_vol - (b_data - b_vol)) / au; /* Number of clusters */ - if (n_clst <16) return FR_MKFS_ABORTED; /* Too few clusters? */ - if (n_clst > MAX_EXFAT) return FR_MKFS_ABORTED; /* Too many clusters? */ + if (n_clst <16) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too few clusters? */ + if (n_clst > MAX_EXFAT) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters? */ szb_bit = (n_clst + 7) / 8; /* Size of allocation bitmap */ tbl[0] = (szb_bit + au * ss - 1) / (au * ss); /* Number of allocation bitmap clusters */ @@ -5192,11 +5504,11 @@ FRESULT f_mkfs ( /* Create a compressed up-case table */ sect = b_data + au * tbl[0]; /* Table start sector */ sum = 0; /* Table checksum to be stored in the 82 entry */ - st = si = i = j = szb_case = 0; + st = 0; si = 0; i = 0; j = 0; szb_case = 0; do { switch (st) { case 0: - ch = ff_wtoupper(si); /* Get an up-case char */ + ch = (WCHAR)ff_wtoupper(si); /* Get an up-case char */ if (ch != si) { si++; break; /* Store the up-case char if exist */ } @@ -5205,21 +5517,22 @@ FRESULT f_mkfs ( ch = 0xFFFF; st = 2; break; /* Compress the no-case block if run is >= 128 */ } st = 1; /* Do not compress short run */ - /* continue */ + /* go to next case */ case 1: ch = si++; /* Fill the short run */ if (--j == 0) st = 0; break; + default: - ch = (WCHAR)j; si += j; /* Number of chars to skip */ + ch = (WCHAR)j; si += (WCHAR)j; /* Number of chars to skip */ st = 0; } sum = xsum32(buf[i + 0] = (BYTE)ch, sum); /* Put it into the write buffer */ sum = xsum32(buf[i + 1] = (BYTE)(ch >> 8), sum); i += 2; szb_case += 2; - if (!si || i == szb_buf) { /* Write buffered data when buffer full or end of process */ + if (si == 0 || i == szb_buf) { /* Write buffered data when buffer full or end of process */ n = (i + ss - 1) / ss; - if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR; + if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); sect += n; i = 0; } } while (si); @@ -5232,9 +5545,9 @@ FRESULT f_mkfs ( do { mem_set(buf, 0, szb_buf); for (i = 0; nb >= 8 && i < szb_buf; buf[i++] = 0xFF, nb -= 8) ; - for (b = 1; nb && i < szb_buf; buf[i] |= b, b <<= 1, nb--) ; + for (b = 1; nb != 0 && i < szb_buf; buf[i] |= b, b <<= 1, nb--) ; n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */ - if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR; + if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); sect += n; nsect -= n; } while (nsect); @@ -5248,31 +5561,31 @@ FRESULT f_mkfs ( st_dword(buf + i, 0xFFFFFFFF); i += 4; cl++; } do { /* Create chains of bitmap, up-case and root dir */ - while (nb && i < szb_buf) { /* Create a chain */ + while (nb != 0 && i < szb_buf) { /* Create a chain */ st_dword(buf + i, (nb > 1) ? cl + 1 : 0xFFFFFFFF); i += 4; cl++; nb--; } - if (!nb && j < 3) nb = tbl[j++]; /* Next chain */ - } while (nb && i < szb_buf); + if (nb == 0 && j < 3) nb = tbl[j++]; /* Next chain */ + } while (nb != 0 && i < szb_buf); n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */ - if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR; + if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); sect += n; nsect -= n; } while (nsect); /* Initialize the root directory */ mem_set(buf, 0, szb_buf); - buf[SZDIRE * 0 + 0] = 0x83; /* 83 entry (volume label) */ - buf[SZDIRE * 1 + 0] = 0x81; /* 81 entry (allocation bitmap) */ - st_dword(buf + SZDIRE * 1 + 20, 2); - st_dword(buf + SZDIRE * 1 + 24, szb_bit); - buf[SZDIRE * 2 + 0] = 0x82; /* 82 entry (up-case table) */ - st_dword(buf + SZDIRE * 2 + 4, sum); - st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); - st_dword(buf + SZDIRE * 2 + 24, szb_case); + buf[SZDIRE * 0 + 0] = ET_VLABEL; /* Volume label entry */ + buf[SZDIRE * 1 + 0] = ET_BITMAP; /* Bitmap entry */ + st_dword(buf + SZDIRE * 1 + 20, 2); /* cluster */ + st_dword(buf + SZDIRE * 1 + 24, szb_bit); /* size */ + buf[SZDIRE * 2 + 0] = ET_UPCASE; /* Up-case table entry */ + st_dword(buf + SZDIRE * 2 + 4, sum); /* sum */ + st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); /* cluster */ + st_dword(buf + SZDIRE * 2 + 24, szb_case); /* size */ sect = b_data + au * (tbl[0] + tbl[1]); nsect = au; /* Start of the root directory and number of sectors */ do { /* Fill root directory sectors */ n = (nsect > sz_buf) ? sz_buf : nsect; - if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR; + if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); mem_set(buf, 0, ss); sect += n; nsect -= n; } while (nsect); @@ -5291,7 +5604,7 @@ FRESULT f_mkfs ( st_dword(buf + BPB_NumClusEx, n_clst); /* Number of clusters */ st_dword(buf + BPB_RootClusEx, 2 + tbl[0] + tbl[1]); /* Root dir cluster # */ st_dword(buf + BPB_VolIDEx, GET_FATTIME()); /* VSN */ - st_word(buf + BPB_FSVerEx, 0x100); /* File system version (1.00) */ + st_word(buf + BPB_FSVerEx, 0x100); /* Filesystem version (1.00) */ for (buf[BPB_BytsPerSecEx] = 0, i = ss; i >>= 1; buf[BPB_BytsPerSecEx]++) ; /* Log2 of sector size [byte] */ for (buf[BPB_SecPerClusEx] = 0, i = au; i >>= 1; buf[BPB_SecPerClusEx]++) ; /* Log2 of cluster size [sector] */ buf[BPB_NumFATsEx] = 1; /* Number of FATs */ @@ -5301,33 +5614,33 @@ FRESULT f_mkfs ( for (i = sum = 0; i < ss; i++) { /* VBR checksum */ if (i != BPB_VolFlagEx && i != BPB_VolFlagEx + 1 && i != BPB_PercInUseEx) sum = xsum32(buf[i], sum); } - if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR; + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Extended bootstrap record (+1..+8) */ mem_set(buf, 0, ss); st_word(buf + ss - 2, 0xAA55); /* Signature (placed at end of sector) */ for (j = 1; j < 9; j++) { for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ - if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR; + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); } /* OEM/Reserved record (+9..+10) */ mem_set(buf, 0, ss); for ( ; j < 11; j++) { for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ - if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR; + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); } /* Sum record (+11) */ for (i = 0; i < ss; i += 4) st_dword(buf + i, sum); /* Fill with checksum value */ - if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR; + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); } } else -#endif /* _FS_EXFAT */ - { /* Create an FAT12/16/32 volume */ +#endif /* FF_FS_EXFAT */ + { /* Create an FAT/FAT32 volume */ do { pau = au; /* Pre-determine number of clusters and FAT sub-type */ if (fmt == FS_FAT32) { /* FAT32 volume */ - if (!pau) { /* au auto-selection */ + if (pau == 0) { /* au auto-selection */ n = sz_vol / 0x20000; /* Volume size in unit of 128KS */ for (i = 0, pau = 1; cst32[i] && cst32[i] <= n; i++, pau <<= 1) ; /* Get from table */ } @@ -5335,9 +5648,9 @@ FRESULT f_mkfs ( sz_fat = (n_clst * 4 + 8 + ss - 1) / ss; /* FAT size [sector] */ sz_rsv = 32; /* Number of reserved sectors */ sz_dir = 0; /* No static directory */ - if (n_clst <= MAX_FAT16 || n_clst > MAX_FAT32) return FR_MKFS_ABORTED; - } else { /* FAT12/16 volume */ - if (!pau) { /* au auto-selection */ + if (n_clst <= MAX_FAT16 || n_clst > MAX_FAT32) LEAVE_MKFS(FR_MKFS_ABORTED); + } else { /* FAT volume */ + if (pau == 0) { /* au auto-selection */ n = sz_vol / 0x1000; /* Volume size in unit of 4KS */ for (i = 0, pau = 1; cst[i] && cst[i] <= n; i++, pau <<= 1) ; /* Get from table */ } @@ -5359,42 +5672,42 @@ FRESULT f_mkfs ( n = ((b_data + sz_blk - 1) & ~(sz_blk - 1)) - b_data; /* Next nearest erase block from current data base */ if (fmt == FS_FAT32) { /* FAT32: Move FAT base */ sz_rsv += n; b_fat += n; - } else { /* FAT12/16: Expand FAT size */ + } else { /* FAT: Expand FAT size */ sz_fat += n / n_fats; } /* Determine number of clusters and final check of validity of the FAT sub-type */ - if (sz_vol < b_data + pau * 16 - b_vol) return FR_MKFS_ABORTED; /* Too small volume */ + if (sz_vol < b_data + pau * 16 - b_vol) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume */ n_clst = (sz_vol - sz_rsv - sz_fat * n_fats - sz_dir) / pau; if (fmt == FS_FAT32) { if (n_clst <= MAX_FAT16) { /* Too few clusters for FAT32 */ - if (!au && (au = pau / 2) != 0) continue; /* Adjust cluster size and retry */ - return FR_MKFS_ABORTED; + if (au == 0 && (au = pau / 2) != 0) continue; /* Adjust cluster size and retry */ + LEAVE_MKFS(FR_MKFS_ABORTED); } } if (fmt == FS_FAT16) { if (n_clst > MAX_FAT16) { /* Too many clusters for FAT16 */ - if (!au && (pau * 2) <= 64) { + if (au == 0 && (pau * 2) <= 64) { au = pau * 2; continue; /* Adjust cluster size and retry */ } if ((opt & FM_FAT32)) { fmt = FS_FAT32; continue; /* Switch type to FAT32 and retry */ } - if (!au && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ - return FR_MKFS_ABORTED; + if (au == 0 && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ + LEAVE_MKFS(FR_MKFS_ABORTED); } if (n_clst <= MAX_FAT12) { /* Too few clusters for FAT16 */ - if (!au && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ - return FR_MKFS_ABORTED; + if (au == 0 && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ + LEAVE_MKFS(FR_MKFS_ABORTED); } } - if (fmt == FS_FAT12 && n_clst > MAX_FAT12) return FR_MKFS_ABORTED; /* Too many clusters for FAT12 */ + if (fmt == FS_FAT12 && n_clst > MAX_FAT12) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters for FAT12 */ /* Ok, it is the valid cluster configuration */ break; } while (1); -#if _USE_TRIM +#if FF_USE_TRIM tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area can be erased */ disk_ioctl(pdrv, CTRL_TRIM, tbl); #endif @@ -5432,7 +5745,7 @@ FRESULT f_mkfs ( mem_cpy(buf + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ } st_word(buf + BS_55AA, 0xAA55); /* Signature (offset is fixed here regardless of sector size) */ - if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) return FR_DISK_ERR; /* Write it to the VBR sector */ + if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it to the VBR sector */ /* Create FSINFO record if needed */ if (fmt == FS_FAT32) { @@ -5461,7 +5774,7 @@ FRESULT f_mkfs ( nsect = sz_fat; /* Number of FAT sectors */ do { /* Fill FAT sectors */ n = (nsect > sz_buf) ? sz_buf : nsect; - if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) return FR_DISK_ERR; + if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); mem_set(buf, 0, ss); sect += n; nsect -= n; } while (nsect); @@ -5471,34 +5784,34 @@ FRESULT f_mkfs ( nsect = (fmt == FS_FAT32) ? pau : sz_dir; /* Number of root directory sectors */ do { n = (nsect > sz_buf) ? sz_buf : nsect; - if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) return FR_DISK_ERR; + if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); sect += n; nsect -= n; } while (nsect); } /* Determine system ID in the partition table */ - if (_FS_EXFAT && fmt == FS_EXFAT) { + if (FF_FS_EXFAT && fmt == FS_EXFAT) { sys = 0x07; /* HPFS/NTFS/exFAT */ } else { if (fmt == FS_FAT32) { sys = 0x0C; /* FAT32X */ } else { if (sz_vol >= 0x10000) { - sys = 0x06; /* FAT12/16 (>=64KS) */ + sys = 0x06; /* FAT12/16 (large) */ } else { - sys = (fmt == FS_FAT16) ? 0x04 : 0x01; /* FAT16 (<64KS) : FAT12 (<64KS) */ + sys = (fmt == FS_FAT16) ? 0x04 : 0x01; /* FAT16 : FAT12 */ } } } - if (_MULTI_PARTITION && part != 0) { + /* Update partition information */ + if (FF_MULTI_PARTITION && part != 0) { /* Created in the existing partition */ /* Update system ID in the partition table */ - if (disk_read(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Read the MBR */ - buf[MBR_Table + (part - 1) * SZ_PTE + PTE_System] = sys; /* Set system type */ - if (disk_write(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Write it back to the MBR */ - } else { - if (!(opt & FM_SFD)) { - /* Create partition table in FDISK format */ + if (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Read the MBR */ + buf[MBR_Table + (part - 1) * SZ_PTE + PTE_System] = sys; /* Set system ID */ + if (disk_write(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it back to the MBR */ + } else { /* Created as a new single partition */ + if (!(opt & FM_SFD)) { /* Create partition table if in FDISK format */ mem_set(buf, 0, ss); st_word(buf + BS_55AA, 0xAA55); /* MBR signature */ pte = buf + MBR_Table; /* Create partition table for single partition in the drive */ @@ -5507,38 +5820,39 @@ FRESULT f_mkfs ( pte[PTE_StSec] = 1; /* Start sector */ pte[PTE_StCyl] = 0; /* Start cylinder */ pte[PTE_System] = sys; /* System type */ - n = (b_vol + sz_vol) / (63 * 255); /* (End CHS is incorrect) */ + n = (b_vol + sz_vol) / (63 * 255); /* (End CHS may be invalid) */ pte[PTE_EdHead] = 254; /* End head */ - pte[PTE_EdSec] = (BYTE)(n >> 2 | 63); /* End sector */ + pte[PTE_EdSec] = (BYTE)(((n >> 2) & 0xC0) | 63); /* End sector */ pte[PTE_EdCyl] = (BYTE)n; /* End cylinder */ st_dword(pte + PTE_StLba, b_vol); /* Start offset in LBA */ st_dword(pte + PTE_SizLba, sz_vol); /* Size in sectors */ - if (disk_write(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Write it to the MBR */ + if (disk_write(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it to the MBR */ } } - if (disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) return FR_DISK_ERR; + if (disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); - return FR_OK; + LEAVE_MKFS(FR_OK); } -#if _MULTI_PARTITION +#if FF_MULTI_PARTITION /*-----------------------------------------------------------------------*/ -/* Create partition table on the physical drive */ +/* Create Partition Table on the Physical Drive */ /*-----------------------------------------------------------------------*/ FRESULT f_fdisk ( void *pdrv, /* Physical drive number */ const DWORD* szt, /* Pointer to the size table for each partitions */ - void* work /* Pointer to the working buffer */ + void* work /* Pointer to the working buffer (null: use heap memory) */ ) { UINT i, n, sz_cyl, tot_cyl, b_cyl, e_cyl, p_cyl; BYTE s_hd, e_hd, *p, *buf = (BYTE*)work; DSTATUS stat; DWORD sz_disk, sz_part, s_part; + FRESULT res; disk_ioctl(pdrv, IOCTL_INIT, &stat); @@ -5546,19 +5860,25 @@ FRESULT f_fdisk ( if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) return FR_DISK_ERR; - /* Determine the CHS without any care of the drive geometry */ + buf = (BYTE*)work; +#if FF_USE_LFN == 3 + if (!buf) buf = ff_memalloc(FF_MAX_SS); /* Use heap memory for working buffer */ +#endif + if (!buf) return FR_NOT_ENOUGH_CORE; + + /* Determine the CHS without any consideration of the drive geometry */ for (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2) ; if (n == 256) n--; - e_hd = n - 1; + e_hd = (BYTE)(n - 1); sz_cyl = 63 * n; tot_cyl = sz_disk / sz_cyl; /* Create partition table */ - mem_set(buf, 0, _MAX_SS); + mem_set(buf, 0, FF_MAX_SS); p = buf + MBR_Table; b_cyl = 0; for (i = 0; i < 4; i++, p += SZ_PTE) { - p_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl; - if (!p_cyl) continue; + p_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl; /* Number of cylinders */ + if (p_cyl == 0) continue; s_part = (DWORD)sz_cyl * b_cyl; sz_part = (DWORD)sz_cyl * p_cyl; if (i == 0) { /* Exclude first track of cylinder 0 */ @@ -5567,28 +5887,61 @@ FRESULT f_fdisk ( } else { s_hd = 0; } - e_cyl = b_cyl + p_cyl - 1; - if (e_cyl >= tot_cyl) return FR_INVALID_PARAMETER; + e_cyl = b_cyl + p_cyl - 1; /* End cylinder */ + if (e_cyl >= tot_cyl) LEAVE_MKFS(FR_INVALID_PARAMETER); /* Set partition table */ p[1] = s_hd; /* Start head */ - p[2] = (BYTE)((b_cyl >> 2) + 1); /* Start sector */ + p[2] = (BYTE)(((b_cyl >> 2) & 0xC0) | 1); /* Start sector */ p[3] = (BYTE)b_cyl; /* Start cylinder */ - p[4] = 0x06; /* System type (temporary setting) */ + p[4] = 0x07; /* System type (temporary setting) */ p[5] = e_hd; /* End head */ - p[6] = (BYTE)((e_cyl >> 2) + 63); /* End sector */ + p[6] = (BYTE)(((e_cyl >> 2) & 0xC0) | 63); /* End sector */ p[7] = (BYTE)e_cyl; /* End cylinder */ st_dword(p + 8, s_part); /* Start sector in LBA */ - st_dword(p + 12, sz_part); /* Partition size */ + st_dword(p + 12, sz_part); /* Number of sectors */ /* Next partition */ b_cyl += p_cyl; } - st_word(p, 0xAA55); + st_word(p, 0xAA55); /* MBR signature (always at offset 510) */ /* Write it to the MBR */ - return (disk_write(pdrv, buf, 0, 1) != RES_OK || disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) ? FR_DISK_ERR : FR_OK; + res = (disk_write(pdrv, buf, 0, 1) == RES_OK && disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR; + LEAVE_MKFS(res); } -#endif /* _MULTI_PARTITION */ -#endif /* _USE_MKFS && !_FS_READONLY */ +#endif /* FF_MULTI_PARTITION */ +#endif /* FF_USE_MKFS && !FF_FS_READONLY */ + + + +#if FF_CODE_PAGE == 0 +/*-----------------------------------------------------------------------*/ +/* Set Active Codepage for the Path Name */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_setcp ( + WORD cp /* Value to be set as active code page */ +) +{ + static const WORD validcp[] = { 437, 720, 737, 771, 775, 850, 852, 857, 860, 861, 862, 863, 864, 865, 866, 869, 932, 936, 949, 950, 0}; + static const BYTE* const tables[] = {Ct437, Ct720, Ct737, Ct771, Ct775, Ct850, Ct852, Ct857, Ct860, Ct861, Ct862, Ct863, Ct864, Ct865, Ct866, Ct869, Dc932, Dc936, Dc949, Dc950, 0}; + UINT i; + + + for (i = 0; validcp[i] != 0 && validcp[i] != cp; i++) ; /* Find the code page */ + if (validcp[i] != cp) return FR_INVALID_PARAMETER; /* Not found? */ + + CodePage = cp; + if (cp >= 900) { /* DBCS */ + ExCvt = 0; + DbcTbl = tables[i]; + } else { /* SBCS */ + ExCvt = tables[i]; + DbcTbl = 0; + } + return FR_OK; +} +#endif /* FF_CODE_PAGE == 0 */ + diff --git a/lib/oofatfs/ff.h b/lib/oofatfs/ff.h index 068de11660..a8aa00e9af 100644 --- a/lib/oofatfs/ff.h +++ b/lib/oofatfs/ff.h @@ -3,10 +3,10 @@ */ /*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT file system module R0.12b / +/ FatFs - Generic FAT Filesystem module R0.13c / /-----------------------------------------------------------------------------/ / -/ Copyright (C) 2016, ChaN, all right reserved. +/ Copyright (C) 2018, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided @@ -19,81 +19,93 @@ / and any warranties related to this software are DISCLAIMED. / The copyright owner or contributors be NOT LIABLE for any damages caused / by use of this software. +/ /----------------------------------------------------------------------------*/ -#ifndef _FATFS -#define _FATFS 68020 /* Revision ID */ +#ifndef FF_DEFINED +#define FF_DEFINED 86604 /* Revision ID */ #ifdef __cplusplus extern "C" { #endif -#include +#include FFCONF_H /* FatFs configuration options */ -/* This type MUST be 8-bit */ -typedef uint8_t BYTE; - -/* These types MUST be 16-bit */ -typedef int16_t SHORT; -typedef uint16_t WORD; -typedef uint16_t WCHAR; - -/* These types MUST be 16-bit or 32-bit */ -typedef int INT; -typedef unsigned int UINT; - -/* These types MUST be 32-bit */ -typedef int32_t LONG; -typedef uint32_t DWORD; - -/* This type MUST be 64-bit (Remove this for C89 compatibility) */ -typedef uint64_t QWORD; - -#include FFCONF_H /* FatFs configuration options */ - -#if _FATFS != _FFCONF +#if FF_DEFINED != FFCONF_DEF #error Wrong configuration file (ffconf.h). #endif +/* Integer types used for FatFs API */ + +#if defined(_WIN32) /* Main development platform */ +#define FF_INTDEF 2 +#include +typedef unsigned __int64 QWORD; +#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) /* C99 or later */ +#define FF_INTDEF 2 +#include +typedef unsigned int UINT; /* int must be 16-bit or 32-bit */ +typedef unsigned char BYTE; /* char must be 8-bit */ +typedef uint16_t WORD; /* 16-bit unsigned integer */ +typedef uint16_t WCHAR; /* 16-bit unsigned integer */ +typedef uint32_t DWORD; /* 32-bit unsigned integer */ +typedef uint64_t QWORD; /* 64-bit unsigned integer */ +#else /* Earlier than C99 */ +#define FF_INTDEF 1 +typedef unsigned int UINT; /* int must be 16-bit or 32-bit */ +typedef unsigned char BYTE; /* char must be 8-bit */ +typedef unsigned short WORD; /* 16-bit unsigned integer */ +typedef unsigned short WCHAR; /* 16-bit unsigned integer */ +typedef unsigned long DWORD; /* 32-bit unsigned integer */ +#endif + /* Definitions of volume management */ -#if _MULTI_PARTITION /* Multiple partition configuration */ -#define LD2PT(fs) (fs->part) /* Get partition index */ -#else /* Single partition configuration */ -#define LD2PT(fs) 0 /* Find first valid partition or in SFD */ +#if FF_STR_VOLUME_ID +#ifndef FF_VOLUME_STRS +extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */ +#endif #endif /* Type of path name strings on FatFs API */ -#if _LFN_UNICODE /* Unicode (UTF-16) string */ -#if _USE_LFN == 0 -#error _LFN_UNICODE must be 0 at non-LFN cfg. -#endif #ifndef _INC_TCHAR +#define _INC_TCHAR + +#if FF_USE_LFN && FF_LFN_UNICODE == 1 /* Unicode in UTF-16 encoding */ typedef WCHAR TCHAR; #define _T(x) L ## x #define _TEXT(x) L ## x -#endif -#else /* ANSI/OEM string */ -#ifndef _INC_TCHAR +#elif FF_USE_LFN && FF_LFN_UNICODE == 2 /* Unicode in UTF-8 encoding */ +typedef char TCHAR; +#define _T(x) u8 ## x +#define _TEXT(x) u8 ## x +#elif FF_USE_LFN && FF_LFN_UNICODE == 3 /* Unicode in UTF-32 encoding */ +typedef DWORD TCHAR; +#define _T(x) U ## x +#define _TEXT(x) U ## x +#elif FF_USE_LFN && (FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3) +#error Wrong FF_LFN_UNICODE setting +#else /* ANSI/OEM code in SBCS/DBCS */ typedef char TCHAR; #define _T(x) x #define _TEXT(x) x #endif + #endif /* Type of file size variables */ -#if _FS_EXFAT -#if _USE_LFN == 0 -#error LFN must be enabled when enable exFAT +#if FF_FS_EXFAT +#if FF_INTDEF != 2 +#error exFAT feature wants C99 or later #endif typedef QWORD FSIZE_t; #else @@ -102,39 +114,39 @@ typedef DWORD FSIZE_t; -/* File system object structure (FATFS) */ +/* Filesystem object structure (FATFS) */ typedef struct { void *drv; // block device underlying this filesystem -#if _MULTI_PARTITION /* Multiple partition configuration */ +#if FF_MULTI_PARTITION /* Multiple partition configuration */ BYTE part; // Partition: 0:Auto detect, 1-4:Forced partition #endif - BYTE fs_type; /* File system type (0:N/A) */ + BYTE fs_type; /* Filesystem type (0:not mounted) */ BYTE n_fats; /* Number of FATs (1 or 2) */ BYTE wflag; /* win[] flag (b0:dirty) */ BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ - WORD id; /* File system mount ID */ + WORD id; /* Volume mount ID */ WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ WORD csize; /* Cluster size [sectors] */ -#if _MAX_SS != _MIN_SS +#if FF_MAX_SS != FF_MIN_SS WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */ #endif -#if _USE_LFN != 0 +#if FF_USE_LFN WCHAR* lfnbuf; /* LFN working buffer */ #endif -#if _FS_EXFAT - BYTE* dirbuf; /* Directory entry block scratchpad buffer */ +#if FF_FS_EXFAT + BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */ #endif -#if _FS_REENTRANT - _SYNC_t sobj; /* Identifier of sync object */ +#if FF_FS_REENTRANT + FF_SYNC_t sobj; /* Identifier of sync object */ #endif -#if !_FS_READONLY +#if !FF_FS_READONLY DWORD last_clst; /* Last allocated cluster */ DWORD free_clst; /* Number of free clusters */ #endif -#if _FS_RPATH != 0 +#if FF_FS_RPATH DWORD cdir; /* Current directory start cluster (0:root) */ -#if _FS_EXFAT +#if FF_FS_EXFAT DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */ DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */ DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */ @@ -146,52 +158,56 @@ typedef struct { DWORD fatbase; /* FAT base sector */ DWORD dirbase; /* Root directory base sector/cluster */ DWORD database; /* Data base sector */ +#if FF_FS_EXFAT + DWORD bitbase; /* Allocation bitmap base sector */ +#endif DWORD winsect; /* Current sector appearing in the win[] */ - BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ + BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ } FATFS; -/* Object ID and allocation information (_FDID) */ +/* Object ID and allocation information (FFOBJID) */ typedef struct { - FATFS* fs; /* Pointer to the owner file system object */ - WORD id; /* Owner file system mount ID */ - BYTE attr; /* Object attribute */ - BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous (no data on FAT), =3:got flagmented, b2:sub-directory stretched) */ - DWORD sclust; /* Object start cluster (0:no cluster or root directory) */ - FSIZE_t objsize; /* Object size (valid when sclust != 0) */ -#if _FS_EXFAT - DWORD n_cont; /* Size of coutiguous part, clusters - 1 (valid when stat == 3) */ - DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */ - DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */ - DWORD c_ofs; /* Offset in the containing directory (valid when sclust != 0) */ + FATFS* fs; /* Pointer to the hosting volume of this object */ + WORD id; /* Hosting volume mount ID */ + BYTE attr; /* Object attribute */ + BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */ + DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */ + FSIZE_t objsize; /* Object size (valid when sclust != 0) */ +#if FF_FS_EXFAT + DWORD n_cont; /* Size of first fragment - 1 (valid when stat == 3) */ + DWORD n_frag; /* Size of last fragment needs to be written to FAT (valid when not zero) */ + DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */ + DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */ + DWORD c_ofs; /* Offset in the containing directory (valid when file object and sclust != 0) */ #endif -#if _FS_LOCK != 0 - UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ +#if FF_FS_LOCK + UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ #endif -} _FDID; +} FFOBJID; /* File object structure (FIL) */ typedef struct { - _FDID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */ + FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */ BYTE flag; /* File status flags */ BYTE err; /* Abort flag (error code) */ FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */ - DWORD clust; /* Current cluster of fpter (invalid when fprt is 0) */ + DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */ DWORD sect; /* Sector number appearing in buf[] (0:invalid) */ -#if !_FS_READONLY - DWORD dir_sect; /* Sector number containing the directory entry */ - BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */ +#if !FF_FS_READONLY + DWORD dir_sect; /* Sector number containing the directory entry (not used at exFAT) */ + BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */ #endif -#if _USE_FASTSEEK +#if FF_USE_FASTSEEK DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */ #endif -#if !_FS_TINY - BYTE buf[_MAX_SS]; /* File private data read/write window */ +#if !FF_FS_TINY + BYTE buf[FF_MAX_SS]; /* File private data read/write window */ #endif } FIL; @@ -200,16 +216,16 @@ typedef struct { /* Directory object structure (FF_DIR) */ typedef struct { - _FDID obj; /* Object identifier */ + FFOBJID obj; /* Object identifier */ DWORD dptr; /* Current read/write offset */ DWORD clust; /* Current cluster */ - DWORD sect; /* Current sector */ + DWORD sect; /* Current sector (0:Read operation has terminated) */ BYTE* dir; /* Pointer to the directory item in the win[] */ BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */ -#if _USE_LFN != 0 +#if FF_USE_LFN DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */ #endif -#if _USE_FIND +#if FF_USE_FIND const TCHAR* pat; /* Pointer to the name matching pattern */ #endif } FF_DIR; @@ -223,11 +239,11 @@ typedef struct { WORD fdate; /* Modified date */ WORD ftime; /* Modified time */ BYTE fattrib; /* File attribute */ -#if _USE_LFN != 0 - TCHAR altname[13]; /* Altenative file name */ - TCHAR fname[_MAX_LFN + 1]; /* Primary file name */ +#if FF_USE_LFN + TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */ + TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */ #else - TCHAR fname[13]; /* File name */ + TCHAR fname[12 + 1]; /* File name */ #endif } FILINFO; @@ -254,7 +270,7 @@ typedef enum { FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ - FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_LOCK */ + FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */ FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ } FRESULT; @@ -292,6 +308,7 @@ FRESULT f_mount (FATFS* fs); /* Mount/Unm FRESULT f_umount (FATFS* fs); /* Unmount a logical drive */ FRESULT f_mkfs (FATFS *fs, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */ FRESULT f_fdisk (void *pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */ +FRESULT f_setcp (WORD cp); /* Set current code page */ #define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) #define f_error(fp) ((fp)->err) @@ -299,6 +316,8 @@ FRESULT f_fdisk (void *pdrv, const DWORD* szt, void* work); /* Divide a #define f_size(fp) ((fp)->obj.objsize) #define f_rewind(fp) f_lseek((fp), 0) #define f_rewinddir(dp) f_readdir((dp), 0) +#define f_rmdir(path) f_unlink(path) +#define f_unmount(path) f_mount(0, path, 0) #ifndef EOF #define EOF (-1) @@ -311,26 +330,27 @@ FRESULT f_fdisk (void *pdrv, const DWORD* szt, void* work); /* Divide a /* Additional user defined functions */ /* RTC function */ -#if !_FS_READONLY && !_FS_NORTC +#if !FF_FS_READONLY && !FF_FS_NORTC DWORD get_fattime (void); #endif -/* Unicode support functions */ -#if _USE_LFN != 0 /* Unicode - OEM code conversion */ -WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */ -WCHAR ff_wtoupper (WCHAR chr); /* Unicode upper-case conversion */ -#if _USE_LFN == 3 /* Memory functions */ +/* LFN support functions */ +#if FF_USE_LFN >= 1 /* Code conversion (defined in unicode.c) */ +WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */ +WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */ +DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */ +#endif +#if FF_USE_LFN == 3 /* Dynamic memory allocation */ void* ff_memalloc (UINT msize); /* Allocate memory block */ void ff_memfree (void* mblock); /* Free memory block */ #endif -#endif /* Sync functions */ -#if _FS_REENTRANT -int ff_cre_syncobj (FATFS *fatfs, _SYNC_t* sobj); /* Create a sync object */ -int ff_req_grant (_SYNC_t sobj); /* Lock sync object */ -void ff_rel_grant (_SYNC_t sobj); /* Unlock sync object */ -int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */ +#if FF_FS_REENTRANT +int ff_cre_syncobj (FATFS *fatfs, FF_SYNC_t* sobj); /* Create a sync object */ +int ff_req_grant (FF_SYNC_t sobj); /* Lock sync object */ +void ff_rel_grant (FF_SYNC_t sobj); /* Unlock sync object */ +int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */ #endif @@ -377,4 +397,4 @@ int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */ } #endif -#endif /* _FATFS */ +#endif /* FF_DEFINED */ diff --git a/lib/oofatfs/option/ccsbcs.c b/lib/oofatfs/ffunicode.c similarity index 58% rename from lib/oofatfs/option/ccsbcs.c rename to lib/oofatfs/ffunicode.c index fdded968d5..4153f9131c 100644 --- a/lib/oofatfs/option/ccsbcs.c +++ b/lib/oofatfs/ffunicode.c @@ -1,33 +1,46 @@ /*------------------------------------------------------------------------*/ -/* Unicode - Local code bidirectional converter (C)ChaN, 2015 */ -/* (SBCS code pages) */ +/* Unicode handling functions for FatFs R0.13c */ /*------------------------------------------------------------------------*/ -/* 437 U.S. -/ 720 Arabic -/ 737 Greek -/ 771 KBL -/ 775 Baltic -/ 850 Latin 1 -/ 852 Latin 2 -/ 855 Cyrillic -/ 857 Turkish -/ 860 Portuguese -/ 861 Icelandic -/ 862 Hebrew -/ 863 Canadian French -/ 864 Arabic -/ 865 Nordic -/ 866 Russian -/ 869 Greek 2 +/* This module will occupy a huge memory in the .const section when the / +/ FatFs is configured for LFN with DBCS. If the system has any Unicode / +/ utilitiy for the code conversion, this module should be modified to use / +/ that function to avoid silly memory consumption. / +/-------------------------------------------------------------------------*/ +/* +/ Copyright (C) 2018, ChaN, all right reserved. +/ +/ FatFs module is an open source software. Redistribution and use of FatFs in +/ source and binary forms, with or without modification, are permitted provided +/ that the following condition is met: +/ +/ 1. Redistributions of source code must retain the above copyright notice, +/ this condition and the following disclaimer. +/ +/ This software is provided by the copyright holder and contributors "AS IS" +/ and any warranties related to this software are DISCLAIMED. +/ The copyright owner or contributors be NOT LIABLE for any damages caused +/ by use of this software. */ -#include "../ff.h" + +#include "ff.h" + +#if FF_USE_LFN /* This module will be blanked at non-LFN configuration */ + +#if FF_DEFINED != 86604 /* Revision ID */ +#error Wrong include file (ff.h). +#endif + +#define MERGE2(a, b) a ## b +#define CVTBL(tbl, cp) MERGE2(tbl, cp) -#if _CODE_PAGE == 437 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP437(0x80-0xFF) to Unicode conversion table */ +/*------------------------------------------------------------------------*/ +/* Code Conversion Tables */ +/*------------------------------------------------------------------------*/ + +#if FF_CODE_PAGE == 437 || FF_CODE_PAGE == 0 +static const WCHAR uc437[] = { /* CP437(U.S.) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, @@ -37,11 +50,9 @@ const WCHAR Tbl[] = { /* CP437(0x80-0xFF) to Unicode conversion table */ 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 720 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP720(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 720 || FF_CODE_PAGE == 0 +static const WCHAR uc720[] = { /* CP720(Arabic) to Unicode conversion table */ 0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9, 0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627, 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB, @@ -51,11 +62,9 @@ const WCHAR Tbl[] = { /* CP720(0x80-0xFF) to Unicode conversion table */ 0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x00B5, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A, 0x2261, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 737 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP737(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 737 || FF_CODE_PAGE == 0 +static const WCHAR uc737[] = { /* CP737(Greek) to Unicode conversion table */ 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0, 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, @@ -65,11 +74,9 @@ const WCHAR Tbl[] = { /* CP737(0x80-0xFF) to Unicode conversion table */ 0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD, 0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E, 0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 771 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP771(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 771 || FF_CODE_PAGE == 0 +static const WCHAR uc771[] = { /* CP771(KBL) to Unicode conversion table */ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, @@ -79,11 +86,9 @@ const WCHAR Tbl[] = { /* CP771(0x80-0xFF) to Unicode conversion table */ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, 0x0118, 0x0119, 0x0116, 0x0117, 0x012E, 0x012F, 0x0160, 0x0161, 0x0172, 0x0173, 0x016A, 0x016B, 0x017D, 0x017E, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 775 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP775(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 775 || FF_CODE_PAGE == 0 +static const WCHAR uc775[] = { /* CP775(Baltic) to Unicode conversion table */ 0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107, 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4, 0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6, 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB, @@ -93,11 +98,9 @@ const WCHAR Tbl[] = { /* CP775(0x80-0xFF) to Unicode conversion table */ 0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144, 0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019, 0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E, 0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 850 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP850(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 850 || FF_CODE_PAGE == 0 +static const WCHAR uc850[] = { /* CP850(Latin 1) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, @@ -107,11 +110,9 @@ const WCHAR Tbl[] = { /* CP850(0x80-0xFF) to Unicode conversion table */ 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4, 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 852 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP852(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 852 || FF_CODE_PAGE == 0 +static const WCHAR uc852[] = { /* CP852(Latin 2) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106, 0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E, 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB, @@ -121,11 +122,9 @@ const WCHAR Tbl[] = { /* CP852(0x80-0xFF) to Unicode conversion table */ 0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161, 0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4, 0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 855 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP855(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 855 || FF_CODE_PAGE == 0 +static const WCHAR uc855[] = { /* CP855(Cyrillic) to Unicode conversion table */ 0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408, 0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C, 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A, 0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB, @@ -135,11 +134,9 @@ const WCHAR Tbl[] = { /* CP855(0x80-0xFF) to Unicode conversion table */ 0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443, 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116, 0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D, 0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 857 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP857(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 857 || FF_CODE_PAGE == 0 +static const WCHAR uc857[] = { /* CP857(Turkish) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, @@ -149,11 +146,9 @@ const WCHAR Tbl[] = { /* CP857(0x80-0xFF) to Unicode conversion table */ 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x0000, 0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4, 0x00AD, 0x00B1, 0x0000, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 860 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP860(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 860 || FF_CODE_PAGE == 0 +static const WCHAR uc860[] = { /* CP860(Portuguese) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E3, 0x00E0, 0x00C1, 0x00E7, 0x00EA, 0x00CA, 0x00E8, 0x00CD, 0x00D4, 0x00EC, 0x00C3, 0x00C2, 0x00C9, 0x00C0, 0x00C8, 0x00F4, 0x00F5, 0x00F2, 0x00DA, 0x00F9, 0x00CC, 0x00D5, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x20A7, 0x00D3, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00D2, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, @@ -163,11 +158,9 @@ const WCHAR Tbl[] = { /* CP860(0x80-0xFF) to Unicode conversion table */ 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 861 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP861(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 861 || FF_CODE_PAGE == 0 +static const WCHAR uc861[] = { /* CP861(Icelandic) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00D0, 0x00F0, 0x00DE, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00FE, 0x00FB, 0x00DD, 0x00FD, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00C1, 0x00CD, 0x00D3, 0x00DA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, @@ -177,11 +170,9 @@ const WCHAR Tbl[] = { /* CP861(0x80-0xFF) to Unicode conversion table */ 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 862 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP862(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 862 || FF_CODE_PAGE == 0 +static const WCHAR uc862[] = { /* CP862(Hebrew) to Unicode conversion table */ 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, @@ -191,11 +182,9 @@ const WCHAR Tbl[] = { /* CP862(0x80-0xFF) to Unicode conversion table */ 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 863 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP863(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 863 || FF_CODE_PAGE == 0 +static const WCHAR uc863[] = { /* CP863(Canadian French) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00C2, 0x00E0, 0x00B6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x2017, 0x00C0, 0x00C9, 0x00C8, 0x00CA, 0x00F4, 0x00CB, 0x00CF, 0x00FB, 0x00F9, 0x00A4, 0x00D4, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x00DB, 0x0192, 0x00A6, 0x00B4, 0x00F3, 0x00FA, 0x00A8, 0x00BB, 0x00B3, 0x00AF, 0x00CE, 0x3210, 0x00AC, 0x00BD, 0x00BC, 0x00BE, 0x00AB, 0x00BB, @@ -205,11 +194,9 @@ const WCHAR Tbl[] = { /* CP863(0x80-0xFF) to Unicode conversion table */ 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2219, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 864 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP864(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 864 || FF_CODE_PAGE == 0 +static const WCHAR uc864[] = { /* CP864(Arabic) to Unicode conversion table */ 0x00B0, 0x00B7, 0x2219, 0x221A, 0x2592, 0x2500, 0x2502, 0x253C, 0x2524, 0x252C, 0x251C, 0x2534, 0x2510, 0x250C, 0x2514, 0x2518, 0x03B2, 0x221E, 0x03C6, 0x00B1, 0x00BD, 0x00BC, 0x2248, 0x00AB, 0x00BB, 0xFEF7, 0xFEF8, 0x0000, 0x0000, 0xFEFB, 0xFEFC, 0x0000, 0x00A0, 0x00AD, 0xFE82, 0x00A3, 0x00A4, 0xFE84, 0x0000, 0x20AC, 0xFE8E, 0xFE8F, 0xFE95, 0xFE99, 0x060C, 0xFE9D, 0xFEA1, 0xFEA5, @@ -219,11 +206,9 @@ const WCHAR Tbl[] = { /* CP864(0x80-0xFF) to Unicode conversion table */ 0x0640, 0xFED3, 0xFED7, 0xFEDB, 0xFEDF, 0xFEE3, 0xFEE7, 0xFEEB, 0xFEED, 0xFEEF, 0xFEF3, 0xFEBD, 0xFECC, 0xFECE, 0xFECD, 0xFEE1, 0xFE7D, 0x0651, 0xFEE5, 0xFEE9, 0xFEEC, 0xFEF0, 0xFEF2, 0xFED0, 0xFED5, 0xFEF5, 0xFEF6, 0xFEDD, 0xFED9, 0xFEF1, 0x25A0, 0x0000 }; - -#elif _CODE_PAGE == 865 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP865(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 865 || FF_CODE_PAGE == 0 +static const WCHAR uc865[] = { /* CP865(Nordic) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, 0x00C5, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00A4, @@ -233,11 +218,9 @@ const WCHAR Tbl[] = { /* CP865(0x80-0xFF) to Unicode conversion table */ 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 866 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP866(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 866 || FF_CODE_PAGE == 0 +static const WCHAR uc866[] = { /* CP866(Russian) to Unicode conversion table */ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, @@ -247,11 +230,9 @@ const WCHAR Tbl[] = { /* CP866(0x80-0xFF) to Unicode conversion table */ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, 0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 869 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP869(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 869 || FF_CODE_PAGE == 0 +static const WCHAR uc869[] = { /* CP869(Greek 2) to Unicode conversion table */ 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x0386, 0x00B7, 0x00B7, 0x00AC, 0x00A6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389, 0x038A, 0x03AA, 0x038C, 0x00B7, 0x00B7, 0x038E, 0x03AB, 0x00A9, 0x038F, 0x00B2, 0x00B3, 0x03AC, 0x00A3, 0x03AD, 0x03AE, 0x03AF, 0x03CA, 0x0390, 0x03CC, 0x03CD, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x00BD, 0x0398, 0x0399, 0x00AB, 0x00BB, @@ -261,36 +242,32 @@ const WCHAR Tbl[] = { /* CP869(0x80-0xFF) to Unicode conversion table */ 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x0384, 0x00AD, 0x00B1, 0x03C5, 0x03C6, 0x03C7, 0x00A7, 0x03C8, 0x0385, 0x00B0, 0x00A8, 0x03C9, 0x03CB, 0x03B0, 0x03CE, 0x25A0, 0x00A0 }; - -#endif - - -#if !_TBLDEF || !_USE_LFN -#error This file is not needed at current configuration. Remove from the project. #endif -WCHAR ff_convert ( /* Converted character, Returns zero on error */ - WCHAR chr, /* Character code to be converted */ - UINT dir /* 0: Unicode to OEM code, 1: OEM code to Unicode */ +/*------------------------------------------------------------------------*/ +/* OEM <==> Unicode conversions for static code page configuration */ +/* SBCS fixed code page */ +/*------------------------------------------------------------------------*/ + +#if FF_CODE_PAGE != 0 && FF_CODE_PAGE < 900 +WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ + DWORD uni, /* UTF-16 encoded character to be converted */ + WORD cp /* Code page for the conversion */ ) { - WCHAR c; + WCHAR c = 0; + const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); - if (chr < 0x80) { /* ASCII */ - c = chr; + if (uni < 0x80) { /* ASCII? */ + c = (WCHAR)uni; - } else { - if (dir) { /* OEM code to Unicode */ - c = (chr >= 0x100) ? 0 : Tbl[chr - 0x80]; - - } else { /* Unicode to OEM code */ - for (c = 0; c < 0x80; c++) { - if (chr == Tbl[c]) break; - } + } else { /* Non-ASCII */ + if (uni < 0x10000 && cp == FF_CODE_PAGE) { /* Is it in BMP and valid code page? */ + for (c = 0; c < 0x80 && uni != p[c]; c++) ; c = (c + 0x80) & 0xFF; } } @@ -298,56 +275,314 @@ WCHAR ff_convert ( /* Converted character, Returns zero on error */ return c; } - - -WCHAR ff_wtoupper ( /* Returns upper converted character */ - WCHAR chr /* Unicode character to be upper converted (BMP only) */ +WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */ + WCHAR oem, /* OEM code to be converted */ + WORD cp /* Code page for the conversion */ ) { - /* Compressed upper conversion table */ - static const WCHAR cvt1[] = { /* U+0000 - U+0FFF */ + WCHAR c = 0; + const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); + + + if (oem < 0x80) { /* ASCII? */ + c = oem; + + } else { /* Extended char */ + if (cp == FF_CODE_PAGE) { /* Is it a valid code page? */ + if (oem < 0x100) c = p[oem - 0x80]; + } + } + + return c; +} + +#endif + + + +/*------------------------------------------------------------------------*/ +/* OEM <==> Unicode conversions for static code page configuration */ +/* DBCS fixed code page */ +/*------------------------------------------------------------------------*/ + +#if FF_CODE_PAGE >= 900 +WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ + DWORD uni, /* UTF-16 encoded character to be converted */ + WORD cp /* Code page for the conversion */ +) +{ + const WCHAR *p; + WCHAR c = 0, uc; + UINT i = 0, n, li, hi; + + + if (uni < 0x80) { /* ASCII? */ + c = (WCHAR)uni; + + } else { /* Non-ASCII */ + if (uni < 0x10000 && cp == FF_CODE_PAGE) { /* Is it in BMP and valid code page? */ + uc = (WCHAR)uni; + p = CVTBL(uni2oem, FF_CODE_PAGE); + hi = sizeof CVTBL(uni2oem, FF_CODE_PAGE) / 4 - 1; + li = 0; + for (n = 16; n; n--) { + i = li + (hi - li) / 2; + if (uc == p[i * 2]) break; + if (uc > p[i * 2]) { + li = i; + } else { + hi = i; + } + } + if (n != 0) c = p[i * 2 + 1]; + } + } + + return c; +} + + +WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */ + WCHAR oem, /* OEM code to be converted */ + WORD cp /* Code page for the conversion */ +) +{ + const WCHAR *p; + WCHAR c = 0; + UINT i = 0, n, li, hi; + + + if (oem < 0x80) { /* ASCII? */ + c = oem; + + } else { /* Extended char */ + if (cp == FF_CODE_PAGE) { /* Is it valid code page? */ + p = CVTBL(oem2uni, FF_CODE_PAGE); + hi = sizeof CVTBL(oem2uni, FF_CODE_PAGE) / 4 - 1; + li = 0; + for (n = 16; n; n--) { + i = li + (hi - li) / 2; + if (oem == p[i * 2]) break; + if (oem > p[i * 2]) { + li = i; + } else { + hi = i; + } + } + if (n != 0) c = p[i * 2 + 1]; + } + } + + return c; +} +#endif + + + +/*------------------------------------------------------------------------*/ +/* OEM <==> Unicode conversions for dynamic code page configuration */ +/*------------------------------------------------------------------------*/ + +#if FF_CODE_PAGE == 0 + +static const WORD cp_code[] = { 437, 720, 737, 771, 775, 850, 852, 855, 857, 860, 861, 862, 863, 864, 865, 866, 869, 0}; +static const WCHAR* const cp_table[] = {uc437, uc720, uc737, uc771, uc775, uc850, uc852, uc855, uc857, uc860, uc861, uc862, uc863, uc864, uc865, uc866, uc869, 0}; + + +WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ + DWORD uni, /* UTF-16 encoded character to be converted */ + WORD cp /* Code page for the conversion */ +) +{ + const WCHAR *p; + WCHAR c = 0, uc; + UINT i, n, li, hi; + + + if (uni < 0x80) { /* ASCII? */ + c = (WCHAR)uni; + + } else { /* Non-ASCII */ + if (uni < 0x10000) { /* Is it in BMP? */ + uc = (WCHAR)uni; + p = 0; + if (cp < 900) { /* SBCS */ + for (i = 0; cp_code[i] != 0 && cp_code[i] != cp; i++) ; /* Get conversion table */ + p = cp_table[i]; + if (p) { /* Is it valid code page ? */ + for (c = 0; c < 0x80 && uc != p[c]; c++) ; /* Find OEM code in the table */ + c = (c + 0x80) & 0xFF; + } + } else { /* DBCS */ + switch (cp) { /* Get conversion table */ + case 932 : p = uni2oem932; hi = sizeof uni2oem932 / 4 - 1; break; + case 936 : p = uni2oem936; hi = sizeof uni2oem936 / 4 - 1; break; + case 949 : p = uni2oem949; hi = sizeof uni2oem949 / 4 - 1; break; + case 950 : p = uni2oem950; hi = sizeof uni2oem950 / 4 - 1; break; + } + if (p) { /* Is it valid code page? */ + li = 0; + for (n = 16; n; n--) { /* Find OEM code */ + i = li + (hi - li) / 2; + if (uc == p[i * 2]) break; + if (uc > p[i * 2]) { + li = i; + } else { + hi = i; + } + } + if (n != 0) c = p[i * 2 + 1]; + } + } + } + } + + return c; +} + + +WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */ + WCHAR oem, /* OEM code to be converted (DBC if >=0x100) */ + WORD cp /* Code page for the conversion */ +) +{ + const WCHAR *p; + WCHAR c = 0; + UINT i, n, li, hi; + + + if (oem < 0x80) { /* ASCII? */ + c = oem; + + } else { /* Extended char */ + p = 0; + if (cp < 900) { /* SBCS */ + for (i = 0; cp_code[i] != 0 && cp_code[i] != cp; i++) ; /* Get table */ + p = cp_table[i]; + if (p) { /* Is it a valid CP ? */ + if (oem < 0x100) c = p[oem - 0x80]; + } + } else { /* DBCS */ + switch (cp) { + case 932 : p = oem2uni932; hi = sizeof oem2uni932 / 4 - 1; break; + case 936 : p = oem2uni936; hi = sizeof oem2uni936 / 4 - 1; break; + case 949 : p = oem2uni949; hi = sizeof oem2uni949 / 4 - 1; break; + case 950 : p = oem2uni950; hi = sizeof oem2uni950 / 4 - 1; break; + } + if (p) { + li = 0; + for (n = 16; n; n--) { + i = li + (hi - li) / 2; + if (oem == p[i * 2]) break; + if (oem > p[i * 2]) { + li = i; + } else { + hi = i; + } + } + if (n != 0) c = p[i * 2 + 1]; + } + } + } + + return c; +} +#endif + + + +/*------------------------------------------------------------------------*/ +/* Unicode up-case conversion */ +/*------------------------------------------------------------------------*/ + +DWORD ff_wtoupper ( /* Returns up-converted code point */ + DWORD uni /* Unicode code point to be up-converted */ +) +{ + const WORD *p; + WORD uc, bc, nc, cmd; + static const WORD cvt1[] = { /* Compressed up conversion table for U+0000 - U+0FFF */ /* Basic Latin */ 0x0061,0x031A, /* Latin-1 Supplement */ - 0x00E0,0x0317, 0x00F8,0x0307, 0x00FF,0x0001,0x0178, + 0x00E0,0x0317, + 0x00F8,0x0307, + 0x00FF,0x0001,0x0178, /* Latin Extended-A */ - 0x0100,0x0130, 0x0132,0x0106, 0x0139,0x0110, 0x014A,0x012E, 0x0179,0x0106, + 0x0100,0x0130, + 0x0132,0x0106, + 0x0139,0x0110, + 0x014A,0x012E, + 0x0179,0x0106, /* Latin Extended-B */ 0x0180,0x004D,0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,0x0187,0x0189,0x018A,0x018B,0x018B,0x018D,0x018E,0x018F,0x0190,0x0191,0x0191,0x0193,0x0194,0x01F6,0x0196,0x0197,0x0198,0x0198,0x023D,0x019B,0x019C,0x019D,0x0220,0x019F,0x01A0,0x01A0,0x01A2,0x01A2,0x01A4,0x01A4,0x01A6,0x01A7,0x01A7,0x01A9,0x01AA,0x01AB,0x01AC,0x01AC,0x01AE,0x01AF,0x01AF,0x01B1,0x01B2,0x01B3,0x01B3,0x01B5,0x01B5,0x01B7,0x01B8,0x01B8,0x01BA,0x01BB,0x01BC,0x01BC,0x01BE,0x01F7,0x01C0,0x01C1,0x01C2,0x01C3,0x01C4,0x01C5,0x01C4,0x01C7,0x01C8,0x01C7,0x01CA,0x01CB,0x01CA, - 0x01CD,0x0110, 0x01DD,0x0001,0x018E, 0x01DE,0x0112, 0x01F3,0x0003,0x01F1,0x01F4,0x01F4, 0x01F8,0x0128, - 0x0222,0x0112, 0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241, 0x0246,0x010A, + 0x01CD,0x0110, + 0x01DD,0x0001,0x018E, + 0x01DE,0x0112, + 0x01F3,0x0003,0x01F1,0x01F4,0x01F4, + 0x01F8,0x0128, + 0x0222,0x0112, + 0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241, + 0x0246,0x010A, /* IPA Extensions */ 0x0253,0x0040,0x0181,0x0186,0x0255,0x0189,0x018A,0x0258,0x018F,0x025A,0x0190,0x025C,0x025D,0x025E,0x025F,0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,0x0197,0x0196,0x026A,0x2C62,0x026C,0x026D,0x026E,0x019C,0x0270,0x0271,0x019D,0x0273,0x0274,0x019F,0x0276,0x0277,0x0278,0x0279,0x027A,0x027B,0x027C,0x2C64,0x027E,0x027F,0x01A6,0x0281,0x0282,0x01A9,0x0284,0x0285,0x0286,0x0287,0x01AE,0x0244,0x01B1,0x01B2,0x0245,0x028D,0x028E,0x028F,0x0290,0x0291,0x01B7, /* Greek, Coptic */ - 0x037B,0x0003,0x03FD,0x03FE,0x03FF, 0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A, 0x03B1,0x0311, - 0x03C2,0x0002,0x03A3,0x03A3, 0x03C4,0x0308, 0x03CC,0x0003,0x038C,0x038E,0x038F, 0x03D8,0x0118, + 0x037B,0x0003,0x03FD,0x03FE,0x03FF, + 0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A, + 0x03B1,0x0311, + 0x03C2,0x0002,0x03A3,0x03A3, + 0x03C4,0x0308, + 0x03CC,0x0003,0x038C,0x038E,0x038F, + 0x03D8,0x0118, 0x03F2,0x000A,0x03F9,0x03F3,0x03F4,0x03F5,0x03F6,0x03F7,0x03F7,0x03F9,0x03FA,0x03FA, /* Cyrillic */ - 0x0430,0x0320, 0x0450,0x0710, 0x0460,0x0122, 0x048A,0x0136, 0x04C1,0x010E, 0x04CF,0x0001,0x04C0, 0x04D0,0x0144, + 0x0430,0x0320, + 0x0450,0x0710, + 0x0460,0x0122, + 0x048A,0x0136, + 0x04C1,0x010E, + 0x04CF,0x0001,0x04C0, + 0x04D0,0x0144, /* Armenian */ 0x0561,0x0426, - 0x0000 + 0x0000 /* EOT */ }; - static const WCHAR cvt2[] = { /* U+1000 - U+FFFF */ + static const WORD cvt2[] = { /* Compressed up conversion table for U+1000 - U+FFFF */ /* Phonetic Extensions */ 0x1D7D,0x0001,0x2C63, /* Latin Extended Additional */ - 0x1E00,0x0196, 0x1EA0,0x015A, + 0x1E00,0x0196, + 0x1EA0,0x015A, /* Greek Extended */ - 0x1F00,0x0608, 0x1F10,0x0606, 0x1F20,0x0608, 0x1F30,0x0608, 0x1F40,0x0606, - 0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F, 0x1F60,0x0608, + 0x1F00,0x0608, + 0x1F10,0x0606, + 0x1F20,0x0608, + 0x1F30,0x0608, + 0x1F40,0x0606, + 0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F, + 0x1F60,0x0608, 0x1F70,0x000E,0x1FBA,0x1FBB,0x1FC8,0x1FC9,0x1FCA,0x1FCB,0x1FDA,0x1FDB,0x1FF8,0x1FF9,0x1FEA,0x1FEB,0x1FFA,0x1FFB, - 0x1F80,0x0608, 0x1F90,0x0608, 0x1FA0,0x0608, 0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC, - 0x1FCC,0x0001,0x1FC3, 0x1FD0,0x0602, 0x1FE0,0x0602, 0x1FE5,0x0001,0x1FEC, 0x1FF2,0x0001,0x1FFC, + 0x1F80,0x0608, + 0x1F90,0x0608, + 0x1FA0,0x0608, + 0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC, + 0x1FCC,0x0001,0x1FC3, + 0x1FD0,0x0602, + 0x1FE0,0x0602, + 0x1FE5,0x0001,0x1FEC, + 0x1FF3,0x0001,0x1FFC, /* Letterlike Symbols */ 0x214E,0x0001,0x2132, /* Number forms */ - 0x2170,0x0210, 0x2184,0x0001,0x2183, + 0x2170,0x0210, + 0x2184,0x0001,0x2183, /* Enclosed Alphanumerics */ - 0x24D0,0x051A, 0x2C30,0x042F, + 0x24D0,0x051A, + 0x2C30,0x042F, /* Latin Extended-C */ - 0x2C60,0x0102, 0x2C67,0x0106, 0x2C75,0x0102, + 0x2C60,0x0102, + 0x2C67,0x0106, 0x2C75,0x0102, /* Coptic */ 0x2C80,0x0164, /* Georgian Supplement */ @@ -355,34 +590,38 @@ WCHAR ff_wtoupper ( /* Returns upper converted character */ /* Full-width */ 0xFF41,0x031A, - 0x0000 + 0x0000 /* EOT */ }; - const WCHAR *p; - WCHAR bc, nc, cmd; - p = chr < 0x1000 ? cvt1 : cvt2; - for (;;) { - bc = *p++; /* Get block base */ - if (!bc || chr < bc) break; - nc = *p++; cmd = nc >> 8; nc &= 0xFF; /* Get processing command and block size */ - if (chr < bc + nc) { /* In the block? */ - switch (cmd) { - case 0: chr = p[chr - bc]; break; /* Table conversion */ - case 1: chr -= (chr - bc) & 1; break; /* Case pairs */ - case 2: chr -= 16; break; /* Shift -16 */ - case 3: chr -= 32; break; /* Shift -32 */ - case 4: chr -= 48; break; /* Shift -48 */ - case 5: chr -= 26; break; /* Shift -26 */ - case 6: chr += 8; break; /* Shift +8 */ - case 7: chr -= 80; break; /* Shift -80 */ - case 8: chr -= 0x1C60; break; /* Shift -0x1C60 */ + if (uni < 0x10000) { /* Is it in BMP? */ + uc = (WORD)uni; + p = uc < 0x1000 ? cvt1 : cvt2; + for (;;) { + bc = *p++; /* Get the block base */ + if (bc == 0 || uc < bc) break; /* Not matched? */ + nc = *p++; cmd = nc >> 8; nc &= 0xFF; /* Get processing command and block size */ + if (uc < bc + nc) { /* In the block? */ + switch (cmd) { + case 0: uc = p[uc - bc]; break; /* Table conversion */ + case 1: uc -= (uc - bc) & 1; break; /* Case pairs */ + case 2: uc -= 16; break; /* Shift -16 */ + case 3: uc -= 32; break; /* Shift -32 */ + case 4: uc -= 48; break; /* Shift -48 */ + case 5: uc -= 26; break; /* Shift -26 */ + case 6: uc += 8; break; /* Shift +8 */ + case 7: uc -= 80; break; /* Shift -80 */ + case 8: uc -= 0x1C60; break; /* Shift -0x1C60 */ + } + break; } - break; + if (cmd == 0) p += nc; /* Skip table if needed */ } - if (!cmd) p += nc; + uni = uc; } - return chr; + return uni; } + +#endif /* #if FF_USE_LFN */ diff --git a/lib/oofatfs/option/unicode.c b/lib/oofatfs/option/unicode.c deleted file mode 100644 index e48d09c6b0..0000000000 --- a/lib/oofatfs/option/unicode.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "../ff.h" - -#if _USE_LFN != 0 - -#if _CODE_PAGE == 932 /* Japanese Shift_JIS */ -#include "cc932.c" -#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */ -#include "cc936.c" -#elif _CODE_PAGE == 949 /* Korean */ -#include "cc949.c" -#elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */ -#include "cc950.c" -#else /* Single Byte Character-Set */ -#include "ccsbcs.c" -#endif - -#endif From 7eadcaa8c674ba950549a336154a1571ab78f07a Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 25 Feb 2019 23:45:32 +1100 Subject: [PATCH 0159/1788] lib/oofatfs: Update ffconf.h config for new oofatfs version. --- lib/oofatfs/ffconf.h | 242 +++++++++++++++++++++++-------------------- 1 file changed, 131 insertions(+), 111 deletions(-) diff --git a/lib/oofatfs/ffconf.h b/lib/oofatfs/ffconf.h index 315101f0e4..4a8015668f 100644 --- a/lib/oofatfs/ffconf.h +++ b/lib/oofatfs/ffconf.h @@ -2,11 +2,11 @@ * This file is part of the MicroPython project, http://micropython.org/ * * Original file from: - * FatFs - FAT file system module configuration file R0.12a (C)ChaN, 2016 + * FatFs - FAT file system module configuration file R0.13c (C)ChaN, 2018 * * The MIT License (MIT) * - * Copyright (c) 2013-2017 Damien P. George + * Copyright (c) 2013-2019 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 @@ -30,73 +30,72 @@ #include "py/mpconfig.h" /*---------------------------------------------------------------------------/ -/ FatFs - FAT file system module configuration file +/ FatFs Functional Configurations /---------------------------------------------------------------------------*/ -#define _FFCONF 68020 /* Revision ID */ +#define FFCONF_DEF 86604 /* Revision ID */ /*---------------------------------------------------------------------------/ / Function Configurations /---------------------------------------------------------------------------*/ -#define _FS_READONLY 0 +#define FF_FS_READONLY 0 /* This option switches read-only configuration. (0:Read/Write or 1:Read-only) / Read-only configuration removes writing API functions, f_write(), f_sync(), / f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() / and optional writing functions as well. */ -#define _FS_MINIMIZE 0 +#define FF_FS_MINIMIZE 0 /* This option defines minimization level to remove some basic API functions. / -/ 0: All basic functions are enabled. +/ 0: Basic functions are fully enabled. / 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename() / are removed. / 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. / 3: f_lseek() function is removed in addition to 2. */ -#define _USE_STRFUNC 0 -/* This option switches string functions, f_gets(), f_putc(), f_puts() and -/ f_printf(). +#define FF_USE_STRFUNC 0 +/* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf(). / / 0: Disable string functions. / 1: Enable without LF-CRLF conversion. / 2: Enable with LF-CRLF conversion. */ -#define _USE_FIND 0 +#define FF_USE_FIND 0 /* This option switches filtered directory read functions, f_findfirst() and / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ -#define _USE_MKFS 1 +#define FF_USE_MKFS 1 /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ -#define _USE_FASTSEEK 0 +#define FF_USE_FASTSEEK 0 /* This option switches fast seek function. (0:Disable or 1:Enable) */ -#define _USE_EXPAND 0 +#define FF_USE_EXPAND 0 /* This option switches f_expand function. (0:Disable or 1:Enable) */ -#define _USE_CHMOD 1 +#define FF_USE_CHMOD 1 /* This option switches attribute manipulation functions, f_chmod() and f_utime(). -/ (0:Disable or 1:Enable) Also _FS_READONLY needs to be 0 to enable this option. */ +/ (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */ #ifdef MICROPY_FATFS_USE_LABEL -#define _USE_LABEL (MICROPY_FATFS_USE_LABEL) +#define FF_USE_LABEL (MICROPY_FATFS_USE_LABEL) #else -#define _USE_LABEL 0 +#define FF_USE_LABEL 0 #endif /* This option switches volume label functions, f_getlabel() and f_setlabel(). / (0:Disable or 1:Enable) */ -#define _USE_FORWARD 0 +#define FF_USE_FORWARD 0 /* This option switches f_forward() function. (0:Disable or 1:Enable) */ @@ -105,14 +104,13 @@ /---------------------------------------------------------------------------*/ #ifdef MICROPY_FATFS_LFN_CODE_PAGE -#define _CODE_PAGE (MICROPY_FATFS_LFN_CODE_PAGE) +#define FF_CODE_PAGE MICROPY_FATFS_LFN_CODE_PAGE #else -#define _CODE_PAGE 1 +#define FF_CODE_PAGE 437 #endif /* This option specifies the OEM code page to be used on the target system. -/ Incorrect setting of the code page can cause a file open failure. +/ Incorrect code page setting can cause a file open failure. / -/ 1 - ASCII (No extended character. Non-LFN cfg. only) / 437 - U.S. / 720 - Arabic / 737 - Greek @@ -134,59 +132,77 @@ / 936 - Simplified Chinese (DBCS) / 949 - Korean (DBCS) / 950 - Traditional Chinese (DBCS) +/ 0 - Include all code pages above and configured by f_setcp() */ #ifdef MICROPY_FATFS_ENABLE_LFN -#define _USE_LFN (MICROPY_FATFS_ENABLE_LFN) +#define FF_USE_LFN (MICROPY_FATFS_ENABLE_LFN) #else -#define _USE_LFN 0 +#define FF_USE_LFN 0 #endif #ifdef MICROPY_FATFS_MAX_LFN -#define _MAX_LFN (MICROPY_FATFS_MAX_LFN) +#define FF_MAX_LFN (MICROPY_FATFS_MAX_LFN) #else -#define _MAX_LFN 255 +#define FF_MAX_LFN 255 #endif -/* The _USE_LFN switches the support of long file name (LFN). +/* The FF_USE_LFN switches the support for LFN (long file name). / -/ 0: Disable support of LFN. _MAX_LFN has no effect. +/ 0: Disable LFN. FF_MAX_LFN has no effect. / 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. / 2: Enable LFN with dynamic working buffer on the STACK. / 3: Enable LFN with dynamic working buffer on the HEAP. / -/ To enable the LFN, Unicode handling functions (option/unicode.c) must be added -/ to the project. The working buffer occupies (_MAX_LFN + 1) * 2 bytes and -/ additional 608 bytes at exFAT enabled. _MAX_LFN can be in range from 12 to 255. -/ It should be set 255 to support full featured LFN operations. +/ To enable the LFN, ffunicode.c needs to be added to the project. The LFN function +/ requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and +/ additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled. +/ The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can +/ be in range of 12 to 255. It is recommended to be set 255 to fully support LFN +/ specification. / When use stack for the working buffer, take care on stack overflow. When use heap / memory for the working buffer, memory management functions, ff_memalloc() and -/ ff_memfree(), must be added to the project. */ +/ ff_memfree() in ffsystem.c, need to be added to the project. */ -#define _LFN_UNICODE 0 -/* This option switches character encoding on the API. (0:ANSI/OEM or 1:UTF-16) -/ To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1. -/ This option also affects behavior of string I/O functions. */ - - -#define _STRF_ENCODE 3 -/* When _LFN_UNICODE == 1, this option selects the character encoding ON THE FILE to -/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf(). +#define FF_LFN_UNICODE 0 +/* This option switches the character encoding on the API when LFN is enabled. / -/ 0: ANSI/OEM -/ 1: UTF-16LE -/ 2: UTF-16BE -/ 3: UTF-8 +/ 0: ANSI/OEM in current CP (TCHAR = char) +/ 1: Unicode in UTF-16 (TCHAR = WCHAR) +/ 2: Unicode in UTF-8 (TCHAR = char) +/ 3: Unicode in UTF-32 (TCHAR = DWORD) / -/ This option has no effect when _LFN_UNICODE == 0. */ +/ Also behavior of string I/O functions will be affected by this option. +/ When LFN is not enabled, this option has no effect. */ + + +#define FF_LFN_BUF 255 +#define FF_SFN_BUF 12 +/* This set of options defines size of file name members in the FILINFO structure +/ which is used to read out directory items. These values should be suffcient for +/ the file names to read. The maximum possible length of the read file name depends +/ on character encoding. When LFN is not enabled, these options have no effect. */ + + +#define FF_STRF_ENCODE 3 +/* When FF_LFN_UNICODE >= 1 with LFN enabled, string I/O functions, f_gets(), +/ f_putc(), f_puts and f_printf() convert the character encoding in it. +/ This option selects assumption of character encoding ON THE FILE to be +/ read/written via those functions. +/ +/ 0: ANSI/OEM in current CP +/ 1: Unicode in UTF-16LE +/ 2: Unicode in UTF-16BE +/ 3: Unicode in UTF-8 +*/ #ifdef MICROPY_FATFS_RPATH -#define _FS_RPATH (MICROPY_FATFS_RPATH) +#define FF_FS_RPATH (MICROPY_FATFS_RPATH) #else -#define _FS_RPATH 0 +#define FF_FS_RPATH 0 #endif -/* This option configures support of relative path. +/* This option configures support for relative path. / / 0: Disable relative path and remove related functions. / 1: Enable relative path. f_chdir() and f_chdrive() are available. @@ -198,53 +214,58 @@ / Drive/Volume Configurations /---------------------------------------------------------------------------*/ -#define _VOLUMES 1 -/* Number of volumes (logical drives) to be used. */ +#define FF_VOLUMES 1 +/* Number of volumes (logical drives) to be used. (1-10) */ -#define _STR_VOLUME_ID 0 -#define _VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3" -/* _STR_VOLUME_ID switches string support of volume ID. -/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive -/ number in the path name. _VOLUME_STRS defines the drive ID strings for each -/ logical drives. Number of items must be equal to _VOLUMES. Valid characters for -/ the drive ID strings are: A-Z and 0-9. */ +#define FF_STR_VOLUME_ID 0 +#define FF_VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3" +/* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings. +/ When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive +/ number in the path name. FF_VOLUME_STRS defines the volume ID strings for each +/ logical drives. Number of items must not be less than FF_VOLUMES. Valid +/ characters for the volume ID strings are A-Z, a-z and 0-9, however, they are +/ compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is +/ not defined, a user defined volume string table needs to be defined as: +/ +/ const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",... +*/ #ifdef MICROPY_FATFS_MULTI_PARTITION -#define _MULTI_PARTITION (MICROPY_FATFS_MULTI_PARTITION) +#define FF_MULTI_PARTITION (MICROPY_FATFS_MULTI_PARTITION) #else -#define _MULTI_PARTITION 0 +#define FF_MULTI_PARTITION 0 #endif -/* This option switches support of multi-partition on a physical drive. +/* This option switches support for multiple volumes on the physical drive. / By default (0), each logical drive number is bound to the same physical drive / number and only an FAT volume found on the physical drive will be mounted. -/ When multi-partition is enabled (1), each logical drive number can be bound to +/ When this function is enabled (1), each logical drive number can be bound to / arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() / funciton will be available. */ -#define _MIN_SS 512 +#define FF_MIN_SS 512 #ifdef MICROPY_FATFS_MAX_SS -#define _MAX_SS (MICROPY_FATFS_MAX_SS) +#define FF_MAX_SS (MICROPY_FATFS_MAX_SS) #else -#define _MAX_SS 512 +#define FF_MAX_SS 512 #endif -/* These options configure the range of sector size to be supported. (512, 1024, -/ 2048 or 4096) Always set both 512 for most systems, all type of memory cards and +/* This set of options configures the range of sector size to be supported. (512, +/ 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and / harddisk. But a larger value may be required for on-board flash memory and some -/ type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured -/ to variable sector size and GET_SECTOR_SIZE command must be implemented to the -/ disk_ioctl() function. */ +/ type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured +/ for variable sector size mode and disk_ioctl() function needs to implement +/ GET_SECTOR_SIZE command. */ -#define _USE_TRIM 0 -/* This option switches support of ATA-TRIM. (0:Disable or 1:Enable) +#define FF_USE_TRIM 0 +/* This option switches support for ATA-TRIM. (0:Disable or 1:Enable) / To enable Trim function, also CTRL_TRIM command should be implemented to the / disk_ioctl() function. */ -#define _FS_NOFSINFO 0 +#define FF_FS_NOFSINFO 0 /* If you need to know correct free space on the FAT32 volume, set bit 0 of this / option, and f_getfree() function at first time after volume mount will force / a full FAT scan. Bit 1 controls the use of last allocated cluster number. @@ -261,44 +282,44 @@ / System Configurations /---------------------------------------------------------------------------*/ -#define _FS_TINY 1 +#define FF_FS_TINY 1 /* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) -/ At the tiny configuration, size of file object (FIL) is reduced _MAX_SS bytes. +/ At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes. / Instead of private sector buffer eliminated from the file object, common sector -/ buffer in the file system object (FATFS) is used for the file data transfer. */ +/ buffer in the filesystem object (FATFS) is used for the file data transfer. */ #ifdef MICROPY_FATFS_EXFAT -#define _FS_EXFAT (MICROPY_FATFS_EXFAT) +#define FF_FS_EXFAT (MICROPY_FATFS_EXFAT) #else -#define _FS_EXFAT 0 +#define FF_FS_EXFAT 0 #endif -/* This option switches support of exFAT file system. (0:Disable or 1:Enable) -/ When enable exFAT, also LFN needs to be enabled. (_USE_LFN >= 1) -/ Note that enabling exFAT discards C89 compatibility. */ +/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable) +/ To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1) +/ Note that enabling exFAT discards ANSI C (C89) compatibility. */ #ifdef MICROPY_FATFS_NORTC -#define _FS_NORTC (MICROPY_FATFS_NORTC) +#define FF_FS_NORTC (MICROPY_FATFS_NORTC) #else -#define _FS_NORTC 0 +#define FF_FS_NORTC 0 #endif -#define _NORTC_MON 1 -#define _NORTC_MDAY 1 -#define _NORTC_YEAR 2016 -/* The option _FS_NORTC switches timestamp functiton. If the system does not have -/ any RTC function or valid timestamp is not needed, set _FS_NORTC = 1 to disable -/ the timestamp function. All objects modified by FatFs will have a fixed timestamp -/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR in local time. -/ To enable timestamp function (_FS_NORTC = 0), get_fattime() function need to be -/ added to the project to get current time form real-time clock. _NORTC_MON, -/ _NORTC_MDAY and _NORTC_YEAR have no effect. -/ These options have no effect at read-only configuration (_FS_READONLY = 1). */ +#define FF_NORTC_MON 1 +#define FF_NORTC_MDAY 1 +#define FF_NORTC_YEAR 2018 +/* The option FF_FS_NORTC switches timestamp functiton. If the system does not have +/ any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable +/ the timestamp function. Every object modified by FatFs will have a fixed timestamp +/ defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time. +/ To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be +/ added to the project to read current time form real-time clock. FF_NORTC_MON, +/ FF_NORTC_MDAY and FF_NORTC_YEAR have no effect. +/ These options have no effect at read-only configuration (FF_FS_READONLY = 1). */ -#define _FS_LOCK 0 -/* The option _FS_LOCK switches file lock function to control duplicated file open -/ and illegal operation to open objects. This option must be 0 when _FS_READONLY +#define FF_FS_LOCK 0 +/* The option FF_FS_LOCK switches file lock function to control duplicated file open +/ and illegal operation to open objects. This option must be 0 when FF_FS_READONLY / is 1. / / 0: Disable file lock function. To avoid volume corruption, application program @@ -309,41 +330,40 @@ #ifdef MICROPY_FATFS_REENTRANT -#define _FS_REENTRANT (MICROPY_FATFS_REENTRANT) +#define FF_FS_REENTRANT (MICROPY_FATFS_REENTRANT) #else -#define _FS_REENTRANT 0 +#define FF_FS_REENTRANT 0 #endif // milliseconds #ifdef MICROPY_FATFS_TIMEOUT -#define _FS_TIMEOUT (MICROPY_FATFS_TIMEOUT) +#define FF_FS_TIMEOUT (MICROPY_FATFS_TIMEOUT) #else -#define _FS_TIMEOUT 1000 +#define FF_FS_TIMEOUT 1000 #endif #ifdef MICROPY_FATFS_SYNC_T -#define _SYNC_t MICROPY_FATFS_SYNC_T +#define FF_SYNC_t MICROPY_FATFS_SYNC_T #else -#define _SYNC_t HANDLE +#define FF_SYNC_t HANDLE #endif -/* The option _FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs +/* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs / module itself. Note that regardless of this option, file access to different / volume is always re-entrant and volume control functions, f_mount(), f_mkfs() / and f_fdisk() function, are always not re-entrant. Only file/directory access / to the same volume is under control of this function. / -/ 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect. +/ 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect. / 1: Enable re-entrancy. Also user provided synchronization handlers, / ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() / function, must be added to the project. Samples are available in / option/syscall.c. / -/ The _FS_TIMEOUT defines timeout period in unit of time tick. -/ The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, -/ SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be +/ The FF_FS_TIMEOUT defines timeout period in unit of time tick. +/ The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, +/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be / included somewhere in the scope of ff.h. */ -/* #include // O/S definitions */ /*--- End of configuration options ---*/ From e959f21986e13bada076d47ea71a6ac1370295c1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 25 Feb 2019 23:46:03 +1100 Subject: [PATCH 0160/1788] extmod/vfs_fat: Update for new oofatfs version. --- extmod/vfs_fat.c | 10 +++++----- extmod/vfs_fat_diskio.c | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index 4af836b2d0..024cecfe93 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -39,8 +39,8 @@ #include "extmod/vfs_fat.h" #include "lib/timeutils/timeutils.h" -#if _MAX_SS == _MIN_SS -#define SECSIZE(fs) (_MIN_SS) +#if FF_MAX_SS == FF_MIN_SS +#define SECSIZE(fs) (FF_MIN_SS) #else #define SECSIZE(fs) ((fs)->ssize) #endif @@ -111,7 +111,7 @@ STATIC mp_obj_t fat_vfs_mkfs(mp_obj_t bdev_in) { fs_user_mount_t *vfs = MP_OBJ_TO_PTR(fat_vfs_make_new(&mp_fat_vfs_type, 1, 0, &bdev_in)); // make the filesystem - uint8_t working_buf[_MAX_SS]; + uint8_t working_buf[FF_MAX_SS]; FRESULT res = f_mkfs(&vfs->fatfs, FM_FAT | FM_SFD, 0, working_buf, sizeof(working_buf)); if (res != FR_OK) { mp_raise_OSError(fresult_to_errno_table[res]); @@ -363,7 +363,7 @@ STATIC mp_obj_t fat_vfs_statvfs(mp_obj_t vfs_in, mp_obj_t path_in) { t->items[6] = MP_OBJ_NEW_SMALL_INT(0); // f_ffree t->items[7] = MP_OBJ_NEW_SMALL_INT(0); // f_favail t->items[8] = MP_OBJ_NEW_SMALL_INT(0); // f_flags - t->items[9] = MP_OBJ_NEW_SMALL_INT(_MAX_LFN); // f_namemax + t->items[9] = MP_OBJ_NEW_SMALL_INT(FF_MAX_LFN); // f_namemax return MP_OBJ_FROM_PTR(t); } @@ -383,7 +383,7 @@ STATIC mp_obj_t vfs_fat_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs // 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]; + uint8_t working_buf[FF_MAX_SS]; res = f_mkfs(&self->fatfs, FM_FAT | FM_SFD, 0, working_buf, sizeof(working_buf)); } if (res != FR_OK) { diff --git a/extmod/vfs_fat_diskio.c b/extmod/vfs_fat_diskio.c index fa013d2786..e80d612411 100644 --- a/extmod/vfs_fat_diskio.c +++ b/extmod/vfs_fat_diskio.c @@ -42,8 +42,8 @@ #include "lib/oofatfs/diskio.h" #include "extmod/vfs_fat.h" -#if _MAX_SS == _MIN_SS -#define SECSIZE(fs) (_MIN_SS) +#if FF_MAX_SS == FF_MIN_SS +#define SECSIZE(fs) (FF_MIN_SS) #else #define SECSIZE(fs) ((fs)->ssize) #endif @@ -194,7 +194,7 @@ DRESULT disk_ioctl ( } else { *((WORD*)buff) = mp_obj_get_int(ret); } - #if _MAX_SS != _MIN_SS + #if FF_MAX_SS != FF_MIN_SS // need to store ssize because we use it in disk_read/disk_write vfs->fatfs.ssize = *((WORD*)buff); #endif From b5f33ac2cb6076468a77f36d69df6db16b62134a Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 25 Feb 2019 23:46:17 +1100 Subject: [PATCH 0161/1788] ports: Update to work with new oofatfs version. --- ports/cc3200/application.mk | 2 +- ports/cc3200/fatfs_port.c | 12 ++++++------ ports/cc3200/mpconfigport.h | 2 +- ports/cc3200/mptask.c | 2 +- ports/esp32/Makefile | 2 +- ports/esp32/mpconfigport.h | 2 +- ports/esp8266/Makefile | 2 +- ports/esp8266/mpconfigport.h | 2 +- ports/nrf/mpconfigport.h | 2 +- ports/stm32/Makefile | 2 +- ports/stm32/main.c | 2 +- ports/stm32/mboot/diskio.c | 4 ++-- ports/stm32/mpconfigport.h | 2 +- ports/unix/Makefile | 2 +- ports/unix/mpconfigport.h | 2 +- 15 files changed, 21 insertions(+), 21 deletions(-) diff --git a/ports/cc3200/application.mk b/ports/cc3200/application.mk index 7bfd43d626..468fa134f9 100644 --- a/ports/cc3200/application.mk +++ b/ports/cc3200/application.mk @@ -140,7 +140,7 @@ APP_MAIN_SRC_C = \ APP_LIB_SRC_C = $(addprefix lib/,\ oofatfs/ff.c \ - oofatfs/option/unicode.c \ + oofatfs/ffunicode.c \ libc/string0.c \ mp-readline/readline.c \ netutils/netutils.c \ diff --git a/ports/cc3200/fatfs_port.c b/ports/cc3200/fatfs_port.c index 658c94e886..6cfc17c3d8 100644 --- a/ports/cc3200/fatfs_port.c +++ b/ports/cc3200/fatfs_port.c @@ -30,12 +30,12 @@ #include "lib/timeutils/timeutils.h" #include "mods/pybrtc.h" -#if _FS_REENTRANT +#if FF_FS_REENTRANT // Create a Synchronization Object // This function is called in f_mount() function to create a new // synchronization object, such as semaphore and mutex. // A return of 0 indicates failure, and then f_mount() fails with FR_INT_ERR. -int ff_cre_syncobj(FATFS *fatfs, _SYNC_t *sobj) { +int ff_cre_syncobj(FATFS *fatfs, FF_SYNC_t *sobj) { vSemaphoreCreateBinary((*sobj)); return (int)(*sobj != NULL); } @@ -44,7 +44,7 @@ int ff_cre_syncobj(FATFS *fatfs, _SYNC_t *sobj) { // This function is called in f_mount() function to delete a synchronization // object that created with ff_cre_syncobj function. // A return of 0 indicates failure, and then f_mount() fails with FR_INT_ERR. -int ff_del_syncobj(_SYNC_t sobj) { +int ff_del_syncobj(FF_SYNC_t sobj) { vSemaphoreDelete(sobj); return 1; } @@ -52,13 +52,13 @@ int ff_del_syncobj(_SYNC_t sobj) { // Request Grant to Access the Volume // This function is called on entering file functions to lock the volume. // When a 0 is returned, the file function fails with FR_TIMEOUT. -int ff_req_grant(_SYNC_t sobj) { - return (int)(xSemaphoreTake(sobj, _FS_TIMEOUT) == pdTRUE); +int ff_req_grant(FF_SYNC_t sobj) { + return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE); } // Release Grant to Access the Volume // This function is called on leaving file functions to unlock the volume. -void ff_rel_grant(_SYNC_t sobj) { +void ff_rel_grant(FF_SYNC_t sobj) { xSemaphoreGive(sobj); } diff --git a/ports/cc3200/mpconfigport.h b/ports/cc3200/mpconfigport.h index 17de4a2f65..e7894dd023 100644 --- a/ports/cc3200/mpconfigport.h +++ b/ports/cc3200/mpconfigport.h @@ -65,7 +65,7 @@ // fatfs configuration used in ffconf.h #define MICROPY_FATFS_ENABLE_LFN (2) #define MICROPY_FATFS_MAX_LFN (MICROPY_ALLOC_PATH_MAX) -#define MICROPY_FATFS_LFN_CODE_PAGE (437) // 1=SFN/ANSI 437=LFN/U.S.(OEM) +#define MICROPY_FATFS_LFN_CODE_PAGE 437 // 1=SFN/ANSI 437=LFN/U.S.(OEM) #define MICROPY_FATFS_RPATH (2) #define MICROPY_FATFS_REENTRANT (1) #define MICROPY_FATFS_TIMEOUT (2500) diff --git a/ports/cc3200/mptask.c b/ports/cc3200/mptask.c index 9390978474..9d75f4678e 100644 --- a/ports/cc3200/mptask.c +++ b/ports/cc3200/mptask.c @@ -307,7 +307,7 @@ STATIC void mptask_init_sflash_filesystem (void) { FRESULT res = f_mount(&vfs_fat->fatfs); if (res == FR_NO_FILESYSTEM) { // no filesystem, so create a fresh one - uint8_t working_buf[_MAX_SS]; + uint8_t working_buf[FF_MAX_SS]; res = f_mkfs(&vfs_fat->fatfs, FM_FAT | FM_SFD, 0, working_buf, sizeof(working_buf)); if (res == FR_OK) { // success creating fresh LFS diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 068757834e..36ee4b3b0a 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -209,7 +209,7 @@ LIB_SRC_C = $(addprefix lib/,\ ifeq ($(MICROPY_FATFS), 1) LIB_SRC_C += \ lib/oofatfs/ff.c \ - lib/oofatfs/option/unicode.c + lib/oofatfs/ffunicode.c endif DRIVERS_SRC_C = $(addprefix drivers/,\ diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 01b23de05f..7b9b400250 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -155,7 +155,7 @@ #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 MICROPY_FATFS_LFN_CODE_PAGE 437 /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ #define mp_type_fileio mp_type_vfs_fat_fileio #define mp_type_textio mp_type_vfs_fat_textio diff --git a/ports/esp8266/Makefile b/ports/esp8266/Makefile index 0bbb990d29..64116b139b 100644 --- a/ports/esp8266/Makefile +++ b/ports/esp8266/Makefile @@ -127,7 +127,7 @@ LIB_SRC_C = $(addprefix lib/,\ ifeq ($(MICROPY_FATFS), 1) LIB_SRC_C += \ lib/oofatfs/ff.c \ - lib/oofatfs/option/unicode.c + lib/oofatfs/ffunicode.c endif DRIVERS_SRC_C = $(addprefix drivers/,\ diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h index c6bd4c87d8..03be59b063 100644 --- a/ports/esp8266/mpconfigport.h +++ b/ports/esp8266/mpconfigport.h @@ -110,7 +110,7 @@ #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 MICROPY_FATFS_LFN_CODE_PAGE 437 /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ #define MICROPY_VFS_FAT (1) #define MICROPY_ESP8266_APA102 (1) #define MICROPY_ESP8266_NEOPIXEL (1) diff --git a/ports/nrf/mpconfigport.h b/ports/nrf/mpconfigport.h index a5e16421cc..0e3cf7b39d 100644 --- a/ports/nrf/mpconfigport.h +++ b/ports/nrf/mpconfigport.h @@ -65,7 +65,7 @@ // fatfs configuration used in ffconf.h #define MICROPY_FATFS_ENABLE_LFN (1) -#define MICROPY_FATFS_LFN_CODE_PAGE (437) /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ +#define MICROPY_FATFS_LFN_CODE_PAGE 437 /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ #define MICROPY_FATFS_USE_LABEL (1) #define MICROPY_FATFS_RPATH (2) #define MICROPY_FATFS_MULTI_PARTITION (1) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index a4f3cb2d0b..4fddc6c7d3 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -108,7 +108,7 @@ endif SRC_LIB = $(addprefix lib/,\ libc/string0.c \ oofatfs/ff.c \ - oofatfs/option/unicode.c \ + oofatfs/ffunicode.c \ mp-readline/readline.c \ netutils/netutils.c \ netutils/trace.c \ diff --git a/ports/stm32/main.c b/ports/stm32/main.c index c7b189dabf..48b4692bc5 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -201,7 +201,7 @@ MP_NOINLINE STATIC bool init_flash_fs(uint reset_mode) { led_state(PYB_LED_GREEN, 1); uint32_t start_tick = HAL_GetTick(); - uint8_t working_buf[_MAX_SS]; + uint8_t working_buf[FF_MAX_SS]; res = f_mkfs(&vfs_fat->fatfs, FM_FAT, 0, working_buf, sizeof(working_buf)); if (res == FR_OK) { // success creating fresh LFS diff --git a/ports/stm32/mboot/diskio.c b/ports/stm32/mboot/diskio.c index 2426f9329a..5f68f26a8e 100644 --- a/ports/stm32/mboot/diskio.c +++ b/ports/stm32/mboot/diskio.c @@ -31,8 +31,8 @@ #if MBOOT_FSLOAD -#if _MAX_SS == _MIN_SS -#define SECSIZE (_MIN_SS) +#if FF_MAX_SS == FF_MIN_SS +#define SECSIZE (FF_MIN_SS) #else #error Unsupported #endif diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 712697c80e..bdceb8c532 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -169,7 +169,7 @@ // fatfs configuration used in ffconf.h #define MICROPY_FATFS_ENABLE_LFN (1) -#define MICROPY_FATFS_LFN_CODE_PAGE (437) /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ +#define MICROPY_FATFS_LFN_CODE_PAGE 437 /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ #define MICROPY_FATFS_USE_LABEL (1) #define MICROPY_FATFS_RPATH (2) #define MICROPY_FATFS_MULTI_PARTITION (1) diff --git a/ports/unix/Makefile b/ports/unix/Makefile index badfac7c8d..be45513c31 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -162,7 +162,7 @@ LIB_SRC_C = $(addprefix lib/,\ # FatFS VFS support LIB_SRC_C += $(addprefix lib/,\ oofatfs/ff.c \ - oofatfs/option/unicode.c \ + oofatfs/ffunicode.c \ ) OBJ = $(PY_O) diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h index 2614af8392..97a9f49084 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -145,7 +145,7 @@ #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 MICROPY_FATFS_LFN_CODE_PAGE 437 /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ #define MICROPY_VFS_FAT (0) // Define to MICROPY_ERROR_REPORTING_DETAILED to get function, etc. From e1fb03f3e2d1e99d0f745e9e17a963a036d34476 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 2 Jan 2019 17:48:43 +1100 Subject: [PATCH 0162/1788] py: Fix VM crash with unwinding jump out of a finally block. This patch fixes a bug in the VM when breaking within a try-finally. The bug has to do with executing a break within the finally block of a try-finally statement. For example: def f(): for x in (1,): print('a', x) try: raise Exception finally: print(1) break print('b', x) f() Currently in uPy the above code will print: a 1 1 1 segmentation fault (core dumped) micropython Not only is there a seg fault, but the "1" in the finally block is printed twice. This is because when the VM executes a finally block it doesn't really know if that block was executed due to a fall-through of the try (no exception raised), or because an exception is active. In particular, for nested finallys the VM has no idea which of the nested ones have active exceptions and which are just fall-throughs. So when a break (or continue) is executed it tries to unwind all of the finallys, when in fact only some may be active. It's questionable whether break (or return or continue) should be allowed within a finally block, because they implicitly swallow any active exception, but nevertheless it's allowed by CPython (although almost never used in the standard library). And uPy should at least not crash in such a case. The solution here relies on the fact that exception and finally handlers always appear in the bytecode after the try body. Note: there was a similar bug with a return in a finally block, but that was previously fixed in b735208403a54774f9fd3d966f7c1a194c41870f --- py/compile.c | 5 +- py/emitbc.c | 1 - py/vm.c | 10 ++-- tests/basics/try_finally_break.py | 99 +++++++++++++++++++++++++++++++ tests/basics/try_return.py | 9 +++ tests/cmdline/cmd_showbc.py.exp | 2 - 6 files changed, 114 insertions(+), 12 deletions(-) create mode 100644 tests/basics/try_finally_break.py diff --git a/py/compile.c b/py/compile.c index 42222528e2..ca01d74785 100644 --- a/py/compile.c +++ b/py/compile.c @@ -1599,7 +1599,6 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_ } compile_node(comp, pns_except->nodes[1]); // the if (qstr_exception_local != 0) { - EMIT(pop_block); EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); EMIT_ARG(label_assign, l3); EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); @@ -1635,7 +1634,6 @@ STATIC void compile_try_finally(compiler_t *comp, mp_parse_node_t pn_body, int n } else { compile_try_except(comp, pn_body, n_except, pn_except, pn_else); } - EMIT(pop_block); EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); EMIT_ARG(label_assign, l_finally_block); compile_node(comp, pn_finally); @@ -1811,8 +1809,7 @@ STATIC void compile_async_with_stmt_helper(compiler_t *comp, int n, mp_parse_nod compile_async_with_stmt_helper(comp, n - 1, nodes + 1, body); EMIT_ARG(adjust_stack_size, -3); - // Finish the "try" block - EMIT(pop_block); + // We have now finished the "try" block and fall through to the "finally" // At this point, after the with body has executed, we have 3 cases: // 1. no exception, we just fall through to this point; stack: (..., ctx_mgr) diff --git a/py/emitbc.c b/py/emitbc.c index 6a46cfb593..65d6509051 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -738,7 +738,6 @@ 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) { - mp_emit_bc_pop_block(emit); mp_emit_bc_load_const_tok(emit, MP_TOKEN_KW_NONE); mp_emit_bc_label_assign(emit, label); emit_bc_pre(emit, 2); // ensure we have enough stack space to call the __exit__ method diff --git a/py/vm.c b/py/vm.c index a0ee2e89a4..56494dfa14 100644 --- a/py/vm.c +++ b/py/vm.c @@ -633,8 +633,6 @@ dispatch_loop: // replacing it with None, which signals END_FINALLY to just // execute the finally handler normally. SET_TOP(mp_const_none); - assert(exc_sp >= exc_stack); - POP_EXC_BLOCK(); } else { // We need to re-raise the exception. We pop __exit__ handler // by copying the exception instance down to the new top-of-stack. @@ -654,7 +652,7 @@ unwind_jump:; while ((unum & 0x7f) > 0) { unum -= 1; assert(exc_sp >= exc_stack); - if (MP_TAGPTR_TAG1(exc_sp->val_sp)) { + if (MP_TAGPTR_TAG1(exc_sp->val_sp) && exc_sp->handler > ip) { // Getting here the stack looks like: // (..., X, dest_ip) // where X is pointed to by exc_sp->val_sp and in the case @@ -698,6 +696,8 @@ unwind_jump:; // if TOS is an integer, finishes coroutine and returns control to caller // if TOS is an exception, reraises the exception if (TOP() == mp_const_none) { + assert(exc_sp >= exc_stack); + POP_EXC_BLOCK(); sp--; } else if (mp_obj_is_small_int(TOP())) { // We finished "finally" coroutine and now dispatch back @@ -1063,7 +1063,7 @@ unwind_jump:; unwind_return: // Search for and execute finally handlers that aren't already active while (exc_sp >= exc_stack) { - if (!currently_in_except_block && MP_TAGPTR_TAG1(exc_sp->val_sp)) { + if (!currently_in_except_block && MP_TAGPTR_TAG1(exc_sp->val_sp) && exc_sp->handler > ip) { // Found a finally handler that isn't active. // Getting here the stack looks like: // (..., X, [iter0, iter1, ...,] ret_val) @@ -1419,7 +1419,7 @@ unwind_loop: mp_obj_exception_add_traceback(MP_OBJ_FROM_PTR(nlr.ret_val), source_file, source_line, block_name); } - while (currently_in_except_block) { + while (currently_in_except_block || (exc_sp >= exc_stack && exc_sp->handler <= code_state->ip)) { // nested exception assert(exc_sp >= exc_stack); diff --git a/tests/basics/try_finally_break.py b/tests/basics/try_finally_break.py new file mode 100644 index 0000000000..ae7226637d --- /dev/null +++ b/tests/basics/try_finally_break.py @@ -0,0 +1,99 @@ +# test break within (nested) finally + +# basic case with break in finally +def f(): + for _ in range(2): + print(1) + try: + pass + finally: + print(2) + break + print(3) + print(4) + print(5) +f() + +# where the finally swallows an exception +def f(): + lst = [1, 2, 3] + for x in lst: + print('a', x) + try: + raise Exception + finally: + print(1) + break + print('b', x) +f() + +# basic nested finally with break in inner finally +def f(): + for i in range(2): + print('iter', i) + try: + raise TypeError + finally: + print(1) + try: + raise ValueError + finally: + break +print(f()) + +# similar to above but more nesting +def f(): + for i in range(2): + try: + raise ValueError + finally: + print(1) + try: + raise TypeError + finally: + print(2) + try: + pass + finally: + break +print(f()) + +# lots of nesting +def f(): + for i in range(2): + try: + raise ValueError + finally: + print(1) + try: + raise TypeError + finally: + print(2) + try: + raise Exception + finally: + break +print(f()) + +# basic case combined with try-else +def f(arg): + for _ in range(2): + print(1) + try: + if arg == 1: + raise ValueError + elif arg == 2: + raise TypeError + except ValueError: + print(2) + else: + print(3) + finally: + print(4) + break + print(5) + print(6) + print(7) +f(0) # no exception, else should execute +f(1) # exception caught, else should be skipped +f(2) # exception not caught, finally swallows exception, else should be skipped diff --git a/tests/basics/try_return.py b/tests/basics/try_return.py index 492c18d95c..a24290c4fb 100644 --- a/tests/basics/try_return.py +++ b/tests/basics/try_return.py @@ -1,5 +1,14 @@ # test use of return with try-except +def f(): + try: + print(1) + return + except: + print(2) + print(3) +f() + def f(l, i): try: return l[i] diff --git a/tests/cmdline/cmd_showbc.py.exp b/tests/cmdline/cmd_showbc.py.exp index 1274cda00f..d119a6198b 100644 --- a/tests/cmdline/cmd_showbc.py.exp +++ b/tests/cmdline/cmd_showbc.py.exp @@ -265,7 +265,6 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): \\d\+ POP_EXCEPT \\d\+ JUMP \\d\+ \\d\+ END_FINALLY -\\d\+ POP_BLOCK \\d\+ LOAD_CONST_NONE \\d\+ LOAD_FAST 1 \\d\+ POP_TOP @@ -286,7 +285,6 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): \\d\+ POP_TOP \\d\+ LOAD_DEREF 14 \\d\+ POP_TOP -\\d\+ POP_BLOCK \\d\+ LOAD_CONST_NONE \\d\+ WITH_CLEANUP \\d\+ END_FINALLY From 6f9e3ff719917616f163d3d671d6abe9472ba6ff Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 4 Jan 2019 16:40:29 +1100 Subject: [PATCH 0163/1788] py/vm: Remove currently_in_except_block variable. After the previous commit it is no longer needed. --- py/vm.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/py/vm.c b/py/vm.c index 56494dfa14..a53b4a0838 100644 --- a/py/vm.c +++ b/py/vm.c @@ -100,13 +100,11 @@ DECODE_ULABEL; /* except labels are always forward */ \ ++exc_sp; \ exc_sp->handler = ip + ulab; \ - exc_sp->val_sp = MP_TAGPTR_MAKE(sp, ((with_or_finally) << 1) | currently_in_except_block); \ + exc_sp->val_sp = MP_TAGPTR_MAKE(sp, ((with_or_finally) << 1)); \ exc_sp->prev_exc = NULL; \ - currently_in_except_block = 0; /* in a try block now */ \ } while (0) #define POP_EXC_BLOCK() \ - currently_in_except_block = MP_TAGPTR_TAG0(exc_sp->val_sp); /* restore previous state */ \ exc_sp--; /* pop back to previous exception handler */ \ CLEAR_SYS_EXC_INFO() /* just clear sys.exc_info(), not compliant, but it shouldn't be used in 1st place */ @@ -161,7 +159,6 @@ run_code_state: ; } // variables that are visible to the exception handler (declared volatile) - volatile bool currently_in_except_block = MP_TAGPTR_TAG0(code_state->exc_sp); // 0 or 1, to detect nested exceptions mp_exc_stack_t *volatile exc_sp = MP_TAGPTR_PTR(code_state->exc_sp); // stack grows up, exc_sp points to top of stack #if MICROPY_PY_THREAD_GIL && MICROPY_PY_THREAD_GIL_VM_DIVISOR @@ -771,7 +768,6 @@ unwind_jump:; // matched against: SETUP_EXCEPT ENTRY(MP_BC_POP_EXCEPT): assert(exc_sp >= exc_stack); - assert(currently_in_except_block); POP_EXC_BLOCK(); DISPATCH(); @@ -906,7 +902,7 @@ unwind_jump:; if (mp_obj_get_type(*sp) == &mp_type_fun_bc) { code_state->ip = ip; code_state->sp = sp; - code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block); + code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, 0); mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1); #if !MICROPY_ENABLE_PYSTACK if (new_state == NULL) { @@ -942,7 +938,7 @@ unwind_jump:; if (mp_obj_get_type(*sp) == &mp_type_fun_bc) { code_state->ip = ip; code_state->sp = sp; - code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block); + code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, 0); mp_call_args_t out_args; mp_call_prepare_args_n_kw_var(false, unum, sp, &out_args); @@ -985,7 +981,7 @@ unwind_jump:; if (mp_obj_get_type(*sp) == &mp_type_fun_bc) { code_state->ip = ip; code_state->sp = sp; - code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block); + code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, 0); size_t n_args = unum & 0xff; size_t n_kw = (unum >> 8) & 0xff; @@ -1025,7 +1021,7 @@ unwind_jump:; if (mp_obj_get_type(*sp) == &mp_type_fun_bc) { code_state->ip = ip; code_state->sp = sp; - code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block); + code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, 0); mp_call_args_t out_args; mp_call_prepare_args_n_kw_var(true, unum, sp, &out_args); @@ -1063,7 +1059,7 @@ unwind_jump:; unwind_return: // Search for and execute finally handlers that aren't already active while (exc_sp >= exc_stack) { - if (!currently_in_except_block && MP_TAGPTR_TAG1(exc_sp->val_sp) && exc_sp->handler > ip) { + if (MP_TAGPTR_TAG1(exc_sp->val_sp) && exc_sp->handler > ip) { // Found a finally handler that isn't active. // Getting here the stack looks like: // (..., X, [iter0, iter1, ...,] ret_val) @@ -1145,7 +1141,7 @@ yield: nlr_pop(); code_state->ip = ip; code_state->sp = sp; - code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block); + code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, 0); return MP_VM_RETURN_YIELD; ENTRY(MP_BC_YIELD_FROM): { @@ -1419,7 +1415,8 @@ unwind_loop: mp_obj_exception_add_traceback(MP_OBJ_FROM_PTR(nlr.ret_val), source_file, source_line, block_name); } - while (currently_in_except_block || (exc_sp >= exc_stack && exc_sp->handler <= code_state->ip)) { + while (exc_sp >= exc_stack && exc_sp->handler <= code_state->ip) { + // nested exception assert(exc_sp >= exc_stack); @@ -1432,9 +1429,6 @@ unwind_loop: } if (exc_sp >= exc_stack) { - // set flag to indicate that we are now handling an exception - currently_in_except_block = 1; - // catch exception and pass to byte code code_state->ip = exc_sp->handler; mp_obj_t *sp = MP_TAGPTR_PTR(exc_sp->val_sp); @@ -1460,7 +1454,6 @@ unwind_loop: fastn = &code_state->state[n_state - 1]; exc_stack = (mp_exc_stack_t*)(code_state->state + n_state); // variables that are visible to the exception handler (declared volatile) - currently_in_except_block = MP_TAGPTR_TAG0(code_state->exc_sp); // 0 or 1, to detect nested exceptions exc_sp = MP_TAGPTR_PTR(code_state->exc_sp); // stack grows up, exc_sp points to top of stack goto unwind_loop; From 5a2599d96299ad37cda954f1de345159f9acf11c Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 15 Feb 2019 12:18:59 +1100 Subject: [PATCH 0164/1788] py: Replace POP_BLOCK and POP_EXCEPT opcodes with POP_EXCEPT_JUMP. POP_BLOCK and POP_EXCEPT are now the same, and are always followed by a JUMP. So this optimisation reduces code size, and RAM usage of bytecode by two bytes for each try-except handler. --- py/bc.c | 2 +- py/bc0.h | 3 +-- py/compile.c | 12 ++++-------- py/emit.h | 6 ++---- py/emitbc.c | 13 ++++--------- py/emitnative.c | 22 +++++++++------------- py/showbc.c | 11 +++-------- py/vm.c | 14 +++++--------- py/vmentrytable.h | 3 +-- tests/cmdline/cmd_showbc.py.exp | 12 ++++-------- tools/mpy-tool.py | 2 +- 11 files changed, 35 insertions(+), 65 deletions(-) diff --git a/py/bc.c b/py/bc.c index 1d6e4322b2..4a29f439e3 100644 --- a/py/bc.c +++ b/py/bc.c @@ -321,7 +321,7 @@ STATIC const byte opcode_format_table[64] = { OC4(O, O, U, U), // 0x38-0x3b OC4(U, O, B, O), // 0x3c-0x3f OC4(O, B, B, O), // 0x40-0x43 - OC4(B, B, O, B), // 0x44-0x47 + OC4(O, U, O, B), // 0x44-0x47 OC4(U, U, U, U), // 0x48-0x4b OC4(U, U, U, U), // 0x4c-0x4f OC4(V, V, U, V), // 0x50-0x53 diff --git a/py/bc0.h b/py/bc0.h index 70acfb0cac..175ee263a0 100644 --- a/py/bc0.h +++ b/py/bc0.h @@ -77,8 +77,7 @@ #define MP_BC_END_FINALLY (0x41) #define MP_BC_GET_ITER (0x42) #define MP_BC_FOR_ITER (0x43) // rel byte code offset, 16-bit unsigned -#define MP_BC_POP_BLOCK (0x44) -#define MP_BC_POP_EXCEPT (0x45) +#define MP_BC_POP_EXCEPT_JUMP (0x44) // rel byte code offset, 16-bit unsigned #define MP_BC_UNWIND_JUMP (0x46) // rel byte code offset, 16-bit signed, in excess; then a byte #define MP_BC_GET_ITER_STACK (0x47) diff --git a/py/compile.c b/py/compile.c index ca01d74785..b7f1d7b0c1 100644 --- a/py/compile.c +++ b/py/compile.c @@ -1535,8 +1535,7 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_ compile_increase_except_level(comp, l1, MP_EMIT_SETUP_BLOCK_EXCEPT); compile_node(comp, pn_body); // body - EMIT(pop_block); - EMIT_ARG(jump, success_label); // jump over exception handler + EMIT_ARG(pop_except_jump, success_label, false); // jump over exception handler EMIT_ARG(label_assign, l1); // start of exception handler EMIT(start_except_handler); @@ -1607,8 +1606,7 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_ compile_decrease_except_level(comp); } - EMIT(pop_except); - EMIT_ARG(jump, l2); + EMIT_ARG(pop_except_jump, l2, true); EMIT_ARG(label_assign, end_finally_label); EMIT_ARG(adjust_stack_size, 1); // stack adjust for the exception instance } @@ -1741,8 +1739,7 @@ STATIC void compile_async_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns compile_load_id(comp, context); compile_await_object_method(comp, MP_QSTR___anext__); c_assign(comp, pns->nodes[0], ASSIGN_STORE); // variable - EMIT(pop_block); - EMIT_ARG(jump, try_else_label); + EMIT_ARG(pop_except_jump, try_else_label, false); EMIT_ARG(label_assign, try_exception_label); EMIT(start_except_handler); @@ -1751,8 +1748,7 @@ STATIC void compile_async_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns EMIT_ARG(binary_op, MP_BINARY_OP_EXCEPTION_MATCH); EMIT_ARG(pop_jump_if, false, try_finally_label); EMIT(pop_top); // pop exception instance - EMIT(pop_except); - EMIT_ARG(jump, while_else_label); + EMIT_ARG(pop_except_jump, while_else_label, true); EMIT_ARG(label_assign, try_finally_label); EMIT_ARG(adjust_stack_size, 1); // if we jump here, the exc is on the stack diff --git a/py/emit.h b/py/emit.h index 3c42bdf143..34c6cfd845 100644 --- a/py/emit.h +++ b/py/emit.h @@ -134,8 +134,7 @@ typedef struct _emit_method_table_t { void (*get_iter)(emit_t *emit, bool use_stack); void (*for_iter)(emit_t *emit, mp_uint_t label); void (*for_iter_end)(emit_t *emit); - void (*pop_block)(emit_t *emit); - void (*pop_except)(emit_t *emit); + void (*pop_except_jump)(emit_t *emit, mp_uint_t label, bool within_exc_handler); void (*unary_op)(emit_t *emit, mp_unary_op_t op); void (*binary_op)(emit_t *emit, mp_binary_op_t op); void (*build)(emit_t *emit, mp_uint_t n_args, int kind); @@ -232,8 +231,7 @@ 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); void mp_emit_bc_for_iter_end(emit_t *emit); -void mp_emit_bc_pop_block(emit_t *emit); -void mp_emit_bc_pop_except(emit_t *emit); +void mp_emit_bc_pop_except_jump(emit_t *emit, mp_uint_t label, bool within_exc_handler); 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); diff --git a/py/emitbc.c b/py/emitbc.c index 65d6509051..4142e892d6 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -764,14 +764,10 @@ void mp_emit_bc_for_iter_end(emit_t *emit) { emit_bc_pre(emit, -MP_OBJ_ITER_BUF_NSLOTS); } -void mp_emit_bc_pop_block(emit_t *emit) { +void mp_emit_bc_pop_except_jump(emit_t *emit, mp_uint_t label, bool within_exc_handler) { + (void)within_exc_handler; emit_bc_pre(emit, 0); - emit_write_bytecode_byte(emit, MP_BC_POP_BLOCK); -} - -void mp_emit_bc_pop_except(emit_t *emit) { - emit_bc_pre(emit, 0); - emit_write_bytecode_byte(emit, MP_BC_POP_EXCEPT); + emit_write_bytecode_byte_unsigned_label(emit, MP_BC_POP_EXCEPT_JUMP, label); } void mp_emit_bc_unary_op(emit_t *emit, mp_unary_op_t op) { @@ -958,8 +954,7 @@ const emit_method_table_t emit_bc_method_table = { mp_emit_bc_get_iter, mp_emit_bc_for_iter, mp_emit_bc_for_iter_end, - mp_emit_bc_pop_block, - mp_emit_bc_pop_except, + mp_emit_bc_pop_except_jump, mp_emit_bc_unary_op, mp_emit_bc_binary_op, mp_emit_bc_build, diff --git a/py/emitnative.c b/py/emitnative.c index 8b7ebe5301..c8a1a33d6b 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -1916,7 +1916,7 @@ STATIC void emit_native_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t exc prev_finally->unwind_label = UNWIND_LABEL_DO_FINAL_UNWIND; ASM_MOV_REG_PCREL(emit->as, REG_RET, label & ~MP_EMIT_BREAK_FROM_FOR); ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_UNWIND(emit), REG_RET); - // Cancel any active exception (see also emit_native_pop_except) + // Cancel any active exception (see also emit_native_pop_except_jump) emit_native_mov_reg_const(emit, REG_RET, MP_F_CONST_NONE_OBJ); ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_RET); // Jump to the innermost active finally @@ -2111,18 +2111,15 @@ STATIC void emit_native_for_iter_end(emit_t *emit) { emit_post(emit); } -STATIC void emit_native_pop_block(emit_t *emit) { - emit_native_pre(emit); - if (!emit->exc_stack[emit->exc_stack_size - 1].is_finally) { +STATIC void emit_native_pop_except_jump(emit_t *emit, mp_uint_t label, bool within_exc_handler) { + if (within_exc_handler) { + // Cancel any active exception so subsequent handlers don't see it + emit_native_mov_reg_const(emit, REG_TEMP0, MP_F_CONST_NONE_OBJ); + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_TEMP0); + } else { emit_native_leave_exc_stack(emit, false); } - emit_post(emit); -} - -STATIC void emit_native_pop_except(emit_t *emit) { - // Cancel any active exception so subsequent handlers don't see it - emit_native_mov_reg_const(emit, REG_TEMP0, MP_F_CONST_NONE_OBJ); - ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_TEMP0); + emit_native_jump(emit, label); } STATIC void emit_native_unary_op(emit_t *emit, mp_unary_op_t op) { @@ -2726,8 +2723,7 @@ const emit_method_table_t EXPORT_FUN(method_table) = { emit_native_get_iter, emit_native_for_iter, emit_native_for_iter_end, - emit_native_pop_block, - emit_native_pop_except, + emit_native_pop_except_jump, emit_native_unary_op, emit_native_binary_op, emit_native_build, diff --git a/py/showbc.c b/py/showbc.c index 3deb18cd31..b9024b716d 100644 --- a/py/showbc.c +++ b/py/showbc.c @@ -401,14 +401,9 @@ const byte *mp_bytecode_print_str(const byte *ip) { printf("FOR_ITER " UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start)); break; - case MP_BC_POP_BLOCK: - // pops block and restores the stack - printf("POP_BLOCK"); - break; - - case MP_BC_POP_EXCEPT: - // pops block, checks it's an exception block, and restores the stack, saving the 3 exception values to local threadstate - printf("POP_EXCEPT"); + case MP_BC_POP_EXCEPT_JUMP: + DECODE_ULABEL; // these labels are always forward + printf("POP_EXCEPT_JUMP " UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start)); break; case MP_BC_BUILD_TUPLE: diff --git a/py/vm.c b/py/vm.c index a53b4a0838..901a23f225 100644 --- a/py/vm.c +++ b/py/vm.c @@ -759,17 +759,13 @@ unwind_jump:; } // matched against: SETUP_EXCEPT, SETUP_FINALLY, SETUP_WITH - ENTRY(MP_BC_POP_BLOCK): - // we are exiting an exception handler, so pop the last one of the exception-stack + ENTRY(MP_BC_POP_EXCEPT_JUMP): { assert(exc_sp >= exc_stack); POP_EXC_BLOCK(); - DISPATCH(); - - // matched against: SETUP_EXCEPT - ENTRY(MP_BC_POP_EXCEPT): - assert(exc_sp >= exc_stack); - POP_EXC_BLOCK(); - DISPATCH(); + DECODE_ULABEL; + ip += ulab; + DISPATCH_WITH_PEND_EXC_CHECK(); + } ENTRY(MP_BC_BUILD_TUPLE): { MARK_EXC_IP_SELECTIVE(); diff --git a/py/vmentrytable.h b/py/vmentrytable.h index 615f4e2ce4..641c8ee422 100644 --- a/py/vmentrytable.h +++ b/py/vmentrytable.h @@ -76,8 +76,7 @@ static const void *const entry_table[256] = { [MP_BC_GET_ITER] = &&entry_MP_BC_GET_ITER, [MP_BC_GET_ITER_STACK] = &&entry_MP_BC_GET_ITER_STACK, [MP_BC_FOR_ITER] = &&entry_MP_BC_FOR_ITER, - [MP_BC_POP_BLOCK] = &&entry_MP_BC_POP_BLOCK, - [MP_BC_POP_EXCEPT] = &&entry_MP_BC_POP_EXCEPT, + [MP_BC_POP_EXCEPT_JUMP] = &&entry_MP_BC_POP_EXCEPT_JUMP, [MP_BC_BUILD_TUPLE] = &&entry_MP_BC_BUILD_TUPLE, [MP_BC_BUILD_LIST] = &&entry_MP_BC_BUILD_LIST, [MP_BC_BUILD_MAP] = &&entry_MP_BC_BUILD_MAP, diff --git a/tests/cmdline/cmd_showbc.py.exp b/tests/cmdline/cmd_showbc.py.exp index d119a6198b..8d36b89df7 100644 --- a/tests/cmdline/cmd_showbc.py.exp +++ b/tests/cmdline/cmd_showbc.py.exp @@ -257,13 +257,11 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): \\d\+ JUMP \\d\+ \\d\+ LOAD_FAST 0 \\d\+ POP_JUMP_IF_TRUE \\d\+ -\\d\+ POP_BLOCK -\\d\+ JUMP \\d\+ +\\d\+ POP_EXCEPT_JUMP \\d\+ \\d\+ POP_TOP \\d\+ LOAD_DEREF 14 \\d\+ POP_TOP -\\d\+ POP_EXCEPT -\\d\+ JUMP \\d\+ +\\d\+ POP_EXCEPT_JUMP \\d\+ \\d\+ END_FINALLY \\d\+ LOAD_CONST_NONE \\d\+ LOAD_FAST 1 @@ -272,11 +270,9 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): \\d\+ JUMP \\d\+ \\d\+ SETUP_EXCEPT \\d\+ \\d\+ UNWIND_JUMP \\d\+ 1 -\\d\+ POP_BLOCK -\\d\+ JUMP \\d\+ +\\d\+ POP_EXCEPT_JUMP \\d\+ \\d\+ POP_TOP -\\d\+ POP_EXCEPT -\\d\+ JUMP \\d\+ +\\d\+ POP_EXCEPT_JUMP \\d\+ \\d\+ END_FINALLY \\d\+ LOAD_FAST 0 \\d\+ POP_JUMP_IF_TRUE \\d\+ diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index 6fbb10a39d..62f2ac4815 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -105,7 +105,7 @@ def make_opcode_format(): OC4(O, O, U, U), # 0x38-0x3b OC4(U, O, B, O), # 0x3c-0x3f OC4(O, B, B, O), # 0x40-0x43 - OC4(B, B, O, B), # 0x44-0x47 + OC4(O, U, O, B), # 0x44-0x47 OC4(U, U, U, U), # 0x48-0x4b OC4(U, U, U, U), # 0x4c-0x4f OC4(V, V, U, V), # 0x50-0x53 From 5996eeb48fa6ce773003eacbc7e0b52ad5cc4d31 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 25 Feb 2019 23:15:51 +1100 Subject: [PATCH 0165/1788] py/persistentcode: Add a qstr window to save mpy files more efficiently. This is an implementation of a sliding qstr window used to reduce the number of qstrs stored in a .mpy file. The window size is configured to 32 entries which takes a fixed 64 bytes (16-bits each) on the C stack when loading/saving a .mpy file. It allows to remember the most recent 32 qstrs so they don't need to be stored again in the .mpy file. The qstr window uses a simple least-recently-used mechanism to discard the least recently used qstr when the window overflows (similar to dictionary compression). This scheme only needs a single pass to save/load the .mpy file. Reduces mpy file size by about 25% with a window size of 32. --- py/persistentcode.c | 128 +++++++++++++++++++++++++------- tests/import/mpy_invalid.py | 1 + tests/import/mpy_invalid.py.exp | 1 + tools/mpy-tool.py | 50 +++++++++---- 4 files changed, 140 insertions(+), 40 deletions(-) diff --git a/py/persistentcode.c b/py/persistentcode.c index aff37036b3..9cea08a2d7 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -41,7 +41,11 @@ // The current version of .mpy files #define MPY_VERSION (3) -// The feature flags byte encodes the compile-time config options that +// Macros to encode/decode flags to/from the feature byte +#define MPY_FEATURE_ENCODE_FLAGS(flags) (flags) +#define MPY_FEATURE_DECODE_FLAGS(feat) ((feat) & 3) + +// The feature flag bits encode the compile-time config options that // affect the generate bytecode. #define MPY_FEATURE_FLAGS ( \ ((MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) << 0) \ @@ -68,6 +72,57 @@ STATIC int mp_small_int_bits(void) { } #endif +#define QSTR_WINDOW_SIZE (32) + +typedef struct _qstr_window_t { + uint16_t idx; // indexes the head of the window + uint16_t window[QSTR_WINDOW_SIZE]; +} qstr_window_t; + +// Push a qstr to the head of the window, and the tail qstr is overwritten +STATIC void qstr_window_push(qstr_window_t *qw, qstr qst) { + qw->idx = (qw->idx + 1) % QSTR_WINDOW_SIZE; + qw->window[qw->idx] = qst; +} + +// Pull an existing qstr from within the window to the head of the window +STATIC qstr qstr_window_pull(qstr_window_t *qw, size_t idx) { + qstr qst = qw->window[idx]; + if (idx > qw->idx) { + memmove(&qw->window[idx], &qw->window[idx + 1], (QSTR_WINDOW_SIZE - idx - 1) * sizeof(uint16_t)); + qw->window[QSTR_WINDOW_SIZE - 1] = qw->window[0]; + idx = 0; + } + memmove(&qw->window[idx], &qw->window[idx + 1], (qw->idx - idx) * sizeof(uint16_t)); + qw->window[qw->idx] = qst; + return qst; +} + +#if MICROPY_PERSISTENT_CODE_LOAD + +// Access a qstr at the given index, relative to the head of the window (0=head) +STATIC qstr qstr_window_access(qstr_window_t *qw, size_t idx) { + return qstr_window_pull(qw, (qw->idx + QSTR_WINDOW_SIZE - idx) % QSTR_WINDOW_SIZE); +} + +#endif + +#if MICROPY_PERSISTENT_CODE_SAVE + +// Insert a qstr at the head of the window, either by pulling an existing one or pushing a new one +STATIC size_t qstr_window_insert(qstr_window_t *qw, qstr qst) { + for (size_t idx = 0; idx < QSTR_WINDOW_SIZE; ++idx) { + if (qw->window[idx] == qst) { + qstr_window_pull(qw, idx); + return (qw->idx + QSTR_WINDOW_SIZE - idx) % QSTR_WINDOW_SIZE; + } + } + qstr_window_push(qw, qst); + return QSTR_WINDOW_SIZE; +} + +#endif + typedef struct _bytecode_prelude_t { uint n_state; uint n_exc_stack; @@ -122,12 +177,18 @@ STATIC size_t read_uint(mp_reader_t *reader) { return unum; } -STATIC qstr load_qstr(mp_reader_t *reader) { +STATIC qstr load_qstr(mp_reader_t *reader, qstr_window_t *qw) { size_t len = read_uint(reader); + if (len & 1) { + // qstr in window + return qstr_window_access(qw, len >> 1); + } + len >>= 1; char *str = m_new(char, len); read_bytes(reader, (byte*)str, len); qstr qst = qstr_from_strn(str, len); m_del(char, str, len); + qstr_window_push(qw, qst); return qst; } @@ -151,12 +212,12 @@ STATIC mp_obj_t load_obj(mp_reader_t *reader) { } } -STATIC void load_bytecode_qstrs(mp_reader_t *reader, byte *ip, byte *ip_top) { +STATIC void load_bytecode_qstrs(mp_reader_t *reader, qstr_window_t *qw, byte *ip, byte *ip_top) { while (ip < ip_top) { size_t sz; uint f = mp_opcode_format(ip, &sz); if (f == MP_OPCODE_QSTR) { - qstr qst = load_qstr(reader); + qstr qst = load_qstr(reader, qw); ip[1] = qst; ip[2] = qst >> 8; } @@ -164,7 +225,7 @@ STATIC void load_bytecode_qstrs(mp_reader_t *reader, byte *ip, byte *ip_top) { } } -STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader) { +STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { // load bytecode size_t bc_len = read_uint(reader); byte *bytecode = m_new(byte, bc_len); @@ -177,11 +238,11 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader) { extract_prelude(&ip, &ip2, &prelude); // load qstrs and link global qstr ids into bytecode - qstr simple_name = load_qstr(reader); - qstr source_file = load_qstr(reader); + qstr simple_name = load_qstr(reader, qw); + qstr source_file = load_qstr(reader, qw); ((byte*)ip2)[0] = simple_name; ((byte*)ip2)[1] = simple_name >> 8; ((byte*)ip2)[2] = source_file; ((byte*)ip2)[3] = source_file >> 8; - load_bytecode_qstrs(reader, (byte*)ip, bytecode + bc_len); + load_bytecode_qstrs(reader, qw, (byte*)ip, bytecode + bc_len); // load constant table size_t n_obj = read_uint(reader); @@ -189,13 +250,13 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader) { mp_uint_t *const_table = m_new(mp_uint_t, prelude.n_pos_args + prelude.n_kwonly_args + n_obj + n_raw_code); mp_uint_t *ct = const_table; for (size_t i = 0; i < prelude.n_pos_args + prelude.n_kwonly_args; ++i) { - *ct++ = (mp_uint_t)MP_OBJ_NEW_QSTR(load_qstr(reader)); + *ct++ = (mp_uint_t)MP_OBJ_NEW_QSTR(load_qstr(reader, qw)); } for (size_t i = 0; i < n_obj; ++i) { *ct++ = (mp_uint_t)load_obj(reader); } for (size_t i = 0; i < n_raw_code; ++i) { - *ct++ = (mp_uint_t)(uintptr_t)load_raw_code(reader); + *ct++ = (mp_uint_t)(uintptr_t)load_raw_code(reader, qw); } // create raw_code and return it @@ -217,11 +278,14 @@ mp_raw_code_t *mp_raw_code_load(mp_reader_t *reader) { read_bytes(reader, header, sizeof(header)); if (header[0] != 'M' || header[1] != MPY_VERSION - || header[2] != MPY_FEATURE_FLAGS - || header[3] > mp_small_int_bits()) { + || MPY_FEATURE_DECODE_FLAGS(header[2]) != MPY_FEATURE_FLAGS + || header[3] > mp_small_int_bits() + || read_uint(reader, NULL) > QSTR_WINDOW_SIZE) { mp_raise_ValueError("incompatible .mpy file"); } - mp_raw_code_t *rc = load_raw_code(reader); + qstr_window_t qw; + qw.idx = 0; + mp_raw_code_t *rc = load_raw_code(reader, &qw); reader->close(reader->data); return rc; } @@ -264,10 +328,16 @@ STATIC void mp_print_uint(mp_print_t *print, size_t n) { print->print_strn(print->data, (char*)p, buf + sizeof(buf) - p); } -STATIC void save_qstr(mp_print_t *print, qstr qst) { +STATIC void save_qstr(mp_print_t *print, qstr_window_t *qw, qstr qst) { + size_t idx = qstr_window_insert(qw, qst); + if (idx < QSTR_WINDOW_SIZE) { + // qstr found in window, encode index to it + mp_print_uint(print, idx << 1 | 1); + return; + } size_t len; const byte *str = qstr_data(qst, &len); - mp_print_uint(print, len); + mp_print_uint(print, len << 1); mp_print_bytes(print, str, len); } @@ -312,19 +382,19 @@ STATIC void save_obj(mp_print_t *print, mp_obj_t o) { } } -STATIC void save_bytecode_qstrs(mp_print_t *print, const byte *ip, const byte *ip_top) { +STATIC void save_bytecode_qstrs(mp_print_t *print, qstr_window_t *qw, const byte *ip, const byte *ip_top) { while (ip < ip_top) { size_t sz; uint f = mp_opcode_format(ip, &sz); if (f == MP_OPCODE_QSTR) { qstr qst = ip[1] | (ip[2] << 8); - save_qstr(print, qst); + save_qstr(print, qw, qst); } ip += sz; } } -STATIC void save_raw_code(mp_print_t *print, mp_raw_code_t *rc) { +STATIC void save_raw_code(mp_print_t *print, mp_raw_code_t *rc, qstr_window_t *qstr_window) { if (rc->kind != MP_CODE_BYTECODE) { mp_raise_ValueError("can only save bytecode"); } @@ -340,9 +410,9 @@ STATIC void save_raw_code(mp_print_t *print, mp_raw_code_t *rc) { extract_prelude(&ip, &ip2, &prelude); // save qstrs - save_qstr(print, ip2[0] | (ip2[1] << 8)); // simple_name - save_qstr(print, ip2[2] | (ip2[3] << 8)); // source_file - save_bytecode_qstrs(print, ip, rc->data.u_byte.bytecode + rc->data.u_byte.bc_len); + save_qstr(print, qstr_window, ip2[0] | (ip2[1] << 8)); // simple_name + save_qstr(print, qstr_window, ip2[2] | (ip2[3] << 8)); // source_file + save_bytecode_qstrs(print, qstr_window, ip, rc->data.u_byte.bytecode + rc->data.u_byte.bc_len); // save constant table mp_print_uint(print, rc->data.u_byte.n_obj); @@ -350,13 +420,13 @@ STATIC void save_raw_code(mp_print_t *print, mp_raw_code_t *rc) { const mp_uint_t *const_table = rc->data.u_byte.const_table; for (uint i = 0; i < prelude.n_pos_args + prelude.n_kwonly_args; ++i) { mp_obj_t o = (mp_obj_t)*const_table++; - save_qstr(print, MP_OBJ_QSTR_VALUE(o)); + save_qstr(print, qstr_window, MP_OBJ_QSTR_VALUE(o)); } for (uint i = 0; i < rc->data.u_byte.n_obj; ++i) { save_obj(print, (mp_obj_t)*const_table++); } for (uint i = 0; i < rc->data.u_byte.n_raw_code; ++i) { - save_raw_code(print, (mp_raw_code_t*)(uintptr_t)*const_table++); + save_raw_code(print, (mp_raw_code_t*)(uintptr_t)*const_table++, qstr_window); } } @@ -366,7 +436,11 @@ void mp_raw_code_save(mp_raw_code_t *rc, mp_print_t *print) { // byte version // byte feature flags // byte number of bits in a small int - byte header[4] = {'M', MPY_VERSION, MPY_FEATURE_FLAGS_DYNAMIC, + // uint size of qstr window + byte header[4] = { + 'M', + MPY_VERSION, + MPY_FEATURE_ENCODE_FLAGS(MPY_FEATURE_FLAGS_DYNAMIC), #if MICROPY_DYNAMIC_COMPILER mp_dynamic_compiler.small_int_bits, #else @@ -374,8 +448,12 @@ void mp_raw_code_save(mp_raw_code_t *rc, mp_print_t *print) { #endif }; mp_print_bytes(print, header, sizeof(header)); + mp_print_uint(print, QSTR_WINDOW_SIZE); - save_raw_code(print, rc); + qstr_window_t qw; + qw.idx = 0; + memset(qw.window, 0, sizeof(qw.window)); + save_raw_code(print, rc, &qw); } // here we define mp_raw_code_save_file depending on the port diff --git a/tests/import/mpy_invalid.py b/tests/import/mpy_invalid.py index 6a4e116e78..6e9cbc9db9 100644 --- a/tests/import/mpy_invalid.py +++ b/tests/import/mpy_invalid.py @@ -48,6 +48,7 @@ user_files = { '/mod0.mpy': b'', # empty file '/mod1.mpy': b'M', # too short header '/mod2.mpy': b'M\x00\x00\x00', # bad version + '/mod3.mpy': b'M\x00\x00\x00\x7f', # qstr window too large } # create and mount a user filesystem diff --git a/tests/import/mpy_invalid.py.exp b/tests/import/mpy_invalid.py.exp index 1727ea1cea..ea748ff6c1 100644 --- a/tests/import/mpy_invalid.py.exp +++ b/tests/import/mpy_invalid.py.exp @@ -1,3 +1,4 @@ mod0 ValueError incompatible .mpy file mod1 ValueError incompatible .mpy file mod2 ValueError incompatible .mpy file +mod3 ValueError incompatible .mpy file diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index 62f2ac4815..8e7c84f6fe 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -63,6 +63,19 @@ class Config: MICROPY_LONGINT_IMPL_MPZ = 2 config = Config() +class QStrWindow: + def __init__(self, size_log2): + self.window = [] + self.size = 1 << size_log2 + + def push(self, val): + self.window = [val] + self.window[:self.size - 1] + + def access(self, idx): + val = self.window[idx] + self.window = [val] + self.window[:idx] + self.window[idx + 1:] + return val + MP_OPCODE_BYTE = 0 MP_OPCODE_QSTR = 1 MP_OPCODE_VAR_UINT = 2 @@ -391,11 +404,16 @@ def read_uint(f): global_qstrs = [] qstr_type = namedtuple('qstr', ('str', 'qstr_esc', 'qstr_id')) -def read_qstr(f): +def read_qstr(f, qstr_win): ln = read_uint(f) + if ln & 1: + # qstr in table + return qstr_win.access(ln >> 1) + ln >>= 1 data = str_cons(f.read(ln), 'utf8') qstr_esc = qstrutil.qstr_escape(data) global_qstrs.append(qstr_type(data, qstr_esc, 'MP_QSTR_' + qstr_esc)) + qstr_win.push(len(global_qstrs) - 1) return len(global_qstrs) - 1 def read_obj(f): @@ -417,30 +435,30 @@ def read_obj(f): else: assert 0 -def read_qstr_and_pack(f, bytecode, ip): - qst = read_qstr(f) +def read_qstr_and_pack(f, bytecode, ip, qstr_win): + qst = read_qstr(f, qstr_win) bytecode[ip] = qst & 0xff bytecode[ip + 1] = qst >> 8 -def read_bytecode_qstrs(file, bytecode, ip): +def read_bytecode_qstrs(file, bytecode, ip, qstr_win): while ip < len(bytecode): f, sz = mp_opcode_format(bytecode, ip) if f == 1: - read_qstr_and_pack(file, bytecode, ip + 1) + read_qstr_and_pack(file, bytecode, ip + 1, qstr_win) ip += sz -def read_raw_code(f): +def read_raw_code(f, qstr_win): bc_len = read_uint(f) bytecode = bytearray(f.read(bc_len)) ip, ip2, prelude = extract_prelude(bytecode) - read_qstr_and_pack(f, bytecode, ip2) # simple_name - read_qstr_and_pack(f, bytecode, ip2 + 2) # source_file - read_bytecode_qstrs(f, bytecode, ip) + read_qstr_and_pack(f, bytecode, ip2, qstr_win) # simple_name + read_qstr_and_pack(f, bytecode, ip2 + 2, qstr_win) # source_file + read_bytecode_qstrs(f, bytecode, ip, qstr_win) n_obj = read_uint(f) n_raw_code = read_uint(f) - qstrs = [read_qstr(f) for _ in range(prelude[3] + prelude[4])] + qstrs = [read_qstr(f, qstr_win) for _ in range(prelude[3] + prelude[4])] objs = [read_obj(f) for _ in range(n_obj)] - raw_codes = [read_raw_code(f) for _ in range(n_raw_code)] + raw_codes = [read_raw_code(f, qstr_win) for _ in range(n_raw_code)] return RawCode(bytecode, qstrs, objs, raw_codes) def read_mpy(filename): @@ -450,11 +468,13 @@ def read_mpy(filename): raise Exception('not a valid .mpy file') if header[1] != config.MPY_VERSION: raise Exception('incompatible .mpy version') - feature_flags = header[2] - config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE = (feature_flags & 1) != 0 - config.MICROPY_PY_BUILTINS_STR_UNICODE = (feature_flags & 2) != 0 + feature_byte = header[2] + qw_size = read_uint(f) + config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE = (feature_byte & 1) != 0 + config.MICROPY_PY_BUILTINS_STR_UNICODE = (feature_byte & 2) != 0 config.mp_small_int_bits = header[3] - return read_raw_code(f) + qstr_win = QStrWindow(qw_size) + return read_raw_code(f, qstr_win) def dump_mpy(raw_codes): for rc in raw_codes: From 992a6e1deab06aba07ab09687402d39a0c028a73 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 1 Mar 2019 14:03:10 +1100 Subject: [PATCH 0166/1788] py/persistentcode: Pack qstrs directly in bytecode to reduce mpy size. Instead of emitting two bytes in the bytecode for where the linked qstr should be written to, it is now replaced by the actual qstr data, or a reference into the qstr window. Reduces mpy file size by about 10%. --- py/bc.c | 6 ++- py/bc.h | 2 +- py/persistentcode.c | 89 +++++++++++++++++++++++++++++++++------------ tools/mpy-tool.py | 87 +++++++++++++++++++++++++++++++++----------- 4 files changed, 135 insertions(+), 49 deletions(-) diff --git a/py/bc.c b/py/bc.c index 4a29f439e3..b178e7c202 100644 --- a/py/bc.c +++ b/py/bc.c @@ -382,7 +382,7 @@ STATIC const byte opcode_format_table[64] = { #undef V #undef O -uint mp_opcode_format(const byte *ip, size_t *opcode_size) { +uint mp_opcode_format(const byte *ip, size_t *opcode_size, bool count_var_uint) { uint f = (opcode_format_table[*ip >> 2] >> (2 * (*ip & 3))) & 3; const byte *ip_start = ip; if (f == MP_OPCODE_QSTR) { @@ -403,7 +403,9 @@ uint mp_opcode_format(const byte *ip, size_t *opcode_size) { ); ip += 1; if (f == MP_OPCODE_VAR_UINT) { - while ((*ip++ & 0x80) != 0) { + if (count_var_uint) { + while ((*ip++ & 0x80) != 0) { + } } } else if (f == MP_OPCODE_OFFSET) { ip += 2; diff --git a/py/bc.h b/py/bc.h index ebfdeaac1d..6d86fbdea9 100644 --- a/py/bc.h +++ b/py/bc.h @@ -114,7 +114,7 @@ const byte *mp_bytecode_print_str(const byte *ip); #define MP_OPCODE_VAR_UINT (2) #define MP_OPCODE_OFFSET (3) -uint mp_opcode_format(const byte *ip, size_t *opcode_size); +uint mp_opcode_format(const byte *ip, size_t *opcode_size, bool count_var_uint); #endif diff --git a/py/persistentcode.c b/py/persistentcode.c index 9cea08a2d7..d47425db92 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -133,6 +133,8 @@ typedef struct _bytecode_prelude_t { uint code_info_size; } bytecode_prelude_t; +#if MICROPY_PERSISTENT_CODE_SAVE + // ip will point to start of opcodes // ip2 will point to simple_name, source_file qstrs STATIC void extract_prelude(const byte **ip, const byte **ip2, bytecode_prelude_t *prelude) { @@ -149,6 +151,8 @@ STATIC void extract_prelude(const byte **ip, const byte **ip2, bytecode_prelude_ } } +#endif + #endif // MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE #if MICROPY_PERSISTENT_CODE_LOAD @@ -165,10 +169,14 @@ STATIC void read_bytes(mp_reader_t *reader, byte *buf, size_t len) { } } -STATIC size_t read_uint(mp_reader_t *reader) { +STATIC size_t read_uint(mp_reader_t *reader, byte **out) { size_t unum = 0; for (;;) { byte b = reader->readbyte(reader->data); + if (out != NULL) { + **out = b; + ++*out; + } unum = (unum << 7) | (b & 0x7f); if ((b & 0x80) == 0) { break; @@ -178,7 +186,7 @@ STATIC size_t read_uint(mp_reader_t *reader) { } STATIC qstr load_qstr(mp_reader_t *reader, qstr_window_t *qw) { - size_t len = read_uint(reader); + size_t len = read_uint(reader, NULL); if (len & 1) { // qstr in window return qstr_window_access(qw, len >> 1); @@ -197,7 +205,7 @@ STATIC mp_obj_t load_obj(mp_reader_t *reader) { if (obj_type == 'e') { return MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj); } else { - size_t len = read_uint(reader); + size_t len = read_uint(reader, NULL); vstr_t vstr; vstr_init_len(&vstr, len); read_bytes(reader, (byte*)vstr.buf, len); @@ -212,41 +220,66 @@ STATIC mp_obj_t load_obj(mp_reader_t *reader) { } } -STATIC void load_bytecode_qstrs(mp_reader_t *reader, qstr_window_t *qw, byte *ip, byte *ip_top) { +STATIC void load_prelude(mp_reader_t *reader, byte **ip, byte **ip2, bytecode_prelude_t *prelude) { + prelude->n_state = read_uint(reader, ip); + prelude->n_exc_stack = read_uint(reader, ip); + read_bytes(reader, *ip, 4); + prelude->scope_flags = *(*ip)++; + prelude->n_pos_args = *(*ip)++; + prelude->n_kwonly_args = *(*ip)++; + prelude->n_def_pos_args = *(*ip)++; + *ip2 = *ip; + prelude->code_info_size = read_uint(reader, ip2); + read_bytes(reader, *ip2, prelude->code_info_size - (*ip2 - *ip)); + *ip += prelude->code_info_size; + while ((*(*ip)++ = read_byte(reader)) != 255) { + } +} + +STATIC void load_bytecode(mp_reader_t *reader, qstr_window_t *qw, byte *ip, byte *ip_top) { while (ip < ip_top) { + *ip = read_byte(reader); size_t sz; - uint f = mp_opcode_format(ip, &sz); + uint f = mp_opcode_format(ip, &sz, false); + ++ip; + --sz; if (f == MP_OPCODE_QSTR) { qstr qst = load_qstr(reader, qw); - ip[1] = qst; - ip[2] = qst >> 8; + *ip++ = qst; + *ip++ = qst >> 8; + sz -= 2; + } else if (f == MP_OPCODE_VAR_UINT) { + while ((*ip++ = read_byte(reader)) & 0x80) { + } } + read_bytes(reader, ip, sz); ip += sz; } } STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { - // load bytecode - size_t bc_len = read_uint(reader); + // get bytecode size and allocate memory for it + size_t bc_len = read_uint(reader, NULL); byte *bytecode = m_new(byte, bc_len); - read_bytes(reader, bytecode, bc_len); - // extract prelude - const byte *ip = bytecode; - const byte *ip2; + // load prelude + byte *ip = bytecode; + byte *ip2; bytecode_prelude_t prelude; - extract_prelude(&ip, &ip2, &prelude); + load_prelude(reader, &ip, &ip2, &prelude); + + // load bytecode + load_bytecode(reader, qw, ip, bytecode + bc_len); // load qstrs and link global qstr ids into bytecode qstr simple_name = load_qstr(reader, qw); qstr source_file = load_qstr(reader, qw); ((byte*)ip2)[0] = simple_name; ((byte*)ip2)[1] = simple_name >> 8; ((byte*)ip2)[2] = source_file; ((byte*)ip2)[3] = source_file >> 8; - load_bytecode_qstrs(reader, qw, (byte*)ip, bytecode + bc_len); // load constant table - size_t n_obj = read_uint(reader); - size_t n_raw_code = read_uint(reader); + size_t n_obj = read_uint(reader, NULL); + size_t n_raw_code = read_uint(reader, NULL); mp_uint_t *const_table = m_new(mp_uint_t, prelude.n_pos_args + prelude.n_kwonly_args + n_obj + n_raw_code); mp_uint_t *ct = const_table; for (size_t i = 0; i < prelude.n_pos_args + prelude.n_kwonly_args; ++i) { @@ -382,14 +415,18 @@ STATIC void save_obj(mp_print_t *print, mp_obj_t o) { } } -STATIC void save_bytecode_qstrs(mp_print_t *print, qstr_window_t *qw, const byte *ip, const byte *ip_top) { +STATIC void save_bytecode(mp_print_t *print, qstr_window_t *qw, const byte *ip, const byte *ip_top) { while (ip < ip_top) { size_t sz; - uint f = mp_opcode_format(ip, &sz); + uint f = mp_opcode_format(ip, &sz, true); if (f == MP_OPCODE_QSTR) { + mp_print_bytes(print, ip, 1); qstr qst = ip[1] | (ip[2] << 8); save_qstr(print, qw, qst); + ip += 3; + sz -= 3; } + mp_print_bytes(print, ip, sz); ip += sz; } } @@ -399,20 +436,24 @@ STATIC void save_raw_code(mp_print_t *print, mp_raw_code_t *rc, qstr_window_t *q mp_raise_ValueError("can only save bytecode"); } - // save bytecode - mp_print_uint(print, rc->data.u_byte.bc_len); - mp_print_bytes(print, rc->data.u_byte.bytecode, rc->data.u_byte.bc_len); - // extract prelude const byte *ip = rc->data.u_byte.bytecode; const byte *ip2; bytecode_prelude_t prelude; extract_prelude(&ip, &ip2, &prelude); + // save prelude + size_t prelude_len = ip - rc->data.u_byte.bytecode; + const byte *ip_top = rc->data.u_byte.bytecode + rc->data.u_byte.bc_len; + mp_print_uint(print, rc->data.u_byte.bc_len); + mp_print_bytes(print, rc->data.u_byte.bytecode, prelude_len); + + // save bytecode + save_bytecode(print, qstr_window, ip, ip_top); + // save qstrs save_qstr(print, qstr_window, ip2[0] | (ip2[1] << 8)); // simple_name save_qstr(print, qstr_window, ip2[2] | (ip2[3] << 8)); // source_file - save_bytecode_qstrs(print, qstr_window, ip, rc->data.u_byte.bytecode + rc->data.u_byte.bc_len); // save constant table mp_print_uint(print, rc->data.u_byte.n_obj); diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index 8e7c84f6fe..4d14f5256a 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -174,7 +174,7 @@ def make_opcode_format(): )) # this function mirrors that in py/bc.c -def mp_opcode_format(bytecode, ip, opcode_format=make_opcode_format()): +def mp_opcode_format(bytecode, ip, count_var_uint, opcode_format=make_opcode_format()): opcode = bytecode[ip] ip_start = ip f = (opcode_format[opcode >> 2] >> (2 * (opcode & 3))) & 3 @@ -194,9 +194,10 @@ def mp_opcode_format(bytecode, ip, opcode_format=make_opcode_format()): ) ip += 1 if f == MP_OPCODE_VAR_UINT: - while bytecode[ip] & 0x80 != 0: + if count_var_uint: + while bytecode[ip] & 0x80 != 0: + ip += 1 ip += 1 - ip += 1 elif f == MP_OPCODE_OFFSET: ip += 2 ip += extra_byte @@ -288,7 +289,7 @@ class RawCode: print() ip = self.ip while ip < len(self.bytecode): - f, sz = mp_opcode_format(self.bytecode, ip) + f, sz = mp_opcode_format(self.bytecode, ip, True) if f == 1: qst = self._unpack_qstr(ip + 1).qstr_id extra = '' if sz == 3 else ' 0x%02x,' % self.bytecode[ip + 3] @@ -393,10 +394,28 @@ class RawCode: print(' },') print('};') -def read_uint(f): +class BytecodeBuffer: + def __init__(self, size): + self.buf = bytearray(size) + self.idx = 0 + + def is_full(self): + return self.idx == len(self.buf) + + def append(self, b): + self.buf[self.idx] = b + self.idx += 1 + +def read_byte(f, out=None): + b = bytes_cons(f.read(1))[0] + if out is not None: + out.append(b) + return b + +def read_uint(f, out=None): i = 0 while True: - b = bytes_cons(f.read(1))[0] + b = read_byte(f, out) i = (i << 7) | (b & 0x7f) if b & 0x80 == 0: break @@ -435,31 +454,55 @@ def read_obj(f): else: assert 0 -def read_qstr_and_pack(f, bytecode, ip, qstr_win): - qst = read_qstr(f, qstr_win) - bytecode[ip] = qst & 0xff - bytecode[ip + 1] = qst >> 8 +def read_prelude(f, bytecode): + n_state = read_uint(f, bytecode) + n_exc_stack = read_uint(f, bytecode) + scope_flags = read_byte(f, bytecode) + n_pos_args = read_byte(f, bytecode) + n_kwonly_args = read_byte(f, bytecode) + n_def_pos_args = read_byte(f, bytecode) + l1 = bytecode.idx + code_info_size = read_uint(f, bytecode) + l2 = bytecode.idx + for _ in range(code_info_size - (l2 - l1)): + read_byte(f, bytecode) + while read_byte(f, bytecode) != 255: + pass + return l2, (n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args, code_info_size) -def read_bytecode_qstrs(file, bytecode, ip, qstr_win): - while ip < len(bytecode): - f, sz = mp_opcode_format(bytecode, ip) - if f == 1: - read_qstr_and_pack(file, bytecode, ip + 1, qstr_win) - ip += sz +def read_qstr_and_pack(f, bytecode, qstr_win): + qst = read_qstr(f, qstr_win) + bytecode.append(qst & 0xff) + bytecode.append(qst >> 8) + +def read_bytecode(file, bytecode, qstr_win): + while not bytecode.is_full(): + op = read_byte(file, bytecode) + f, sz = mp_opcode_format(bytecode.buf, bytecode.idx - 1, False) + sz -= 1 + if f == MP_OPCODE_QSTR: + read_qstr_and_pack(file, bytecode, qstr_win) + sz -= 2 + elif f == MP_OPCODE_VAR_UINT: + while read_byte(file, bytecode) & 0x80: + pass + for _ in range(sz): + read_byte(file, bytecode) def read_raw_code(f, qstr_win): bc_len = read_uint(f) - bytecode = bytearray(f.read(bc_len)) - ip, ip2, prelude = extract_prelude(bytecode) - read_qstr_and_pack(f, bytecode, ip2, qstr_win) # simple_name - read_qstr_and_pack(f, bytecode, ip2 + 2, qstr_win) # source_file - read_bytecode_qstrs(f, bytecode, ip, qstr_win) + bytecode = BytecodeBuffer(bc_len) + name_idx, prelude = read_prelude(f, bytecode) + read_bytecode(f, bytecode, qstr_win) + bytecode.idx = name_idx # rewind to where qstrs are in prelude + read_qstr_and_pack(f, bytecode, qstr_win) # simple_name + read_qstr_and_pack(f, bytecode, qstr_win) # source_file n_obj = read_uint(f) n_raw_code = read_uint(f) qstrs = [read_qstr(f, qstr_win) for _ in range(prelude[3] + prelude[4])] objs = [read_obj(f) for _ in range(n_obj)] raw_codes = [read_raw_code(f, qstr_win) for _ in range(n_raw_code)] - return RawCode(bytecode, qstrs, objs, raw_codes) + return RawCode(bytecode.buf, qstrs, objs, raw_codes) def read_mpy(filename): with open(filename, 'rb') as f: From 4f0931b21f72be86aae22f05b718aa36792afc9b Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 1 Mar 2019 14:33:03 +1100 Subject: [PATCH 0167/1788] py/persistentcode: Define static qstr set to reduce size of mpy files. When encoded in the mpy file, if qstr <= QSTR_LAST_STATIC then store two bytes: 0, static_qstr_id. Otherwise encode the qstr as usual (either with string data or a reference into the qstr window). Reduces mpy file size by about 5%. --- py/makeqstrdata.py | 185 +++++++++++++++++++++++++++++++++++++++++++- py/persistentcode.c | 12 +++ tools/mpy-tool.py | 22 ++++-- 3 files changed, 213 insertions(+), 6 deletions(-) diff --git a/py/makeqstrdata.py b/py/makeqstrdata.py index 3c0a609092..060ebb7fd7 100644 --- a/py/makeqstrdata.py +++ b/py/makeqstrdata.py @@ -51,6 +51,176 @@ codepoint2name[ord('^')] = 'caret' codepoint2name[ord('|')] = 'pipe' codepoint2name[ord('~')] = 'tilde' +# static qstrs, should be sorted + +static_qstr_list = [ + "", + "__dir__", # Put __dir__ after empty qstr for builtin dir() to work + "\n", + " ", + "*", + "/", + "", + "_", + "__call__", + "__class__", + "__delitem__", + "__enter__", + "__exit__", + "__getattr__", + "__getitem__", + "__hash__", + "__init__", + "__int__", + "__iter__", + "__len__", + "__main__", + "__module__", + "__name__", + "__new__", + "__next__", + "__qualname__", + "__repr__", + "__setitem__", + "__str__", + "ArithmeticError", + "AssertionError", + "AttributeError", + "BaseException", + "EOFError", + "Ellipsis", + "Exception", + "GeneratorExit", + "ImportError", + "IndentationError", + "IndexError", + "KeyError", + "KeyboardInterrupt", + "LookupError", + "MemoryError", + "NameError", + "NoneType", + "NotImplementedError", + "OSError", + "OverflowError", + "RuntimeError", + "StopIteration", + "SyntaxError", + "SystemExit", + "TypeError", + "ValueError", + "ZeroDivisionError", + "abs", + "all", + "any", + "append", + "args", + "bool", + "builtins", + "bytearray", + "bytecode", + "bytes", + "callable", + "chr", + "classmethod", + "clear", + "close", + "const", + "copy", + "count", + "dict", + "dir", + "divmod", + "end", + "endswith", + "eval", + "exec", + "extend", + "find", + "format", + "from_bytes", + "get", + "getattr", + "globals", + "hasattr", + "hash", + "id", + "index", + "insert", + "int", + "isalpha", + "isdigit", + "isinstance", + "islower", + "isspace", + "issubclass", + "isupper", + "items", + "iter", + "join", + "key", + "keys", + "len", + "list", + "little", + "locals", + "lower", + "lstrip", + "main", + "map", + "micropython", + "next", + "object", + "open", + "ord", + "pop", + "popitem", + "pow", + "print", + "range", + "read", + "readinto", + "readline", + "remove", + "replace", + "repr", + "reverse", + "rfind", + "rindex", + "round", + "rsplit", + "rstrip", + "self", + "send", + "sep", + "set", + "setattr", + "setdefault", + "sort", + "sorted", + "split", + "start", + "startswith", + "staticmethod", + "step", + "stop", + "str", + "strip", + "sum", + "super", + "throw", + "to_bytes", + "tuple", + "type", + "update", + "upper", + "utf-8", + "value", + "values", + "write", + "zip", +] + # this must match the equivalent function in qstr.c def compute_hash(qstr, bytes_hash): hash = 5381 @@ -70,9 +240,22 @@ def qstr_escape(qst): return re.sub(r'[^A-Za-z0-9_]', esc_char, qst) def parse_input_headers(infiles): - # read the qstrs in from the input files qcfgs = {} qstrs = {} + + # add static qstrs + for qstr in static_qstr_list: + # work out the corresponding qstr name + ident = qstr_escape(qstr) + + # don't add duplicates + assert ident not in qstrs + + # add the qstr to the list, with order number to retain original order in file + order = len(qstrs) - 300000 + qstrs[ident] = (order, ident, qstr) + + # read the qstrs in from the input files for infile in infiles: with open(infile, 'rt') as f: for line in f: diff --git a/py/persistentcode.c b/py/persistentcode.c index d47425db92..c0a3281113 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -38,6 +38,8 @@ #include "py/smallint.h" +#define QSTR_LAST_STATIC MP_QSTR_zip + // The current version of .mpy files #define MPY_VERSION (3) @@ -187,6 +189,10 @@ STATIC size_t read_uint(mp_reader_t *reader, byte **out) { STATIC qstr load_qstr(mp_reader_t *reader, qstr_window_t *qw) { size_t len = read_uint(reader, NULL); + if (len == 0) { + // static qstr + return read_byte(reader); + } if (len & 1) { // qstr in window return qstr_window_access(qw, len >> 1); @@ -362,6 +368,12 @@ STATIC void mp_print_uint(mp_print_t *print, size_t n) { } STATIC void save_qstr(mp_print_t *print, qstr_window_t *qw, qstr qst) { + if (qst <= QSTR_LAST_STATIC) { + // encode static qstr + byte buf[2] = {0, qst & 0xff}; + mp_print_bytes(print, buf, 2); + return; + } size_t idx = qstr_window_insert(qw, qst); if (idx < QSTR_WINDOW_SIZE) { // qstr found in window, encode index to it diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index 4d14f5256a..8a82374031 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -63,6 +63,17 @@ class Config: MICROPY_LONGINT_IMPL_MPZ = 2 config = Config() +class QStrType: + def __init__(self, str): + self.str = str + self.qstr_esc = qstrutil.qstr_escape(self.str) + self.qstr_id = 'MP_QSTR_' + self.qstr_esc + +# Initialise global list of qstrs with static qstrs +global_qstrs = [None] # MP_QSTR_NULL should never be referenced +for n in qstrutil.static_qstr_list: + global_qstrs.append(QStrType(n)) + class QStrWindow: def __init__(self, size_log2): self.window = [] @@ -421,17 +432,17 @@ def read_uint(f, out=None): break return i -global_qstrs = [] -qstr_type = namedtuple('qstr', ('str', 'qstr_esc', 'qstr_id')) def read_qstr(f, qstr_win): ln = read_uint(f) + if ln == 0: + # static qstr + return bytes_cons(f.read(1))[0] if ln & 1: # qstr in table return qstr_win.access(ln >> 1) ln >>= 1 data = str_cons(f.read(ln), 'utf8') - qstr_esc = qstrutil.qstr_escape(data) - global_qstrs.append(qstr_type(data, qstr_esc, 'MP_QSTR_' + qstr_esc)) + global_qstrs.append(QStrType(data)) qstr_win.push(len(global_qstrs) - 1) return len(global_qstrs) - 1 @@ -476,6 +487,7 @@ def read_qstr_and_pack(f, bytecode, qstr_win): bytecode.append(qst >> 8) def read_bytecode(file, bytecode, qstr_win): + QSTR_LAST_STATIC = len(qstrutil.static_qstr_list) while not bytecode.is_full(): op = read_byte(file, bytecode) f, sz = mp_opcode_format(bytecode.buf, bytecode.idx - 1, False) @@ -528,7 +540,7 @@ def freeze_mpy(base_qstrs, raw_codes): new = {} for q in global_qstrs: # don't add duplicates - if q.qstr_esc in base_qstrs or q.qstr_esc in new: + if q is None or q.qstr_esc in base_qstrs or q.qstr_esc in new: continue new[q.qstr_esc] = (len(new), q.qstr_esc, q.str) new = sorted(new.values(), key=lambda x: x[0]) From 62483bb957f5882e550e059d577718f347f0cba4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 1 Mar 2019 22:21:25 +1100 Subject: [PATCH 0168/1788] minimal/frozentest: Recompile now that mpy format changed. --- ports/minimal/frozentest.mpy | Bin 255 -> 206 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/ports/minimal/frozentest.mpy b/ports/minimal/frozentest.mpy index 7c6809bf6522f90339ec72ae0dcd16560ac5aafc..3b5e0fee15024a08a20a63ab3a6f15a868066190 100644 GIT binary patch delta 135 zcmey*c#g5&mzhakA%>X&1bEpQSQxc5G&Hm|7#RLbGgOPQl?GI%Fd6}w;tWul5lS;b zXpvp-XNdxt4W|4J1}aRMK&8?kC5=xFTCSVDt~U~lW?+{}E6T4*%_~VQF3~HfWM(K< QN>s?n&r4S*p18pu0H<0aE&u=k delta 173 zcmX@d_@A-fmzhaEhM55bc)1upGH7XNXlQFNF#MN3$RPHKA%)Qh$PkCoj8HxkgcjNL zewHYZ* Date: Thu, 7 Mar 2019 15:03:09 +1100 Subject: [PATCH 0169/1788] lib/oofatfs: Update oofatfs library to fix issue with logic not. From https://github.com/micropython/oofatfs, branch work-R0.13c, commit 3b4ee5a646af2769b3dddfe17d5d866233c1e45b. --- lib/oofatfs/ff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/oofatfs/ff.c b/lib/oofatfs/ff.c index c7c79a1dd6..0c9d04fe74 100644 --- a/lib/oofatfs/ff.c +++ b/lib/oofatfs/ff.c @@ -3356,7 +3356,7 @@ static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ res = FR_TIMEOUT; } #else - if (disk_ioctl(obj->fs->drv, IOCTL_STATUS, &stat) == RES_OK && (!stat & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ + if (disk_ioctl(obj->fs->drv, IOCTL_STATUS, &stat) == RES_OK && !(stat & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ res = FR_OK; } #endif From f2ebee9cf12d26bf365d3e328a8a915a44802d04 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Wed, 6 Mar 2019 15:52:36 +1100 Subject: [PATCH 0170/1788] stm32/mboot: Update to match latest oofatfs version. See corresponding commit b5f33ac2cb6076468a77f36d69df6db16b62134a --- ports/stm32/mboot/Makefile | 2 +- ports/stm32/mboot/ffconf.h | 66 ++++++++++++++++++++------------------ 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/ports/stm32/mboot/Makefile b/ports/stm32/mboot/Makefile index a59a210823..486d72e19a 100644 --- a/ports/stm32/mboot/Makefile +++ b/ports/stm32/mboot/Makefile @@ -74,7 +74,7 @@ endif SRC_LIB = \ lib/libc/string0.c \ lib/oofatfs/ff.c \ - lib/oofatfs/option/unicode.c \ + lib/oofatfs/ffunicode.c \ extmod/uzlib/crc32.c \ extmod/uzlib/adler32.c \ extmod/uzlib/tinflate.c \ diff --git a/ports/stm32/mboot/ffconf.h b/ports/stm32/mboot/ffconf.h index 7c45266a05..f598e7eca4 100644 --- a/ports/stm32/mboot/ffconf.h +++ b/ports/stm32/mboot/ffconf.h @@ -24,40 +24,42 @@ * THE SOFTWARE. */ -#define _FFCONF 68020 +#define FFCONF_DEF 86604 -#define _FS_READONLY 1 -#define _FS_MINIMIZE 0 -#define _USE_STRFUNC 0 +#define FF_FS_READONLY 1 +#define FF_FS_MINIMIZE 0 +#define FF_USE_STRFUNC 0 -#define _USE_FIND 0 -#define _USE_MKFS 0 -#define _USE_FASTSEEK 0 -#define _USE_EXPAND 0 -#define _USE_CHMOD 0 -#define _USE_LABEL 0 -#define _USE_FORWARD 0 +#define FF_USE_FIND 0 +#define FF_USE_MKFS 0 +#define FF_USE_FASTSEEK 0 +#define FF_USE_EXPAND 0 +#define FF_USE_CHMOD 0 +#define FF_USE_LABEL 0 +#define FF_USE_FORWARD 0 -#define _CODE_PAGE 437 -#define _USE_LFN 1 -#define _MAX_LFN 255 -#define _LFN_UNICODE 0 -#define _STRF_ENCODE 3 -#define _FS_RPATH 0 +#define FF_CODE_PAGE 437 +#define FF_USE_LFN 1 +#define FF_MAX_LFN 255 +#define FF_LFN_UNICODE 0 +#define FF_LFN_BUF 255 +#define FF_SFN_BUF 12 +#define FF_STRF_ENCODE 3 +#define FF_FS_RPATH 0 -#define _VOLUMES 1 -#define _STR_VOLUME_ID 0 -#define _MULTI_PARTITION 0 -#define _MIN_SS 512 -#define _MAX_SS 512 -#define _USE_TRIM 0 -#define _FS_NOFSINFO 0 +#define FF_VOLUMES 1 +#define FF_STR_VOLUME_ID 0 +#define FF_MULTI_PARTITION 0 +#define FF_MIN_SS 512 +#define FF_MAX_SS 512 +#define FF_USE_TRIM 0 +#define FF_FS_NOFSINFO 0 -#define _FS_TINY 1 -#define _FS_EXFAT 0 -#define _FS_NORTC 1 -#define _NORTC_MON 1 -#define _NORTC_MDAY 1 -#define _NORTC_YEAR 2019 -#define _FS_LOCK 0 -#define _FS_REENTRANT 0 +#define FF_FS_TINY 1 +#define FF_FS_EXFAT 0 +#define FF_FS_NORTC 1 +#define FF_NORTC_MON 1 +#define FF_NORTC_MDAY 1 +#define FF_NORTC_YEAR 2019 +#define FF_FS_LOCK 0 +#define FF_FS_REENTRANT 0 From 02cc288edbc47a3b21b88b83f15990cc5a36ed23 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 8 Mar 2019 15:48:20 +1100 Subject: [PATCH 0171/1788] py: Add independent config for debugging sentinel object values. The new compile-time option is MICROPY_DEBUG_MP_OBJ_SENTINELS, disabled by default. This is to allow finer control of whether this debugging feature is enabled or not (because, for example, this setting must be the same for mpy-cross and the MicroPython main code when using native code generation). --- py/emitnative.c | 8 ++++---- py/mpconfig.h | 5 +++++ py/obj.h | 10 +++++----- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/py/emitnative.c b/py/emitnative.c index c8a1a33d6b..0c756f9a53 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -2094,12 +2094,12 @@ 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); - #ifdef NDEBUG - MP_STATIC_ASSERT(MP_OBJ_STOP_ITERATION == 0); - ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, label, false); - #else + #if MICROPY_DEBUG_MP_OBJ_SENTINELS 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); + #else + MP_STATIC_ASSERT(MP_OBJ_STOP_ITERATION == 0); + ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, label, false); #endif emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } diff --git a/py/mpconfig.h b/py/mpconfig.h index c4b62dd847..893ac7dc7e 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -414,6 +414,11 @@ #define MICROPY_DEBUG_VERBOSE (0) #endif +// Whether to enable debugging versions of MP_OBJ_NULL/STOP_ITERATION/SENTINEL +#ifndef MICROPY_DEBUG_MP_OBJ_SENTINELS +#define MICROPY_DEBUG_MP_OBJ_SENTINELS (0) +#endif + // Whether to enable a simple VM stack overflow check #ifndef MICROPY_DEBUG_VM_STACK_OVERFLOW #define MICROPY_DEBUG_VM_STACK_OVERFLOW (0) diff --git a/py/obj.h b/py/obj.h index e8575dbd10..4d42c43de3 100644 --- a/py/obj.h +++ b/py/obj.h @@ -65,14 +65,14 @@ typedef struct _mp_obj_base_t mp_obj_base_t; // For debugging purposes they are all different. For non-debug mode, we alias // as many as we can to MP_OBJ_NULL because it's cheaper to load/compare 0. -#ifdef NDEBUG -#define MP_OBJ_NULL (MP_OBJ_FROM_PTR((void*)0)) -#define MP_OBJ_STOP_ITERATION (MP_OBJ_FROM_PTR((void*)0)) -#define MP_OBJ_SENTINEL (MP_OBJ_FROM_PTR((void*)4)) -#else +#if MICROPY_DEBUG_MP_OBJ_SENTINELS #define MP_OBJ_NULL (MP_OBJ_FROM_PTR((void*)0)) #define MP_OBJ_STOP_ITERATION (MP_OBJ_FROM_PTR((void*)4)) #define MP_OBJ_SENTINEL (MP_OBJ_FROM_PTR((void*)8)) +#else +#define MP_OBJ_NULL (MP_OBJ_FROM_PTR((void*)0)) +#define MP_OBJ_STOP_ITERATION (MP_OBJ_FROM_PTR((void*)0)) +#define MP_OBJ_SENTINEL (MP_OBJ_FROM_PTR((void*)4)) #endif // These macros/inline functions operate on objects and depend on the From 01a1f31f67ff6c9b6b1539783a8109dc380992fb Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 7 Mar 2019 22:46:04 +1100 Subject: [PATCH 0172/1788] py/emitnative: Consolidate where HASCONSTS is set to load-const-obj fun. Simplifies the code and fixes handling of the Ellipsis const in native code generation (which also needs the constant table so must set this flag). --- py/compile.c | 9 --------- py/emitnative.c | 1 + 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/py/compile.c b/py/compile.c index b7f1d7b0c1..4609a50213 100644 --- a/py/compile.c +++ b/py/compile.c @@ -2693,9 +2693,6 @@ STATIC mp_obj_t get_const_object(mp_parse_node_struct_t *pns) { } STATIC void compile_const_object(compiler_t *comp, mp_parse_node_struct_t *pns) { - #if MICROPY_EMIT_NATIVE - comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_HASCONSTS; - #endif EMIT_ARG(load_const_obj, get_const_object(pns)); } @@ -2730,9 +2727,6 @@ STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn) { } else { EMIT_ARG(load_const_obj, mp_obj_new_int_from_ll(arg)); } - #if MICROPY_EMIT_NATIVE - comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_HASCONSTS; - #endif } #else EMIT_ARG(load_const_small_int, arg); @@ -2751,9 +2745,6 @@ STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn) { const byte *data = qstr_data(arg, &len); EMIT_ARG(load_const_obj, mp_obj_new_bytes(data, len)); } - #if MICROPY_EMIT_NATIVE - comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_HASCONSTS; - #endif break; case MP_PARSE_NODE_TOKEN: default: if (arg == MP_TOKEN_NEWLINE) { diff --git a/py/emitnative.c b/py/emitnative.c index 0c756f9a53..f04de81cd3 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -1250,6 +1250,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->scope->scope_flags |= MP_SCOPE_FLAG_HASCONSTS; emit_native_pre(emit); need_reg_single(emit, REG_RET, 0); emit_load_reg_with_object(emit, REG_RET, obj); From 205edb43056cf9a43f439cee0edbd04cdd154f6e Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 3 Feb 2019 12:25:50 +1100 Subject: [PATCH 0173/1788] py/emitnative: Provide concentrated points of qstr emit. --- py/emitnative.c | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/py/emitnative.c b/py/emitnative.c index f04de81cd3..0e03507eac 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -279,6 +279,14 @@ STATIC void emit_native_mov_reg_state_addr(emit_t *emit, int reg_dest, int local } } +STATIC void emit_native_mov_reg_qstr(emit_t *emit, int arg_reg, qstr qst) { + ASM_MOV_REG_IMM(emit->as, arg_reg, qst); +} + +STATIC void emit_native_mov_reg_qstr_obj(emit_t *emit, int reg_dest, qstr qst) { + ASM_MOV_REG_IMM(emit->as, reg_dest, (mp_uint_t)MP_OBJ_NEW_QSTR(qst)); +} + #define emit_native_mov_state_imm_via(emit, local_num, imm, reg_temp) \ do { \ ASM_MOV_REG_IMM((emit)->as, (reg_temp), (imm)); \ @@ -883,6 +891,12 @@ STATIC void emit_call_with_2_imm_args(emit_t *emit, mp_fun_kind_t fun_kind, mp_i ASM_CALL_IND(emit->as, fun_kind); } +STATIC void emit_call_with_qstr_arg(emit_t *emit, mp_fun_kind_t fun_kind, qstr qst, int arg_reg) { + need_reg_all(emit); + emit_native_mov_reg_qstr(emit, arg_reg, qst); + ASM_CALL_IND(emit->as, fun_kind); +} + // vtype of all n_pop objects is VTYPE_PYOBJ // Will convert any items that are not VTYPE_PYOBJ to this type and put them back on the stack. // If any conversions of non-immediate values are needed, then it uses REG_ARG_1, REG_ARG_2 and REG_RET. @@ -1181,7 +1195,7 @@ STATIC void emit_native_import_name(emit_t *emit, qstr qst) { assert(vtype_level == VTYPE_PYOBJ); emit->do_viper_types = orig_do_viper_types; - emit_call_with_imm_arg(emit, MP_F_IMPORT_NAME, qst, REG_ARG_1); // arg1 = import name + emit_call_with_qstr_arg(emit, MP_F_IMPORT_NAME, qst, REG_ARG_1); // arg1 = import name emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } @@ -1191,7 +1205,7 @@ STATIC void emit_native_import_from(emit_t *emit, qstr qst) { vtype_kind_t vtype_module; emit_access_stack(emit, 1, &vtype_module, REG_ARG_1); // arg1 = module assert(vtype_module == VTYPE_PYOBJ); - emit_call_with_imm_arg(emit, MP_F_IMPORT_FROM, qst, REG_ARG_2); // arg2 = import name + emit_call_with_qstr_arg(emit, MP_F_IMPORT_FROM, qst, REG_ARG_2); // arg2 = import name emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } @@ -1245,7 +1259,9 @@ STATIC void emit_native_load_const_str(emit_t *emit, qstr qst) { } else */ { - emit_post_push_imm(emit, VTYPE_PYOBJ, (mp_uint_t)MP_OBJ_NEW_QSTR(qst)); + need_reg_single(emit, REG_TEMP0, 0); + emit_native_mov_reg_qstr_obj(emit, REG_TEMP0, qst); + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_TEMP0); } } @@ -1315,7 +1331,7 @@ STATIC void emit_native_load_global(emit_t *emit, qstr qst, int kind) { } } } - emit_call_with_imm_arg(emit, MP_F_LOAD_NAME + kind, qst, REG_ARG_1); + emit_call_with_qstr_arg(emit, MP_F_LOAD_NAME + kind, qst, REG_ARG_1); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } @@ -1327,7 +1343,7 @@ STATIC void emit_native_load_attr(emit_t *emit, qstr qst) { vtype_kind_t vtype_base; emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base assert(vtype_base == VTYPE_PYOBJ); - emit_call_with_imm_arg(emit, MP_F_LOAD_ATTR, qst, REG_ARG_2); // arg2 = attribute name + emit_call_with_qstr_arg(emit, MP_F_LOAD_ATTR, qst, REG_ARG_2); // arg2 = attribute name emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } @@ -1335,13 +1351,13 @@ STATIC void emit_native_load_method(emit_t *emit, qstr qst, bool is_super) { if (is_super) { emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, 3); // arg2 = dest ptr emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_2, 2); // arg2 = dest ptr - emit_call_with_imm_arg(emit, MP_F_LOAD_SUPER_METHOD, qst, REG_ARG_1); // arg1 = method name + emit_call_with_qstr_arg(emit, MP_F_LOAD_SUPER_METHOD, qst, REG_ARG_1); // arg1 = method name } else { vtype_kind_t vtype_base; emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base assert(vtype_base == VTYPE_PYOBJ); emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, 2); // arg3 = dest ptr - emit_call_with_imm_arg(emit, MP_F_LOAD_METHOD, qst, REG_ARG_2); // arg2 = method name + emit_call_with_qstr_arg(emit, MP_F_LOAD_METHOD, qst, REG_ARG_2); // arg2 = method name } } @@ -1548,7 +1564,7 @@ STATIC void emit_native_store_global(emit_t *emit, qstr qst, int kind) { ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_RET); } } - emit_call_with_imm_arg(emit, MP_F_STORE_NAME + kind, qst, REG_ARG_1); // arg1 = name + emit_call_with_qstr_arg(emit, MP_F_STORE_NAME + kind, qst, REG_ARG_1); // arg1 = name emit_post(emit); } @@ -1557,7 +1573,7 @@ STATIC void emit_native_store_attr(emit_t *emit, qstr qst) { emit_pre_pop_reg_reg(emit, &vtype_base, REG_ARG_1, &vtype_val, REG_ARG_3); // arg1 = base, arg3 = value assert(vtype_base == VTYPE_PYOBJ); assert(vtype_val == VTYPE_PYOBJ); - emit_call_with_imm_arg(emit, MP_F_STORE_ATTR, qst, REG_ARG_2); // arg2 = attribute name + emit_call_with_qstr_arg(emit, MP_F_STORE_ATTR, qst, REG_ARG_2); // arg2 = attribute name emit_post(emit); } @@ -1754,7 +1770,7 @@ 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 + kind, qst, REG_ARG_1); + emit_call_with_qstr_arg(emit, MP_F_DELETE_NAME + kind, qst, REG_ARG_1); emit_post(emit); } @@ -1762,7 +1778,8 @@ STATIC void emit_native_delete_attr(emit_t *emit, qstr qst) { vtype_kind_t vtype_base; emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base assert(vtype_base == VTYPE_PYOBJ); - emit_call_with_2_imm_args(emit, MP_F_STORE_ATTR, qst, REG_ARG_2, (mp_uint_t)MP_OBJ_NULL, REG_ARG_3); // arg2 = attribute name, arg3 = value (null for delete) + ASM_XOR_REG_REG(emit->as, REG_ARG_3, REG_ARG_3); // arg3 = value (null for delete) + emit_call_with_qstr_arg(emit, MP_F_STORE_ATTR, qst, REG_ARG_2); // arg2 = attribute name emit_post(emit); } @@ -1936,7 +1953,7 @@ STATIC void emit_native_setup_with(emit_t *emit, mp_uint_t label) { emit_access_stack(emit, 1, &vtype, REG_ARG_1); // arg1 = ctx_mgr assert(vtype == VTYPE_PYOBJ); emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, 2); // arg3 = dest ptr - emit_call_with_imm_arg(emit, MP_F_LOAD_METHOD, MP_QSTR___exit__, REG_ARG_2); + emit_call_with_qstr_arg(emit, MP_F_LOAD_METHOD, MP_QSTR___exit__, REG_ARG_2); // stack: (..., ctx_mgr, __exit__, self) emit_pre_pop_reg(emit, &vtype, REG_ARG_3); // self @@ -1949,7 +1966,7 @@ STATIC void emit_native_setup_with(emit_t *emit, mp_uint_t label) { // get __enter__ method emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, 2); // arg3 = dest ptr - emit_call_with_imm_arg(emit, MP_F_LOAD_METHOD, MP_QSTR___enter__, REG_ARG_2); // arg2 = method name + emit_call_with_qstr_arg(emit, MP_F_LOAD_METHOD, MP_QSTR___enter__, REG_ARG_2); // arg2 = method name // stack: (..., __exit__, self, __enter__, self) // call __enter__ method From 3986820912acee0909643636f52c2c672b6427d0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 25 Feb 2019 15:57:35 +1100 Subject: [PATCH 0174/1788] py/emitnative: Adjust accounting of size of const_table. n_obj no longer includes a count for mp_fun_table to make it a bit simpler. --- py/emitnative.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/py/emitnative.c b/py/emitnative.c index 0e03507eac..8d7c93af1e 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -299,7 +299,7 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop emit->pass = pass; emit->do_viper_types = scope->emit_options == MP_EMIT_OPT_VIPER; emit->stack_size = 0; - emit->const_table_cur_obj = 1; // first entry is for mp_fun_table + emit->const_table_cur_obj = 0; emit->const_table_cur_raw_code = 0; emit->last_emit_was_return_value = false; emit->scope = scope; @@ -588,7 +588,7 @@ STATIC void emit_native_end_pass(emit_t *emit) { assert(emit->pass <= MP_PASS_STACK_SIZE || (emit->const_table_num_obj == emit->const_table_cur_obj)); emit->const_table_num_obj = emit->const_table_cur_obj; if (emit->pass == MP_PASS_CODE_SIZE) { - size_t const_table_alloc = emit->const_table_num_obj + emit->const_table_cur_raw_code; + size_t const_table_alloc = 1 + emit->const_table_num_obj + emit->const_table_cur_raw_code; size_t nqstr = 0; if (!emit->do_viper_types) { // Add room for qstr names of arguments @@ -1013,12 +1013,14 @@ STATIC void emit_load_reg_with_ptr(emit_t *emit, int reg, mp_uint_t ptr, size_t } STATIC void emit_load_reg_with_object(emit_t *emit, int reg, mp_obj_t obj) { - size_t table_off = emit->const_table_cur_obj++; + // First entry is for mp_fun_table + size_t table_off = 1 + emit->const_table_cur_obj++; emit_load_reg_with_ptr(emit, reg, (mp_uint_t)obj, table_off); } STATIC void emit_load_reg_with_raw_code(emit_t *emit, int reg, mp_raw_code_t *rc) { - size_t table_off = emit->const_table_num_obj + emit->const_table_cur_raw_code++; + // First entry is for mp_fun_table, then constant objects + size_t table_off = 1 + emit->const_table_num_obj + emit->const_table_cur_raw_code++; emit_load_reg_with_ptr(emit, reg, (mp_uint_t)rc, table_off); } From 636ed0ff8d4d3c43f7d9fb2d8852073f99c1e6cf Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 Feb 2019 14:15:39 +1100 Subject: [PATCH 0175/1788] py/emitglue: Remove union in mp_raw_code_t to combine bytecode & native. --- py/emitglue.c | 22 +++++++++++----------- py/emitglue.h | 26 ++++++++++---------------- py/persistentcode.c | 20 ++++++++++---------- tools/mpy-tool.py | 18 ++++++++---------- 4 files changed, 39 insertions(+), 47 deletions(-) diff --git a/py/emitglue.c b/py/emitglue.c index 0e13fd6d1f..996b79e173 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -67,12 +67,12 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, rc->kind = MP_CODE_BYTECODE; rc->scope_flags = scope_flags; - rc->data.u_byte.bytecode = code; - rc->data.u_byte.const_table = const_table; + rc->fun_data = code; + rc->const_table = const_table; #if MICROPY_PERSISTENT_CODE_SAVE - rc->data.u_byte.bc_len = len; - rc->data.u_byte.n_obj = n_obj; - rc->data.u_byte.n_raw_code = n_raw_code; + rc->fun_data_len = len; + rc->n_obj = n_obj; + rc->n_raw_code = n_raw_code; #endif #ifdef DEBUG_PRINT @@ -94,9 +94,9 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void rc->kind = kind; rc->scope_flags = scope_flags; rc->n_pos_args = n_pos_args; - rc->data.u_native.fun_data = fun_data; - rc->data.u_native.const_table = const_table; - rc->data.u_native.type_sig = type_sig; + rc->fun_data = fun_data; + rc->const_table = const_table; + rc->type_sig = type_sig; #ifdef DEBUG_PRINT DEBUG_printf("assign native: kind=%d fun=%p len=" UINT_FMT " n_pos_args=" UINT_FMT " flags=%x\n", kind, fun_data, fun_len, n_pos_args, (uint)scope_flags); @@ -135,7 +135,7 @@ mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, mp_obj_t def_ar #if MICROPY_EMIT_NATIVE case MP_CODE_NATIVE_PY: case MP_CODE_NATIVE_VIPER: - fun = mp_obj_new_fun_native(def_args, def_kw_args, rc->data.u_native.fun_data, rc->data.u_native.const_table); + fun = mp_obj_new_fun_native(def_args, def_kw_args, rc->fun_data, rc->const_table); // Check for a generator function, and if so change the type of the object if ((rc->scope_flags & MP_SCOPE_FLAG_GENERATOR) != 0) { ((mp_obj_base_t*)MP_OBJ_TO_PTR(fun))->type = &mp_type_native_gen_wrap; @@ -144,13 +144,13 @@ mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, mp_obj_t def_ar #endif #if MICROPY_EMIT_INLINE_ASM case MP_CODE_NATIVE_ASM: - fun = mp_obj_new_fun_asm(rc->n_pos_args, rc->data.u_native.fun_data, rc->data.u_native.type_sig); + fun = mp_obj_new_fun_asm(rc->n_pos_args, rc->fun_data, rc->type_sig); break; #endif default: // rc->kind should always be set and BYTECODE is the only remaining case assert(rc->kind == MP_CODE_BYTECODE); - fun = mp_obj_new_fun_bc(def_args, def_kw_args, rc->data.u_byte.bytecode, rc->data.u_byte.const_table); + fun = mp_obj_new_fun_bc(def_args, def_kw_args, rc->fun_data, rc->const_table); // check for generator functions and if so change the type of the object if ((rc->scope_flags & MP_SCOPE_FLAG_GENERATOR) != 0) { ((mp_obj_base_t*)MP_OBJ_TO_PTR(fun))->type = &mp_type_gen_wrap; diff --git a/py/emitglue.h b/py/emitglue.h index d39a10ee94..53049b161e 100644 --- a/py/emitglue.h +++ b/py/emitglue.h @@ -52,22 +52,16 @@ typedef struct _mp_raw_code_t { 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 { - struct { - const byte *bytecode; - const mp_uint_t *const_table; - #if MICROPY_PERSISTENT_CODE_SAVE - mp_uint_t bc_len; - uint16_t n_obj; - uint16_t n_raw_code; - #endif - } u_byte; - struct { - void *fun_data; - const mp_uint_t *const_table; - mp_uint_t type_sig; // for viper, compressed as 2-bit types; ret is MSB, then arg0, arg1, etc - } u_native; - } data; + const void *fun_data; + const mp_uint_t *const_table; + #if MICROPY_PERSISTENT_CODE_SAVE + size_t fun_data_len; + uint16_t n_obj; + uint16_t n_raw_code; + #endif + #if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM + mp_uint_t type_sig; // for viper, compressed as 2-bit types; ret is MSB, then arg0, arg1, etc + #endif } mp_raw_code_t; mp_raw_code_t *mp_emit_glue_new_raw_code(void); diff --git a/py/persistentcode.c b/py/persistentcode.c index c0a3281113..d4ca50e81f 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -449,16 +449,16 @@ STATIC void save_raw_code(mp_print_t *print, mp_raw_code_t *rc, qstr_window_t *q } // extract prelude - const byte *ip = rc->data.u_byte.bytecode; + const byte *ip = rc->fun_data; const byte *ip2; bytecode_prelude_t prelude; extract_prelude(&ip, &ip2, &prelude); // save prelude - size_t prelude_len = ip - rc->data.u_byte.bytecode; - const byte *ip_top = rc->data.u_byte.bytecode + rc->data.u_byte.bc_len; - mp_print_uint(print, rc->data.u_byte.bc_len); - mp_print_bytes(print, rc->data.u_byte.bytecode, prelude_len); + size_t prelude_len = ip - rc->fun_data; + const byte *ip_top = rc->fun_data + rc->fun_data_len; + mp_print_uint(print, rc->fun_data_len); + mp_print_bytes(print, rc->fun_data, prelude_len); // save bytecode save_bytecode(print, qstr_window, ip, ip_top); @@ -468,17 +468,17 @@ STATIC void save_raw_code(mp_print_t *print, mp_raw_code_t *rc, qstr_window_t *q save_qstr(print, qstr_window, ip2[2] | (ip2[3] << 8)); // source_file // save constant table - mp_print_uint(print, rc->data.u_byte.n_obj); - mp_print_uint(print, rc->data.u_byte.n_raw_code); - const mp_uint_t *const_table = rc->data.u_byte.const_table; + mp_print_uint(print, rc->n_obj); + mp_print_uint(print, rc->n_raw_code); + const mp_uint_t *const_table = rc->const_table; for (uint i = 0; i < prelude.n_pos_args + prelude.n_kwonly_args; ++i) { mp_obj_t o = (mp_obj_t)*const_table++; save_qstr(print, qstr_window, MP_OBJ_QSTR_VALUE(o)); } - for (uint i = 0; i < rc->data.u_byte.n_obj; ++i) { + for (uint i = 0; i < rc->n_obj; ++i) { save_obj(print, (mp_obj_t)*const_table++); } - for (uint i = 0; i < rc->data.u_byte.n_raw_code; ++i) { + for (uint i = 0; i < rc->n_raw_code; ++i) { save_raw_code(print, (mp_raw_code_t*)(uintptr_t)*const_table++, qstr_window); } } diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index 8a82374031..37adaf3556 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -391,18 +391,16 @@ class RawCode: print(' .kind = MP_CODE_BYTECODE,') print(' .scope_flags = 0x%02x,' % self.prelude[2]) print(' .n_pos_args = %u,' % self.prelude[3]) - print(' .data.u_byte = {') - print(' .bytecode = bytecode_data_%s,' % self.escaped_name) + print(' .fun_data = bytecode_data_%s,' % self.escaped_name) if const_table_len: - print(' .const_table = (mp_uint_t*)const_table_data_%s,' % self.escaped_name) + print(' .const_table = (mp_uint_t*)const_table_data_%s,' % self.escaped_name) else: - print(' .const_table = NULL,') - print(' #if MICROPY_PERSISTENT_CODE_SAVE') - print(' .bc_len = %u,' % len(self.bytecode)) - print(' .n_obj = %u,' % len(self.objs)) - print(' .n_raw_code = %u,' % len(self.raw_codes)) - print(' #endif') - print(' },') + print(' .const_table = NULL,') + print(' #if MICROPY_PERSISTENT_CODE_SAVE') + print(' .fun_data_len = %u,' % len(self.bytecode)) + print(' .n_obj = %u,' % len(self.objs)) + print(' .n_raw_code = %u,' % len(self.raw_codes)) + print(' #endif') print('};') class BytecodeBuffer: From 1396a026be78bc90ea18961ba6760f851b691b4c Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 21 Feb 2019 15:18:33 +1100 Subject: [PATCH 0176/1788] py: Add support to save native, viper and asm code to .mpy files. This commit adds support for saving and loading .mpy files that contain native code (native, viper and inline-asm). A lot of the ground work was already done for this in the form of removing pointers from generated native code. The changes here are mainly to link in qstr values to the native code, and change the format of .mpy files to contain native code blocks (possibly mixed with bytecode). A top-level summary: - @micropython.native, @micropython.viper and @micropython.asm_thumb/ asm_xtensa are now allowed in .py files when compiling to .mpy, and they work transparently to the user. - Entire .py files can be compiled to native via mpy-cross -X emit=native and for the most part the generated .mpy files should work the same as their bytecode version. - The .mpy file format is changed to 1) specify in the header if the file contains native code and if so the architecture (eg x86, ARMV7M, Xtensa); 2) for each function block the kind of code is specified (bytecode, native, viper, asm). - When native code is loaded from a .mpy file the native code must be modified (in place) to link qstr values in, just like bytecode (see py/persistentcode.c:arch_link_qstr() function). In addition, this now defines a public, native ABI for dynamically loadable native code generated by other languages, like C. --- py/asmarm.c | 16 +- py/asmarm.h | 7 +- py/asmthumb.c | 10 +- py/asmthumb.h | 6 +- py/asmx64.c | 4 +- py/asmx64.h | 3 + py/asmx86.c | 4 +- py/asmx86.h | 4 +- py/asmxtensa.c | 24 +-- py/asmxtensa.h | 8 +- py/compile.c | 6 +- py/emitglue.c | 19 ++- py/emitglue.h | 20 ++- py/emitnative.c | 43 ++++++ py/persistentcode.c | 363 ++++++++++++++++++++++++++++++++++++-------- py/persistentcode.h | 13 ++ 16 files changed, 457 insertions(+), 93 deletions(-) diff --git a/py/asmarm.c b/py/asmarm.c index 3610f838e6..f2221f8a92 100644 --- a/py/asmarm.c +++ b/py/asmarm.c @@ -197,7 +197,16 @@ void asm_arm_mov_reg_reg(asm_arm_t *as, uint reg_dest, uint reg_src) { emit_al(as, asm_arm_op_mov_reg(reg_dest, reg_src)); } -void asm_arm_mov_reg_i32(asm_arm_t *as, uint rd, int imm) { +size_t asm_arm_mov_reg_i32(asm_arm_t *as, uint rd, int imm) { + // Insert immediate into code and jump over it + emit_al(as, 0x59f0000 | (rd << 12)); // ldr rd, [pc] + emit_al(as, 0xa000000); // b pc + size_t loc = mp_asm_base_get_code_pos(&as->base); + emit(as, imm); + return loc; +} + +void asm_arm_mov_reg_i32_optimised(asm_arm_t *as, uint rd, int imm) { // TODO: There are more variants of immediate values if ((imm & 0xFF) == imm) { emit_al(as, asm_arm_op_mov_imm(rd, imm)); @@ -205,10 +214,7 @@ void asm_arm_mov_reg_i32(asm_arm_t *as, uint rd, int imm) { // mvn is "move not", not "move negative" emit_al(as, asm_arm_op_mvn_imm(rd, ~imm)); } else { - //Insert immediate into code and jump over it - emit_al(as, 0x59f0000 | (rd << 12)); // ldr rd, [pc] - emit_al(as, 0xa000000); // b pc - emit(as, imm); + asm_arm_mov_reg_i32(as, rd, imm); } } diff --git a/py/asmarm.h b/py/asmarm.h index 58a13cc83e..825fd88400 100644 --- a/py/asmarm.h +++ b/py/asmarm.h @@ -81,7 +81,8 @@ void asm_arm_bkpt(asm_arm_t *as); // mov void asm_arm_mov_reg_reg(asm_arm_t *as, uint reg_dest, uint reg_src); -void asm_arm_mov_reg_i32(asm_arm_t *as, uint rd, int imm); +size_t asm_arm_mov_reg_i32(asm_arm_t *as, uint rd, int imm); +void asm_arm_mov_reg_i32_optimised(asm_arm_t *as, uint rd, int imm); void asm_arm_mov_local_reg(asm_arm_t *as, int local_num, uint rd); void asm_arm_mov_reg_local(asm_arm_t *as, uint rd, int local_num); void asm_arm_setcc_reg(asm_arm_t *as, uint rd, uint cond); @@ -177,7 +178,9 @@ void asm_arm_bx_reg(asm_arm_t *as, uint reg_src); #define ASM_CALL_IND(as, idx) asm_arm_bl_ind(as, idx, ASM_ARM_REG_R3) #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_IMM(as, reg_dest, imm) asm_arm_mov_reg_i32_optimised((as), (reg_dest), (imm)) +#define ASM_MOV_REG_IMM_FIX_U16(as, reg_dest, imm) asm_arm_mov_reg_i32((as), (reg_dest), (imm)) +#define ASM_MOV_REG_IMM_FIX_WORD(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_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_arm_mov_reg_local_addr((as), (reg_dest), (local_num)) diff --git a/py/asmthumb.c b/py/asmthumb.c index 46102395dc..e6bba7ea60 100644 --- a/py/asmthumb.c +++ b/py/asmthumb.c @@ -225,10 +225,12 @@ void asm_thumb_mov_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_src) { } // if loading lo half with movw, the i16 value will be zero extended into the r32 register! -void asm_thumb_mov_reg_i16(asm_thumb_t *as, uint mov_op, uint reg_dest, int i16_src) { +size_t asm_thumb_mov_reg_i16(asm_thumb_t *as, uint mov_op, uint reg_dest, int i16_src) { assert(reg_dest < ASM_THUMB_REG_R15); + size_t loc = mp_asm_base_get_code_pos(&as->base); // mov[wt] reg_dest, #i16_src asm_thumb_op32(as, mov_op | ((i16_src >> 1) & 0x0400) | ((i16_src >> 12) & 0xf), ((i16_src << 4) & 0x7000) | (reg_dest << 8) | (i16_src & 0xff)); + return loc; } #define OP_B_N(byte_offset) (0xe000 | (((byte_offset) >> 1) & 0x07ff)) @@ -271,12 +273,16 @@ bool asm_thumb_bl_label(asm_thumb_t *as, uint label) { return as->base.pass != MP_ASM_PASS_EMIT || SIGNED_FIT23(rel); } -void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, mp_uint_t i32) { +size_t asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, mp_uint_t i32) { // movw, movt does it in 8 bytes // ldr [pc, #], dw does it in 6 bytes, but we might not reach to end of code for dw + size_t loc = mp_asm_base_get_code_pos(&as->base); + asm_thumb_mov_reg_i16(as, ASM_THUMB_OP_MOVW, reg_dest, i32); asm_thumb_mov_reg_i16(as, ASM_THUMB_OP_MOVT, reg_dest, i32 >> 16); + + return loc; } void asm_thumb_mov_reg_i32_optimised(asm_thumb_t *as, uint reg_dest, int i32) { diff --git a/py/asmthumb.h b/py/asmthumb.h index 9a44a78cae..c21c23ff79 100644 --- a/py/asmthumb.h +++ b/py/asmthumb.h @@ -241,14 +241,14 @@ static inline void asm_thumb_ldrh_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uin #define ASM_THUMB_OP_MOVT (0xf2c0) void asm_thumb_mov_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_src); -void asm_thumb_mov_reg_i16(asm_thumb_t *as, uint mov_op, uint reg_dest, int i16_src); +size_t asm_thumb_mov_reg_i16(asm_thumb_t *as, uint mov_op, uint reg_dest, int i16_src); // these return true if the destination is in range, false otherwise bool asm_thumb_b_n_label(asm_thumb_t *as, uint label); bool asm_thumb_bcc_nw_label(asm_thumb_t *as, int cond, uint label, bool wide); bool asm_thumb_bl_label(asm_thumb_t *as, uint label); -void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, mp_uint_t i32_src); // convenience +size_t asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, mp_uint_t i32_src); // convenience void asm_thumb_mov_reg_i32_optimised(asm_thumb_t *as, uint reg_dest, int i32_src); // convenience void asm_thumb_mov_local_reg(asm_thumb_t *as, int local_num_dest, uint rlo_src); // convenience void asm_thumb_mov_reg_local(asm_thumb_t *as, uint rlo_dest, int local_num); // convenience @@ -315,6 +315,8 @@ void asm_thumb_bl_ind(asm_thumb_t *as, uint fun_id, uint reg_temp); // convenien #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_IMM_FIX_U16(as, reg_dest, imm) asm_thumb_mov_reg_i16((as), ASM_THUMB_OP_MOVW, (reg_dest), (imm)) +#define ASM_MOV_REG_IMM_FIX_WORD(as, reg_dest, imm) asm_thumb_mov_reg_i32((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_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_thumb_mov_reg_local_addr((as), (reg_dest), (local_num)) diff --git a/py/asmx64.c b/py/asmx64.c index 3609f49d30..b18703a9c5 100644 --- a/py/asmx64.c +++ b/py/asmx64.c @@ -334,14 +334,16 @@ void asm_x64_mov_i8_to_r8(asm_x64_t *as, int src_i8, int dest_r64) { } */ -STATIC void asm_x64_mov_i32_to_r64(asm_x64_t *as, int src_i32, int dest_r64) { +size_t asm_x64_mov_i32_to_r64(asm_x64_t *as, int src_i32, int dest_r64) { // cpu defaults to i32 to r64, with zero extension if (dest_r64 < 8) { asm_x64_write_byte_1(as, OPCODE_MOV_I64_TO_R64 | dest_r64); } else { asm_x64_write_byte_2(as, REX_PREFIX | REX_B, OPCODE_MOV_I64_TO_R64 | (dest_r64 & 7)); } + size_t loc = mp_asm_base_get_code_pos(&as->base); asm_x64_write_word32(as, src_i32); + return loc; } void asm_x64_mov_i64_to_r64(asm_x64_t *as, int64_t src_i64, int dest_r64) { diff --git a/py/asmx64.h b/py/asmx64.h index 1c8755a84c..d3761b78f3 100644 --- a/py/asmx64.h +++ b/py/asmx64.h @@ -83,6 +83,7 @@ void asm_x64_nop(asm_x64_t* as); void asm_x64_push_r64(asm_x64_t* as, int src_r64); void asm_x64_pop_r64(asm_x64_t* as, int dest_r64); void asm_x64_mov_r64_r64(asm_x64_t* as, int dest_r64, int src_r64); +size_t asm_x64_mov_i32_to_r64(asm_x64_t *as, int src_i32, int dest_r64); void asm_x64_mov_i64_to_r64(asm_x64_t* as, int64_t src_i64, int dest_r64); void asm_x64_mov_i64_to_r64_optimised(asm_x64_t *as, int64_t src_i64, int dest_r64); void asm_x64_mov_r8_to_mem8(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp); @@ -181,6 +182,8 @@ void asm_x64_call_ind(asm_x64_t* as, size_t fun_id, int temp_r32); #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_IMM_FIX_U16(as, reg_dest, imm) asm_x64_mov_i32_to_r64((as), (imm), (reg_dest)) +#define ASM_MOV_REG_IMM_FIX_WORD(as, reg_dest, imm) asm_x64_mov_i32_to_r64((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_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_x64_mov_local_addr_to_r64((as), (local_num), (reg_dest)) diff --git a/py/asmx86.c b/py/asmx86.c index 8ce576ac89..23160c9c20 100644 --- a/py/asmx86.c +++ b/py/asmx86.c @@ -236,9 +236,11 @@ void asm_x86_mov_i8_to_r8(asm_x86_t *as, int src_i8, int dest_r32) { } #endif -void asm_x86_mov_i32_to_r32(asm_x86_t *as, int32_t src_i32, int dest_r32) { +size_t asm_x86_mov_i32_to_r32(asm_x86_t *as, int32_t src_i32, int dest_r32) { asm_x86_write_byte_1(as, OPCODE_MOV_I32_TO_R32 | dest_r32); + size_t loc = mp_asm_base_get_code_pos(&as->base); asm_x86_write_word32(as, src_i32); + return loc; } void asm_x86_and_r32_r32(asm_x86_t *as, int dest_r32, int src_r32) { diff --git a/py/asmx86.h b/py/asmx86.h index 82a8629ddf..7ba677b2c2 100644 --- a/py/asmx86.h +++ b/py/asmx86.h @@ -83,7 +83,7 @@ static inline void asm_x86_end_pass(asm_x86_t *as) { } void asm_x86_mov_r32_r32(asm_x86_t* as, int dest_r32, int src_r32); -void asm_x86_mov_i32_to_r32(asm_x86_t *as, int32_t src_i32, int dest_r32); +size_t asm_x86_mov_i32_to_r32(asm_x86_t *as, int32_t src_i32, int dest_r32); void asm_x86_mov_r8_to_mem8(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp); void asm_x86_mov_r16_to_mem16(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp); void asm_x86_mov_r32_to_mem32(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp); @@ -179,6 +179,8 @@ void asm_x86_call_ind(asm_x86_t* as, size_t fun_id, mp_uint_t n_args, int temp_r #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_IMM_FIX_U16(as, reg_dest, imm) asm_x86_mov_i32_to_r32((as), (imm), (reg_dest)) +#define ASM_MOV_REG_IMM_FIX_WORD(as, reg_dest, imm) asm_x86_mov_i32_to_r32((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_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_x86_mov_local_addr_to_r32((as), (local_num), (reg_dest)) diff --git a/py/asmxtensa.c b/py/asmxtensa.c index 8da56ffe30..a269e5e7fc 100644 --- a/py/asmxtensa.c +++ b/py/asmxtensa.c @@ -156,18 +156,24 @@ void asm_xtensa_setcc_reg_reg_reg(asm_xtensa_t *as, uint cond, uint reg_dest, ui asm_xtensa_op_movi_n(as, reg_dest, 0); } -void asm_xtensa_mov_reg_i32(asm_xtensa_t *as, uint reg_dest, uint32_t i32) { +size_t asm_xtensa_mov_reg_i32(asm_xtensa_t *as, uint reg_dest, uint32_t i32) { + // load the constant + uint32_t const_table_offset = (uint8_t*)as->const_table - as->base.code_base; + size_t loc = const_table_offset + as->cur_const * WORD_SIZE; + asm_xtensa_op_l32r(as, reg_dest, as->base.code_offset, loc); + // store the constant in the table + if (as->const_table != NULL) { + as->const_table[as->cur_const] = i32; + } + ++as->cur_const; + return loc; +} + +void asm_xtensa_mov_reg_i32_optimised(asm_xtensa_t *as, uint reg_dest, uint32_t i32) { if (SIGNED_FIT12(i32)) { asm_xtensa_op_movi(as, reg_dest, i32); } else { - // load the constant - uint32_t const_table_offset = (uint8_t*)as->const_table - as->base.code_base; - asm_xtensa_op_l32r(as, reg_dest, as->base.code_offset, const_table_offset + as->cur_const * WORD_SIZE); - // store the constant in the table - if (as->const_table != NULL) { - as->const_table[as->cur_const] = i32; - } - ++as->cur_const; + asm_xtensa_mov_reg_i32(as, reg_dest, i32); } } diff --git a/py/asmxtensa.h b/py/asmxtensa.h index a595dc2b5a..d95af14a5d 100644 --- a/py/asmxtensa.h +++ b/py/asmxtensa.h @@ -26,6 +26,7 @@ #ifndef MICROPY_INCLUDED_PY_ASMXTENSA_H #define MICROPY_INCLUDED_PY_ASMXTENSA_H +#include "py/misc.h" #include "py/asmbase.h" // calling conventions: @@ -238,7 +239,8 @@ void asm_xtensa_j_label(asm_xtensa_t *as, uint label); void asm_xtensa_bccz_reg_label(asm_xtensa_t *as, uint cond, uint reg, uint label); void asm_xtensa_bcc_reg_reg_label(asm_xtensa_t *as, uint cond, uint reg1, uint reg2, uint label); void asm_xtensa_setcc_reg_reg_reg(asm_xtensa_t *as, uint cond, uint reg_dest, uint reg_src1, uint reg_src2); -void asm_xtensa_mov_reg_i32(asm_xtensa_t *as, uint reg_dest, uint32_t i32); +size_t asm_xtensa_mov_reg_i32(asm_xtensa_t *as, uint reg_dest, uint32_t i32); +void asm_xtensa_mov_reg_i32_optimised(asm_xtensa_t *as, uint reg_dest, uint32_t i32); void asm_xtensa_mov_local_reg(asm_xtensa_t *as, int local_num, uint reg_src); void asm_xtensa_mov_reg_local(asm_xtensa_t *as, uint reg_dest, int local_num); void asm_xtensa_mov_reg_local_addr(asm_xtensa_t *as, uint reg_dest, int local_num); @@ -289,7 +291,9 @@ void asm_xtensa_call_ind(asm_xtensa_t *as, uint idx); #define ASM_CALL_IND(as, idx) asm_xtensa_call_ind((as), (idx)) #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_IMM(as, reg_dest, imm) asm_xtensa_mov_reg_i32_optimised((as), (reg_dest), (imm)) +#define ASM_MOV_REG_IMM_FIX_U16(as, reg_dest, imm) asm_xtensa_mov_reg_i32((as), (reg_dest), (imm)) +#define ASM_MOV_REG_IMM_FIX_WORD(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_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_xtensa_mov_reg_local_addr((as), (reg_dest), (local_num)) diff --git a/py/compile.c b/py/compile.c index 4609a50213..a38998fdb6 100644 --- a/py/compile.c +++ b/py/compile.c @@ -3266,7 +3266,11 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind void *f = mp_asm_base_get_code((mp_asm_base_t*)comp->emit_inline_asm); mp_emit_glue_assign_native(comp->scope_cur->raw_code, MP_CODE_NATIVE_ASM, f, mp_asm_base_get_code_size((mp_asm_base_t*)comp->emit_inline_asm), - NULL, comp->scope_cur->num_pos_args, 0, type_sig); + NULL, + #if MICROPY_PERSISTENT_CODE_SAVE + 0, 0, 0, 0, NULL, + #endif + comp->scope_cur->num_pos_args, 0, type_sig); } } diff --git a/py/emitglue.c b/py/emitglue.c index 996b79e173..c073258f01 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -89,8 +89,16 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, } #if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM -void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, const mp_uint_t *const_table, mp_uint_t n_pos_args, mp_uint_t scope_flags, mp_uint_t type_sig) { +void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, const mp_uint_t *const_table, + #if MICROPY_PERSISTENT_CODE_SAVE + uint16_t prelude_offset, + uint16_t n_obj, uint16_t n_raw_code, + uint16_t n_qstr, mp_qstr_link_entry_t *qstr_link, + #endif + mp_uint_t n_pos_args, mp_uint_t scope_flags, mp_uint_t type_sig) { + assert(kind == MP_CODE_NATIVE_PY || kind == MP_CODE_NATIVE_VIPER || kind == MP_CODE_NATIVE_ASM); + rc->kind = kind; rc->scope_flags = scope_flags; rc->n_pos_args = n_pos_args; @@ -98,6 +106,15 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void rc->const_table = const_table; rc->type_sig = type_sig; + #if MICROPY_PERSISTENT_CODE_SAVE + rc->fun_data_len = fun_len; + rc->prelude_offset = prelude_offset; + rc->n_obj = n_obj; + rc->n_raw_code = n_raw_code; + rc->n_qstr= n_qstr; + rc->qstr_link = qstr_link; + #endif + #ifdef DEBUG_PRINT DEBUG_printf("assign native: kind=%d fun=%p len=" UINT_FMT " n_pos_args=" UINT_FMT " flags=%x\n", kind, fun_data, fun_len, n_pos_args, (uint)scope_flags); for (mp_uint_t i = 0; i < fun_len; i++) { diff --git a/py/emitglue.h b/py/emitglue.h index 53049b161e..058f060186 100644 --- a/py/emitglue.h +++ b/py/emitglue.h @@ -48,6 +48,11 @@ typedef enum { MP_CODE_NATIVE_ASM, } mp_raw_code_kind_t; +typedef struct _mp_qstr_link_entry_t { + uint16_t off; + uint16_t qst; +} mp_qstr_link_entry_t; + typedef struct _mp_raw_code_t { mp_uint_t kind : 3; // of type mp_raw_code_kind_t mp_uint_t scope_flags : 7; @@ -58,6 +63,11 @@ typedef struct _mp_raw_code_t { size_t fun_data_len; uint16_t n_obj; uint16_t n_raw_code; + #if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM + uint16_t prelude_offset; + uint16_t n_qstr; + mp_qstr_link_entry_t *qstr_link; + #endif #endif #if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM mp_uint_t type_sig; // for viper, compressed as 2-bit types; ret is MSB, then arg0, arg1, etc @@ -75,7 +85,15 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, uint16_t n_obj, uint16_t n_raw_code, #endif mp_uint_t scope_flags); -void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, const mp_uint_t *const_table, mp_uint_t n_pos_args, mp_uint_t scope_flags, mp_uint_t type_sig); + +void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, + const mp_uint_t *const_table, + #if MICROPY_PERSISTENT_CODE_SAVE + uint16_t prelude_offset, + uint16_t n_obj, uint16_t n_raw_code, + uint16_t n_qstr, mp_qstr_link_entry_t *qstr_link, + #endif + mp_uint_t n_pos_args, mp_uint_t scope_flags, mp_uint_t type_sig); mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args); mp_obj_t mp_make_closure_from_raw_code(const mp_raw_code_t *rc, mp_uint_t n_closed_over, const mp_obj_t *args); diff --git a/py/emitnative.c b/py/emitnative.c index 8d7c93af1e..ffdebd6432 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -214,6 +214,11 @@ struct _emit_t { uint16_t const_table_cur_raw_code; mp_uint_t *const_table; + #if MICROPY_PERSISTENT_CODE_SAVE + uint16_t qstr_link_cur; + mp_qstr_link_entry_t *qstr_link; + #endif + bool last_emit_was_return_value; scope_t *scope; @@ -225,6 +230,7 @@ STATIC const uint8_t reg_local_table[REG_LOCAL_NUM] = {REG_LOCAL_1, REG_LOCAL_2, STATIC void emit_native_global_exc_entry(emit_t *emit); STATIC void emit_native_global_exc_exit(emit_t *emit); +STATIC void emit_native_load_const_obj(emit_t *emit, mp_obj_t obj); emit_t *EXPORT_FUN(new)(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels) { emit_t *emit = m_new0(emit_t, 1); @@ -280,11 +286,29 @@ STATIC void emit_native_mov_reg_state_addr(emit_t *emit, int reg_dest, int local } STATIC void emit_native_mov_reg_qstr(emit_t *emit, int arg_reg, qstr qst) { + #if MICROPY_PERSISTENT_CODE_SAVE + size_t loc = ASM_MOV_REG_IMM_FIX_U16(emit->as, arg_reg, qst); + size_t link_idx = emit->qstr_link_cur++; + if (emit->pass == MP_PASS_EMIT) { + emit->qstr_link[link_idx].off = loc << 2 | 1; + emit->qstr_link[link_idx].qst = qst; + } + #else ASM_MOV_REG_IMM(emit->as, arg_reg, qst); + #endif } STATIC void emit_native_mov_reg_qstr_obj(emit_t *emit, int reg_dest, qstr qst) { + #if MICROPY_PERSISTENT_CODE_SAVE + size_t loc = ASM_MOV_REG_IMM_FIX_WORD(emit->as, reg_dest, (mp_uint_t)MP_OBJ_NEW_QSTR(qst)); + size_t link_idx = emit->qstr_link_cur++; + if (emit->pass == MP_PASS_EMIT) { + emit->qstr_link[link_idx].off = loc << 2 | 2; + emit->qstr_link[link_idx].qst = qst; + } + #else ASM_MOV_REG_IMM(emit->as, reg_dest, (mp_uint_t)MP_OBJ_NEW_QSTR(qst)); + #endif } #define emit_native_mov_state_imm_via(emit, local_num, imm, reg_temp) \ @@ -301,6 +325,9 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop emit->stack_size = 0; emit->const_table_cur_obj = 0; emit->const_table_cur_raw_code = 0; + #if MICROPY_PERSISTENT_CODE_SAVE + emit->qstr_link_cur = 0; + #endif emit->last_emit_was_return_value = false; emit->scope = scope; @@ -598,6 +625,13 @@ STATIC void emit_native_end_pass(emit_t *emit) { emit->const_table = m_new(mp_uint_t, const_table_alloc); // Store mp_fun_table pointer just after qstrs emit->const_table[nqstr] = (mp_uint_t)(uintptr_t)mp_fun_table; + + #if MICROPY_PERSISTENT_CODE_SAVE + size_t qstr_link_alloc = emit->qstr_link_cur; + if (qstr_link_alloc > 0) { + emit->qstr_link = m_new(mp_qstr_link_entry_t, qstr_link_alloc); + } + #endif } if (emit->pass == MP_PASS_EMIT) { @@ -607,6 +641,11 @@ STATIC void emit_native_end_pass(emit_t *emit) { mp_emit_glue_assign_native(emit->scope->raw_code, emit->do_viper_types ? MP_CODE_NATIVE_VIPER : MP_CODE_NATIVE_PY, f, f_len, emit->const_table, + #if MICROPY_PERSISTENT_CODE_SAVE + emit->prelude_offset, + emit->const_table_cur_obj, emit->const_table_cur_raw_code, + emit->qstr_link_cur, emit->qstr_link, + #endif emit->scope->num_pos_args, emit->scope->scope_flags, 0); } } @@ -1233,7 +1272,11 @@ STATIC void emit_native_import(emit_t *emit, qstr qst, int kind) { STATIC void emit_native_load_const_tok(emit_t *emit, mp_token_kind_t tok) { DEBUG_printf("load_const_tok(tok=%u)\n", tok); if (tok == MP_TOKEN_ELLIPSIS) { + #if MICROPY_PERSISTENT_CODE_SAVE + emit_native_load_const_obj(emit, MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj)); + #else emit_post_push_imm(emit, VTYPE_PYOBJ, (mp_uint_t)MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj)); + #endif } else { emit_native_pre(emit); if (tok == MP_TOKEN_KW_NONE) { diff --git a/py/persistentcode.c b/py/persistentcode.c index d4ca50e81f..78849fedff 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -47,6 +47,10 @@ #define MPY_FEATURE_ENCODE_FLAGS(flags) (flags) #define MPY_FEATURE_DECODE_FLAGS(feat) ((feat) & 3) +// Macros to encode/decode native architecture to/from the feature byte +#define MPY_FEATURE_ENCODE_ARCH(arch) ((arch) << 2) +#define MPY_FEATURE_DECODE_ARCH(feat) ((feat) >> 2) + // The feature flag bits encode the compile-time config options that // affect the generate bytecode. #define MPY_FEATURE_FLAGS ( \ @@ -59,6 +63,21 @@ | ((MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC) << 1) \ ) +// Define the host architecture +#if MICROPY_EMIT_X86 +#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_X86) +#elif MICROPY_EMIT_X64 +#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_X64) +#elif MICROPY_EMIT_THUMB +#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7M) +#elif MICROPY_EMIT_ARM +#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV6) +#elif MICROPY_EMIT_XTENSA +#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_XTENSA) +#else +#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_NONE) +#endif + #if MICROPY_PERSISTENT_CODE_LOAD || (MICROPY_PERSISTENT_CODE_SAVE && !MICROPY_DYNAMIC_COMPILER) // The bytecode will depend on the number of bits in a small-int, and // this function computes that (could make it a fixed constant, but it @@ -135,7 +154,7 @@ typedef struct _bytecode_prelude_t { uint code_info_size; } bytecode_prelude_t; -#if MICROPY_PERSISTENT_CODE_SAVE +#if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_EMIT_NATIVE // ip will point to start of opcodes // ip2 will point to simple_name, source_file qstrs @@ -161,6 +180,42 @@ STATIC void extract_prelude(const byte **ip, const byte **ip2, bytecode_prelude_ #include "py/parsenum.h" +#if MICROPY_EMIT_NATIVE + +#if MICROPY_EMIT_THUMB +STATIC void asm_thumb_rewrite_mov(uint8_t *pc, uint16_t val) { + // high part + *(uint16_t*)pc = (*(uint16_t*)pc & 0xfbf0) | (val >> 1 & 0x0400) | (val >> 12); + // low part + *(uint16_t*)(pc + 2) = (*(uint16_t*)(pc + 2) & 0x0f00) | (val << 4 & 0x7000) | (val & 0x00ff); + +} +#endif + +STATIC void arch_link_qstr(uint8_t *pc, bool is_obj, qstr qst) { + mp_uint_t val = qst; + if (is_obj) { + val = (mp_uint_t)MP_OBJ_NEW_QSTR(qst); + } + #if MICROPY_EMIT_X86 || MICROPY_EMIT_X64 || MICROPY_EMIT_ARM || MICROPY_EMIT_XTENSA + pc[0] = val & 0xff; + pc[1] = (val >> 8) & 0xff; + pc[2] = (val >> 16) & 0xff; + pc[3] = (val >> 24) & 0xff; + #elif MICROPY_EMIT_THUMB + if (is_obj) { + // qstr object, movw and movt + asm_thumb_rewrite_mov(pc, val); // movw + asm_thumb_rewrite_mov(pc + 4, val >> 16); // movt + } else { + // qstr number, movw instruction + asm_thumb_rewrite_mov(pc, val); // movw + } + #endif +} + +#endif + STATIC int read_byte(mp_reader_t *reader) { return reader->readbyte(reader->data); } @@ -264,51 +319,155 @@ STATIC void load_bytecode(mp_reader_t *reader, qstr_window_t *qw, byte *ip, byte } STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { - // get bytecode size and allocate memory for it - size_t bc_len = read_uint(reader, NULL); - byte *bytecode = m_new(byte, bc_len); + // Load function kind and data length + size_t kind_len = read_uint(reader, NULL); + int kind = (kind_len & 3) + MP_CODE_BYTECODE; + size_t fun_data_len = kind_len >> 2; - // load prelude - byte *ip = bytecode; + #if !MICROPY_EMIT_NATIVE + if (kind != MP_CODE_BYTECODE) { + mp_raise_ValueError("incompatible .mpy file"); + } + #endif + + uint8_t *fun_data = NULL; byte *ip2; - bytecode_prelude_t prelude; - load_prelude(reader, &ip, &ip2, &prelude); + bytecode_prelude_t prelude = {0}; + #if MICROPY_EMIT_NATIVE + size_t prelude_offset; + mp_uint_t type_sig = 0; + size_t n_qstr_link = 0; + #endif - // load bytecode - load_bytecode(reader, qw, ip, bytecode + bc_len); + if (kind == MP_CODE_BYTECODE) { + // Allocate memory for the bytecode + fun_data = m_new(uint8_t, fun_data_len); - // load qstrs and link global qstr ids into bytecode - qstr simple_name = load_qstr(reader, qw); - qstr source_file = load_qstr(reader, qw); - ((byte*)ip2)[0] = simple_name; ((byte*)ip2)[1] = simple_name >> 8; - ((byte*)ip2)[2] = source_file; ((byte*)ip2)[3] = source_file >> 8; + // Load prelude + byte *ip = fun_data; + load_prelude(reader, &ip, &ip2, &prelude); - // load constant table - size_t n_obj = read_uint(reader, NULL); - size_t n_raw_code = read_uint(reader, NULL); - mp_uint_t *const_table = m_new(mp_uint_t, prelude.n_pos_args + prelude.n_kwonly_args + n_obj + n_raw_code); - mp_uint_t *ct = const_table; - for (size_t i = 0; i < prelude.n_pos_args + prelude.n_kwonly_args; ++i) { - *ct++ = (mp_uint_t)MP_OBJ_NEW_QSTR(load_qstr(reader, qw)); - } - for (size_t i = 0; i < n_obj; ++i) { - *ct++ = (mp_uint_t)load_obj(reader); - } - for (size_t i = 0; i < n_raw_code; ++i) { - *ct++ = (mp_uint_t)(uintptr_t)load_raw_code(reader, qw); + // Load bytecode + load_bytecode(reader, qw, ip, fun_data + fun_data_len); + + #if MICROPY_EMIT_NATIVE + } else { + // Allocate memory for native data and load it + size_t fun_alloc; + MP_PLAT_ALLOC_EXEC(fun_data_len, (void**)&fun_data, &fun_alloc); + read_bytes(reader, fun_data, fun_data_len); + + if (kind == MP_CODE_NATIVE_PY || kind == MP_CODE_NATIVE_VIPER) { + // Parse qstr link table and link native code + n_qstr_link = read_uint(reader, NULL); + for (size_t i = 0; i < n_qstr_link; ++i) { + size_t off = read_uint(reader, NULL); + qstr qst = load_qstr(reader, qw); + uint8_t *dest = fun_data + (off >> 2); + if ((off & 3) == 0) { + // Generic 16-bit link + dest[0] = qst & 0xff; + dest[1] = (qst >> 8) & 0xff; + } else { + // Architecture-specific link + arch_link_qstr(dest, (off & 3) == 2, qst); + } + } + } + + if (kind == MP_CODE_NATIVE_PY) { + // Extract prelude for later use + prelude_offset = read_uint(reader, NULL); + const byte *ip = fun_data + prelude_offset; + extract_prelude(&ip, (const byte**)&ip2, &prelude); + } else { + // Load basic scope info for viper and asm + prelude.scope_flags = read_uint(reader, NULL); + prelude.n_pos_args = 0; + prelude.n_kwonly_args = 0; + if (kind == MP_CODE_NATIVE_ASM) { + prelude.n_pos_args = read_uint(reader, NULL); + type_sig = read_uint(reader, NULL); + } + } + #endif } - // create raw_code and return it + if (kind == MP_CODE_BYTECODE || kind == MP_CODE_NATIVE_PY) { + // Load qstrs in prelude + qstr simple_name = load_qstr(reader, qw); + qstr source_file = load_qstr(reader, qw); + ip2[0] = simple_name; ip2[1] = simple_name >> 8; + ip2[2] = source_file; ip2[3] = source_file >> 8; + } + + mp_uint_t *const_table = NULL; + if (kind != MP_CODE_NATIVE_ASM) { + // Load constant table for bytecode, native and viper + + // Number of entries in constant table + size_t n_obj = read_uint(reader, NULL); + size_t n_raw_code = read_uint(reader, NULL); + + // Allocate constant table + size_t n_alloc = prelude.n_pos_args + prelude.n_kwonly_args + n_obj + n_raw_code; + if (kind != MP_CODE_BYTECODE) { + ++n_alloc; // additional entry for mp_fun_table + } + const_table = m_new(mp_uint_t, n_alloc); + mp_uint_t *ct = const_table; + + // Load function argument names (initial entries in const_table) + // (viper has n_pos_args=n_kwonly_args=0 so doesn't load any qstrs here) + for (size_t i = 0; i < prelude.n_pos_args + prelude.n_kwonly_args; ++i) { + *ct++ = (mp_uint_t)MP_OBJ_NEW_QSTR(load_qstr(reader, qw)); + } + + #if MICROPY_EMIT_NATIVE + if (kind != MP_CODE_BYTECODE) { + // Populate mp_fun_table entry + *ct++ = (mp_uint_t)(uintptr_t)mp_fun_table; + } + #endif + + // Load constant objects and raw code children + for (size_t i = 0; i < n_obj; ++i) { + *ct++ = (mp_uint_t)load_obj(reader); + } + for (size_t i = 0; i < n_raw_code; ++i) { + *ct++ = (mp_uint_t)(uintptr_t)load_raw_code(reader, qw); + } + } + + // Create raw_code and return it mp_raw_code_t *rc = mp_emit_glue_new_raw_code(); - mp_emit_glue_assign_bytecode(rc, bytecode, - #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS - bc_len, + if (kind == MP_CODE_BYTECODE) { + mp_emit_glue_assign_bytecode(rc, fun_data, + #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS + fun_data_len, + #endif + const_table, + #if MICROPY_PERSISTENT_CODE_SAVE + n_obj, n_raw_code, + #endif + prelude.scope_flags); + + #if MICROPY_EMIT_NATIVE + } else { + #if defined(MP_PLAT_COMMIT_EXEC) + fun_data = MP_PLAT_COMMIT_EXEC(fun_data, fun_data_len); #endif - const_table, - #if MICROPY_PERSISTENT_CODE_SAVE - n_obj, n_raw_code, - #endif - prelude.scope_flags); + + mp_emit_glue_assign_native(rc, kind, + fun_data, fun_data_len, const_table, + #if MICROPY_PERSISTENT_CODE_SAVE + prelude_offset, + n_obj, n_raw_code, + n_qstr_link, NULL, + #endif + prelude.n_pos_args, prelude.scope_flags, type_sig); + #endif + } return rc; } @@ -322,6 +481,10 @@ mp_raw_code_t *mp_raw_code_load(mp_reader_t *reader) { || read_uint(reader, NULL) > QSTR_WINDOW_SIZE) { mp_raise_ValueError("incompatible .mpy file"); } + if (MPY_FEATURE_DECODE_ARCH(header[2]) != MP_NATIVE_ARCH_NONE + && MPY_FEATURE_DECODE_ARCH(header[2]) != MPY_FEATURE_ARCH) { + mp_raise_ValueError("incompatible .mpy arch"); + } qstr_window_t qw; qw.idx = 0; mp_raw_code_t *rc = load_raw_code(reader, &qw); @@ -444,43 +607,110 @@ STATIC void save_bytecode(mp_print_t *print, qstr_window_t *qw, const byte *ip, } STATIC void save_raw_code(mp_print_t *print, mp_raw_code_t *rc, qstr_window_t *qstr_window) { - if (rc->kind != MP_CODE_BYTECODE) { - mp_raise_ValueError("can only save bytecode"); + // Save function kind and data length + mp_print_uint(print, (rc->fun_data_len << 2) | (rc->kind - MP_CODE_BYTECODE)); + + const byte *ip2; + bytecode_prelude_t prelude; + + if (rc->kind == MP_CODE_BYTECODE) { + // Save prelude + const byte *ip = rc->fun_data; + extract_prelude(&ip, &ip2, &prelude); + size_t prelude_len = ip - (const byte*)rc->fun_data; + const byte *ip_top = (const byte*)rc->fun_data + rc->fun_data_len; + mp_print_bytes(print, rc->fun_data, prelude_len); + + // Save bytecode + save_bytecode(print, qstr_window, ip, ip_top); + } else { + // Save native code + mp_print_bytes(print, rc->fun_data, rc->fun_data_len); + + if (rc->kind == MP_CODE_NATIVE_PY || rc->kind == MP_CODE_NATIVE_VIPER) { + // Save qstr link table for native code + mp_print_uint(print, rc->n_qstr); + for (size_t i = 0; i < rc->n_qstr; ++i) { + mp_print_uint(print, rc->qstr_link[i].off); + save_qstr(print, qstr_window, rc->qstr_link[i].qst); + } + } + + if (rc->kind == MP_CODE_NATIVE_PY) { + // Save prelude size, and extract prelude for later use + mp_print_uint(print, rc->prelude_offset); + const byte *ip = (const byte*)rc->fun_data + rc->prelude_offset; + extract_prelude(&ip, &ip2, &prelude); + } else { + // Save basic scope info for viper and asm + mp_print_uint(print, rc->scope_flags); + prelude.n_pos_args = 0; + prelude.n_kwonly_args = 0; + if (rc->kind == MP_CODE_NATIVE_ASM) { + mp_print_uint(print, rc->n_pos_args); + mp_print_uint(print, rc->type_sig); + } + } + } + + if (rc->kind == MP_CODE_BYTECODE || rc->kind == MP_CODE_NATIVE_PY) { + // Save qstrs in prelude + save_qstr(print, qstr_window, ip2[0] | (ip2[1] << 8)); // simple_name + save_qstr(print, qstr_window, ip2[2] | (ip2[3] << 8)); // source_file + } + + if (rc->kind != MP_CODE_NATIVE_ASM) { + // Save constant table for bytecode, native and viper + + // Number of entries in constant table + mp_print_uint(print, rc->n_obj); + mp_print_uint(print, rc->n_raw_code); + + const mp_uint_t *const_table = rc->const_table; + + // Save function argument names (initial entries in const_table) + // (viper has n_pos_args=n_kwonly_args=0 so doesn't save any qstrs here) + for (size_t i = 0; i < prelude.n_pos_args + prelude.n_kwonly_args; ++i) { + mp_obj_t o = (mp_obj_t)*const_table++; + save_qstr(print, qstr_window, MP_OBJ_QSTR_VALUE(o)); + } + + if (rc->kind != MP_CODE_BYTECODE) { + // Skip saving mp_fun_table entry + ++const_table; + } + + // Save constant objects and raw code children + for (size_t i = 0; i < rc->n_obj; ++i) { + save_obj(print, (mp_obj_t)*const_table++); + } + for (size_t i = 0; i < rc->n_raw_code; ++i) { + save_raw_code(print, (mp_raw_code_t*)(uintptr_t)*const_table++, qstr_window); + } + } +} + +STATIC bool mp_raw_code_has_native(mp_raw_code_t *rc) { + if (rc->kind != MP_CODE_BYTECODE) { + return true; } - // extract prelude const byte *ip = rc->fun_data; const byte *ip2; bytecode_prelude_t prelude; extract_prelude(&ip, &ip2, &prelude); - // save prelude - size_t prelude_len = ip - rc->fun_data; - const byte *ip_top = rc->fun_data + rc->fun_data_len; - mp_print_uint(print, rc->fun_data_len); - mp_print_bytes(print, rc->fun_data, prelude_len); + const mp_uint_t *const_table = rc->const_table + + prelude.n_pos_args + prelude.n_kwonly_args + + rc->n_obj; - // save bytecode - save_bytecode(print, qstr_window, ip, ip_top); + for (size_t i = 0; i < rc->n_raw_code; ++i) { + if (mp_raw_code_has_native((mp_raw_code_t*)(uintptr_t)*const_table++)) { + return true; + } + } - // save qstrs - save_qstr(print, qstr_window, ip2[0] | (ip2[1] << 8)); // simple_name - save_qstr(print, qstr_window, ip2[2] | (ip2[3] << 8)); // source_file - - // save constant table - mp_print_uint(print, rc->n_obj); - mp_print_uint(print, rc->n_raw_code); - const mp_uint_t *const_table = rc->const_table; - for (uint i = 0; i < prelude.n_pos_args + prelude.n_kwonly_args; ++i) { - mp_obj_t o = (mp_obj_t)*const_table++; - save_qstr(print, qstr_window, MP_OBJ_QSTR_VALUE(o)); - } - for (uint i = 0; i < rc->n_obj; ++i) { - save_obj(print, (mp_obj_t)*const_table++); - } - for (uint i = 0; i < rc->n_raw_code; ++i) { - save_raw_code(print, (mp_raw_code_t*)(uintptr_t)*const_table++, qstr_window); - } + return false; } void mp_raw_code_save(mp_raw_code_t *rc, mp_print_t *print) { @@ -500,6 +730,9 @@ void mp_raw_code_save(mp_raw_code_t *rc, mp_print_t *print) { mp_small_int_bits(), #endif }; + if (mp_raw_code_has_native(rc)) { + header[2] |= MPY_FEATURE_ENCODE_ARCH(MPY_FEATURE_ARCH); + } mp_print_bytes(print, header, sizeof(header)); mp_print_uint(print, QSTR_WINDOW_SIZE); diff --git a/py/persistentcode.h b/py/persistentcode.h index d04e0b6330..b27c3de2f0 100644 --- a/py/persistentcode.h +++ b/py/persistentcode.h @@ -30,6 +30,19 @@ #include "py/reader.h" #include "py/emitglue.h" +enum { + MP_NATIVE_ARCH_NONE = 0, + MP_NATIVE_ARCH_X86, + MP_NATIVE_ARCH_X64, + MP_NATIVE_ARCH_ARMV6, + MP_NATIVE_ARCH_ARMV6M, + MP_NATIVE_ARCH_ARMV7M, + MP_NATIVE_ARCH_ARMV7EM, + MP_NATIVE_ARCH_ARMV7EMSP, + MP_NATIVE_ARCH_ARMV7EMDP, + MP_NATIVE_ARCH_XTENSA, +}; + mp_raw_code_t *mp_raw_code_load(mp_reader_t *reader); mp_raw_code_t *mp_raw_code_load_mem(const byte *buf, size_t len); mp_raw_code_t *mp_raw_code_load_file(const char *filename); From ea3c80a514c5dc4cc3a8349815eceec4fa1ac57f Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 21 Feb 2019 15:18:59 +1100 Subject: [PATCH 0177/1788] tools/mpy-tool.py: Add support for freezing native code. This adds support to freeze .mpy files that contain native code blocks. --- tools/mpy-tool.py | 301 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 246 insertions(+), 55 deletions(-) diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index 37adaf3556..318343227c 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -87,6 +87,22 @@ class QStrWindow: self.window = [val] + self.window[:idx] + self.window[idx + 1:] return val +MP_CODE_BYTECODE = 2 +MP_CODE_NATIVE_PY = 3 +MP_CODE_NATIVE_VIPER = 4 +MP_CODE_NATIVE_ASM = 5 + +MP_NATIVE_ARCH_NONE = 0 +MP_NATIVE_ARCH_X86 = 1 +MP_NATIVE_ARCH_X64 = 2 +MP_NATIVE_ARCH_ARMV6 = 3 +MP_NATIVE_ARCH_ARMV6M = 4 +MP_NATIVE_ARCH_ARMV7M = 5 +MP_NATIVE_ARCH_ARMV7EM = 6 +MP_NATIVE_ARCH_ARMV7EMSP = 7 +MP_NATIVE_ARCH_ARMV7EMDP = 8 +MP_NATIVE_ARCH_XTENSA = 9 + MP_OPCODE_BYTE = 0 MP_OPCODE_QSTR = 1 MP_OPCODE_VAR_UINT = 2 @@ -224,8 +240,7 @@ def decode_uint(bytecode, ip): break return ip, unum -def extract_prelude(bytecode): - ip = 0 +def extract_prelude(bytecode, ip): ip, n_state = decode_uint(bytecode, ip) ip, n_exc_stack = decode_uint(bytecode, ip) scope_flags = bytecode[ip]; ip += 1 @@ -241,21 +256,39 @@ def extract_prelude(bytecode): # ip2 points to simple_name qstr return ip, ip2, (n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args, code_info_size) +class MPFunTable: + pass + class RawCode: # a set of all escaped names, to make sure they are unique escaped_names = set() - def __init__(self, bytecode, qstrs, objs, raw_codes): + # convert code kind number to string + code_kind_str = { + MP_CODE_BYTECODE: 'MP_CODE_BYTECODE', + MP_CODE_NATIVE_PY: 'MP_CODE_NATIVE_PY', + MP_CODE_NATIVE_VIPER: 'MP_CODE_NATIVE_VIPER', + MP_CODE_NATIVE_ASM: 'MP_CODE_NATIVE_ASM', + } + + def __init__(self, code_kind, bytecode, prelude_offset, qstrs, objs, raw_codes): # set core variables + self.code_kind = code_kind self.bytecode = bytecode + self.prelude_offset = prelude_offset self.qstrs = qstrs self.objs = objs self.raw_codes = raw_codes - # extract prelude - self.ip, self.ip2, self.prelude = extract_prelude(self.bytecode) - self.simple_name = self._unpack_qstr(self.ip2) - self.source_file = self._unpack_qstr(self.ip2 + 2) + if self.prelude_offset is None: + # no prelude, assign a dummy simple_name + self.prelude_offset = 0 + self.simple_name = global_qstrs[1] + else: + # extract prelude + self.ip, self.ip2, self.prelude = extract_prelude(self.bytecode, self.prelude_offset) + self.simple_name = self._unpack_qstr(self.ip2) + self.source_file = self._unpack_qstr(self.ip2 + 2) def _unpack_qstr(self, ip): qst = self.bytecode[ip] | self.bytecode[ip + 1] << 8 @@ -267,7 +300,7 @@ class RawCode: rc.freeze('') # TODO - def freeze(self, parent_name): + def freeze_children(self, parent_name): self.escaped_name = parent_name + self.simple_name.qstr_esc # make sure the escaped name is unique @@ -281,39 +314,13 @@ class RawCode: for rc in self.raw_codes: rc.freeze(self.escaped_name + '_') - # generate bytecode data - print() - print('// frozen bytecode for file %s, scope %s%s' % (self.source_file.str, parent_name, self.simple_name.str)) - print('STATIC ', end='') - if not config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE: - print('const ', end='') - print('byte bytecode_data_%s[%u] = {' % (self.escaped_name, len(self.bytecode))) - print(' ', end='') - for i in range(self.ip2): - print(' 0x%02x,' % self.bytecode[i], end='') - print() - print(' ', self.simple_name.qstr_id, '& 0xff,', self.simple_name.qstr_id, '>> 8,') - print(' ', self.source_file.qstr_id, '& 0xff,', self.source_file.qstr_id, '>> 8,') - print(' ', end='') - for i in range(self.ip2 + 4, self.ip): - print(' 0x%02x,' % self.bytecode[i], end='') - print() - ip = self.ip - while ip < len(self.bytecode): - f, sz = mp_opcode_format(self.bytecode, ip, True) - if f == 1: - qst = self._unpack_qstr(ip + 1).qstr_id - extra = '' if sz == 3 else ' 0x%02x,' % self.bytecode[ip + 3] - print(' ', '0x%02x,' % self.bytecode[ip], qst, '& 0xff,', qst, '>> 8,', extra) - else: - print(' ', ''.join('0x%02x, ' % self.bytecode[ip + i] for i in range(sz))) - ip += sz - print('};') - + def freeze_constants(self): # generate constant objects for i, obj in enumerate(self.objs): obj_name = 'const_obj_%s_%u' % (self.escaped_name, i) - if obj is Ellipsis: + if obj is MPFunTable: + pass + elif 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): @@ -366,7 +373,9 @@ class RawCode: for qst in self.qstrs: print(' MP_ROM_QSTR(%s),' % global_qstrs[qst].qstr_id) for i in range(len(self.objs)): - if type(self.objs[i]) is float: + if self.objs[i] is MPFunTable: + print(' mp_fun_table,') + elif type(self.objs[i]) is float: print('#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B') print(' MP_ROM_PTR(&const_obj_%s_%u),' % (self.escaped_name, i)) print('#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C') @@ -384,15 +393,16 @@ class RawCode: print(' MP_ROM_PTR(&raw_code_%s),' % rc.escaped_name) print('};') + def freeze_module(self, qstr_links=(), type_sig=0): # generate module if self.simple_name.str != '': print('STATIC ', end='') print('const mp_raw_code_t raw_code_%s = {' % self.escaped_name) - print(' .kind = MP_CODE_BYTECODE,') + print(' .kind = %s,' % RawCode.code_kind_str[self.code_kind]) print(' .scope_flags = 0x%02x,' % self.prelude[2]) print(' .n_pos_args = %u,' % self.prelude[3]) - print(' .fun_data = bytecode_data_%s,' % self.escaped_name) - if const_table_len: + print(' .fun_data = fun_data_%s,' % self.escaped_name) + if len(self.qstrs) + len(self.objs) + len(self.raw_codes): print(' .const_table = (mp_uint_t*)const_table_data_%s,' % self.escaped_name) else: print(' .const_table = NULL,') @@ -400,9 +410,147 @@ class RawCode: print(' .fun_data_len = %u,' % len(self.bytecode)) print(' .n_obj = %u,' % len(self.objs)) print(' .n_raw_code = %u,' % len(self.raw_codes)) + print(' #if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM') + print(' .prelude_offset = %u,' % self.prelude_offset) + print(' .n_qstr = %u,' % len(qstr_links)) + print(' .qstr_link = NULL,') # TODO + print(' #endif') + print(' #endif') + print(' #if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM') + print(' .type_sig = %u,' % type_sig) print(' #endif') print('};') +class RawCodeBytecode(RawCode): + def __init__(self, bytecode, qstrs, objs, raw_codes): + super().__init__(MP_CODE_BYTECODE, bytecode, 0, qstrs, objs, raw_codes) + + def freeze(self, parent_name): + self.freeze_children(parent_name) + + # generate bytecode data + print() + print('// frozen bytecode for file %s, scope %s%s' % (self.source_file.str, parent_name, self.simple_name.str)) + print('STATIC ', end='') + if not config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE: + print('const ', end='') + print('byte fun_data_%s[%u] = {' % (self.escaped_name, len(self.bytecode))) + print(' ', end='') + for i in range(self.ip2): + print(' 0x%02x,' % self.bytecode[i], end='') + print() + print(' ', self.simple_name.qstr_id, '& 0xff,', self.simple_name.qstr_id, '>> 8,') + print(' ', self.source_file.qstr_id, '& 0xff,', self.source_file.qstr_id, '>> 8,') + print(' ', end='') + for i in range(self.ip2 + 4, self.ip): + print(' 0x%02x,' % self.bytecode[i], end='') + print() + ip = self.ip + while ip < len(self.bytecode): + f, sz = mp_opcode_format(self.bytecode, ip, True) + if f == 1: + qst = self._unpack_qstr(ip + 1).qstr_id + extra = '' if sz == 3 else ' 0x%02x,' % self.bytecode[ip + 3] + print(' ', '0x%02x,' % self.bytecode[ip], qst, '& 0xff,', qst, '>> 8,', extra) + else: + print(' ', ''.join('0x%02x, ' % self.bytecode[ip + i] for i in range(sz))) + ip += sz + print('};') + + self.freeze_constants() + self.freeze_module() + +class RawCodeNative(RawCode): + def __init__(self, code_kind, fun_data, prelude_offset, prelude, qstr_links, qstrs, objs, raw_codes, type_sig): + super().__init__(code_kind, fun_data, prelude_offset, qstrs, objs, raw_codes) + self.prelude = prelude + self.qstr_links = qstr_links + self.type_sig = type_sig + if config.native_arch in (MP_NATIVE_ARCH_X86, MP_NATIVE_ARCH_X64): + self.fun_data_attributes = '__attribute__((section(".text,\\"ax\\",@progbits # ")))' + else: + self.fun_data_attributes = '__attribute__((section(".text,\\"ax\\",%progbits @ ")))' + + def _asm_thumb_rewrite_mov(self, pc, val): + print(' (%u & 0xf0) | (%s >> 12),' % (self.bytecode[pc], val), end='') + print(' (%u & 0xfb) | (%s >> 9 & 0x04),' % (self.bytecode[pc + 1], val), end='') + print(' (%s & 0xff),' % (val,), end='') + print(' (%u & 0x07) | (%s >> 4 & 0x70),' % (self.bytecode[pc + 3], val)) + + def _link_qstr(self, pc, kind, qst): + if kind == 0: + print(' %s & 0xff, %s >> 8,' % (qst, qst)) + else: + if kind == 2: + qst = '((uintptr_t)MP_OBJ_NEW_QSTR(%s))' % qst + if config.native_arch in (MP_NATIVE_ARCH_X86, MP_NATIVE_ARCH_X64): + print(' %s & 0xff, %s >> 8, 0, 0,' % (qst, qst)) + elif MP_NATIVE_ARCH_ARMV6M <= config.native_arch <= MP_NATIVE_ARCH_ARMV7EMDP: + if is_obj: + self._asm_thumb_rewrite_mov(i, qst) + self._asm_thumb_rewrite_mov(i + 4, '(%s >> 16)' % qst) + else: + self._asm_thumb_rewrite_mov(i, qst) + else: + assert 0 + + def freeze(self, parent_name): + self.freeze_children(parent_name) + + # generate native code data + print() + if self.code_kind == MP_CODE_NATIVE_PY: + print('// frozen native code for file %s, scope %s%s' % (self.source_file.str, parent_name, self.simple_name.str)) + elif self.code_kind == MP_CODE_NATIVE_VIPER: + print('// frozen viper code for scope %s' % (parent_name,)) + else: + print('// frozen assembler code for scope %s' % (parent_name,)) + print('STATIC const byte fun_data_%s[%u] %s = {' % (self.escaped_name, len(self.bytecode), self.fun_data_attributes)) + + if self.code_kind == MP_CODE_NATIVE_PY: + i_top = self.prelude_offset + else: + i_top = len(self.bytecode) + i = 0 + qi = 0 + while i < i_top: + if qi < len(self.qstr_links) and i == self.qstr_links[qi][0]: + # link qstr + qi_off, qi_kind, qi_val = self.qstr_links[qi] + qst = global_qstrs[qi_val].qstr_id + self._link_qstr(i, qi_kind, qst) + i += 4 + qi += 1 + else: + # copy machine code (max 16 bytes) + i16 = min(i + 16, i_top) + if qi < len(self.qstr_links): + i16 = min(i16, self.qstr_links[qi][0]) + print(' ', end='') + for ii in range(i, i16): + print(' 0x%02x,' % self.bytecode[ii], end='') + print() + i = i16 + + if self.code_kind == MP_CODE_NATIVE_PY: + print(' ', end='') + for i in range(self.prelude_offset, self.ip2): + print(' 0x%02x,' % self.bytecode[i], end='') + print() + + print(' ', self.simple_name.qstr_id, '& 0xff,', self.simple_name.qstr_id, '>> 8,') + print(' ', self.source_file.qstr_id, '& 0xff,', self.source_file.qstr_id, '>> 8,') + + print(' ', end='') + for i in range(self.ip2 + 4, self.ip): + print(' 0x%02x,' % self.bytecode[i], end='') + print() + + print('};') + + self.freeze_constants() + self.freeze_module(self.qstr_links, self.type_sig) + class BytecodeBuffer: def __init__(self, size): self.buf = bytearray(size) @@ -500,19 +648,61 @@ def read_bytecode(file, bytecode, qstr_win): read_byte(file, bytecode) def read_raw_code(f, qstr_win): - bc_len = read_uint(f) - bytecode = BytecodeBuffer(bc_len) - name_idx, prelude = read_prelude(f, bytecode) - read_bytecode(f, bytecode, qstr_win) - bytecode.idx = name_idx # rewind to where qstrs are in prelude - read_qstr_and_pack(f, bytecode, qstr_win) # simple_name - read_qstr_and_pack(f, bytecode, qstr_win) # source_file - n_obj = read_uint(f) - n_raw_code = read_uint(f) - qstrs = [read_qstr(f, qstr_win) for _ in range(prelude[3] + prelude[4])] - objs = [read_obj(f) for _ in range(n_obj)] - raw_codes = [read_raw_code(f, qstr_win) for _ in range(n_raw_code)] - return RawCode(bytecode.buf, qstrs, objs, raw_codes) + kind_len = read_uint(f) + kind = (kind_len & 3) + MP_CODE_BYTECODE + fun_data_len = kind_len >> 2 + fun_data = BytecodeBuffer(fun_data_len) + + if kind == MP_CODE_BYTECODE: + name_idx, prelude = read_prelude(f, fun_data) + read_bytecode(f, fun_data, qstr_win) + else: + fun_data.buf[:] = f.read(fun_data_len) + + qstr_links = [] + if kind in (MP_CODE_NATIVE_PY, MP_CODE_NATIVE_VIPER): + # load qstr link table + n_qstr_link = read_uint(f) + for _ in range(n_qstr_link): + off = read_uint(f, qstr_win) + qst = read_qstr(f, qstr_win) + qstr_links.append((off >> 2, off & 3, qst)) + + type_sig = 0 + if kind == MP_CODE_NATIVE_PY: + prelude_offset = read_uint(f) + _, name_idx, prelude = extract_prelude(fun_data.buf, prelude_offset) + else: + prelude_offset = None + scope_flags = read_uint(f) + n_pos_args = 0 + if kind == MP_CODE_NATIVE_ASM: + n_pos_args = read_uint(f) + type_sig = read_uint(f) + prelude = (None, None, scope_flags, n_pos_args, 0) + + if kind in (MP_CODE_BYTECODE, MP_CODE_NATIVE_PY): + fun_data.idx = name_idx # rewind to where qstrs are in prelude + read_qstr_and_pack(f, fun_data, qstr_win) # simple_name + read_qstr_and_pack(f, fun_data, qstr_win) # source_file + + qstrs = [] + objs = [] + raw_codes = [] + if kind != MP_CODE_NATIVE_ASM: + # load constant table + n_obj = read_uint(f) + n_raw_code = read_uint(f) + qstrs = [read_qstr(f, qstr_win) for _ in range(prelude[3] + prelude[4])] + if kind != MP_CODE_BYTECODE: + objs.append(MPFunTable) + objs.extend([read_obj(f) for _ in range(n_obj)]) + raw_codes = [read_raw_code(f, qstr_win) for _ in range(n_raw_code)] + + if kind == MP_CODE_BYTECODE: + return RawCodeBytecode(fun_data.buf, qstrs, objs, raw_codes) + else: + return RawCodeNative(kind, fun_data.buf, prelude_offset, prelude, qstr_links, qstrs, objs, raw_codes, type_sig) def read_mpy(filename): with open(filename, 'rb') as f: @@ -525,6 +715,7 @@ def read_mpy(filename): qw_size = read_uint(f) config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE = (feature_byte & 1) != 0 config.MICROPY_PY_BUILTINS_STR_UNICODE = (feature_byte & 2) != 0 + config.native_arch = feature_byte >> 2 config.mp_small_int_bits = header[3] qstr_win = QStrWindow(qw_size) return read_raw_code(f, qstr_win) From 9a5f92ea72754c01cc03e5efcdfe94021120531e Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 7 Mar 2019 17:13:24 +1100 Subject: [PATCH 0178/1788] py/persistentcode: Bump .mpy version to 4. --- py/persistentcode.c | 2 +- tools/mpy-tool.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/py/persistentcode.c b/py/persistentcode.c index 78849fedff..ad502a5116 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -41,7 +41,7 @@ #define QSTR_LAST_STATIC MP_QSTR_zip // The current version of .mpy files -#define MPY_VERSION (3) +#define MPY_VERSION (4) // Macros to encode/decode flags to/from the feature byte #define MPY_FEATURE_ENCODE_FLAGS(flags) (flags) diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index 318343227c..ff31a61bde 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -57,7 +57,7 @@ class FreezeError(Exception): return 'error while freezing %s: %s' % (self.rawcode.source_file, self.msg) class Config: - MPY_VERSION = 3 + MPY_VERSION = 4 MICROPY_LONGINT_IMPL_NONE = 0 MICROPY_LONGINT_IMPL_LONGLONG = 1 MICROPY_LONGINT_IMPL_MPZ = 2 From 7852b287df0d012f8600dc7d3e6f352fb5925a88 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 7 Mar 2019 17:14:18 +1100 Subject: [PATCH 0179/1788] minimal/frozentest: Recompile now that mpy format and version changed. --- ports/minimal/frozentest.mpy | Bin 206 -> 207 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/ports/minimal/frozentest.mpy b/ports/minimal/frozentest.mpy index 3b5e0fee15024a08a20a63ab3a6f15a868066190..08d7385322f415230c3a23b9597975bf7c42f87e 100644 GIT binary patch delta 25 gcmX@dc%D(vmxW1Qp{anGL4kpRftQ_ueWJiV07YE{(f|Me delta 24 dcmX@lc#cuPmzhakA%>X&1bEpQSSAYY0{}SI1Q-AS From 31d2d83e79828552363732e0a118a6e61d8c196b Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 21 Feb 2019 15:19:24 +1100 Subject: [PATCH 0180/1788] mpy-cross: Enable building of x64 native .mpy files. --- mpy-cross/gccollect.c | 3 --- mpy-cross/mpconfigport.h | 4 +++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/mpy-cross/gccollect.c b/mpy-cross/gccollect.c index 75891a2fb5..9e4b59d9ef 100644 --- a/mpy-cross/gccollect.c +++ b/mpy-cross/gccollect.c @@ -143,9 +143,6 @@ void gc_collect(void) { // GC stack (and regs because we captured them) void **regs_ptr = (void**)(void*)®s; gc_collect_root(regs_ptr, ((mp_uint_t)MP_STATE_THREAD(stack_top) - (mp_uint_t)®s) / sizeof(mp_uint_t)); - #if MICROPY_EMIT_NATIVE - mp_unix_mark_exec(); - #endif gc_collect_end(); } diff --git a/mpy-cross/mpconfigport.h b/mpy-cross/mpconfigport.h index e227d1be54..21ddfcf6a7 100644 --- a/mpy-cross/mpconfigport.h +++ b/mpy-cross/mpconfigport.h @@ -30,13 +30,15 @@ #define MICROPY_PERSISTENT_CODE_LOAD (0) #define MICROPY_PERSISTENT_CODE_SAVE (1) -#define MICROPY_EMIT_X64 (0) +#define MICROPY_EMIT_X64 (1) #define MICROPY_EMIT_X86 (0) #define MICROPY_EMIT_THUMB (0) #define MICROPY_EMIT_INLINE_THUMB (0) #define MICROPY_EMIT_INLINE_THUMB_ARMV7M (0) #define MICROPY_EMIT_INLINE_THUMB_FLOAT (0) #define MICROPY_EMIT_ARM (0) +#define MICROPY_EMIT_XTENSA (0) +#define MICROPY_EMIT_INLINE_XTENSA (0) #define MICROPY_DYNAMIC_COMPILER (1) #define MICROPY_COMP_CONST_FOLDING (1) From 69955238a23b0a9c6e8d1ba6cbacd81f986efa19 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 25 Feb 2019 00:19:43 +1100 Subject: [PATCH 0181/1788] tests/run-tests: Support running native tests via mpy. --- tests/run-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-tests b/tests/run-tests index 62af90f28c..bf5c97c2b6 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -121,7 +121,7 @@ def run_micropython(pyb, args, test_file, is_special=False): # if running via .mpy, first compile the .py file if args.via_mpy: - subprocess.check_output([MPYCROSS, '-mcache-lookup-bc', '-o', 'mpytest.mpy', test_file]) + subprocess.check_output([MPYCROSS, '-mcache-lookup-bc', '-o', 'mpytest.mpy', '-X', 'emit=' + args.emit, test_file]) cmdlist.extend(['-m', 'mpytest']) else: cmdlist.append(test_file) From 2bcb240b559ff440d7f008b93bb626f7d7f33cf3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 25 Feb 2019 00:20:05 +1100 Subject: [PATCH 0182/1788] travis: Enable test for running native code via mpy. --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index be81d6aa23..0ba9a00223 100644 --- a/.travis.yml +++ b/.travis.yml @@ -66,7 +66,8 @@ jobs: - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests) - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests -d thread) - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --emit native) - - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --via-mpy -d basics float) + - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --via-mpy -d basics float micropython) + - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --via-mpy --emit native -d basics float micropython) # 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) From 6e11d8631821d7e8bf7c6b1feab11b83f2a8577a Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 25 Feb 2019 00:20:52 +1100 Subject: [PATCH 0183/1788] tools/upip.py: Use "raise arg" instead of no-arg raise form, for native. --- tools/upip.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/upip.py b/tools/upip.py index a400c31743..7ecf61e54b 100644 --- a/tools/upip.py +++ b/tools/upip.py @@ -55,7 +55,7 @@ def _makedirs(name, mode=0o777): ret = True except OSError as e: if e.args[0] != errno.EEXIST and e.args[0] != errno.EISDIR: - raise + raise e ret = False return ret From c6a9bb23cd3ad4ae5f6cabfcd1952f39d46bce94 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 7 Mar 2019 22:52:07 +1100 Subject: [PATCH 0184/1788] unix/Makefile: Update coverage tests to match those in Travis. --- ports/unix/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ports/unix/Makefile b/ports/unix/Makefile index be45513c31..41552bf5c9 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -258,7 +258,8 @@ coverage_test: coverage cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests 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 + cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests --via-mpy -d basics float micropython + cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests --via-mpy --emit native -d basics float micropython 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 1e23a29c8a9c8d0e6288efd20759778608cb1da3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 8 Mar 2019 16:47:46 +1100 Subject: [PATCH 0185/1788] tests/import: Add test for importing x64 native code. --- tests/import/mpy_native.py | 93 ++++++++++++++++++++++++++++++++++ tests/import/mpy_native.py.exp | 2 + 2 files changed, 95 insertions(+) create mode 100644 tests/import/mpy_native.py create mode 100644 tests/import/mpy_native.py.exp diff --git a/tests/import/mpy_native.py b/tests/import/mpy_native.py new file mode 100644 index 0000000000..e03d14e2ed --- /dev/null +++ b/tests/import/mpy_native.py @@ -0,0 +1,93 @@ +# test importing of .mpy files with native code (x64 only) + +import sys, uio + +try: + uio.IOBase + import uos + uos.mount +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + +if not (sys.platform == 'linux' and sys.maxsize > 2 ** 32): + 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 = { + # bad architecture + '/mod0.mpy': b'M\x04\xff\x00\x10', + + # test loading of viper and asm + '/mod1.mpy': ( + b'M\x04\x0b\x1f\x20' # header + + b'\x38' # n bytes, bytecode + b'\x01\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\xff' # prelude + b'\x11' # LOAD_CONST_NONE + b'\x5b' # RETURN_VALUE + + b'\x02m\x02m\x00\x02' # simple_name, source_file, n_obj, n_raw_code + + b'\x22' # n bytes, viper code + b'\x00\x00\x00\x00\x00\x00' # dummy machine code + b'\x00\x00' # qstr0 + b'\x01\x0c\x0aprint' # n_qstr, qstr0 + b'\x00\x00\x00' # scope_flags, n_obj, n_raw_code + + b'\x23' # n bytes, asm code + b'\x00\x00\x00\x00\x00\x00\x00\x00' # dummy machine code + b'\x00\x00\x00' # scope_flags, n_pos_args, type_sig + ), +} + +# 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) + print(mod, 'OK') + 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_native.py.exp b/tests/import/mpy_native.py.exp new file mode 100644 index 0000000000..b73812094a --- /dev/null +++ b/tests/import/mpy_native.py.exp @@ -0,0 +1,2 @@ +mod0 ValueError incompatible .mpy arch +mod1 OK From e4ac104b7f2980114c6d1b0d8ff5917777cf8f24 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 8 Mar 2019 22:29:54 +1100 Subject: [PATCH 0186/1788] stm32: Allow to build with threading with the GIL disabled. --- ports/stm32/gccollect.c | 2 +- ports/stm32/mpthreadport.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ports/stm32/gccollect.c b/ports/stm32/gccollect.c index d92fc5cef0..5c1bf1e06d 100644 --- a/ports/stm32/gccollect.c +++ b/ports/stm32/gccollect.c @@ -27,7 +27,7 @@ #include #include -#include "py/obj.h" +#include "py/mpstate.h" #include "py/gc.h" #include "py/mpthread.h" #include "lib/utils/gchelper.h" diff --git a/ports/stm32/mpthreadport.c b/ports/stm32/mpthreadport.c index 11653b24cf..7b3b92934b 100644 --- a/ports/stm32/mpthreadport.c +++ b/ports/stm32/mpthreadport.c @@ -26,6 +26,7 @@ #include +#include "py/mpstate.h" #include "py/gc.h" #include "py/mpthread.h" #include "gccollect.h" From cf22f4793cb04e8e63a0d11f479a69c9be6c93ba Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Mon, 18 Feb 2019 14:58:44 +1100 Subject: [PATCH 0187/1788] py: Allow registration of modules at their definition. During make, makemoduledefs.py parses the current builds c files for MP_REGISTER_MODULE(module_name, obj_module, enabled_define) These are used to generate a header with the required entries for "mp_rom_map_elem_t mp_builtin_module_table[]" in py/objmodule.c --- ports/windows/msvc/genhdr.targets | 16 ++++- py/makemoduledefs.py | 107 ++++++++++++++++++++++++++++++ py/modarray.c | 2 + py/obj.h | 7 ++ py/objmodule.c | 10 ++- py/py.mk | 5 ++ 6 files changed, 143 insertions(+), 4 deletions(-) create mode 100644 py/makemoduledefs.py diff --git a/ports/windows/msvc/genhdr.targets b/ports/windows/msvc/genhdr.targets index fa3e95e41b..db8cfea7d7 100644 --- a/ports/windows/msvc/genhdr.targets +++ b/ports/windows/msvc/genhdr.targets @@ -4,7 +4,7 @@ - + @@ -83,6 +83,20 @@ using(var outFile = System.IO.File.CreateText(OutputFile)) { + + + $(DestDir)moduledefs.h + $(DestFile).tmp + + + + $([System.String]::new('%(FullPath)').Replace('$(PyBaseDir)', '')) + + + + + + $(QstrGen).tmp diff --git a/py/makemoduledefs.py b/py/makemoduledefs.py new file mode 100644 index 0000000000..18d327f002 --- /dev/null +++ b/py/makemoduledefs.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python + +# This pre-processor parses provided objects' c files for +# MP_REGISTER_MODULE(module_name, obj_module, enabled_define) +# These are used to generate a header with the required entries for +# "mp_rom_map_elem_t mp_builtin_module_table[]" in py/objmodule.c + +from __future__ import print_function + +import re +import os +import argparse + + +pattern = re.compile( + r"[\n;]\s*MP_REGISTER_MODULE\((.*?),\s*(.*?),\s*(.*?)\);", + flags=re.DOTALL +) + + +def find_c_file(obj_file, vpath): + """ Search vpaths for the c file that matches the provided object_file. + + :param str obj_file: object file to find the matching c file for + :param List[str] vpath: List of base paths, similar to gcc vpath + :return: str path to c file or None + """ + c_file = None + relative_c_file = os.path.splitext(obj_file)[0] + ".c" + relative_c_file = relative_c_file.lstrip('/\\') + for p in vpath: + possible_c_file = os.path.join(p, relative_c_file) + if os.path.exists(possible_c_file): + c_file = possible_c_file + break + + return c_file + + +def find_module_registrations(c_file): + """ Find any MP_REGISTER_MODULE definitions in the provided c file. + + :param str c_file: path to c file to check + :return: List[(module_name, obj_module, enabled_define)] + """ + global pattern + + if c_file is None: + # No c file to match the object file, skip + return set() + + with open(c_file) as c_file_obj: + return set(re.findall(pattern, c_file_obj.read())) + + +def generate_module_table_header(modules): + """ Generate header with module table entries for builtin modules. + + :param List[(module_name, obj_module, enabled_define)] modules: module defs + :return: None + """ + + # Print header file for all external modules. + mod_defs = [] + print("// Automatically generated by makemoduledefs.py.\n") + for module_name, obj_module, enabled_define in modules: + mod_def = "MODULE_DEF_{}".format(module_name.upper()) + mod_defs.append(mod_def) + print(( + "#if ({enabled_define})\n" + " extern const struct _mp_obj_module_t {obj_module};\n" + " #define {mod_def} {{ MP_ROM_QSTR({module_name}), MP_ROM_PTR(&{obj_module}) }},\n" + "#else\n" + " #define {mod_def}\n" + "#endif\n" + ).format(module_name=module_name, obj_module=obj_module, + enabled_define=enabled_define, mod_def=mod_def) + ) + + print("\n#define MICROPY_REGISTERED_MODULES \\") + + for mod_def in mod_defs: + print(" {mod_def} \\".format(mod_def=mod_def)) + + print("// MICROPY_REGISTERED_MODULES") + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--vpath", default=".", + help="comma separated list of folders to search for c files in") + parser.add_argument("files", nargs="*", + help="list of c files to search") + args = parser.parse_args() + + vpath = [p.strip() for p in args.vpath.split(',')] + + modules = set() + for obj_file in args.files: + c_file = find_c_file(obj_file, vpath) + modules |= find_module_registrations(c_file) + + generate_module_table_header(sorted(modules)) + + +if __name__ == '__main__': + main() diff --git a/py/modarray.c b/py/modarray.c index c0cdca9286..de84fc8587 100644 --- a/py/modarray.c +++ b/py/modarray.c @@ -40,4 +40,6 @@ const mp_obj_module_t mp_module_array = { .globals = (mp_obj_dict_t*)&mp_module_array_globals, }; +MP_REGISTER_MODULE(MP_QSTR_array, mp_module_array, MICROPY_PY_ARRAY); + #endif diff --git a/py/obj.h b/py/obj.h index 4d42c43de3..a22d5f8b81 100644 --- a/py/obj.h +++ b/py/obj.h @@ -326,6 +326,13 @@ typedef struct _mp_rom_obj_t { mp_const_obj_t o; } mp_rom_obj_t; #define MP_DEFINE_CONST_STATICMETHOD_OBJ(obj_name, fun_name) const mp_rom_obj_static_class_method_t obj_name = {{&mp_type_staticmethod}, fun_name} #define MP_DEFINE_CONST_CLASSMETHOD_OBJ(obj_name, fun_name) const mp_rom_obj_static_class_method_t obj_name = {{&mp_type_classmethod}, fun_name} +// Declare a module as a builtin, processed by makemoduledefs.py +// param module_name: MP_QSTR_ +// param obj_module: mp_obj_module_t instance +// prarm enabled_define: used as `#if (enabled_define) around entry` + +#define MP_REGISTER_MODULE(module_name, obj_module, enabled_define) + // Underlying map/hash table implementation (not dict object or map function) typedef struct _mp_map_elem_t { diff --git a/py/objmodule.c b/py/objmodule.c index 9ba617707a..9191c73ec3 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -31,6 +31,8 @@ #include "py/runtime.h" #include "py/builtin.h" +#include "genhdr/moduledefs.h" + STATIC void module_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in); @@ -136,9 +138,6 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = { { MP_ROM_QSTR(MP_QSTR_builtins), MP_ROM_PTR(&mp_module_builtins) }, { MP_ROM_QSTR(MP_QSTR_micropython), MP_ROM_PTR(&mp_module_micropython) }, -#if MICROPY_PY_ARRAY - { MP_ROM_QSTR(MP_QSTR_array), MP_ROM_PTR(&mp_module_array) }, -#endif #if MICROPY_PY_IO { MP_ROM_QSTR(MP_QSTR_uio), MP_ROM_PTR(&mp_module_io) }, #endif @@ -226,6 +225,11 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = { // extra builtin modules as defined by a port MICROPY_PORT_BUILTIN_MODULES + + #ifdef MICROPY_REGISTERED_MODULES + // builtin modules declared with MP_REGISTER_MODULE() + MICROPY_REGISTERED_MODULES + #endif }; MP_DEFINE_CONST_MAP(mp_builtin_module_map, mp_builtin_module_table); diff --git a/py/py.mk b/py/py.mk index b85d94fee7..85e9072d7c 100644 --- a/py/py.mk +++ b/py/py.mk @@ -323,6 +323,11 @@ $(HEADER_BUILD)/qstrdefs.generated.h: $(PY_QSTR_DEFS) $(QSTR_DEFS) $(QSTR_DEFS_C $(Q)cat $(PY_QSTR_DEFS) $(QSTR_DEFS) $(QSTR_DEFS_COLLECTED) | $(SED) 's/^Q(.*)/"&"/' | $(CPP) $(CFLAGS) - | $(SED) 's/^"\(Q(.*)\)"/\1/' > $(HEADER_BUILD)/qstrdefs.preprocessed.h $(Q)$(PYTHON) $(PY_SRC)/makeqstrdata.py $(HEADER_BUILD)/qstrdefs.preprocessed.h > $@ +# build a list of registered modules for py/objmodule.c. +$(HEADER_BUILD)/moduledefs.h: $(SRC_QSTR) $(QSTR_GLOBAL_DEPENDENCIES) | $(HEADER_BUILD)/mpversion.h + @$(ECHO) "GEN $@" + $(Q)$(PYTHON) $(PY_SRC)/makemoduledefs.py --vpath="., $(TOP), $(USER_C_MODULES)" $(SRC_QSTR) > $@ + # Force nlr code to always be compiled with space-saving optimisation so # that the function preludes are of a minimal and predictable form. $(PY_BUILD)/nlr%.o: CFLAGS += -Os From 2e516074daee76fb3e0710a893a0f40532bb3252 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Thu, 14 Jun 2018 15:57:29 +0200 Subject: [PATCH 0188/1788] py: Implement a module system for external, user C modules. This system makes it a lot easier to include external libraries as static, native modules in MicroPython. Simply pass USER_C_MODULES (like FROZEN_MPY_DIR) as a make parameter. --- docs/reference/cmodules.rst | 86 +++++++++++++++++++++++++++++++++ docs/reference/index.rst | 8 +++ docs/reference/speed_python.rst | 2 + py/mkenv.mk | 1 + py/mkrules.mk | 9 +++- py/objmodule.c | 2 - py/py.mk | 9 +++- tools/gen-cmodules.py | 28 +++++++++++ 8 files changed, 141 insertions(+), 4 deletions(-) create mode 100644 docs/reference/cmodules.rst create mode 100755 tools/gen-cmodules.py diff --git a/docs/reference/cmodules.rst b/docs/reference/cmodules.rst new file mode 100644 index 0000000000..f361af4a38 --- /dev/null +++ b/docs/reference/cmodules.rst @@ -0,0 +1,86 @@ +Extending MicroPython with C +============================ + +Some specialized code would be unacceptably slow or needs to access hardware in +a way that cannot be done from MicroPython. Therefore, it supports a way of +extending the language with custom modules written in C. But before you consider +writing a module in C, please take a look at :ref:`speed_python`. + +`Unlike CPython `_, these +modules are (currently) embedded directly in the program image instead of being +dynamically loaded. This requires a `custom build of MicroPython +`_. + + +Writing a module +---------------- + +A module is a directory with the following files: + + * ``micropython.mk``, which contains the Makefile fragment for this module. + * All C files you would like included. + +Put the required build commands in ``micropython.mk``. For a simple module, you +will only have to add the file paths to ``SRC_MOD``, which will include these C +files in the build: + +.. highlight:: make +.. code:: + + # Add all C files to SRC_MOD. + SRC_MOD += $(USER_C_MODULES)/example/example.c + +This is a very bare bones module named ``example`` that provides +``example.double(x)``. Note that the name of the module must be equal to the +directory name and is also used in the name of the ``mp_obj_module_t`` object at +the bottom. + +.. highlight:: c +.. code:: + + // Include required definitions first. + #include "py/obj.h" + #include "py/runtime.h" + + // This is the function you will call using example.double(n). + STATIC mp_obj_t example_double(mp_obj_t x_obj) { + // Check input value and convert it to a C type. + if (!MP_OBJ_IS_SMALL_INT(x_obj)) { + mp_raise_ValueError("x is not a small int"); + } + int x = mp_obj_int_get_truncated(x_obj); + + // Calculate the double, and convert back to MicroPython object. + return mp_obj_new_int(x + x); + } + STATIC MP_DEFINE_CONST_FUN_OBJ_1(example_double_obj, example_double); + + // Define all properties of the example module, which currently are the name (a + // string) and a function. + // All identifiers and strings are written as MP_QSTR_xxx and will be + // optimized to word-sized integers by the build system (interned strings). + STATIC const mp_rom_map_elem_t example_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_example) }, + { MP_ROM_QSTR(MP_QSTR_double), MP_ROM_PTR(&example_double_obj) }, + }; + STATIC MP_DEFINE_CONST_DICT(example_module_globals, example_module_globals_table); + + // Define module object. + const mp_obj_module_t example_user_cmodule = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&example_module_globals, + }; + + +Using a module +-------------- + +To build such a module, compile MicroPython (see `getting started +`_) with an +extra ``make`` flag named ``USER_C_MODULES`` set to the directory containing +all modules you want included (not to the module itself!). For example: + +.. highlight:: shell +.. code:: + + $ make USER_C_MODULES=path-to-modules-folder all diff --git a/docs/reference/index.rst b/docs/reference/index.rst index d0c7f69de9..e2e08a7f72 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -26,3 +26,11 @@ implementation and the best practices to use them. constrained.rst packages.rst asm_thumb2_index.rst + cmodules.rst + +.. only:: port_pyboard + + .. toctree:: + :maxdepth: 1 + + asm_thumb2_index.rst diff --git a/docs/reference/speed_python.rst b/docs/reference/speed_python.rst index 4db60ec14d..c5aa80c6e1 100644 --- a/docs/reference/speed_python.rst +++ b/docs/reference/speed_python.rst @@ -1,3 +1,5 @@ +.. _speed_python: + Maximising MicroPython Speed ============================ diff --git a/py/mkenv.mk b/py/mkenv.mk index 87e92ec6f9..5f4b11b6be 100644 --- a/py/mkenv.mk +++ b/py/mkenv.mk @@ -61,6 +61,7 @@ endif MAKE_FROZEN = $(PYTHON) $(TOP)/tools/make-frozen.py MPY_CROSS = $(TOP)/mpy-cross/mpy-cross MPY_TOOL = $(PYTHON) $(TOP)/tools/mpy-tool.py +GEN_CMODULES = $(PYTHON) $(TOP)/tools/gen-cmodules.py all: .PHONY: all diff --git a/py/mkrules.mk b/py/mkrules.mk index 30ac520aa1..65d86834ef 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -105,7 +105,7 @@ endif ifneq ($(FROZEN_MPY_DIR),) # to build the MicroPython cross compiler $(TOP)/mpy-cross/mpy-cross: $(TOP)/py/*.[ch] $(TOP)/mpy-cross/*.[ch] $(TOP)/ports/windows/fmode.c - $(Q)$(MAKE) -C $(TOP)/mpy-cross + $(Q)$(MAKE) -C $(TOP)/mpy-cross USER_C_MODULES= # make a list of all the .py files that need compiling and freezing FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py' | $(SED) -e 's=^$(FROZEN_MPY_DIR)/==') @@ -123,6 +123,13 @@ $(BUILD)/frozen_mpy.c: $(FROZEN_MPY_MPY_FILES) $(BUILD)/genhdr/qstrdefs.generate $(Q)$(MPY_TOOL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h $(FROZEN_MPY_MPY_FILES) > $@ endif +# to build a list of modules for py/objmodule.c. +ifneq ($(USER_C_MODULES),) +$(BUILD)/genhdr/cmodules.h: | $(HEADER_BUILD)/mpversion.h + @$(ECHO) "GEN $@" + $(Q)$(GEN_CMODULES) $(USER_C_MODULES) > $@ +endif + ifneq ($(PROG),) # Build a standalone executable (unix does this) diff --git a/py/objmodule.c b/py/objmodule.c index 9191c73ec3..04d210260d 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -31,8 +31,6 @@ #include "py/runtime.h" #include "py/builtin.h" -#include "genhdr/moduledefs.h" - STATIC void module_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in); diff --git a/py/py.mk b/py/py.mk index 85e9072d7c..ad7d122048 100644 --- a/py/py.mk +++ b/py/py.mk @@ -129,6 +129,13 @@ $(BUILD)/$(BTREE_DIR)/%.o: CFLAGS += -Wno-old-style-definition -Wno-sign-compare $(BUILD)/extmod/modbtree.o: CFLAGS += $(BTREE_DEFS) endif +# External modules written in C. +ifneq ($(USER_C_MODULES),) +CFLAGS_MOD += -DMICROPY_CMODULES_INCLUDE_H='"genhdr/cmodules.h"' +include $(USER_C_MODULES)/*/micropython.mk +SRC_QSTR += $(BUILD)/genhdr/cmodules.h +endif + # py object files PY_CORE_O_BASENAME = $(addprefix py/,\ mpstate.o \ @@ -300,7 +307,7 @@ endif # Sources that may contain qstrings 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) +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: diff --git a/tools/gen-cmodules.py b/tools/gen-cmodules.py new file mode 100755 index 0000000000..524e3c03d3 --- /dev/null +++ b/tools/gen-cmodules.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +# Generate genhdr/cmodules.h for inclusion in py/objmodule.c. + +from __future__ import print_function + +import sys +import os +from glob import glob + +def update_modules(path): + modules = [] + for module in sorted(os.listdir(path)): + if not os.path.isfile('%s/%s/micropython.mk' % (path, module)): + continue # not a module + modules.append(module) + + # Print header file for all external modules. + print('// Automatically generated by genmodules.py.\n') + for module in modules: + print('extern const struct _mp_obj_module_t %s_user_cmodule;' % module) + print('\n#define MICROPY_EXTRA_BUILTIN_MODULES \\') + for module in modules: + print(' { MP_ROM_QSTR(MP_QSTR_%s), MP_ROM_PTR(&%s_user_cmodule) }, \\' % (module, module)) + print() + +if __name__ == '__main__': + update_modules(sys.argv[1]) From 89ff506513d52c0c415b2cf45335d60cefac527d Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Wed, 12 Dec 2018 16:50:55 +1100 Subject: [PATCH 0189/1788] py: Update and rework build system for including external C modules. How to use this feature is documented in docs/develop/cmodules.rst. --- docs/develop/cmodules.rst | 163 ++++++++++++++++++++++++++++++++++++ docs/develop/index.rst | 15 ++++ docs/index.rst | 1 + docs/reference/cmodules.rst | 86 ------------------- docs/reference/index.rst | 8 -- mpy-cross/Makefile | 2 + ports/stm32/Makefile | 2 +- py/mkenv.mk | 1 - py/mkrules.mk | 17 ++-- py/objmodule.c | 2 + py/py.mk | 19 ++++- tools/gen-cmodules.py | 28 ------- 12 files changed, 205 insertions(+), 139 deletions(-) create mode 100644 docs/develop/cmodules.rst create mode 100644 docs/develop/index.rst delete mode 100644 docs/reference/cmodules.rst delete mode 100755 tools/gen-cmodules.py diff --git a/docs/develop/cmodules.rst b/docs/develop/cmodules.rst new file mode 100644 index 0000000000..c3de90a0f6 --- /dev/null +++ b/docs/develop/cmodules.rst @@ -0,0 +1,163 @@ +MicroPython external C modules +============================== + +When developing modules for use with MicroPython you may find you run into +limitations with the Python environment, often due to an inability to access +certain hardware resources or Python speed limitations. + +If your limitations can't be resolved with suggestions in :ref:`speed_python`, +writing some or all of your module in C is a viable option. + +If your module is designed to access or work with commonly available +hardware or libraries please consider implementing it inside the MicroPython +source tree alongside similar modules and submitting it as a pull request. +If however you're targeting obscure or proprietary systems it may make +more sense to keep this external to the main MicroPython repository. + +This chapter describes how to compile such external modules into the +MicroPython executable or firmware image. + + +Structure of an external C module +--------------------------------- + +A MicroPython user C module is a directory with the following files: + +* ``*.c`` and/or ``*.h`` source code files for your module. + + These will typically include the low level functionality being implemented and + the MicroPython binding functions to expose the functions and module(s). + + Currently the best reference for writing these functions/modules is + to find similar modules within the MicroPython tree and use them as examples. + +* ``micropython.mk`` contains the Makefile fragment for this module. + + ``$(USERMOD_DIR)`` is available in ``micropython.mk`` as the path to your + module directory. As it's redefined for each c module, is should be expanded + in your ``micropython.mk`` to a local make variable, + eg ``EXAMPLE_MOD_DIR := $(USERMOD_DIR)`` + + Your ``micropython.mk`` must add your modules C files relative to your + expanded copy of ``$(USERMOD_DIR)`` to ``SRC_USERMOD``, eg + ``SRC_USERMOD += $(EXAMPLE_MOD_DIR)/example.c`` + + If you have custom ``CFLAGS`` settings or include folders to define, these + should be added to ``CFLAGS_USERMOD``. + + See below for full usage example. + + +Basic Example +------------- + +This simple module named ``example`` provides a single function +``example.add_ints(a, b)`` which adds the two integer args together and returns +the result. + +Directory:: + + example/ + ├── example.c + └── micropython.mk + + +``example.c`` + +.. code-block:: c + + // Include required definitions first. + #include "py/obj.h" + #include "py/runtime.h" + #include "py/builtin.h" + + #define MODULE_EXAMPLE_ENABLED (1) + + // This is the function which will be called from Python as example.add_ints(a, b). + STATIC mp_obj_t example_add_ints(mp_obj_t a_obj, mp_obj_tab_obj) { + // Extract the ints from the micropython input objects + int a = mp_obj_get_int(a_obj); + int b = mp_obj_get_int(b_obj); + + // Calculate the addition and convert to MicroPython object. + return mp_obj_new_int(a + b); + } + // Define a Python reference to the function above + STATIC MP_DEFINE_CONST_FUN_OBJ_1(example_add_ints_obj, example_add_ints); + + // Define all properties of the example module. + // Table entries are key/value pairs of the attribute name (a string) + // and the MicroPython object reference. + // All identifiers and strings are written as MP_QSTR_xxx and will be + // optimized to word-sized integers by the build system (interned strings). + STATIC const mp_rom_map_elem_t example_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_example) }, + { MP_ROM_QSTR(MP_QSTR_add_ints), MP_ROM_PTR(&example_add_ints_obj) }, + }; + STATIC MP_DEFINE_CONST_DICT(example_module_globals, example_module_globals_table); + + // Define module object. + const mp_obj_module_t example_user_cmodule = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&example_module_globals, + }; + + // Register the module to make it available in Python + MP_REGISTER_MODULE(MP_QSTR_example, example_user_cmodule, MODULE_EXAMPLE_ENABLED); + + +``micropython.mk`` + +.. code-block:: make + + EXAMPLE_MOD_DIR := $(USERMOD_DIR) + + # Add all C files to SRC_USERMOD. + SRC_USERMOD += $(EXAMPLE_MOD_DIR)/example.c + + # We can add our module folder to include paths if needed + # This is not actually needed in this example. + CFLAGS_USERMOD += -I$(EXAMPLE_MOD_DIR) + + +Compiling the cmodule into MicroPython +-------------------------------------- + +To build such a module, compile MicroPython (see `getting started +`_) with an +extra ``make`` flag named ``USER_C_MODULES`` set to the directory containing +all modules you want included (not to the module itself). For example: + + +Directory:: + + my_project/ + ├── modules/ + │ └──example/ + │ ├──example.c + │ └──micropython.mk + └── micropython/ + ├──ports/ + ... ├──stm32/ + ... + +Building for stm32 port: + +.. code-block:: bash + + cd my_project/micropython/ports/stm32 + make USER_C_MODULES=../../../modules all + + +Module usage in MicroPython +--------------------------- + +Once built into your copy of MicroPython, the module implemented +in ``example.c`` above can now be accessed in Python just +like any other builtin module, eg + +.. code-block:: python + + import example + print(example.add_ints(1, 3)) + # should display 4 diff --git a/docs/develop/index.rst b/docs/develop/index.rst new file mode 100644 index 0000000000..6b7b3c3910 --- /dev/null +++ b/docs/develop/index.rst @@ -0,0 +1,15 @@ +Developing and building MicroPython +=================================== + +This chapter describes modules (function and class libraries) which are built +into MicroPython. There are a few categories of such modules: + +This chapter describes some options for extending MicroPython in C. Note +that it doesn't aim to be a complete guide for developing with MicroPython. +See the `getting started guide +`_ for further information. + +.. toctree:: + :maxdepth: 1 + + cmodules.rst diff --git a/docs/index.rst b/docs/index.rst index 235185b6c2..c0417c227c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -6,6 +6,7 @@ MicroPython documentation and references library/index.rst reference/index.rst genrst/index.rst + develop/index.rst license.rst pyboard/quickref.rst esp8266/quickref.rst diff --git a/docs/reference/cmodules.rst b/docs/reference/cmodules.rst deleted file mode 100644 index f361af4a38..0000000000 --- a/docs/reference/cmodules.rst +++ /dev/null @@ -1,86 +0,0 @@ -Extending MicroPython with C -============================ - -Some specialized code would be unacceptably slow or needs to access hardware in -a way that cannot be done from MicroPython. Therefore, it supports a way of -extending the language with custom modules written in C. But before you consider -writing a module in C, please take a look at :ref:`speed_python`. - -`Unlike CPython `_, these -modules are (currently) embedded directly in the program image instead of being -dynamically loaded. This requires a `custom build of MicroPython -`_. - - -Writing a module ----------------- - -A module is a directory with the following files: - - * ``micropython.mk``, which contains the Makefile fragment for this module. - * All C files you would like included. - -Put the required build commands in ``micropython.mk``. For a simple module, you -will only have to add the file paths to ``SRC_MOD``, which will include these C -files in the build: - -.. highlight:: make -.. code:: - - # Add all C files to SRC_MOD. - SRC_MOD += $(USER_C_MODULES)/example/example.c - -This is a very bare bones module named ``example`` that provides -``example.double(x)``. Note that the name of the module must be equal to the -directory name and is also used in the name of the ``mp_obj_module_t`` object at -the bottom. - -.. highlight:: c -.. code:: - - // Include required definitions first. - #include "py/obj.h" - #include "py/runtime.h" - - // This is the function you will call using example.double(n). - STATIC mp_obj_t example_double(mp_obj_t x_obj) { - // Check input value and convert it to a C type. - if (!MP_OBJ_IS_SMALL_INT(x_obj)) { - mp_raise_ValueError("x is not a small int"); - } - int x = mp_obj_int_get_truncated(x_obj); - - // Calculate the double, and convert back to MicroPython object. - return mp_obj_new_int(x + x); - } - STATIC MP_DEFINE_CONST_FUN_OBJ_1(example_double_obj, example_double); - - // Define all properties of the example module, which currently are the name (a - // string) and a function. - // All identifiers and strings are written as MP_QSTR_xxx and will be - // optimized to word-sized integers by the build system (interned strings). - STATIC const mp_rom_map_elem_t example_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_example) }, - { MP_ROM_QSTR(MP_QSTR_double), MP_ROM_PTR(&example_double_obj) }, - }; - STATIC MP_DEFINE_CONST_DICT(example_module_globals, example_module_globals_table); - - // Define module object. - const mp_obj_module_t example_user_cmodule = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t*)&example_module_globals, - }; - - -Using a module --------------- - -To build such a module, compile MicroPython (see `getting started -`_) with an -extra ``make`` flag named ``USER_C_MODULES`` set to the directory containing -all modules you want included (not to the module itself!). For example: - -.. highlight:: shell -.. code:: - - $ make USER_C_MODULES=path-to-modules-folder all diff --git a/docs/reference/index.rst b/docs/reference/index.rst index e2e08a7f72..d0c7f69de9 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -26,11 +26,3 @@ implementation and the best practices to use them. constrained.rst packages.rst asm_thumb2_index.rst - cmodules.rst - -.. only:: port_pyboard - - .. toctree:: - :maxdepth: 1 - - asm_thumb2_index.rst diff --git a/mpy-cross/Makefile b/mpy-cross/Makefile index c42c2c5abb..4ff96fc80c 100644 --- a/mpy-cross/Makefile +++ b/mpy-cross/Makefile @@ -9,6 +9,8 @@ override undefine MICROPY_FORCE_32BIT override undefine CROSS_COMPILE override undefine FROZEN_DIR override undefine FROZEN_MPY_DIR +override undefine USER_C_MODULES +override undefine SRC_MOD override undefine BUILD override undefine PROG endif diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 4fddc6c7d3..b4c7a15c13 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -494,7 +494,7 @@ $(BUILD)/firmware.hex: $(BUILD)/firmware.elf $(BUILD)/firmware.elf: $(OBJ) $(ECHO) "LINK $@" - $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS) + $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LDFLAGS_MOD) $(LIBS) $(Q)$(SIZE) $@ PLLVALUES = boards/pllvalues.py diff --git a/py/mkenv.mk b/py/mkenv.mk index 5f4b11b6be..87e92ec6f9 100644 --- a/py/mkenv.mk +++ b/py/mkenv.mk @@ -61,7 +61,6 @@ endif MAKE_FROZEN = $(PYTHON) $(TOP)/tools/make-frozen.py MPY_CROSS = $(TOP)/mpy-cross/mpy-cross MPY_TOOL = $(PYTHON) $(TOP)/tools/mpy-tool.py -GEN_CMODULES = $(PYTHON) $(TOP)/tools/gen-cmodules.py all: .PHONY: all diff --git a/py/mkrules.mk b/py/mkrules.mk index 65d86834ef..caa9527c70 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -20,12 +20,12 @@ endif # can be located. By following this scheme, it allows a single build rule # to be used to compile all .c files. -vpath %.S . $(TOP) +vpath %.S . $(TOP) $(USER_C_MODULES) $(BUILD)/%.o: %.S $(ECHO) "CC $<" $(Q)$(CC) $(CFLAGS) -c -o $@ $< -vpath %.s . $(TOP) +vpath %.s . $(TOP) $(USER_C_MODULES) $(BUILD)/%.o: %.s $(ECHO) "AS $<" $(Q)$(AS) -o $@ $< @@ -42,14 +42,14 @@ $(Q)$(CC) $(CFLAGS) -c -MD -o $@ $< $(RM) -f $(@:.o=.d) endef -vpath %.c . $(TOP) +vpath %.c . $(TOP) $(USER_C_MODULES) $(BUILD)/%.o: %.c $(call compile_c) QSTR_GEN_EXTRA_CFLAGS += -DNO_QSTR QSTR_GEN_EXTRA_CFLAGS += -I$(BUILD)/tmp -vpath %.c . $(TOP) +vpath %.c . $(TOP) $(USER_C_MODULES) $(BUILD)/%.pp: %.c $(ECHO) "PreProcess $<" @@ -105,7 +105,7 @@ endif ifneq ($(FROZEN_MPY_DIR),) # to build the MicroPython cross compiler $(TOP)/mpy-cross/mpy-cross: $(TOP)/py/*.[ch] $(TOP)/mpy-cross/*.[ch] $(TOP)/ports/windows/fmode.c - $(Q)$(MAKE) -C $(TOP)/mpy-cross USER_C_MODULES= + $(Q)$(MAKE) -C $(TOP)/mpy-cross # make a list of all the .py files that need compiling and freezing FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py' | $(SED) -e 's=^$(FROZEN_MPY_DIR)/==') @@ -123,13 +123,6 @@ $(BUILD)/frozen_mpy.c: $(FROZEN_MPY_MPY_FILES) $(BUILD)/genhdr/qstrdefs.generate $(Q)$(MPY_TOOL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h $(FROZEN_MPY_MPY_FILES) > $@ endif -# to build a list of modules for py/objmodule.c. -ifneq ($(USER_C_MODULES),) -$(BUILD)/genhdr/cmodules.h: | $(HEADER_BUILD)/mpversion.h - @$(ECHO) "GEN $@" - $(Q)$(GEN_CMODULES) $(USER_C_MODULES) > $@ -endif - ifneq ($(PROG),) # Build a standalone executable (unix does this) diff --git a/py/objmodule.c b/py/objmodule.c index 04d210260d..9191c73ec3 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -31,6 +31,8 @@ #include "py/runtime.h" #include "py/builtin.h" +#include "genhdr/moduledefs.h" + STATIC void module_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in); diff --git a/py/py.mk b/py/py.mk index ad7d122048..0fbc9f14bb 100644 --- a/py/py.mk +++ b/py/py.mk @@ -131,9 +131,20 @@ endif # External modules written in C. ifneq ($(USER_C_MODULES),) -CFLAGS_MOD += -DMICROPY_CMODULES_INCLUDE_H='"genhdr/cmodules.h"' -include $(USER_C_MODULES)/*/micropython.mk -SRC_QSTR += $(BUILD)/genhdr/cmodules.h +# pre-define USERMOD variables as expanded so that variables are immediate +# expanded as they're added to them +SRC_USERMOD := +CFLAGS_USERMOD := +LDFLAGS_USERMOD := +$(foreach module, $(wildcard $(USER_C_MODULES)/*/micropython.mk), \ + $(eval USERMOD_DIR = $(patsubst %/,%,$(dir $(module))))\ + $(info Including User C Module from $(USERMOD_DIR))\ + $(eval include $(module))\ +) + +SRC_MOD += $(patsubst $(USER_C_MODULES)/%.c,%.c,$(SRC_USERMOD)) +CFLAGS_MOD += $(CFLAGS_USERMOD) +LDFLAGS_MOD += $(LDFLAGS_USERMOD) endif # py object files @@ -335,6 +346,8 @@ $(HEADER_BUILD)/moduledefs.h: $(SRC_QSTR) $(QSTR_GLOBAL_DEPENDENCIES) | $(HEADER @$(ECHO) "GEN $@" $(Q)$(PYTHON) $(PY_SRC)/makemoduledefs.py --vpath="., $(TOP), $(USER_C_MODULES)" $(SRC_QSTR) > $@ +SRC_QSTR += $(HEADER_BUILD)/moduledefs.h + # Force nlr code to always be compiled with space-saving optimisation so # that the function preludes are of a minimal and predictable form. $(PY_BUILD)/nlr%.o: CFLAGS += -Os diff --git a/tools/gen-cmodules.py b/tools/gen-cmodules.py deleted file mode 100755 index 524e3c03d3..0000000000 --- a/tools/gen-cmodules.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python - -# Generate genhdr/cmodules.h for inclusion in py/objmodule.c. - -from __future__ import print_function - -import sys -import os -from glob import glob - -def update_modules(path): - modules = [] - for module in sorted(os.listdir(path)): - if not os.path.isfile('%s/%s/micropython.mk' % (path, module)): - continue # not a module - modules.append(module) - - # Print header file for all external modules. - print('// Automatically generated by genmodules.py.\n') - for module in modules: - print('extern const struct _mp_obj_module_t %s_user_cmodule;' % module) - print('\n#define MICROPY_EXTRA_BUILTIN_MODULES \\') - for module in modules: - print(' { MP_ROM_QSTR(MP_QSTR_%s), MP_ROM_PTR(&%s_user_cmodule) }, \\' % (module, module)) - print() - -if __name__ == '__main__': - update_modules(sys.argv[1]) From 2ed2ec1711b13dd9a28bdc29ce8cba13ca7d503f Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Tue, 29 Jan 2019 15:20:01 +1100 Subject: [PATCH 0190/1788] drivers/memory/spiflash: Rework wait_sr to fix uninit'd variable 'sr'. --- drivers/memory/spiflash.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/memory/spiflash.c b/drivers/memory/spiflash.c index c0b55591be..22775d5416 100644 --- a/drivers/memory/spiflash.c +++ b/drivers/memory/spiflash.c @@ -128,19 +128,14 @@ STATIC void mp_spiflash_write_cmd_addr(mp_spiflash_t *self, uint8_t cmd, uint32_ STATIC int mp_spiflash_wait_sr(mp_spiflash_t *self, uint8_t mask, uint8_t val, uint32_t timeout) { uint8_t sr; - for (; timeout; --timeout) { + do { sr = mp_spiflash_read_cmd(self, CMD_RDSR, 1); if ((sr & mask) == val) { - break; + return 0; // success } - } - if ((sr & mask) == val) { - return 0; // success - } else if (timeout == 0) { - return -MP_ETIMEDOUT; - } else { - return -MP_EIO; - } + } while (timeout--); + + return -MP_ETIMEDOUT; } STATIC int mp_spiflash_wait_wel1(mp_spiflash_t *self) { From 0c60cb1fc4d5555478e4a0949bccdad45d16d50b Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Fri, 1 Mar 2019 13:39:44 +1100 Subject: [PATCH 0191/1788] stm32/qspi: Set pin speed to very-high and allow to config some options. The default speed of the QSPI interface is 72Mhz whereas the standard AF pin speed (high) is only rated to 50Mhz, so increase speed to very-high. --- ports/stm32/mboot/mphalport.h | 4 ++++ ports/stm32/qspi.c | 36 +++++++++++++++++++++++++---------- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/ports/stm32/mboot/mphalport.h b/ports/stm32/mboot/mphalport.h index d3ed18a998..86063c4ef2 100644 --- a/ports/stm32/mboot/mphalport.h +++ b/ports/stm32/mboot/mphalport.h @@ -39,6 +39,10 @@ #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_SPEED_LOW (GPIO_SPEED_FREQ_LOW) +#define MP_HAL_PIN_SPEED_MEDIUM (GPIO_SPEED_FREQ_MEDIUM) +#define MP_HAL_PIN_SPEED_HIGH (GPIO_SPEED_FREQ_HIGH) +#define MP_HAL_PIN_SPEED_VERY_HIGH (GPIO_SPEED_FREQ_VERY_HIGH) #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) diff --git a/ports/stm32/qspi.c b/ports/stm32/qspi.c index 469858c683..8c8b9c4940 100644 --- a/ports/stm32/qspi.c +++ b/ports/stm32/qspi.c @@ -33,21 +33,37 @@ #if defined(MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2) +#ifndef MICROPY_HW_QSPI_PRESCALER +#define MICROPY_HW_QSPI_PRESCALER 3 // F_CLK = F_AHB/3 (72MHz when CPU is 216MHz) +#endif + +#ifndef MICROPY_HW_QSPI_SAMPLE_SHIFT +#define MICROPY_HW_QSPI_SAMPLE_SHIFT 1 // sample shift enabled +#endif + +#ifndef MICROPY_HW_QSPI_TIMEOUT_COUNTER +#define MICROPY_HW_QSPI_TIMEOUT_COUNTER 0 // timeout counter disabled (see F7 errata) +#endif + +#ifndef MICROPY_HW_QSPI_CS_HIGH_CYCLES +#define MICROPY_HW_QSPI_CS_HIGH_CYCLES 2 // nCS stays high for 2 cycles +#endif + void qspi_init(void) { // Configure pins - mp_hal_pin_config_alt_static(MICROPY_HW_QSPIFLASH_CS, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_QUADSPI_BK1_NCS); - mp_hal_pin_config_alt_static(MICROPY_HW_QSPIFLASH_SCK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_QUADSPI_CLK); - mp_hal_pin_config_alt_static(MICROPY_HW_QSPIFLASH_IO0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_QUADSPI_BK1_IO0); - mp_hal_pin_config_alt_static(MICROPY_HW_QSPIFLASH_IO1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_QUADSPI_BK1_IO1); - mp_hal_pin_config_alt_static(MICROPY_HW_QSPIFLASH_IO2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_QUADSPI_BK1_IO2); - mp_hal_pin_config_alt_static(MICROPY_HW_QSPIFLASH_IO3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_QUADSPI_BK1_IO3); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_QSPIFLASH_CS, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_QUADSPI_BK1_NCS); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_QSPIFLASH_SCK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_QUADSPI_CLK); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_QSPIFLASH_IO0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_QUADSPI_BK1_IO0); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_QSPIFLASH_IO1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_QUADSPI_BK1_IO1); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_QSPIFLASH_IO2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_QUADSPI_BK1_IO2); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_QSPIFLASH_IO3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_QUADSPI_BK1_IO3); // 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) + (MICROPY_HW_QSPI_PRESCALER - 1) << QUADSPI_CR_PRESCALER_Pos | 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 @@ -55,14 +71,14 @@ void qspi_init(void) { #if defined(QUADSPI_CR_DFM_Pos) | 0 << QUADSPI_CR_DFM_Pos // dual-flash mode disabled #endif - | 1 << QUADSPI_CR_SSHIFT_Pos // do sample shift - | 0 << QUADSPI_CR_TCEN_Pos // timeout counter disabled (see F7 errata) + | MICROPY_HW_QSPI_SAMPLE_SHIFT << QUADSPI_CR_SSHIFT_Pos + | MICROPY_HW_QSPI_TIMEOUT_COUNTER << QUADSPI_CR_TCEN_Pos | 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 + | (MICROPY_HW_QSPI_CS_HIGH_CYCLES - 1) << QUADSPI_DCR_CSHT_Pos | 0 << QUADSPI_DCR_CKMODE_Pos // CLK idles at low state ; } From 5688c9ba09ea8f9ffeeb25bd577a08b57828ffa7 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Wed, 6 Mar 2019 15:27:18 +1100 Subject: [PATCH 0192/1788] stm32/usb: Allow to override USB strings & VID/PID in app and mboot. The override #define's should go in the board's mpconfigboard.h file. --- ports/stm32/mboot/main.c | 35 +++++++++++++++++++++++++++++------ ports/stm32/usbd_desc.c | 30 ++++++++++++++++++++++++++---- 2 files changed, 55 insertions(+), 10 deletions(-) diff --git a/ports/stm32/mboot/main.c b/ports/stm32/mboot/main.c index 838c5fe08a..6958d3f61e 100644 --- a/ports/stm32/mboot/main.c +++ b/ports/stm32/mboot/main.c @@ -888,16 +888,39 @@ typedef struct _pyb_usbdd_obj_t { __ALIGN_BEGIN uint8_t usbd_str_desc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END; } pyb_usbdd_obj_t; -#define USBD_LANGID_STRING (0x409) +#ifndef MBOOT_USBD_LANGID_STRING +#define MBOOT_USBD_LANGID_STRING (0x409) +#endif + +#ifndef MBOOT_USBD_MANUFACTURER_STRING +#define MBOOT_USBD_MANUFACTURER_STRING "MicroPython" +#endif + +#ifndef MBOOT_USBD_PRODUCT_STRING +#define MBOOT_USBD_PRODUCT_STRING "Pyboard DFU" +#endif + +#ifndef MBOOT_USB_VID +#define MBOOT_USB_VID 0x0483 +#endif + +#ifndef MBOOT_USB_PID +#define MBOOT_USB_PID 0xDF11 +#endif __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), + LOBYTE(MBOOT_USBD_LANGID_STRING), + HIBYTE(MBOOT_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"; +static const uint8_t dev_descr[0x12] = { + 0x12, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, + LOBYTE(MBOOT_USB_VID), HIBYTE(MBOOT_USB_VID), + LOBYTE(MBOOT_USB_PID), HIBYTE(MBOOT_USB_PID), + 0x00, 0x22, 0x01, 0x02, 0x03, 0x01 +}; // This may be modified by USBD_GetDescriptor static uint8_t cfg_descr[9 + 9 + 9] = @@ -934,11 +957,11 @@ static uint8_t *pyb_usbdd_StrDescriptor(USBD_HandleTypeDef *pdev, uint8_t idx, u 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); + USBD_GetString((uint8_t*)MBOOT_USBD_MANUFACTURER_STRING, str_desc, length); return str_desc; case USBD_IDX_PRODUCT_STR: - USBD_GetString((uint8_t*)"USBDevice Product", str_desc, length); + USBD_GetString((uint8_t*)MBOOT_USBD_PRODUCT_STRING, str_desc, length); return str_desc; case USBD_IDX_SERIAL_STR: { diff --git a/ports/stm32/usbd_desc.c b/ports/stm32/usbd_desc.c index 4babebf640..a7de71ef20 100644 --- a/ports/stm32/usbd_desc.c +++ b/ports/stm32/usbd_desc.c @@ -36,18 +36,40 @@ // 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. -// This needs a proper solution. -#define USBD_VID 0xf055 -#define USBD_PID 0x9800 +// need this header for any overrides to the below constants +#include "mpconfigboard.h" + +#ifndef USBD_LANGID_STRING #define USBD_LANGID_STRING 0x409 +#endif + +#ifndef USBD_MANUFACTURER_STRING #define USBD_MANUFACTURER_STRING "MicroPython" +#endif + +#ifndef USBD_PRODUCT_HS_STRING #define USBD_PRODUCT_HS_STRING "Pyboard Virtual Comm Port in HS Mode" +#endif + +#ifndef USBD_PRODUCT_FS_STRING #define USBD_PRODUCT_FS_STRING "Pyboard Virtual Comm Port in FS Mode" +#endif + +#ifndef USBD_CONFIGURATION_HS_STRING #define USBD_CONFIGURATION_HS_STRING "Pyboard Config" +#endif + +#ifndef USBD_INTERFACE_HS_STRING #define USBD_INTERFACE_HS_STRING "Pyboard Interface" +#endif + +#ifndef USBD_CONFIGURATION_FS_STRING #define USBD_CONFIGURATION_FS_STRING "Pyboard Config" +#endif + +#ifndef USBD_INTERFACE_FS_STRING #define USBD_INTERFACE_FS_STRING "Pyboard Interface" +#endif __ALIGN_BEGIN static const uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END = { USB_LEN_LANGID_STR_DESC, From 73c48b1b453e3531966901f088f35f8d94e392c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Krac=C3=ADk?= Date: Fri, 1 Mar 2019 08:52:40 +0100 Subject: [PATCH 0193/1788] esp32/modnetwork: Implement RSSI for WiFi STA via WLAN.status('rssi'). --- ports/esp32/modnetwork.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index 3754b293f1..a9c379e16b 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -398,7 +398,14 @@ STATIC mp_obj_t esp_status(size_t n_args, const mp_obj_t *args) { } return list; } + case (uintptr_t)MP_OBJ_NEW_QSTR(MP_QSTR_rssi): { + // return signal of AP, only in STA mode + require_if(args[0], WIFI_IF_STA); + wifi_ap_record_t info; + ESP_EXCEPTIONS(esp_wifi_sta_get_ap_info(&info)); + return MP_OBJ_NEW_SMALL_INT(info.rssi); + } default: mp_raise_ValueError("unknown status param"); } From 41e7ad647e6434d79847d43a445d2ae14f384322 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Krac=C3=ADk?= Date: Sun, 3 Mar 2019 12:14:23 +0100 Subject: [PATCH 0194/1788] esp32/modnetwork: Remove redundant esp_log include. --- ports/esp32/modnetwork.c | 1 - 1 file changed, 1 deletion(-) diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index a9c379e16b..5d3c19b802 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -46,7 +46,6 @@ #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" From fcace26d87a99a23e74461e0b59f740de9f40365 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 11 Mar 2019 23:17:09 +1100 Subject: [PATCH 0195/1788] esp32/Makefile: Add some missing IDF source files to bootloader and app. Functions in these files may be needed when certain features are enabled (eg dual core mode), even if the linker does not give a warning or error about unresolved symbols. --- ports/esp32/Makefile | 49 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 36ee4b3b0a..ea90c9f3f5 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -135,6 +135,7 @@ LDFLAGS += -L$(ESPCOMP)/esp32/ld LDFLAGS += -T $(BUILD)/esp32_out.ld LDFLAGS += -T $(BUILD)/esp32.common.ld LDFLAGS += -T esp32.rom.ld +LDFLAGS += -T esp32.rom.libgcc.ld LDFLAGS += -T esp32.peripherals.ld LIBGCC_FILE_NAME = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) @@ -265,10 +266,16 @@ $(BUILD)/$(ESPCOMP)/esp32/dport_access.o: CFLAGS += -Wno-array-bounds ESPIDF_ESP32_O = $(addprefix $(ESPCOMP)/esp32/,\ brownout.o \ cache_sram_mmu.o \ + coexist.o \ dbg_stubs.o \ + dport_panic_highint_hdl.o \ esp_err_to_name.o \ + esp_himem.o \ panic.o \ + pm_trace.o \ reset_reason.o \ + restore.o \ + stack_check.o \ esp_timer.o \ esp_timer_esp32.o \ ets_timer_legacy.o \ @@ -362,6 +369,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/xtensa_vector_defaults.o: CFLAGS = $(CFLAGS_ASM) $(BUILD)/$(ESPCOMP)/freertos/%.o: CFLAGS = $(CFLAGS_BASE) -I. -I$(BUILD) $(INC_ESPCOMP) -I$(ESPCOMP)/freertos/include/freertos -D_ESP_FREERTOS_INTERNAL ESPIDF_FREERTOS_O = $(addprefix $(ESPCOMP)/freertos/,\ croutine.o \ @@ -914,16 +922,38 @@ $(BOOTLOADER_LIB_DIR)/libmicro-ecc.a: $(BOOTLOADER_LIB_MICRO_ECC_OBJ) $(ECHO) "AR $@" $(Q)$(AR) cr $@ $^ -# remaining object files -BOOTLOADER_OBJ = $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/,\ - soc/esp32/rtc_clk.o \ - soc/esp32/rtc_clk_init.o \ - soc/esp32/rtc_init.o \ - soc/esp32/rtc_time.o \ - soc/esp32/rtc_wdt.o \ - soc/esp32/cpu_util.o \ +# libsoc.a +$(BUILD)/bootloader/$(ESPCOMP)/soc/esp32/rtc_clk.o: CFLAGS += -fno-jump-tables -fno-tree-switch-conversion +BOOTLOADER_LIB_ALL += soc +BOOTLOADER_LIB_SOC_OBJ = $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/soc/,\ + esp32/cpu_util.o \ + esp32/gpio_periph.o \ + esp32/rtc_clk.o \ + esp32/rtc_clk_init.o \ + esp32/rtc_init.o \ + esp32/rtc_periph.o \ + esp32/rtc_pm.o \ + esp32/rtc_sleep.o \ + esp32/rtc_time.o \ + esp32/rtc_wdt.o \ + esp32/sdio_slave_periph.o \ + esp32/sdmmc_periph.o \ + esp32/soc_memory_layout.o \ + esp32/spi_periph.o \ + src/memory_layout_utils.o \ + ) +$(BOOTLOADER_LIB_DIR)/libsoc.a: $(BOOTLOADER_LIB_SOC_OBJ) + $(ECHO) "AR $@" + $(Q)$(AR) cr $@ $^ + +# libmain.a +BOOTLOADER_LIB_ALL += main +BOOTLOADER_LIB_MAIN_OBJ = $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/,\ bootloader/subproject/main/bootloader_start.o \ ) +$(BOOTLOADER_LIB_DIR)/libmain.a: $(BOOTLOADER_LIB_MAIN_OBJ) + $(ECHO) "AR $@" + $(Q)$(AR) cr $@ $^ # all objects files BOOTLOADER_OBJ_ALL = \ @@ -931,7 +961,8 @@ BOOTLOADER_OBJ_ALL = \ $(BOOTLOADER_LIB_LOG_OBJ) \ $(BOOTLOADER_LIB_SPI_FLASH_OBJ) \ $(BOOTLOADER_LIB_MICRO_ECC_OBJ) \ - $(BOOTLOADER_OBJ) + $(BOOTLOADER_LIB_SOC_OBJ) \ + $(BOOTLOADER_LIB_MAIN_OBJ) $(BOOTLOADER_OBJ_ALL): $(SDKCONFIG_H) From 297092a76a6be2d5f5da32524e91f768e95937f4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 12 Mar 2019 15:46:44 +1100 Subject: [PATCH 0196/1788] esp32/mphalport: Use ets_delay_us for mp_hal_delay_us_fast. The system provided one is in ROM and is more accurate. --- ports/esp32/mphalport.c | 9 --------- ports/esp32/mphalport.h | 2 +- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/ports/esp32/mphalport.c b/ports/esp32/mphalport.c index 7992c8dedf..804c719869 100644 --- a/ports/esp32/mphalport.c +++ b/ports/esp32/mphalport.c @@ -148,15 +148,6 @@ void mp_hal_delay_us(uint32_t 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() { diff --git a/ports/esp32/mphalport.h b/ports/esp32/mphalport.h index b829627792..ff39b7aa1c 100644 --- a/ports/esp32/mphalport.h +++ b/ports/esp32/mphalport.h @@ -47,7 +47,7 @@ __attribute__((always_inline)) static inline uint32_t mp_hal_ticks_cpu(void) { } void mp_hal_delay_us(uint32_t); -void mp_hal_delay_us_fast(uint32_t); +#define mp_hal_delay_us_fast(us) ets_delay_us(us) void mp_hal_set_interrupt_char(int c); uint32_t mp_hal_get_cpu_freq(void); From a42c1d9fd5bc18dc69c635c3dc876bd52cba2240 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 27 Sep 2018 00:24:40 +0300 Subject: [PATCH 0197/1788] zephyr/modzephyr: Revamp stacks_analyze() call. Underlying k_call_stacks_analyze() was gone in Zephyr, reimplement using k_thread_foreach(). --- ports/zephyr/modzephyr.c | 23 ++++++++++++++++++++++- ports/zephyr/prj_base.conf | 3 +++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/ports/zephyr/modzephyr.c b/ports/zephyr/modzephyr.c index 265fc882dc..3d686605d5 100644 --- a/ports/zephyr/modzephyr.c +++ b/ports/zephyr/modzephyr.c @@ -27,6 +27,7 @@ #include "py/mpconfig.h" #if MICROPY_PY_ZEPHYR +#include #include #include @@ -42,11 +43,29 @@ STATIC mp_obj_t mod_current_tid(void) { } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_current_tid_obj, mod_current_tid); +#ifdef CONFIG_THREAD_STACK_INFO +extern k_tid_t const _main_thread; +extern k_tid_t const _idle_thread; + +static void thread_stack_dump(const struct k_thread *thread, void *user_data) +{ + const char *th_name = k_thread_name_get((k_tid_t)thread); + + if (th_name == NULL) { + static char tid[9]; + snprintf(tid, sizeof(tid), "%08x", (int)thread); + th_name = tid; + } + + stack_analyze(th_name, (char*)thread->stack_info.start, thread->stack_info.size); +} + STATIC mp_obj_t mod_stacks_analyze(void) { - k_call_stacks_analyze(); + k_thread_foreach(thread_stack_dump, NULL); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_stacks_analyze_obj, mod_stacks_analyze); +#endif #ifdef CONFIG_NET_SHELL @@ -64,7 +83,9 @@ STATIC const mp_rom_map_elem_t mp_module_time_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_zephyr) }, { MP_ROM_QSTR(MP_QSTR_is_preempt_thread), MP_ROM_PTR(&mod_is_preempt_thread_obj) }, { MP_ROM_QSTR(MP_QSTR_current_tid), MP_ROM_PTR(&mod_current_tid_obj) }, + #ifdef CONFIG_THREAD_STACK_INFO { MP_ROM_QSTR(MP_QSTR_stacks_analyze), MP_ROM_PTR(&mod_stacks_analyze_obj) }, + #endif #ifdef CONFIG_NET_SHELL { MP_ROM_QSTR(MP_QSTR_shell_net_iface), MP_ROM_PTR(&mod_shell_net_iface_obj) }, diff --git a/ports/zephyr/prj_base.conf b/ports/zephyr/prj_base.conf index 34124dd3cc..993dfdc26f 100644 --- a/ports/zephyr/prj_base.conf +++ b/ports/zephyr/prj_base.conf @@ -51,6 +51,9 @@ CONFIG_NET_DHCPV4=y # Required for zephyr.stack_analyze() CONFIG_INIT_STACKS=y +CONFIG_THREAD_MONITOR=y +CONFIG_THREAD_NAME=y +CONFIG_THREAD_STACK_INFO=y # Required for usocket.pkt_get_info() CONFIG_NET_BUF_POOL_USAGE=y From 21fc0c448e13814df80eeecddfa9e53a3e2fa229 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 2 Nov 2018 20:30:12 +0300 Subject: [PATCH 0198/1788] zephyr/modzsensor: Rename "TEMP" sensor channel to "DIE_TEMP". I.e. on-die temperature sensor. Upstream made more fine-grained channels for different kinds of temperature. --- ports/zephyr/modzsensor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/zephyr/modzsensor.c b/ports/zephyr/modzsensor.c index 74c909d167..2630899b04 100644 --- a/ports/zephyr/modzsensor.c +++ b/ports/zephyr/modzsensor.c @@ -127,7 +127,7 @@ STATIC const mp_rom_map_elem_t mp_module_zsensor_globals_table[] = { C(MAGN_X), C(MAGN_Y), C(MAGN_Z), - C(TEMP), + C(DIE_TEMP), C(PRESS), C(PROX), C(HUMIDITY), From 755b0b807bc6f390f933372e153d29d5cd7fd7cc Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 25 Feb 2019 12:19:14 +0300 Subject: [PATCH 0199/1788] zephyr/prj_minimal.conf: Switch to CONFIG_STDOUT_CONSOLE. Prompted by code size analysis, after arduino_101 build overflowing ROM. --- ports/zephyr/prj_minimal.conf | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ports/zephyr/prj_minimal.conf b/ports/zephyr/prj_minimal.conf index 5d6b353ba3..d9c2894e6f 100644 --- a/ports/zephyr/prj_minimal.conf +++ b/ports/zephyr/prj_minimal.conf @@ -1,6 +1,12 @@ -CONFIG_STDOUT_CONSOLE=y -CONFIG_CONSOLE_HANDLER=y -CONFIG_UART_CONSOLE_DEBUG_SERVER_HOOKS=y CONFIG_NEWLIB_LIBC=y CONFIG_FLOAT=y CONFIG_MAIN_STACK_SIZE=4096 + +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_CONSOLE_SUBSYS=y +CONFIG_CONSOLE_GETCHAR=y +CONFIG_CONSOLE_GETCHAR_BUFSIZE=32 +CONFIG_CONSOLE_PUTCHAR_BUFSIZE=32 +# TODO: Disable once https://github.com/zephyrproject-rtos/zephyr/pull/13731 is merged +#CONFIG_CONSOLE=n +#CONFIG_UART_CONSOLE=n From 6d82499a487a5f528e268c6d0415393965a75587 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 25 Feb 2019 12:21:31 +0300 Subject: [PATCH 0200/1788] zephyr/Makefile: Proxy ram_report, rom_report targets from Zephyr. --- ports/zephyr/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ports/zephyr/Makefile b/ports/zephyr/Makefile index 8cb4c12ef7..8e71d7f081 100644 --- a/ports/zephyr/Makefile +++ b/ports/zephyr/Makefile @@ -62,7 +62,8 @@ CFLAGS = $(Z_CFLAGS) \ include $(TOP)/py/mkrules.mk -GENERIC_TARGETS = all zephyr run qemu qemugdb flash debug debugserver +GENERIC_TARGETS = all zephyr run qemu qemugdb flash debug debugserver \ + ram_report rom_report KCONFIG_TARGETS = \ initconfig config nconfig menuconfig xconfig gconfig \ oldconfig silentoldconfig defconfig savedefconfig \ From 7748375b6e5daaf9b7d917b4c6e6c37ffd4c25b6 Mon Sep 17 00:00:00 2001 From: Maureen Helm Date: Thu, 28 Feb 2019 13:14:41 -0600 Subject: [PATCH 0201/1788] zephyr/prj_frdm_k64f.conf: Add fxos8700 sensor. Adds the fxos8700 accelerometer/magnetometer/die temperature sensor to the frdm_k64f board configuration. --- ports/zephyr/prj_frdm_k64f.conf | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ports/zephyr/prj_frdm_k64f.conf b/ports/zephyr/prj_frdm_k64f.conf index 611d6bc0a4..c974bffb62 100644 --- a/ports/zephyr/prj_frdm_k64f.conf +++ b/ports/zephyr/prj_frdm_k64f.conf @@ -1,2 +1,8 @@ # Networking drivers CONFIG_NET_L2_ETHERNET=y + +# Sensor drivers +CONFIG_I2C=y +CONFIG_FXOS8700=y +CONFIG_FXOS8700_MODE_HYBRID=y +CONFIG_FXOS8700_TEMP=y From 493ee7df1875f3b15eac1a725e933fa7a386bd71 Mon Sep 17 00:00:00 2001 From: Maureen Helm Date: Thu, 28 Feb 2019 13:24:58 -0600 Subject: [PATCH 0202/1788] zephyr/prj_frdm_kw41z.conf: Add new board configuration. Adds a new board configuration for the frdm_kw41z board, including support for the fxos8700 accelerometer/magnetometer/die temperature sensor. --- ports/zephyr/prj_frdm_kw41z.conf | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 ports/zephyr/prj_frdm_kw41z.conf diff --git a/ports/zephyr/prj_frdm_kw41z.conf b/ports/zephyr/prj_frdm_kw41z.conf new file mode 100644 index 0000000000..de51820027 --- /dev/null +++ b/ports/zephyr/prj_frdm_kw41z.conf @@ -0,0 +1,5 @@ +# Sensor drivers +CONFIG_I2C=y +CONFIG_FXOS8700=y +CONFIG_FXOS8700_MODE_HYBRID=y +CONFIG_FXOS8700_TEMP=y From 68a5d6fe7746850ce049b8bf295bfce1382383f3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 12 Mar 2019 22:35:52 +1100 Subject: [PATCH 0203/1788] extmod/modlwip: Fix case where concurrency lock isn't released on error. --- extmod/modlwip.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index 1b8caa8944..c7e050129d 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -536,6 +536,15 @@ STATIC mp_uint_t lwip_udp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_ } \ assert(socket->pcb.tcp); +// Version of above for use when lock is held +#define STREAM_ERROR_CHECK_WITH_LOCK(socket) \ + if (socket->state < 0) { \ + *_errno = error_lookup_table[-socket->state]; \ + MICROPY_PY_LWIP_EXIT \ + return MP_STREAM_ERROR; \ + } \ + assert(socket->pcb.tcp); + // Helper function for send/sendto to handle TCP packets STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno) { @@ -572,7 +581,7 @@ STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui } // While we waited, something could happen - STREAM_ERROR_CHECK(socket); + STREAM_ERROR_CHECK_WITH_LOCK(socket); } u16_t write_len = MIN(available, len); From d390ad90534d35d31d891ad24f723675e4b077f5 Mon Sep 17 00:00:00 2001 From: johnthagen Date: Wed, 6 Mar 2019 07:42:28 -0500 Subject: [PATCH 0204/1788] docs/pyboard: Add link to pyboard v1.1 schematic and layout PDF. --- docs/pyboard/hardware/index.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/pyboard/hardware/index.rst b/docs/pyboard/hardware/index.rst index d6a14b2c5e..24e11c8d62 100644 --- a/docs/pyboard/hardware/index.rst +++ b/docs/pyboard/hardware/index.rst @@ -3,9 +3,12 @@ The pyboard hardware For the pyboard: -* `PYBv1.0 schematics and layout `_ (2.4MiB PDF) -* `PYBv1.0 metric dimensions `_ (360KiB PDF) -* `PYBv1.0 imperial dimensions `_ (360KiB PDF) +* v1.1 + * `PYBv1.1 schematics and layout `_ (2.9MiB PDF) +* v1.0 + * `PYBv1.0 schematics and layout `_ (2.4MiB PDF) + * `PYBv1.0 metric dimensions `_ (360KiB PDF) + * `PYBv1.0 imperial dimensions `_ (360KiB PDF) For the official skin modules: From ea95bdc1ca24e3006ef78a723e0740128ae4b0d9 Mon Sep 17 00:00:00 2001 From: johnthagen Date: Fri, 8 Mar 2019 10:20:11 -0500 Subject: [PATCH 0205/1788] docs/pyboard: Make pyboard v1.1 pinout the default shown in quickref. --- docs/pyboard/quickref.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/pyboard/quickref.rst b/docs/pyboard/quickref.rst index ec789f2f0b..5d4985f587 100644 --- a/docs/pyboard/quickref.rst +++ b/docs/pyboard/quickref.rst @@ -3,22 +3,22 @@ Quick reference for the pyboard =============================== -The below pinout is for PYBv1.0. You can also view pinouts for +The below pinout is for PYBv1.1. You can also view pinouts for other versions of the pyboard: -`PYBv1.1 `__ +`PYBv1.0 `__ or `PYBLITEv1.0-AC `__ or `PYBLITEv1.0 `__. .. only:: not latex - .. image:: http://micropython.org/resources/pybv10-pinout.jpg - :alt: PYBv1.0 pinout + .. image:: http://micropython.org/resources/pybv11-pinout.jpg + :alt: PYBv1.1 pinout :width: 700px .. only:: latex - .. image:: http://micropython.org/resources/pybv10-pinout-800px.jpg - :alt: PYBv1.0 pinout + .. image:: http://micropython.org/resources/pybv11-pinout-800px.jpg + :alt: PYBv1.1 pinout Below is a quick reference for the pyboard. If it is your first time working with this board please consider reading the following sections first: From 912e957512dc6a4582b1bd02aeb8f1c92be6f5b2 Mon Sep 17 00:00:00 2001 From: Martin Fischer Date: Tue, 12 Mar 2019 21:21:22 +0100 Subject: [PATCH 0206/1788] docs/develop: Fix typos in C-module example for example_add_ints. --- docs/develop/cmodules.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/develop/cmodules.rst b/docs/develop/cmodules.rst index c3de90a0f6..919f518242 100644 --- a/docs/develop/cmodules.rst +++ b/docs/develop/cmodules.rst @@ -74,7 +74,7 @@ Directory:: #define MODULE_EXAMPLE_ENABLED (1) // This is the function which will be called from Python as example.add_ints(a, b). - STATIC mp_obj_t example_add_ints(mp_obj_t a_obj, mp_obj_tab_obj) { + STATIC mp_obj_t example_add_ints(mp_obj_t a_obj, mp_obj_t b_obj) { // Extract the ints from the micropython input objects int a = mp_obj_get_int(a_obj); int b = mp_obj_get_int(b_obj); @@ -83,7 +83,7 @@ Directory:: return mp_obj_new_int(a + b); } // Define a Python reference to the function above - STATIC MP_DEFINE_CONST_FUN_OBJ_1(example_add_ints_obj, example_add_ints); + STATIC MP_DEFINE_CONST_FUN_OBJ_2(example_add_ints_obj, example_add_ints); // Define all properties of the example module. // Table entries are key/value pairs of the attribute name (a string) From 921b999225d0aaa220fb4c302e1fb514c6ab39f4 Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Wed, 13 Mar 2019 12:55:15 +0100 Subject: [PATCH 0207/1788] extmod/moduselect: Adjust select_select and poll_register to use size_t. --- extmod/moduselect.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extmod/moduselect.c b/extmod/moduselect.c index 13bf5611e7..a65fa6df29 100644 --- a/extmod/moduselect.c +++ b/extmod/moduselect.c @@ -111,7 +111,7 @@ STATIC mp_uint_t poll_map_poll(mp_map_t *poll_map, size_t *rwx_num) { } /// \function select(rlist, wlist, xlist[, timeout]) -STATIC mp_obj_t select_select(uint n_args, const mp_obj_t *args) { +STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) { // get array data from tuple/list arguments size_t rwx_len[3]; mp_obj_t *r_array, *w_array, *x_array; @@ -190,7 +190,7 @@ typedef struct _mp_obj_poll_t { } mp_obj_poll_t; /// \method register(obj[, eventmask]) -STATIC mp_obj_t poll_register(uint n_args, const mp_obj_t *args) { +STATIC mp_obj_t poll_register(size_t n_args, const mp_obj_t *args) { mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]); mp_uint_t flags; if (n_args == 3) { From 7d675f3a17b435c4dc7880ff597ab81274721ae9 Mon Sep 17 00:00:00 2001 From: Rami Ali Date: Fri, 19 Jan 2018 18:35:42 +1100 Subject: [PATCH 0208/1788] javascript: Add new port targeting JavaScript via Emscripten. In this port JavaScript is the underlying "machine" and MicroPython is transmuted into JavaScript by Emscripten. MicroPython can then run under Node.js or in the browser. --- ports/javascript/JSBackend.patch | 10 ++ ports/javascript/Makefile | 59 +++++++++ ports/javascript/README.md | 128 +++++++++++++++++++ ports/javascript/library.h | 31 +++++ ports/javascript/library.js | 69 ++++++++++ ports/javascript/main.c | 135 ++++++++++++++++++++ ports/javascript/modutime.c | 56 ++++++++ ports/javascript/mpconfigport.h | 212 +++++++++++++++++++++++++++++++ ports/javascript/mphalport.c | 62 +++++++++ ports/javascript/mphalport.h | 39 ++++++ ports/javascript/node_run.sh | 2 + ports/javascript/qstrdefsport.h | 1 + ports/javascript/wrapper.js | 70 ++++++++++ 13 files changed, 874 insertions(+) create mode 100644 ports/javascript/JSBackend.patch create mode 100644 ports/javascript/Makefile create mode 100644 ports/javascript/README.md create mode 100644 ports/javascript/library.h create mode 100644 ports/javascript/library.js create mode 100644 ports/javascript/main.c create mode 100644 ports/javascript/modutime.c create mode 100644 ports/javascript/mpconfigport.h create mode 100644 ports/javascript/mphalport.c create mode 100644 ports/javascript/mphalport.h create mode 100755 ports/javascript/node_run.sh create mode 100644 ports/javascript/qstrdefsport.h create mode 100644 ports/javascript/wrapper.js diff --git a/ports/javascript/JSBackend.patch b/ports/javascript/JSBackend.patch new file mode 100644 index 0000000000..a5fd41a3fb --- /dev/null +++ b/ports/javascript/JSBackend.patch @@ -0,0 +1,10 @@ +--- JSBackend.cpp 2018-01-10 16:35:07.331418145 +1100 ++++ JSBackend_mp_js.cpp 2018-01-10 16:40:04.804633134 +1100 +@@ -4280,6 +4280,7 @@ + + void JSWriter::calculateNativizedVars(const Function *F) { + NativizedVars.clear(); ++ return; + + for (Function::const_iterator I = F->begin(), BE = F->end(); I != BE; ++I) { + auto BI = &*I; diff --git a/ports/javascript/Makefile b/ports/javascript/Makefile new file mode 100644 index 0000000000..3ce698f101 --- /dev/null +++ b/ports/javascript/Makefile @@ -0,0 +1,59 @@ +include ../../py/mkenv.mk + +CROSS = 0 + +QSTR_DEFS = qstrdefsport.h + +include $(TOP)/py/py.mk + +CC = emcc -g4 +LD = emcc -g4 + +INC += -I. +INC += -I$(TOP) +INC += -I$(BUILD) + +CPP = clang -E +CFLAGS = -m32 $(INC) -Wall -Werror -std=c99 $(COPT) +LDFLAGS = -m32 -Wl,-Map=$@.map,--cref -Wl,--gc-sections + +CFLAGS += -O0 -DNDEBUG +CFLAGS += -fdata-sections -ffunction-sections + +SRC_LIB = $(addprefix lib/,\ + utils/interrupt_char.c \ + utils/stdout_helpers.c \ + utils/pyexec.c \ + mp-readline/readline.c \ + ) + +SRC_C = \ + main.c \ + mphalport.c \ + modutime.c \ + +SRC_QSTR += $(SRC_C) + +OBJ = +OBJ = $(PY_O) +OBJ += $(addprefix $(BUILD)/, $(SRC_LIB:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) + +JSFLAGS = -O0 -s EXPORTED_FUNCTIONS="['_mp_js_init', '_mp_js_init_repl', '_mp_js_do_str', '_mp_js_process_char', '_mp_hal_get_interrupt_char', '_mp_keyboard_interrupt']" -s EXTRA_EXPORTED_RUNTIME_METHODS="['ccall', 'cwrap']" --memory-init-file 0 --js-library library.js + +all: $(BUILD)/micropython.js + +$(BUILD)/micropython.js: $(OBJ) library.js wrapper.js + $(ECHO) "LINK $(BUILD)/firmware.js" + $(Q)emcc $(LDFLAGS) -o $(BUILD)/firmware.js $(OBJ) $(JSFLAGS) + cat $(BUILD)/firmware.js > $@ + cat wrapper.js >> $@ + +min: $(BUILD)/micropython.js + uglifyjs $< -c -o $(BUILD)/micropython.min.js + +test: $(BUILD)/micropython.js $(TOP)/tests/run-tests + $(eval DIRNAME=ports/$(notdir $(CURDIR))) + cd $(TOP)/tests && MICROPY_MICROPYTHON=../ports/javascript/node_run.sh ./run-tests + +include $(TOP)/py/mkrules.mk diff --git a/ports/javascript/README.md b/ports/javascript/README.md new file mode 100644 index 0000000000..ac268bb3bf --- /dev/null +++ b/ports/javascript/README.md @@ -0,0 +1,128 @@ +MicroPython.js +============== + +MicroPython transmuted into Javascript by Emscripten. + +Dependencies +------------ + +Building micropython.js bears the same requirements as the standard MicroPython +ports with the addition of Emscripten (and uglify-js for the minified file). + +A standard installation of Emscripten should provide functional code, however +if memory errors are encountered it may be worthwhile to modify the tool. +`emscripten-fastcomp/lib/Target/JSBackend.cpp` may require the minor fix +found in JSBackend.patch. This patch attempts to address situations where +C code running through Emscripten is denied access to Javascript variables +leading to false-positives in the MicroPython garbage collector as variables +with pointers exclusively in Javascript will be erased prematurely. +Refer to Emscripten documentation for instructions on building Emscripten +from source. + +Build instructions +------------------ + +In order to build micropython.js, run: + + $ make + +To generate the minified file micropython.min.js, run: + + $ make min + +Running with Node.js +-------------------- + +Access the repl with: + + $ node build/micropython.js + +Stack size may be modified using: + + $ node build/micropython.js -X stack=64K + +Where stack size may be represented in Bytes, KiB or MiB. + +MicroPython scripts may be executed using: + + $ node build/micropython.js hello.py + +Alternatively micropython.js may by accessed by other javascript programs in node +using the require command and the general API outlined below. For example: + +```javascript +var mp_js = require('./build/micropython.js'); + +mp_js_init(64 * 1024); +mp_js_do_str("print('hello world')\n"); +``` + +Running with HTML +----------------- + +The prerequisite for browser operation of micropython.js is an element with +the id `mp_js_stdout` which receives `print` events. The following code +demonstrates basic functionality: + +```html + + + + + + +
+ + + +``` + +MicroPython code execution will suspend the browser so be sure to atomize usage +within this environment. Unfortunately interrupts have not been implemented for the +browser. + +Testing +------- + +Run the test suite using: + + $ make test + +API +--- + +The following functions have been exposed to javascript. + +``` +mp_js_init(stack_size) +``` + +Initialize MicroPython with the given stack size in bytes. This must be +called before attempting to interact with MicroPython. + +``` +mp_js_do_str(code) +``` + +Execute the input code. `code` must be a `string`. + +``` +mp_js_init_repl() +``` + +Initialize MicroPython repl. Must be called before entering characters into +the repl. + +``` +mp_js_process_char(char) +``` + +Input character into MicroPython repl. `char` must be of type `number`. This +will execute MicroPython code when necessary. diff --git a/ports/javascript/library.h b/ports/javascript/library.h new file mode 100644 index 0000000000..47982e0640 --- /dev/null +++ b/ports/javascript/library.h @@ -0,0 +1,31 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017, 2018 Rami Ali + * + * 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" + +extern void mp_js_write(const char *str, mp_uint_t len); +extern int mp_js_ticks_ms(void); +extern void mp_js_hook(void); diff --git a/ports/javascript/library.js b/ports/javascript/library.js new file mode 100644 index 0000000000..ed58167d5d --- /dev/null +++ b/ports/javascript/library.js @@ -0,0 +1,69 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017, 2018 Rami Ali + * + * 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. + */ + +mergeInto(LibraryManager.library, { + mp_js_write: function(ptr, len) { + for (var i = 0; i < len; ++i) { + c = String.fromCharCode(getValue(ptr + i, 'i8')); + if (typeof window === 'undefined') { + process.stdout.write(c); + } else { + var mp_js_stdout = document.getElementById('mp_js_stdout'); + var print = new Event('print'); + print.data = c; + mp_js_stdout.dispatchEvent(print); + } + } + }, + + mp_js_ticks_ms: function() { + return (new Date()).getTime() - MP_JS_EPOCH; + }, + + mp_js_hook: function() { + if (typeof window === 'undefined') { + var mp_interrupt_char = Module.ccall('mp_hal_get_interrupt_char', 'number', ['number'], ['null']); + var fs = require('fs'); + + var buf = new Buffer(1); + try { + var n = fs.readSync(process.stdin.fd, buf, 0, 1); + if (n > 0) { + if (buf[0] == mp_interrupt_char) { + Module.ccall('mp_keyboard_interrupt', 'null', ['null'], ['null']); + } else { + process.stdout.write(String.fromCharCode(buf[0])); + } + } + } catch (e) { + if (e.code === 'EAGAIN') { + } else { + throw e; + } + } + } + }, +}); diff --git a/ports/javascript/main.c b/ports/javascript/main.c new file mode 100644 index 0000000000..65bae98b44 --- /dev/null +++ b/ports/javascript/main.c @@ -0,0 +1,135 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George and 2017, 2018 Rami Ali + * + * 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/compile.h" +#include "py/runtime.h" +#include "py/repl.h" +#include "py/gc.h" +#include "py/mperrno.h" +#include "lib/utils/pyexec.h" + +#include "library.h" + +#if MICROPY_ENABLE_COMPILER +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, false); + mp_call_function_0(module_fun); + nlr_pop(); + } else { + // uncaught exception + if (mp_obj_is_subclass_fast(mp_obj_get_type((mp_obj_t)nlr.ret_val), &mp_type_SystemExit)) { + // at the moment, the value of SystemExit is unused + } else { + mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); + } + } +} +#endif + +static char *stack_top; + +void mp_js_do_str(const char *code) { + do_str(code, MP_PARSE_FILE_INPUT); +} + +int mp_js_process_char(int c) { + return pyexec_event_repl_process_char(c); +} + +void mp_js_init(int heap_size) { + int stack_dummy; + stack_top = (char*)&stack_dummy; + + #if MICROPY_ENABLE_GC + char *heap = (char*)malloc(heap_size * sizeof(char)); + 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(); + + mp_obj_list_init(mp_sys_path, 0); + mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); + mp_obj_list_init(mp_sys_argv, 0); +} + +void mp_js_init_repl() { + pyexec_event_repl_init(); +} + +void gc_collect(void) { + // WARNING: This gc_collect implementation doesn't try to get root + // pointers from CPU registers, and thus may function incorrectly. + jmp_buf dummy; + if (setjmp(dummy) == 0) { + longjmp(dummy, 1); + } + gc_collect_start(); + gc_collect_root((void*)stack_top, ((mp_uint_t)(void*)(&dummy + 1) - (mp_uint_t)stack_top) / sizeof(mp_uint_t)); + gc_collect_end(); +} + +mp_lexer_t *mp_lexer_new_from_file(const char *filename) { + mp_raise_OSError(MP_ENOENT); +} + +mp_import_stat_t mp_import_stat(const char *path) { + return MP_IMPORT_STAT_NO_EXIST; +} + +mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open); + +void nlr_jump_fail(void *val) { + while (1); +} + +void NORETURN __fatal_error(const char *msg) { + while (1); +} + +#ifndef NDEBUG +void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) { + printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line); + __fatal_error("Assertion failed"); +} +#endif diff --git a/ports/javascript/modutime.c b/ports/javascript/modutime.c new file mode 100644 index 0000000000..6c6bdcfa27 --- /dev/null +++ b/ports/javascript/modutime.c @@ -0,0 +1,56 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George and 2017, 2018 Rami Ali + * + * 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 "mphalport.h" +#include "py/nlr.h" +#include "py/smallint.h" +#include "py/obj.h" +#include "py/runtime.h" +#include "lib/timeutils/timeutils.h" +#include "extmod/utime_mphal.h" + +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_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 mp_module_utime = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&time_module_globals, +}; diff --git a/ports/javascript/mpconfigport.h b/ports/javascript/mpconfigport.h new file mode 100644 index 0000000000..228113c48e --- /dev/null +++ b/ports/javascript/mpconfigport.h @@ -0,0 +1,212 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George and 2017, 2018 Rami Ali + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +// options to control how MicroPython is built + +// You can disable the built-in MicroPython compiler by setting the following +// config option to 0. If you do this then you won't get a REPL prompt, but you +// will still be able to execute pre-compiled scripts, compiled with mpy-cross. +#define MICROPY_ENABLE_COMPILER (1) + +#define MICROPY_QSTR_BYTES_IN_HASH (2) +#define MICROPY_ALLOC_PATH_MAX (256) +#define MICROPY_ALLOC_PARSE_CHUNK_INIT (16) +#define MICROPY_EMIT_X64 (0) //BROKEN +#define MICROPY_EMIT_THUMB (0) //BROKEN +#define MICROPY_EMIT_INLINE_THUMB (0) +#define MICROPY_COMP_MODULE_CONST (0) +#define MICROPY_COMP_CONST (1) +#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (1) +#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0) +#define MICROPY_MEM_STATS (0) //BROKEN +#define MICROPY_DEBUG_PRINTERS (0) +#define MICROPY_ENABLE_GC (1) +#define MICROPY_GC_ALLOC_THRESHOLD (1) +#define MICROPY_GC_USES_ALLOCATED_SIZE (1) +#define MICROPY_REPL_EVENT_DRIVEN (1) +#define MICROPY_HELPER_REPL (1) +#define MICROPY_HELPER_LEXER_UNIX (0) +#define MICROPY_ENABLE_SOURCE_LINE (1) +#define MICROPY_ENABLE_DOC_STRING (1) +#define MICROPY_WARNINGS (1) +#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (1) +#define MICROPY_PY_ASYNC_AWAIT (1) +#define MICROPY_PY_BUILTINS_BYTEARRAY (1) +#define MICROPY_PY_BUILTINS_MEMORYVIEW (1) +#define MICROPY_PY_BUILTINS_ENUMERATE (1) +#define MICROPY_PY_BUILTINS_FILTER (1) +#define MICROPY_PY_BUILTINS_FROZENSET (1) +#define MICROPY_PY_BUILTINS_REVERSED (1) +#define MICROPY_PY_BUILTINS_SET (1) +#define MICROPY_PY_BUILTINS_SLICE (1) +#define MICROPY_PY_BUILTINS_PROPERTY (1) +#define MICROPY_PY_BUILTINS_MIN_MAX (1) +#define MICROPY_PY___FILE__ (1) +#define MICROPY_PY_GC (1) +#define MICROPY_PY_ARRAY (1) +#define MICROPY_PY_ATTRTUPLE (1) +#define MICROPY_PY_COLLECTIONS (1) +#define MICROPY_PY_MATH (1) +#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) +#define MICROPY_PY_CMATH (1) +#define MICROPY_PY_IO (1) +#define MICROPY_PY_STRUCT (1) +#define MICROPY_PY_SYS (1) +#define MICROPY_PY_SYS_MAXSIZE (1) +#define MICROPY_CPYTHON_COMPAT (1) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_DOUBLE) + +#define MICROPY_USE_INTERNAL_PRINTF (0) +#define MICROPY_ENABLE_PYSTACK (1) +#define MICROPY_KBD_EXCEPTION (1) +#define MICROPY_PY_UTIME_MP_HAL (1) +#define MICROPY_REPL_AUTO_INDENT (1) +#define MICROPY_PY_FUNCTION_ATTRS (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_SLICE_ATTRS (1) +#define MICROPY_PY_ALL_SPECIAL_METHODS (1) +#define MICROPY_PY_BUILTINS_COMPILE (1) +#define MICROPY_PY_BUILTINS_EXECFILE (1) +#define MICROPY_PY_BUILTINS_INPUT (1) +#define MICROPY_PY_BUILTINS_POW3 (1) +#define MICROPY_PY_BUILTINS_HELP (1) +#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_ORDEREDDICT (1) +#define MICROPY_PY_SYS_PLATFORM "javascript" +#define MICROPY_PY_UERRNO (1) +#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_UHASHLIB (1) +#define MICROPY_PY_UBINASCII (1) +#define MICROPY_PY_URANDOM (1) +#define MICROPY_PY_URANDOM_EXTRA_FUNCS (1) +#define MICROPY_PY_USELECT (1) +#define MICROPY_PY_FRAMEBUF (1) +#define MICROPY_STREAMS_NON_BLOCK (1) +#define MICROPY_MODULE_WEAK_LINKS (1) +#define MICROPY_CAN_OVERRIDE_BUILTINS (1) +#define MICROPY_USE_INTERNAL_ERRNO (1) +#define MICROPY_ENABLE_SCHEDULER (1) +#define MICROPY_SCHEDULER_DEPTH (1) + +#define MP_SSIZE_MAX (0x7fffffff) + +extern const struct _mp_obj_module_t mp_module_utime; + +#define MICROPY_PORT_BUILTIN_MODULES \ + { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_utime) }, \ + +#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \ + { 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_re), MP_ROM_PTR(&mp_module_ure) }, \ + { MP_ROM_QSTR(MP_QSTR_zlib), MP_ROM_PTR(&mp_module_uzlib) }, \ + { MP_ROM_QSTR(MP_QSTR_json), MP_ROM_PTR(&mp_module_ujson) }, \ + { MP_ROM_QSTR(MP_QSTR_heapq), MP_ROM_PTR(&mp_module_uheapq) }, \ + { 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_random), MP_ROM_PTR(&mp_module_urandom) }, \ + { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mp_module_utime) }, \ + { MP_ROM_QSTR(MP_QSTR_select), MP_ROM_PTR(&mp_module_uselect) }, \ + { MP_ROM_QSTR(MP_QSTR_struct), MP_ROM_PTR(&mp_module_ustruct) }, \ + { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mp_module_uerrno) }, \ + +//#define MICROPY_EVENT_POLL_HOOK {ets_event_poll();} +#if MICROPY_PY_THREAD +#define MICROPY_EVENT_POLL_HOOK \ + do { \ + extern void mp_handle_pending(void); \ + mp_handle_pending(); \ + if (pyb_thread_enabled) { \ + MP_THREAD_GIL_EXIT(); \ + pyb_thread_yield(); \ + MP_THREAD_GIL_ENTER(); \ + } else { \ + } \ + } while (0); + +#define MICROPY_THREAD_YIELD() pyb_thread_yield() +#else +#define MICROPY_EVENT_POLL_HOOK \ + do { \ + extern void mp_handle_pending(void); \ + mp_handle_pending(); \ + } while (0); + +#define MICROPY_THREAD_YIELD() +#endif + +#define MICROPY_VM_HOOK_COUNT (10) +#define MICROPY_VM_HOOK_INIT static uint vm_hook_divisor = MICROPY_VM_HOOK_COUNT; +#define MICROPY_VM_HOOK_POLL if (--vm_hook_divisor == 0) { \ + vm_hook_divisor = MICROPY_VM_HOOK_COUNT; \ + extern void mp_js_hook(void); \ + mp_js_hook(); \ + } +#define MICROPY_VM_HOOK_LOOP MICROPY_VM_HOOK_POLL +#define MICROPY_VM_HOOK_RETURN MICROPY_VM_HOOK_POLL + +// type definitions for the specific machine + +//#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1)) + +// This port is intended to be 32-bit, but unfortunately, int32_t for +// different targets may be defined in different ways - either as int +// or as long. This requires different printf formatting specifiers +// to print such value. So, we avoid int32_t and use int directly. +#define UINT_FMT "%u" +#define INT_FMT "%d" +typedef int mp_int_t; // must be pointer size +typedef unsigned mp_uint_t; // must be pointer size +typedef long mp_off_t; + +#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) + +// extra built in names to add to the global namespace +#define MICROPY_PORT_BUILTINS \ + { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) }, + +// We need to provide a declaration/definition of alloca() +#include + +#define MICROPY_HW_BOARD_NAME "JS" +#define MICROPY_HW_MCU_NAME "Emscripten" + +#define MP_STATE_PORT MP_STATE_VM + +#define MICROPY_PORT_ROOT_POINTERS \ + const char *readline_hist[8]; diff --git a/ports/javascript/mphalport.c b/ports/javascript/mphalport.c new file mode 100644 index 0000000000..18e3e2adeb --- /dev/null +++ b/ports/javascript/mphalport.c @@ -0,0 +1,62 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George and 2017, 2018 Rami Ali + * + * 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 "library.h" +#include "mphalport.h" + +void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { + mp_js_write(str, len); +} + +void mp_hal_delay_ms(mp_uint_t ms) { + uint32_t start = mp_hal_ticks_ms(); + while (mp_hal_ticks_ms() - start < ms) { + } +} + +void mp_hal_delay_us(mp_uint_t us) { + uint32_t start = mp_hal_ticks_us(); + while (mp_hal_ticks_us() - start < us) { + } +} + +mp_uint_t mp_hal_ticks_us(void) { + return mp_js_ticks_ms() * 1000; +} + +mp_uint_t mp_hal_ticks_ms(void) { + return mp_js_ticks_ms(); +} + +mp_uint_t mp_hal_ticks_cpu(void) { + return 0; +} + +extern int mp_interrupt_char; + +int mp_hal_get_interrupt_char(void) { + return mp_interrupt_char; +} diff --git a/ports/javascript/mphalport.h b/ports/javascript/mphalport.h new file mode 100644 index 0000000000..8ba66fcc9f --- /dev/null +++ b/ports/javascript/mphalport.h @@ -0,0 +1,39 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George and 2017, 2018 Rami Ali + * + * 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/utils/interrupt_char.h" + +#define mp_hal_stdin_rx_chr() (0) +void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len); + +void mp_hal_delay_ms(mp_uint_t ms); +void mp_hal_delay_us(mp_uint_t us); +mp_uint_t mp_hal_ticks_ms(void); +mp_uint_t mp_hal_ticks_us(void); +mp_uint_t mp_hal_ticks_cpu(void); + +int mp_hal_get_interrupt_char(void); diff --git a/ports/javascript/node_run.sh b/ports/javascript/node_run.sh new file mode 100755 index 0000000000..466ffe39e3 --- /dev/null +++ b/ports/javascript/node_run.sh @@ -0,0 +1,2 @@ +#!/bin/sh +node $(dirname $0)/build/micropython.js "$@" diff --git a/ports/javascript/qstrdefsport.h b/ports/javascript/qstrdefsport.h new file mode 100644 index 0000000000..3ba897069b --- /dev/null +++ b/ports/javascript/qstrdefsport.h @@ -0,0 +1 @@ +// qstrs specific to this port diff --git a/ports/javascript/wrapper.js b/ports/javascript/wrapper.js new file mode 100644 index 0000000000..6109de902f --- /dev/null +++ b/ports/javascript/wrapper.js @@ -0,0 +1,70 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017, 2018 Rami Ali + * + * 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. + */ + +mp_js_init = Module.cwrap('mp_js_init', 'null', ['number']); +mp_js_do_str = Module.cwrap('mp_js_do_str', 'null', ['string']); +mp_js_init_repl = Module.cwrap('mp_js_init_repl', 'null', ['null']); +mp_js_process_char = Module.cwrap('mp_js_process_char', 'number', ['number']); + +var MP_JS_EPOCH = (new Date()).getTime(); + +if (typeof window === 'undefined' && require.main === module) { + var fs = require('fs'); + var stack_size = 64 * 1024; + var contents = ''; + var repl = true; + + for (var i = 0; i < process.argv.length; i++) { + if (process.argv[i] === '-X' && i < process.argv.length - 1) { + if (process.argv[i + 1].includes('stack=')) { + stack_size = parseInt(process.argv[i + 1].split('stack=')[1]); + if (process.argv[i + 1].substr(-1).toLowerCase() === 'k') { + stack_size *= 1024; + } else if (process.argv[i + 1].substr(-1).toLowerCase() === 'm') { + stack_size *= 1024 * 1024; + } + } + } else if (process.argv[i].includes('.py')) { + contents += fs.readFileSync(process.argv[i], 'utf8'); + repl = false;; + } + } + mp_js_init(stack_size); + + if (repl) { + mp_js_init_repl(); + process.stdin.setRawMode(true); + process.stdin.on('data', function (data) { + for (var i = 0; i < data.length; i++) { + if (mp_js_process_char(data[i])) { + process.exit() + } + } + }); + } else { + mp_js_do_str(contents); + } +} From ea2fcdd338b9a9a545c119a7d86de1b8caf77314 Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Sun, 10 Feb 2019 16:29:25 +0100 Subject: [PATCH 0209/1788] javascript: Fix Emscripten async load, and to compile with modern clang. --- ports/javascript/Makefile | 10 +++-- ports/javascript/mphalport.c | 2 +- ports/javascript/mphalport.h | 2 +- ports/javascript/wrapper.js | 85 +++++++++++++++++++----------------- 4 files changed, 55 insertions(+), 44 deletions(-) diff --git a/ports/javascript/Makefile b/ports/javascript/Makefile index 3ce698f101..9b0f4d89c0 100644 --- a/ports/javascript/Makefile +++ b/ports/javascript/Makefile @@ -14,7 +14,12 @@ INC += -I$(TOP) INC += -I$(BUILD) CPP = clang -E -CFLAGS = -m32 $(INC) -Wall -Werror -std=c99 $(COPT) + +ifdef EMSCRIPTEN + CPP += -isystem $(EMSCRIPTEN)/system/include/libc -cxx-isystem $(EMSCRIPTEN)/system/include/libcxx +endif + +CFLAGS = -m32 -Wall -Werror $(INC) -std=c99 $(COPT) LDFLAGS = -m32 -Wl,-Map=$@.map,--cref -Wl,--gc-sections CFLAGS += -O0 -DNDEBUG @@ -46,8 +51,7 @@ all: $(BUILD)/micropython.js $(BUILD)/micropython.js: $(OBJ) library.js wrapper.js $(ECHO) "LINK $(BUILD)/firmware.js" $(Q)emcc $(LDFLAGS) -o $(BUILD)/firmware.js $(OBJ) $(JSFLAGS) - cat $(BUILD)/firmware.js > $@ - cat wrapper.js >> $@ + cat wrapper.js $(BUILD)/firmware.js > $@ min: $(BUILD)/micropython.js uglifyjs $< -c -o $(BUILD)/micropython.min.js diff --git a/ports/javascript/mphalport.c b/ports/javascript/mphalport.c index 18e3e2adeb..c938a63928 100644 --- a/ports/javascript/mphalport.c +++ b/ports/javascript/mphalport.c @@ -27,7 +27,7 @@ #include "library.h" #include "mphalport.h" -void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { +void mp_hal_stdout_tx_strn(const char *str, size_t len) { mp_js_write(str, len); } diff --git a/ports/javascript/mphalport.h b/ports/javascript/mphalport.h index 8ba66fcc9f..614ce8526a 100644 --- a/ports/javascript/mphalport.h +++ b/ports/javascript/mphalport.h @@ -28,7 +28,7 @@ #include "lib/utils/interrupt_char.h" #define mp_hal_stdin_rx_chr() (0) -void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len); +void mp_hal_stdout_tx_strn(const char *str, size_t len); void mp_hal_delay_ms(mp_uint_t ms); void mp_hal_delay_us(mp_uint_t us); diff --git a/ports/javascript/wrapper.js b/ports/javascript/wrapper.js index 6109de902f..84ad2ae3a7 100644 --- a/ports/javascript/wrapper.js +++ b/ports/javascript/wrapper.js @@ -24,47 +24,54 @@ * THE SOFTWARE. */ -mp_js_init = Module.cwrap('mp_js_init', 'null', ['number']); -mp_js_do_str = Module.cwrap('mp_js_do_str', 'null', ['string']); -mp_js_init_repl = Module.cwrap('mp_js_init_repl', 'null', ['null']); -mp_js_process_char = Module.cwrap('mp_js_process_char', 'number', ['number']); +var Module = {}; -var MP_JS_EPOCH = (new Date()).getTime(); +var mainProgram = function() +{ + mp_js_init = Module.cwrap('mp_js_init', 'null', ['number']); + mp_js_do_str = Module.cwrap('mp_js_do_str', 'null', ['string']); + mp_js_init_repl = Module.cwrap('mp_js_init_repl', 'null', ['null']); + mp_js_process_char = Module.cwrap('mp_js_process_char', 'number', ['number']); -if (typeof window === 'undefined' && require.main === module) { - var fs = require('fs'); - var stack_size = 64 * 1024; - var contents = ''; - var repl = true; + MP_JS_EPOCH = (new Date()).getTime(); - for (var i = 0; i < process.argv.length; i++) { - if (process.argv[i] === '-X' && i < process.argv.length - 1) { - if (process.argv[i + 1].includes('stack=')) { - stack_size = parseInt(process.argv[i + 1].split('stack=')[1]); - if (process.argv[i + 1].substr(-1).toLowerCase() === 'k') { - stack_size *= 1024; - } else if (process.argv[i + 1].substr(-1).toLowerCase() === 'm') { - stack_size *= 1024 * 1024; - } - } - } else if (process.argv[i].includes('.py')) { - contents += fs.readFileSync(process.argv[i], 'utf8'); - repl = false;; - } - } - mp_js_init(stack_size); + if (typeof window === 'undefined' && require.main === module) { + var fs = require('fs'); + var stack_size = 64 * 1024; + var contents = ''; + var repl = true; - if (repl) { - mp_js_init_repl(); - process.stdin.setRawMode(true); - process.stdin.on('data', function (data) { - for (var i = 0; i < data.length; i++) { - if (mp_js_process_char(data[i])) { - process.exit() - } - } - }); - } else { - mp_js_do_str(contents); - } + for (var i = 0; i < process.argv.length; i++) { + if (process.argv[i] === '-X' && i < process.argv.length - 1) { + if (process.argv[i + 1].includes('stack=')) { + stack_size = parseInt(process.argv[i + 1].split('stack=')[1]); + if (process.argv[i + 1].substr(-1).toLowerCase() === 'k') { + stack_size *= 1024; + } else if (process.argv[i + 1].substr(-1).toLowerCase() === 'm') { + stack_size *= 1024 * 1024; + } + } + } else if (process.argv[i].includes('.py')) { + contents += fs.readFileSync(process.argv[i], 'utf8'); + repl = false;; + } + } + mp_js_init(stack_size); + + if (repl) { + mp_js_init_repl(); + process.stdin.setRawMode(true); + process.stdin.on('data', function (data) { + for (var i = 0; i < data.length; i++) { + if (mp_js_process_char(data[i])) { + process.exit() + } + } + }); + } else { + mp_js_do_str(contents); + } + } } + +Module["onRuntimeInitialized"] = mainProgram; \ No newline at end of file From 349b54525e0b9715dde713c4ff64ca2660163fe9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 28 Feb 2019 12:38:28 +1100 Subject: [PATCH 0210/1788] esp32/machine_pin: Make it so None as pull value disables pull up/down. Previously specifying None as the pull value would leave the pull up/down state unchanged. This change makes it so -1 leaves the state unchanged and None makes the pin float, as per the docs. --- ports/esp32/machine_pin.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ports/esp32/machine_pin.c b/ports/esp32/machine_pin.c index a899fa62ad..648674f9ad 100644 --- a/ports/esp32/machine_pin.c +++ b/ports/esp32/machine_pin.c @@ -137,7 +137,7 @@ STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_ 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_pull, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(-1)}}, { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, }; @@ -164,8 +164,12 @@ STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_ } // 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)); + if (args[ARG_pull].u_obj != MP_OBJ_NEW_SMALL_INT(-1)) { + if (args[ARG_pull].u_obj == mp_const_none) { + gpio_set_pull_mode(self->id, GPIO_FLOATING); + } else { + gpio_set_pull_mode(self->id, mp_obj_get_int(args[ARG_pull].u_obj)); + } } return mp_const_none; From ddc934631ca318b41ae2c7cf839936bda0277771 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 8 Mar 2019 23:51:39 +1100 Subject: [PATCH 0211/1788] esp32/machine_pin: Add new PULL_HOLD pin pull mode. --- ports/esp32/machine_pin.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/ports/esp32/machine_pin.c b/ports/esp32/machine_pin.c index 648674f9ad..cbd9ae7e9f 100644 --- a/ports/esp32/machine_pin.c +++ b/ports/esp32/machine_pin.c @@ -39,6 +39,9 @@ #include "machine_rtc.h" #include "modesp32.h" +// Used to implement gpio_hold_en() functionality; value should be distinct from all IDF pull modes +#define GPIO_PULLHOLD (8) + typedef struct _machine_pin_obj_t { mp_obj_base_t base; gpio_num_t id; @@ -168,7 +171,15 @@ STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_ if (args[ARG_pull].u_obj == mp_const_none) { gpio_set_pull_mode(self->id, GPIO_FLOATING); } else { - gpio_set_pull_mode(self->id, mp_obj_get_int(args[ARG_pull].u_obj)); + int mode = mp_obj_get_int(args[ARG_pull].u_obj); + if (mode == GPIO_PULLHOLD) { + gpio_hold_en(self->id); + } else { + if (GPIO_IS_VALID_OUTPUT_GPIO(self->id)) { + gpio_hold_dis(self->id); + } + gpio_set_pull_mode(self->id, mode); + } } } @@ -320,6 +331,7 @@ STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = { { 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_PULL_HOLD), MP_ROM_INT(GPIO_PULLHOLD) }, { 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) }, From 6fa830bfd84fe0d4b3f33381ec38bd987c4937dc Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 14 Mar 2019 07:29:04 +1100 Subject: [PATCH 0212/1788] docs/library/machine.Pin: Add PULL_HOLD constant to possible pin pulls. As already mentioned in the docs, not all constants may be available on all ports, so this is optional to implement. --- docs/library/machine.Pin.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/library/machine.Pin.rst b/docs/library/machine.Pin.rst index a355a6f7ce..5254e163c0 100644 --- a/docs/library/machine.Pin.rst +++ b/docs/library/machine.Pin.rst @@ -235,6 +235,7 @@ not all constants are available on all ports. .. data:: Pin.PULL_UP Pin.PULL_DOWN + Pin.PULL_HOLD Selects whether there is a pull up/down resistor. Use the value ``None`` for no pull. From 28c2873d99a6dcd8978eea1161fc2346fed067d0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 14 Mar 2019 07:38:50 +1100 Subject: [PATCH 0213/1788] docs/esp32: Add a note to quickref about use of Pin.PULL_HOLD. --- docs/esp32/quickref.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst index 426d14e3ec..e6c53b1172 100644 --- a/docs/esp32/quickref.rst +++ b/docs/esp32/quickref.rst @@ -161,6 +161,9 @@ Notes: * Pins 34-39 are input only, and also do not have internal pull-up resistors +* The pull value of some pins can be set to ``Pin.PULL_HOLD`` to reduce power + consumption during deepsleep. + PWM (pulse width modulation) ---------------------------- From 3b973a5658025bb99f503fb15ba11884729ac77a Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 9 Mar 2019 10:16:09 +1100 Subject: [PATCH 0214/1788] py: Move mp_native_type_from_qstr() from emitnative.c to nativeglue.c. --- py/emit.h | 2 -- py/emitnative.c | 14 -------------- py/nativeglue.c | 14 ++++++++++++++ py/runtime.h | 1 + 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/py/emit.h b/py/emit.h index 34c6cfd845..2a5da8e8e3 100644 --- a/py/emit.h +++ b/py/emit.h @@ -156,8 +156,6 @@ typedef struct _emit_method_table_t { void (*end_except_handler)(emit_t *emit); } emit_method_table_t; -int mp_native_type_from_qstr(qstr qst); - static inline void mp_emit_common_get_id_for_load(scope_t *scope, qstr qst) { scope_find_or_add_id(scope, qst, ID_INFO_KIND_GLOBAL_IMPLICIT); } diff --git a/py/emitnative.c b/py/emitnative.c index ffdebd6432..aa5ec4935d 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -136,20 +136,6 @@ typedef enum { VTYPE_BUILTIN_CAST = 0x70 | MP_NATIVE_TYPE_OBJ, } vtype_kind_t; -int mp_native_type_from_qstr(qstr qst) { - switch (qst) { - case MP_QSTR_object: return MP_NATIVE_TYPE_OBJ; - case MP_QSTR_bool: return MP_NATIVE_TYPE_BOOL; - case MP_QSTR_int: return MP_NATIVE_TYPE_INT; - case MP_QSTR_uint: return MP_NATIVE_TYPE_UINT; - case MP_QSTR_ptr: return MP_NATIVE_TYPE_PTR; - case MP_QSTR_ptr8: return MP_NATIVE_TYPE_PTR8; - case MP_QSTR_ptr16: return MP_NATIVE_TYPE_PTR16; - case MP_QSTR_ptr32: return MP_NATIVE_TYPE_PTR32; - default: return -1; - } -} - STATIC qstr vtype_to_qstr(vtype_kind_t vtype) { switch (vtype) { case VTYPE_PYOBJ: return MP_QSTR_object; diff --git a/py/nativeglue.c b/py/nativeglue.c index b7031a5d27..6e5bd6ce2e 100644 --- a/py/nativeglue.c +++ b/py/nativeglue.c @@ -41,6 +41,20 @@ #if MICROPY_EMIT_NATIVE +int mp_native_type_from_qstr(qstr qst) { + switch (qst) { + case MP_QSTR_object: return MP_NATIVE_TYPE_OBJ; + case MP_QSTR_bool: return MP_NATIVE_TYPE_BOOL; + case MP_QSTR_int: return MP_NATIVE_TYPE_INT; + case MP_QSTR_uint: return MP_NATIVE_TYPE_UINT; + case MP_QSTR_ptr: return MP_NATIVE_TYPE_PTR; + case MP_QSTR_ptr8: return MP_NATIVE_TYPE_PTR8; + case MP_QSTR_ptr16: return MP_NATIVE_TYPE_PTR16; + case MP_QSTR_ptr32: return MP_NATIVE_TYPE_PTR32; + default: return -1; + } +} + // convert a MicroPython object to a valid native value based on type mp_uint_t mp_convert_obj_to_native(mp_obj_t obj, mp_uint_t type) { DEBUG_printf("mp_convert_obj_to_native(%p, " UINT_FMT ")\n", obj, type); diff --git a/py/runtime.h b/py/runtime.h index 9811c1b5ae..3e447ee4fe 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -169,6 +169,7 @@ NORETURN void mp_raise_recursion_depth(void); #endif // helper functions for native/viper code +int mp_native_type_from_qstr(qstr qst); mp_uint_t mp_convert_obj_to_native(mp_obj_t obj, mp_uint_t type); mp_obj_t mp_convert_native_to_obj(mp_uint_t val, mp_uint_t type); mp_obj_dict_t *mp_native_swap_globals(mp_obj_dict_t *new_globals); From 0e4c24ec08c19773b26a662abb133c05b474b1fa Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 9 Mar 2019 10:22:09 +1100 Subject: [PATCH 0215/1788] py/nativeglue: Rename native convert funs to match other native helpers. --- py/nativeglue.c | 12 ++++++------ py/objfun.c | 2 +- py/runtime.h | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/py/nativeglue.c b/py/nativeglue.c index 6e5bd6ce2e..db54d12332 100644 --- a/py/nativeglue.c +++ b/py/nativeglue.c @@ -56,8 +56,8 @@ int mp_native_type_from_qstr(qstr qst) { } // convert a MicroPython object to a valid native value based on type -mp_uint_t mp_convert_obj_to_native(mp_obj_t obj, mp_uint_t type) { - DEBUG_printf("mp_convert_obj_to_native(%p, " UINT_FMT ")\n", obj, type); +mp_uint_t mp_native_from_obj(mp_obj_t obj, mp_uint_t type) { + DEBUG_printf("mp_native_from_obj(%p, " UINT_FMT ")\n", obj, type); switch (type & 0xf) { case MP_NATIVE_TYPE_OBJ: return (mp_uint_t)obj; case MP_NATIVE_TYPE_BOOL: @@ -80,8 +80,8 @@ mp_uint_t mp_convert_obj_to_native(mp_obj_t obj, mp_uint_t type) { #if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM // convert a native value to a MicroPython object based on type -mp_obj_t mp_convert_native_to_obj(mp_uint_t val, mp_uint_t type) { - DEBUG_printf("mp_convert_native_to_obj(" UINT_FMT ", " UINT_FMT ")\n", val, type); +mp_obj_t mp_native_to_obj(mp_uint_t val, mp_uint_t type) { + DEBUG_printf("mp_native_to_obj(" UINT_FMT ", " UINT_FMT ")\n", val, type); switch (type & 0xf) { case MP_NATIVE_TYPE_OBJ: return (mp_obj_t)val; case MP_NATIVE_TYPE_BOOL: return mp_obj_new_bool(val); @@ -192,8 +192,8 @@ const void *const mp_fun_table[MP_F_NUMBER_OF] = { &mp_const_none_obj, &mp_const_false_obj, &mp_const_true_obj, - mp_convert_obj_to_native, - mp_convert_native_to_obj, + mp_native_from_obj, + mp_native_to_obj, mp_native_swap_globals, mp_load_name, mp_load_global, diff --git a/py/objfun.c b/py/objfun.c index 159d67e5ea..d50b7fa25d 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -510,7 +510,7 @@ STATIC mp_obj_t fun_asm_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const ); } - return mp_convert_native_to_obj(ret, self->type_sig); + return mp_native_to_obj(ret, self->type_sig); } STATIC const mp_obj_type_t mp_type_fun_asm = { diff --git a/py/runtime.h b/py/runtime.h index 3e447ee4fe..0dd97a584f 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -170,8 +170,8 @@ NORETURN void mp_raise_recursion_depth(void); // helper functions for native/viper code int mp_native_type_from_qstr(qstr qst); -mp_uint_t mp_convert_obj_to_native(mp_obj_t obj, mp_uint_t type); -mp_obj_t mp_convert_native_to_obj(mp_uint_t val, mp_uint_t type); +mp_uint_t mp_native_from_obj(mp_obj_t obj, mp_uint_t type); +mp_obj_t mp_native_to_obj(mp_uint_t val, mp_uint_t type); mp_obj_dict_t *mp_native_swap_globals(mp_obj_dict_t *new_globals); mp_obj_t mp_native_call_function_n_kw(mp_obj_t fun_in, size_t n_args_kw, const mp_obj_t *args); void mp_native_raise(mp_obj_t o); From d9d92f27d7cce287850d971abf3104d2230092fa Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 9 Mar 2019 10:59:25 +1100 Subject: [PATCH 0216/1788] py/compile: Add support to select the native emitter at runtime. --- py/compile.c | 24 ++++++++++++++++++++++-- py/emit.h | 5 +++++ py/emitbc.c | 5 +++++ py/emitnative.c | 5 +++++ py/mpstate.h | 1 + py/persistentcode.c | 8 +++++++- 6 files changed, 45 insertions(+), 3 deletions(-) diff --git a/py/compile.c b/py/compile.c index a38998fdb6..7caa562816 100644 --- a/py/compile.c +++ b/py/compile.c @@ -35,6 +35,7 @@ #include "py/compile.h" #include "py/runtime.h" #include "py/asmbase.h" +#include "py/persistentcode.h" #if MICROPY_ENABLE_COMPILER @@ -78,7 +79,25 @@ typedef enum { #endif -#if MICROPY_EMIT_NATIVE +#if MICROPY_EMIT_NATIVE && MICROPY_DYNAMIC_COMPILER + +#define NATIVE_EMITTER(f) emit_native_table[mp_dynamic_compiler.native_arch]->emit_##f +#define NATIVE_EMITTER_TABLE emit_native_table[mp_dynamic_compiler.native_arch] + +STATIC const emit_method_table_t *emit_native_table[] = { + NULL, + &emit_native_x86_method_table, + &emit_native_x64_method_table, + &emit_native_arm_method_table, + &emit_native_thumb_method_table, + &emit_native_thumb_method_table, + &emit_native_thumb_method_table, + &emit_native_thumb_method_table, + &emit_native_thumb_method_table, + &emit_native_xtensa_method_table, +}; + +#elif MICROPY_EMIT_NATIVE // define a macro to access external native emitter #if MICROPY_EMIT_X64 #define NATIVE_EMITTER(f) emit_native_x64_##f @@ -93,6 +112,7 @@ typedef enum { #else #error "unknown native emitter" #endif +#define NATIVE_EMITTER_TABLE &NATIVE_EMITTER(method_table) #endif #if MICROPY_EMIT_INLINE_ASM @@ -3470,7 +3490,7 @@ mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_f if (emit_native == NULL) { emit_native = NATIVE_EMITTER(new)(&comp->compile_error, &comp->next_label, max_num_labels); } - comp->emit_method_table = &NATIVE_EMITTER(method_table); + comp->emit_method_table = NATIVE_EMITTER_TABLE; comp->emit = emit_native; break; #endif // MICROPY_EMIT_NATIVE diff --git a/py/emit.h b/py/emit.h index 2a5da8e8e3..7b97372bcb 100644 --- a/py/emit.h +++ b/py/emit.h @@ -98,6 +98,11 @@ typedef struct _mp_emit_method_table_id_ops_t { } mp_emit_method_table_id_ops_t; typedef struct _emit_method_table_t { + #if MICROPY_DYNAMIC_COMPILER + emit_t *(*emit_new)(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels); + void (*emit_free)(emit_t *emit); + #endif + void (*start_pass)(emit_t *emit, pass_kind_t pass, scope_t *scope); void (*end_pass)(emit_t *emit); bool (*last_emit_was_return_value)(emit_t *emit); diff --git a/py/emitbc.c b/py/emitbc.c index 4142e892d6..35eb6df9c0 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -909,6 +909,11 @@ void mp_emit_bc_end_except_handler(emit_t *emit) { #if MICROPY_EMIT_NATIVE const emit_method_table_t emit_bc_method_table = { + #if MICROPY_DYNAMIC_COMPILER + NULL, + NULL, + #endif + mp_emit_bc_start_pass, mp_emit_bc_end_pass, mp_emit_bc_last_emit_was_return_value, diff --git a/py/emitnative.c b/py/emitnative.c index aa5ec4935d..da986dc5d9 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -2727,6 +2727,11 @@ STATIC void emit_native_end_except_handler(emit_t *emit) { } const emit_method_table_t EXPORT_FUN(method_table) = { + #if MICROPY_DYNAMIC_COMPILER + EXPORT_FUN(new), + EXPORT_FUN(free), + #endif + emit_native_start_pass, emit_native_end_pass, emit_native_last_emit_was_return_value, diff --git a/py/mpstate.h b/py/mpstate.h index 98371ca646..1496600402 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -46,6 +46,7 @@ typedef struct mp_dynamic_compiler_t { uint8_t small_int_bits; // must be <= host small_int_bits bool opt_cache_map_lookup_in_bytecode; bool py_builtins_str_unicode; + uint8_t native_arch; } mp_dynamic_compiler_t; extern mp_dynamic_compiler_t mp_dynamic_compiler; #endif diff --git a/py/persistentcode.c b/py/persistentcode.c index ad502a5116..70ec2ddd65 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -78,6 +78,12 @@ #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_NONE) #endif +#if MICROPY_DYNAMIC_COMPILER +#define MPY_FEATURE_ARCH_DYNAMIC mp_dynamic_compiler.native_arch +#else +#define MPY_FEATURE_ARCH_DYNAMIC MPY_FEATURE_ARCH +#endif + #if MICROPY_PERSISTENT_CODE_LOAD || (MICROPY_PERSISTENT_CODE_SAVE && !MICROPY_DYNAMIC_COMPILER) // The bytecode will depend on the number of bits in a small-int, and // this function computes that (could make it a fixed constant, but it @@ -731,7 +737,7 @@ void mp_raw_code_save(mp_raw_code_t *rc, mp_print_t *print) { #endif }; if (mp_raw_code_has_native(rc)) { - header[2] |= MPY_FEATURE_ENCODE_ARCH(MPY_FEATURE_ARCH); + header[2] |= MPY_FEATURE_ENCODE_ARCH(MPY_FEATURE_ARCH_DYNAMIC); } mp_print_bytes(print, header, sizeof(header)); mp_print_uint(print, QSTR_WINDOW_SIZE); From 9c9bc65e74abb645817c757f005eef6d7394f507 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 9 Mar 2019 10:59:57 +1100 Subject: [PATCH 0217/1788] mpy-cross: Add "-march=" option to select native emitter. --- mpy-cross/main.c | 23 +++++++++++++++++++++++ mpy-cross/mpconfigport.h | 16 ++++++++-------- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/mpy-cross/main.c b/mpy-cross/main.c index d819f74f12..ef5d8752a8 100644 --- a/mpy-cross/main.c +++ b/mpy-cross/main.c @@ -109,6 +109,7 @@ STATIC int usage(char **argv) { "-msmall-int-bits=number : set the maximum bits used to encode a small-int\n" "-mno-unicode : don't support unicode in compiled strings\n" "-mcache-lookup-bc : cache map lookups in the bytecode\n" +"-march= : set architecture for native emitter; x86, x64, armv6, armv7m, xtensa\n" "\n" "Implementation specific options:\n", argv[0] ); @@ -193,6 +194,13 @@ MP_NOINLINE int main_(int argc, char **argv) { mp_dynamic_compiler.small_int_bits = 31; mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode = 0; mp_dynamic_compiler.py_builtins_str_unicode = 1; + #if defined(__i386__) + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X86; + #elif defined(__x86_64__) + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X64; + #else + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_NONE; + #endif const char *input_file = NULL; const char *output_file = NULL; @@ -240,6 +248,21 @@ MP_NOINLINE int main_(int argc, char **argv) { mp_dynamic_compiler.py_builtins_str_unicode = 0; } else if (strcmp(argv[a], "-municode") == 0) { mp_dynamic_compiler.py_builtins_str_unicode = 1; + } else if (strncmp(argv[a], "-march=", sizeof("-march=") - 1) == 0) { + const char *arch = argv[a] + sizeof("-march=") - 1; + if (strcmp(arch, "x86") == 0) { + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X86; + } else if (strcmp(arch, "x64") == 0) { + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X64; + } else if (strcmp(arch, "armv6") == 0) { + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_ARMV6; + } else if (strcmp(arch, "armv7m") == 0) { + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_ARMV7M; + } else if (strcmp(arch, "xtensa") == 0) { + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_XTENSA; + } else { + return usage(argv); + } } else { return usage(argv); } diff --git a/mpy-cross/mpconfigport.h b/mpy-cross/mpconfigport.h index 21ddfcf6a7..6aa013a134 100644 --- a/mpy-cross/mpconfigport.h +++ b/mpy-cross/mpconfigport.h @@ -31,14 +31,14 @@ #define MICROPY_PERSISTENT_CODE_SAVE (1) #define MICROPY_EMIT_X64 (1) -#define MICROPY_EMIT_X86 (0) -#define MICROPY_EMIT_THUMB (0) -#define MICROPY_EMIT_INLINE_THUMB (0) -#define MICROPY_EMIT_INLINE_THUMB_ARMV7M (0) -#define MICROPY_EMIT_INLINE_THUMB_FLOAT (0) -#define MICROPY_EMIT_ARM (0) -#define MICROPY_EMIT_XTENSA (0) -#define MICROPY_EMIT_INLINE_XTENSA (0) +#define MICROPY_EMIT_X86 (1) +#define MICROPY_EMIT_THUMB (1) +#define MICROPY_EMIT_INLINE_THUMB (1) +#define MICROPY_EMIT_INLINE_THUMB_ARMV7M (1) +#define MICROPY_EMIT_INLINE_THUMB_FLOAT (1) +#define MICROPY_EMIT_ARM (1) +#define MICROPY_EMIT_XTENSA (1) +#define MICROPY_EMIT_INLINE_XTENSA (1) #define MICROPY_DYNAMIC_COMPILER (1) #define MICROPY_COMP_CONST_FOLDING (1) From 55fcb83a42fef108dfa2cd23bae55597d1569f68 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 9 Mar 2019 12:32:09 +1100 Subject: [PATCH 0218/1788] py/compile: Support multiple inline asm emitters. --- py/compile.c | 37 ++++++++++++++++++++++++++++++++++--- py/emit.h | 5 +++++ py/emitinlinethumb.c | 5 +++++ py/emitinlinextensa.c | 5 +++++ 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/py/compile.c b/py/compile.c index 7caa562816..8ed7cad5f3 100644 --- a/py/compile.c +++ b/py/compile.c @@ -115,7 +115,25 @@ STATIC const emit_method_table_t *emit_native_table[] = { #define NATIVE_EMITTER_TABLE &NATIVE_EMITTER(method_table) #endif -#if MICROPY_EMIT_INLINE_ASM +#if MICROPY_EMIT_INLINE_ASM && MICROPY_DYNAMIC_COMPILER + +#define ASM_EMITTER(f) emit_asm_table[mp_dynamic_compiler.native_arch]->asm_##f +#define ASM_EMITTER_TABLE emit_asm_table[mp_dynamic_compiler.native_arch] + +STATIC const emit_inline_asm_method_table_t *emit_asm_table[] = { + NULL, + NULL, + NULL, + NULL, + &emit_inline_thumb_method_table, + &emit_inline_thumb_method_table, + &emit_inline_thumb_method_table, + &emit_inline_thumb_method_table, + &emit_inline_thumb_method_table, + &emit_inline_xtensa_method_table, +}; + +#elif MICROPY_EMIT_INLINE_ASM // define macros for inline assembler #if MICROPY_EMIT_INLINE_THUMB #define ASM_DECORATOR_QSTR MP_QSTR_asm_thumb @@ -126,6 +144,7 @@ STATIC const emit_method_table_t *emit_native_table[] = { #else #error "unknown asm emitter" #endif +#define ASM_EMITTER_TABLE &ASM_EMITTER(method_table) #endif #define EMIT_INLINE_ASM(fun) (comp->emit_inline_asm_method_table->fun(comp->emit_inline_asm)) @@ -819,9 +838,16 @@ STATIC bool compile_built_in_decorator(compiler_t *comp, int name_len, mp_parse_ *emit_options = MP_EMIT_OPT_VIPER; #endif #if MICROPY_EMIT_INLINE_ASM + #if MICROPY_DYNAMIC_COMPILER + } else if (attr == MP_QSTR_asm_thumb) { + *emit_options = MP_EMIT_OPT_ASM; + } else if (attr == MP_QSTR_asm_xtensa) { + *emit_options = MP_EMIT_OPT_ASM; + #else } else if (attr == ASM_DECORATOR_QSTR) { *emit_options = MP_EMIT_OPT_ASM; #endif + #endif } else { compile_syntax_error(comp, name_nodes[1], "invalid micropython decorator"); } @@ -3465,13 +3491,18 @@ mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_f comp->emit_inline_asm = ASM_EMITTER(new)(max_num_labels); } comp->emit = NULL; - comp->emit_inline_asm_method_table = &ASM_EMITTER(method_table); + comp->emit_inline_asm_method_table = ASM_EMITTER_TABLE; compile_scope_inline_asm(comp, s, MP_PASS_CODE_SIZE); #if MICROPY_EMIT_INLINE_XTENSA // Xtensa requires an extra pass to compute size of l32r const table // TODO this can be improved by calculating it during SCOPE pass // but that requires some other structural changes to the asm emitters - compile_scope_inline_asm(comp, s, MP_PASS_CODE_SIZE); + #if MICROPY_DYNAMIC_COMPILER + if (mp_dynamic_compiler.native_arch == MP_NATIVE_ARCH_XTENSA) + #endif + { + compile_scope_inline_asm(comp, s, MP_PASS_CODE_SIZE); + } #endif if (comp->compile_error == MP_OBJ_NULL) { compile_scope_inline_asm(comp, s, MP_PASS_EMIT); diff --git a/py/emit.h b/py/emit.h index 7b97372bcb..70f7bf1220 100644 --- a/py/emit.h +++ b/py/emit.h @@ -255,6 +255,11 @@ void mp_emit_bc_end_except_handler(emit_t *emit); typedef struct _emit_inline_asm_t emit_inline_asm_t; typedef struct _emit_inline_asm_method_table_t { + #if MICROPY_DYNAMIC_COMPILER + emit_inline_asm_t *(*asm_new)(mp_uint_t max_num_labels); + void (*asm_free)(emit_inline_asm_t *emit); + #endif + void (*start_pass)(emit_inline_asm_t *emit, pass_kind_t pass, mp_obj_t *error_slot); void (*end_pass)(emit_inline_asm_t *emit, mp_uint_t type_sig); mp_uint_t (*count_params)(emit_inline_asm_t *emit, mp_uint_t n_params, mp_parse_node_t *pn_params); diff --git a/py/emitinlinethumb.c b/py/emitinlinethumb.c index 0649c59edd..020dfc8153 100644 --- a/py/emitinlinethumb.c +++ b/py/emitinlinethumb.c @@ -812,6 +812,11 @@ branch_not_in_range: } const emit_inline_asm_method_table_t emit_inline_thumb_method_table = { + #if MICROPY_DYNAMIC_COMPILER + emit_inline_thumb_new, + emit_inline_thumb_free, + #endif + emit_inline_thumb_start_pass, emit_inline_thumb_end_pass, emit_inline_thumb_count_params, diff --git a/py/emitinlinextensa.c b/py/emitinlinextensa.c index b5f9189d4b..d10179127f 100644 --- a/py/emitinlinextensa.c +++ b/py/emitinlinextensa.c @@ -335,6 +335,11 @@ branch_not_in_range: } const emit_inline_asm_method_table_t emit_inline_xtensa_method_table = { + #if MICROPY_DYNAMIC_COMPILER + emit_inline_xtensa_new, + emit_inline_xtensa_free, + #endif + emit_inline_xtensa_start_pass, emit_inline_xtensa_end_pass, emit_inline_xtensa_count_params, From 5a6026c614e0b7dd26fcf277f01169c95c5d93a4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 9 Mar 2019 12:32:26 +1100 Subject: [PATCH 0219/1788] py/compile: Check that arch is set when compiling native, viper or asm. --- py/compile.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/py/compile.c b/py/compile.c index 8ed7cad5f3..4919a16595 100644 --- a/py/compile.c +++ b/py/compile.c @@ -852,6 +852,18 @@ STATIC bool compile_built_in_decorator(compiler_t *comp, int name_len, mp_parse_ compile_syntax_error(comp, name_nodes[1], "invalid micropython decorator"); } + #if MICROPY_DYNAMIC_COMPILER + if (*emit_options == MP_EMIT_OPT_NATIVE_PYTHON || *emit_options == MP_EMIT_OPT_VIPER) { + if (emit_native_table[mp_dynamic_compiler.native_arch] == NULL) { + compile_syntax_error(comp, name_nodes[1], "invalid arch"); + } + } else if (*emit_options == MP_EMIT_OPT_ASM) { + if (emit_asm_table[mp_dynamic_compiler.native_arch] == NULL) { + compile_syntax_error(comp, name_nodes[1], "invalid arch"); + } + } + #endif + return true; } From c7d19dc0adab2d615e6044f7bbbf6b71255ae8df Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 14 Mar 2019 12:20:39 +1100 Subject: [PATCH 0220/1788] ports/{stm32,esp8266}: Set mpy-cross native arch for frozen native code. --- ports/esp8266/Makefile | 3 +++ ports/stm32/Makefile | 3 +++ 2 files changed, 6 insertions(+) diff --git a/ports/esp8266/Makefile b/ports/esp8266/Makefile index 64116b139b..2162c72f07 100644 --- a/ports/esp8266/Makefile +++ b/ports/esp8266/Makefile @@ -59,6 +59,9 @@ COPT += -Os -DNDEBUG LDFLAGS += --gc-sections endif +# Options for mpy-cross +MPY_CROSS_FLAGS += -march=xtensa + SRC_C = \ strtoll.c \ main.c \ diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index b4c7a15c13..d0b90c7617 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -105,6 +105,9 @@ else COPT += -Os -DNDEBUG endif +# Options for mpy-cross +MPY_CROSS_FLAGS += -march=armv7m + SRC_LIB = $(addprefix lib/,\ libc/string0.c \ oofatfs/ff.c \ From c9eb7eb449a246c607fa92a5313e3137d728fbcb Mon Sep 17 00:00:00 2001 From: roland van straten Date: Tue, 12 Mar 2019 13:56:39 +0100 Subject: [PATCH 0221/1788] stm32/stm32_it: Guard UART7_IRQHandler with check for UART7 define. All STM32 with a UART7 also have a UART8 and vice versa, but this change improves readability and allows for them to be independent in the future. --- ports/stm32/stm32_it.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index 004e0f974d..637442a916 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -735,7 +735,7 @@ void USART6_IRQHandler(void) { IRQ_EXIT(USART6_IRQn); } -#if defined(UART8) +#if defined(UART7) void UART7_IRQHandler(void) { IRQ_ENTER(UART7_IRQn); uart_irq_handler(7); From e8ed2dea71962e0f04871f393d21a5afe7ac902c Mon Sep 17 00:00:00 2001 From: Nguyen Hoan Hoang Date: Tue, 12 Feb 2019 21:35:53 -0500 Subject: [PATCH 0222/1788] nrf/bluetooth: Add support for SoftDevice s132 version 6.1.1. Updating download script to fetch the new SoftDevice, and adding corresponding linker script for the BLE stack. --- ports/nrf/boards/s132_6.1.1.ld | 4 +++ .../drivers/bluetooth/download_ble_stack.sh | 25 +++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 ports/nrf/boards/s132_6.1.1.ld diff --git a/ports/nrf/boards/s132_6.1.1.ld b/ports/nrf/boards/s132_6.1.1.ld new file mode 100644 index 0000000000..b3e6bc1614 --- /dev/null +++ b/ports/nrf/boards/s132_6.1.1.ld @@ -0,0 +1,4 @@ +/* GNU linker script for s132 SoftDevice version 6.1.1 */ + +_sd_size = 0x00026000; +_sd_ram = 0x000039c0; diff --git a/ports/nrf/drivers/bluetooth/download_ble_stack.sh b/ports/nrf/drivers/bluetooth/download_ble_stack.sh index 32c0d9c8ee..4c9f372b2f 100755 --- a/ports/nrf/drivers/bluetooth/download_ble_stack.sh +++ b/ports/nrf/drivers/bluetooth/download_ble_stack.sh @@ -39,6 +39,24 @@ function download_s132_nrf52_6_0_0 cd - } +function download_s132_nrf52_6_1_1 +{ + echo "" + echo "####################################" + echo "### Downloading s132_nrf52_6.1.1 ###" + echo "####################################" + echo "" + + mkdir -p $1/s132_nrf52_6.1.1 + cd $1/s132_nrf52_6.1.1 + wget --post-data="fileName=DeviceDownload&ids=3AB3E86666FE4361A4A3B7E0D1CBB9B9" https://www.nordicsemi.com/api/sitecore/Products/MedialibraryZipDownload2 + mv MedialibraryZipDownload2 temp.zip + unzip -u temp.zip + unzip -u s132nrf52611.zip + rm s132nrf52611.zip + rm temp.zip + cd - +} function download_s140_nrf52_6_0_0 { @@ -66,14 +84,17 @@ if [ $# -eq 0 ]; then echo "No Bluetooth LE stack defined, downloading all." download_s110_nrf51_8_0_0 ${SCRIPT_DIR} download_s132_nrf52_6_0_0 ${SCRIPT_DIR} + download_s132_nrf52_6_1_1 ${SCRIPT_DIR} download_s140_nrf52_6_0_0 ${SCRIPT_DIR} else case $1 in "s110_nrf51" ) download_s110_nrf51_8_0_0 ${SCRIPT_DIR} ;; - "s132_nrf52_2_0_1" ) + "s132_nrf52_6_0_0" ) download_s132_nrf52_6_0_0 ${SCRIPT_DIR} ;; - "s132_nrf52_3_0_0" ) + "s132_nrf52_6_1_1" ) + download_s132_nrf52_6_1_1 ${SCRIPT_DIR} ;; + "s140_nrf52_6_0_0" ) download_s140_nrf52_6_0_0 ${SCRIPT_DIR} ;; esac fi From 5f26ef1112d5daca2eef9a5768e8f3c3c5393805 Mon Sep 17 00:00:00 2001 From: Glenn Ruben Bakke Date: Mon, 18 Feb 2019 20:42:38 +0100 Subject: [PATCH 0223/1788] nrf/board: Migrate all nrf52832 targets to new BLE stack. This patch moves all the nrf52832 target boards to use the new SoftDevice s132 v6.1.1 instead of the legacy v6.0.0. --- ports/nrf/boards/arduino_primo/mpconfigboard.mk | 2 +- ports/nrf/boards/dvk_bl652/mpconfigboard.mk | 2 +- ports/nrf/boards/feather52/mpconfigboard.mk | 2 +- ports/nrf/boards/pca10040/mpconfigboard.mk | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ports/nrf/boards/arduino_primo/mpconfigboard.mk b/ports/nrf/boards/arduino_primo/mpconfigboard.mk index e0be6c6ba1..84685236bd 100644 --- a/ports/nrf/boards/arduino_primo/mpconfigboard.mk +++ b/ports/nrf/boards/arduino_primo/mpconfigboard.mk @@ -1,7 +1,7 @@ MCU_SERIES = m4 MCU_VARIANT = nrf52 MCU_SUB_VARIANT = nrf52832 -SOFTDEV_VERSION = 6.0.0 +SOFTDEV_VERSION = 6.1.1 LD_FILES += boards/nrf52832_512k_64k.ld FLASHER = pyocd diff --git a/ports/nrf/boards/dvk_bl652/mpconfigboard.mk b/ports/nrf/boards/dvk_bl652/mpconfigboard.mk index e293779d72..8730d02978 100644 --- a/ports/nrf/boards/dvk_bl652/mpconfigboard.mk +++ b/ports/nrf/boards/dvk_bl652/mpconfigboard.mk @@ -1,7 +1,7 @@ MCU_SERIES = m4 MCU_VARIANT = nrf52 MCU_SUB_VARIANT = nrf52832 -SOFTDEV_VERSION = 6.0.0 +SOFTDEV_VERSION = 6.1.1 LD_FILES += boards/nrf52832_512k_64k.ld NRF_DEFINES += -DNRF52832_XXAA diff --git a/ports/nrf/boards/feather52/mpconfigboard.mk b/ports/nrf/boards/feather52/mpconfigboard.mk index ea4a831978..5e0f336da4 100644 --- a/ports/nrf/boards/feather52/mpconfigboard.mk +++ b/ports/nrf/boards/feather52/mpconfigboard.mk @@ -1,7 +1,7 @@ MCU_SERIES = m4 MCU_VARIANT = nrf52 MCU_SUB_VARIANT = nrf52832 -SOFTDEV_VERSION = 6.0.0 +SOFTDEV_VERSION = 6.1.1 LD_FILES += boards/nrf52832_512k_64k.ld NRF_DEFINES += -DNRF52832_XXAA diff --git a/ports/nrf/boards/pca10040/mpconfigboard.mk b/ports/nrf/boards/pca10040/mpconfigboard.mk index 92fbb26e24..db64a60dd3 100644 --- a/ports/nrf/boards/pca10040/mpconfigboard.mk +++ b/ports/nrf/boards/pca10040/mpconfigboard.mk @@ -1,7 +1,7 @@ MCU_SERIES = m4 MCU_VARIANT = nrf52 MCU_SUB_VARIANT = nrf52832 -SOFTDEV_VERSION = 6.0.0 +SOFTDEV_VERSION = 6.1.1 LD_FILES += boards/nrf52832_512k_64k.ld NRF_DEFINES += -DNRF52832_XXAA From 1e5e3e3d488af8b06baedd52eb54772258293257 Mon Sep 17 00:00:00 2001 From: Glenn Ruben Bakke Date: Mon, 18 Feb 2019 20:53:22 +0100 Subject: [PATCH 0224/1788] nrf/bluetooth: Deprecate use of SoftDevice s132 v6.0.0. Removing linker script for nrf52832 s132 v6.0.0 as all target boards now points to the new v6.1.1. Also, removing the entry from the download_ble_stack.sh script. --- ports/nrf/boards/s132_6.0.0.ld | 4 ---- .../drivers/bluetooth/download_ble_stack.sh | 23 ------------------- 2 files changed, 27 deletions(-) delete mode 100644 ports/nrf/boards/s132_6.0.0.ld diff --git a/ports/nrf/boards/s132_6.0.0.ld b/ports/nrf/boards/s132_6.0.0.ld deleted file mode 100644 index 044af97199..0000000000 --- a/ports/nrf/boards/s132_6.0.0.ld +++ /dev/null @@ -1,4 +0,0 @@ -/* GNU linker script for s132 SoftDevice version 6.0.0 */ - -_sd_size = 0x00026000; -_sd_ram = 0x000039c0; diff --git a/ports/nrf/drivers/bluetooth/download_ble_stack.sh b/ports/nrf/drivers/bluetooth/download_ble_stack.sh index 4c9f372b2f..b9b32f24de 100755 --- a/ports/nrf/drivers/bluetooth/download_ble_stack.sh +++ b/ports/nrf/drivers/bluetooth/download_ble_stack.sh @@ -19,26 +19,6 @@ function download_s110_nrf51_8_0_0 cd - } - -function download_s132_nrf52_6_0_0 -{ - echo "" - echo "####################################" - echo "### Downloading s132_nrf52_6.0.0 ###" - echo "####################################" - echo "" - - mkdir -p $1/s132_nrf52_6.0.0 - cd $1/s132_nrf52_6.0.0 - wget --post-data="fileName=DeviceDownload&ids=C44AF08D58934BDB98F1EE7C4B8D2815" https://www.nordicsemi.com/api/sitecore/Products/MedialibraryZipDownload2 - mv MedialibraryZipDownload2 temp.zip - unzip -u temp.zip - unzip -u s132nrf52600.zip - rm s132nrf52600.zip - rm temp.zip - cd - -} - function download_s132_nrf52_6_1_1 { echo "" @@ -83,15 +63,12 @@ SCRIPT_DIR="$(cd -P "$(dirname "${BASH_SOURCE[0]}")" && pwd)" if [ $# -eq 0 ]; then echo "No Bluetooth LE stack defined, downloading all." download_s110_nrf51_8_0_0 ${SCRIPT_DIR} - download_s132_nrf52_6_0_0 ${SCRIPT_DIR} download_s132_nrf52_6_1_1 ${SCRIPT_DIR} download_s140_nrf52_6_0_0 ${SCRIPT_DIR} else case $1 in "s110_nrf51" ) download_s110_nrf51_8_0_0 ${SCRIPT_DIR} ;; - "s132_nrf52_6_0_0" ) - download_s132_nrf52_6_0_0 ${SCRIPT_DIR} ;; "s132_nrf52_6_1_1" ) download_s132_nrf52_6_1_1 ${SCRIPT_DIR} ;; "s140_nrf52_6_0_0" ) From d3c1436e757b3a6d1230f0217de7db4ec9e5f816 Mon Sep 17 00:00:00 2001 From: Glenn Ruben Bakke Date: Mon, 18 Feb 2019 21:22:50 +0100 Subject: [PATCH 0225/1788] nrf/bluetooth: Add support for SoftDevice s140 version 6.1.1. Updating download script to fetch the new SoftDevice, and adding corresponding linker script for the BLE stack. --- ports/nrf/boards/s140_6.1.1.ld | 4 ++++ .../drivers/bluetooth/download_ble_stack.sh | 21 +++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 ports/nrf/boards/s140_6.1.1.ld diff --git a/ports/nrf/boards/s140_6.1.1.ld b/ports/nrf/boards/s140_6.1.1.ld new file mode 100644 index 0000000000..d8c8cccb6e --- /dev/null +++ b/ports/nrf/boards/s140_6.1.1.ld @@ -0,0 +1,4 @@ +/* GNU linker script for s140 SoftDevice version 6.1.1 */ + +_sd_size = 0x00026000; +_sd_ram = 0x000039c0; diff --git a/ports/nrf/drivers/bluetooth/download_ble_stack.sh b/ports/nrf/drivers/bluetooth/download_ble_stack.sh index b9b32f24de..321a645fcb 100755 --- a/ports/nrf/drivers/bluetooth/download_ble_stack.sh +++ b/ports/nrf/drivers/bluetooth/download_ble_stack.sh @@ -57,6 +57,24 @@ function download_s140_nrf52_6_0_0 cd - } +function download_s140_nrf52_6_1_1 +{ + echo "" + echo "####################################" + echo "### Downloading s140_nrf52_6.1.1 ###" + echo "####################################" + echo "" + + mkdir -p $1/s140_nrf52_6.1.1 + cd $1/s140_nrf52_6.1.1 + wget --post-data="fileName=DeviceDownload&ids=CE89BA7633C540AFA48AB88E934DBF05" https://www.nordicsemi.com/api/sitecore/Products/MedialibraryZipDownload2 + mv MedialibraryZipDownload2 temp.zip + unzip -u temp.zip + unzip -u s140nrf52611.zip + rm s140nrf52611.zip + rm temp.zip + cd - +} SCRIPT_DIR="$(cd -P "$(dirname "${BASH_SOURCE[0]}")" && pwd)" @@ -65,6 +83,7 @@ if [ $# -eq 0 ]; then download_s110_nrf51_8_0_0 ${SCRIPT_DIR} download_s132_nrf52_6_1_1 ${SCRIPT_DIR} download_s140_nrf52_6_0_0 ${SCRIPT_DIR} + download_s140_nrf52_6_1_1 ${SCRIPT_DIR} else case $1 in "s110_nrf51" ) @@ -73,6 +92,8 @@ else download_s132_nrf52_6_1_1 ${SCRIPT_DIR} ;; "s140_nrf52_6_0_0" ) download_s140_nrf52_6_0_0 ${SCRIPT_DIR} ;; + "s140_nrf52_6_1_1" ) + download_s140_nrf52_6_1_1 ${SCRIPT_DIR} ;; esac fi From a3a266a9c38a06269d517835eb0a93d8b25a9fa4 Mon Sep 17 00:00:00 2001 From: Glenn Ruben Bakke Date: Mon, 18 Feb 2019 21:25:39 +0100 Subject: [PATCH 0226/1788] nrf/board: Migrate nrf52840 target to new BLE stack. This patch moves pca10056/nrf52840 target board to use the new SoftDevice s140 v6.1.1 instead of the legacy v6.0.0. --- ports/nrf/boards/pca10056/mpconfigboard.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/nrf/boards/pca10056/mpconfigboard.mk b/ports/nrf/boards/pca10056/mpconfigboard.mk index 866698c0f6..ca555d3932 100644 --- a/ports/nrf/boards/pca10056/mpconfigboard.mk +++ b/ports/nrf/boards/pca10056/mpconfigboard.mk @@ -1,7 +1,7 @@ MCU_SERIES = m4 MCU_VARIANT = nrf52 MCU_SUB_VARIANT = nrf52840 -SOFTDEV_VERSION = 6.0.0 +SOFTDEV_VERSION = 6.1.1 LD_FILES += boards/nrf52840_1M_256k.ld NRF_DEFINES += -DNRF52840_XXAA From 696549d2e5cfbd2621bbe037af53e97af96b29c2 Mon Sep 17 00:00:00 2001 From: Glenn Ruben Bakke Date: Mon, 18 Feb 2019 21:31:10 +0100 Subject: [PATCH 0227/1788] nrf/bluetooth: Deprecate use of SoftDevice s140 v6.0.0. Removing linker script for nrf52840 s140 v6.0.0 as pca10056 target board now points to the new v6.1.1. Also, removing the entry from the download_ble_stack.sh script. --- ports/nrf/boards/s140_6.0.0.ld | 4 ---- .../drivers/bluetooth/download_ble_stack.sh | 22 ------------------- 2 files changed, 26 deletions(-) delete mode 100644 ports/nrf/boards/s140_6.0.0.ld diff --git a/ports/nrf/boards/s140_6.0.0.ld b/ports/nrf/boards/s140_6.0.0.ld deleted file mode 100644 index 044af97199..0000000000 --- a/ports/nrf/boards/s140_6.0.0.ld +++ /dev/null @@ -1,4 +0,0 @@ -/* GNU linker script for s132 SoftDevice version 6.0.0 */ - -_sd_size = 0x00026000; -_sd_ram = 0x000039c0; diff --git a/ports/nrf/drivers/bluetooth/download_ble_stack.sh b/ports/nrf/drivers/bluetooth/download_ble_stack.sh index 321a645fcb..2c32018583 100755 --- a/ports/nrf/drivers/bluetooth/download_ble_stack.sh +++ b/ports/nrf/drivers/bluetooth/download_ble_stack.sh @@ -38,25 +38,6 @@ function download_s132_nrf52_6_1_1 cd - } -function download_s140_nrf52_6_0_0 -{ - echo "" - echo "####################################" - echo "### Downloading s140_nrf52_6.0.0 ###" - echo "####################################" - echo "" - - mkdir -p $1/s140_nrf52_6.0.0 - cd $1/s140_nrf52_6.0.0 - wget --post-data="fileName=DeviceDownload&ids=D631FCC10C9741A49135BC0450E42B19" https://www.nordicsemi.com/api/sitecore/Products/MedialibraryZipDownload2 - mv MedialibraryZipDownload2 temp.zip - unzip -u temp.zip - unzip -u s140nrf52600.zip - rm s140nrf52600.zip - rm temp.zip - cd - -} - function download_s140_nrf52_6_1_1 { echo "" @@ -82,7 +63,6 @@ if [ $# -eq 0 ]; then echo "No Bluetooth LE stack defined, downloading all." download_s110_nrf51_8_0_0 ${SCRIPT_DIR} download_s132_nrf52_6_1_1 ${SCRIPT_DIR} - download_s140_nrf52_6_0_0 ${SCRIPT_DIR} download_s140_nrf52_6_1_1 ${SCRIPT_DIR} else case $1 in @@ -90,8 +70,6 @@ else download_s110_nrf51_8_0_0 ${SCRIPT_DIR} ;; "s132_nrf52_6_1_1" ) download_s132_nrf52_6_1_1 ${SCRIPT_DIR} ;; - "s140_nrf52_6_0_0" ) - download_s140_nrf52_6_0_0 ${SCRIPT_DIR} ;; "s140_nrf52_6_1_1" ) download_s140_nrf52_6_1_1 ${SCRIPT_DIR} ;; esac From ec6e62efc2426a2edab58e5fad178873a1eaba8c Mon Sep 17 00:00:00 2001 From: Dave Hylands Date: Thu, 14 Mar 2019 19:27:54 -0700 Subject: [PATCH 0228/1788] stm32/mboot: Set USE_MBOOT=1 by default in the Makefile. This allows boards that need USE_MBOOT to be built properly whether or not USE_MBOOT=1 is specified when building mboot. --- ports/stm32/mboot/Makefile | 4 ++++ 1 file changed, 4 insertions(+) mode change 100644 => 100755 ports/stm32/mboot/Makefile diff --git a/ports/stm32/mboot/Makefile b/ports/stm32/mboot/Makefile old mode 100644 new mode 100755 index 486d72e19a..122abf27aa --- a/ports/stm32/mboot/Makefile +++ b/ports/stm32/mboot/Makefile @@ -8,6 +8,10 @@ BUILD ?= build-$(BOARD) # Allow the directory containing the board configuration to be specified BOARD_DIR ?= $(abspath ../boards/$(BOARD)) +# Set USE_MBOOT to 1 so that TEXT0_ADDR gets set properly for those boards +# that can be built with or without mboot. +USE_MBOOT ?= 1 + # Sanity check that the board configuration directory exists ifeq ($(wildcard $(BOARD_DIR)/.),) $(error Invalid BOARD specified: $(BOARD_DIR)) From 440462b18ee9ee167e0bf3bf2bf18c09dc99d4a3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 20 Mar 2019 00:16:37 +1100 Subject: [PATCH 0229/1788] py/runtime: Remove long-obsolete MICROPY_FSUSERMOUNT init code. In 1808b2e8d5c9fff8020628a7849a537ffa9790e3 it was replaced by MICROPY_VFS and related code. --- py/runtime.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/py/runtime.c b/py/runtime.c index 7f8ff84e53..4a50698cbb 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -111,11 +111,6 @@ void mp_init(void) { } #endif - #if MICROPY_FSUSERMOUNT - // zero out the pointers to the user-mounted devices - memset(MP_STATE_VM(fs_user_mount), 0, sizeof(MP_STATE_VM(fs_user_mount))); - #endif - #if MICROPY_VFS // initialise the VFS sub-system MP_STATE_VM(vfs_cur) = NULL; From e0c6dfe90a3e6265b06265c5b3124c24703776f1 Mon Sep 17 00:00:00 2001 From: Glenn Ruben Bakke Date: Mon, 18 Feb 2019 19:50:21 +0100 Subject: [PATCH 0230/1788] nrf/readme: Add section about LTO. Adding section about on how to disable use of the linker flag -flto, by setting the LTO=0 argument to Make. Also, added a note on recommended toolchains to use that works well with LTO enabled. --- ports/nrf/README.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/ports/nrf/README.md b/ports/nrf/README.md index 6c77774888..659a556ae2 100644 --- a/ports/nrf/README.md +++ b/ports/nrf/README.md @@ -55,7 +55,21 @@ Alternatively the target board could be defined: make BOARD=pca10040 make BOARD=pca10040 flash - + +## Compile without LTO enabled + +As a space optimization, LTO (Link Time Optimization) has been enabled on all +targets in the nrf-port. The `-flto` linker flag can be toggled easily by using +the argument LTO when building. The example below shows how to disable LTO for +the compilation: + + make BOARD=pca10040 LTO=0 + +**Note**: There have been several issues with use of LTO in conjunction with +GNU ARM Embedded Toolchain 7.2.1/4Q17. It's recommended to use a toolchain after +this release, for example 7.3.1/2Q18 or 8.2.1/4Q18. The alternative would be to +build the target using the LTO=0 as described above. + ## Compile and Flash with Bluetooth Stack First prepare the bluetooth folder by downloading Bluetooth LE stacks and headers: From 673db939b5c1f42c9411f684343d39811b7a16b2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 26 Mar 2019 15:21:23 +1100 Subject: [PATCH 0231/1788] esp32/machine_pin: Rework pull mode config to fix GPIO hold feature. For gpio_hold_en() to work properly (not draw additional current) pull up/down must be disabled when hold is enabled. This patch makes sure this is the case by reworking the pull constants to be a bit mask. --- ports/esp32/machine_pin.c | 40 +++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/ports/esp32/machine_pin.c b/ports/esp32/machine_pin.c index cbd9ae7e9f..cca7c0ef66 100644 --- a/ports/esp32/machine_pin.c +++ b/ports/esp32/machine_pin.c @@ -39,8 +39,10 @@ #include "machine_rtc.h" #include "modesp32.h" -// Used to implement gpio_hold_en() functionality; value should be distinct from all IDF pull modes -#define GPIO_PULLHOLD (8) +// Used to implement a range of pull capabilities +#define GPIO_PULL_DOWN (1) +#define GPIO_PULL_UP (2) +#define GPIO_PULL_HOLD (4) typedef struct _machine_pin_obj_t { mp_obj_base_t base; @@ -168,18 +170,24 @@ STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_ // configure pull if (args[ARG_pull].u_obj != MP_OBJ_NEW_SMALL_INT(-1)) { - if (args[ARG_pull].u_obj == mp_const_none) { - gpio_set_pull_mode(self->id, GPIO_FLOATING); + int mode = 0; + if (args[ARG_pull].u_obj != mp_const_none) { + mode = mp_obj_get_int(args[ARG_pull].u_obj); + } + if (mode & GPIO_PULL_DOWN) { + gpio_pulldown_en(self->id); } else { - int mode = mp_obj_get_int(args[ARG_pull].u_obj); - if (mode == GPIO_PULLHOLD) { - gpio_hold_en(self->id); - } else { - if (GPIO_IS_VALID_OUTPUT_GPIO(self->id)) { - gpio_hold_dis(self->id); - } - gpio_set_pull_mode(self->id, mode); - } + gpio_pulldown_dis(self->id); + } + if (mode & GPIO_PULL_UP) { + gpio_pullup_en(self->id); + } else { + gpio_pullup_dis(self->id); + } + if (mode & GPIO_PULL_HOLD) { + gpio_hold_en(self->id); + } else if (GPIO_IS_VALID_OUTPUT_GPIO(self->id)) { + gpio_hold_dis(self->id); } } @@ -329,9 +337,9 @@ STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = { { 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_PULL_HOLD), MP_ROM_INT(GPIO_PULLHOLD) }, + { MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(GPIO_PULL_UP) }, + { MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_PULL_DOWN) }, + { MP_ROM_QSTR(MP_QSTR_PULL_HOLD), MP_ROM_INT(GPIO_PULL_HOLD) }, { 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) }, From 2befcb8a9d54f3f9c059b45eba3e9d4e5fb13514 Mon Sep 17 00:00:00 2001 From: Maureen Helm Date: Mon, 18 Mar 2019 08:54:08 -0500 Subject: [PATCH 0232/1788] zephyr/i2c: Add support for hardware i2c. Adds support for hardware i2c to the zephyr port. Similar to other ports such as stm32 and nrf, we only implement the i2c protocol functions (readfrom and writeto) and defer memory operations (readfrom_mem, readfrom_mem_into, and writeto_mem) to the software i2c implementation. This may need to change in the future because zephyr is considering deprecating its i2c_transfer function in favor of i2c_write_read; in this case we would probably want to implement the memory operations directly using i2c_write_read. Tested with the accelerometer on frdm_k64f and bbc_microbit boards. --- ports/zephyr/Makefile | 1 + ports/zephyr/README.md | 8 ++ ports/zephyr/machine_i2c.c | 145 +++++++++++++++++++++++++++++++ ports/zephyr/modmachine.c | 1 + ports/zephyr/mpconfigport.h | 2 + ports/zephyr/mphalport.h | 5 ++ ports/zephyr/prj_base.conf | 3 + ports/zephyr/prj_frdm_k64f.conf | 1 - ports/zephyr/prj_frdm_kw41z.conf | 1 - 9 files changed, 165 insertions(+), 2 deletions(-) create mode 100644 ports/zephyr/machine_i2c.c diff --git a/ports/zephyr/Makefile b/ports/zephyr/Makefile index 8e71d7f081..b23ee10936 100644 --- a/ports/zephyr/Makefile +++ b/ports/zephyr/Makefile @@ -43,6 +43,7 @@ SRC_C = main.c \ modzephyr.c \ modzsensor.c \ modmachine.c \ + machine_i2c.c \ machine_pin.c \ uart_core.c \ lib/utils/stdout_helpers.c \ diff --git a/ports/zephyr/README.md b/ports/zephyr/README.md index f7001af4b8..3d2e883adc 100644 --- a/ports/zephyr/README.md +++ b/ports/zephyr/README.md @@ -12,6 +12,7 @@ Features supported at this time: * REPL (interactive prompt) over Zephyr UART console. * `utime` module for time measurements and delays. +* `machine.I2C` class for I2C control. * `machine.Pin` class for GPIO control. * `usocket` module for networking (IPv4/IPv6). * "Frozen modules" support to allow to bundle Python modules together @@ -81,6 +82,13 @@ To blink an LED: LED.value(0) time.sleep(0.5) +To scan for I2C slaves: + + from machine import I2C + + i2c = I2C("I2C_0") + i2c.scan() + The above code uses an LED location for a FRDM-K64F board (port B, pin 21; following Zephyr conventions port are identified by "GPIO_x", where *x* starts from 0). You will need to adjust it for another board (using board's diff --git a/ports/zephyr/machine_i2c.c b/ports/zephyr/machine_i2c.c new file mode 100644 index 0000000000..bc9851a00c --- /dev/null +++ b/ports/zephyr/machine_i2c.c @@ -0,0 +1,145 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014, 2015 Damien P. George + * Copyright (c) 2019, NXP + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include +#include + +#include "py/runtime.h" +#include "py/gc.h" +#include "py/mphal.h" +#include "py/mperrno.h" +#include "extmod/machine_i2c.h" + +STATIC const mp_obj_type_t machine_hard_i2c_type; + +typedef struct _machine_hard_i2c_obj_t { + mp_obj_base_t base; + struct device *dev; + bool restart; +} machine_hard_i2c_obj_t; + +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 = self_in; + mp_printf(print, "%s", self->dev->config->name); +} + +mp_obj_t machine_hard_i2c_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_scl, ARG_sda, ARG_freq, ARG_timeout }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_scl, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_sda, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.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); + + const char *dev_name = mp_obj_str_get_str(args[ARG_id].u_obj); + struct device *dev = device_get_binding(dev_name); + + if (dev == NULL) { + mp_raise_ValueError("device not found"); + } + + if ((args[ARG_scl].u_obj != MP_OBJ_NULL) || (args[ARG_sda].u_obj != MP_OBJ_NULL)) { + mp_raise_NotImplementedError("explicit choice of scl/sda is not implemented"); + } + + if ((args[ARG_freq].u_obj != MP_OBJ_NULL)) { + mp_raise_NotImplementedError("explicit choice of freq is not implemented"); + } + + if ((args[ARG_timeout].u_obj != MP_OBJ_NULL)) { + mp_raise_NotImplementedError("explicit choice of timeout is not implemented"); + } + + machine_hard_i2c_obj_t *self = m_new_obj(machine_hard_i2c_obj_t); + + self->base.type = &machine_hard_i2c_type; + self->dev = dev; + self->restart = false; + + return MP_OBJ_FROM_PTR(self); +} + +STATIC int machine_hard_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, uint8_t *buf, size_t len, bool stop, bool read) { + machine_hard_i2c_obj_t *self = (machine_hard_i2c_obj_t *)self_in; + struct i2c_msg msg; + int ret; + + msg.buf = (u8_t*)buf; + msg.len = len; + msg.flags = 0; + + if (read) { + msg.flags |= I2C_MSG_READ; + } else { + msg.flags |= I2C_MSG_WRITE; + } + + if (self->restart) { + msg.flags |= I2C_MSG_RESTART; + } + + if (stop) { + msg.flags |= I2C_MSG_STOP; + self->restart = false; + } else { + self->restart = true; + } + + ret = i2c_transfer(self->dev, &msg, 1, addr); + return (ret < 0) ? -MP_EIO : len; +} + +STATIC int machine_hard_i2c_readfrom(mp_obj_base_t *self_in, uint16_t addr, uint8_t *dest, size_t len, bool stop) { + return machine_hard_i2c_transfer(self_in, addr, dest, len, stop, true); +} + +STATIC int machine_hard_i2c_writeto(mp_obj_base_t *self_in, uint16_t addr, const uint8_t *src, size_t len, bool stop) { + return machine_hard_i2c_transfer(self_in, addr, (uint8_t*)src, len, stop, false); +} + +STATIC const mp_machine_i2c_p_t machine_hard_i2c_p = { + .readfrom = machine_hard_i2c_readfrom, + .writeto = machine_hard_i2c_writeto, +}; + +STATIC const mp_obj_type_t machine_hard_i2c_type = { + { &mp_type_type }, + .name = MP_QSTR_I2C, + .print = machine_hard_i2c_print, + .make_new = machine_hard_i2c_make_new, + .protocol = &machine_hard_i2c_p, + .locals_dict = (mp_obj_dict_t*)&mp_machine_soft_i2c_locals_dict, +}; diff --git a/ports/zephyr/modmachine.c b/ports/zephyr/modmachine.c index 5909c37d6f..c89529aa9c 100644 --- a/ports/zephyr/modmachine.c +++ b/ports/zephyr/modmachine.c @@ -60,6 +60,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { #endif { MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) }, + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_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) }, diff --git a/ports/zephyr/mpconfigport.h b/ports/zephyr/mpconfigport.h index ab55601081..0b35de35b7 100644 --- a/ports/zephyr/mpconfigport.h +++ b/ports/zephyr/mpconfigport.h @@ -60,6 +60,8 @@ #define MICROPY_PY_IO (0) #define MICROPY_PY_MICROPYTHON_MEM_INFO (1) #define MICROPY_PY_MACHINE (1) +#define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_I2C_MAKE_NEW machine_hard_i2c_make_new #define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new #define MICROPY_MODULE_WEAK_LINKS (1) #define MICROPY_PY_STRUCT (0) diff --git a/ports/zephyr/mphalport.h b/ports/zephyr/mphalport.h index e3cca8d37d..4388f607dc 100644 --- a/ports/zephyr/mphalport.h +++ b/ports/zephyr/mphalport.h @@ -23,3 +23,8 @@ static inline void mp_hal_delay_us(mp_uint_t delay) { static inline void mp_hal_delay_ms(mp_uint_t delay) { k_sleep(delay); } + +#define mp_hal_delay_us_fast(us) (mp_hal_delay_us(us)) +#define mp_hal_pin_od_low(p) (mp_raise_NotImplementedError("mp_hal_pin_od_low")) +#define mp_hal_pin_od_high(p) (mp_raise_NotImplementedError("mp_hal_pin_od_high")) +#define mp_hal_pin_open_drain(p) (mp_raise_NotImplementedError("mp_hal_pin_open_drain")) diff --git a/ports/zephyr/prj_base.conf b/ports/zephyr/prj_base.conf index 993dfdc26f..58206a0bc2 100644 --- a/ports/zephyr/prj_base.conf +++ b/ports/zephyr/prj_base.conf @@ -14,6 +14,9 @@ CONFIG_NEWLIB_LIBC=y CONFIG_FLOAT=y CONFIG_MAIN_STACK_SIZE=4736 +# Drivers +CONFIG_I2C=y + # Enable sensor subsystem (doesn't add code if not used). # Specific sensors should be enabled per-board. CONFIG_SENSOR=y diff --git a/ports/zephyr/prj_frdm_k64f.conf b/ports/zephyr/prj_frdm_k64f.conf index c974bffb62..477f3b8257 100644 --- a/ports/zephyr/prj_frdm_k64f.conf +++ b/ports/zephyr/prj_frdm_k64f.conf @@ -2,7 +2,6 @@ CONFIG_NET_L2_ETHERNET=y # Sensor drivers -CONFIG_I2C=y CONFIG_FXOS8700=y CONFIG_FXOS8700_MODE_HYBRID=y CONFIG_FXOS8700_TEMP=y diff --git a/ports/zephyr/prj_frdm_kw41z.conf b/ports/zephyr/prj_frdm_kw41z.conf index de51820027..486ece2bd8 100644 --- a/ports/zephyr/prj_frdm_kw41z.conf +++ b/ports/zephyr/prj_frdm_kw41z.conf @@ -1,5 +1,4 @@ # Sensor drivers -CONFIG_I2C=y CONFIG_FXOS8700=y CONFIG_FXOS8700_MODE_HYBRID=y CONFIG_FXOS8700_TEMP=y From 8977c7eb581f5d06500edb1ea29aea5cbda04f28 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Thu, 21 Mar 2019 11:52:10 +1100 Subject: [PATCH 0233/1788] py/scheduler: Convert micropythyon.schedule() to a circular buffer. This means the schedule operates on a first-in, first-executed manner rather than the current last-in, first executed. --- py/mpstate.h | 3 ++- py/runtime.c | 3 ++- py/runtime.h | 2 +- py/scheduler.c | 27 +++++++++++++++++++++------ tests/unix/extra_coverage.py.exp | 6 +++--- 5 files changed, 29 insertions(+), 12 deletions(-) diff --git a/py/mpstate.h b/py/mpstate.h index 1496600402..a9c2b32d66 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -209,7 +209,8 @@ typedef struct _mp_state_vm_t { #if MICROPY_ENABLE_SCHEDULER volatile int16_t sched_state; - uint16_t sched_sp; + uint8_t sched_len; + uint8_t sched_idx; #endif #if MICROPY_PY_THREAD_GIL diff --git a/py/runtime.c b/py/runtime.c index 4a50698cbb..75d50596e4 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -63,7 +63,8 @@ void mp_init(void) { MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; #if MICROPY_ENABLE_SCHEDULER MP_STATE_VM(sched_state) = MP_SCHED_IDLE; - MP_STATE_VM(sched_sp) = 0; + MP_STATE_VM(sched_idx) = 0; + MP_STATE_VM(sched_len) = 0; #endif #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF diff --git a/py/runtime.h b/py/runtime.h index 0dd97a584f..0eb15d4617 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -70,7 +70,7 @@ void mp_handle_pending_tail(mp_uint_t atomic_state); #if MICROPY_ENABLE_SCHEDULER void mp_sched_lock(void); void mp_sched_unlock(void); -static inline unsigned int mp_sched_num_pending(void) { return MP_STATE_VM(sched_sp); } +static inline unsigned int mp_sched_num_pending(void) { return MP_STATE_VM(sched_len); } bool mp_sched_schedule(mp_obj_t function, mp_obj_t arg); #endif diff --git a/py/scheduler.c b/py/scheduler.c index 30851a4d2b..5edff45b6f 100644 --- a/py/scheduler.c +++ b/py/scheduler.c @@ -30,6 +30,19 @@ #if MICROPY_ENABLE_SCHEDULER +#define IDX_MASK(i) ((i) & (MICROPY_SCHEDULER_DEPTH - 1)) + +static inline bool mp_sched_full(void) { + MP_STATIC_ASSERT(MICROPY_SCHEDULER_DEPTH <= 255); // MICROPY_SCHEDULER_DEPTH must fit in 8 bits + MP_STATIC_ASSERT((IDX_MASK(MICROPY_SCHEDULER_DEPTH) == 0)); // MICROPY_SCHEDULER_DEPTH must be a power of 2 + + return mp_sched_num_pending() == MICROPY_SCHEDULER_DEPTH; +} + +static inline bool mp_sched_empty(void) { + return mp_sched_num_pending() == 0; +} + // A variant of this is inlined in the VM at the pending exception check void mp_handle_pending(void) { if (MP_STATE_VM(sched_state) == MP_SCHED_PENDING) { @@ -51,8 +64,10 @@ void mp_handle_pending(void) { // or by the VM's inlined version of that function. void mp_handle_pending_tail(mp_uint_t atomic_state) { MP_STATE_VM(sched_state) = MP_SCHED_LOCKED; - if (MP_STATE_VM(sched_sp) > 0) { - mp_sched_item_t item = MP_STATE_VM(sched_stack)[--MP_STATE_VM(sched_sp)]; + if (!mp_sched_empty()) { + mp_sched_item_t item = MP_STATE_VM(sched_stack)[MP_STATE_VM(sched_idx)]; + MP_STATE_VM(sched_idx) = IDX_MASK(MP_STATE_VM(sched_idx) + 1); + --MP_STATE_VM(sched_len); MICROPY_END_ATOMIC_SECTION(atomic_state); mp_call_function_1_protected(item.func, item.arg); } else { @@ -87,13 +102,13 @@ void mp_sched_unlock(void) { bool mp_sched_schedule(mp_obj_t function, mp_obj_t arg) { mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); bool ret; - if (MP_STATE_VM(sched_sp) < MICROPY_SCHEDULER_DEPTH) { + if (!mp_sched_full()) { if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) { MP_STATE_VM(sched_state) = MP_SCHED_PENDING; } - MP_STATE_VM(sched_stack)[MP_STATE_VM(sched_sp)].func = function; - MP_STATE_VM(sched_stack)[MP_STATE_VM(sched_sp)].arg = arg; - ++MP_STATE_VM(sched_sp); + uint8_t iput = IDX_MASK(MP_STATE_VM(sched_idx) + MP_STATE_VM(sched_len)++); + MP_STATE_VM(sched_stack)[iput].func = function; + MP_STATE_VM(sched_stack)[iput].arg = arg; ret = true; } else { // schedule stack is full diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index 9df8527577..2e23b24585 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -70,10 +70,10 @@ sched(2)=1 sched(3)=1 sched(4)=0 unlocked -3 -2 -1 0 +1 +2 +3 0123456789 b'0123456789' 7300 7300 From dce785cc3d79f6145dc4d4411dbef00bc6d3d9bf Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 21 Mar 2019 09:33:41 +0100 Subject: [PATCH 0234/1788] py/nlrthumb: Add support for iOS where the C func is _nlr_push_tail. --- py/nlrthumb.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/py/nlrthumb.c b/py/nlrthumb.c index c283023551..99061e62cd 100644 --- a/py/nlrthumb.c +++ b/py/nlrthumb.c @@ -72,7 +72,11 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { ".align 2 \n" "nlr_push_tail_var: .word nlr_push_tail \n" #else + #if defined(__APPLE__) || defined(__MACH__) + "b _nlr_push_tail \n" // do the rest in C + #else "b nlr_push_tail \n" // do the rest in C + #endif #endif ); From 869a8b70ce384be7c8ab7cfbde1de683ba2fc077 Mon Sep 17 00:00:00 2001 From: rhubarbdog <33667064+rhubarbdog@users.noreply.github.com> Date: Sat, 23 Mar 2019 08:49:12 +0000 Subject: [PATCH 0235/1788] tools/pyboard.py: Add missing line from example usage comments. --- tools/pyboard.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/pyboard.py b/tools/pyboard.py index 86a07a151c..42b077de22 100755 --- a/tools/pyboard.py +++ b/tools/pyboard.py @@ -47,6 +47,7 @@ Or: Then: pyb.enter_raw_repl() + pyb.exec('import pyb') pyb.exec('pyb.LED(1).on()') pyb.exit_raw_repl() From d396a7e10d69f9490ca3aaa0b2ca147223f20314 Mon Sep 17 00:00:00 2001 From: roland van straten Date: Sun, 24 Mar 2019 20:53:27 +0100 Subject: [PATCH 0236/1788] stm32/system_stm32: Provide default value for HSI calibration. If HSI is used the calibration value must be valid. Fixes #4596. --- ports/stm32/system_stm32.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/stm32/system_stm32.c b/ports/stm32/system_stm32.c index e0f0545006..be8badea43 100644 --- a/ports/stm32/system_stm32.c +++ b/ports/stm32/system_stm32.c @@ -416,6 +416,7 @@ void SystemClock_Config(void) RCC_OscInitStruct.OscillatorType = MICROPY_HW_RCC_OSCILLATOR_TYPE; RCC_OscInitStruct.HSEState = MICROPY_HW_RCC_HSE_STATE; RCC_OscInitStruct.HSIState = MICROPY_HW_RCC_HSI_STATE; + RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; #if defined(STM32H7) RCC_OscInitStruct.CSIState = RCC_CSI_OFF; #endif From 74d07469f276aff862a99423ded03f08ec5006b3 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Mon, 25 Mar 2019 11:20:54 +1100 Subject: [PATCH 0237/1788] extmod/vfs_fat: Fallback to FAT32 if standard FAT16/SFD format fails. This allows formatting SD cards, larger flash etc which do not support the default FAT16/SFD format mode. --- extmod/vfs_fat.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index 024cecfe93..ec7aaed388 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -113,6 +113,9 @@ STATIC mp_obj_t fat_vfs_mkfs(mp_obj_t bdev_in) { // make the filesystem uint8_t working_buf[FF_MAX_SS]; FRESULT res = f_mkfs(&vfs->fatfs, FM_FAT | FM_SFD, 0, working_buf, sizeof(working_buf)); + if (res == FR_MKFS_ABORTED) { // Probably doesn't support FAT16 + res = f_mkfs(&vfs->fatfs, FM_FAT32, 0, working_buf, sizeof(working_buf)); + } if (res != FR_OK) { mp_raise_OSError(fresult_to_errno_table[res]); } From 1556af19bfde9e8f14c84e2bc6a2c3a087e18325 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 26 Mar 2019 18:19:21 +1100 Subject: [PATCH 0238/1788] mpy-cross: Support compiling with MICROPY_PY___FILE__ enabled. --- mpy-cross/main.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mpy-cross/main.c b/mpy-cross/main.c index ef5d8752a8..6e5af2739b 100644 --- a/mpy-cross/main.c +++ b/mpy-cross/main.c @@ -67,9 +67,7 @@ STATIC int compile_and_save(const char *file, const char *output_file, const cha } #if MICROPY_PY___FILE__ - if (input_kind == MP_PARSE_FILE_INPUT) { - mp_store_global(MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); - } + mp_store_global(MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); #endif mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT); From 781947afdc11887f30957dccc37593caff97b79f Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 26 Mar 2019 18:40:05 +1100 Subject: [PATCH 0239/1788] stm32/mpconfigport.h: Remove malloc/free/realloc helper macros. These macros are unused, and they can conflict with other entities by the same name. If needed they can be provided as static inline functions, or just functions. Fixes issue #4559. --- ports/stm32/mpconfigport.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index bdceb8c532..86f65fda26 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -365,13 +365,5 @@ static inline mp_uint_t disable_irq(void) { // We need an implementation of the log2 function which is not a macro #define MP_NEED_LOG2 (1) -// There is no classical C heap in bare-metal ports, only Python -// garbage-collected heap. For completeness, emulate C heap via -// GC heap. Note that MicroPython core never uses malloc() and friends, -// so these defines are mostly to help extension module writers. -#define malloc(n) m_malloc(n) -#define free(p) m_free(p) -#define realloc(p, n) m_realloc(p, n) - // We need to provide a declaration/definition of alloca() #include From 968b688055b75f3779b6d07bea0d2c1e0f3c17ba Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 26 Mar 2019 17:46:27 +1100 Subject: [PATCH 0240/1788] tests/extmod: Add test for FAT filesystem on a very large block device. --- tests/extmod/vfs_fat_ramdisklarge.py | 70 ++++++++++++++++++++++++ tests/extmod/vfs_fat_ramdisklarge.py.exp | 3 + 2 files changed, 73 insertions(+) create mode 100644 tests/extmod/vfs_fat_ramdisklarge.py create mode 100644 tests/extmod/vfs_fat_ramdisklarge.py.exp diff --git a/tests/extmod/vfs_fat_ramdisklarge.py b/tests/extmod/vfs_fat_ramdisklarge.py new file mode 100644 index 0000000000..6f95910315 --- /dev/null +++ b/tests/extmod/vfs_fat_ramdisklarge.py @@ -0,0 +1,70 @@ +# test making a FAT filesystem on a very large block device + +try: + import uos +except ImportError: + print("SKIP") + raise SystemExit + +try: + uos.VfsFat +except AttributeError: + print("SKIP") + raise SystemExit + + +class RAMBDevSparse: + + SEC_SIZE = 512 + + def __init__(self, blocks): + self.blocks = blocks + self.data = {} + + def readblocks(self, n, buf): + #print("readblocks(%s, %x(%d))" % (n, id(buf), len(buf))) + assert len(buf) == self.SEC_SIZE + if n not in self.data: + self.data[n] = bytearray(self.SEC_SIZE) + buf[:] = self.data[n] + + def writeblocks(self, n, buf): + #print("writeblocks(%s, %x)" % (n, id(buf))) + mv = memoryview(buf) + for off in range(0, len(buf), self.SEC_SIZE): + s = n + off // self.SEC_SIZE + if s not in self.data: + self.data[s] = bytearray(self.SEC_SIZE) + self.data[s][:] = mv[off:off + self.SEC_SIZE] + + 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 + + +try: + bdev = RAMBDevSparse(4 * 1024 * 1024 * 1024 // RAMBDevSparse.SEC_SIZE) + uos.VfsFat.mkfs(bdev) +except MemoryError: + print("SKIP") + raise SystemExit + +vfs = uos.VfsFat(bdev) +uos.mount(vfs, "/ramdisk") + +print("statvfs:", vfs.statvfs("/ramdisk")) + +f = open('/ramdisk/test.txt', 'w') +f.write('test file') +f.close() + +print("statvfs:", vfs.statvfs("/ramdisk")) + +f = open('/ramdisk/test.txt') +print(f.read()) +f.close() + +uos.umount(vfs) diff --git a/tests/extmod/vfs_fat_ramdisklarge.py.exp b/tests/extmod/vfs_fat_ramdisklarge.py.exp new file mode 100644 index 0000000000..ea723e2249 --- /dev/null +++ b/tests/extmod/vfs_fat_ramdisklarge.py.exp @@ -0,0 +1,3 @@ +statvfs: (32768, 32768, 131054, 131053, 131053, 0, 0, 0, 0, 255) +statvfs: (32768, 32768, 131054, 131052, 131052, 0, 0, 0, 0, 255) +test file From 0b86ba565c3d5093620faeb0d5abdd3ff56beffa Mon Sep 17 00:00:00 2001 From: Damiano Mazzella Date: Tue, 5 Feb 2019 22:13:36 +0100 Subject: [PATCH 0241/1788] unix/mpthreadport: Use named semaphores on Mac OS X. Unnamed semaphores (via sem_init) are not supported on this OS. See #4465. --- ports/unix/mpthreadport.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/ports/unix/mpthreadport.c b/ports/unix/mpthreadport.c index 29f2efe752..4fe5fa9218 100644 --- a/ports/unix/mpthreadport.c +++ b/ports/unix/mpthreadport.c @@ -34,6 +34,7 @@ #if MICROPY_PY_THREAD +#include #include #include #include @@ -54,7 +55,12 @@ STATIC thread_t *thread; // this is used to synchronise the signal handler of the thread // it's needed because we can't use any pthread calls in a signal handler +#if defined(__APPLE__) +STATIC char thread_signal_done_name[25]; +STATIC sem_t *thread_signal_done_p; +#else STATIC sem_t thread_signal_done; +#endif // this signal handler is used to scan the regs and stack of a thread STATIC void mp_thread_gc(int signo, siginfo_t *info, void *context) { @@ -71,7 +77,11 @@ STATIC void mp_thread_gc(int signo, siginfo_t *info, void *context) { 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 + #if defined (__APPLE__) + sem_post(thread_signal_done_p); + #else sem_post(&thread_signal_done); + #endif } } @@ -85,7 +95,13 @@ void mp_thread_init(void) { thread->ready = 1; thread->arg = NULL; thread->next = NULL; + + #if defined(__APPLE__) + snprintf(thread_signal_done_name, sizeof(thread_signal_done_name), "micropython_sem_%d", (int)thread->id); + thread_signal_done_p = sem_open(thread_signal_done_name, O_CREAT | O_EXCL, 0666, 0); + #else sem_init(&thread_signal_done, 0, 0); + #endif // enable signal handler for garbage collection struct sigaction sa; @@ -104,6 +120,10 @@ void mp_thread_deinit(void) { free(th); } pthread_mutex_unlock(&thread_mutex); + #if defined(__APPLE__) + sem_close(thread_signal_done_p); + sem_unlink(thread_signal_done_name); + #endif assert(thread->id == pthread_self()); free(thread); } @@ -125,7 +145,11 @@ void mp_thread_gc_others(void) { continue; } pthread_kill(th->id, SIGUSR1); + #if defined(__APPLE__) + sem_wait(thread_signal_done_p); + #else sem_wait(&thread_signal_done); + #endif } pthread_mutex_unlock(&thread_mutex); } From 815b79a8d0ff698bd577ad86280a599191dd5949 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 27 Mar 2019 11:11:06 +1100 Subject: [PATCH 0242/1788] esp32/mpthreadport: Exit vPortCleanUpTCB early if threading not init'd. --- ports/esp32/mpthreadport.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ports/esp32/mpthreadport.c b/ports/esp32/mpthreadport.c index 52d4d7ff4d..6c4ed9b5e3 100644 --- a/ports/esp32/mpthreadport.c +++ b/ports/esp32/mpthreadport.c @@ -54,7 +54,7 @@ typedef struct _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 +STATIC thread_t *thread = NULL; // 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); @@ -166,6 +166,10 @@ void mp_thread_finish(void) { } void vPortCleanUpTCB(void *tcb) { + if (thread == NULL) { + // threading not yet initialised + return; + } thread_t *prev = NULL; mp_thread_mutex_lock(&thread_mutex, 1); for (thread_t *th = thread; th != NULL; prev = th, th = th->next) { From 92149c8a7954169285b2909012dc601c6e7cb0aa Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 27 Mar 2019 11:20:21 +1100 Subject: [PATCH 0243/1788] esp32/boards: Enable dual core support by default. Single core is still supported, just by adding CONFIG_FREERTOS_UNICORE=y to a custom sdkconfig file. --- ports/esp32/boards/sdkconfig | 1 - ports/esp32/boards/sdkconfig.spiram | 1 - 2 files changed, 2 deletions(-) diff --git a/ports/esp32/boards/sdkconfig b/ports/esp32/boards/sdkconfig index 23fc8dead5..eaafed5d6b 100644 --- a/ports/esp32/boards/sdkconfig +++ b/ports/esp32/boards/sdkconfig @@ -19,7 +19,6 @@ CONFIG_ESP32_XTAL_FREQ_AUTO=y CONFIG_PM_ENABLE=y # FreeRTOS -CONFIG_FREERTOS_UNICORE=y CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=2 CONFIG_SUPPORT_STATIC_ALLOCATION=y CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK=y diff --git a/ports/esp32/boards/sdkconfig.spiram b/ports/esp32/boards/sdkconfig.spiram index b34781a0d0..6de2db7cb0 100644 --- a/ports/esp32/boards/sdkconfig.spiram +++ b/ports/esp32/boards/sdkconfig.spiram @@ -22,7 +22,6 @@ CONFIG_ESP32_XTAL_FREQ_AUTO=y CONFIG_PM_ENABLE=y # FreeRTOS -CONFIG_FREERTOS_UNICORE=y CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=2 CONFIG_SUPPORT_STATIC_ALLOCATION=y CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK=y From 95b6330403a1b111b88704b327d172ae00927389 Mon Sep 17 00:00:00 2001 From: spacemanspiff2007 Date: Tue, 26 Mar 2019 09:22:21 +0100 Subject: [PATCH 0244/1788] docs/esp32: Add example for pin isolation in combination with deepsleep. --- docs/esp32/quickref.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst index e6c53b1172..5ac8aa3b2f 100644 --- a/docs/esp32/quickref.rst +++ b/docs/esp32/quickref.rst @@ -340,6 +340,15 @@ Notes: * Calling ``deepsleep()`` without an argument will put the device to sleep indefinitely * A software reset does not change the reset cause +* There may be some leakage current flowing through enabled internal pullups. + To further reduce power consumption it is possible to disable the internal pullups:: + + p1 = Pin(4, Pin.IN, Pin.PULL_HOLD) + + After leaving deepsleep it may be necessary to un-hold the pin explicitly (e.g. if + it is an output pin) via:: + + p1 = Pin(4, Pin.OUT, None) OneWire driver -------------- From 1a608ce1e892745fbe740e8dcc41c7871bf3dec3 Mon Sep 17 00:00:00 2001 From: Boris Vinogradov Date: Wed, 27 Mar 2019 20:19:50 +0300 Subject: [PATCH 0245/1788] stm32/boards/STM32L476DISC: Enable servo support on STM32L476DISC board. --- 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 2653ebb34d..2831187531 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_SERVO (1) #define MICROPY_HW_ENABLE_USB (1) // use external SPI flash for storage From 6947dff7dacc513efa2dbe4392c31ecb07ec50db Mon Sep 17 00:00:00 2001 From: Boris Vinogradov Date: Thu, 28 Mar 2019 10:02:57 +0300 Subject: [PATCH 0246/1788] stm32/Makefile: Allow to override CROSS_COMPILE with included Makefile. --- ports/stm32/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index d0b90c7617..40560b842b 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -42,7 +42,8 @@ OPENOCD ?= openocd OPENOCD_CONFIG ?= boards/openocd_stm32f4.cfg STARTUP_FILE ?= boards/startup_stm32$(MCU_SERIES).o -CROSS_COMPILE = arm-none-eabi- +# Select the cross compile prefix +CROSS_COMPILE ?= arm-none-eabi- INC += -I. INC += -I$(TOP) From 0fb15fc3f4b532faa3ca4fe49809f9d9e6c5cd53 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 29 Mar 2019 11:50:39 +1100 Subject: [PATCH 0247/1788] docs/develop: Remove paragraph that was copied in error from other doc. --- docs/develop/index.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/develop/index.rst b/docs/develop/index.rst index 6b7b3c3910..64dbc46613 100644 --- a/docs/develop/index.rst +++ b/docs/develop/index.rst @@ -1,9 +1,6 @@ Developing and building MicroPython =================================== -This chapter describes modules (function and class libraries) which are built -into MicroPython. There are a few categories of such modules: - This chapter describes some options for extending MicroPython in C. Note that it doesn't aim to be a complete guide for developing with MicroPython. See the `getting started guide From 9d6f70f7154aa01a02d3de1c669241e3a1439218 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Thu, 21 Feb 2019 05:23:41 +1100 Subject: [PATCH 0248/1788] stm32: Make default USB_VCP stream go through uos.dupterm for main REPL. Use uos.dupterm for REPL configuration of the main USB_VCP(0) stream on dupterm slot 1, if USB is enabled. This means dupterm can also be used to disable the boot REPL port if desired, via uos.dupterm(None, 1). For efficiency this adds a simple hook to the global uos.dupterm code to work with streams that are known to be native streams. --- extmod/misc.h | 1 + extmod/uos_dupterm.c | 25 +++++++++++++++++++++++++ ports/stm32/main.c | 4 ++++ ports/stm32/moduos.c | 13 +++++++++++++ ports/stm32/mpconfigport.h | 3 ++- ports/stm32/mphalport.c | 12 ------------ ports/stm32/usb.c | 27 ++++++++++++++++++++------- ports/stm32/usb.h | 5 +++++ ports/stm32/usbd_cdc_interface.c | 5 ----- 9 files changed, 70 insertions(+), 25 deletions(-) diff --git a/extmod/misc.h b/extmod/misc.h index d6f6d859c6..dae6bec4a1 100644 --- a/extmod/misc.h +++ b/extmod/misc.h @@ -35,6 +35,7 @@ MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_uos_dupterm_obj); #if MICROPY_PY_OS_DUPTERM +bool mp_uos_dupterm_is_builtin_stream(mp_const_obj_t stream); int mp_uos_dupterm_rx_chr(void); void mp_uos_dupterm_tx_strn(const char *str, size_t len); void mp_uos_deactivate(size_t dupterm_idx, const char *msg, mp_obj_t exc); diff --git a/extmod/uos_dupterm.c b/extmod/uos_dupterm.c index dec3e1a400..42cb21444b 100644 --- a/extmod/uos_dupterm.c +++ b/extmod/uos_dupterm.c @@ -32,6 +32,7 @@ #include "py/objtuple.h" #include "py/objarray.h" #include "py/stream.h" +#include "extmod/misc.h" #include "lib/utils/interrupt_char.h" #if MICROPY_PY_OS_DUPTERM @@ -58,6 +59,20 @@ int mp_uos_dupterm_rx_chr(void) { continue; } + #if MICROPY_PY_UOS_DUPTERM_BUILTIN_STREAM + if (mp_uos_dupterm_is_builtin_stream(MP_STATE_VM(dupterm_objs[idx]))) { + byte buf[1]; + int errcode = 0; + 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 (errcode == 0 && out_sz != 0) { + return buf[0]; + } else { + continue; + } + } + #endif + nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { byte buf[1]; @@ -98,6 +113,16 @@ void mp_uos_dupterm_tx_strn(const char *str, size_t len) { if (MP_STATE_VM(dupterm_objs[idx]) == MP_OBJ_NULL) { continue; } + + #if MICROPY_PY_UOS_DUPTERM_BUILTIN_STREAM + if (mp_uos_dupterm_is_builtin_stream(MP_STATE_VM(dupterm_objs[idx]))) { + int errcode = 0; + const mp_stream_p_t *stream_p = mp_get_stream(MP_STATE_VM(dupterm_objs[idx])); + stream_p->write(MP_STATE_VM(dupterm_objs[idx]), str, len, &errcode); + continue; + } + #endif + nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { mp_stream_write(MP_STATE_VM(dupterm_objs[idx]), str, len, MP_STREAM_RW_WRITE); diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 48b4692bc5..c1d27a9680 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -630,6 +630,10 @@ soft_reset: #if MICROPY_HW_ENABLE_USB pyb_usb_init0(); + + // Activate USB_VCP(0) on dupterm slot 1 for the REPL + MP_STATE_VM(dupterm_objs[1]) = MP_OBJ_FROM_PTR(&pyb_usb_vcp_obj); + usb_vcp_attach_to_repl(&pyb_usb_vcp_obj, true); #endif // Initialise the local flash filesystem. diff --git a/ports/stm32/moduos.c b/ports/stm32/moduos.c index f492b0b752..ffecccd17d 100644 --- a/ports/stm32/moduos.c +++ b/ports/stm32/moduos.c @@ -38,6 +38,7 @@ #include "extmod/vfs_fat.h" #include "genhdr/mpversion.h" #include "rng.h" +#include "usb.h" #include "uart.h" #include "portmodules.h" @@ -108,14 +109,26 @@ STATIC mp_obj_t os_urandom(mp_obj_t num) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom); #endif +bool mp_uos_dupterm_is_builtin_stream(mp_const_obj_t stream) { + mp_obj_type_t *type = mp_obj_get_type(stream); + return type == &pyb_uart_type || type == &pyb_usb_vcp_type; +} + 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(prev_obj) == &pyb_usb_vcp_type) { + usb_vcp_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); } + if (mp_obj_get_type(args[0]) == &pyb_usb_vcp_type) { + usb_vcp_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); diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 86f65fda26..7cb67a115a 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -145,7 +145,8 @@ #define MICROPY_PY_USELECT (1) #define MICROPY_PY_UTIMEQ (1) #define MICROPY_PY_UTIME_MP_HAL (1) -#define MICROPY_PY_OS_DUPTERM (1) +#define MICROPY_PY_OS_DUPTERM (3) +#define MICROPY_PY_UOS_DUPTERM_BUILTIN_STREAM (1) #define MICROPY_PY_MACHINE (1) #define MICROPY_PY_MACHINE_PULSE (1) #define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new diff --git a/ports/stm32/mphalport.c b/ports/stm32/mphalport.c index 9e59eb6138..c770b62d2e 100644 --- a/ports/stm32/mphalport.c +++ b/ports/stm32/mphalport.c @@ -30,13 +30,6 @@ MP_WEAK 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; - } - #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)); } @@ -59,11 +52,6 @@ MP_WEAK 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/usb.c b/ports/stm32/usb.c index 1ff62b4ab5..1db32c9ae4 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -111,6 +111,10 @@ const mp_rom_obj_tuple_t pyb_usb_hid_keyboard_obj = { }; void pyb_usb_init0(void) { + usb_device.usbd_cdc_itf.attached_to_repl = false; + #if MICROPY_HW_USB_ENABLE_CDC2 + usb_device.usbd_cdc2_itf.attached_to_repl = false; + #endif mp_hal_set_interrupt_char(-1); MP_STATE_PORT(pyb_hid_report_desc) = MP_OBJ_NULL; } @@ -380,7 +384,7 @@ typedef struct _pyb_usb_vcp_obj_t { 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.usbd_cdc_itf}; +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 @@ -390,6 +394,10 @@ STATIC void pyb_usb_vcp_print(const mp_print_t *print, mp_obj_t self_in, mp_prin mp_printf(print, "USB_VCP(%u)", id); } +void usb_vcp_attach_to_repl(const pyb_usb_vcp_obj_t *self, bool attached) { + self->cdc_itf->attached_to_repl = attached; +} + /// \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) { @@ -566,13 +574,18 @@ 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->cdc_itf, (const byte*)buf, size, 0); - if (ret == 0) { - // return EAGAIN error to indicate non-blocking - *errcode = MP_EAGAIN; - return MP_STREAM_ERROR; + if (self->cdc_itf->attached_to_repl) { + usbd_cdc_tx_always(self->cdc_itf, (const byte*)buf, size); + return size; + } else { + 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; + return MP_STREAM_ERROR; + } + return ret; } - return ret; } STATIC mp_uint_t pyb_usb_vcp_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { diff --git a/ports/stm32/usb.h b/ports/stm32/usb.h index 45a05882a9..2a3861f210 100644 --- a/ports/stm32/usb.h +++ b/ports/stm32/usb.h @@ -49,12 +49,16 @@ typedef enum { USB_PHY_HS_ID = 1, } USB_PHY_ID; +typedef struct _pyb_usb_vcp_obj_t pyb_usb_vcp_obj_t; + extern mp_uint_t pyb_usb_flags; extern pyb_usb_storage_medium_t pyb_usb_storage_medium; extern const struct _mp_rom_obj_tuple_t pyb_usb_hid_mouse_obj; extern const struct _mp_rom_obj_tuple_t pyb_usb_hid_keyboard_obj; extern const mp_obj_type_t pyb_usb_vcp_type; extern const mp_obj_type_t pyb_usb_hid_type; +extern const pyb_usb_vcp_obj_t pyb_usb_vcp_obj; + MP_DECLARE_CONST_FUN_OBJ_KW(pyb_usb_mode_obj); MP_DECLARE_CONST_FUN_OBJ_0(pyb_have_cdc_obj); // deprecated MP_DECLARE_CONST_FUN_OBJ_1(pyb_hid_send_report_obj); // deprecated @@ -65,6 +69,7 @@ void pyb_usb_dev_deinit(void); bool usb_vcp_is_enabled(void); int usb_vcp_recv_byte(uint8_t *c); // if a byte is available, return 1 and put the byte in *c, else return 0 void usb_vcp_send_strn(const char* str, int len); +void usb_vcp_attach_to_repl(const pyb_usb_vcp_obj_t *self, bool attached); void pyb_usb_host_init(void); void pyb_usb_host_process(void); diff --git a/ports/stm32/usbd_cdc_interface.c b/ports/stm32/usbd_cdc_interface.c index bc35ff50c9..586f2d525e 100644 --- a/ports/stm32/usbd_cdc_interface.c +++ b/ports/stm32/usbd_cdc_interface.c @@ -74,11 +74,6 @@ uint8_t *usbd_cdc_init(usbd_cdc_state_t *cdc_in) { cdc->tx_buf_ptr_out_shadow = 0; cdc->tx_need_empty_packet = 0; cdc->connect_state = USBD_CDC_CONNECT_STATE_DISCONNECTED; - #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; From edd0e0f93d180e79c1422d1eb7a9ec1954bb6d03 Mon Sep 17 00:00:00 2001 From: roland van straten Date: Thu, 14 Mar 2019 12:15:35 +0100 Subject: [PATCH 0249/1788] stm32/timer: Expose the PWM BRK capability of Timer 1 and 8. The break mode is configurable via the 'brk' keyword to the Timer constructor and init method. It's disabled by default. --- ports/stm32/timer.c | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/ports/stm32/timer.c b/ports/stm32/timer.c index 28dc749b4e..b3bb92f2e5 100644 --- a/ports/stm32/timer.c +++ b/ports/stm32/timer.c @@ -112,6 +112,12 @@ STATIC const struct { { MP_QSTR_ENC_AB, TIM_ENCODERMODE_TI12 }, }; +enum { + BRK_OFF, + BRK_LOW, + BRK_HIGH, +}; + typedef struct _pyb_timer_channel_obj_t { mp_obj_base_t base; struct _pyb_timer_obj_t *timer; @@ -462,14 +468,14 @@ STATIC mp_int_t compute_ticks_from_dtg(uint32_t dtg) { return 512 + ((dtg & 0x1F) * 16); } -STATIC void config_deadtime(pyb_timer_obj_t *self, mp_int_t ticks) { +STATIC void config_deadtime(pyb_timer_obj_t *self, mp_int_t ticks, mp_int_t brk) { TIM_BreakDeadTimeConfigTypeDef deadTimeConfig; deadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE; deadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE; deadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF; deadTimeConfig.DeadTime = compute_dtg_from_ticks(ticks); - deadTimeConfig.BreakState = TIM_BREAK_DISABLE; - deadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_LOW; + deadTimeConfig.BreakState = brk == BRK_OFF ? TIM_BREAK_DISABLE : TIM_BREAK_ENABLE; + deadTimeConfig.BreakPolarity = brk == BRK_LOW ? TIM_BREAKPOLARITY_LOW : TIM_BREAKPOLARITY_HIGH; deadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; HAL_TIMEx_ConfigBreakDeadTime(&self->tim, &deadTimeConfig); } @@ -512,6 +518,12 @@ STATIC void pyb_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ { mp_printf(print, ", deadtime=%u", compute_ticks_from_dtg(self->tim.Instance->BDTR & TIM_BDTR_DTG)); + if ((self->tim.Instance->BDTR & TIM_BDTR_BKE) == TIM_BDTR_BKE) { + mp_printf(print, ", brk=%s", + ((self->tim.Instance->BDTR & TIM_BDTR_BKP) == TIM_BDTR_BKP) ? "BRK_HIGH" : "BRK_LOW"); + } else { + mp_printf(print, ", brk=BRK_OFF"); + } } mp_print_str(print, ")"); } @@ -561,9 +573,15 @@ STATIC void pyb_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ /// measures ticks of `source_freq` divided by `div` clock ticks. /// `deadtime` is only available on timers 1 and 8. /// +/// - `brk` - specifies if the break mode is used to kill the output of +/// the PWM when the BRK_IN input is asserted. The polarity set how the +/// BRK_IN input is triggered. It can be set to `BRK_OFF`, `BRK_LOW` +/// and `BRK_HIGH`. +/// +/// /// You must either specify freq or both of period and prescaler. STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_freq, ARG_prescaler, ARG_period, ARG_tick_hz, ARG_mode, ARG_div, ARG_callback, ARG_deadtime }; + enum { ARG_freq, ARG_prescaler, ARG_period, ARG_tick_hz, ARG_mode, ARG_div, ARG_callback, ARG_deadtime, ARG_brk }; static const mp_arg_t allowed_args[] = { { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, { MP_QSTR_prescaler, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, @@ -573,6 +591,7 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, size_t n_args, cons { MP_QSTR_div, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, { MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, { MP_QSTR_deadtime, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_brk, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = BRK_OFF} }, }; // parse args @@ -679,7 +698,8 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, size_t n_args, cons #else if (0) { #endif - config_deadtime(self, args[ARG_deadtime].u_int); + config_deadtime(self, args[ARG_deadtime].u_int, args[ARG_brk].u_int); + } // Enable ARPE so that the auto-reload register is buffered. @@ -1307,6 +1327,9 @@ STATIC const mp_rom_map_elem_t pyb_timer_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_RISING), MP_ROM_INT(TIM_ICPOLARITY_RISING) }, { MP_ROM_QSTR(MP_QSTR_FALLING), MP_ROM_INT(TIM_ICPOLARITY_FALLING) }, { MP_ROM_QSTR(MP_QSTR_BOTH), MP_ROM_INT(TIM_ICPOLARITY_BOTHEDGE) }, + { MP_ROM_QSTR(MP_QSTR_BRK_OFF), MP_ROM_INT(BRK_OFF) }, + { MP_ROM_QSTR(MP_QSTR_BRK_LOW), MP_ROM_INT(BRK_LOW) }, + { MP_ROM_QSTR(MP_QSTR_BRK_HIGH), MP_ROM_INT(BRK_HIGH) }, }; STATIC MP_DEFINE_CONST_DICT(pyb_timer_locals_dict, pyb_timer_locals_dict_table); From da938a83b587c7387b8849f795f3497735d14267 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 27 Mar 2019 15:58:51 +1100 Subject: [PATCH 0250/1788] extmod/modlwip: Handle case of connection closing while on accept queue. In such a case the connection is aborted by lwIP and so must be removed from the pending accept queue. --- extmod/modlwip.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index c7e050129d..d1359a2aa4 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -370,6 +370,43 @@ STATIC err_t _lwip_tcp_connected(void *arg, struct tcp_pcb *tpcb, err_t err) { return ERR_OK; } +// Handle errors (eg connection aborted) on TCP PCBs that have been put on the +// accept queue but are not yet actually accepted. +STATIC void _lwip_tcp_err_unaccepted(void *arg, err_t err) { + struct tcp_pcb *pcb = (struct tcp_pcb*)arg; + + // The ->connected entry is repurposed to store the parent socket; this is safe + // because it's only ever used by lwIP if tcp_connect is called on the TCP PCB. + lwip_socket_obj_t *socket = (lwip_socket_obj_t*)pcb->connected; + + // Array is not volatile because thiss callback is executed within the lwIP context + uint8_t alloc = socket->incoming.connection.alloc; + struct tcp_pcb **tcp_array = (struct tcp_pcb**)lwip_socket_incoming_array(socket); + + // Search for PCB on the accept queue of the parent socket + struct tcp_pcb **shift_down = NULL; + uint8_t i = socket->incoming.connection.iget; + do { + if (shift_down == NULL) { + if (tcp_array[i] == pcb) { + shift_down = &tcp_array[i]; + } + } else { + *shift_down = tcp_array[i]; + shift_down = &tcp_array[i]; + } + if (++i >= alloc) { + i = 0; + } + } while (i != socket->incoming.connection.iput); + + // PCB found in queue, remove it + if (shift_down != NULL) { + *shift_down = NULL; + socket->incoming.connection.iput = shift_down - tcp_array; + } +} + // By default, a child socket of listen socket is created with recv // handler which discards incoming pbuf's. We don't want to do that, // so set this handler which requests lwIP to keep pbuf's and deliver @@ -409,6 +446,15 @@ STATIC err_t _lwip_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err) { // is idle. tcp_poll(newpcb, _lwip_tcp_accept_finished, 1); } + + // Set the error callback to handle the case of a dropped connection before we + // have a chance to take it off the accept queue. + // The ->connected entry is repurposed to store the parent socket; this is safe + // because it's only ever used by lwIP if tcp_connect is called on the TCP PCB. + newpcb->connected = (void*)socket; + tcp_arg(newpcb, newpcb); + tcp_err(newpcb, _lwip_tcp_err_unaccepted); + return ERR_OK; } From 2ec7838967aec9d43d44c2d53377e827d6fcf041 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 27 Mar 2019 16:00:25 +1100 Subject: [PATCH 0251/1788] extmod/modlwip: Handle case of accept callback called with null PCB. --- extmod/modlwip.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index d1359a2aa4..6960546f68 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -429,6 +429,11 @@ STATIC err_t _lwip_tcp_accept_finished(void *arg, struct tcp_pcb *pcb) // Callback for incoming tcp connections. STATIC err_t _lwip_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err) { + // err can be ERR_MEM to notify us that there was no memory for an incoming connection + if (err != ERR_OK) { + return ERR_OK; + } + lwip_socket_obj_t *socket = (lwip_socket_obj_t*)arg; tcp_recv(newpcb, _lwip_tcp_recv_unaccepted); From 490e0f39d1470d4cdf4b91a0632f6147ab4220ea Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 27 Mar 2019 16:11:33 +1100 Subject: [PATCH 0252/1788] extmod/modlwip: Protect socket.accept with lwIP concurrency lock. This is needed now that the accept queue can have pending connections removed asynchronously. --- extmod/modlwip.c | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index 6960546f68..d501f4be2a 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -859,15 +859,28 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_listen_obj, lwip_socket_listen); STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) { lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in); - if (socket->pcb.tcp == NULL) { - mp_raise_OSError(MP_EBADF); - } if (socket->type != MOD_NETWORK_SOCK_STREAM) { mp_raise_OSError(MP_EOPNOTSUPP); } + + // Create new socket object, do it here because we must not raise an out-of-memory + // exception when the LWIP concurrency lock is held + lwip_socket_obj_t *socket2 = m_new_obj_with_finaliser(lwip_socket_obj_t); + socket2->base.type = &lwip_socket_type; + + MICROPY_PY_LWIP_ENTER + + if (socket->pcb.tcp == NULL) { + MICROPY_PY_LWIP_EXIT + m_del_obj(lwip_socket_obj_t, socket2); + mp_raise_OSError(MP_EBADF); + } + // I need to do this because "tcp_accepted", later, is a macro. struct tcp_pcb *listener = socket->pcb.tcp; if (listener->state != LISTEN) { + MICROPY_PY_LWIP_EXIT + m_del_obj(lwip_socket_obj_t, socket2); mp_raise_OSError(MP_EINVAL); } @@ -875,26 +888,29 @@ STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) { struct tcp_pcb *volatile *incoming_connection = &lwip_socket_incoming_array(socket)[socket->incoming.connection.iget]; if (*incoming_connection == NULL) { if (socket->timeout == 0) { + MICROPY_PY_LWIP_EXIT + m_del_obj(lwip_socket_obj_t, socket2); mp_raise_OSError(MP_EAGAIN); } else if (socket->timeout != -1) { - for (mp_uint_t retries = socket->timeout / 100; retries--;) { + mp_uint_t retries = socket->timeout / 100; + while (*incoming_connection == NULL) { + MICROPY_PY_LWIP_EXIT + if (retries-- == 0) { + m_del_obj(lwip_socket_obj_t, socket2); + mp_raise_OSError(MP_ETIMEDOUT); + } mp_hal_delay_ms(100); - if (*incoming_connection != NULL) break; - } - if (*incoming_connection == NULL) { - mp_raise_OSError(MP_ETIMEDOUT); + MICROPY_PY_LWIP_REENTER } } else { while (*incoming_connection == NULL) { + MICROPY_PY_LWIP_EXIT poll_sockets(); + MICROPY_PY_LWIP_REENTER } } } - // create new socket object - lwip_socket_obj_t *socket2 = m_new_obj_with_finaliser(lwip_socket_obj_t); - socket2->base.type = &lwip_socket_type; - // We get a new pcb handle... socket2->pcb.tcp = *incoming_connection; if (++socket->incoming.connection.iget >= socket->incoming.connection.alloc) { @@ -916,6 +932,8 @@ STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) { tcp_accepted(listener); + MICROPY_PY_LWIP_EXIT + // make the return value uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE]; memcpy(ip, &(socket2->pcb.tcp->remote_ip), sizeof(ip)); From 2848a613ac61fce209962354c2698ee587a2c26a Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 28 Mar 2019 12:49:58 +1100 Subject: [PATCH 0253/1788] extmod/modlwip: Free any stored incoming bufs/connections on TCP error. --- extmod/modlwip.c | 49 ++++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index d501f4be2a..af19648a6e 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -323,6 +323,30 @@ STATIC struct tcp_pcb *volatile *lwip_socket_incoming_array(lwip_socket_obj_t *s } } +STATIC void lwip_socket_free_incoming(lwip_socket_obj_t *socket) { + bool socket_is_listener = + socket->type == MOD_NETWORK_SOCK_STREAM + && socket->pcb.tcp->state == LISTEN; + + if (!socket_is_listener) { + if (socket->incoming.pbuf != NULL) { + pbuf_free(socket->incoming.pbuf); + socket->incoming.pbuf = NULL; + } + } else { + uint8_t alloc = socket->incoming.connection.alloc; + struct tcp_pcb *volatile *tcp_array = lwip_socket_incoming_array(socket); + for (uint8_t i = 0; i < alloc; ++i) { + // Deregister callback and abort + if (tcp_array[i] != NULL) { + tcp_poll(tcp_array[i], NULL, 0); + tcp_abort(tcp_array[i]); + tcp_array[i] = NULL; + } + } + } +} + /*******************************************************************************/ // Callback functions for the lwIP raw API. @@ -356,6 +380,8 @@ STATIC void _lwip_udp_incoming(void *arg, struct udp_pcb *upcb, struct pbuf *p, STATIC void _lwip_tcp_error(void *arg, err_t err) { lwip_socket_obj_t *socket = (lwip_socket_obj_t*)arg; + // Free any incoming buffers or connections that are stored + lwip_socket_free_incoming(socket); // Pass the error code back via the connection variable. socket->state = err; // If we got here, the lwIP stack either has deallocated or will deallocate the pcb. @@ -1368,8 +1394,6 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ } } else if (request == MP_STREAM_CLOSE) { - bool socket_is_listener = false; - if (socket->pcb.tcp == NULL) { MICROPY_PY_LWIP_EXIT return 0; @@ -1380,9 +1404,6 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ 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); @@ -1392,25 +1413,9 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ case MOD_NETWORK_SOCK_DGRAM: udp_remove(socket->pcb.udp); break; //case MOD_NETWORK_SOCK_RAW: raw_remove(socket->pcb.raw); break; } + lwip_socket_free_incoming(socket); socket->pcb.tcp = NULL; socket->state = _ERR_BADF; - if (!socket_is_listener) { - if (socket->incoming.pbuf != NULL) { - pbuf_free(socket->incoming.pbuf); - socket->incoming.pbuf = NULL; - } - } else { - uint8_t alloc = socket->incoming.connection.alloc; - struct tcp_pcb *volatile *tcp_array = lwip_socket_incoming_array(socket); - for (uint8_t i = 0; i < alloc; ++i) { - // Deregister callback and abort - if (tcp_array[i] != NULL) { - tcp_poll(tcp_array[i], NULL, 0); - tcp_abort(tcp_array[i]); - tcp_array[i] = NULL; - } - } - } ret = 0; } else { From 7b5bf5f6fda0cfec6894c0512a3168039575405e Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 29 Mar 2019 12:56:24 +1100 Subject: [PATCH 0254/1788] stm32/uart: Handle correctly the char overrun case of RXNE=0 and ORE=1. Fixes issue #3375. --- ports/stm32/uart.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c index e514709b72..4156551038 100644 --- a/ports/stm32/uart.c +++ b/ports/stm32/uart.c @@ -745,6 +745,16 @@ void uart_irq_handler(mp_uint_t uart_id) { } } } + // If RXNE is clear but ORE set then clear the ORE flag (it's tied to RXNE IRQ) + #if defined(STM32F4) + else if (self->uartx->SR & USART_SR_ORE) { + (void)self->uartx->DR; + } + #else + else if (self->uartx->ISR & USART_ISR_ORE) { + self->uartx->ICR = USART_ICR_ORECF; + } + #endif // Set user IRQ flags self->mp_irq_flags = 0; From 9670b2652649c674e580e039a4fe8e8e885b44fc Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 1 Apr 2019 15:21:26 +1100 Subject: [PATCH 0255/1788] stm32: Rename MICROPY_HW_HAS_SDCARD to MICROPY_HW_ENABLE_SDCARD. For consistency with the majority of other MICROPY_HW_ENABLE_xxx macros. --- ports/stm32/boards/HYDRABUS/mpconfigboard.h | 2 +- ports/stm32/boards/NETDUINO_PLUS_2/board_init.c | 2 +- ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h | 2 +- ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h | 2 +- ports/stm32/boards/OLIMEX_E407/mpconfigboard.h | 2 +- ports/stm32/boards/PYBLITEV10/mpconfigboard.h | 2 +- ports/stm32/boards/PYBV10/mpconfigboard.h | 2 +- ports/stm32/boards/PYBV11/mpconfigboard.h | 2 +- ports/stm32/boards/PYBV3/mpconfigboard.h | 2 +- ports/stm32/boards/PYBV4/mpconfigboard.h | 2 +- ports/stm32/boards/STM32F439/mpconfigboard.h | 4 ++-- ports/stm32/boards/STM32F769DISC/mpconfigboard.h | 2 +- ports/stm32/boards/STM32F7DISC/mpconfigboard.h | 2 +- ports/stm32/dma.c | 12 ++++++------ ports/stm32/main.c | 2 +- ports/stm32/modpyb.c | 2 +- ports/stm32/mpconfigboard_common.h | 6 +++--- ports/stm32/sdcard.c | 4 ++-- ports/stm32/usb.c | 4 ++-- ports/stm32/usbd_msc_storage.c | 6 +++--- 20 files changed, 32 insertions(+), 32 deletions(-) diff --git a/ports/stm32/boards/HYDRABUS/mpconfigboard.h b/ports/stm32/boards/HYDRABUS/mpconfigboard.h index 2e73d3ec88..d8f1a864b2 100644 --- a/ports/stm32/boards/HYDRABUS/mpconfigboard.h +++ b/ports/stm32/boards/HYDRABUS/mpconfigboard.h @@ -3,10 +3,10 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (1) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_ENABLE_SDCARD (1) // HSE is 8MHz #define MICROPY_HW_CLK_PLLM (8) diff --git a/ports/stm32/boards/NETDUINO_PLUS_2/board_init.c b/ports/stm32/boards/NETDUINO_PLUS_2/board_init.c index 53df72503b..176e085943 100644 --- a/ports/stm32/boards/NETDUINO_PLUS_2/board_init.c +++ b/ports/stm32/boards/NETDUINO_PLUS_2/board_init.c @@ -10,7 +10,7 @@ void NETDUINO_PLUS_2_board_early_init(void) { GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStructure.Pull = GPIO_PULLUP; -#if MICROPY_HW_HAS_SDCARD +#if MICROPY_HW_ENABLE_SDCARD // Turn on the power enable for the sdcard (PB1) GPIO_InitStructure.Pin = GPIO_PIN_1; HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); diff --git a/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h b/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h index 3125767562..d2075b52bf 100644 --- a/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h +++ b/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h @@ -7,7 +7,7 @@ // On the netuino, the sdcard appears to be wired up as a 1-bit // 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_ENABLE_SDCARD (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_USB (1) #define MICROPY_HW_ENABLE_SERVO (1) diff --git a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h index 05645633f8..68dece24ff 100644 --- a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h @@ -6,9 +6,9 @@ #define MICROPY_HW_ENABLE_ADC (1) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_ENABLE_SDCARD (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); diff --git a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h index a56f6f79df..d5cd7bb1ec 100644 --- a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h +++ b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h @@ -3,11 +3,11 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (1) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_ENABLE_SDCARD (1) // HSE is 12MHz #define MICROPY_HW_CLK_PLLM (12) diff --git a/ports/stm32/boards/PYBLITEV10/mpconfigboard.h b/ports/stm32/boards/PYBLITEV10/mpconfigboard.h index 60a6980aaf..77509a6003 100644 --- a/ports/stm32/boards/PYBLITEV10/mpconfigboard.h +++ b/ports/stm32/boards/PYBLITEV10/mpconfigboard.h @@ -3,12 +3,12 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (1) #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) +#define MICROPY_HW_ENABLE_SDCARD (1) // 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 81282e799e..dda98776cd 100644 --- a/ports/stm32/boards/PYBV10/mpconfigboard.h +++ b/ports/stm32/boards/PYBV10/mpconfigboard.h @@ -3,7 +3,6 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (1) #define MICROPY_HW_HAS_MMA7660 (1) #define MICROPY_HW_HAS_LCD (1) #define MICROPY_HW_ENABLE_RNG (1) @@ -11,6 +10,7 @@ #define MICROPY_HW_ENABLE_SERVO (1) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_ENABLE_SDCARD (1) // HSE is 8MHz #define MICROPY_HW_CLK_PLLM (8) diff --git a/ports/stm32/boards/PYBV11/mpconfigboard.h b/ports/stm32/boards/PYBV11/mpconfigboard.h index 3cce2302e6..7d10c13e8f 100644 --- a/ports/stm32/boards/PYBV11/mpconfigboard.h +++ b/ports/stm32/boards/PYBV11/mpconfigboard.h @@ -3,7 +3,6 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (1) #define MICROPY_HW_HAS_MMA7660 (1) #define MICROPY_HW_HAS_LCD (1) #define MICROPY_HW_ENABLE_RNG (1) @@ -11,6 +10,7 @@ #define MICROPY_HW_ENABLE_SERVO (1) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_ENABLE_SDCARD (1) // HSE is 12MHz #define MICROPY_HW_CLK_PLLM (12) diff --git a/ports/stm32/boards/PYBV3/mpconfigboard.h b/ports/stm32/boards/PYBV3/mpconfigboard.h index 3e457c5e21..7f1531770f 100644 --- a/ports/stm32/boards/PYBV3/mpconfigboard.h +++ b/ports/stm32/boards/PYBV3/mpconfigboard.h @@ -3,13 +3,13 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (1) #define MICROPY_HW_HAS_MMA7660 (1) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_SERVO (1) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_ENABLE_SDCARD (1) // HSE is 8MHz #define MICROPY_HW_CLK_PLLM (8) diff --git a/ports/stm32/boards/PYBV4/mpconfigboard.h b/ports/stm32/boards/PYBV4/mpconfigboard.h index 8c05644f6d..c1c6075113 100644 --- a/ports/stm32/boards/PYBV4/mpconfigboard.h +++ b/ports/stm32/boards/PYBV4/mpconfigboard.h @@ -3,7 +3,6 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (1) #define MICROPY_HW_HAS_MMA7660 (1) #define MICROPY_HW_HAS_LCD (1) #define MICROPY_HW_ENABLE_RNG (1) @@ -11,6 +10,7 @@ #define MICROPY_HW_ENABLE_SERVO (1) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_ENABLE_SDCARD (1) // HSE is 8MHz #define MICROPY_HW_CLK_PLLM (8) diff --git a/ports/stm32/boards/STM32F439/mpconfigboard.h b/ports/stm32/boards/STM32F439/mpconfigboard.h index 4ac5b32138..a4e1093445 100644 --- a/ports/stm32/boards/STM32F439/mpconfigboard.h +++ b/ports/stm32/boards/STM32F439/mpconfigboard.h @@ -2,14 +2,14 @@ #define MICROPY_HW_MCU_NAME "STM32F439" #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (1) //works with no SD card too #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_ENABLE_SDCARD (1) // works with no SD card too // SD card detect switch -#if MICROPY_HW_HAS_SDCARD +#if MICROPY_HW_ENABLE_SDCARD #define MICROPY_HW_SDCARD_DETECT_PIN (pin_A8) #define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP) #define MICROPY_HW_SDCARD_DETECT_PRESENT (1) diff --git a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h index 58cf707892..9a700d8e42 100644 --- a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h @@ -7,10 +7,10 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (1) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_ENABLE_SDCARD (1) #define MICROPY_BOARD_EARLY_INIT board_early_init void board_early_init(void); diff --git a/ports/stm32/boards/STM32F7DISC/mpconfigboard.h b/ports/stm32/boards/STM32F7DISC/mpconfigboard.h index 609d908bba..b07f0a7b8f 100644 --- a/ports/stm32/boards/STM32F7DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F7DISC/mpconfigboard.h @@ -3,10 +3,10 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (1) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_ENABLE_SDCARD (1) #define MICROPY_BOARD_EARLY_INIT STM32F7DISC_board_early_init void STM32F7DISC_board_early_init(void); diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c index b17c46068e..7262a696e4 100644 --- a/ports/stm32/dma.c +++ b/ports/stm32/dma.c @@ -100,7 +100,7 @@ static const DMA_InitTypeDef dma_init_struct_spi_i2c = { #endif }; -#if defined(MICROPY_HW_HAS_SDCARD) && MICROPY_HW_HAS_SDCARD && !defined(STM32H7) +#if MICROPY_HW_ENABLE_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) @@ -256,7 +256,7 @@ const dma_descr_t dma_I2C_1_TX = { DMA1_Stream6, DMA_CHANNEL_1, dma_id_6, &dma */ // DMA2 streams -#if defined(STM32F7) && defined(SDMMC2) && MICROPY_HW_HAS_SDCARD +#if defined(STM32F7) && defined(SDMMC2) && MICROPY_HW_ENABLE_SDCARD const dma_descr_t dma_SDMMC_2 = { DMA2_Stream0, DMA_CHANNEL_11, dma_id_8, &dma_init_struct_sdio }; #endif #if MICROPY_HW_ENABLE_DCMI @@ -264,7 +264,7 @@ const dma_descr_t dma_DCMI_0 = { DMA2_Stream1, DMA_CHANNEL_1, dma_id_9, &dma_in #endif const dma_descr_t dma_SPI_1_RX = { DMA2_Stream2, DMA_CHANNEL_3, dma_id_10, &dma_init_struct_spi_i2c }; const dma_descr_t dma_SPI_5_RX = { DMA2_Stream3, DMA_CHANNEL_2, dma_id_11, &dma_init_struct_spi_i2c }; -#if defined(MICROPY_HW_HAS_SDCARD) && MICROPY_HW_HAS_SDCARD +#if MICROPY_HW_ENABLE_SDCARD const dma_descr_t dma_SDIO_0 = { DMA2_Stream3, DMA_CHANNEL_4, dma_id_11, &dma_init_struct_sdio }; #endif const dma_descr_t dma_SPI_4_RX = { DMA2_Stream3, DMA_CHANNEL_5, dma_id_11, &dma_init_struct_spi_i2c }; @@ -272,11 +272,11 @@ const dma_descr_t dma_SPI_5_TX = { DMA2_Stream4, DMA_CHANNEL_2, dma_id_12, &dma const dma_descr_t dma_SPI_4_TX = { DMA2_Stream4, DMA_CHANNEL_5, dma_id_12, &dma_init_struct_spi_i2c }; const dma_descr_t dma_SPI_6_TX = { DMA2_Stream5, DMA_CHANNEL_1, dma_id_13, &dma_init_struct_spi_i2c }; const dma_descr_t dma_SPI_1_TX = { DMA2_Stream5, DMA_CHANNEL_3, dma_id_13, &dma_init_struct_spi_i2c }; -//#if defined(STM32F7) && defined(SDMMC2) && MICROPY_HW_HAS_SDCARD +//#if defined(STM32F7) && defined(SDMMC2) && MICROPY_HW_ENABLE_SDCARD //const dma_descr_t dma_SDMMC_2 = { DMA2_Stream5, DMA_CHANNEL_11, dma_id_13, &dma_init_struct_sdio }; //#endif const dma_descr_t dma_SPI_6_RX = { DMA2_Stream6, DMA_CHANNEL_1, dma_id_14, &dma_init_struct_spi_i2c }; -//#if defined(MICROPY_HW_HAS_SDCARD) && MICROPY_HW_HAS_SDCARD +//#if MICROPY_HW_ENABLE_SDCARD //const dma_descr_t dma_SDIO_0 = { DMA2_Stream6, DMA_CHANNEL_4, dma_id_14, &dma_init_struct_sdio }; //#endif /* not preferred streams @@ -352,7 +352,7 @@ const dma_descr_t dma_ADC_2_RX = { DMA2_Channel4, DMA_REQUEST_0, dma_id_10, NUL const dma_descr_t dma_DAC_1_TX = { DMA2_Channel4, DMA_REQUEST_3, dma_id_10, &dma_init_struct_dac }; const dma_descr_t dma_SPI_1_TX = { DMA2_Channel4, DMA_REQUEST_4, dma_id_10, &dma_init_struct_spi_i2c }; */ -#if defined(MICROPY_HW_HAS_SDCARD) && MICROPY_HW_HAS_SDCARD +#if MICROPY_HW_ENABLE_SDCARD const dma_descr_t dma_SDIO_0 = { DMA2_Channel4, DMA_REQUEST_7, dma_id_10, &dma_init_struct_sdio }; #endif /* not preferred streams diff --git a/ports/stm32/main.c b/ports/stm32/main.c index c1d27a9680..8c2d7d529a 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -539,7 +539,7 @@ void stm32_main(uint32_t reset_mode) { #if MICROPY_PY_PYB_LEGACY && MICROPY_HW_ENABLE_HW_I2C i2c_init0(); #endif - #if MICROPY_HW_HAS_SDCARD + #if MICROPY_HW_ENABLE_SDCARD sdcard_init(); #endif #if MICROPY_HW_ENABLE_STORAGE diff --git a/ports/stm32/modpyb.c b/ports/stm32/modpyb.c index 60b287fb1c..da7ca487db 100644 --- a/ports/stm32/modpyb.c +++ b/ports/stm32/modpyb.c @@ -194,7 +194,7 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_Flash), MP_ROM_PTR(&pyb_flash_type) }, #endif -#if MICROPY_HW_HAS_SDCARD +#if MICROPY_HW_ENABLE_SDCARD #if MICROPY_PY_PYB_LEGACY { MP_ROM_QSTR(MP_QSTR_SD), MP_ROM_PTR(&pyb_sdcard_obj) }, // now obsolete #endif diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index e208f2238a..c15324726e 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -93,13 +93,13 @@ #endif // Whether to enable the SD card interface, exposed as pyb.SDCard -#ifndef MICROPY_HW_HAS_SDCARD -#define MICROPY_HW_HAS_SDCARD (0) +#ifndef MICROPY_HW_ENABLE_SDCARD +#define MICROPY_HW_ENABLE_SDCARD (0) #endif // Whether to automatically mount (and boot from) the SD card if it's present #ifndef MICROPY_HW_SDCARD_MOUNT_AT_BOOT -#define MICROPY_HW_SDCARD_MOUNT_AT_BOOT (MICROPY_HW_HAS_SDCARD) +#define MICROPY_HW_SDCARD_MOUNT_AT_BOOT (MICROPY_HW_ENABLE_SDCARD) #endif // Whether to enable the MMA7660 driver, exposed as pyb.Accel diff --git a/ports/stm32/sdcard.c b/ports/stm32/sdcard.c index 94bfc5cd86..c284270bd8 100644 --- a/ports/stm32/sdcard.c +++ b/ports/stm32/sdcard.c @@ -38,7 +38,7 @@ #include "dma.h" #include "irq.h" -#if MICROPY_HW_HAS_SDCARD +#if MICROPY_HW_ENABLE_SDCARD #if defined(STM32F7) || defined(STM32H7) || defined(STM32L4) @@ -602,4 +602,4 @@ void sdcard_init_vfs(fs_user_mount_t *vfs, int part) { vfs->u.ioctl[1] = MP_OBJ_FROM_PTR(&pyb_sdcard_obj); } -#endif // MICROPY_HW_HAS_SDCARD +#endif // MICROPY_HW_ENABLE_SDCARD diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index 1db32c9ae4..ce2a828598 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -147,11 +147,11 @@ bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, usb_device_mode_t mode, USBD_H } switch (pyb_usb_storage_medium) { -#if MICROPY_HW_HAS_SDCARD + #if MICROPY_HW_ENABLE_SDCARD case PYB_USB_STORAGE_MEDIUM_SDCARD: USBD_MSC_RegisterStorage(&usb_dev->usbd_cdc_msc_hid_state, (USBD_StorageTypeDef*)&USBD_SDCARD_STORAGE_fops); break; -#endif + #endif default: USBD_MSC_RegisterStorage(&usb_dev->usbd_cdc_msc_hid_state, (USBD_StorageTypeDef*)&USBD_FLASH_STORAGE_fops); break; diff --git a/ports/stm32/usbd_msc_storage.c b/ports/stm32/usbd_msc_storage.c index 7d6c19e9fe..01d15f6e75 100644 --- a/ports/stm32/usbd_msc_storage.c +++ b/ports/stm32/usbd_msc_storage.c @@ -44,7 +44,7 @@ // can be unmounted, and won't be remounted automatically. static uint8_t flash_started = 0; -#if MICROPY_HW_HAS_SDCARD +#if MICROPY_HW_ENABLE_SDCARD static uint8_t sdcard_started = 0; #endif @@ -175,7 +175,7 @@ const USBD_StorageTypeDef USBD_FLASH_STORAGE_fops = { /******************************************************************************/ // Callback functions for when the SD card is the mass storage device -#if MICROPY_HW_HAS_SDCARD +#if MICROPY_HW_ENABLE_SDCARD static const int8_t SDCARD_STORAGE_Inquirydata[] = { // 36 bytes // LUN 0 @@ -303,4 +303,4 @@ const USBD_StorageTypeDef USBD_SDCARD_STORAGE_fops = { (int8_t *)SDCARD_STORAGE_Inquirydata, }; -#endif // MICROPY_HW_HAS_SDCARD +#endif // MICROPY_HW_ENABLE_SDCARD From 7ce2a082311fb8679e0abdc379d9cf9655d66fd1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 1 Apr 2019 15:55:04 +1100 Subject: [PATCH 0256/1788] stm32: Add support for MMC driver, exposed via pyb.MMCard class. Enable it via MICROPY_HW_ENABLE_MMCARD. --- ports/stm32/Makefile | 1 + ports/stm32/dma.c | 14 +- ports/stm32/modpyb.c | 3 + ports/stm32/mpconfigboard_common.h | 5 + ports/stm32/sdcard.c | 416 +++++++++++++++++++++++------ ports/stm32/sdcard.h | 1 + 6 files changed, 358 insertions(+), 82 deletions(-) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 40560b842b..242ced38cb 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -329,6 +329,7 @@ endif ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 h7)) SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ + hal_mmc.c \ hal_sdram.c \ hal_dma_ex.c \ hal_dcmi.c \ diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c index 7262a696e4..3b8b74081c 100644 --- a/ports/stm32/dma.c +++ b/ports/stm32/dma.c @@ -39,6 +39,8 @@ #define DMA_IDLE_TICK_MAX (8) // 8*8 = 64 msec #define DMA_IDLE_TICK(tick) (((tick) & ~(SYSTICK_DISPATCH_NUM_SLOTS - 1) & DMA_SYSTICK_MASK) == 0) +#define ENABLE_SDIO (MICROPY_HW_ENABLE_SDCARD || MICROPY_HW_ENABLE_MMCARD) + typedef enum { dma_id_not_defined=-1, dma_id_0, @@ -100,7 +102,7 @@ static const DMA_InitTypeDef dma_init_struct_spi_i2c = { #endif }; -#if MICROPY_HW_ENABLE_SDCARD && !defined(STM32H7) +#if ENABLE_SDIO && !defined(STM32H7) // Parameters to dma_init() for SDIO tx and rx. static const DMA_InitTypeDef dma_init_struct_sdio = { #if defined(STM32F4) || defined(STM32F7) @@ -256,7 +258,7 @@ const dma_descr_t dma_I2C_1_TX = { DMA1_Stream6, DMA_CHANNEL_1, dma_id_6, &dma */ // DMA2 streams -#if defined(STM32F7) && defined(SDMMC2) && MICROPY_HW_ENABLE_SDCARD +#if defined(STM32F7) && defined(SDMMC2) && ENABLE_SDIO const dma_descr_t dma_SDMMC_2 = { DMA2_Stream0, DMA_CHANNEL_11, dma_id_8, &dma_init_struct_sdio }; #endif #if MICROPY_HW_ENABLE_DCMI @@ -264,7 +266,7 @@ const dma_descr_t dma_DCMI_0 = { DMA2_Stream1, DMA_CHANNEL_1, dma_id_9, &dma_in #endif const dma_descr_t dma_SPI_1_RX = { DMA2_Stream2, DMA_CHANNEL_3, dma_id_10, &dma_init_struct_spi_i2c }; const dma_descr_t dma_SPI_5_RX = { DMA2_Stream3, DMA_CHANNEL_2, dma_id_11, &dma_init_struct_spi_i2c }; -#if MICROPY_HW_ENABLE_SDCARD +#if ENABLE_SDIO const dma_descr_t dma_SDIO_0 = { DMA2_Stream3, DMA_CHANNEL_4, dma_id_11, &dma_init_struct_sdio }; #endif const dma_descr_t dma_SPI_4_RX = { DMA2_Stream3, DMA_CHANNEL_5, dma_id_11, &dma_init_struct_spi_i2c }; @@ -272,11 +274,11 @@ const dma_descr_t dma_SPI_5_TX = { DMA2_Stream4, DMA_CHANNEL_2, dma_id_12, &dma const dma_descr_t dma_SPI_4_TX = { DMA2_Stream4, DMA_CHANNEL_5, dma_id_12, &dma_init_struct_spi_i2c }; const dma_descr_t dma_SPI_6_TX = { DMA2_Stream5, DMA_CHANNEL_1, dma_id_13, &dma_init_struct_spi_i2c }; const dma_descr_t dma_SPI_1_TX = { DMA2_Stream5, DMA_CHANNEL_3, dma_id_13, &dma_init_struct_spi_i2c }; -//#if defined(STM32F7) && defined(SDMMC2) && MICROPY_HW_ENABLE_SDCARD +//#if defined(STM32F7) && defined(SDMMC2) && ENABLE_SDIO //const dma_descr_t dma_SDMMC_2 = { DMA2_Stream5, DMA_CHANNEL_11, dma_id_13, &dma_init_struct_sdio }; //#endif const dma_descr_t dma_SPI_6_RX = { DMA2_Stream6, DMA_CHANNEL_1, dma_id_14, &dma_init_struct_spi_i2c }; -//#if MICROPY_HW_ENABLE_SDCARD +//#if ENABLE_SDIO //const dma_descr_t dma_SDIO_0 = { DMA2_Stream6, DMA_CHANNEL_4, dma_id_14, &dma_init_struct_sdio }; //#endif /* not preferred streams @@ -352,7 +354,7 @@ const dma_descr_t dma_ADC_2_RX = { DMA2_Channel4, DMA_REQUEST_0, dma_id_10, NUL const dma_descr_t dma_DAC_1_TX = { DMA2_Channel4, DMA_REQUEST_3, dma_id_10, &dma_init_struct_dac }; const dma_descr_t dma_SPI_1_TX = { DMA2_Channel4, DMA_REQUEST_4, dma_id_10, &dma_init_struct_spi_i2c }; */ -#if MICROPY_HW_ENABLE_SDCARD +#if ENABLE_SDIO const dma_descr_t dma_SDIO_0 = { DMA2_Channel4, DMA_REQUEST_7, dma_id_10, &dma_init_struct_sdio }; #endif /* not preferred streams diff --git a/ports/stm32/modpyb.c b/ports/stm32/modpyb.c index da7ca487db..85c6ee1381 100644 --- a/ports/stm32/modpyb.c +++ b/ports/stm32/modpyb.c @@ -200,6 +200,9 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { #endif { MP_ROM_QSTR(MP_QSTR_SDCard), MP_ROM_PTR(&pyb_sdcard_type) }, #endif + #if MICROPY_HW_ENABLE_MMCARD + { MP_ROM_QSTR(MP_QSTR_MMCard), MP_ROM_PTR(&pyb_mmcard_type) }, + #endif #if defined(MICROPY_HW_LED1) { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pyb_led_type) }, diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index c15324726e..1ace8fcaf4 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -97,6 +97,11 @@ #define MICROPY_HW_ENABLE_SDCARD (0) #endif +// Whether to enable the MMC interface, exposed as pyb.MMCard +#ifndef MICROPY_HW_ENABLE_MMCARD +#define MICROPY_HW_ENABLE_MMCARD (0) +#endif + // Whether to automatically mount (and boot from) the SD card if it's present #ifndef MICROPY_HW_SDCARD_MOUNT_AT_BOOT #define MICROPY_HW_SDCARD_MOUNT_AT_BOOT (MICROPY_HW_ENABLE_SDCARD) diff --git a/ports/stm32/sdcard.c b/ports/stm32/sdcard.c index c284270bd8..16e6506156 100644 --- a/ports/stm32/sdcard.c +++ b/ports/stm32/sdcard.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2013-2019 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 @@ -38,7 +38,7 @@ #include "dma.h" #include "irq.h" -#if MICROPY_HW_ENABLE_SDCARD +#if MICROPY_HW_ENABLE_SDCARD || MICROPY_HW_ENABLE_MMCARD #if defined(STM32F7) || defined(STM32H7) || defined(STM32L4) @@ -125,14 +125,25 @@ #endif +#define PYB_SDMMC_FLAG_SD (0x01) +#define PYB_SDMMC_FLAG_MMC (0x02) +#define PYB_SDMMC_FLAG_ACTIVE (0x04) + +static uint8_t pyb_sdmmc_flags; + // TODO: I think that as an optimization, we can allocate these dynamically // 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; +static union { + SD_HandleTypeDef sd; + #if MICROPY_HW_ENABLE_MMCARD + MMC_HandleTypeDef mmc; + #endif +} sdmmc_handle; void sdcard_init(void) { - // invalidate the sd_handle - sd_handle.Instance = NULL; + // Set SD/MMC to no mode and inactive + pyb_sdmmc_flags = 0; // configure SD GPIO // we do this here an not in HAL_SD_MspInit because it apparently @@ -163,7 +174,7 @@ void sdcard_init(void) { 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) { +STATIC void sdmmc_msp_init(void) { // enable SDIO clock SDMMC_CLK_ENABLE(); @@ -185,76 +196,192 @@ void HAL_SD_MspInit(SD_HandleTypeDef *hsd) { // GPIO have already been initialised by sdcard_init } -void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) { +void sdmmc_msp_deinit(void) { HAL_NVIC_DisableIRQ(SDMMC_IRQn); SDMMC_CLK_DISABLE(); } +#if MICROPY_HW_ENABLE_SDCARD +void HAL_SD_MspInit(SD_HandleTypeDef *hsd) { + sdmmc_msp_init(); +} + +void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) { + sdmmc_msp_deinit(); +} +#endif + +#if MICROPY_HW_ENABLE_MMCARD +void HAL_MMC_MspInit(MMC_HandleTypeDef *hsd) { + sdmmc_msp_init(); +} + +void HAL_MMC_MspDeInit(MMC_HandleTypeDef *hsd) { + sdmmc_msp_deinit(); +} +#endif + bool sdcard_is_present(void) { + #if MICROPY_HW_ENABLE_MMCARD + if (pyb_sdmmc_flags & PYB_SDMMC_FLAG_MMC) { + return false; + } + #endif 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) { - if (!sdcard_is_present()) { - return false; - } - if (sd_handle.Instance) { - return true; - } - +#if MICROPY_HW_ENABLE_SDCARD +STATIC HAL_StatusTypeDef sdmmc_init_sd(void) { // SD device interface configuration - sd_handle.Instance = SDIO; - sd_handle.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING; + sdmmc_handle.sd.Instance = SDIO; + sdmmc_handle.sd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING; #ifndef STM32H7 - sd_handle.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE; + sdmmc_handle.sd.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; - sd_handle.Init.ClockDiv = SDIO_TRANSFER_CLK_DIV; + sdmmc_handle.sd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_ENABLE; + sdmmc_handle.sd.Init.BusWide = SDIO_BUS_WIDE_1B; + sdmmc_handle.sd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE; + sdmmc_handle.sd.Init.ClockDiv = SDIO_TRANSFER_CLK_DIV; // init the SD interface, with retry if it's not ready yet - for (int retry = 10; HAL_SD_Init(&sd_handle) != HAL_OK; retry--) { + HAL_StatusTypeDef status; + for (int retry = 10; (status = HAL_SD_Init(&sdmmc_handle.sd)) != HAL_OK; retry--) { if (retry == 0) { - goto error; + return status; } mp_hal_delay_ms(50); } // configure the SD bus width for wide operation - if (HAL_SD_ConfigWideBusOperation(&sd_handle, SDIO_BUS_WIDE_4B) != HAL_OK) { - HAL_SD_DeInit(&sd_handle); - goto error; + status = HAL_SD_ConfigWideBusOperation(&sdmmc_handle.sd, SDIO_BUS_WIDE_4B); + if (status != HAL_OK) { + HAL_SD_DeInit(&sdmmc_handle.sd); + return status; } - return true; + return HAL_OK; +} +#endif -error: - sd_handle.Instance = NULL; - return false; +#if MICROPY_HW_ENABLE_MMCARD +STATIC HAL_StatusTypeDef sdmmc_init_mmc(void) { + // MMC device interface configuration + sdmmc_handle.mmc.Instance = SDIO; + sdmmc_handle.mmc.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING; + #ifndef STM32H7 + sdmmc_handle.mmc.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE; + #endif + sdmmc_handle.mmc.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_ENABLE; + sdmmc_handle.mmc.Init.BusWide = SDIO_BUS_WIDE_1B; + sdmmc_handle.mmc.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE; + sdmmc_handle.mmc.Init.ClockDiv = SDIO_TRANSFER_CLK_DIV; + + // Init the SDIO interface + HAL_StatusTypeDef status = HAL_MMC_Init(&sdmmc_handle.mmc); + if (status != HAL_OK) { + return status; + } + + // As this is an eMMC card, overwrite LogBlockNbr with actual value + sdmmc_handle.mmc.MmcCard.LogBlockNbr = 7469056 + 2048; + + // Configure the SDIO bus width for wide operation + #ifdef STM32F7 + sdmmc_handle.mmc.Init.ClockBypass = SDIO_CLOCK_BYPASS_ENABLE; + #endif + status = HAL_MMC_ConfigWideBusOperation(&sdmmc_handle.mmc, SDIO_BUS_WIDE_4B); + if (status != HAL_OK) { + HAL_MMC_DeInit(&sdmmc_handle.mmc); + return status; + } + + return HAL_OK; +} +#endif + +bool sdcard_power_on(void) { + if (pyb_sdmmc_flags & PYB_SDMMC_FLAG_ACTIVE) { + return true; + } + + HAL_StatusTypeDef status = HAL_ERROR; + switch (pyb_sdmmc_flags) { + #if MICROPY_HW_ENABLE_SDCARD + case PYB_SDMMC_FLAG_SD: + if (sdcard_is_present()) { + status = sdmmc_init_sd(); + } + break; + #endif + #if MICROPY_HW_ENABLE_MMCARD + case PYB_SDMMC_FLAG_MMC: + status = sdmmc_init_mmc(); + break; + #endif + } + + if (status == HAL_OK) { + pyb_sdmmc_flags |= PYB_SDMMC_FLAG_ACTIVE; + return true; + } else { + return false; + } } void sdcard_power_off(void) { - if (!sd_handle.Instance) { - return; + switch (pyb_sdmmc_flags) { + #if MICROPY_HW_ENABLE_SDCARD + case PYB_SDMMC_FLAG_ACTIVE | PYB_SDMMC_FLAG_SD: + HAL_SD_DeInit(&sdmmc_handle.sd); + break; + #endif + #if MICROPY_HW_ENABLE_MMCARD + case PYB_SDMMC_FLAG_ACTIVE | PYB_SDMMC_FLAG_MMC: + HAL_MMC_DeInit(&sdmmc_handle.mmc); + break; + #endif } - HAL_SD_DeInit(&sd_handle); - sd_handle.Instance = NULL; + pyb_sdmmc_flags &= ~PYB_SDMMC_FLAG_ACTIVE; } uint64_t sdcard_get_capacity_in_bytes(void) { - if (sd_handle.Instance == NULL) { - return 0; + switch (pyb_sdmmc_flags) { + #if MICROPY_HW_ENABLE_SDCARD + case PYB_SDMMC_FLAG_ACTIVE | PYB_SDMMC_FLAG_SD: { + HAL_SD_CardInfoTypeDef cardinfo; + HAL_SD_GetCardInfo(&sdmmc_handle.sd, &cardinfo); + return (uint64_t)cardinfo.LogBlockNbr * (uint64_t)cardinfo.LogBlockSize; + } + #endif + #if MICROPY_HW_ENABLE_MMCARD + case PYB_SDMMC_FLAG_ACTIVE | PYB_SDMMC_FLAG_MMC: { + HAL_MMC_CardInfoTypeDef cardinfo; + HAL_MMC_GetCardInfo(&sdmmc_handle.mmc, &cardinfo); + return (uint64_t)cardinfo.LogBlockNbr * (uint64_t)cardinfo.LogBlockSize; + } + #endif + default: + return 0; + } +} + +STATIC void sdmmc_irq_handler(void) { + switch (pyb_sdmmc_flags) { + #if MICROPY_HW_ENABLE_SDCARD + case PYB_SDMMC_FLAG_ACTIVE | PYB_SDMMC_FLAG_SD: + HAL_SD_IRQHandler(&sdmmc_handle.sd); + #endif + #if MICROPY_HW_ENABLE_MMCARD + case PYB_SDMMC_FLAG_ACTIVE | PYB_SDMMC_FLAG_MMC: + HAL_MMC_IRQHandler(&sdmmc_handle.mmc); + #endif } - HAL_SD_CardInfoTypeDef cardinfo; - HAL_SD_GetCardInfo(&sd_handle, &cardinfo); - 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); + sdmmc_irq_handler(); IRQ_EXIT(SDIO_IRQn); } #endif @@ -262,7 +389,7 @@ void SDIO_IRQHandler(void) { #if defined(STM32F7) void SDMMC2_IRQHandler(void) { IRQ_ENTER(SDMMC2_IRQn); - HAL_SD_IRQHandler(&sd_handle); + sdmmc_irq_handler(); IRQ_EXIT(SDMMC2_IRQn); } #endif @@ -271,21 +398,31 @@ STATIC void sdcard_reset_periph(void) { // Fully reset the SDMMC peripheral before calling HAL SD DMA functions. // (There could be an outstanding DTIMEOUT event from a previous call and the // HAL function enables IRQs before fully configuring the SDMMC peripheral.) - sd_handle.Instance->DTIMER = 0; - sd_handle.Instance->DLEN = 0; - sd_handle.Instance->DCTRL = 0; - sd_handle.Instance->ICR = SDMMC_STATIC_FLAGS; + SDIO->DTIMER = 0; + SDIO->DLEN = 0; + SDIO->DCTRL = 0; + SDIO->ICR = SDMMC_STATIC_FLAGS; } -STATIC HAL_StatusTypeDef sdcard_wait_finished(SD_HandleTypeDef *sd, uint32_t timeout) { +STATIC HAL_StatusTypeDef sdcard_wait_finished(uint32_t timeout) { // Wait for HAL driver to be ready (eg for DMA to finish) uint32_t start = HAL_GetTick(); 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; + #if MICROPY_HW_ENABLE_MMCARD + if (pyb_sdmmc_flags & PYB_SDMMC_FLAG_MMC) { + if (sdmmc_handle.mmc.State != HAL_MMC_STATE_BUSY) { + enable_irq(irq_state); + break; + } + } else + #endif + { + if (sdmmc_handle.sd.State != HAL_SD_STATE_BUSY) { + enable_irq(irq_state); + break; + } } __WFI(); enable_irq(irq_state); @@ -296,7 +433,20 @@ 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); + uint32_t state; + #if MICROPY_HW_ENABLE_MMCARD + MP_STATIC_ASSERT((uint32_t)HAL_SD_CARD_TRANSFER == (uint32_t)HAL_MMC_CARD_TRANSFER); + MP_STATIC_ASSERT((uint32_t)HAL_SD_CARD_SENDING == (uint32_t)HAL_MMC_CARD_SENDING); + MP_STATIC_ASSERT((uint32_t)HAL_SD_CARD_RECEIVING == (uint32_t)HAL_MMC_CARD_RECEIVING); + MP_STATIC_ASSERT((uint32_t)HAL_SD_CARD_PROGRAMMING == (uint32_t)HAL_MMC_CARD_PROGRAMMING); + if (pyb_sdmmc_flags & PYB_SDMMC_FLAG_MMC) { + state = HAL_MMC_GetCardState(&sdmmc_handle.mmc); + } else + #endif + { + state = HAL_SD_GetCardState(&sdmmc_handle.sd); + } + if (state == HAL_SD_CARD_TRANSFER) { return HAL_OK; } @@ -313,7 +463,7 @@ STATIC HAL_StatusTypeDef sdcard_wait_finished(SD_HandleTypeDef *sd, uint32_t tim mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) { // check that SD card is initialised - if (sd_handle.Instance == NULL) { + if (!(pyb_sdmmc_flags & PYB_SDMMC_FLAG_ACTIVE)) { return HAL_ERROR; } @@ -343,8 +493,15 @@ mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blo #if SDIO_USE_GPDMA DMA_HandleTypeDef sd_dma; - dma_init(&sd_dma, &SDMMC_DMA, DMA_PERIPH_TO_MEMORY, &sd_handle); - sd_handle.hdmarx = &sd_dma; + dma_init(&sd_dma, &SDMMC_DMA, DMA_PERIPH_TO_MEMORY, &sdmmc_handle); + #if MICROPY_HW_ENABLE_MMCARD + if (pyb_sdmmc_flags & PYB_SDMMC_FLAG_MMC) { + sdmmc_handle.mmc.hdmarx = &sd_dma; + } else + #endif + { + sdmmc_handle.sd.hdmarx = &sd_dma; + } #endif // make sure cache is flushed and invalidated so when DMA updates the RAM @@ -352,21 +509,42 @@ mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blo MP_HAL_CLEANINVALIDATE_DCACHE(dest, num_blocks * SDCARD_BLOCK_SIZE); sdcard_reset_periph(); - err = HAL_SD_ReadBlocks_DMA(&sd_handle, dest, block_num, num_blocks); + #if MICROPY_HW_ENABLE_MMCARD + if (pyb_sdmmc_flags & PYB_SDMMC_FLAG_MMC) { + err = HAL_MMC_ReadBlocks_DMA(&sdmmc_handle.mmc, dest, block_num, num_blocks); + } else + #endif + { + err = HAL_SD_ReadBlocks_DMA(&sdmmc_handle.sd, dest, block_num, num_blocks); + } if (err == HAL_OK) { - err = sdcard_wait_finished(&sd_handle, 60000); + err = sdcard_wait_finished(60000); } #if SDIO_USE_GPDMA dma_deinit(&SDMMC_DMA); - sd_handle.hdmarx = NULL; + #if MICROPY_HW_ENABLE_MMCARD + if (pyb_sdmmc_flags & PYB_SDMMC_FLAG_MMC) { + sdmmc_handle.mmc.hdmarx = NULL; + } else + #endif + { + sdmmc_handle.sd.hdmarx = NULL; + } #endif restore_irq_pri(basepri); } else { - err = HAL_SD_ReadBlocks(&sd_handle, dest, block_num, num_blocks, 60000); + #if MICROPY_HW_ENABLE_MMCARD + if (pyb_sdmmc_flags & PYB_SDMMC_FLAG_MMC) { + err = HAL_MMC_ReadBlocks(&sdmmc_handle.mmc, dest, block_num, num_blocks, 60000); + } else + #endif + { + err = HAL_SD_ReadBlocks(&sdmmc_handle.sd, dest, block_num, num_blocks, 60000); + } if (err == HAL_OK) { - err = sdcard_wait_finished(&sd_handle, 60000); + err = sdcard_wait_finished(60000); } } @@ -381,7 +559,7 @@ mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blo mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) { // check that SD card is initialised - if (sd_handle.Instance == NULL) { + if (!(pyb_sdmmc_flags & PYB_SDMMC_FLAG_ACTIVE)) { return HAL_ERROR; } @@ -411,29 +589,57 @@ mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t n #if SDIO_USE_GPDMA DMA_HandleTypeDef sd_dma; - dma_init(&sd_dma, &SDMMC_DMA, DMA_MEMORY_TO_PERIPH, &sd_handle); - sd_handle.hdmatx = &sd_dma; + dma_init(&sd_dma, &SDMMC_DMA, DMA_MEMORY_TO_PERIPH, &sdmmc_handle); + #if MICROPY_HW_ENABLE_MMCARD + if (pyb_sdmmc_flags & PYB_SDMMC_FLAG_MMC) { + sdmmc_handle.mmc.hdmatx = &sd_dma; + } else + #endif + { + sdmmc_handle.sd.hdmatx = &sd_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); sdcard_reset_periph(); - err = HAL_SD_WriteBlocks_DMA(&sd_handle, (uint8_t*)src, block_num, num_blocks); + #if MICROPY_HW_ENABLE_MMCARD + if (pyb_sdmmc_flags & PYB_SDMMC_FLAG_MMC) { + err = HAL_MMC_WriteBlocks_DMA(&sdmmc_handle.mmc, (uint8_t*)src, block_num, num_blocks); + } else + #endif + { + err = HAL_SD_WriteBlocks_DMA(&sdmmc_handle.sd, (uint8_t*)src, block_num, num_blocks); + } if (err == HAL_OK) { - err = sdcard_wait_finished(&sd_handle, 60000); + err = sdcard_wait_finished(60000); } #if SDIO_USE_GPDMA dma_deinit(&SDMMC_DMA); - sd_handle.hdmatx = NULL; + #if MICROPY_HW_ENABLE_MMCARD + if (pyb_sdmmc_flags & PYB_SDMMC_FLAG_MMC) { + sdmmc_handle.mmc.hdmatx = NULL; + } else + #endif + { + sdmmc_handle.sd.hdmatx = NULL; + } #endif restore_irq_pri(basepri); } else { - err = HAL_SD_WriteBlocks(&sd_handle, (uint8_t*)src, block_num, num_blocks, 60000); + #if MICROPY_HW_ENABLE_MMCARD + if (pyb_sdmmc_flags & PYB_SDMMC_FLAG_MMC) { + err = HAL_MMC_WriteBlocks(&sdmmc_handle.mmc, (uint8_t*)src, block_num, num_blocks, 60000); + } else + #endif + { + err = HAL_SD_WriteBlocks(&sdmmc_handle.sd, (uint8_t*)src, block_num, num_blocks, 60000); + } if (err == HAL_OK) { - err = sdcard_wait_finished(&sd_handle, 60000); + err = sdcard_wait_finished(60000); } } @@ -443,18 +649,51 @@ mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t n /******************************************************************************/ // MicroPython bindings // -// Expose the SD card as an object with the block protocol. +// Expose the SD card or MMC as an object with the block protocol. -// there is a singleton SDCard object +// There are singleton SDCard/MMCard objects +#if MICROPY_HW_ENABLE_SDCARD const mp_obj_base_t pyb_sdcard_obj = {&pyb_sdcard_type}; +#endif +#if MICROPY_HW_ENABLE_MMCARD +const mp_obj_base_t pyb_mmcard_obj = {&pyb_mmcard_type}; +#endif +#if MICROPY_HW_ENABLE_SDCARD STATIC mp_obj_t pyb_sdcard_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); + #if MICROPY_HW_ENABLE_MMCARD + if (pyb_sdmmc_flags & PYB_SDMMC_FLAG_MMC) { + mp_raise_ValueError("peripheral used by MMCard"); + } + #endif + + pyb_sdmmc_flags |= PYB_SDMMC_FLAG_SD; + // return singleton object return MP_OBJ_FROM_PTR(&pyb_sdcard_obj); } +#endif + +#if MICROPY_HW_ENABLE_MMCARD +STATIC mp_obj_t pyb_mmcard_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); + + #if MICROPY_HW_ENABLE_SDCARD + if (pyb_sdmmc_flags & PYB_SDMMC_FLAG_SD) { + mp_raise_ValueError("peripheral used by SDCard"); + } + #endif + + pyb_sdmmc_flags |= PYB_SDMMC_FLAG_MMC; + + // return singleton object + return MP_OBJ_FROM_PTR(&pyb_mmcard_obj); +} +#endif STATIC mp_obj_t sd_present(mp_obj_t self) { return mp_obj_new_bool(sdcard_is_present()); @@ -474,16 +713,29 @@ STATIC mp_obj_t sd_power(mp_obj_t self, mp_obj_t state) { STATIC MP_DEFINE_CONST_FUN_OBJ_2(sd_power_obj, sd_power); STATIC mp_obj_t sd_info(mp_obj_t self) { - if (sd_handle.Instance == NULL) { + if (!(pyb_sdmmc_flags & PYB_SDMMC_FLAG_ACTIVE)) { return mp_const_none; } - HAL_SD_CardInfoTypeDef cardinfo; - HAL_SD_GetCardInfo(&sd_handle, &cardinfo); + uint32_t card_type; + uint32_t log_block_nbr; + uint32_t log_block_size; + #if MICROPY_HW_ENABLE_MMCARD + if (pyb_sdmmc_flags & PYB_SDMMC_FLAG_MMC) { + card_type = sdmmc_handle.mmc.MmcCard.CardType; + log_block_nbr = sdmmc_handle.mmc.MmcCard.LogBlockNbr; + log_block_size = sdmmc_handle.mmc.MmcCard.LogBlockSize; + } else + #endif + { + card_type = sdmmc_handle.sd.SdCard.CardType; + log_block_nbr = sdmmc_handle.sd.SdCard.LogBlockNbr; + log_block_size = sdmmc_handle.sd.SdCard.LogBlockSize; + } // cardinfo.SD_csd and cardinfo.SD_cid have lots of info but we don't use them mp_obj_t tuple[3] = { - mp_obj_new_int_from_ull((uint64_t)cardinfo.LogBlockNbr * (uint64_t)cardinfo.LogBlockSize), - mp_obj_new_int_from_uint(cardinfo.LogBlockSize), - mp_obj_new_int(cardinfo.CardType), + mp_obj_new_int_from_ull((uint64_t)log_block_nbr * (uint64_t)log_block_size), + mp_obj_new_int_from_uint(log_block_size), + mp_obj_new_int(card_type), }; return mp_obj_new_tuple(3, tuple); } @@ -580,14 +832,26 @@ STATIC const mp_rom_map_elem_t pyb_sdcard_locals_dict_table[] = { STATIC MP_DEFINE_CONST_DICT(pyb_sdcard_locals_dict, pyb_sdcard_locals_dict_table); +#if MICROPY_HW_ENABLE_SDCARD const mp_obj_type_t pyb_sdcard_type = { { &mp_type_type }, .name = MP_QSTR_SDCard, .make_new = pyb_sdcard_make_new, .locals_dict = (mp_obj_dict_t*)&pyb_sdcard_locals_dict, }; +#endif + +#if MICROPY_HW_ENABLE_MMCARD +const mp_obj_type_t pyb_mmcard_type = { + { &mp_type_type }, + .name = MP_QSTR_MMCard, + .make_new = pyb_mmcard_make_new, + .locals_dict = (mp_obj_dict_t*)&pyb_sdcard_locals_dict, +}; +#endif void sdcard_init_vfs(fs_user_mount_t *vfs, int part) { + pyb_sdmmc_flags = (pyb_sdmmc_flags & PYB_SDMMC_FLAG_ACTIVE) | PYB_SDMMC_FLAG_SD; // force SD mode vfs->base.type = &mp_fat_vfs_type; vfs->flags |= FSUSER_NATIVE | FSUSER_HAVE_IOCTL; vfs->fatfs.drv = vfs; @@ -602,4 +866,4 @@ void sdcard_init_vfs(fs_user_mount_t *vfs, int part) { vfs->u.ioctl[1] = MP_OBJ_FROM_PTR(&pyb_sdcard_obj); } -#endif // MICROPY_HW_ENABLE_SDCARD +#endif // MICROPY_HW_ENABLE_SDCARD || MICROPY_HW_ENABLE_MMCARD diff --git a/ports/stm32/sdcard.h b/ports/stm32/sdcard.h index 4afc258aa1..e436ffffe1 100644 --- a/ports/stm32/sdcard.h +++ b/ports/stm32/sdcard.h @@ -40,6 +40,7 @@ mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blo mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks); extern const struct _mp_obj_type_t pyb_sdcard_type; +extern const struct _mp_obj_type_t pyb_mmcard_type; extern const struct _mp_obj_base_t pyb_sdcard_obj; struct _fs_user_mount_t; From ca5f8975fa8c15b48df2988e077c39a98693be3d Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 1 Apr 2019 16:48:20 +1100 Subject: [PATCH 0257/1788] lib/stm32lib: Update library to fix F7 MMC capacity calculation. --- lib/stm32lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/stm32lib b/lib/stm32lib index d752828b36..a5e93de184 160000 --- a/lib/stm32lib +++ b/lib/stm32lib @@ -1 +1 @@ -Subproject commit d752828b3654c26ee5c4a236eb13c1ba86bd5aa7 +Subproject commit a5e93de18479879dd129cf6272cfd75e0c794bd4 From 83f3c29d36ce9125f11dcdf2b9699daa1f390a69 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 1 Apr 2019 17:11:39 +1100 Subject: [PATCH 0258/1788] stm32/moduos: Allow to compile again without USB enabled. --- ports/stm32/moduos.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ports/stm32/moduos.c b/ports/stm32/moduos.c index ffecccd17d..ead2380b33 100644 --- a/ports/stm32/moduos.c +++ b/ports/stm32/moduos.c @@ -111,7 +111,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom); bool mp_uos_dupterm_is_builtin_stream(mp_const_obj_t stream) { mp_obj_type_t *type = mp_obj_get_type(stream); - return type == &pyb_uart_type || type == &pyb_usb_vcp_type; + return type == &pyb_uart_type + #if MICROPY_HW_ENABLE_USB + || type == &pyb_usb_vcp_type + #endif + ; } STATIC mp_obj_t uos_dupterm(size_t n_args, const mp_obj_t *args) { @@ -119,16 +123,20 @@ STATIC mp_obj_t uos_dupterm(size_t n_args, const mp_obj_t *args) { if (mp_obj_get_type(prev_obj) == &pyb_uart_type) { uart_attach_to_repl(MP_OBJ_TO_PTR(prev_obj), false); } + #if MICROPY_HW_ENABLE_USB if (mp_obj_get_type(prev_obj) == &pyb_usb_vcp_type) { usb_vcp_attach_to_repl(MP_OBJ_TO_PTR(prev_obj), false); } + #endif if (mp_obj_get_type(args[0]) == &pyb_uart_type) { uart_attach_to_repl(MP_OBJ_TO_PTR(args[0]), true); } + #if MICROPY_HW_ENABLE_USB if (mp_obj_get_type(args[0]) == &pyb_usb_vcp_type) { usb_vcp_attach_to_repl(MP_OBJ_TO_PTR(args[0]), true); } + #endif return prev_obj; } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(uos_dupterm_obj, 1, 2, uos_dupterm); From 1f5d945afa20a2d780b8197ce1dd1d5cfd05724b Mon Sep 17 00:00:00 2001 From: Glenn Ruben Bakke Date: Fri, 29 Mar 2019 14:07:43 +0100 Subject: [PATCH 0259/1788] nrf/Makefile: Update to match latest oofatfs version. See corresponding commit b5f33ac2cb6076468a77f36d69df6db16b62134a --- ports/nrf/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index 6ca83f1e6e..80110f9704 100644 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -163,7 +163,7 @@ SRC_LIB += $(addprefix lib/,\ ifeq ($(MICROPY_FATFS), 1) SRC_LIB += $(addprefix lib/,\ oofatfs/ff.c \ - oofatfs/option/unicode.c \ + oofatfs/ffunicode.c \ ) endif From 3dda9647855b6e7ca265d77027d8eefc143a74b9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Apr 2019 16:43:44 +1100 Subject: [PATCH 0260/1788] extmod/modlwip: Use correct listening socket object in accept callback. Since commit da938a83b587c7387b8849f795f3497735d14267 the tcp_arg() that is set for the new connection is the new connection itself, and the parent listening socket is found in the pcb->connected entry. --- extmod/modlwip.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index af19648a6e..7ebfa89047 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -447,7 +447,8 @@ STATIC err_t _lwip_tcp_recv_unaccepted(void *arg, struct tcp_pcb *pcb, struct pb // from accept callback itself. STATIC err_t _lwip_tcp_accept_finished(void *arg, struct tcp_pcb *pcb) { - lwip_socket_obj_t *socket = (lwip_socket_obj_t*)arg; + // The ->connected entry of the pcb holds the listening socket of the accept + lwip_socket_obj_t *socket = (lwip_socket_obj_t*)pcb->connected; tcp_poll(pcb, NULL, 0); exec_user_callback(socket); return ERR_OK; From d89ce2ed1d4d2bf2ac3e273163af1e69603d9780 Mon Sep 17 00:00:00 2001 From: stijn Date: Sun, 31 Mar 2019 09:47:11 +0200 Subject: [PATCH 0261/1788] tests/run-tests: Ignore exception in process kill when ending repl test. When running Linux on WSL, Popen.kill() can raise a ProcessLookupError if the process does not exist anymore, which can happen here since the previous statement already tries to close the process by sending Ctrl-D to the running repl. This doesn't seem to be a problem on other OSes, so just swallow the exception silently since it indicates the process has been closed already, which after all is what we want. --- tests/run-tests | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/run-tests b/tests/run-tests index bf5c97c2b6..9f74c1cfcc 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -103,7 +103,16 @@ def run_micropython(pyb, args, test_file, is_special=False): banner = get(True) output_mupy = banner + b''.join(send_get(line) for line in f) send_get(b'\x04') # exit the REPL, so coverage info is saved - p.kill() + # At this point the process might have exited already, but trying to + # kill it 'again' normally doesn't result in exceptions as Python and/or + # the OS seem to try to handle this nicely. When running Linux on WSL + # though, the situation differs and calling Popen.kill after the process + # terminated results in a ProcessLookupError. Just catch that one here + # since we just want the process to be gone and that's the case. + try: + p.kill() + except ProcessLookupError: + pass os.close(master) os.close(slave) else: From 69cb24a21d1df509b90f8c32b2224b84dde36f33 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 5 Apr 2019 12:25:21 +1100 Subject: [PATCH 0262/1788] esp32/boards/sdkconfig: Disable WDT check of idle task on CPU1. With dual-core enabled it's possible that the uPy task has full utilisation of CPU1. Fixes issue #4673. --- ports/esp32/boards/sdkconfig | 1 + ports/esp32/boards/sdkconfig.spiram | 1 + 2 files changed, 2 insertions(+) diff --git a/ports/esp32/boards/sdkconfig b/ports/esp32/boards/sdkconfig index eaafed5d6b..7bd731a66b 100644 --- a/ports/esp32/boards/sdkconfig +++ b/ports/esp32/boards/sdkconfig @@ -13,6 +13,7 @@ CONFIG_LOG_BOOTLOADER_LEVEL_WARN=y # ESP32-specific CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=n +CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1=n CONFIG_ESP32_XTAL_FREQ_AUTO=y # Power Management diff --git a/ports/esp32/boards/sdkconfig.spiram b/ports/esp32/boards/sdkconfig.spiram index 6de2db7cb0..1467f3171b 100644 --- a/ports/esp32/boards/sdkconfig.spiram +++ b/ports/esp32/boards/sdkconfig.spiram @@ -16,6 +16,7 @@ CONFIG_SPIRAM_SUPPORT=y CONFIG_SPIRAM_IGNORE_NOTFOUND=y CONFIG_SPIRAM_USE_MEMMAP=y CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=n +CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1=n CONFIG_ESP32_XTAL_FREQ_AUTO=y # Power Management From 4410efc1e349bc5e098f8263b4d652651f26d585 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 5 Apr 2019 22:33:49 +1100 Subject: [PATCH 0263/1788] stm32/network_wiznet5k: Add ability to trace Ethernet TX and RX frames. Via: nic.config(trace=2|4) --- ports/stm32/network_wiznet5k.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/ports/stm32/network_wiznet5k.c b/ports/stm32/network_wiznet5k.c index 9db42b7874..99b8b68536 100644 --- a/ports/stm32/network_wiznet5k.c +++ b/ports/stm32/network_wiznet5k.c @@ -32,12 +32,16 @@ #if MICROPY_PY_WIZNET5K && MICROPY_PY_LWIP +#include "lib/netutils/netutils.h" #include "drivers/wiznet5k/ethernet/socket.h" #include "lwip/err.h" #include "lwip/dns.h" #include "lwip/dhcp.h" #include "netif/etharp.h" +#define TRACE_ETH_TX (0x0002) +#define TRACE_ETH_RX (0x0004) + /*******************************************************************************/ // Wiznet5k Ethernet driver in MACRAW mode @@ -48,6 +52,7 @@ typedef struct _wiznet5k_obj_t { mp_hal_pin_obj_t cs; mp_hal_pin_obj_t rst; uint8_t eth_frame[1514]; + uint32_t trace_flags; struct netif netif; struct dhcp dhcp_struct; } wiznet5k_obj_t; @@ -176,6 +181,9 @@ STATIC uint16_t wiznet5k_recv_ethernet(wiznet5k_obj_t *self) { 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); + if (self->trace_flags & TRACE_ETH_TX) { + netutils_ethernet_trace(MP_PYTHON_PRINTER, p->tot_len, self->eth_frame, NETUTILS_TRACE_IS_TX | NETUTILS_TRACE_NEWLINE); + } wiznet5k_send_ethernet(self, p->tot_len, self->eth_frame); return ERR_OK; } @@ -223,6 +231,9 @@ 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) { + if (self->trace_flags & TRACE_ETH_RX) { + netutils_ethernet_trace(MP_PYTHON_PRINTER, len, self->eth_frame, NETUTILS_TRACE_NEWLINE); + } struct pbuf *p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); if (p != NULL) { pbuf_take(p, self->eth_frame, len); @@ -260,6 +271,7 @@ STATIC mp_obj_t wiznet5k_make_new(const mp_obj_type_t *type, size_t n_args, size wiznet5k_obj.spi = spi; wiznet5k_obj.cs = cs; wiznet5k_obj.rst = rst; + wiznet5k_obj.trace_flags = 0; // Return wiznet5k object return MP_OBJ_FROM_PTR(&wiznet5k_obj); @@ -381,7 +393,22 @@ STATIC mp_obj_t wiznet5k_config(size_t n_args, const mp_obj_t *args, mp_map_t *k if (n_args != 1) { mp_raise_TypeError("can't specify pos and kw args"); } - mp_raise_ValueError("unknown config param"); + + for (size_t i = 0; i < kwargs->alloc; ++i) { + if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) { + mp_map_elem_t *e = &kwargs->table[i]; + switch (mp_obj_str_get_qstr(e->key)) { + case MP_QSTR_trace: { + self->trace_flags = mp_obj_get_int(e->value); + break; + } + default: + mp_raise_ValueError("unknown config param"); + } + } + } + + return mp_const_none; } } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wiznet5k_config_obj, 1, wiznet5k_config); From 4f936afc441da48ab8043ec108a2a2f6a92fdd6e Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 5 Apr 2019 22:35:04 +1100 Subject: [PATCH 0264/1788] stm32/network_wiznet5k: Add ability to set the MAC address. --- ports/stm32/network_wiznet5k.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ports/stm32/network_wiznet5k.c b/ports/stm32/network_wiznet5k.c index 99b8b68536..e0fc5d5bab 100644 --- a/ports/stm32/network_wiznet5k.c +++ b/ports/stm32/network_wiznet5k.c @@ -25,6 +25,8 @@ */ #include +#include + #include "py/runtime.h" #include "py/mphal.h" #include "spi.h" @@ -398,6 +400,16 @@ STATIC mp_obj_t wiznet5k_config(size_t n_args, const mp_obj_t *args, mp_map_t *k if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) { mp_map_elem_t *e = &kwargs->table[i]; switch (mp_obj_str_get_qstr(e->key)) { + case MP_QSTR_mac: { + mp_buffer_info_t buf; + mp_get_buffer_raise(e->value, &buf, MP_BUFFER_READ); + if (buf.len != 6) { + mp_raise_ValueError(NULL); + } + setSHAR(buf.buf); + memcpy(self->netif.hwaddr, buf.buf, 6); + break; + } case MP_QSTR_trace: { self->trace_flags = mp_obj_get_int(e->value); break; From fd523c53c37b36a9c343b1061d08e65e920dffa0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 5 Apr 2019 22:37:06 +1100 Subject: [PATCH 0265/1788] stm32/network_wiznet5k: Automatically set MAC if device doesn't have one --- ports/stm32/network_wiznet5k.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ports/stm32/network_wiznet5k.c b/ports/stm32/network_wiznet5k.c index e0fc5d5bab..3bbe639acc 100644 --- a/ports/stm32/network_wiznet5k.c +++ b/ports/stm32/network_wiznet5k.c @@ -128,6 +128,14 @@ STATIC void wiznet5k_init(void) { // Seems we need a small delay after init mp_hal_delay_ms(250); + // If the device doesn't have a MAC address then set one + uint8_t mac[6]; + getSHAR(mac); + if ((mac[0] | mac[1] | mac[2] | mac[3] | mac[4] | mac[5]) == 0) { + mp_hal_get_mac(MP_HAL_MAC_ETH0, mac); + setSHAR(mac); + } + // Hook the Wiznet into lwIP wiznet5k_lwip_init(&wiznet5k_obj); } From 643d2a0e86bd151130508171804e5ab5b1a7bd4e Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 8 Apr 2019 11:21:18 +1000 Subject: [PATCH 0266/1788] tools/mpy-tool.py: Adjust use of super() to make it work with Python 2. Fixes the regression introduced in ea3c80a514c5dc4cc3a8349815eceec4fa1ac57f --- tools/mpy-tool.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index ff31a61bde..b8e5297aa4 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -259,7 +259,7 @@ def extract_prelude(bytecode, ip): class MPFunTable: pass -class RawCode: +class RawCode(object): # a set of all escaped names, to make sure they are unique escaped_names = set() @@ -423,7 +423,7 @@ class RawCode: class RawCodeBytecode(RawCode): def __init__(self, bytecode, qstrs, objs, raw_codes): - super().__init__(MP_CODE_BYTECODE, bytecode, 0, qstrs, objs, raw_codes) + super(RawCodeBytecode, self).__init__(MP_CODE_BYTECODE, bytecode, 0, qstrs, objs, raw_codes) def freeze(self, parent_name): self.freeze_children(parent_name) @@ -462,7 +462,7 @@ class RawCodeBytecode(RawCode): class RawCodeNative(RawCode): def __init__(self, code_kind, fun_data, prelude_offset, prelude, qstr_links, qstrs, objs, raw_codes, type_sig): - super().__init__(code_kind, fun_data, prelude_offset, qstrs, objs, raw_codes) + super(RawCodeNative, self).__init__(code_kind, fun_data, prelude_offset, qstrs, objs, raw_codes) self.prelude = prelude self.qstr_links = qstr_links self.type_sig = type_sig From 2c3fa4ad820c26b485da803a2de679744317ff90 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 8 Apr 2019 14:28:45 +1000 Subject: [PATCH 0267/1788] stm32/i2cslave: Add support for H7 MCUs. --- ports/stm32/i2cslave.c | 2 +- ports/stm32/i2cslave.h | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/ports/stm32/i2cslave.c b/ports/stm32/i2cslave.c index 473f0c8c55..da165294ac 100644 --- a/ports/stm32/i2cslave.c +++ b/ports/stm32/i2cslave.c @@ -60,7 +60,7 @@ void i2c_slave_ev_irq_handler(i2c_slave_t *i2c) { } } -#elif defined(STM32F7) +#elif defined(STM32F7) || defined(STM32H7) 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; diff --git a/ports/stm32/i2cslave.h b/ports/stm32/i2cslave.h index ac35c0cc82..55882acd8e 100644 --- a/ports/stm32/i2cslave.h +++ b/ports/stm32/i2cslave.h @@ -33,10 +33,16 @@ 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; + int i2c_idx = ((uintptr_t)i2c - I2C1_BASE) / (I2C2_BASE - I2C1_BASE); + #if defined(STM32F4) || defined(STM32F7) + RCC->APB1ENR |= 1 << (RCC_APB1ENR_I2C1EN_Pos + i2c_idx); volatile uint32_t tmp = RCC->APB1ENR; // Delay after enabling clock (void)tmp; + #elif defined(STM32H7) + RCC->APB1LENR |= 1 << (RCC_APB1LENR_I2C1EN_Pos + i2c_idx); + volatile uint32_t tmp = RCC->APB1LENR; // Delay after enabling clock + (void)tmp; + #endif i2c_slave_init_helper(i2c, addr); From ae1e18a346b9a3f4bdd75dcb9faa9287b4f5e7cf Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 8 Apr 2019 14:30:16 +1000 Subject: [PATCH 0268/1788] stm32/usbd_conf: Add support for USB HS peripheral on H7 MCUs. --- ports/stm32/usbd_conf.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c index 48af633cb7..b7c1665f0a 100644 --- a/ports/stm32/usbd_conf.c +++ b/ports/stm32/usbd_conf.c @@ -104,10 +104,16 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) { else if (hpcd->Instance == USB_OTG_HS) { #if MICROPY_HW_USB_HS_IN_FS + #if defined(STM32H7) + const uint32_t otg_alt = GPIO_AF12_OTG2_FS; + #else + const uint32_t otg_alt = GPIO_AF12_OTG_HS_FS; + #endif + // 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(pin_B14, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, otg_alt); 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(pin_B15, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, otg_alt); mp_hal_pin_config_speed(pin_B15, GPIO_SPEED_FREQ_VERY_HIGH); #if defined(MICROPY_HW_USB_VBUS_DETECT_PIN) @@ -117,7 +123,7 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) { #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); + 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 // Enable calling WFI and correct function of the embedded USB_FS_IN_HS phy From fd13ce5e60143491f0db24655393cea5437ee85b Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 8 Apr 2019 14:33:57 +1000 Subject: [PATCH 0269/1788] stm32/mboot: Add support for H7 MCUs, with H743 flash layout. --- ports/stm32/mboot/Makefile | 1 + ports/stm32/mboot/main.c | 207 ++++++++++++++++++++++++++++++++-- ports/stm32/mboot/mphalport.h | 5 + 3 files changed, 202 insertions(+), 11 deletions(-) diff --git a/ports/stm32/mboot/Makefile b/ports/stm32/mboot/Makefile index 122abf27aa..0a5759347f 100755 --- a/ports/stm32/mboot/Makefile +++ b/ports/stm32/mboot/Makefile @@ -48,6 +48,7 @@ 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_h7 = $(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) diff --git a/ports/stm32/mboot/main.c b/ports/stm32/mboot/main.c index 6958d3f61e..f6b89004d4 100644 --- a/ports/stm32/mboot/main.c +++ b/ports/stm32/mboot/main.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2017-2018 Damien P. George + * Copyright (c) 2017-2019 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 @@ -38,7 +38,7 @@ // 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 +// Using cache probably won't make it faster because we run at a low frequency, and best // to keep the MCU config as minimal as possible. #define USE_CACHE (0) @@ -46,18 +46,25 @@ #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 +// Configure PLL to give the desired CPU freq +#undef MICROPY_HW_FLASH_LATENCY +#if defined(STM32H7) +#define CORE_PLL_FREQ (96000000) +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_2 +#else #define CORE_PLL_FREQ (48000000) +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_1 +#endif #undef MICROPY_HW_CLK_PLLM #undef MICROPY_HW_CLK_PLLN #undef MICROPY_HW_CLK_PLLP #undef MICROPY_HW_CLK_PLLQ -#undef MICROPY_HW_FLASH_LATENCY +#undef MICROPY_HW_CLK_PLLR #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_PLLP (MICROPY_HW_CLK_PLLN / (CORE_PLL_FREQ / 1000000)) #define MICROPY_HW_CLK_PLLQ (4) -#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_1 +#define MICROPY_HW_CLK_PLLR (2) // Work out which USB device to use for the USB DFU interface #if !defined(MICROPY_HW_USB_MAIN_DEV) @@ -137,11 +144,25 @@ static void __fatal_error(const char *msg) { #define CONFIG_RCC_CR_2ND (RCC_CR_HSEON || RCC_CR_CSSON || RCC_CR_PLLON) #define CONFIG_RCC_PLLCFGR (0x24003010) +#elif defined(STM32H7) + +#define CONFIG_RCC_CR_1ST (RCC_CR_HSION) +#define CONFIG_RCC_CR_2ND (RCC_CR_PLL3ON | RCC_CR_PLL2ON | RCC_CR_PLL1ON | RCC_CR_CSSHSEON \ + | RCC_CR_HSEON | RCC_CR_HSI48ON | RCC_CR_CSIKERON | RCC_CR_CSION) +#define CONFIG_RCC_PLLCFGR (0x00000000) + #else #error Unknown processor #endif void SystemInit(void) { + #if defined(STM32H7) + // Configure write-once power options, and wait for voltage levels to be ready + PWR->CR3 = PWR_CR3_LDOEN; + while (!(PWR->CSR1 & PWR_CSR1_ACTVOSRDY)) { + } + #endif + // Set HSION bit RCC->CR |= CONFIG_RCC_CR_1ST; @@ -154,11 +175,27 @@ void SystemInit(void) { // Reset PLLCFGR register RCC->PLLCFGR = CONFIG_RCC_PLLCFGR; + #if defined(STM32H7) + // Reset PLL and clock configuration registers + RCC->D1CFGR = 0x00000000; + RCC->D2CFGR = 0x00000000; + RCC->D3CFGR = 0x00000000; + RCC->PLLCKSELR = 0x00000000; + RCC->D1CCIPR = 0x00000000; + RCC->D2CCIP1R = 0x00000000; + RCC->D2CCIP2R = 0x00000000; + RCC->D3CCIPR = 0x00000000; + #endif + // Reset HSEBYP bit RCC->CR &= (uint32_t)0xFFFBFFFF; // Disable all interrupts + #if defined(STM32F4) || defined(STM32F7) RCC->CIR = 0x00000000; + #elif defined(STM32H7) + RCC->CIER = 0x00000000; + #endif // Set location of vector table SCB->VTOR = FLASH_BASE; @@ -173,6 +210,8 @@ void systick_init(void) { NVIC_SetPriority(SysTick_IRQn, IRQ_PRI_SYSTICK); } +#if defined(STM32F4) || defined(STM32F7) + void SystemClock_Config(void) { // This function assumes that HSI is used as the system clock (see RCC->CFGR, SWS bits) @@ -243,6 +282,87 @@ void SystemClock_Config(void) { #endif } +#elif defined(STM32H7) + +void SystemClock_Config(void) { + // This function assumes that HSI is used as the system clock (see RCC->CFGR, SWS bits) + + // Select VOS level as high voltage to give reliable operation + __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); + while (__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY) == RESET) { + } + + // Turn HSE on + __HAL_RCC_HSE_CONFIG(RCC_HSE_ON); + while (__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET) { + } + + // Disable PLL1 + __HAL_RCC_PLL_DISABLE(); + while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) != RESET) { + } + + // Configure PLL1 factors and source + RCC->PLLCKSELR = + MICROPY_HW_CLK_PLLM << RCC_PLLCKSELR_DIVM1_Pos + | 2 << RCC_PLLCKSELR_PLLSRC_Pos; // HSE selected as PLL source + RCC->PLL1DIVR = + (MICROPY_HW_CLK_PLLN - 1) << RCC_PLL1DIVR_N1_Pos + | (MICROPY_HW_CLK_PLLP - 1) << RCC_PLL1DIVR_P1_Pos // only even P allowed + | (MICROPY_HW_CLK_PLLQ - 1) << RCC_PLL1DIVR_Q1_Pos + | (MICROPY_HW_CLK_PLLR - 1) << RCC_PLL1DIVR_R1_Pos; + + // Enable PLL1 outputs for SYSCLK and USB + RCC->PLLCFGR = RCC_PLLCFGR_DIVP1EN | RCC_PLLCFGR_DIVQ1EN; + + // Select PLL1-Q for USB clock source + RCC->D2CCIP2R |= 1 << RCC_D2CCIP2R_USBSEL_Pos; + + // Enable PLL1 + __HAL_RCC_PLL_ENABLE(); + while(__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) == RESET) { + } + + // Increase latency before changing SYSCLK + if (MICROPY_HW_FLASH_LATENCY > (FLASH->ACR & FLASH_ACR_LATENCY)) { + __HAL_FLASH_SET_LATENCY(MICROPY_HW_FLASH_LATENCY); + } + + // Configure AHB divider + RCC->D1CFGR = + 0 << RCC_D1CFGR_D1CPRE_Pos // SYSCLK prescaler of 1 + | 8 << RCC_D1CFGR_HPRE_Pos // AHB prescaler of 2 + ; + + // Configure SYSCLK source from PLL + __HAL_RCC_SYSCLK_CONFIG(RCC_SYSCLKSOURCE_PLLCLK); + while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL1) { + } + + // 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 + RCC->D1CFGR |= + 4 << RCC_D1CFGR_D1PPRE_Pos // APB3 prescaler of 2 + ; + RCC->D2CFGR = + 4 << RCC_D2CFGR_D2PPRE2_Pos // APB2 prescaler of 2 + | 4 << RCC_D2CFGR_D2PPRE1_Pos // APB1 prescaler of 2 + ; + RCC->D3CFGR = + 4 << RCC_D3CFGR_D3PPRE_Pos // APB4 prescaler of 2 + ; + + // Update clock value and reconfigure systick now that the frequency changed + SystemCoreClock = CORE_PLL_FREQ; + systick_init(); +} + +#endif + // Needed by HAL_PCD_IRQHandler uint32_t HAL_RCC_GetHCLKFreq(void) { return SystemCoreClock; @@ -251,13 +371,21 @@ uint32_t HAL_RCC_GetHCLKFreq(void) { /******************************************************************************/ // GPIO +#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 +#endif + 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 + uint32_t gpio_idx = ((uintptr_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; // Configure the pin @@ -381,6 +509,14 @@ static const flash_layout_t flash_layout[] = { { 0x08040000, 0x40000, 7 }, }; +#elif defined(STM32H743xx) + +#define FLASH_LAYOUT_STR "@Internal Flash /0x08000000/16*128Kg" MBOOT_SPIFLASH_LAYOUT MBOOT_SPIFLASH2_LAYOUT + +static const flash_layout_t flash_layout[] = { + { 0x08000000, 0x20000, 16 }, +}; + #endif static uint32_t flash_get_sector_index(uint32_t addr, uint32_t *sector_size) { @@ -401,6 +537,27 @@ static uint32_t flash_get_sector_index(uint32_t addr, uint32_t *sector_size) { return 0; } +#if defined(STM32H7) +// get the bank of a given flash address +static uint32_t get_bank(uint32_t addr) { + if (READ_BIT(FLASH->OPTCR, FLASH_OPTCR_SWAP_BANK) == 0) { + // no bank swap + if (addr < (FLASH_BASE + FLASH_BANK_SIZE)) { + return FLASH_BANK_1; + } else { + return FLASH_BANK_2; + } + } else { + // bank swap + if (addr < (FLASH_BASE + FLASH_BANK_SIZE)) { + return FLASH_BANK_2; + } else { + return FLASH_BANK_1; + } + } +} +#endif + static int flash_mass_erase(void) { // TODO return -1; @@ -419,13 +576,20 @@ static int flash_page_erase(uint32_t addr, uint32_t *next_addr) { HAL_FLASH_Unlock(); // 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) FLASH_EraseInitTypeDef EraseInitStruct; 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(addr); + #endif EraseInitStruct.Sector = sector; EraseInitStruct.NbSectors = 1; @@ -454,6 +618,20 @@ static int flash_write(uint32_t addr, const uint8_t *src8, size_t len) { const uint32_t *src = (const uint32_t*)src8; size_t num_word32 = (len + 3) / 4; HAL_FLASH_Unlock(); + + #if 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, addr, (uint64_t)(uint32_t)src) != HAL_OK) { + return - 1; + } + addr += 32; + src += 8; + } + + #else + // 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) { @@ -463,6 +641,8 @@ static int flash_write(uint32_t addr, const uint8_t *src8, size_t len) { src += 1; } + #endif + // TODO verify data return 0; @@ -1130,6 +1310,11 @@ static void pyb_usbdd_init(pyb_usbdd_obj_t *self, int phy_id) { static void pyb_usbdd_start(pyb_usbdd_obj_t *self) { if (!self->started) { + #if defined(STM32H7) + PWR->CR3 |= PWR_CR3_USB33DEN; + while (!(PWR->CR3 & PWR_CR3_USB33RDY)) { + } + #endif USBD_LL_Init(&self->hUSBDDevice, 0); USBD_LL_Start(&self->hUSBDDevice); self->started = true; @@ -1249,8 +1434,8 @@ void stm32_main(int initial_r0) { goto enter_bootloader; } - // MCU starts up with 16MHz HSI - SystemCoreClock = 16000000; + // MCU starts up with HSI + SystemCoreClock = HSI_VALUE; int reset_mode = get_reset_mode(); uint32_t msp = *(volatile uint32_t*)APPLICATION_ADDR; diff --git a/ports/stm32/mboot/mphalport.h b/ports/stm32/mboot/mphalport.h index 86063c4ef2..69ca0b035b 100644 --- a/ports/stm32/mboot/mphalport.h +++ b/ports/stm32/mboot/mphalport.h @@ -48,8 +48,13 @@ #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_low(p) (((GPIO_TypeDef*)((p) & ~0xf))->BSRRH = 1 << ((p) & 0xf)) +#define mp_hal_pin_high(p) (((GPIO_TypeDef*)((p) & ~0xf))->BSRRL = 1 << ((p) & 0xf)) +#else #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)) +#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) ((((GPIO_TypeDef*)((p) & ~0xf))->IDR >> ((p) & 0xf)) & 1) From 4831e38c7e3f7b46be3282354c0f6051bb96f6e6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 8 Apr 2019 14:34:37 +1000 Subject: [PATCH 0270/1788] stm32/boards/NUCLEO_H743ZI: Add config options to support mboot. --- ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk index 4d3455441f..1d232e0803 100644 --- a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk @@ -1,7 +1,18 @@ +USE_MBOOT ?= 0 + +# MCU settings MCU_SERIES = h7 CMSIS_MCU = STM32H743xx MICROPY_FLOAT_IMPL = double AF_FILE = boards/stm32h743_af.csv + +ifeq ($(USE_MBOOT),1) +# When using Mboot all the text goes together after the filesystem +LD_FILES = boards/stm32h743.ld boards/common_blifs.ld +TEXT0_ADDR = 0x08040000 +else +# When not using Mboot the ISR text goes first, then the rest after the filesystem LD_FILES = boards/stm32h743.ld boards/common_ifs.ld TEXT0_ADDR = 0x08000000 TEXT1_ADDR = 0x08040000 +endif From 74ed06828f4f8d4ec5c04f5b551e90f2fccbd0f3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 8 Apr 2019 15:20:56 +1000 Subject: [PATCH 0271/1788] tools/mpy-tool.py: Fix init of QStrWindow, and remove unused variable. The qstr window size is not log-2 encoded, it's just the actual number (but in mpy-tool.py this didn't lead to an error because the size is just used to truncate the window so it doesn't grow arbitrarily large in memory). Addresses issue #4635. --- tools/mpy-tool.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index b8e5297aa4..c8216bb603 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -75,9 +75,9 @@ for n in qstrutil.static_qstr_list: global_qstrs.append(QStrType(n)) class QStrWindow: - def __init__(self, size_log2): + def __init__(self, size): self.window = [] - self.size = 1 << size_log2 + self.size = size def push(self, val): self.window = [val] + self.window[:self.size - 1] @@ -633,7 +633,6 @@ def read_qstr_and_pack(f, bytecode, qstr_win): bytecode.append(qst >> 8) def read_bytecode(file, bytecode, qstr_win): - QSTR_LAST_STATIC = len(qstrutil.static_qstr_list) while not bytecode.is_full(): op = read_byte(file, bytecode) f, sz = mp_opcode_format(bytecode.buf, bytecode.idx - 1, False) From 358364b45e21585103017325e72a36b2de4d2b6a Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 9 Apr 2019 11:23:08 +1000 Subject: [PATCH 0272/1788] stm32/boards/NUCLEO_L432KC: Disable complex nos and default frozen mods. To save space, since this board only hase 256k of flash. --- ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h | 1 + ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.mk | 3 +++ 2 files changed, 4 insertions(+) diff --git a/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h b/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h index aa8c9e6744..7f2ebbad55 100644 --- a/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h @@ -3,6 +3,7 @@ #define MICROPY_EMIT_THUMB (0) #define MICROPY_EMIT_INLINE_THUMB (0) +#define MICROPY_PY_BUILTINS_COMPLEX (0) #define MICROPY_PY_USOCKET (0) #define MICROPY_PY_NETWORK (0) #define MICROPY_PY_STM (0) diff --git a/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.mk index e8740d64ad..46697348fe 100644 --- a/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.mk @@ -3,3 +3,6 @@ CMSIS_MCU = STM32L432xx AF_FILE = boards/stm32l432_af.csv LD_FILES = boards/stm32l432.ld boards/common_basic.ld OPENOCD_CONFIG = boards/openocd_stm32l4.cfg + +# Don't include default frozen modules because MCU is tight on flash space +FROZEN_MPY_DIR ?= From d5f0c87bb985ae344014dc2041fbaad5c522f638 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 4 Apr 2019 14:20:42 +1100 Subject: [PATCH 0273/1788] extmod/modlwip: Abort TCP conns that didn't close cleanly in a while. --- extmod/modlwip.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index 7ebfa89047..e0bf17db8c 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -57,6 +57,10 @@ #define DEBUG_printf(...) (void)0 #endif +// Timeout between closing a TCP socket and doing a tcp_abort on that +// socket, if the connection isn't closed cleanly in that time. +#define MICROPY_PY_LWIP_TCP_CLOSE_TIMEOUT_MS (10000) + // All socket options should be globally distinct, // because we ignore option levels for efficiency. #define IP_ADD_MEMBERSHIP 0x400 @@ -1342,6 +1346,13 @@ STATIC mp_uint_t lwip_socket_write(mp_obj_t self_in, const void *buf, mp_uint_t return MP_STREAM_ERROR; } +STATIC err_t _lwip_tcp_close_poll(void *arg, struct tcp_pcb *pcb) { + // Connection has not been cleanly closed so just abort it to free up memory + tcp_poll(pcb, NULL, 0); + tcp_abort(pcb); + return ERR_OK; +} + STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in); mp_uint_t ret; @@ -1401,6 +1412,8 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ } // Deregister callback (pcb.tcp is set to NULL below so must deregister now) + tcp_arg(socket->pcb.tcp, NULL); + tcp_err(socket->pcb.tcp, NULL); tcp_recv(socket->pcb.tcp, NULL); switch (socket->type) { @@ -1408,6 +1421,9 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ if (tcp_close(socket->pcb.tcp) != ERR_OK) { DEBUG_printf("lwip_close: had to call tcp_abort()\n"); tcp_abort(socket->pcb.tcp); + } else { + // If connection not cleanly closed after timeout then abort the connection + tcp_poll(socket->pcb.tcp, _lwip_tcp_close_poll, MICROPY_PY_LWIP_TCP_CLOSE_TIMEOUT_MS / 500); } break; } From 46e5d6b8893e07538c33677a349e9e2fd038e62c Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 11 Apr 2019 12:09:21 +1000 Subject: [PATCH 0274/1788] stm32/rtc: Add auto-LSE-bypass detection with fallback to LSE then LSI. If MICROPY_HW_RTC_USE_BYPASS is enabled the RTC startup goes as follows: - RTC is started with LSE in bypass mode to begin with - if that fails to start (after a given timeout) then LSE is reconfigured in non-bypass - if that fails to start then RTC is switched to LSI --- ports/stm32/mpconfigboard_common.h | 6 +++ ports/stm32/rtc.c | 65 +++++++++++++++++++++--------- 2 files changed, 52 insertions(+), 19 deletions(-) diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index 1ace8fcaf4..08c835a1c2 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -210,6 +210,12 @@ #endif #endif +// If disabled then try normal (non-bypass) LSE first, with fallback to LSI. +// If enabled first try LSE in bypass mode. If that fails to start, try non-bypass mode, with fallback to LSI. +#ifndef MICROPY_HW_RTC_USE_BYPASS +#define MICROPY_HW_RTC_USE_BYPASS (0) +#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/rtc.c b/ports/stm32/rtc.c index 250c34bcf5..ec1e947b21 100644 --- a/ports/stm32/rtc.c +++ b/ports/stm32/rtc.c @@ -61,11 +61,11 @@ static mp_uint_t rtc_info; #endif STATIC HAL_StatusTypeDef PYB_RTC_Init(RTC_HandleTypeDef *hrtc); -STATIC void PYB_RTC_MspInit_Kick(RTC_HandleTypeDef *hrtc, bool rtc_use_lse); +STATIC void PYB_RTC_MspInit_Kick(RTC_HandleTypeDef *hrtc, bool rtc_use_lse, bool rtc_use_byp); STATIC HAL_StatusTypeDef PYB_RTC_MspInit_Finalise(RTC_HandleTypeDef *hrtc); STATIC void RTC_CalendarConfig(void); -#if defined(MICROPY_HW_RTC_USE_LSE) && MICROPY_HW_RTC_USE_LSE +#if MICROPY_HW_RTC_USE_LSE || MICROPY_HW_RTC_USE_BYPASS STATIC bool rtc_use_lse = true; #else STATIC bool rtc_use_lse = false; @@ -159,7 +159,7 @@ void rtc_init_start(bool force_init) { rtc_info &= ~0x01000000; } } - PYB_RTC_MspInit_Kick(&RTCHandle, rtc_use_lse); + PYB_RTC_MspInit_Kick(&RTCHandle, rtc_use_lse, MICROPY_HW_RTC_USE_BYPASS); } void rtc_init_finalise() { @@ -167,26 +167,34 @@ void rtc_init_finalise() { return; } - rtc_info = 0x20000000; - if (PYB_RTC_Init(&RTCHandle) != HAL_OK) { + rtc_info = 0; + while (PYB_RTC_Init(&RTCHandle) != HAL_OK) { if (rtc_use_lse) { - // fall back to LSI... - rtc_use_lse = false; + #if MICROPY_HW_RTC_USE_BYPASS + if (RCC->BDCR & RCC_BDCR_LSEBYP) { + // LSEBYP failed, fallback to LSE non-bypass + rtc_info |= 0x02000000; + } else + #endif + { + // LSE failed, fallback to LSI + rtc_use_lse = false; + rtc_info |= 0x01000000; + } rtc_startup_tick = HAL_GetTick(); - PYB_RTC_MspInit_Kick(&RTCHandle, rtc_use_lse); + PYB_RTC_MspInit_Kick(&RTCHandle, rtc_use_lse, false); HAL_PWR_EnableBkUpAccess(); RTCHandle.State = HAL_RTC_STATE_RESET; - if (PYB_RTC_Init(&RTCHandle) != HAL_OK) { - rtc_info = 0x0100ffff; // indicate error - return; - } } else { // init error - rtc_info = 0xffff; // indicate error + rtc_info |= 0xffff; // indicate error return; } } + // RTC started successfully + rtc_info = 0x20000000; + // record if LSE or LSI is used rtc_info |= (rtc_use_lse << 28); @@ -257,6 +265,16 @@ STATIC HAL_StatusTypeDef PYB_RCC_OscConfig(RCC_OscInitTypeDef *RCC_OscInitStruc } #endif + #if MICROPY_HW_RTC_USE_BYPASS + // If LSEBYP is enabled and new state is non-bypass then disable LSEBYP + if (RCC_OscInitStruct->LSEState == RCC_LSE_ON && (RCC->BDCR & RCC_BDCR_LSEBYP)) { + CLEAR_BIT(RCC->BDCR, RCC_BDCR_LSEON); + while (RCC->BDCR & RCC_BDCR_LSERDY) { + } + CLEAR_BIT(RCC->BDCR, RCC_BDCR_LSEBYP); + } + #endif + // Set the new LSE configuration __HAL_RCC_LSE_CONFIG(RCC_OscInitStruct->LSEState); } @@ -327,7 +345,7 @@ STATIC HAL_StatusTypeDef PYB_RTC_Init(RTC_HandleTypeDef *hrtc) { } } -STATIC void PYB_RTC_MspInit_Kick(RTC_HandleTypeDef *hrtc, bool rtc_use_lse) { +STATIC void PYB_RTC_MspInit_Kick(RTC_HandleTypeDef *hrtc, bool rtc_use_lse, bool rtc_use_byp) { /* To change the source clock of the RTC feature (LSE, LSI), You have to: - Enable the power clock using __PWR_CLK_ENABLE() - Enable write access using HAL_PWR_EnableBkUpAccess() function before to @@ -342,12 +360,14 @@ STATIC void PYB_RTC_MspInit_Kick(RTC_HandleTypeDef *hrtc, bool rtc_use_lse) { RCC_OscInitTypeDef RCC_OscInitStruct; 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 + #if MICROPY_HW_RTC_USE_BYPASS + if (rtc_use_byp) { RCC_OscInitStruct.LSEState = RCC_LSE_BYPASS; - #else + RCC_OscInitStruct.LSIState = RCC_LSI_OFF; + } else + #endif + if (rtc_use_lse) { RCC_OscInitStruct.LSEState = RCC_LSE_ON; - #endif RCC_OscInitStruct.LSIState = RCC_LSI_OFF; } else { RCC_OscInitStruct.LSEState = RCC_LSE_OFF; @@ -361,14 +381,21 @@ STATIC void PYB_RTC_MspInit_Kick(RTC_HandleTypeDef *hrtc, bool rtc_use_lse) { #define PYB_LSE_TIMEOUT_VALUE 1000 // ST docs spec 2000 ms LSE startup, seems to be too pessimistic #define PYB_LSI_TIMEOUT_VALUE 500 // this is way too pessimistic, typ. < 1ms +#define PYB_BYP_TIMEOUT_VALUE 150 STATIC HAL_StatusTypeDef PYB_RTC_MspInit_Finalise(RTC_HandleTypeDef *hrtc) { // we already had a kick so now wait for the corresponding ready state... if (rtc_use_lse) { // we now have to wait for LSE ready or timeout + uint32_t timeout = PYB_LSE_TIMEOUT_VALUE; + #if MICROPY_HW_RTC_USE_BYPASS + if (RCC->BDCR & RCC_BDCR_LSEBYP) { + timeout = PYB_BYP_TIMEOUT_VALUE; + } + #endif uint32_t tickstart = rtc_startup_tick; while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == RESET) { - if ((HAL_GetTick() - tickstart ) > PYB_LSE_TIMEOUT_VALUE) { + if ((HAL_GetTick() - tickstart ) > timeout) { return HAL_TIMEOUT; } } From fc9f2ff0cdc3cc75732d7954ac012b5a25f20f10 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 11 Apr 2019 12:14:21 +1000 Subject: [PATCH 0275/1788] stm32/rtc: Remove unused LSE detection code. --- ports/stm32/rtc.c | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/ports/stm32/rtc.c b/ports/stm32/rtc.c index ec1e947b21..8e56e25f9f 100644 --- a/ports/stm32/rtc.c +++ b/ports/stm32/rtc.c @@ -73,36 +73,6 @@ STATIC bool rtc_use_lse = false; STATIC uint32_t rtc_startup_tick; STATIC bool rtc_need_init_finalise = false; -// check if LSE exists -// not well tested, should probably be removed -STATIC bool lse_magic(void) { -#if 0 - uint32_t mode_in = GPIOC->MODER & 0x3fffffff; - uint32_t mode_out = mode_in | 0x40000000; - GPIOC->MODER = mode_out; - GPIOC->OTYPER &= 0x7fff; - GPIOC->BSRRH = 0x8000; - GPIOC->OSPEEDR &= 0x3fffffff; - GPIOC->PUPDR &= 0x3fffffff; - int i = 0xff0; - __IO int d = 0; - uint32_t tc = 0; - __IO uint32_t j; - while (i) { - GPIOC->MODER = mode_out; - GPIOC->MODER = mode_in; - for (j = 0; j < d; j++) ; - i--; - if ((GPIOC->IDR & 0x8000) == 0) { - tc++; - } - } - return (tc < 0xff0)?true:false; -#else - return false; -#endif -} - void rtc_init_start(bool force_init) { RTCHandle.Instance = RTC; @@ -152,13 +122,6 @@ void rtc_init_start(bool force_init) { rtc_startup_tick = HAL_GetTick(); rtc_info = 0x3f000000 | (rtc_startup_tick & 0xffffff); - if (rtc_use_lse) { - if (lse_magic()) { - // don't even try LSE - rtc_use_lse = false; - rtc_info &= ~0x01000000; - } - } PYB_RTC_MspInit_Kick(&RTCHandle, rtc_use_lse, MICROPY_HW_RTC_USE_BYPASS); } From 3c9f78b048fade80f71cca25999ee2541a80034e Mon Sep 17 00:00:00 2001 From: Damiano Mazzella Date: Sat, 6 Apr 2019 23:24:55 +0200 Subject: [PATCH 0276/1788] zephyr/CMakeLists.txt: Set AR to point to the Zephyr toolchain exe. --- ports/zephyr/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/zephyr/CMakeLists.txt b/ports/zephyr/CMakeLists.txt index 8e01624170..017b0689ce 100644 --- a/ports/zephyr/CMakeLists.txt +++ b/ports/zephyr/CMakeLists.txt @@ -17,6 +17,7 @@ zephyr_get_compile_options_for_lang_as_string(C options) add_custom_target( outputexports COMMAND echo CC="${CMAKE_C_COMPILER}" + COMMAND echo AR="${CMAKE_AR}" COMMAND echo Z_CFLAGS=${system_includes} ${includes} ${definitions} ${options} VERBATIM USES_TERMINAL From fd112239d6b7e6ebeb78f62e3b02aa6640a88772 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 12 Apr 2019 11:31:22 +1000 Subject: [PATCH 0277/1788] stm32/rtc: Remove non-ASCII mu-character from source code comment. And fix a typo in the comment on this line. --- ports/stm32/rtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/rtc.c b/ports/stm32/rtc.c index 8e56e25f9f..4b9fbbda52 100644 --- a/ports/stm32/rtc.c +++ b/ports/stm32/rtc.c @@ -52,7 +52,7 @@ static mp_uint_t rtc_info; // Note: LSI is around (32KHz), these dividers should work either way // ck_spre(1Hz) = RTCCLK(LSE) /(uwAsynchPrediv + 1)*(uwSynchPrediv + 1) // modify RTC_ASYNCH_PREDIV & RTC_SYNCH_PREDIV in board//mpconfigport.h to change sub-second ticks -// default is 3906.25 µs, min is ~30.52 µs (will increas Ivbat by ~500nA) +// default is 3906.25 us, min is ~30.52 us (will increase Ivbat by ~500nA) #ifndef RTC_ASYNCH_PREDIV #define RTC_ASYNCH_PREDIV (0x7f) #endif From 673e154dfef6aef827b86ea177c211269358b282 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 12 Apr 2019 11:34:52 +1000 Subject: [PATCH 0278/1788] py/makedefs: Use io.open with utf-8 encoding when processing source. In case (user) source code contains utf-8 encoded data and the default locale is not utf-8. See #4592. --- py/makemoduledefs.py | 3 ++- py/makeqstrdefs.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/py/makemoduledefs.py b/py/makemoduledefs.py index 18d327f002..f17b0e38df 100644 --- a/py/makemoduledefs.py +++ b/py/makemoduledefs.py @@ -8,6 +8,7 @@ from __future__ import print_function import re +import io import os import argparse @@ -49,7 +50,7 @@ def find_module_registrations(c_file): # No c file to match the object file, skip return set() - with open(c_file) as c_file_obj: + with io.open(c_file, encoding='utf-8') as c_file_obj: return set(re.findall(pattern, c_file_obj.read())) diff --git a/py/makeqstrdefs.py b/py/makeqstrdefs.py index 176440136d..457bdeef65 100644 --- a/py/makeqstrdefs.py +++ b/py/makeqstrdefs.py @@ -9,6 +9,7 @@ from __future__ import print_function import re import sys +import io import os # Blacklist of qstrings that are specially handled in further @@ -108,7 +109,7 @@ if __name__ == "__main__": pass if args.command == "split": - with open(args.input_filename) as infile: + with io.open(args.input_filename, encoding='utf-8') as infile: process_file(infile) if args.command == "cat": From 1754c71f45b6c56b55f5e9e0bb7e77c8083c96bb Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 14 Apr 2019 23:32:53 +1000 Subject: [PATCH 0279/1788] py/runtime: Optimise to not create temp float for int to power negative. --- py/runtime.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/py/runtime.c b/py/runtime.c index 75d50596e4..9210070de3 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -456,8 +456,7 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { case MP_BINARY_OP_INPLACE_POWER: if (rhs_val < 0) { #if MICROPY_PY_BUILTINS_FLOAT - lhs = mp_obj_new_float(lhs_val); - goto generic_binary_op; + return mp_obj_float_binary_op(op, lhs_val, rhs); #else mp_raise_ValueError("negative power with no float support"); #endif From 3fa06cf61e6a94417402c4a074e326ccea9cd9d8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 15 Apr 2019 11:14:22 +1000 Subject: [PATCH 0280/1788] py/objset: Remove unused forward declaration and clean up whitespace. --- py/objset.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/py/objset.c b/py/objset.c index 88e9d5cc6f..6f5bcc032a 100644 --- a/py/objset.c +++ b/py/objset.c @@ -45,8 +45,6 @@ typedef struct _mp_obj_set_it_t { size_t cur; } mp_obj_set_it_t; -STATIC mp_obj_t set_it_iternext(mp_obj_t self_in); - STATIC bool is_set_or_frozenset(mp_obj_t o) { return mp_obj_is_type(o, &mp_type_set) #if MICROPY_PY_BUILTINS_FROZENSET @@ -154,7 +152,6 @@ STATIC mp_obj_t set_getiter(mp_obj_t set_in, mp_obj_iter_buf_t *iter_buf) { return MP_OBJ_FROM_PTR(o); } - /******************************************************************************/ /* set methods */ @@ -169,9 +166,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_add_obj, set_add); STATIC mp_obj_t set_clear(mp_obj_t self_in) { check_set(self_in); mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); - mp_set_clear(&self->set); - return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(set_clear_obj, set_clear); @@ -332,6 +327,7 @@ STATIC mp_obj_t set_issubset_internal(mp_obj_t self_in, mp_obj_t other_in, bool } return out; } + STATIC mp_obj_t set_issubset(mp_obj_t self_in, mp_obj_t other_in) { return set_issubset_internal(self_in, other_in, false); } @@ -518,7 +514,6 @@ STATIC mp_obj_t set_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { /******************************************************************************/ /* set constructors & public C API */ - STATIC const mp_rom_map_elem_t set_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_add), MP_ROM_PTR(&set_add_obj) }, { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&set_clear_obj) }, @@ -539,7 +534,6 @@ STATIC const mp_rom_map_elem_t set_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&set_update_obj) }, { MP_ROM_QSTR(MP_QSTR___contains__), MP_ROM_PTR(&mp_op_contains_obj) }, }; - STATIC MP_DEFINE_CONST_DICT(set_locals_dict, set_locals_dict_table); const mp_obj_type_t mp_type_set = { From 9ce25d70220853faee5c817f9e8d75e265cf73ee Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 15 Apr 2019 11:30:19 +1000 Subject: [PATCH 0281/1788] py/runtime: Fix mp_unpack_ex so seq can't be reclaimed by GC during use. The issue described in the comment added here can be seen by forcing a gc_collect() at the start of each call to gc_alloc(). --- py/runtime.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/py/runtime.c b/py/runtime.c index 9210070de3..a3628eecb4 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -875,8 +875,12 @@ void mp_unpack_ex(mp_obj_t seq_in, size_t num_in, mp_obj_t *items) { DEBUG_OP_printf("unpack ex " UINT_FMT " " UINT_FMT "\n", num_left, num_right); size_t seq_len; if (mp_obj_is_type(seq_in, &mp_type_tuple) || mp_obj_is_type(seq_in, &mp_type_list)) { + // Make the seq variable volatile so the compiler keeps a reference to it, + // since if it's a tuple then seq_items points to the interior of the GC cell + // and mp_obj_new_list may trigger a GC which doesn't trace this and reclaims seq. + volatile mp_obj_t seq = seq_in; mp_obj_t *seq_items; - mp_obj_get_array(seq_in, &seq_len, &seq_items); + mp_obj_get_array(seq, &seq_len, &seq_items); if (seq_len < num_left + num_right) { goto too_short; } @@ -887,6 +891,7 @@ void mp_unpack_ex(mp_obj_t seq_in, size_t num_in, mp_obj_t *items) { for (size_t i = 0; i < num_left; i++) { items[num_right + 1 + i] = seq_items[num_left - 1 - i]; } + seq = MP_OBJ_NULL; } else { // Generic iterable; this gets a bit messy: we unpack known left length to the // items destination array, then the rest to a dynamically created list. Once the From 194d6b6788e73216b9c0b60ced0b9ade1b0cb2dd Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 15 Apr 2019 11:41:03 +1000 Subject: [PATCH 0282/1788] stm32/timer: Correctly initialise extended break settings on F7/H7/L4. Fixes issue #4693. --- ports/stm32/timer.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ports/stm32/timer.c b/ports/stm32/timer.c index b3bb92f2e5..7f4c0d85a9 100644 --- a/ports/stm32/timer.c +++ b/ports/stm32/timer.c @@ -476,6 +476,12 @@ STATIC void config_deadtime(pyb_timer_obj_t *self, mp_int_t ticks, mp_int_t brk) deadTimeConfig.DeadTime = compute_dtg_from_ticks(ticks); deadTimeConfig.BreakState = brk == BRK_OFF ? TIM_BREAK_DISABLE : TIM_BREAK_ENABLE; deadTimeConfig.BreakPolarity = brk == BRK_LOW ? TIM_BREAKPOLARITY_LOW : TIM_BREAKPOLARITY_HIGH; + #if defined(STM32F7) || defined(STM32H7) | defined(STM32L4) + deadTimeConfig.BreakFilter = 0; + deadTimeConfig.Break2State = TIM_BREAK_DISABLE; + deadTimeConfig.Break2Polarity = TIM_BREAKPOLARITY_LOW; + deadTimeConfig.Break2Filter = 0; + #endif deadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; HAL_TIMEx_ConfigBreakDeadTime(&self->tim, &deadTimeConfig); } From fd58136d6bffe422f4afb6bc08973ecfb6ff8f1d Mon Sep 17 00:00:00 2001 From: Daniel O'Connor Date: Sat, 13 Apr 2019 21:27:22 +0930 Subject: [PATCH 0283/1788] docs/cmodules: Fix example to globally define MODULE_EXAMPLE_ENABLED. MODULE_EXAMPLE_ENABLED must be globally defined for the module to be seen and referenced by all parts of the code. --- docs/develop/cmodules.rst | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/develop/cmodules.rst b/docs/develop/cmodules.rst index 919f518242..5c0b498ff5 100644 --- a/docs/develop/cmodules.rst +++ b/docs/develop/cmodules.rst @@ -71,8 +71,6 @@ Directory:: #include "py/runtime.h" #include "py/builtin.h" - #define MODULE_EXAMPLE_ENABLED (1) - // This is the function which will be called from Python as example.add_ints(a, b). STATIC mp_obj_t example_add_ints(mp_obj_t a_obj, mp_obj_t b_obj) { // Extract the ints from the micropython input objects @@ -119,6 +117,14 @@ Directory:: # This is not actually needed in this example. CFLAGS_USERMOD += -I$(EXAMPLE_MOD_DIR) +Finally you will need to modify the ``mpconfigboard.h`` for your board +to tell the build process to include the new module by adding the +following + +.. code-block:: c + + #define MODULE_EXAMPLE_ENABLED (1) + Compiling the cmodule into MicroPython -------------------------------------- From a6e5846ba75d20df1795f75423535d9bc280c804 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 11 Apr 2019 11:03:05 +0200 Subject: [PATCH 0284/1788] extmod/modurandom: Add init method to seed the Yasmarang generator. In CPython the random module is seeded differently on each import, and so this new macro option MICROPY_PY_URANDOM_SEED_INIT_FUNC allows to implement such a behaviour. --- extmod/modurandom.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/extmod/modurandom.c b/extmod/modurandom.c index 1512a3fd4a..2e667570d6 100644 --- a/extmod/modurandom.c +++ b/extmod/modurandom.c @@ -200,8 +200,19 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_urandom_uniform_obj, mod_urandom_uniform); #endif // MICROPY_PY_URANDOM_EXTRA_FUNCS +#ifdef MICROPY_PY_URANDOM_SEED_INIT_FUNC +STATIC mp_obj_t mod_urandom___init__() { + mod_urandom_seed(MP_OBJ_NEW_SMALL_INT(MICROPY_PY_URANDOM_SEED_INIT_FUNC)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_urandom___init___obj, mod_urandom___init__); +#endif + STATIC const mp_rom_map_elem_t mp_module_urandom_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_urandom) }, + #ifdef MICROPY_PY_URANDOM_SEED_INIT_FUNC + { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&mod_urandom___init___obj) }, + #endif { MP_ROM_QSTR(MP_QSTR_getrandbits), MP_ROM_PTR(&mod_urandom_getrandbits_obj) }, { MP_ROM_QSTR(MP_QSTR_seed), MP_ROM_PTR(&mod_urandom_seed_obj) }, #if MICROPY_PY_URANDOM_EXTRA_FUNCS From d4e182039f61979b22071274149b0ffcea17c370 Mon Sep 17 00:00:00 2001 From: Daniel O'Connor Date: Mon, 15 Apr 2019 14:31:15 +0930 Subject: [PATCH 0285/1788] docs/cmodules: Note the various ways MODULE_EXAMPLE_ENABLED can be set. --- docs/develop/cmodules.rst | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/develop/cmodules.rst b/docs/develop/cmodules.rst index 5c0b498ff5..ba43c3dc93 100644 --- a/docs/develop/cmodules.rst +++ b/docs/develop/cmodules.rst @@ -117,14 +117,19 @@ Directory:: # This is not actually needed in this example. CFLAGS_USERMOD += -I$(EXAMPLE_MOD_DIR) -Finally you will need to modify the ``mpconfigboard.h`` for your board -to tell the build process to include the new module by adding the -following +Finally you will need to define ``MODULE_EXAMPLE_ENABLED`` to 1. This +can be done by adding ``CFLAGS_EXTRA=-DMODULE_EXAMPLE_ENABLED=1`` to +the ``make`` command, or editing ``mpconfigport.h`` or +``mpconfigboard.h`` to add .. code-block:: c #define MODULE_EXAMPLE_ENABLED (1) +Note that the exact method depends on the port as they have different +structures. If not done correctly it will compile but importing will +fail to find the module. + Compiling the cmodule into MicroPython -------------------------------------- @@ -152,7 +157,7 @@ Building for stm32 port: .. code-block:: bash cd my_project/micropython/ports/stm32 - make USER_C_MODULES=../../../modules all + make USER_C_MODULES=../../../modules CFLAGS_EXTRA=-DMODULE_EXAMPLE_ENABLED=1 all Module usage in MicroPython From 4ce0091449052daca592f852a31eece074d34a57 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 18 Apr 2019 14:16:11 +1000 Subject: [PATCH 0286/1788] esp32/README: Add info about pyparsing and the correct Python version. See issue #4655. --- ports/esp32/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ports/esp32/README.md b/ports/esp32/README.md index 0e6531db82..cd3d5af198 100644 --- a/ports/esp32/README.md +++ b/ports/esp32/README.md @@ -48,12 +48,12 @@ If you use WSL then follow the [Linux guidelines](https://esp-idf.readthedocs.io/en/latest/get-started/linux-setup.html) for the ESP-IDF instead of the Windows ones. -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: +You will also need either Python 2 or Python 3, along with the `pyserial` and +`pyparsing` packages installed for the version of Python that you will be using +(when building you can use, eg, `make PYTHON=python2` to specify the version +used). To install the required packages do: ```bash -$ pip install pyserial +$ pip install pyserial pyparsing ``` Once everything is set up you should have a functioning toolchain with From eb1f81b209f0d13059ebb4fa2ed105a0d6a4b0d0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 18 Apr 2019 14:34:12 +1000 Subject: [PATCH 0287/1788] tests/micropython: Add some tests for failed heap allocation. This adds tests for some locations in the code where a memory allocation should raise an exception. --- tests/micropython/heapalloc_fail_bytearray.py | 90 +++++++++++++++++++ .../heapalloc_fail_bytearray.py.exp | 11 +++ tests/micropython/heapalloc_fail_dict.py | 21 +++++ tests/micropython/heapalloc_fail_dict.py.exp | 2 + tests/micropython/heapalloc_fail_list.py | 36 ++++++++ tests/micropython/heapalloc_fail_list.py.exp | 4 + .../micropython/heapalloc_fail_memoryview.py | 25 ++++++ .../heapalloc_fail_memoryview.py.exp | 2 + tests/micropython/heapalloc_fail_set.py | 21 +++++ tests/micropython/heapalloc_fail_set.py.exp | 2 + tests/micropython/heapalloc_fail_tuple.py | 12 +++ tests/micropython/heapalloc_fail_tuple.py.exp | 1 + 12 files changed, 227 insertions(+) create mode 100644 tests/micropython/heapalloc_fail_bytearray.py create mode 100644 tests/micropython/heapalloc_fail_bytearray.py.exp create mode 100644 tests/micropython/heapalloc_fail_dict.py create mode 100644 tests/micropython/heapalloc_fail_dict.py.exp create mode 100644 tests/micropython/heapalloc_fail_list.py create mode 100644 tests/micropython/heapalloc_fail_list.py.exp create mode 100644 tests/micropython/heapalloc_fail_memoryview.py create mode 100644 tests/micropython/heapalloc_fail_memoryview.py.exp create mode 100644 tests/micropython/heapalloc_fail_set.py create mode 100644 tests/micropython/heapalloc_fail_set.py.exp create mode 100644 tests/micropython/heapalloc_fail_tuple.py create mode 100644 tests/micropython/heapalloc_fail_tuple.py.exp diff --git a/tests/micropython/heapalloc_fail_bytearray.py b/tests/micropython/heapalloc_fail_bytearray.py new file mode 100644 index 0000000000..fbf585c7f1 --- /dev/null +++ b/tests/micropython/heapalloc_fail_bytearray.py @@ -0,0 +1,90 @@ +# test handling of failed heap allocation with bytearray + +import micropython + +class GetSlice: + def __getitem__(self, idx): + return idx +sl = GetSlice()[:] + +# create bytearray +micropython.heap_lock() +try: + bytearray(4) +except MemoryError: + print('MemoryError: bytearray create') +micropython.heap_unlock() + +# create bytearray from bytes +micropython.heap_lock() +try: + bytearray(b'0123') +except MemoryError: + print('MemoryError: bytearray create from bytes') +micropython.heap_unlock() + +# create bytearray from iterator +r = range(4) +micropython.heap_lock() +try: + bytearray(r) +except MemoryError: + print('MemoryError: bytearray create from iter') +micropython.heap_unlock() + +# bytearray add +b = bytearray(4) +micropython.heap_lock() +try: + b + b'01' +except MemoryError: + print('MemoryError: bytearray.__add__') +micropython.heap_unlock() + +# bytearray iadd +b = bytearray(4) +micropython.heap_lock() +try: + b += b'01234567' +except MemoryError: + print('MemoryError: bytearray.__iadd__') +micropython.heap_unlock() +print(b) + +# bytearray append +b = bytearray(4) +micropython.heap_lock() +try: + for i in range(100): + b.append(1) +except MemoryError: + print('MemoryError: bytearray.append') +micropython.heap_unlock() + +# bytearray extend +b = bytearray(4) +micropython.heap_lock() +try: + b.extend(b'01234567') +except MemoryError: + print('MemoryError: bytearray.extend') +micropython.heap_unlock() + +# bytearray get with slice +b = bytearray(4) +micropython.heap_lock() +try: + b[sl] +except MemoryError: + print('MemoryError: bytearray subscr get') +micropython.heap_unlock() + +# extend bytearray using slice subscr +b = bytearray(4) +micropython.heap_lock() +try: + b[sl] = b'01234567' +except MemoryError: + print('MemoryError: bytearray subscr grow') +micropython.heap_unlock() +print(b) diff --git a/tests/micropython/heapalloc_fail_bytearray.py.exp b/tests/micropython/heapalloc_fail_bytearray.py.exp new file mode 100644 index 0000000000..57f6202f5e --- /dev/null +++ b/tests/micropython/heapalloc_fail_bytearray.py.exp @@ -0,0 +1,11 @@ +MemoryError: bytearray create +MemoryError: bytearray create from bytes +MemoryError: bytearray create from iter +MemoryError: bytearray.__add__ +MemoryError: bytearray.__iadd__ +bytearray(b'\x00\x00\x00\x00') +MemoryError: bytearray.append +MemoryError: bytearray.extend +MemoryError: bytearray subscr get +MemoryError: bytearray subscr grow +bytearray(b'\x00\x00\x00\x00') diff --git a/tests/micropython/heapalloc_fail_dict.py b/tests/micropython/heapalloc_fail_dict.py new file mode 100644 index 0000000000..ba872bfeb6 --- /dev/null +++ b/tests/micropython/heapalloc_fail_dict.py @@ -0,0 +1,21 @@ +# test handling of failed heap allocation with dict + +import micropython + +# create dict +x = 1 +micropython.heap_lock() +try: + {x:x} +except MemoryError: + print('MemoryError: create dict') +micropython.heap_unlock() + +# create dict view +x = {1:1} +micropython.heap_lock() +try: + x.items() +except MemoryError: + print('MemoryError: dict.items') +micropython.heap_unlock() diff --git a/tests/micropython/heapalloc_fail_dict.py.exp b/tests/micropython/heapalloc_fail_dict.py.exp new file mode 100644 index 0000000000..70cfc64ba4 --- /dev/null +++ b/tests/micropython/heapalloc_fail_dict.py.exp @@ -0,0 +1,2 @@ +MemoryError: create dict +MemoryError: dict.items diff --git a/tests/micropython/heapalloc_fail_list.py b/tests/micropython/heapalloc_fail_list.py new file mode 100644 index 0000000000..a54bdb6cf6 --- /dev/null +++ b/tests/micropython/heapalloc_fail_list.py @@ -0,0 +1,36 @@ +# test handling of failed heap allocation with list + +import micropython + +class GetSlice: + def __getitem__(self, idx): + return idx +sl = GetSlice()[:] + +# create slice in VM +l = [1, 2, 3] +micropython.heap_lock() +try: + print(l[0:1]) +except MemoryError: + print('MemoryError: list index') +micropython.heap_unlock() + +# get from list using slice +micropython.heap_lock() +try: + l[sl] +except MemoryError: + print('MemoryError: list get slice') +micropython.heap_unlock() + +# extend list using slice subscr +l = [1, 2] +l2 = [3, 4, 5, 6, 7, 8, 9, 10] +micropython.heap_lock() +try: + l[sl] = l2 +except MemoryError: + print('MemoryError: list extend slice') +micropython.heap_unlock() +print(l) diff --git a/tests/micropython/heapalloc_fail_list.py.exp b/tests/micropython/heapalloc_fail_list.py.exp new file mode 100644 index 0000000000..0e1637476b --- /dev/null +++ b/tests/micropython/heapalloc_fail_list.py.exp @@ -0,0 +1,4 @@ +MemoryError: list index +MemoryError: list get slice +MemoryError: list extend slice +[1, 2] diff --git a/tests/micropython/heapalloc_fail_memoryview.py b/tests/micropython/heapalloc_fail_memoryview.py new file mode 100644 index 0000000000..3ba9015ff1 --- /dev/null +++ b/tests/micropython/heapalloc_fail_memoryview.py @@ -0,0 +1,25 @@ +# test handling of failed heap allocation with memoryview + +import micropython + +class GetSlice: + def __getitem__(self, idx): + return idx +sl = GetSlice()[:] + +# create memoryview +micropython.heap_lock() +try: + memoryview(b'') +except MemoryError: + print('MemoryError: memoryview create') +micropython.heap_unlock() + +# memoryview get with slice +m = memoryview(b'') +micropython.heap_lock() +try: + m[sl] +except MemoryError: + print('MemoryError: memoryview subscr get') +micropython.heap_unlock() diff --git a/tests/micropython/heapalloc_fail_memoryview.py.exp b/tests/micropython/heapalloc_fail_memoryview.py.exp new file mode 100644 index 0000000000..e41a1e6cb2 --- /dev/null +++ b/tests/micropython/heapalloc_fail_memoryview.py.exp @@ -0,0 +1,2 @@ +MemoryError: memoryview create +MemoryError: memoryview subscr get diff --git a/tests/micropython/heapalloc_fail_set.py b/tests/micropython/heapalloc_fail_set.py new file mode 100644 index 0000000000..98e615d64a --- /dev/null +++ b/tests/micropython/heapalloc_fail_set.py @@ -0,0 +1,21 @@ +# test handling of failed heap allocation with set + +import micropython + +# create set +x = 1 +micropython.heap_lock() +try: + {x,} +except MemoryError: + print('MemoryError: set create') +micropython.heap_unlock() + +# set copy +s = {1, 2} +micropython.heap_lock() +try: + s.copy() +except MemoryError: + print('MemoryError: set copy') +micropython.heap_unlock() diff --git a/tests/micropython/heapalloc_fail_set.py.exp b/tests/micropython/heapalloc_fail_set.py.exp new file mode 100644 index 0000000000..dd749672dc --- /dev/null +++ b/tests/micropython/heapalloc_fail_set.py.exp @@ -0,0 +1,2 @@ +MemoryError: set create +MemoryError: set copy diff --git a/tests/micropython/heapalloc_fail_tuple.py b/tests/micropython/heapalloc_fail_tuple.py new file mode 100644 index 0000000000..1cd23fb74b --- /dev/null +++ b/tests/micropython/heapalloc_fail_tuple.py @@ -0,0 +1,12 @@ +# test handling of failed heap allocation with tuple + +import micropython + +# create tuple +x = 1 +micropython.heap_lock() +try: + (x,) +except MemoryError: + print('MemoryError: tuple create') +micropython.heap_unlock() diff --git a/tests/micropython/heapalloc_fail_tuple.py.exp b/tests/micropython/heapalloc_fail_tuple.py.exp new file mode 100644 index 0000000000..5bf632d799 --- /dev/null +++ b/tests/micropython/heapalloc_fail_tuple.py.exp @@ -0,0 +1 @@ +MemoryError: tuple create From f1774fa049afc6f35192ff0f60ac5486cd9d3b08 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 18 Apr 2019 15:36:59 +1000 Subject: [PATCH 0288/1788] stm32/system_stm32f0: Enable PWR clock on startup. To be consistent with how F4/F7/H7/L4 works in system_stm32.c. The power control peripheral is needed at least for the RTC. --- ports/stm32/system_stm32f0.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ports/stm32/system_stm32f0.c b/ports/stm32/system_stm32f0.c index 9d4b06e568..afabdb667f 100644 --- a/ports/stm32/system_stm32f0.c +++ b/ports/stm32/system_stm32f0.c @@ -129,6 +129,9 @@ void SystemInit(void) { } void SystemClock_Config(void) { + // Enable power control peripheral + __HAL_RCC_PWR_CLK_ENABLE(); + // Set flash latency to 1 because SYSCLK > 24MHz FLASH->ACR = (FLASH->ACR & ~0x7) | 0x1; From 11657f2f20c869212364efa8633a7870c9be0c3c Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 18 Apr 2019 15:59:47 +1000 Subject: [PATCH 0289/1788] stm32/system_stm32f0: Add support for using HSE and PLL as SYSCLK. To configure the SYSCLK on an F0 enable one of: MICROPY_HW_CLK_USE_HSI48 MICROPY_HW_CLK_USE_HSE MICROPY_HW_CLK_USE_BYPASS --- .../boards/NUCLEO_F091RC/mpconfigboard.h | 1 + ports/stm32/system_stm32f0.c | 31 +++++++++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h index 5e67916cbc..e1802da2da 100644 --- a/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h @@ -17,6 +17,7 @@ #define MICROPY_HW_HAS_SWITCH (1) // For system clock, board uses internal 48MHz, HSI48 +#define MICROPY_HW_CLK_USE_HSI48 (1) // The board has an external 32kHz crystal #define MICROPY_HW_RTC_USE_LSE (1) diff --git a/ports/stm32/system_stm32f0.c b/ports/stm32/system_stm32f0.c index afabdb667f..c3c675c745 100644 --- a/ports/stm32/system_stm32f0.c +++ b/ports/stm32/system_stm32f0.c @@ -40,7 +40,7 @@ ****************************************************************************** */ -#include STM32_HAL_H +#include "py/mphal.h" #ifndef HSE_VALUE #define HSE_VALUE (8000000) @@ -135,12 +135,37 @@ void SystemClock_Config(void) { // Set flash latency to 1 because SYSCLK > 24MHz FLASH->ACR = (FLASH->ACR & ~0x7) | 0x1; + #if MICROPY_HW_CLK_USE_HSI48 // 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) { + const uint32_t sysclk_src = 3; + + #else + // Use HSE and the PLL to get a 48MHz SYSCLK + + #if MICROPY_HW_CLK_USE_BYPASS + RCC->CR |= RCC_CR_HSEBYP; + #endif + RCC->CR |= RCC_CR_HSEON; + while ((RCC->CR & RCC_CR_HSERDY) == 0) { + // Wait for HSE to be ready + } + RCC->CFGR = ((48000000 / HSE_VALUE) - 2) << RCC_CFGR_PLLMUL_Pos | 2 << RCC_CFGR_PLLSRC_Pos; + RCC->CFGR2 = 0; // Input clock not divided + RCC->CR |= RCC_CR_PLLON; // Turn PLL on + while ((RCC->CR & RCC_CR_PLLRDY) == 0) { + // Wait for PLL to lock + } + const uint32_t sysclk_src = 2; + + #endif + + // Select SYSCLK source + RCC->CFGR |= sysclk_src << RCC_CFGR_SW_Pos; + while (((RCC->CFGR >> RCC_CFGR_SWS_Pos) & 0x3) != sysclk_src) { // Wait for SYSCLK source to change } From 8402c26cfa98b4689f5ac4673952a654cfe5b678 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 18 Apr 2019 17:15:11 +1000 Subject: [PATCH 0290/1788] stm32/powerctrl: Enable EIWUP to ensure RTC wakes device from standby. --- ports/stm32/powerctrl.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c index 165919977f..669e568f8a 100644 --- a/ports/stm32/powerctrl.c +++ b/ports/stm32/powerctrl.c @@ -390,6 +390,12 @@ void powerctrl_enter_standby_mode(void) { // enable previously-enabled RTC interrupts RTC->CR |= save_irq_bits; + #if defined(STM32F7) + // Enable the internal (eg RTC) wakeup sources + // See Errata 2.2.2 "Wakeup from Standby mode when the back-up SRAM regulator is enabled" + PWR->CSR1 |= PWR_CSR1_EIWUP; + #endif + // enter standby mode HAL_PWR_EnterSTANDBYMode(); // we never return; MCU is reset on exit from standby From 27d22d8712d79636be7115d47c8872d6c1da749c Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 19 Apr 2019 17:38:27 +1000 Subject: [PATCH 0291/1788] py/mpprint: Support printing %ld and %lu formats on 64-bit archs. Fixes issue #4702. --- py/mpprint.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/py/mpprint.c b/py/mpprint.c index 82e78f62fa..cf09f7bbe2 100644 --- a/py/mpprint.c +++ b/py/mpprint.c @@ -503,22 +503,28 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) { chrs += mp_print_strn(print, str, prec, flags, fill, width); break; } + case 'd': { + mp_int_t val; + if (long_arg) { + val = va_arg(args, long int); + } else { + val = va_arg(args, int); + } + chrs += mp_print_int(print, val, 1, 10, 'a', flags, fill, width); + break; + } case 'u': - chrs += mp_print_int(print, va_arg(args, unsigned int), 0, 10, 'a', flags, fill, width); - break; - case 'd': - chrs += mp_print_int(print, va_arg(args, int), 1, 10, 'a', flags, fill, width); - break; case 'x': case 'X': { - char fmt_c = *fmt - 'X' + 'A'; + int base = 16 - ((*fmt + 1) & 6); // maps char u/x/X to base 10/16/16 + char fmt_c = (*fmt & 0xf0) - 'P' + 'A'; // maps char u/x/X to char a/a/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); + chrs += mp_print_int(print, val, 0, base, fmt_c, flags, fill, width); break; } case 'p': From aa7b32c81136b1250d9515adf9d13eefd81e86d4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 24 Apr 2019 15:51:19 +1000 Subject: [PATCH 0292/1788] stm32/dac: Rework DAC driver to use direct register access. This patch makes the DAC driver simpler and removes the need for the ST HAL. As part of it, new helper functions are added to the DMA driver, which also use direct register access instead of the ST HAL. Main changes to the DAC interface are: - The DAC uPy object is no longer allocated dynamically on the heap, rather it's statically allocated and the same object is retrieved for subsequent uses of pyb.DAC(). This allows to access the DAC objects without resetting the DAC peripheral. It also means that the DAC is only reset if explicitly passed initialisation parameters, like "bits" or "buffering". - The DAC.noise() and DAC.triangle() methods now output a signal which is full scale (previously it was a fraction of the full output voltage). - The DAC.write_timed() method is fixed so that it continues in the background when another peripheral (eg SPI) uses the DMA (previously the DAC would stop if another peripheral finished with the DMA and shut the DMA peripheral off completely). Based on the above, the following backwards incompatibilities are introduced: - pyb.DAC(id) will now only reset the DAC the first time it is called, whereas previously each call to create a DAC object would reset the DAC. To get the old behaviour pass the bits parameter like: pyb.DAC(id, bits). - DAC.noise() and DAC.triangle() are now full scale. To get previous behaviour (to change the amplitude and offset) write to the DAC_CR (MAMP bits) and DAC_DHR12Rx registers manually. --- ports/stm32/Makefile | 2 - ports/stm32/dac.c | 296 ++++++++++++++++++------------------------- ports/stm32/dac.h | 2 - ports/stm32/dma.c | 100 ++++++++++++++- ports/stm32/dma.h | 4 + ports/stm32/main.c | 4 - 6 files changed, 226 insertions(+), 182 deletions(-) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 242ced38cb..d90a7c2e4f 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -296,8 +296,6 @@ SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ hal_adc.c \ hal_adc_ex.c \ hal_cortex.c \ - hal_dac.c \ - hal_dac_ex.c \ hal_dma.c \ hal_flash.c \ hal_flash_ex.c \ diff --git a/ports/stm32/dac.c b/ports/stm32/dac.c index 3a92258ffb..cb9157c3da 100644 --- a/ports/stm32/dac.c +++ b/ports/stm32/dac.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2013-2019 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 @@ -70,15 +70,6 @@ #define DAC DAC1 #endif -STATIC DAC_HandleTypeDef DAC_Handle; - -void dac_init(void) { - memset(&DAC_Handle, 0, sizeof DAC_Handle); - DAC_Handle.Instance = DAC; - DAC_Handle.State = HAL_DAC_STATE_RESET; - HAL_DAC_Init(&DAC_Handle); -} - #if defined(TIM6) STATIC void TIM6_Config(uint freq) { // Init TIM6 at the required frequency (in Hz) @@ -131,27 +122,97 @@ STATIC uint32_t TIMx_Config(mp_obj_t timer) { } } +STATIC void dac_deinit(uint32_t dac_channel) { + DAC->CR &= ~(DAC_CR_EN1 << dac_channel); + #if defined(STM32H7) || defined(STM32L4) + DAC->MCR = (DAC->MCR & ~(DAC_MCR_MODE1_Msk << dac_channel)) | (DAC_OUTPUTBUFFER_DISABLE << dac_channel); + #else + DAC->CR |= DAC_CR_BOFF1 << dac_channel; + #endif +} + +STATIC void dac_config_channel(uint32_t dac_channel, uint32_t trig, uint32_t outbuf) { + DAC->CR &= ~(DAC_CR_EN1 << dac_channel); + uint32_t cr_off = DAC_CR_DMAEN1 | DAC_CR_MAMP1 | DAC_CR_WAVE1 | DAC_CR_TSEL1 | DAC_CR_TEN1; + uint32_t cr_on = trig; + #if defined(STM32H7) || defined(STM32L4) + DAC->MCR = (DAC->MCR & ~(DAC_MCR_MODE1_Msk << dac_channel)) | (outbuf << dac_channel); + #else + cr_off |= DAC_CR_BOFF1; + cr_on |= outbuf; + #endif + DAC->CR = (DAC->CR & ~(cr_off << dac_channel)) | (cr_on << dac_channel); +} + +STATIC void dac_set_value(uint32_t dac_channel, uint32_t align, uint32_t value) { + uint32_t base; + if (dac_channel == DAC_CHANNEL_1) { + base = (uint32_t)&DAC->DHR12R1; + } else { + base = (uint32_t)&DAC->DHR12R2; + } + *(volatile uint32_t*)(base + align) = value; +} + +STATIC void dac_start(uint32_t dac_channel) { + DAC->CR |= DAC_CR_EN1 << dac_channel; +} + +STATIC void dac_start_dma(uint32_t dac_channel, const dma_descr_t *dma_descr, uint32_t dma_mode, uint32_t bit_size, uint32_t dac_align, size_t len, void *buf) { + uint32_t dma_align; + if (bit_size == 8) { + dma_align = DMA_MDATAALIGN_BYTE | DMA_PDATAALIGN_BYTE; + } else { + dma_align = DMA_MDATAALIGN_HALFWORD | DMA_PDATAALIGN_HALFWORD; + } + + uint32_t base; + if (dac_channel == DAC_CHANNEL_1) { + base = (uint32_t)&DAC->DHR12R1; + } else { + base = (uint32_t)&DAC->DHR12R2; + } + + dma_nohal_deinit(dma_descr); + dma_nohal_init(dma_descr, DMA_MEMORY_TO_PERIPH | dma_mode | dma_align); + dma_nohal_start(dma_descr, (uint32_t)buf, base + dac_align, len); + + DAC->CR |= DAC_CR_EN1 << dac_channel; +} + /******************************************************************************/ // MicroPython bindings -typedef enum { - DAC_STATE_RESET, - DAC_STATE_WRITE_SINGLE, - DAC_STATE_BUILTIN_WAVEFORM, - DAC_STATE_DMA_WAVEFORM, // should be last enum since we use space beyond it -} pyb_dac_state_t; - 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; - mp_hal_pin_obj_t pin; // pin_A4 or pin_A5 + uint8_t dac_channel; // DAC_CHANNEL_1 or DAC_CHANNEL_2 uint8_t bits; // 8 or 12 - uint8_t state; uint8_t outbuf_single; uint8_t outbuf_waveform; } pyb_dac_obj_t; +STATIC pyb_dac_obj_t pyb_dac_obj[2]; + +STATIC void pyb_dac_reconfigure(pyb_dac_obj_t *self, uint32_t cr, uint32_t outbuf, uint32_t value) { + bool restart = false; + const uint32_t cr_mask = DAC_CR_DMAEN1 | DAC_CR_MAMP1 | DAC_CR_WAVE1 | DAC_CR_TSEL1 | DAC_CR_TEN1 | DAC_CR_EN1; + if (((DAC->CR >> self->dac_channel) & cr_mask) != (cr | DAC_CR_EN1)) { + const dma_descr_t *tx_dma_descr; + if (self->dac_channel == DAC_CHANNEL_1) { + tx_dma_descr = &dma_DAC_1_TX; + } else { + tx_dma_descr = &dma_DAC_2_TX; + } + dma_nohal_deinit(tx_dma_descr); + dac_config_channel(self->dac_channel, cr, outbuf); + restart = true; + } + dac_set_value(self->dac_channel, DAC_ALIGN_12B_R, value); + if (restart) { + dac_start(self->dac_channel); + } +} + 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)", @@ -170,7 +231,13 @@ 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 - mp_hal_pin_config(self->pin, MP_HAL_PIN_MODE_ANALOG, MP_HAL_PIN_PULL_NONE, 0); + mp_hal_pin_obj_t pin; + if (self->dac_channel == DAC_CHANNEL_1) { + pin = pin_A4; + } else { + pin = pin_A5; + } + mp_hal_pin_config(pin, MP_HAL_PIN_MODE_ANALOG, MP_HAL_PIN_PULL_NONE, 0); // DAC peripheral clock #if defined(STM32F4) || defined(STM32F7) @@ -183,20 +250,8 @@ STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, size_t n_args, const mp #error Unsupported Processor #endif - // stop anything already going on - __HAL_RCC_DMA1_CLK_ENABLE(); - DMA_HandleTypeDef DMA_Handle; - /* Get currently configured dma */ - dma_init_handle(&DMA_Handle, self->tx_dma_descr, DMA_MEMORY_TO_PERIPH, (void*)NULL); - // Need to deinit DMA first - DMA_Handle.State = HAL_DMA_STATE_READY; - HAL_DMA_DeInit(&DMA_Handle); - - HAL_DAC_Stop(&DAC_Handle, self->dac_channel); - if ((self->dac_channel == DAC_CHANNEL_1 && DAC_Handle.DMA_Handle1 != NULL) - || (self->dac_channel == DAC_CHANNEL_2 && DAC_Handle.DMA_Handle2 != NULL)) { - HAL_DAC_Stop_DMA(&DAC_Handle, self->dac_channel); - } + // Stop the DAC in case it was already running + DAC->CR &= ~(DAC_CR_EN1 << self->dac_channel); // set bit resolution if (args[0].u_int == 8 || args[0].u_int == 12) { @@ -218,9 +273,6 @@ STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, size_t n_args, const mp self->outbuf_waveform = DAC_OUTPUTBUFFER_DISABLE; } - // reset state of DAC - self->state = DAC_STATE_RESET; - return mp_const_none; } @@ -251,25 +303,25 @@ STATIC mp_obj_t pyb_dac_make_new(const mp_obj_type_t *type, size_t n_args, size_ } } - pyb_dac_obj_t *dac = m_new_obj(pyb_dac_obj_t); - dac->base.type = &pyb_dac_type; - + uint32_t dac_channel; if (dac_id == 1) { - dac->pin = pin_A4; - dac->dac_channel = DAC_CHANNEL_1; - dac->tx_dma_descr = &dma_DAC_1_TX; + dac_channel = DAC_CHANNEL_1; } else if (dac_id == 2) { - dac->pin = pin_A5; - dac->dac_channel = DAC_CHANNEL_2; - dac->tx_dma_descr = &dma_DAC_2_TX; + dac_channel = DAC_CHANNEL_2; } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "DAC(%d) doesn't exist", dac_id)); } - // configure the peripheral - mp_map_t kw_args; - mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); - pyb_dac_init_helper(dac, n_args - 1, args + 1, &kw_args); + pyb_dac_obj_t *dac = &pyb_dac_obj[dac_id - 1]; + dac->base.type = &pyb_dac_type; + dac->dac_channel = dac_channel; + + if (dac->bits == 0 || n_args > 1 || n_kw > 0) { + // configure the peripheral + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + pyb_dac_init_helper(dac, n_args - 1, args + 1, &kw_args); + } // return object return MP_OBJ_FROM_PTR(dac); @@ -284,21 +336,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_dac_init_obj, 1, pyb_dac_init); /// Turn off the DAC, enable other use of pin. STATIC mp_obj_t pyb_dac_deinit(mp_obj_t self_in) { pyb_dac_obj_t *self = MP_OBJ_TO_PTR(self_in); - if (self->dac_channel == DAC_CHANNEL_1) { - DAC_Handle.Instance->CR &= ~DAC_CR_EN1; - #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; - #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 - } + dac_deinit(self->dac_channel); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_dac_deinit_obj, pyb_dac_deinit); @@ -313,19 +351,9 @@ STATIC mp_obj_t pyb_dac_noise(mp_obj_t self_in, mp_obj_t freq) { // set TIM6 to trigger the DAC at the given frequency TIM6_Config(mp_obj_get_int(freq)); - if (self->state != DAC_STATE_BUILTIN_WAVEFORM) { - // configure DAC to trigger via TIM6 - DAC_ChannelConfTypeDef config; - config.DAC_Trigger = DAC_TRIGGER_T6_TRGO; - config.DAC_OutputBuffer = self->outbuf_waveform; - HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); - self->state = DAC_STATE_BUILTIN_WAVEFORM; - } - - // set noise wave generation - HAL_DACEx_NoiseWaveGenerate(&DAC_Handle, self->dac_channel, DAC_LFSRUNMASK_BITS10_0); - HAL_DAC_SetValue(&DAC_Handle, self->dac_channel, DAC_ALIGN_12B_L, 0x7ff0); - HAL_DAC_Start(&DAC_Handle, self->dac_channel); + // Configure DAC in noise mode with trigger via TIM6 + uint32_t cr = DAC_LFSRUNMASK_BITS11_0 | DAC_CR_WAVE1_0 | DAC_TRIGGER_T6_TRGO; + pyb_dac_reconfigure(self, cr, self->outbuf_waveform, 0); return mp_const_none; } @@ -343,19 +371,9 @@ STATIC mp_obj_t pyb_dac_triangle(mp_obj_t self_in, mp_obj_t freq) { // set TIM6 to trigger the DAC at the given frequency TIM6_Config(mp_obj_get_int(freq)); - if (self->state != DAC_STATE_BUILTIN_WAVEFORM) { - // configure DAC to trigger via TIM6 - DAC_ChannelConfTypeDef config; - config.DAC_Trigger = DAC_TRIGGER_T6_TRGO; - config.DAC_OutputBuffer = self->outbuf_waveform; - HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); - self->state = DAC_STATE_BUILTIN_WAVEFORM; - } - - // set triangle wave generation - HAL_DACEx_TriangleWaveGenerate(&DAC_Handle, self->dac_channel, DAC_TRIANGLEAMPLITUDE_1023); - HAL_DAC_SetValue(&DAC_Handle, self->dac_channel, DAC_ALIGN_12B_R, 0x100); - HAL_DAC_Start(&DAC_Handle, self->dac_channel); + // Configure DAC in triangle mode with trigger via TIM6 + uint32_t cr = DAC_TRIANGLEAMPLITUDE_4095 | DAC_CR_WAVE1_1 | DAC_TRIGGER_T6_TRGO; + pyb_dac_reconfigure(self, cr, self->outbuf_waveform, 0); return mp_const_none; } @@ -367,20 +385,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_dac_triangle_obj, pyb_dac_triangle); STATIC mp_obj_t pyb_dac_write(mp_obj_t self_in, mp_obj_t val) { pyb_dac_obj_t *self = MP_OBJ_TO_PTR(self_in); - if (self->state != DAC_STATE_WRITE_SINGLE) { - DAC_ChannelConfTypeDef config; - config.DAC_Trigger = DAC_TRIGGER_NONE; - config.DAC_OutputBuffer = self->outbuf_single; - HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); - self->state = DAC_STATE_WRITE_SINGLE; - } - // DAC output is always 12-bit at the hardware level, and we provide support // for multiple bit "resolutions" simply by shifting the input value. - HAL_DAC_SetValue(&DAC_Handle, self->dac_channel, DAC_ALIGN_12B_R, - mp_obj_get_int(val) << (12 - self->bits)); - - HAL_DAC_Start(&DAC_Handle, self->dac_channel); + uint32_t cr = DAC_TRIGGER_NONE; + uint32_t value = mp_obj_get_int(val) << (12 - self->bits); + pyb_dac_reconfigure(self, cr, self->outbuf_single, value); return mp_const_none; } @@ -432,83 +441,24 @@ 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); } - __HAL_RCC_DMA1_CLK_ENABLE(); - - DMA_HandleTypeDef DMA_Handle; - /* Get currently configured dma */ - dma_init_handle(&DMA_Handle, self->tx_dma_descr, DMA_MEMORY_TO_PERIPH, (void*)NULL); - /* - DMA_Cmd(DMA_Handle->Instance, DISABLE); - while (DMA_GetCmdStatus(DMA_Handle->Instance) != DISABLE) { - } - - DAC_Cmd(self->dac_channel, DISABLE); - */ - - /* - // DAC channel configuration - DAC_InitTypeDef DAC_InitStructure; - DAC_InitStructure.DAC_Trigger = DAC_Trigger_T7_TRGO; - DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None; - DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_TriangleAmplitude_1; // unused, but need to set it to a valid value - DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; - DAC_Init(self->dac_channel, &DAC_InitStructure); - */ - - // Need to deinit DMA first - DMA_Handle.State = HAL_DMA_STATE_READY; - HAL_DMA_DeInit(&DMA_Handle); - - if (self->bits == 8) { - DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; - DMA_Handle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; - } else { - DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; - DMA_Handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; - } - DMA_Handle.Init.Mode = args[2].u_int; - HAL_DMA_Init(&DMA_Handle); + dac_config_channel(self->dac_channel, DAC_CR_DMAEN1 | dac_trigger, self->outbuf_waveform); + const dma_descr_t *tx_dma_descr; if (self->dac_channel == DAC_CHANNEL_1) { - __HAL_LINKDMA(&DAC_Handle, DMA_Handle1, DMA_Handle); + tx_dma_descr = &dma_DAC_1_TX; } else { - __HAL_LINKDMA(&DAC_Handle, DMA_Handle2, DMA_Handle); - } - - DAC_Handle.Instance = DAC; - DAC_Handle.State = HAL_DAC_STATE_RESET; - HAL_DAC_Init(&DAC_Handle); - - if (self->state != DAC_STATE_DMA_WAVEFORM + dac_trigger) { - DAC_ChannelConfTypeDef config; - config.DAC_Trigger = dac_trigger; - config.DAC_OutputBuffer = self->outbuf_waveform; - HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); - self->state = DAC_STATE_DMA_WAVEFORM + dac_trigger; + tx_dma_descr = &dma_DAC_2_TX; } + uint32_t align; if (self->bits == 8) { - HAL_DAC_Start_DMA(&DAC_Handle, self->dac_channel, - (uint32_t*)bufinfo.buf, bufinfo.len, DAC_ALIGN_8B_R); + align = DAC_ALIGN_8B_R; } else { - HAL_DAC_Start_DMA(&DAC_Handle, self->dac_channel, - (uint32_t*)bufinfo.buf, bufinfo.len / 2, DAC_ALIGN_12B_R); + align = DAC_ALIGN_12B_R; + bufinfo.len /= 2; } - /* - // enable DMA stream - DMA_Cmd(DMA_Handle->Instance, ENABLE); - while (DMA_GetCmdStatus(DMA_Handle->Instance) == DISABLE) { - } - - // enable DAC channel - DAC_Cmd(self->dac_channel, ENABLE); - - // enable DMA for DAC channel - DAC_DMACmd(self->dac_channel, ENABLE); - */ - - //printf("DMA: %p %lu\n", bufinfo.buf, bufinfo.len); + dac_start_dma(self->dac_channel, tx_dma_descr, args[2].u_int, self->bits, align, bufinfo.len, bufinfo.buf); return mp_const_none; } diff --git a/ports/stm32/dac.h b/ports/stm32/dac.h index 1d8f0ab61e..fca36e019e 100644 --- a/ports/stm32/dac.h +++ b/ports/stm32/dac.h @@ -26,8 +26,6 @@ #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_STM32_DAC_H diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c index 3b8b74081c..a4ddcc42f9 100644 --- a/ports/stm32/dma.c +++ b/ports/stm32/dma.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2015 Damien P. George + * Copyright (c) 2015-2019 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,6 +29,7 @@ #include #include "py/obj.h" +#include "py/mphal.h" #include "systick.h" #include "dma.h" #include "irq.h" @@ -729,3 +730,100 @@ static void dma_idle_handler(uint32_t tick) { } } } + +#if defined(STM32F0) || defined(STM32L4) + +void dma_nohal_init(const dma_descr_t *descr, uint32_t config) { + DMA_Channel_TypeDef *dma = descr->instance; + + // Enable the DMA peripheral + dma_enable_clock(descr->id); + + // Set main configuration register + dma->CCR = + descr->init->Priority // PL + | descr->init->MemInc // MINC + | descr->init->PeriphInc // PINC + | config // MSIZE | PSIZE | CIRC | DIR + ; + + // Select channel that the DMA stream uses + #if defined(STM32F0) + if (dma < DMA2_Channel1) { + __HAL_DMA1_REMAP(descr->sub_instance); + } else { + __HAL_DMA2_REMAP(descr->sub_instance); + } + #else + DMA_Request_TypeDef *dma_ctrl = (void*)(((uint32_t)dma & ~0xff) + (DMA1_CSELR_BASE - DMA1_BASE)); // DMA1_CSELR or DMA2_CSELR + uint32_t channel_number = (((uint32_t)dma & 0xff) - 0x08) / 20; // 0 through 6 + uint32_t channel_pos = channel_number * 4; + dma_ctrl->CSELR = (dma_ctrl->CSELR & ~(0xf << channel_pos)) | (descr->sub_instance << channel_pos); + #endif +} + +void dma_nohal_deinit(const dma_descr_t *descr) { + DMA_Channel_TypeDef *dma = descr->instance; + dma->CCR &= ~DMA_CCR_EN; + dma->CCR = 0; + dma->CNDTR = 0; + dma_deinit(descr); +} + +void dma_nohal_start(const dma_descr_t *descr, uint32_t src_addr, uint32_t dst_addr, uint16_t len) { + DMA_Channel_TypeDef *dma = descr->instance; + dma->CNDTR = len; + dma->CPAR = dst_addr; + dma->CMAR = src_addr; + dma->CCR |= DMA_CCR_EN; +} + +#else + +void dma_nohal_init(const dma_descr_t *descr, uint32_t config) { + DMA_Stream_TypeDef *dma = descr->instance; + + // Enable the DMA peripheral + dma_enable_clock(descr->id); + + // Set main configuration register + const DMA_InitTypeDef *init = descr->init; + dma->CR = + descr->sub_instance // CHSEL + | init->MemBurst // MBURST + | init->PeriphBurst // PBURST + | init->Priority // PL + | init->MemInc // MINC + | init->PeriphInc // PINC + | config // MSIZE | PSIZE | CIRC | DIR + ; + + // Set FIFO control register + dma->FCR = + init->FIFOMode // DMDIS + | init->FIFOThreshold // FTH + ; +} + +void dma_nohal_deinit(const dma_descr_t *descr) { + DMA_Stream_TypeDef *dma = descr->instance; + dma->CR &= ~DMA_SxCR_EN; + uint32_t t0 = mp_hal_ticks_ms(); + while ((dma->CR & DMA_SxCR_EN) && mp_hal_ticks_ms() - t0 < 100) { + } + dma->CR = 0; + dma->NDTR = 0; + dma->FCR = 0x21; + dma_deinit(descr); +} + +void dma_nohal_start(const dma_descr_t *descr, uint32_t src_addr, uint32_t dst_addr, uint16_t len) { + DMA_Stream_TypeDef *dma = descr->instance; + dma->CR &= ~DMA_SxCR_DBM; + dma->NDTR = len; + dma->PAR = dst_addr; + dma->M0AR = src_addr; + dma->CR |= DMA_SxCR_EN; +} + +#endif diff --git a/ports/stm32/dma.h b/ports/stm32/dma.h index 73cb9c3282..7b74a73993 100644 --- a/ports/stm32/dma.h +++ b/ports/stm32/dma.h @@ -86,4 +86,8 @@ void dma_init_handle(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint3 void dma_deinit(const dma_descr_t *dma_descr); void dma_invalidate_channel(const dma_descr_t *dma_descr); +void dma_nohal_init(const dma_descr_t *descr, uint32_t config); +void dma_nohal_deinit(const dma_descr_t *descr); +void dma_nohal_start(const dma_descr_t *descr, uint32_t src_addr, uint32_t dst_addr, uint16_t len); + #endif // MICROPY_INCLUDED_STM32_DMA_H diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 8c2d7d529a..6fa6a6267f 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -721,10 +721,6 @@ soft_reset: servo_init(); #endif - #if MICROPY_HW_ENABLE_DAC - dac_init(); - #endif - #if MICROPY_PY_NETWORK mod_network_init(); #endif From 56f6ceba7f6e86a47680660dbfe81a0a64682eaf Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 25 Apr 2019 13:24:32 +1000 Subject: [PATCH 0293/1788] tools/pyboard.py: Don't accumulate output data if data_consumer used. Prior to this patch, when a lot of data was output by a running script pyboard.py would try to capture all of this output into the "data" variable, which would gradually slow down pyboard.py to the point where it would have large CPU and memory usage (on the host) and potentially lose data. This patch fixes this problem by not accumulating the data in the case that the data is not needed, which is when "data_consumer" is used. --- tools/pyboard.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/pyboard.py b/tools/pyboard.py index 42b077de22..d906235066 100755 --- a/tools/pyboard.py +++ b/tools/pyboard.py @@ -261,6 +261,9 @@ class Pyboard: self.serial.close() def read_until(self, min_num_bytes, ending, timeout=10, data_consumer=None): + # if data_consumer is used then data is not accumulated and the ending must be 1 byte long + assert data_consumer is None or len(ending) == 1 + data = self.serial.read(min_num_bytes) if data_consumer: data_consumer(data) @@ -270,9 +273,11 @@ class Pyboard: break elif self.serial.inWaiting() > 0: new_data = self.serial.read(1) - data = data + new_data if data_consumer: data_consumer(new_data) + data = new_data + else: + data = data + new_data timeout_count = 0 else: timeout_count += 1 From f66c4cbfa6801e154e9f4bd54b8b89a44814af37 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 25 Apr 2019 17:56:13 +1000 Subject: [PATCH 0294/1788] stm32/usbdev: Make USB device descriptors at runtime rather than static. --- .../stm32/usbdev/class/src/usbd_cdc_msc_hid.c | 402 +++++------------- 1 file changed, 101 insertions(+), 301 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 a576796e27..78ad72056a 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -30,18 +30,17 @@ #if MICROPY_HW_ENABLE_USB -#define MSC_TEMPLATE_CONFIG_DESC_SIZE (32) +#define HEAD_DESC_SIZE (9) +#define MSC_CLASS_DESC_SIZE (9 + 7 + 7) +#define CDC_CLASS_DESC_SIZE (8 + 58) +#define HID_CLASS_DESC_SIZE (9 + 9 + 7 + 7) + #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 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) #define CDC_TEMPLATE_CDC_DESC_OFFSET (9) #define CDC_DESC_OFFSET_INTR_INTERVAL (34) @@ -126,20 +125,23 @@ __ALIGN_BEGIN static uint8_t USBD_CDC_MSC_HID_DeviceQualifierDesc[USB_LEN_DEV_QU }; #endif -// USB MSC device Configuration Descriptor -static const uint8_t msc_template_config_desc[MSC_TEMPLATE_CONFIG_DESC_SIZE] = { +// USB partial configuration descriptor +static const uint8_t head_desc_data[HEAD_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 + 0x00, // wTotalLength -- to be filled in + 0x00, // wTotalLength -- to be filled in + 0x00, // bNumInterfaces -- to be filled in 0x01, // bConfigurationValue: Configuration value 0x00, // iConfiguration: Index of string descriptor describing the configuration CONFIG_DESC_ATTRIBUTES, // bmAttributes CONFIG_DESC_MAXPOWER, // bMaxPower +}; +// USB MSC partial configuration descriptor +static const uint8_t msc_class_desc_data[MSC_CLASS_DESC_SIZE] = { //========================================================================== // MSC only has 1 interface so doesn't need an IAD @@ -174,58 +176,13 @@ static const uint8_t msc_template_config_desc[MSC_TEMPLATE_CONFIG_DESC_SIZE] = { 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] = { - //-------------------------------------------------------------------------- - // Configuration Descriptor - 0x09, // bLength: Configuration Descriptor size - USB_DESC_TYPE_CONFIGURATION, // bDescriptorType: Configuration - LOBYTE(CDC_MSC_TEMPLATE_CONFIG_DESC_SIZE), // wTotalLength: no of returned bytes - HIBYTE(CDC_MSC_TEMPLATE_CONFIG_DESC_SIZE), - 0x03, // bNumInterfaces: 3 interfaces - 0x01, // bConfigurationValue: Configuration value - 0x00, // iConfiguration: Index of string descriptor describing the configuration - CONFIG_DESC_ATTRIBUTES, // bmAttributes - CONFIG_DESC_MAXPOWER, // bMaxPower - - //========================================================================== - // 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_FS_MAX_PACKET), // wMaxPacketSize - HIBYTE(MSC_FS_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_FS_MAX_PACKET), // wMaxPacketSize - HIBYTE(MSC_FS_MAX_PACKET), - 0x00, // bInterval: ignore for Bulk transfer - +// USB CDC partial configuration descriptor +static const uint8_t cdc_class_desc_data[CDC_CLASS_DESC_SIZE] = { //========================================================================== // Interface Association for CDC VCP 0x08, // bLength: 8 bytes USB_DESC_TYPE_ASSOCIATION, // bDescriptorType: IAD - CDC_IFACE_NUM_WITH_MSC, // bFirstInterface: first interface for this association + 0x00, // bFirstInterface: first interface for this association -- to be filled in 0x02, // bInterfaceCount: nummber of interfaces for this association 0x02, // bFunctionClass: Communication Interface Class 0x02, // bFunctionSubClass: Abstract Control Model @@ -236,7 +193,7 @@ static const uint8_t cdc_msc_template_config_desc[CDC_MSC_TEMPLATE_CONFIG_DESC_S // Interface Descriptor 0x09, // bLength: Interface Descriptor size USB_DESC_TYPE_INTERFACE, // bDescriptorType: Interface - CDC_IFACE_NUM_WITH_MSC, // bInterfaceNumber: Number of Interface + 0x00, // bInterfaceNumber: Number of Interface -- to be filled in 0x00, // bAlternateSetting: Alternate setting 0x01, // bNumEndpoints: One endpoints used 0x02, // bInterfaceClass: Communication Interface Class @@ -256,7 +213,7 @@ static const uint8_t cdc_msc_template_config_desc[CDC_MSC_TEMPLATE_CONFIG_DESC_S 0x24, // bDescriptorType: CS_INTERFACE 0x01, // bDescriptorSubtype: Call Management Func Desc 0x00, // bmCapabilities: D0+D1 - CDC_IFACE_NUM_WITH_MSC + 1, // bDataInterface: 1 + 0x00, // bDataInterface -- to be filled in // ACM Functional Descriptor 0x04, // bFunctionLength @@ -268,10 +225,10 @@ static const uint8_t cdc_msc_template_config_desc[CDC_MSC_TEMPLATE_CONFIG_DESC_S 0x05, // bFunctionLength 0x24, // bDescriptorType: CS_INTERFACE 0x06, // bDescriptorSubtype: Union func desc - CDC_IFACE_NUM_WITH_MSC + 0, // bMasterInterface: Communication class interface - CDC_IFACE_NUM_WITH_MSC + 1, // bSlaveInterface0: Data Class Interface + 0x00, // bMasterInterface: Communication class interface -- to be filled in + 0x00, // bSlaveInterface0: Data Class Interface -- to be filled in - // Endpoint 2 Descriptor + // Endpoint CMD Descriptor 0x07, // bLength: Endpoint Descriptor size USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint CDC_CMD_EP, // bEndpointAddress @@ -284,7 +241,7 @@ static const uint8_t cdc_msc_template_config_desc[CDC_MSC_TEMPLATE_CONFIG_DESC_S // Data class interface descriptor 0x09, // bLength: Endpoint Descriptor size USB_DESC_TYPE_INTERFACE, // bDescriptorType: interface - CDC_IFACE_NUM_WITH_MSC + 1, // bInterfaceNumber: Number of Interface + 0x00, // bInterfaceNumber: Number of Interface -- to be filled in 0x00, // bAlternateSetting: Alternate setting 0x02, // bNumEndpoints: Two endpoints used 0x0A, // bInterfaceClass: CDC @@ -311,20 +268,8 @@ static const uint8_t cdc_msc_template_config_desc[CDC_MSC_TEMPLATE_CONFIG_DESC_S 0x00, // bInterval: ignore for Bulk transfer }; -// USB CDC HID device Configuration Descriptor -static const uint8_t cdc_hid_template_config_desc[CDC_HID_TEMPLATE_CONFIG_DESC_SIZE] = { - //-------------------------------------------------------------------------- - // Configuration Descriptor - 0x09, // bLength: Configuration Descriptor size - USB_DESC_TYPE_CONFIGURATION, // bDescriptorType: Configuration - LOBYTE(CDC_HID_TEMPLATE_CONFIG_DESC_SIZE), // wTotalLength: no of returned bytes - HIBYTE(CDC_HID_TEMPLATE_CONFIG_DESC_SIZE), - 0x03, // bNumInterfaces: 3 interfaces - 0x01, // bConfigurationValue: Configuration value - 0x00, // iConfiguration: Index of string descriptor describing the configuration - CONFIG_DESC_ATTRIBUTES, // bmAttributes - CONFIG_DESC_MAXPOWER, // bMaxPower - +// USB HID partial configuration descriptor +static const uint8_t hid_class_desc_data[HID_CLASS_DESC_SIZE] = { //========================================================================== // HID only has 1 interface so doesn't need an IAD @@ -368,187 +313,6 @@ static const uint8_t cdc_hid_template_config_desc[CDC_HID_TEMPLATE_CONFIG_DESC_S LOBYTE(USBD_HID_MOUSE_MAX_PACKET), // wMaxPacketSize HIBYTE(USBD_HID_MOUSE_MAX_PACKET), 0x08, // bInterval: Polling interval - - //========================================================================== - // Interface Association for CDC VCP - 0x08, // bLength: 8 bytes - USB_DESC_TYPE_ASSOCIATION, // bDescriptorType: IAD - CDC_IFACE_NUM_WITH_HID, // bFirstInterface: first interface for this association - 0x02, // bInterfaceCount: nummber of interfaces for this association - 0x02, // bFunctionClass: Communication Interface Class - 0x02, // bFunctionSubClass: Abstract Control Model - 0x01, // bFunctionProtocol: Common AT commands - 0x00, // iFunction: index of string for this function - - //-------------------------------------------------------------------------- - // Interface Descriptor - 0x09, // bLength: Interface Descriptor size - USB_DESC_TYPE_INTERFACE, // bDescriptorType: Interface - CDC_IFACE_NUM_WITH_HID, // bInterfaceNumber: Number of Interface - 0x00, // bAlternateSetting: Alternate setting - 0x01, // bNumEndpoints: One endpoints used - 0x02, // bInterfaceClass: Communication Interface Class - 0x02, // bInterfaceSubClass: Abstract Control Model - 0x01, // bInterfaceProtocol: Common AT commands - 0x00, // iInterface: - - // Header Functional Descriptor - 0x05, // bLength: Endpoint Descriptor size - 0x24, // bDescriptorType: CS_INTERFACE - 0x00, // bDescriptorSubtype: Header Func Desc - 0x10, // bcdCDC: spec release number - 0x01, // ? - - // Call Management Functional Descriptor - 0x05, // bFunctionLength - 0x24, // bDescriptorType: CS_INTERFACE - 0x01, // bDescriptorSubtype: Call Management Func Desc - 0x00, // bmCapabilities: D0+D1 - CDC_IFACE_NUM_WITH_HID + 1, // bDataInterface: 1 - - // ACM Functional Descriptor - 0x04, // bFunctionLength - 0x24, // bDescriptorType: CS_INTERFACE - 0x02, // bDescriptorSubtype: Abstract Control Management desc - 0x02, // bmCapabilities - - // Union Functional Descriptor - 0x05, // bFunctionLength - 0x24, // bDescriptorType: CS_INTERFACE - 0x06, // bDescriptorSubtype: Union func desc - CDC_IFACE_NUM_WITH_HID + 0, // bMasterInterface: Communication class interface - CDC_IFACE_NUM_WITH_HID + 1, // bSlaveInterface0: Data Class Interface - - // Endpoint 2 Descriptor - 0x07, // bLength: Endpoint Descriptor size - USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint - CDC_CMD_EP, // bEndpointAddress - 0x03, // bmAttributes: Interrupt - LOBYTE(CDC_CMD_PACKET_SIZE), // wMaxPacketSize: - HIBYTE(CDC_CMD_PACKET_SIZE), - 0x20, // bInterval: polling interval in frames of 1ms - - //-------------------------------------------------------------------------- - // Data class interface descriptor - 0x09, // bLength: Endpoint Descriptor size - USB_DESC_TYPE_INTERFACE, // bDescriptorType: interface - CDC_IFACE_NUM_WITH_HID + 1, // bInterfaceNumber: Number of Interface - 0x00, // bAlternateSetting: Alternate setting - 0x02, // bNumEndpoints: Two endpoints used - 0x0A, // bInterfaceClass: CDC - 0x00, // bInterfaceSubClass: ? - 0x00, // bInterfaceProtocol: ? - 0x00, // iInterface: - - // Endpoint OUT Descriptor - 0x07, // bLength: Endpoint Descriptor size - USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint - CDC_OUT_EP, // bEndpointAddress - 0x02, // bmAttributes: Bulk - LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),// wMaxPacketSize: - HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), - 0x00, // bInterval: ignore for Bulk transfer - - // Endpoint IN Descriptor - 0x07, // bLength: Endpoint Descriptor size - USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint - CDC_IN_EP, // bEndpointAddress - 0x02, // bmAttributes: Bulk - LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),// wMaxPacketSize: - HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), - 0x00, // bInterval: ignore for Bulk transfer -}; - -static const uint8_t cdc_template_config_desc[CDC_TEMPLATE_CONFIG_DESC_SIZE] = { - //-------------------------------------------------------------------------- - // Configuration Descriptor - 0x09, // bLength: Configuration Descriptor size - USB_DESC_TYPE_CONFIGURATION, // bDescriptorType: Configuration - LOBYTE(CDC_TEMPLATE_CONFIG_DESC_SIZE), // wTotalLength:no of returned bytes - HIBYTE(CDC_TEMPLATE_CONFIG_DESC_SIZE), - 0x02, // bNumInterfaces: 2 interface - 0x01, // bConfigurationValue: Configuration value - 0x00, // iConfiguration: Index of string descriptor describing the configuration - CONFIG_DESC_ATTRIBUTES, // bmAttributes - CONFIG_DESC_MAXPOWER, // bMaxPower - - //-------------------------------------------------------------------------- - // Interface Descriptor - 0x09, // bLength: Interface Descriptor size - USB_DESC_TYPE_INTERFACE, // bDescriptorType: Interface - CDC_IFACE_NUM_ALONE, // bInterfaceNumber: Number of Interface - 0x00, // bAlternateSetting: Alternate setting - 0x01, // bNumEndpoints: One endpoints used - 0x02, // bInterfaceClass: Communication Interface Class - 0x02, // bInterfaceSubClass: Abstract Control Model - 0x01, // bInterfaceProtocol: Common AT commands - 0x00, // iInterface: - - // Header Functional Descriptor - 0x05, // bLength: Endpoint Descriptor size - 0x24, // bDescriptorType: CS_INTERFACE - 0x00, // bDescriptorSubtype: Header Func Desc - 0x10, // bcdCDC: spec release number - 0x01, // ? - - // Call Management Functional Descriptor - 0x05, // bFunctionLength - 0x24, // bDescriptorType: CS_INTERFACE - 0x01, // bDescriptorSubtype: Call Management Func Desc - 0x00, // bmCapabilities: D0+D1 - CDC_IFACE_NUM_ALONE + 1, // bDataInterface: 1 - - // ACM Functional Descriptor - 0x04, // bFunctionLength - 0x24, // bDescriptorType: CS_INTERFACE - 0x02, // bDescriptorSubtype: Abstract Control Management desc - 0x02, // bmCapabilities - - // Union Functional Descriptor - 0x05, // bFunctionLength - 0x24, // bDescriptorType: CS_INTERFACE - 0x06, // bDescriptorSubtype: Union func desc - CDC_IFACE_NUM_ALONE + 0, // bMasterInterface: Communication class interface - CDC_IFACE_NUM_ALONE + 1, // bSlaveInterface0: Data Class Interface - - // Endpoint 2 Descriptor - 0x07, // bLength: Endpoint Descriptor size - USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint - CDC_CMD_EP, // bEndpointAddress - 0x03, // bmAttributes: Interrupt - LOBYTE(CDC_CMD_PACKET_SIZE), // wMaxPacketSize: - HIBYTE(CDC_CMD_PACKET_SIZE), - 0x20, // bInterval: polling interval in frames of 1ms - - //-------------------------------------------------------------------------- - // Data class interface descriptor - 0x09, // bLength: Endpoint Descriptor size - USB_DESC_TYPE_INTERFACE, // bDescriptorType: - CDC_IFACE_NUM_ALONE + 1, // bInterfaceNumber: Number of Interface - 0x00, // bAlternateSetting: Alternate setting - 0x02, // bNumEndpoints: Two endpoints used - 0x0a, // bInterfaceClass: CDC - 0x00, // bInterfaceSubClass: ? - 0x00, // bInterfaceProtocol: ? - 0x00, // iInterface: - - // Endpoint OUT Descriptor - 0x07, // bLength: Endpoint Descriptor size - USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint - CDC_OUT_EP, // bEndpointAddress - 0x02, // bmAttributes: Bulk - LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),// wMaxPacketSize: - HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), - 0x00, // bInterval: ignore for Bulk transfer - - // Endpoint IN Descriptor - 0x07, // bLength: Endpoint Descriptor size - USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint - CDC_IN_EP, // bEndpointAddress - 0x02, // bmAttributes: Bulk - LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),// wMaxPacketSize: - HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), - 0x00 // bInterval: ignore for Bulk transfer }; __ALIGN_BEGIN const uint8_t USBD_HID_MOUSE_ReportDesc[USBD_HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END = { @@ -628,6 +392,61 @@ __ALIGN_BEGIN const uint8_t USBD_HID_KEYBOARD_ReportDesc[USBD_HID_KEYBOARD_REPOR 0xC0 // End Collection }; +static void make_head_desc(uint8_t *dest, uint16_t len, uint8_t num_itf) { + memcpy(dest, head_desc_data, sizeof(head_desc_data)); + dest[2] = LOBYTE(len); // wTotalLength + dest[3] = HIBYTE(len); + dest[4] = num_itf; // bNumInterfaces +} + +static size_t make_msc_desc(uint8_t *dest) { + memcpy(dest, msc_class_desc_data, sizeof(msc_class_desc_data)); + return sizeof(msc_class_desc_data); +} + +static size_t make_cdc_desc(uint8_t *dest, int need_iad, uint8_t iface_num) { + if (need_iad) { + memcpy(dest, cdc_class_desc_data, sizeof(cdc_class_desc_data)); + dest[2] = iface_num; // bFirstInterface + dest += 8; + } else { + memcpy(dest, cdc_class_desc_data + 8, sizeof(cdc_class_desc_data) - 8); + } + dest[2] = iface_num; // bInterfaceNumber, main class + dest[18] = iface_num + 1; // bDataInterface + dest[26] = iface_num + 0; // bMasterInterface + dest[27] = iface_num + 1; // bSlaveInterface + dest[37] = iface_num + 1; // bInterfaceNumber, data class + return need_iad ? 8 + 58 : 58; +} + +#if MICROPY_HW_USB_ENABLE_CDC2 +static size_t make_cdc_desc_ep(uint8_t *dest, int need_iad, uint8_t iface_num, uint8_t cmd_ep, uint8_t out_ep, uint8_t in_ep) { + size_t n = make_cdc_desc(dest, need_iad, iface_num); + if (need_iad) { + dest += 8; + } + dest[30] = cmd_ep; // bEndpointAddress, main class CMD + dest[46] = out_ep; // bEndpointAddress, data class OUT + dest[53] = in_ep; // bEndpointAddress, data class IN + return n; +} +#endif + +static size_t make_hid_desc(uint8_t *dest, USBD_HID_ModeInfoTypeDef *hid_info) { + memcpy(dest, hid_class_desc_data, sizeof(hid_class_desc_data)); + dest[HID_DESC_OFFSET_SUBCLASS] = hid_info->subclass; + dest[HID_DESC_OFFSET_PROTOCOL] = hid_info->protocol; + dest[HID_DESC_OFFSET_REPORT_DESC_LEN] = hid_info->report_desc_len; + dest[HID_DESC_OFFSET_MAX_PACKET_LO] = hid_info->max_packet_len; + dest[HID_DESC_OFFSET_MAX_PACKET_HI] = 0; + dest[HID_DESC_OFFSET_POLLING_INTERVAL] = hid_info->polling_interval; + dest[HID_DESC_OFFSET_MAX_PACKET_OUT_LO] = hid_info->max_packet_len; + dest[HID_DESC_OFFSET_MAX_PACKET_OUT_HI] = 0; + dest[HID_DESC_OFFSET_POLLING_INTERVAL_OUT] = hid_info->polling_interval; + return sizeof(hid_class_desc_data); +} + // return the saved usb mode uint8_t USBD_GetMode(usbd_cdc_msc_hid_state_t *usbd) { return usbd->usbd_mode; @@ -638,57 +457,50 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode usbd->usbd_mode = mode; // construct config desc + size_t n = HEAD_DESC_SIZE; + uint8_t *d = usbd->usbd_config_desc; + uint8_t num_itf = 0; 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)); + n += make_msc_desc(d + n); + num_itf = 1; 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)); + n += make_msc_desc(d + n); + n += make_cdc_desc(d + n, 1, CDC_IFACE_NUM_WITH_MSC); usbd->cdc->iface_num = CDC_IFACE_NUM_WITH_MSC; + num_itf = 3; 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 + n += make_msc_desc(d + n); + n += make_cdc_desc(d + n, 1, CDC_IFACE_NUM_WITH_MSC); + n += make_cdc_desc_ep(d + n, 1, CDC2_IFACE_NUM_WITH_MSC, CDC2_CMD_EP, CDC2_OUT_EP, CDC2_IN_EP); usbd->cdc->iface_num = CDC_IFACE_NUM_WITH_MSC; usbd->cdc2->iface_num = CDC2_IFACE_NUM_WITH_MSC; + num_itf = 5; 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)); + usbd->hid->desc = d + n; + n += make_hid_desc(d + n, hid_info); + n += make_cdc_desc(d + n, 1, 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; - usbd->hid->desc = usbd->usbd_config_desc + CDC_HID_TEMPLATE_HID_DESC_OFFSET; + usbd->hid->report_desc = hid_info->report_desc; + num_itf = 3; break; 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)); + n += make_cdc_desc(d + n, 0, CDC_IFACE_NUM_ALONE); usbd->cdc->iface_num = CDC_IFACE_NUM_ALONE; + num_itf = 2; break; /* @@ -705,6 +517,9 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode return -1; } + make_head_desc(d, n, num_itf); + usbd->usbd_config_desc_size = n; + if (usbd->usbd_mode & USBD_MODE_CDC) { usbd->cdc->in_ep = CDC_IN_EP; usbd->cdc->out_ep = CDC_OUT_EP; @@ -717,21 +532,6 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode } #endif - // configure the HID descriptor, if needed - if (usbd->usbd_mode & USBD_MODE_HID) { - 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; - hid_desc[HID_DESC_OFFSET_MAX_PACKET_LO] = hid_info->max_packet_len; - hid_desc[HID_DESC_OFFSET_MAX_PACKET_HI] = 0; - hid_desc[HID_DESC_OFFSET_POLLING_INTERVAL] = hid_info->polling_interval; - 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; - } - return 0; } From 775ffdcc3b85178ac128f774a5a8f992fd637dca Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 26 Apr 2019 14:47:31 +1000 Subject: [PATCH 0295/1788] extmod/machine_signal: Fix fault when no args are passed to Signal(). --- extmod/machine_signal.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/extmod/machine_signal.c b/extmod/machine_signal.c index c494490b60..8204ef174a 100644 --- a/extmod/machine_signal.c +++ b/extmod/machine_signal.c @@ -43,13 +43,13 @@ typedef struct _machine_signal_t { } machine_signal_t; STATIC mp_obj_t signal_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { - mp_obj_t pin = args[0]; + mp_obj_t pin; bool invert = false; #if defined(MICROPY_PY_MACHINE_PIN_MAKE_NEW) mp_pin_p_t *pin_p = NULL; - if (mp_obj_is_obj(pin)) { + if (n_args > 0 && mp_obj_is_obj(args[0])) { mp_obj_base_t *pin_base = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]); pin_p = (mp_pin_p_t*)pin_base->type->protocol; } @@ -96,6 +96,7 @@ STATIC mp_obj_t signal_make_new(const mp_obj_type_t *type, size_t n_args, size_t // Otherwise there should be 1 or 2 args { if (n_args == 1) { + pin = args[0]; if (n_kw == 0) { } else if (n_kw == 1 && args[1] == MP_OBJ_NEW_QSTR(MP_QSTR_invert)) { invert = mp_obj_is_true(args[2]); From 06a532c227c2f37fc190deb84970fdfeaaf37d6a Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 26 Apr 2019 15:21:09 +1000 Subject: [PATCH 0296/1788] lib/utils/pyexec: Add pyexec_file_if_exists() helper function. It will only execute the script if it can be stat'd and is a file. --- lib/utils/pyexec.c | 8 ++++++++ lib/utils/pyexec.h | 1 + 2 files changed, 9 insertions(+) diff --git a/lib/utils/pyexec.c b/lib/utils/pyexec.c index f4e6856e50..946a97a00a 100644 --- a/lib/utils/pyexec.c +++ b/lib/utils/pyexec.c @@ -541,6 +541,14 @@ int pyexec_file(const char *filename) { return parse_compile_execute(filename, MP_PARSE_FILE_INPUT, EXEC_FLAG_SOURCE_IS_FILENAME); } +int pyexec_file_if_exists(const char *filename) { + mp_import_stat_t stat = mp_import_stat(filename); + if (stat != MP_IMPORT_STAT_FILE) { + return 1; // success (no file is the same as an empty file executing without fail) + } + return pyexec_file(filename); +} + #if MICROPY_MODULE_FROZEN int pyexec_frozen_module(const char *name) { void *frozen_data; diff --git a/lib/utils/pyexec.h b/lib/utils/pyexec.h index a0d0b52b16..9eb490be54 100644 --- a/lib/utils/pyexec.h +++ b/lib/utils/pyexec.h @@ -46,6 +46,7 @@ extern int pyexec_system_exit; int pyexec_raw_repl(void); int pyexec_friendly_repl(void); int pyexec_file(const char *filename); +int pyexec_file_if_exists(const char *filename); int pyexec_frozen_module(const char *name); void pyexec_event_repl_init(void); int pyexec_event_repl_process_char(int c); From 0646e607b537b43901db53c743ec2011a375f5e2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 26 Apr 2019 15:22:14 +1000 Subject: [PATCH 0297/1788] ports: Convert to use pyexec_file_if_exists() to execute boot/main.py. The stm32 and nrf ports already had the behaviour that they would first check if the script exists before executing it, and this patch makes all other ports work the same way. This helps when developing apps because it's hard to tell (when unconditionally trying to execute the scripts) if the resulting OSError at boot up comes from missing boot.py or main.py, or from some other error. And it's not really an error if these scripts don't exist. --- ports/cc3200/mptask.c | 4 ++-- ports/esp32/main.c | 4 ++-- ports/esp8266/main.c | 4 ++-- ports/nrf/main.c | 8 ++------ ports/stm32/main.c | 30 ++++++++++++------------------ ports/teensy/main.c | 4 ++-- 6 files changed, 22 insertions(+), 32 deletions(-) diff --git a/ports/cc3200/mptask.c b/ports/cc3200/mptask.c index 9d75f4678e..d35338be18 100644 --- a/ports/cc3200/mptask.c +++ b/ports/cc3200/mptask.c @@ -180,7 +180,7 @@ soft_reset: if (!safeboot) { // run boot.py - int ret = pyexec_file("boot.py"); + int ret = pyexec_file_if_exists("boot.py"); if (ret & PYEXEC_FORCED_EXIT) { goto soft_reset_exit; } @@ -205,7 +205,7 @@ soft_reset: } else { main_py = mp_obj_str_get_str(MP_STATE_PORT(machine_config_main)); } - int ret = pyexec_file(main_py); + int ret = pyexec_file_if_exists(main_py); if (ret & PYEXEC_FORCED_EXIT) { goto soft_reset_exit; } diff --git a/ports/esp32/main.c b/ports/esp32/main.c index 188fb5e70d..d4f79646f6 100644 --- a/ports/esp32/main.c +++ b/ports/esp32/main.c @@ -111,9 +111,9 @@ soft_reset: // run boot-up scripts pyexec_frozen_module("_boot.py"); - pyexec_file("boot.py"); + pyexec_file_if_exists("boot.py"); if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) { - pyexec_file("main.py"); + pyexec_file_if_exists("main.py"); } for (;;) { diff --git a/ports/esp8266/main.c b/ports/esp8266/main.c index 67157ce18c..3465e0446e 100644 --- a/ports/esp8266/main.c +++ b/ports/esp8266/main.c @@ -77,9 +77,9 @@ STATIC void mp_reset(void) { #if MICROPY_MODULE_FROZEN pyexec_frozen_module("_boot.py"); - pyexec_file("boot.py"); + pyexec_file_if_exists("boot.py"); if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) { - pyexec_file("main.py"); + pyexec_file_if_exists("main.py"); } #endif } diff --git a/ports/nrf/main.c b/ports/nrf/main.c index b9c29e7538..e1ffce9385 100644 --- a/ports/nrf/main.c +++ b/ports/nrf/main.c @@ -227,12 +227,8 @@ pin_init0(); #if MICROPY_VFS || MICROPY_MBFS // run boot.py and main.py if they exist. - if (mp_import_stat("boot.py") == MP_IMPORT_STAT_FILE) { - pyexec_file("boot.py"); - } - if (mp_import_stat("main.py") == MP_IMPORT_STAT_FILE) { - pyexec_file("main.py"); - } + pyexec_file_if_exists("boot.py"); + pyexec_file_if_exists("main.py"); #endif for (;;) { diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 6fa6a6267f..0bdbbd481d 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -678,15 +678,12 @@ soft_reset: // TODO perhaps have pyb.reboot([bootpy]) function to soft-reboot and execute custom boot.py if (reset_mode == 1 || reset_mode == 3) { const char *boot_py = "boot.py"; - mp_import_stat_t stat = mp_import_stat(boot_py); - if (stat == MP_IMPORT_STAT_FILE) { - int ret = pyexec_file(boot_py); - if (ret & PYEXEC_FORCED_EXIT) { - goto soft_reset_exit; - } - if (!ret) { - flash_error(4); - } + int ret = pyexec_file_if_exists(boot_py); + if (ret & PYEXEC_FORCED_EXIT) { + goto soft_reset_exit; + } + if (!ret) { + flash_error(4); } } @@ -735,15 +732,12 @@ soft_reset: } else { main_py = mp_obj_str_get_str(MP_STATE_PORT(pyb_config_main)); } - mp_import_stat_t stat = mp_import_stat(main_py); - if (stat == MP_IMPORT_STAT_FILE) { - int ret = pyexec_file(main_py); - if (ret & PYEXEC_FORCED_EXIT) { - goto soft_reset_exit; - } - if (!ret) { - flash_error(3); - } + int ret = pyexec_file_if_exists(main_py); + if (ret & PYEXEC_FORCED_EXIT) { + goto soft_reset_exit; + } + if (!ret) { + flash_error(3); } } diff --git a/ports/teensy/main.c b/ports/teensy/main.c index ad98a43644..1f529f589c 100644 --- a/ports/teensy/main.c +++ b/ports/teensy/main.c @@ -302,7 +302,7 @@ soft_reset: #if MICROPY_MODULE_FROZEN pyexec_frozen_module("boot.py"); #else - if (!pyexec_file("/boot.py")) { + if (!pyexec_file_if_exists("/boot.py")) { flash_error(4); } #endif @@ -322,7 +322,7 @@ soft_reset: } else { vstr_add_str(vstr, mp_obj_str_get_str(pyb_config_main)); } - if (!pyexec_file(vstr_null_terminated_str(vstr))) { + if (!pyexec_file_if_exists(vstr_null_terminated_str(vstr))) { flash_error(3); } vstr_free(vstr); From 70a28e3ad9a251e77f0fa2da643f014044035a36 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Fri, 26 Apr 2019 16:31:49 +1000 Subject: [PATCH 0298/1788] stm32/usb: Add USB device mode for VCP+VCP without MSC. Selectable via pyb.usb_mode('VCP+VCP'). --- ports/stm32/usb.c | 5 +++++ ports/stm32/usb.h | 1 + ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c | 13 +++++++++++++ 3 files changed, 19 insertions(+) diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index ce2a828598..e81225e605 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -306,6 +306,11 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * } mode = USBD_MODE_CDC_MSC; #if MICROPY_HW_USB_ENABLE_CDC2 + } else if (strcmp(mode_str, "VCP+VCP") == 0) { + if (args[2].u_int == -1) { + pid = USBD_PID_CDC2; + } + mode = USBD_MODE_CDC2; } else if (strcmp(mode_str, "VCP+VCP+MSC") == 0) { if (args[2].u_int == -1) { pid = USBD_PID_CDC2_MSC; diff --git a/ports/stm32/usb.h b/ports/stm32/usb.h index 2a3861f210..3d57bf9129 100644 --- a/ports/stm32/usb.h +++ b/ports/stm32/usb.h @@ -37,6 +37,7 @@ #define USBD_PID_CDC (0x9802) #define USBD_PID_MSC (0x9803) #define USBD_PID_CDC2_MSC (0x9804) +#define USBD_PID_CDC2 (0x9805) 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 78ad72056a..47436a4b63 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -62,6 +62,7 @@ #define CDC_IFACE_NUM_ALONE (0) #define CDC_IFACE_NUM_WITH_MSC (1) +#define CDC2_IFACE_NUM_WITH_CDC (2) #define CDC2_IFACE_NUM_WITH_MSC (3) #define CDC_IFACE_NUM_WITH_HID (1) #define MSC_IFACE_NUM_WITH_CDC (0) @@ -474,6 +475,18 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode break; #if MICROPY_HW_USB_ENABLE_CDC2 + case USBD_MODE_CDC2: { + // Ensure the first interface is also enabled + usbd->usbd_mode |= USBD_MODE_CDC; + + n += make_cdc_desc(d + n, 1, CDC_IFACE_NUM_ALONE); + n += make_cdc_desc_ep(d + n, 1, CDC2_IFACE_NUM_WITH_CDC, CDC2_CMD_EP, CDC2_OUT_EP, CDC2_IN_EP); + usbd->cdc->iface_num = CDC_IFACE_NUM_ALONE; + usbd->cdc2->iface_num = CDC2_IFACE_NUM_WITH_CDC; + num_itf = 4; + break; + } + case USBD_MODE_CDC2_MSC: { n += make_msc_desc(d + n); n += make_cdc_desc(d + n, 1, CDC_IFACE_NUM_WITH_MSC); From ca39ea7cef802497834aa2a0afa0ef8cae9ab800 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 28 Apr 2019 22:12:17 +1000 Subject: [PATCH 0299/1788] tests: Skip tests needing machine module if (u)machine doesn't exist. --- tests/basics/subclass_native_call.py | 10 +++++----- tests/extmod/machine_pinbase.py | 10 +++++----- tests/extmod/machine_pulse.py | 10 +++++----- tests/extmod/machine_signal.py | 10 +++++----- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/basics/subclass_native_call.py b/tests/basics/subclass_native_call.py index c645575225..969f0a415e 100644 --- a/tests/basics/subclass_native_call.py +++ b/tests/basics/subclass_native_call.py @@ -4,13 +4,13 @@ # 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: + try: + import umachine as machine + except ImportError: + import machine machine.PinBase machine.Signal -except AttributeError: +except: print("SKIP") raise SystemExit diff --git a/tests/extmod/machine_pinbase.py b/tests/extmod/machine_pinbase.py index e91775504d..45aa4d8b5b 100644 --- a/tests/extmod/machine_pinbase.py +++ b/tests/extmod/machine_pinbase.py @@ -1,10 +1,10 @@ try: - import umachine as machine -except ImportError: - import machine -try: + try: + import umachine as machine + except ImportError: + import machine machine.PinBase -except AttributeError: +except: print("SKIP") raise SystemExit diff --git a/tests/extmod/machine_pulse.py b/tests/extmod/machine_pulse.py index d525974e0c..458fe09a11 100644 --- a/tests/extmod/machine_pulse.py +++ b/tests/extmod/machine_pulse.py @@ -1,11 +1,11 @@ try: - import umachine as machine -except ImportError: - import machine -try: + try: + import umachine as machine + except ImportError: + import machine machine.PinBase machine.time_pulse_us -except AttributeError: +except: print("SKIP") raise SystemExit diff --git a/tests/extmod/machine_signal.py b/tests/extmod/machine_signal.py index 53f4f5890c..dcc0de1a5d 100644 --- a/tests/extmod/machine_signal.py +++ b/tests/extmod/machine_signal.py @@ -1,13 +1,13 @@ # test machine.Signal class try: - import umachine as machine -except ImportError: - import machine -try: + try: + import umachine as machine + except ImportError: + import machine machine.PinBase machine.Signal -except AttributeError: +except: print("SKIP") raise SystemExit From bd0bacb637fb11556e76cbd929ed833dcd3abe97 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 28 Apr 2019 22:14:28 +1000 Subject: [PATCH 0300/1788] javascript/library: Use Buffer.alloc() since new Buffer() is deprecated. --- ports/javascript/library.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/javascript/library.js b/ports/javascript/library.js index ed58167d5d..85fa3e2edd 100644 --- a/ports/javascript/library.js +++ b/ports/javascript/library.js @@ -48,7 +48,7 @@ mergeInto(LibraryManager.library, { var mp_interrupt_char = Module.ccall('mp_hal_get_interrupt_char', 'number', ['number'], ['null']); var fs = require('fs'); - var buf = new Buffer(1); + var buf = Buffer.alloc(1); try { var n = fs.readSync(process.stdin.fd, buf, 0, 1); if (n > 0) { From 93f5f802165c3b8ab01a0393409cbd1c352596c8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 28 Apr 2019 22:16:27 +1000 Subject: [PATCH 0301/1788] javascript: Pass (error) exit value out from script to process caller. --- ports/javascript/main.c | 19 +++++++++++++++---- ports/javascript/wrapper.js | 6 +++--- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/ports/javascript/main.c b/ports/javascript/main.c index 65bae98b44..f8ef0e7c55 100644 --- a/ports/javascript/main.c +++ b/ports/javascript/main.c @@ -39,7 +39,8 @@ #include "library.h" #if MICROPY_ENABLE_COMPILER -void do_str(const char *src, mp_parse_input_kind_t input_kind) { +int do_str(const char *src, mp_parse_input_kind_t input_kind) { + int ret = 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); @@ -51,18 +52,28 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) { } else { // uncaught exception if (mp_obj_is_subclass_fast(mp_obj_get_type((mp_obj_t)nlr.ret_val), &mp_type_SystemExit)) { - // at the moment, the value of SystemExit is unused + mp_obj_t exit_val = mp_obj_exception_get_value(MP_OBJ_FROM_PTR(nlr.ret_val)); + if (exit_val != mp_const_none) { + mp_int_t int_val; + if (mp_obj_get_int_maybe(exit_val, &int_val)) { + ret = int_val & 255; + } else { + ret = 1; + } + } } else { mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); + ret = 1; } } + return ret; } #endif static char *stack_top; -void mp_js_do_str(const char *code) { - do_str(code, MP_PARSE_FILE_INPUT); +int mp_js_do_str(const char *code) { + return do_str(code, MP_PARSE_FILE_INPUT); } int mp_js_process_char(int c) { diff --git a/ports/javascript/wrapper.js b/ports/javascript/wrapper.js index 84ad2ae3a7..ae0f24e7e4 100644 --- a/ports/javascript/wrapper.js +++ b/ports/javascript/wrapper.js @@ -29,7 +29,7 @@ var Module = {}; var mainProgram = function() { mp_js_init = Module.cwrap('mp_js_init', 'null', ['number']); - mp_js_do_str = Module.cwrap('mp_js_do_str', 'null', ['string']); + mp_js_do_str = Module.cwrap('mp_js_do_str', 'number', ['string']); mp_js_init_repl = Module.cwrap('mp_js_init_repl', 'null', ['null']); mp_js_process_char = Module.cwrap('mp_js_process_char', 'number', ['number']); @@ -69,9 +69,9 @@ var mainProgram = function() } }); } else { - mp_js_do_str(contents); + process.exitCode = mp_js_do_str(contents); } } } -Module["onRuntimeInitialized"] = mainProgram; \ No newline at end of file +Module["onRuntimeInitialized"] = mainProgram; From bd6fed8201a818a96611e56ecc521c23cf5255f4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 28 Apr 2019 22:17:42 +1000 Subject: [PATCH 0302/1788] javascript/Makefile: Fix unrepresentable float error by using clamp. Otherwise converting large floats to ints will fail (as seen by the builtin_float_hash.py test). --- ports/javascript/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/javascript/Makefile b/ports/javascript/Makefile index 9b0f4d89c0..7309dfa481 100644 --- a/ports/javascript/Makefile +++ b/ports/javascript/Makefile @@ -44,7 +44,7 @@ OBJ = $(PY_O) OBJ += $(addprefix $(BUILD)/, $(SRC_LIB:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) -JSFLAGS = -O0 -s EXPORTED_FUNCTIONS="['_mp_js_init', '_mp_js_init_repl', '_mp_js_do_str', '_mp_js_process_char', '_mp_hal_get_interrupt_char', '_mp_keyboard_interrupt']" -s EXTRA_EXPORTED_RUNTIME_METHODS="['ccall', 'cwrap']" --memory-init-file 0 --js-library library.js +JSFLAGS = -O0 -s EXPORTED_FUNCTIONS="['_mp_js_init', '_mp_js_init_repl', '_mp_js_do_str', '_mp_js_process_char', '_mp_hal_get_interrupt_char', '_mp_keyboard_interrupt']" -s EXTRA_EXPORTED_RUNTIME_METHODS="['ccall', 'cwrap']" -s "BINARYEN_TRAP_MODE='clamp'" --memory-init-file 0 --js-library library.js all: $(BUILD)/micropython.js From d1dea4f57701b9464e3d6c45a5814d58fb0795f9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 28 Apr 2019 22:39:41 +1000 Subject: [PATCH 0303/1788] javascript/library: Print data as raw bytes to stdout so unicode works. --- ports/javascript/library.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ports/javascript/library.js b/ports/javascript/library.js index 85fa3e2edd..9aab3e4320 100644 --- a/ports/javascript/library.js +++ b/ports/javascript/library.js @@ -27,10 +27,12 @@ mergeInto(LibraryManager.library, { mp_js_write: function(ptr, len) { for (var i = 0; i < len; ++i) { - c = String.fromCharCode(getValue(ptr + i, 'i8')); if (typeof window === 'undefined') { - process.stdout.write(c); + var b = Buffer.alloc(1); + b.writeInt8(getValue(ptr + i, 'i8')); + process.stdout.write(b); } else { + var c = String.fromCharCode(getValue(ptr + i, 'i8')); var mp_js_stdout = document.getElementById('mp_js_stdout'); var print = new Event('print'); print.data = c; From 8031b7a25c21fb864fe9dd1fa40740030be66c11 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 29 Apr 2019 16:31:32 +1000 Subject: [PATCH 0304/1788] stm32/powerctrl: Deselect PLLSAI as 48MHz src before turning off PLLSAI. On the STM32F722 (at least, but STM32F767 is not affected) the CK48MSEL bit must be deselected before PLLSAION is turned off, or else the 48MHz peripherals (RNG, SDMMC, USB) may get stuck without a clock source. In such "lock up" cases it seems that these peripherals are still being clocked from the PLLSAI even though the CK48MSEL bit is turned off. A hard reset does not get them out of this stuck state. Enabling the PLLSAI and then disabling it does get them out. A test case to see this is: import machine, pyb for i in range(100): machine.freq(122_000000) machine.freq(120_000000) print(i, [pyb.rng() for _ in range(4)]) On occasion the RNG will just return 0's, but will get fixed again on the next loop (when PLLSAI is enabled by the change to a SYSCLK of 122MHz). Fixes issue #4696. --- ports/stm32/powerctrl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c index 669e568f8a..42bd262c27 100644 --- a/ports/stm32/powerctrl.c +++ b/ports/stm32/powerctrl.c @@ -54,8 +54,6 @@ int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk } } RCC->DCKCFGR2 |= RCC_DCKCFGR2_CK48MSEL; - } else { - RCC->DCKCFGR2 &= ~RCC_DCKCFGR2_CK48MSEL; } // If possible, scale down the internal voltage regulator to save power @@ -208,6 +206,8 @@ set_clk: } #if defined(STM32F7) + // Deselect PLLSAI as 48MHz source if we were using it + RCC->DCKCFGR2 &= ~RCC_DCKCFGR2_CK48MSEL; // Turn PLLSAI off because we are changing PLLM (which drives PLLSAI) RCC->CR &= ~RCC_CR_PLLSAION; #endif From fbd4e61e57185c0e9eb1aa7ced25926a140b23c9 Mon Sep 17 00:00:00 2001 From: Krono Date: Fri, 6 Jul 2018 12:06:11 +0200 Subject: [PATCH 0305/1788] esp32/machine_wdt: Add timeout arg to select interval, make WDT panic. The machine.WDT() now accepts the "timeout" keyword argument to select the WDT interval. And the WDT is changed to panic mode which means it will reset the device if the interval expires (instead of just printing an error message). --- ports/esp32/machine_wdt.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/ports/esp32/machine_wdt.c b/ports/esp32/machine_wdt.c index 88a58f056a..5c4732f4b6 100644 --- a/ports/esp32/machine_wdt.c +++ b/ports/esp32/machine_wdt.c @@ -41,21 +41,34 @@ typedef struct _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); +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 *all_args) { + enum { ARG_id, ARG_timeout }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_timeout, MP_ARG_INT, {.u_int = 5000} } + }; + 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); - mp_int_t id = 0; - if (n_args > 0) { - id = mp_obj_get_int(args[0]); + if (args[ARG_id].u_int != 0) { + mp_raise_ValueError(NULL); } - switch (id) { - case 0: - esp_task_wdt_add(NULL); - return &wdt_default; - default: - mp_raise_ValueError(NULL); + // Convert milliseconds to seconds (esp_task_wdt_init needs seconds) + args[ARG_timeout].u_int /= 1000; + + if (args[ARG_timeout].u_int <= 0) { + mp_raise_ValueError("WDT timeout too short"); } + + mp_int_t rs_code = esp_task_wdt_init(args[ARG_timeout].u_int, true); + if (rs_code != ESP_OK) { + mp_raise_OSError(rs_code); + } + + esp_task_wdt_add(NULL); + + return &wdt_default; } STATIC mp_obj_t machine_wdt_feed(mp_obj_t self_in) { From 9c7c082396f717a8a8eb845a0af407e78d38165f Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 1 Mar 2019 23:48:16 +0300 Subject: [PATCH 0306/1788] extmod/modussl_mbedtls: Support non-blocking handshake. For this, add wrap_socket(do_handshake=False) param. CPython doesn't have such a param at a module's global function, and at SSLContext.wrap_socket() it has do_handshake_on_connect param, but that uselessly long. Beyond that, make write() handle not just MBEDTLS_ERR_SSL_WANT_WRITE, but also MBEDTLS_ERR_SSL_WANT_READ, as during handshake, write call may be actually preempted by need to read next handshake message from peer. Likewise, for read(). And even after the initial negotiation, situations like that may happen e.g. with renegotiation. Both MBEDTLS_ERR_SSL_WANT_READ and MBEDTLS_ERR_SSL_WANT_WRITE are however mapped to the same None return code. The idea is that if the same read()/write() method is called repeatedly, the progress will be made step by step anyway. The caveat is if user wants to add the underlying socket to uselect.poll(). To be reliable, in this case, the socket should be polled for both POLL_IN and POLL_OUT, as we don't know the actual expected direction. But that's actually problematic. Consider for example that write() ends with MBEDTLS_ERR_SSL_WANT_READ, but gets converted to None. We put the underlying socket on pull using POLL_IN|POLL_OUT but that probably returns immediately with POLL_OUT, as underlyings socket is writable. We call the same ussl write() again, which again results in MBEDTLS_ERR_SSL_WANT_READ, etc. We thus go into busy-loop. So, the handling in this patch is temporary and needs fixing. But exact way to fix it is not clear. One way is to provide explicit function for handshake (CPython has do_handshake()), and let *that* return distinct codes like WANT_READ/WANT_WRITE. But as mentioned above, past the initial handshake, such situation may happen again with at least renegotiation. So apparently, the only robust solution is to return "out of bound" special sentinels like WANT_READ/WANT_WRITE from read()/write() directly. CPython throws exceptions for these, but those are expensive to adopt that way for efficiency-conscious implementation like MicroPython. --- extmod/modussl_mbedtls.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/extmod/modussl_mbedtls.c b/extmod/modussl_mbedtls.c index 348bba4c80..94863be57a 100644 --- a/extmod/modussl_mbedtls.c +++ b/extmod/modussl_mbedtls.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2016 Linaro Ltd. + * Copyright (c) 2019 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 @@ -60,6 +61,7 @@ struct ssl_args { mp_arg_val_t cert; mp_arg_val_t server_side; mp_arg_val_t server_hostname; + mp_arg_val_t do_handshake; }; STATIC const mp_obj_type_t ussl_socket_type; @@ -184,10 +186,12 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { assert(ret == 0); } - while ((ret = mbedtls_ssl_handshake(&o->ssl)) != 0) { - if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { - printf("mbedtls_ssl_handshake error: -%x\n", -ret); - goto cleanup; + if (args->do_handshake.u_bool) { + while ((ret = mbedtls_ssl_handshake(&o->ssl)) != 0) { + if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + printf("mbedtls_ssl_handshake error: -%x\n", -ret); + goto cleanup; + } } } @@ -238,6 +242,11 @@ STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errc } if (ret == MBEDTLS_ERR_SSL_WANT_READ) { ret = MP_EWOULDBLOCK; + } else if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) { + // If handshake is not finished, read attempt may end up in protocol + // wanting to write next handshake message. The same may happen with + // renegotation. + ret = MP_EWOULDBLOCK; } *errcode = ret; return MP_STREAM_ERROR; @@ -252,6 +261,11 @@ STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, in } if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) { ret = MP_EWOULDBLOCK; + } else if (ret == MBEDTLS_ERR_SSL_WANT_READ) { + // If handshake is not finished, write attempt may end up in protocol + // wanting to read next handshake message. The same may happen with + // renegotation. + ret = MP_EWOULDBLOCK; } *errcode = ret; return MP_STREAM_ERROR; @@ -321,6 +335,7 @@ STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_ { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { 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} }, + { MP_QSTR_do_handshake, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, }; // TODO: Check that sock implements stream protocol From c76445315f836eb75835814ebe97e14107adbf0f Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 1 Mar 2019 23:48:16 +0300 Subject: [PATCH 0307/1788] extmod/modussl_axtls: Add non-blocking mode support. It consists of: 1. "do_handhake" param (default True) to wrap_socket(). If it's False, handshake won't be performed by wrap_socket(), as it would be done in blocking way normally. Instead, SSL socket can be set to non-blocking mode, and handshake would be performed before the first read/write request (by just returning EAGAIN to these requests, while instead reading/writing/ processing handshake over the connection). Unfortunately, axTLS doesn't really support non-blocking handshake correctly. So, while framework for this is implemented on MicroPython's module side, in case of axTLS, it won't work reliably. 2. Implementation of .setblocking() method. It must be called on SSL socket for blocking vs non-blocking operation to be handled correctly (for example, it's not enough to wrap non-blocking socket with wrap_socket() call - resulting SSL socket won't be itself non-blocking). Note that .setblocking() propagates call to the underlying socket object, as expected. --- extmod/modussl_axtls.c | 55 ++++++++++++++++++++++------------ tests/extmod/ussl_basic.py.exp | 1 - 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/extmod/modussl_axtls.c b/extmod/modussl_axtls.c index 2dab6ff491..b559b13580 100644 --- a/extmod/modussl_axtls.c +++ b/extmod/modussl_axtls.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2015-2017 Paul Sokolovsky + * Copyright (c) 2015-2019 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 @@ -41,6 +41,7 @@ typedef struct _mp_obj_ssl_socket_t { SSL *ssl_sock; byte *buf; uint32_t bytes_left; + bool blocking; } mp_obj_ssl_socket_t; struct ssl_args { @@ -48,6 +49,7 @@ struct ssl_args { mp_arg_val_t cert; mp_arg_val_t server_side; mp_arg_val_t server_hostname; + mp_arg_val_t do_handshake; }; STATIC const mp_obj_type_t ussl_socket_type; @@ -62,8 +64,12 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { o->buf = NULL; o->bytes_left = 0; o->sock = sock; + o->blocking = true; uint32_t options = SSL_SERVER_VERIFY_LATER; + if (!args->do_handshake.u_bool) { + options |= SSL_CONNECT_IN_PARTS; + } if (args->key.u_obj != mp_const_none) { options |= SSL_NO_DEFAULT_KEY; } @@ -97,17 +103,14 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { o->ssl_sock = ssl_client_new(o->ssl_ctx, (long)sock, NULL, 0, ext); - int res = ssl_handshake_status(o->ssl_sock); - // Pointer to SSL_EXTENSIONS as being passed to ssl_client_new() - // is saved in ssl_sock->extensions. - // As of axTLS 2.1.3, extensions aren't used beyond the initial - // handshake, and that's pretty much how it's expected to be. So - // we allocate them on stack and reset the pointer after handshake. + if (args->do_handshake.u_bool) { + int res = ssl_handshake_status(o->ssl_sock); - if (res != SSL_OK) { - printf("ssl_handshake_status: %d\n", res); - ssl_display_error(res); - mp_raise_OSError(MP_EIO); + if (res != SSL_OK) { + printf("ssl_handshake_status: %d\n", res); + ssl_display_error(res); + mp_raise_OSError(MP_EIO); + } } } @@ -133,8 +136,18 @@ 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 - // no user data yet". So, we just keep reading. - continue; + // no user data yet". It may happen e.g. if handshake is not + // finished yet. The best way we can treat it is by returning + // EAGAIN. This may be a bit unexpected in blocking mode, but + // default is to perform complete handshake in constructor, so + // this should not happen in blocking mode. On the other hand, + // in nonblocking mode EAGAIN (comparing to the alternative of + // looping) is really preferrable. + if (o->blocking) { + continue; + } else { + goto eagain; + } } if (r < 0) { if (r == SSL_CLOSE_NOTIFY || r == SSL_ERROR_CONN_LOST) { @@ -142,6 +155,7 @@ STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errc return 0; } if (r == SSL_EAGAIN) { +eagain: r = MP_EAGAIN; } *errcode = r; @@ -187,12 +201,14 @@ STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, i } STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) { - // Currently supports only blocking mode - (void)self_in; - if (!mp_obj_is_true(flag_in)) { - mp_raise_NotImplementedError(NULL); - } - return mp_const_none; + mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(self_in); + mp_obj_t sock = o->sock; + mp_obj_t dest[3]; + mp_load_method(sock, MP_QSTR_setblocking, dest); + dest[2] = flag_in; + mp_obj_t res = mp_call_method_n_kw(1, 0, dest); + o->blocking = mp_obj_is_true(flag_in); + return res; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking); @@ -234,6 +250,7 @@ STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_ { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, { 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_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_do_handshake, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, }; // TODO: Check that sock implements stream protocol diff --git a/tests/extmod/ussl_basic.py.exp b/tests/extmod/ussl_basic.py.exp index cb9c51f7a1..57eed8c57f 100644 --- a/tests/extmod/ussl_basic.py.exp +++ b/tests/extmod/ussl_basic.py.exp @@ -4,6 +4,5 @@ wrap_socket: OSError(5,) setblocking: NotImplementedError 4 b'' -read: OSError(-261,) read: OSError(9,) write: OSError(9,) From 7b5400134b6d121741234cc99313145c0edf28c2 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 1 Mar 2019 23:48:16 +0300 Subject: [PATCH 0308/1788] tests/ussl_basic: Disable setblocking() calls. Now that setblocking() is implemented in modussl_axtls, it calls into the underlying stream object, and io.BytesIO doesn't have setblocking(). --- tests/extmod/ussl_basic.py | 13 +++++++------ tests/extmod/ussl_basic.py.exp | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/tests/extmod/ussl_basic.py b/tests/extmod/ussl_basic.py index e8710ed51a..a040fc20ca 100644 --- a/tests/extmod/ussl_basic.py +++ b/tests/extmod/ussl_basic.py @@ -20,12 +20,13 @@ ss = ssl.wrap_socket(socket, server_side=1) # print print(repr(ss)[:12]) -# setblocking -try: - ss.setblocking(False) -except NotImplementedError: - print('setblocking: NotImplementedError') -ss.setblocking(True) +# setblocking() propagates call to the underlying stream object, and +# io.BytesIO doesn't have setblocking() (in CPython too). +#try: +# ss.setblocking(False) +#except NotImplementedError: +# print('setblocking: NotImplementedError') +#ss.setblocking(True) # write print(ss.write(b'aaaa')) diff --git a/tests/extmod/ussl_basic.py.exp b/tests/extmod/ussl_basic.py.exp index 57eed8c57f..5282338319 100644 --- a/tests/extmod/ussl_basic.py.exp +++ b/tests/extmod/ussl_basic.py.exp @@ -1,8 +1,8 @@ ssl_handshake_status: -256 wrap_socket: OSError(5,) <_SSLSocket -setblocking: NotImplementedError 4 b'' +read: OSError(-261,) read: OSError(9,) write: OSError(9,) From 859596ce25bcaa9b6104f16b8b55d0832c55e3f8 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Mon, 29 Apr 2019 12:00:13 +1000 Subject: [PATCH 0309/1788] lib/utils: Make pyexec_file_if_exists run frozen scripts if they exist. So that boot.py and/or main.py can be frozen (either as STR or MPY) in the same way that other scripts are frozen. Frozen scripts have preference to scripts in the VFS. --- lib/utils/pyexec.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/utils/pyexec.c b/lib/utils/pyexec.c index 946a97a00a..adb16937d0 100644 --- a/lib/utils/pyexec.c +++ b/lib/utils/pyexec.c @@ -542,8 +542,12 @@ int pyexec_file(const char *filename) { } int pyexec_file_if_exists(const char *filename) { - mp_import_stat_t stat = mp_import_stat(filename); - if (stat != MP_IMPORT_STAT_FILE) { + #if MICROPY_MODULE_FROZEN + if (mp_frozen_stat(filename) == MP_IMPORT_STAT_FILE) { + return pyexec_frozen_module(filename); + } + #endif + if (mp_import_stat(filename) != MP_IMPORT_STAT_FILE) { return 1; // success (no file is the same as an empty file executing without fail) } return pyexec_file(filename); From 245916259926777b1b157c679785597572576f57 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 1 May 2019 12:41:07 +1000 Subject: [PATCH 0310/1788] lib/utils/interrupt_char: Invalidate interrupt char at start up. Otherwise mp_interrupt_char will have a value of zero on start up (because it's in the BSS) and a KeyboardInterrupt may be raised during start up. For example this can occur if there is a UART attached to the REPL which sends spurious null bytes when the device turns on. --- lib/utils/interrupt_char.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/utils/interrupt_char.c b/lib/utils/interrupt_char.c index fca0f95b5b..43d45e5aec 100644 --- a/lib/utils/interrupt_char.c +++ b/lib/utils/interrupt_char.c @@ -29,7 +29,7 @@ #if MICROPY_KBD_EXCEPTION -int mp_interrupt_char; +int mp_interrupt_char = -1; void mp_hal_set_interrupt_char(int c) { if (c != -1) { From ff0306dfa5ceee8c2c52ae82c4336e5c23d36176 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 1 May 2019 13:08:05 +1000 Subject: [PATCH 0311/1788] stm32/usb: Remove mp_hal_set_interrupt_char now that it's reset at boot. --- ports/stm32/usb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index e81225e605..18841fdee4 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -115,7 +115,6 @@ void pyb_usb_init0(void) { #if MICROPY_HW_USB_ENABLE_CDC2 usb_device.usbd_cdc2_itf.attached_to_repl = false; #endif - mp_hal_set_interrupt_char(-1); MP_STATE_PORT(pyb_hid_report_desc) = MP_OBJ_NULL; } From cbeac903e86bfb0c50f55960201f9eaa9d45745a Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 1 May 2019 14:50:27 +1000 Subject: [PATCH 0312/1788] stm32/main: Increase default UART REPL rx buffer from 64 to 260 bytes. This allows the UART to buffer at least 256 bytes (taking into account the extra byte needed by the ring buffer, and word alignment). --- ports/stm32/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 0bdbbd481d..a37c6f8979 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -78,7 +78,7 @@ STATIC fs_user_mount_t fs_user_mount_flash; #if defined(MICROPY_HW_UART_REPL) #ifndef MICROPY_HW_UART_REPL_RXBUF -#define MICROPY_HW_UART_REPL_RXBUF (64) +#define MICROPY_HW_UART_REPL_RXBUF (260) #endif STATIC pyb_uart_obj_t pyb_uart_repl_obj; STATIC uint8_t pyb_uart_repl_rxbuf[MICROPY_HW_UART_REPL_RXBUF]; From 34a7d7ebebc93bf9c4f166b0b523ceab844c7d91 Mon Sep 17 00:00:00 2001 From: stijn Date: Tue, 30 Apr 2019 11:05:57 +0200 Subject: [PATCH 0313/1788] unix/gcollect: Make sure stack/regs get captured properly for GC. When building with link time optimization enabled it is possible both gc_collect() and gc_collect_regs_and_stack() get inlined into gc_alloc() which can result in the regs variable being pushed on the stack earlier than some of the registers. Depending on the calling convention, those registers might however contain pointers to blocks which have just been allocated in the caller of gc_alloc(). Then those pointers end up higher on the stack than regs, aren't marked by gc_collect_root() and hence get sweeped, even though they're still in use. As reported in #4652 this happened for in 32-bit msvc release builds: mp_lexer_new() does two consecutive allocations and the latter triggered a gc_collect() which would sweep the memory of the first allocation again. --- ports/unix/gccollect.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ports/unix/gccollect.c b/ports/unix/gccollect.c index 02f6fc91a8..ddc2d92c3b 100644 --- a/ports/unix/gccollect.c +++ b/ports/unix/gccollect.c @@ -149,9 +149,14 @@ STATIC void gc_helper_get_regs(regs_t arr) { #endif // MICROPY_GCREGS_SETJMP // this function is used by mpthreadport.c -void gc_collect_regs_and_stack(void); +MP_NOINLINE void gc_collect_regs_and_stack(void); -void gc_collect_regs_and_stack(void) { +// Explicitly mark this as noinline to make sure the regs variable +// is effectively at the top of the stack: otherwise, in builds where +// LTO is enabled and a lot of inlining takes place we risk a stack +// layout where regs is lower on the stack than pointers which have +// just been allocated but not yet marked, and get incorrectly sweeped. +MP_NOINLINE void gc_collect_regs_and_stack(void) { regs_t regs; gc_helper_get_regs(regs); // GC stack (and regs because we captured them) From 9ef784dcc6aa2abd7325b43f3d1613b8ac5d9f3f Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 1 May 2019 15:24:21 +1000 Subject: [PATCH 0314/1788] py/asmthumb: Support asm_thumb code running on normal ARM processors. With this change, @micropython.asm_thumb functions will work on standard ARM processors (that are in ARM state by default), in scripts and precompiled .mpy files. Addresses issue #4675. --- py/asmthumb.c | 17 +++++++++++++++++ py/compile.c | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/py/asmthumb.c b/py/asmthumb.c index e6bba7ea60..68fb8f29ee 100644 --- a/py/asmthumb.c +++ b/py/asmthumb.c @@ -33,6 +33,8 @@ // wrapper around everything in this file #if MICROPY_EMIT_THUMB || MICROPY_EMIT_INLINE_THUMB +#include "py/mpstate.h" +#include "py/persistentcode.h" #include "py/mphal.h" #include "py/asmthumb.h" @@ -118,6 +120,21 @@ STATIC void asm_thumb_write_word32(asm_thumb_t *as, int w32) { void asm_thumb_entry(asm_thumb_t *as, int num_locals) { assert(num_locals >= 0); + // If this Thumb machine code is run from ARM state then add a prelude + // to switch to Thumb state for the duration of the function. + #if MICROPY_DYNAMIC_COMPILER || MICROPY_EMIT_ARM || (defined(__arm__) && !defined(__thumb2__)) + #if MICROPY_DYNAMIC_COMPILER + if (mp_dynamic_compiler.native_arch == MP_NATIVE_ARCH_ARMV6) + #endif + { + asm_thumb_op32(as, 0x4010, 0xe92d); // push {r4, lr} + asm_thumb_op32(as, 0xe009, 0xe28f); // add lr, pc, 8 + 1 + asm_thumb_op32(as, 0xff3e, 0xe12f); // blx lr + asm_thumb_op32(as, 0x4010, 0xe8bd); // pop {r4, lr} + asm_thumb_op32(as, 0xff1e, 0xe12f); // bx lr + } + #endif + // 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 diff --git a/py/compile.c b/py/compile.c index 4919a16595..01e4ff9b65 100644 --- a/py/compile.c +++ b/py/compile.c @@ -124,7 +124,7 @@ STATIC const emit_inline_asm_method_table_t *emit_asm_table[] = { NULL, NULL, NULL, - NULL, + &emit_inline_thumb_method_table, &emit_inline_thumb_method_table, &emit_inline_thumb_method_table, &emit_inline_thumb_method_table, From e70c438c71cbc3c44b8370ab5504658328b3ced9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 1 May 2019 15:31:00 +1000 Subject: [PATCH 0315/1788] mpy-cross: Automatically select ARMV6 arch when running on such a host. --- mpy-cross/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mpy-cross/main.c b/mpy-cross/main.c index 6e5af2739b..7bf2075962 100644 --- a/mpy-cross/main.c +++ b/mpy-cross/main.c @@ -196,6 +196,8 @@ MP_NOINLINE int main_(int argc, char **argv) { mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X86; #elif defined(__x86_64__) mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X64; + #elif defined(__arm__) && !defined(__thumb2__) + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_ARMV6; #else mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_NONE; #endif From 3fbf32b947eb798cf4a717adc23026e677d06bf0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 2 May 2019 13:00:00 +1000 Subject: [PATCH 0316/1788] stm32/powerctrl: Support changing frequency when HSI is clock source. This patch makes pllvalues.py generate two tables: one for when HSI is used and one for when HSE is used. The correct table is then selected at compile time via the existing MICROPY_HW_CLK_USE_HSI. --- ports/stm32/boards/pllvalues.py | 59 ++++++++++++++++++++++----------- ports/stm32/powerctrl.c | 10 ++++-- 2 files changed, 48 insertions(+), 21 deletions(-) diff --git a/ports/stm32/boards/pllvalues.py b/ports/stm32/boards/pllvalues.py index 4b090c455b..da1b81216f 100644 --- a/ports/stm32/boards/pllvalues.py +++ b/ports/stm32/boards/pllvalues.py @@ -5,6 +5,7 @@ for the machine.freq() function. """ from __future__ import print_function +import re def close_int(x): return abs(x - round(x)) < 0.01 @@ -109,12 +110,18 @@ def verify_pll(hse, pll): assert 1 <= vco_in <= 2 assert 192 <= vco_out <= 432 +def compute_pll_table(source_clk, relax_pll48): + valid_plls = [] + for sysclk in range(2, 217, 2): + pll = compute_pll2(source_clk, sysclk, relax_pll48) + if pll is not None: + verify_pll(source_clk, pll) + valid_plls.append((sysclk, pll)) + return valid_plls + def generate_c_table(hse, valid_plls): - valid_plls = valid_plls + [(16, (0, 0, 2, 0))] - if hse < 16: - valid_plls.append((hse, (1, 0, 2, 0))) valid_plls.sort() - print("// (M, P/2-1, SYS) values for %u MHz HSE" % hse) + print("// (M, P/2-1, SYS) values for %u MHz source" % hse) print("static const uint16_t pll_freq_table[%u] = {" % len(valid_plls)) for sys, (M, N, P, Q) in valid_plls: print(" (%u << 10) | (%u << 8) | %u," % (M, P // 2 - 1, sys)) @@ -137,6 +144,8 @@ def main(): c_table = False relax_pll48 = False + hse = None + hsi = None while True: if argv[0] == '-c': @@ -153,32 +162,44 @@ def main(): sys.exit(1) if argv[0].startswith("file:"): - # extract HSE_VALUE from header file + # extract HSE_VALUE, and optionally HSI_VALUE, from header file + regex = re.compile(r'#define +(HSE_VALUE|HSI_VALUE) +\(\(uint32_t\)([0-9]+)\)') with open(argv[0][5:]) as f: for line in f: line = line.strip() - if line.startswith("#define") and line.find("HSE_VALUE") != -1: - idx_start = line.find("((uint32_t)") + 11 - idx_end = line.find(")", idx_start) - hse = int(line[idx_start:idx_end]) // 1000000 - break - else: + m = regex.match(line) + if m: + val = int(m.group(2)) // 1000000 + if m.group(1) == 'HSE_VALUE': + hse = val + else: + hsi = val + if hse is None: raise ValueError("%s does not contain a definition of HSE_VALUE" % argv[0]) + if hsi is not None and hsi > 16: + # Currently, a HSI value greater than 16MHz is not supported + hsi = None else: # HSE given directly as an integer hse = int(argv[0]) - valid_plls = [] - for sysclk in range(2, 217, 2): - pll = compute_pll2(hse, sysclk, relax_pll48) - if pll is not None: - verify_pll(hse, pll) - valid_plls.append((sysclk, pll)) + hse_valid_plls = compute_pll_table(hse, relax_pll48) + if hsi is not None: + hsi_valid_plls = compute_pll_table(hsi, relax_pll48) if c_table: - generate_c_table(hse, valid_plls) + print('#if MICROPY_HW_CLK_USE_HSI') + if hsi is not None: + hsi_valid_plls.append((hsi, (0, 0, 2, 0))) + generate_c_table(hsi, hsi_valid_plls) + print('#else') + if hsi is not None: + hse_valid_plls.append((hsi, (0, 0, 2, 0))) + hse_valid_plls.append((hse, (1, 0, 2, 0))) + generate_c_table(hse, hse_valid_plls) + print('#endif') else: - print_table(hse, valid_plls) + print_table(hse, hse_valid_plls) if __name__ == "__main__": main() diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c index 42bd262c27..c3792be3ed 100644 --- a/ports/stm32/powerctrl.c +++ b/ports/stm32/powerctrl.c @@ -136,7 +136,7 @@ int powerctrl_set_sysclk(uint32_t sysclk, uint32_t ahb, uint32_t apb1, uint32_t } // Default PLL parameters that give 48MHz on PLL48CK - uint32_t m = HSE_VALUE / 1000000, n = 336, p = 2, q = 7; + uint32_t m = MICROPY_HW_CLK_VALUE / 1000000, n = 336, p = 2, q = 7; uint32_t sysclk_source; bool need_pllsai = false; @@ -157,7 +157,7 @@ int powerctrl_set_sysclk(uint32_t sysclk, uint32_t ahb, uint32_t apb1, uint32_t // use PLL sysclk_source = RCC_SYSCLKSOURCE_PLLCLK; uint32_t vco_out = sys * p; - n = vco_out * m / (HSE_VALUE / 1000000); + n = vco_out * m / (MICROPY_HW_CLK_VALUE / 1000000); q = vco_out / 48; #if defined(STM32F7) need_pllsai = vco_out % 48 != 0; @@ -178,7 +178,11 @@ set_clk: if (sysclk_source == RCC_SYSCLKSOURCE_PLLCLK) { // Set HSE as system clock source to allow modification of the PLL configuration // We then change to PLL after re-configuring PLL + #if MICROPY_HW_CLK_USE_HSI + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; + #else RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE; + #endif } else { // Directly set the system clock source as desired RCC_ClkInitStruct.SYSCLKSource = sysclk_source; @@ -217,6 +221,8 @@ set_clk: RCC_OscInitTypeDef RCC_OscInitStruct; RCC_OscInitStruct.OscillatorType = MICROPY_HW_RCC_OSCILLATOR_TYPE; RCC_OscInitStruct.HSEState = MICROPY_HW_RCC_HSE_STATE; + RCC_OscInitStruct.HSIState = MICROPY_HW_RCC_HSI_STATE; + RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = MICROPY_HW_RCC_PLL_SRC; RCC_OscInitStruct.PLL.PLLM = m; From a974f2dc6e45dc1fde88863df6b90dcaebf5bfe8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 2 May 2019 14:53:26 +1000 Subject: [PATCH 0317/1788] stm32/flash: Fix bug computing page number for L432 page erase. --- ports/stm32/flash.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ports/stm32/flash.c b/ports/stm32/flash.c index e1cf707d34..56896a7037 100644 --- a/ports/stm32/flash.c +++ b/ports/stm32/flash.c @@ -122,6 +122,12 @@ static uint32_t get_page(uint32_t addr) { } #endif +#elif defined(STM32L4) && !defined(SYSCFG_MEMRMP_FB_MODE) + +static uint32_t get_page(uint32_t addr) { + return (addr - FLASH_BASE) / FLASH_PAGE_SIZE; +} + #endif uint32_t flash_get_sector_info(uint32_t addr, uint32_t *start_addr, uint32_t *size) { @@ -167,7 +173,7 @@ void flash_erase(uint32_t flash_dest, uint32_t num_word32) { #elif (defined(STM32L4) && !defined(SYSCFG_MEMRMP_FB_MODE)) __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS); EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; - EraseInitStruct.Page = flash_dest; + EraseInitStruct.Page = get_page(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); From 1b956ec81701ad9ae36e8e0fd625eff32e3e2a3d Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Fri, 19 Apr 2019 15:15:18 +1000 Subject: [PATCH 0318/1788] stm32: Add support for F413 MCUs. Includes: - Support for CAN3. - Support for UART9 and UART10. - stm32f413xg.ld and stm32f413xh.ld linker scripts. - stm32f413_af.csv alternate function mapping. - startup_stm32f413xx.s because F413 has different interrupt vector table. - Memory configuration with: 240K filesystem, 240K heap, 16K stack. --- ports/stm32/adc.c | 2 +- ports/stm32/boards/startup_stm32f413xx.s | 580 +++++++++++++++++++++++ ports/stm32/boards/stm32f413_af.csv | 116 +++++ ports/stm32/boards/stm32f413xg.ld | 31 ++ ports/stm32/boards/stm32f413xh.ld | 31 ++ ports/stm32/can.c | 53 ++- ports/stm32/can.h | 1 + ports/stm32/flashbdev.c | 9 + ports/stm32/machine_uart.c | 8 + ports/stm32/mpconfigboard_common.h | 19 +- ports/stm32/mpconfigport.h | 2 +- ports/stm32/stm32_it.c | 36 ++ ports/stm32/uart.c | 50 ++ ports/stm32/uart.h | 2 + 14 files changed, 925 insertions(+), 15 deletions(-) create mode 100644 ports/stm32/boards/startup_stm32f413xx.s create mode 100644 ports/stm32/boards/stm32f413_af.csv create mode 100644 ports/stm32/boards/stm32f413xg.ld create mode 100644 ports/stm32/boards/stm32f413xh.ld diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index 73588e4a3f..4f92324562 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -137,7 +137,7 @@ #define VBAT_DIV (2) #elif defined(STM32F427xx) || defined(STM32F429xx) || \ defined(STM32F437xx) || defined(STM32F439xx) || \ - defined(STM32F446xx) || \ + defined(STM32F446xx) || defined(STM32F413xx) || \ defined(STM32F722xx) || defined(STM32F723xx) || \ defined(STM32F732xx) || defined(STM32F733xx) || \ defined(STM32F746xx) || defined(STM32F765xx) || \ diff --git a/ports/stm32/boards/startup_stm32f413xx.s b/ports/stm32/boards/startup_stm32f413xx.s new file mode 100644 index 0000000000..64108ad38d --- /dev/null +++ b/ports/stm32/boards/startup_stm32f413xx.s @@ -0,0 +1,580 @@ +/** + ****************************************************************************** + * @file startup_stm32f413xx.s + * @author MCD Application Team + * @brief STM32F413xx Devices vector table for GCC based toolchains. + * 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 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-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 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 M3. 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, DAC1 and DAC2 */ + .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 DFSDM1_FLT0_IRQHandler /* DFSDM1 Filter0 */ + .word DFSDM1_FLT1_IRQHandler /* DFSDM1 Filter1 */ + .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 CAN3_TX_IRQHandler /* CAN3 TX */ + .word CAN3_RX0_IRQHandler /* CAN3 RX0 */ + .word CAN3_RX1_IRQHandler /* CAN3 RX1 */ + .word CAN3_SCE_IRQHandler /* CAN3 SCE */ + .word 0 /* Reserved */ + .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 0 /* Reserved */ + .word SAI1_IRQHandler /* SAI1 */ + .word UART9_IRQHandler /* UART9 */ + .word UART10_IRQHandler /* UART10 */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word QUADSPI_IRQHandler /* QuadSPI */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word FMPI2C1_EV_IRQHandler /* FMPI2C1 Event */ + .word FMPI2C1_ER_IRQHandler /* FMPI2C1 Error */ + .word LPTIM1_IRQHandler /* LPTIM1 */ + .word DFSDM2_FLT0_IRQHandler /* DFSDM2 Filter0 */ + .word DFSDM2_FLT1_IRQHandler /* DFSDM2 Filter1 */ + .word DFSDM2_FLT2_IRQHandler /* DFSDM2 Filter2 */ + .word DFSDM2_FLT3_IRQHandler /* DFSDM2 Filter3 */ + +/******************************************************************************* +* +* 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 DFSDM1_FLT0_IRQHandler + .thumb_set DFSDM1_FLT0_IRQHandler,Default_Handler + + .weak DFSDM1_FLT1_IRQHandler + .thumb_set DFSDM1_FLT1_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 CAN3_TX_IRQHandler + .thumb_set CAN3_TX_IRQHandler,Default_Handler + + .weak CAN3_RX0_IRQHandler + .thumb_set CAN3_RX0_IRQHandler,Default_Handler + + .weak CAN3_RX1_IRQHandler + .thumb_set CAN3_RX1_IRQHandler,Default_Handler + + .weak CAN3_SCE_IRQHandler + .thumb_set CAN3_SCE_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 SAI1_IRQHandler + .thumb_set SAI1_IRQHandler,Default_Handler + + .weak UART9_IRQHandler + .thumb_set UART9_IRQHandler,Default_Handler + + .weak UART10_IRQHandler + .thumb_set UART10_IRQHandler,Default_Handler + + .weak QUADSPI_IRQHandler + .thumb_set QUADSPI_IRQHandler,Default_Handler + + .weak FMPI2C1_EV_IRQHandler + .thumb_set FMPI2C1_EV_IRQHandler,Default_Handler + + .weak FMPI2C1_ER_IRQHandler + .thumb_set FMPI2C1_ER_IRQHandler,Default_Handler + + .weak LPTIM1_IRQHandler + .thumb_set LPTIM1_IRQHandler,Default_Handler + + .weak DFSDM2_FLT0_IRQHandler + .thumb_set DFSDM2_FLT0_IRQHandler,Default_Handler + + .weak DFSDM2_FLT1_IRQHandler + .thumb_set DFSDM2_FLT1_IRQHandler,Default_Handler + + .weak DFSDM2_FLT2_IRQHandler + .thumb_set DFSDM2_FLT2_IRQHandler,Default_Handler + + .weak DFSDM2_FLT3_IRQHandler + .thumb_set DFSDM2_FLT3_IRQHandler,Default_Handler +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32/boards/stm32f413_af.csv b/ports/stm32/boards/stm32f413_af.csv new file mode 100644 index 0000000000..428ce44cfc --- /dev/null +++ b/ports/stm32/boards/stm32f413_af.csv @@ -0,0 +1,116 @@ +Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15, +,,SYS_AF,TIM1/TIM2/LPTIM1,TIM3/TIM4/TIM5,TIM8/9/10/11/DFSDM2,I2C1/2/3/I2CFMP1,SPI1/2/3/4/I2S1/2/3/4,SPI2/3/4/5/I2S2/3/4/5/DFSDM1/2,SPI3/I2S3/USART1/2/3/DFSDM2,USART3/4/5/6/7/8/CAN1/DFSDM1,I2C2/I2C3/I2CFMP1/CAN1/2/TIM12/13/14/QUADSPI,SAI1/DFSDM1/DFSDM2/QUADSPI/FSMC/OTG1_FS,UART4/5/9/10/CAN3,FSMC /SDIO,,RNG,SYS_AF,ADC +PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,,,,,,EVENTOUT,ADC1_IN0 +PortA,PA1,,TIM2_CH2,TIM5_CH2,,,SPI4_MOSI/I2S4_SD,,USART2_RTS,UART4_RX,QUADSPI_BK1_IO3,,,,,,EVENTOUT,ADC1_IN1 +PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,I2S2_CKIN,,USART2_TX,,,,,FSMC_D4,,,EVENTOUT,ADC1_IN2 +PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,I2S2_MCK,,USART2_RX,,,SAI1_SD_B,,FSMC_D5,,,EVENTOUT,ADC1_IN3 +PortA,PA4,,,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART2_CK,DFSDM1_DATIN1,,,,FSMC_D6,,,EVENTOUT,ADC1_IN4 +PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK/I2S1_CK,,,DFSDM1_CKIN1,,,,FSMC_D7,,,EVENTOUT,ADC1_IN5 +PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,I2S2_MCK,DFSDM2_CKIN1,,TIM13_CH1,QUADSPI_BK2_IO0,,SDIO_CMD,,,EVENTOUT,ADC1_IN6 +PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI/I2S1_SD,,DFSDM2_DATIN1,,TIM14_CH1,QUADSPI_BK2_IO1,,,,,EVENTOUT,ADC1_IN7 +PortA,PA8,MCO_1,TIM1_CH1,,,I2C3_SCL,,DFSDM1_CKOUT,USART1_CK,UART7_RX,,USB_FS_SOF,CAN3_RX,SDIO_D1,,,EVENTOUT, +PortA,PA9,,TIM1_CH2,,DFSDM2_CKIN3,I2C3_SMBA,SPI2_SCK/I2S2_CK,,USART1_TX,,,USB_FS_VBUS,,SDIO_D2,,,EVENTOUT, +PortA,PA10,,TIM1_CH3,,DFSDM2_DATIN3,,SPI2_MOSI/I2S2_SD,SPI5_MOSI/I2S5_SD,USART1_RX,,,USB_FS_ID,,,,,EVENTOUT, +PortA,PA11,,TIM1_CH4,,DFSDM2_CKIN5,,SPI2_NSS/I2S2_WS,SPI4_MISO,USART1_CTS,USART6_TX,CAN1_RX,USB_FS_DM,UART4_RX,,,,EVENTOUT, +PortA,PA12,,TIM1_ETR,,DFSDM2_DATIN5,,SPI2_MISO,SPI5_MISO,USART1_RTS,USART6_RX,CAN1_TX,USB_FS_DP,UART4_TX,,,,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,UART7_TX,,SAI1_MCLK_A,CAN3_TX,,,,EVENTOUT, +PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,SPI5_SCK/I2S5_CK,,,,,,,,,EVENTOUT,ADC1_IN8 +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,SPI5_NSS/I2S5_WS,,DFSDM1_DATIN0,QUADSPI_CLK,,,,,,EVENTOUT,ADC1_IN9 +PortB,PB2,,LPTIM1_OUT,,,,,DFSDM1_CKIN0,,,QUADSPI_CLK,,,,,,EVENTOUT, +PortB,PB3,JTDO,TIM2_CH2,,,I2CFMP1_SDA,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,USART1_RX,UART7_RX,I2C2_SDA,SAI1_SD_A,CAN3_RX,,,,EVENTOUT, +PortB,PB4,JTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,I2S3ext_SD,UART7_TX,I2C3_SDA,SAI1_SCK_A,CAN3_TX,SDIO_D0,,,EVENTOUT, +PortB,PB5,,LPTIM1_IN1,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI/I2S1_SD,SPI3_MOSI/I2S3_SD,,,CAN2_RX,SAI1_FS_A,UART5_RX,SDIO_D3,,,EVENTOUT, +PortB,PB6,,LPTIM1_ETR,TIM4_CH1,,I2C1_SCL,,DFSDM2_CKIN7,USART1_TX,,CAN2_TX,QUADSPI_BK1_NCS,UART5_TX,SDIO_D0,,,EVENTOUT, +PortB,PB7,,LPTIM1_IN2,TIM4_CH2,,I2C1_SDA,,DFSDM2_DATIN7,USART1_RX,,,,,FSMC_NL,,,EVENTOUT, +PortB,PB8,,LPTIM1_OUT,TIM4_CH3,TIM10_CH1,I2C1_SCL,,SPI5_MOSI/I2S5_SD,DFSDM2_CKIN1,CAN1_RX,I2C3_SDA,,UART5_RX,SDIO_D4,,,EVENTOUT, +PortB,PB9,,,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,DFSDM2_DATIN1,,CAN1_TX,I2C2_SDA,,UART5_TX,SDIO_D5,,,EVENTOUT, +PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK/I2S2_CK,I2S3_MCK,USART3_TX,,I2CFMP4_SCL,DFSDM2_CKOUT,,SDIO_D7,,,EVENTOUT, +PortB,PB11,,TIM2_CH4,,,I2C2_SDA,I2S2_CKIN,,USART3_RX,,,,,,,,EVENTOUT, +PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,SPI4_NSS/I2S4_WS,SPI3_SCK/I2S3_CK,USART3__CK,CAN2_RX,DFSDM1_DATIN1,UART5_RX,FSMC_D13/FSMC_DA13,,,EVENTOUT, +PortB,PB13,,TIM1_CH1N,,,I2CFMP1_SMBA,SPI2_SCK/I2S2_CK,SPI4_SCK/I2S4_CK,,USART3_CTS,CAN2_TX,DFSDM1_CKIN1,UART5_TX,,,,EVENTOUT, +PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,I2CFMP1_SDA,SPI2_MISO,I2S2ext_SD,USART3_RTS,DFSDM1_DATIN2,TIM12_CH1,FSMC_D0,,SDIO_D6,,,EVENTOUT, +PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,I2CFMP1_SCL,SPI2_MOSI/I2S2_SD,,,DFSDM1_CKIN2,TIM12_CH2,,,SDIO_CK,,,EVENTOUT, +PortC,PC0,,LPTIM1_IN1,,DFSDM2_CKIN4,,,,SAI1_MCLK_B,,,,,,,,EVENTOUT,ADC1_IN10 +PortC,PC1,,LPTIM1_OUT,,DFSDM2_DATIN4,,,,SAI1_SD_B,,,,,,,,EVENTOUT,ADC1_IN11 +PortC,PC2,,LPTIM1_IN2,,DFSDM2_DATIN7,,SPI2_MISO,I2S2ext_SD,SAI1_SCK_B,DFSDM1_CKOUT,,,,FSMC_NWE,,,EVENTOUT,ADC1_IN12 +PortC,PC3,,LPTIM1_ETR,,DFSDM2_CKIN7,,SPI2_MOSI/I2S2_SD,,SAI1_FS_B,,,,,FSMC_A0,,,EVENTOUT,ADC1_IN13 +PortC,PC4,,,,DFSDM2_CKIN2,,I2S1_MCK,,,,,QUADSPI_BK2_IO2,,FSMC_NE4,,,EVENTOUT,ADC1_IN14 +PortC,PC5,,,,DFSDM2_DATIN2,I2CFMP1_SMBA,,,USART3_RX,,,QUADSPI_BK2_IO3,,FSMC_NOE,,,EVENTOUT,ADC1_IN15 +PortC,PC6,,,TIM3_CH1,TIM8_CH1,2CFMP1_SCL,I2S2_MCK,DFSDM1_CKIN3,DFSDM2_DATIN6,USART6_TX,,FSMC_D1,,SDIO_D6,,,EVENTOUT, +PortC,PC7,,,TIM3_CH2,TIM8_CH2,I2CFMP1_SDA,SPI2_SCK/I2S2_CK,I2S3_MCK,DFSDM2_CKIN6,USART6_RX,,DFSDM1_DATIN3,,SDIO_D7,,,EVENTOUT, +PortC,PC8,,,TIM3_CH3,TIM8_CH3,,,,DFSDM2_CKIN3,USART6_CK,QUADSPI_BK1_IO2,,,SDIO_D0,,,EVENTOUT, +PortC,PC9,MCO_2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S2_CKIN,,DFSDM2_DATIN3,,QUADSPI_BK1_IO0,,,SDIO_D1,,,EVENTOUT, +PortC,PC10,,,,DFSDM2_CKIN5,,,SPI3_SCK/I2S3_CK,USART3_TX,,QUADSPI_BK1_IO1,,,SDIO_D2,,,EVENTOUT, +PortC,PC11,,,,DFSDM2_DATIN5,,I2S3ext_SD,SPI3_MISO,USART3_RX,UART4_RX,QUADSPI_BK2_NCS,FSMC_D2,,SDIO_D3,,,EVENTOUT, +PortC,PC12,,,,,,,SPI3_MOSI/I2S3_SD,USART3_CK,UART5_TX,,FSMC_D3,,SDIO_CK,,,EVENTOUT, +PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD0,,,,DFSDM2_CKIN6,,,,,,CAN1_RX,,UART4_RX,FSMC_D2/FSMC_DA2,,,EVENTOUT, +PortD,PD1,,,,DFSDM2_DATIN6,,,,,,CAN1_TX,,UART4_TX,FSMC_D3/FSMC_DA3,,,EVENTOUT, +PortD,PD2,,,TIM3_ETR,DFSDM2_CKOUT,,,,,UART5_RX,,FSMC_NWE,,SDIO_CMD,,,EVENTOUT, +PortD,PD3,TRACED1,,,,,SPI2_SCK/I2S2_CK,DFSDM1_DATIN0,USART2_CTS,,QUADSPI_CLK,,,FSMC_CLK,,,EVENTOUT, +PortD,PD4,,,,,,,DFSDM1_CKIN0,USART2_RTS,,,,,FSMC_NOE,,,EVENTOUT, +PortD,PD5,,,,DFSDM2_CKOUT,,,,USART2_TX,,,,,FSMC_NWE,,,EVENTOUT, +PortD,PD6,,,,,,SPI3_MOSI/I2S3_SD,DFSDM1_DATIN1,USART2_RX,,,,,FSMC_NWAIT,,,EVENTOUT, +PortD,PD7,,,,,,,DFSDM1_CKIN1,USART2_CK,,,,,FSMC_NE1,,,EVENTOUT, +PortD,PD8,,,,,,,,USART3_TX,,,,,FSMC_D13/FSMC_DA13,,,EVENTOUT, +PortD,PD9,,,,,,,,USART3_RX,,,,,FSMC_D14/FSMC_DA14,,,EVENTOUT, +PortD,PD10,,,,,,,,USART3_CK,UART4_TX,,,,FSMC_D15/FSMC_DA15,,,EVENTOUT, +PortD,PD11,,,,DFSDM2_DATIN2,I2CFMP1_SMBA,,,USART3_CTS,,QUADSPI_BK1_IO0,,,FSMC_A16,,,EVENTOUT, +PortD,PD12,,,TIM4_CH1,DFSDM2_CKIN2,I2CFMP1_SCL,,,USART3_RTS,,QUADSPI_BK1_IO1,,,FSMC_A17,,,EVENTOUT, +PortD,PD13,,,TIM4_CH2,,I2CFMP1_SDA,,,,,QUADSPI_BK1_IO3,,,FSMC_A18,,,EVENTOUT, +PortD,PD14,,,TIM4_CH3,,I2CFMP1_SCL,,,,,,DFSDM2_CKIN0,UART9_RX,FSMC_D0/FSMC_DA0,,,EVENTOUT, +PortD,PD15,,,TIM4_CH4,,I2CFMP1_SDA,,,,,,DFSDM2_DATIN0,UART9_TX,FSMC_D1/FSMC_DA1,,,EVENTOUT, +PortE,PE0,,,TIM4_ETR,DFSDM2_CKIN4,,,,,UART8_RX,,,,FSMC_NBL0,,,EVENTOUT, +PortE,PE1,,,,DFSDM2_DATIN4,,,,,UART8_TX,,,,FSMC_NBL1,,,EVENTOUT, +PortE,PE2,TRACECLK,,,,,SPI4_SCK/I2S4_CK,SPI5_SCK/I2S5_CK,SAI1_MCLK_A,,QUADSPI_BK1_IO2,,UART10_RX,FSMC_A23,,,EVENTOUT, +PortE,PE3,TRACED0,,,,,,,SAI1_SD_B,,,,UART10_TX,FSMC_A19,,,EVENTOUT, +PortE,PE4,TRACED1,,,,,SPI4_NSS/I2S4_WS,SPI5_NSS/I2S5_WS,SAI1_SD_A,DFSDM1_DATIN3,,,,FSMC_A20,,,EVENTOUT, +PortE,PE5,TRACED2,,,TIM9_CH1,,SPI4_MISO,SPI5_MISO,SAI1_SCK_A,DFSDM1_CKIN3,,,,FSMC_A21,,,EVENTOUT, +PortE,PE6,TRACED3,,,TIM9_CH2,,SPI4_MOSI/I2S4_SD,SPI5_MOSI/I2S5_SD,SAI1_FS_A,,,,,FSMC_A22,,,EVENTOUT, +PortE,PE7,,TIM1_ETR,,,,,DFSDM1_DATIN2,,UART7_RX,,QUADSPI_BK2_IO0,,FSMC_D4/FSMC_DA4,,,EVENTOUT, +PortE,PE8,,TIM1_CH1N,,,,,DFSDM1_CKIN2,,UART7_TX,,QUADSPI_BK2_IO1,,FSMC_D5/FSMC_DA5,,,EVENTOUT, +PortE,PE9,,TIM1_CH1,,,,,DFSDM1_CKOUT,,,,QUADSPI_BK2_IO2,,FSMC_D6/FSMC_DA6,,,EVENTOUT, +PortE,PE10,,TIM1_CH2N,,DFSDM2_DATIN0,,,,,,,QUADSPI_BK2_IO3,,FSMC_D7/FSMC_DA7,,,EVENTOUT, +PortE,PE11,,TIM1_CH2,,DFSDM2_CKIN0,,SPI4_NSS/I2S4_WS,SPI5_NSS/I2S5_WS,,,,,,FSMC_D8/FSMC_DA8,,,EVENTOUT, +PortE,PE12,,TIM1_CH3N,,DFSDM2_DATIN7,,SPI4_SCK/I2S4_CK,SPI5_SCK/I2S5_CK,,,,,,FSMC_D9/FSMC_DA9,,,EVENTOUT, +PortE,PE13,,TIM1_CH3,,DFSDM2_CKIN7,,SPI4_MISO,SPI5_MISO,,,,,,FSMC_D10/FSMC_DA10,,,EVENTOUT, +PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI/I2S4_SD,SPI5_MOSI/I2S5_SD,,,,DFSDM2_DATIN1,,FSMC_D11/FSMC_DA11,,,EVENTOUT, +PortE,PE15,,TIM1_BKIN,,,,,,,,,DFSDM2_CKIN1,,FSMC_D12/FSMC_DA12,,,EVENTOUT, +PortF,PF0,,,,,I2C2_SDA,,,,,,,,FSMC_A0,,,EVENTOUT, +PortF,PF1,,,,,I2C2_SCL,,,,,,,,FSMC_A1,,,EVENTOUT, +PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FSMC_A2,,,EVENTOUT, +PortF,PF3,,,TIM5_CH1,,,,,,,,,,FSMC_A3,,,EVENTOUT, +PortF,PF4,,,TIM5_CH2,,,,,,,,,,FSMC_A4,,,EVENTOUT, +PortF,PF5,,,TIM5_CH3,,,,,,,,,,FSMC_A5,,,EVENTOUT, +PortF,PF6,TRACED0,,,TIM10_CH1,,,,SAI1_SD_B,UART7_RX,QUADSPI_BK1_IO3,,,,,,EVENTOUT, +PortF,PF7,TRACED1,,,TIM11_CH1,,,,SAI1_MCLK_B,UART7_TX,QUADSPI_BK1_IO2,,,,,,EVENTOUT, +PortF,PF8,,,,,,,,SAI1_SCK_B,UART8_RX,TIM13_CH1,QUADSPI_BK1_IO0,,,,,EVENTOUT, +PortF,PF9,,,,,,,,SAI1_FS_B,UART8_TX,TIM14_CH1,QUADSPI_BK1_IO1,,,,,EVENTOUT, +PortF,PF10,,TIM1_ETR,TIM5_CH4,,,,,,,,,,,,,EVENTOUT, +PortF,PF11,,,,TIM8_ETR,,,,,,,,,,,,EVENTOUT, +PortF,PF12,,,,TIM8_BKIN,,,,,,,,,FSMC_A6,,,EVENTOUT, +PortF,PF13,,,,,I2CFMP1_SMBA,,,,,,,,FSMC_A7,,,EVENTOUT, +PortF,PF14,,,,,I2CFMP1_SCL,,,,,,,,FSMC_A8,,,EVENTOUT, +PortF,PF15,,,,,I2CFMP1_SDA,,,,,,,,FSMC_A9,,,EVENTOUT, +PortG,PG0,,,,,,,,,,CAN1_RX,,UART9_RX,FSMC_A10,,,EVENTOUT, +PortG,PG1,,,,,,,,,,CAN1_TX,,UART9_TX,FSMC_A11,,,EVENTOUT, +PortG,PG2,,,,,,,,,,,,,FSMC_A12,,,EVENTOUT, +PortG,PG3,,,,,,,,,,,,,FSMC_A13,,,EVENTOUT, +PortG,PG4,,,,,,,,,,,,,FSMC_A14,,,EVENTOUT, +PortG,PG5,,,,,,,,,,,,,FSMC_A15,,,EVENTOUT, +PortG,PG6,,,,,,,,,,,QUADSPI_BK1_NCS,,,,,EVENTOUT, +PortG,PG7,,,,,,,,,USART6_CK,,,,,,,EVENTOUT, +PortG,PG8,,,,,,,,,USART6_RTS,,,,,,,EVENTOUT, +PortG,PG9,,,,,,,,,USART6_RX,QUADSPI_BK2_IO2,,,FSMC_NE2,,,EVENTOUT, +PortG,PG10,,,,,,,,,,,,,FSMC_NE3,,,EVENTOUT, +PortG,PG11,,,,,,,,,,CAN2_RX,,UART10_RX,,,,EVENTOUT, +PortG,PG12,,,,,,,,,USART6_RTS,CAN2_TX,,UART10_TX,FSMC_NE4,,,EVENTOUT, +PortG,PG13,TRACED2,,,,,,,,USART6_CTS,,,,FSMC_A24,,,EVENTOUT, +PortG,PG14,TRACED3,,,,,,,,USART6_TX,QUADSPI_BK2_IO3,,,FSMC_A25,,,EVENTOUT, +PortG,PG15,,,,,,,,,USART6_CTS,,,,,,,EVENTOUT, +PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT, diff --git a/ports/stm32/boards/stm32f413xg.ld b/ports/stm32/boards/stm32f413xg.ld new file mode 100644 index 0000000000..cac313bc67 --- /dev/null +++ b/ports/stm32/boards/stm32f413xg.ld @@ -0,0 +1,31 @@ +/* + GNU linker script for STM32F413xg (1MB flash, 320kB RAM) +*/ + +/* Specify the memory areas */ +/* FLASH_FS2 is placed before FLASH_TEXT to support 1MB and 1.5MB FLASH with common code in flashbdev.c */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K /* entire flash */ + FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 16K /* sector 0 */ + FLASH_FS (rx) : ORIGIN = 0x08004000, LENGTH = 176K /* sectors 1,2,3 are 16K, 4 is 64K, 5 is 128K (64K used) for filesystem */ + FLASH_FS2 (rx) : ORIGIN = 0x08040000, LENGTH = 128K /* sector 6 is 128K (64K used) for filesystem, Total filesystem 240K */ + FLASH_TEXT (rx) : ORIGIN = 0x08060000, LENGTH = 640K /* sectors 7,8,9,10,11 are 128K*/ + SRAM2 (xrw) : ORIGIN = 0x10000000, LENGTH = 64K + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 256K +} + +/* 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 = _ram_end - 16K; /* 240K, tunable */ diff --git a/ports/stm32/boards/stm32f413xh.ld b/ports/stm32/boards/stm32f413xh.ld new file mode 100644 index 0000000000..f6dc430e32 --- /dev/null +++ b/ports/stm32/boards/stm32f413xh.ld @@ -0,0 +1,31 @@ +/* + GNU linker script for STM32F413xh (1.5MB flash, 320kB RAM) +*/ + +/* Specify the memory areas */ +/* FLASH_FS2 is placed before FLASH_TEXT to support 1MB and 1.5MB FLASH with common code in flashbdev.c */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1536K /* entire flash */ + FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 16K /* sector 0 */ + FLASH_FS (rx) : ORIGIN = 0x08004000, LENGTH = 176K /* sectors 1,2,3 are 16K, 4 is 64K, 5 is 128K (64K used) for filesystem */ + FLASH_FS2 (rx) : ORIGIN = 0x08040000, LENGTH = 128K /* sector 6 is 128K (64K used) for filesystem, Total filesystem 240K */ + FLASH_TEXT (rx) : ORIGIN = 0x08060000, LENGTH = 1152K /* sectors 7,8,9,10,11,12,13,14,15 are 128K*/ + SRAM2 (xrw) : ORIGIN = 0x10000000, LENGTH = 64K + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 256K +} + +/* 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 = _ram_end - 16K; /* 240K, tunable */ diff --git a/ports/stm32/can.c b/ports/stm32/can.c index 2293f94db8..90a3d79a95 100644 --- a/ports/stm32/can.c +++ b/ports/stm32/can.c @@ -114,7 +114,7 @@ STATIC bool can_init(pyb_can_obj_t *can_obj) { sce_irq = CAN1_SCE_IRQn; pins[0] = MICROPY_HW_CAN1_TX; pins[1] = MICROPY_HW_CAN1_RX; - __CAN1_CLK_ENABLE(); + __HAL_RCC_CAN1_CLK_ENABLE(); break; #endif @@ -124,8 +124,18 @@ STATIC bool can_init(pyb_can_obj_t *can_obj) { 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(); + __HAL_RCC_CAN1_CLK_ENABLE(); // CAN2 is a "slave" and needs CAN1 enabled as well + __HAL_RCC_CAN2_CLK_ENABLE(); + break; + #endif + + #if defined(MICROPY_HW_CAN3_TX) + case PYB_CAN_3: + CANx = CAN3; + sce_irq = CAN3_SCE_IRQn; + pins[0] = MICROPY_HW_CAN3_TX; + pins[1] = MICROPY_HW_CAN3_RX; + __HAL_RCC_CAN3_CLK_ENABLE(); // CAN3 is a "master" and doesn't need CAN1 enabled as well break; #endif @@ -420,6 +430,10 @@ STATIC mp_obj_t pyb_can_make_new(const mp_obj_type_t *type, size_t n_args, size_ } else if (strcmp(port, MICROPY_HW_CAN2_NAME) == 0) { can_idx = PYB_CAN_2; #endif + #ifdef MICROPY_HW_CAN3_NAME + } else if (strcmp(port, MICROPY_HW_CAN3_NAME) == 0) { + can_idx = PYB_CAN_3; + #endif } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "CAN(%s) doesn't exist", port)); } @@ -479,17 +493,26 @@ STATIC mp_obj_t pyb_can_deinit(mp_obj_t self_in) { 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(); + __HAL_RCC_CAN1_FORCE_RESET(); + __HAL_RCC_CAN1_RELEASE_RESET(); + __HAL_RCC_CAN1_CLK_DISABLE(); #if defined(CAN2) } 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(); + __HAL_RCC_CAN2_FORCE_RESET(); + __HAL_RCC_CAN2_RELEASE_RESET(); + __HAL_RCC_CAN2_CLK_DISABLE(); + #endif + #if defined(CAN3) + } else if (self->can.Instance == CAN3) { + HAL_NVIC_DisableIRQ(CAN3_RX0_IRQn); + HAL_NVIC_DisableIRQ(CAN3_RX1_IRQn); + HAL_NVIC_DisableIRQ(CAN3_SCE_IRQn); + __HAL_RCC_CAN3_FORCE_RESET(); + __HAL_RCC_CAN3_RELEASE_RESET(); + __HAL_RCC_CAN3_CLK_DISABLE(); #endif } return mp_const_none; @@ -890,11 +913,15 @@ STATIC mp_obj_t pyb_can_setfilter(size_t n_args, const mp_obj_t *pos_args, mp_ma if (filter.FilterNumber >= can2_start_bank) { goto error; } - } else { + } else if (self->can_id == 2) { filter.FilterNumber = filter.FilterNumber + can2_start_bank; if (filter.FilterNumber > 27) { goto error; } + } else { + if (filter.FilterNumber > 13) { // CAN3 is independant and has its own 14 filters. + goto error; + } } filter.FilterActivation = ENABLE; filter.BankNumber = can2_start_bank; @@ -930,9 +957,13 @@ STATIC mp_obj_t pyb_can_rxcallback(mp_obj_t self_in, mp_obj_t fifo_in, mp_obj_t if (self->can_id == PYB_CAN_1) { irq = (fifo == 0) ? CAN1_RX0_IRQn : CAN1_RX1_IRQn; #if defined(CAN2) - } else { + } else if (self->can_id == PYB_CAN_2) { irq = (fifo == 0) ? CAN2_RX0_IRQn : CAN2_RX1_IRQn; #endif + #if defined(CAN3) + } else { + irq = (fifo == 0) ? CAN3_RX0_IRQn : CAN3_RX1_IRQn; + #endif } NVIC_SetPriority(irq, IRQ_PRI_CAN); HAL_NVIC_EnableIRQ(irq); diff --git a/ports/stm32/can.h b/ports/stm32/can.h index 54e7deaa5e..ade77acf7e 100644 --- a/ports/stm32/can.h +++ b/ports/stm32/can.h @@ -28,6 +28,7 @@ #define PYB_CAN_1 (1) #define PYB_CAN_2 (2) +#define PYB_CAN_3 (3) extern const mp_obj_type_t pyb_can_type; diff --git a/ports/stm32/flashbdev.c b/ports/stm32/flashbdev.c index 0b95dcc4ff..484fa1a1bc 100644 --- a/ports/stm32/flashbdev.c +++ b/ports/stm32/flashbdev.c @@ -61,6 +61,15 @@ STATIC byte flash_cache_mem[0x4000] __attribute__((aligned(4))); // 16k #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(STM32F413xx) + +#define CACHE_MEM_START_ADDR (0x10000000) // SRAM2 data RAM, 64k +#define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of SRAM2 +#define FLASH_MEM_SEG1_START_ADDR (0x08004000) // sector 1 +#define FLASH_MEM_SEG1_NUM_BLOCKS (352) // sectors 1,2,3,4,5: 16k+16k+16k+64k+64k(of 128k)=176k +#define FLASH_MEM_SEG2_START_ADDR (0x08040000) // sector 6 +#define FLASH_MEM_SEG2_NUM_BLOCKS (128) // sector 6: 64k(of 128k). Filesystem 176K + 64K = 240K + #elif defined(STM32F429xx) #define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k diff --git a/ports/stm32/machine_uart.c b/ports/stm32/machine_uart.c index c1e5948071..169e8c589d 100644 --- a/ports/stm32/machine_uart.c +++ b/ports/stm32/machine_uart.c @@ -385,6 +385,14 @@ STATIC mp_obj_t pyb_uart_make_new(const mp_obj_type_t *type, size_t n_args, size } else if (strcmp(port, MICROPY_HW_UART8_NAME) == 0) { uart_id = PYB_UART_8; #endif + #ifdef MICROPY_HW_UART9_NAME + } else if (strcmp(port, MICROPY_HW_UART9_NAME) == 0) { + uart_id = PYB_UART_9; + #endif + #ifdef MICROPY_HW_UART10_NAME + } else if (strcmp(port, MICROPY_HW_UART10_NAME) == 0) { + uart_id = PYB_UART_10; + #endif } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%s) doesn't exist", port)); } diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index 08c835a1c2..4348f50bdd 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -147,8 +147,14 @@ #define MP_HAL_UNIQUE_ID_ADDRESS (0x1fff7a10) #define PYB_EXTI_NUM_VECTORS (23) #define MICROPY_HW_MAX_TIMER (14) -#ifdef UART8 +#if defined(UART10) +#define MICROPY_HW_MAX_UART (10) +#elif defined(UART9) +#define MICROPY_HW_MAX_UART (9) +#elif defined(UART8) #define MICROPY_HW_MAX_UART (8) +#elif defined(UART7) +#define MICROPY_HW_MAX_UART (7) #else #define MICROPY_HW_MAX_UART (6) #endif @@ -239,11 +245,20 @@ #endif // Enable CAN if there are any peripherals defined -#if defined(MICROPY_HW_CAN1_TX) || defined(MICROPY_HW_CAN2_TX) +#if defined(MICROPY_HW_CAN1_TX) || defined(MICROPY_HW_CAN2_TX) || defined(MICROPY_HW_CAN3_TX) #define MICROPY_HW_ENABLE_CAN (1) #else #define MICROPY_HW_ENABLE_CAN (0) +#define MICROPY_HW_MAX_CAN (0) #endif +#if defined(MICROPY_HW_CAN3_TX) +#define MICROPY_HW_MAX_CAN (3) +#elif defined(MICROPY_HW_CAN2_TX) +#define MICROPY_HW_MAX_CAN (2) +#elif defined(MICROPY_HW_CAN1_TX) +#define MICROPY_HW_MAX_CAN (1) +#endif + // 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 7cb67a115a..5a1687c07b 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -291,7 +291,7 @@ extern const struct _mp_obj_module_t mp_module_onewire; struct _pyb_uart_obj_t *pyb_uart_obj_all[MICROPY_HW_MAX_UART]; \ \ /* pointers to all CAN objects (if they have been created) */ \ - struct _pyb_can_obj_t *pyb_can_obj_all[2]; \ + struct _pyb_can_obj_t *pyb_can_obj_all[MICROPY_HW_MAX_CAN]; \ \ /* list of registered NICs */ \ mp_obj_list_t mod_network_nic_list; \ diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index 637442a916..078b143bbd 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -751,6 +751,22 @@ void UART8_IRQHandler(void) { } #endif +#if defined(UART9) +void UART9_IRQHandler(void) { + IRQ_ENTER(UART9_IRQn); + uart_irq_handler(9); + IRQ_EXIT(UART9_IRQn); +} +#endif + +#if defined(UART10) +void UART10_IRQHandler(void) { + IRQ_ENTER(UART10_IRQn); + uart_irq_handler(10); + IRQ_EXIT(UART10_IRQn); +} +#endif + #endif #if defined(MICROPY_HW_CAN1_TX) @@ -793,6 +809,26 @@ void CAN2_SCE_IRQHandler(void) { } #endif +#if defined(MICROPY_HW_CAN3_TX) +void CAN3_RX0_IRQHandler(void) { + IRQ_ENTER(CAN3_RX0_IRQn); + can_rx_irq_handler(PYB_CAN_3, CAN_FIFO0); + IRQ_EXIT(CAN3_RX0_IRQn); +} + +void CAN3_RX1_IRQHandler(void) { + IRQ_ENTER(CAN3_RX1_IRQn); + can_rx_irq_handler(PYB_CAN_3, CAN_FIFO1); + IRQ_EXIT(CAN3_RX1_IRQn); +} + +void CAN3_SCE_IRQHandler(void) { + IRQ_ENTER(CAN3_SCE_IRQn); + can_sce_irq_handler(PYB_CAN_3); + IRQ_EXIT(CAN3_SCE_IRQn); +} +#endif + #if MICROPY_PY_PYB_LEGACY #if defined(MICROPY_HW_I2C1_SCL) diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c index 4156551038..317dbe95b6 100644 --- a/ports/stm32/uart.c +++ b/ports/stm32/uart.c @@ -154,6 +154,14 @@ bool uart_exists(int uart_id) { case PYB_UART_8: return true; #endif + #if defined(MICROPY_HW_UART9_TX) && defined(MICROPY_HW_UART9_RX) + case PYB_UART_9: return true; + #endif + + #if defined(MICROPY_HW_UART10_TX) && defined(MICROPY_HW_UART10_RX) + case PYB_UART_10: return true; + #endif + default: return false; } } @@ -318,6 +326,28 @@ bool uart_init(pyb_uart_obj_t *uart_obj, break; #endif + #if defined(MICROPY_HW_UART9_TX) && defined(MICROPY_HW_UART9_RX) + case PYB_UART_9: + uart_unit = 9; + UARTx = UART9; + irqn = UART9_IRQn; + __HAL_RCC_UART9_CLK_ENABLE(); + pins[0] = MICROPY_HW_UART9_TX; + pins[1] = MICROPY_HW_UART9_RX; + break; + #endif + + #if defined(MICROPY_HW_UART10_TX) && defined(MICROPY_HW_UART10_RX) + case PYB_UART_10: + uart_unit = 10; + UARTx = UART10; + irqn = UART10_IRQn; + __HAL_RCC_UART10_CLK_ENABLE(); + pins[0] = MICROPY_HW_UART10_TX; + pins[1] = MICROPY_HW_UART10_RX; + break; + #endif + default: // UART does not exist or is not configured for this board return false; @@ -475,6 +505,20 @@ void uart_deinit(pyb_uart_obj_t *self) { __HAL_RCC_USART8_RELEASE_RESET(); __HAL_RCC_USART8_CLK_DISABLE(); #endif + #if defined(UART9) + } else if (self->uart_id == 9) { + HAL_NVIC_DisableIRQ(UART9_IRQn); + __HAL_RCC_UART9_FORCE_RESET(); + __HAL_RCC_UART9_RELEASE_RESET(); + __HAL_RCC_UART9_CLK_DISABLE(); + #endif + #if defined(UART10) + } else if (self->uart_id == 10) { + HAL_NVIC_DisableIRQ(UART10_IRQn); + __HAL_RCC_UART10_FORCE_RESET(); + __HAL_RCC_UART10_RELEASE_RESET(); + __HAL_RCC_UART10_CLK_DISABLE(); + #endif } } @@ -538,6 +582,12 @@ uint32_t uart_get_baudrate(pyb_uart_obj_t *self) { #if defined(USART6) || self->uart_id == 6 #endif + #if defined(UART9) + || self->uart_id == 9 + #endif + #if defined(UART10) + || self->uart_id == 10 + #endif ) { uart_clk = HAL_RCC_GetPCLK2Freq(); } else { diff --git a/ports/stm32/uart.h b/ports/stm32/uart.h index 827b3c12d7..9b0d139588 100644 --- a/ports/stm32/uart.h +++ b/ports/stm32/uart.h @@ -38,6 +38,8 @@ typedef enum { PYB_UART_6 = 6, PYB_UART_7 = 7, PYB_UART_8 = 8, + PYB_UART_9 = 9, + PYB_UART_10 = 10, } pyb_uart_t; #define CHAR_WIDTH_8BIT (0) From 2a791170cea7841b9a7600d371b8c0355a3cc20a Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Fri, 19 Apr 2019 15:19:49 +1000 Subject: [PATCH 0319/1788] stm32/boards: Add NUCLEO_F413ZH board configuration. The alternate function pin allocations are different to other NUCLEO-144 boards. This is because the STM32F413 has a very high peripheral count: 10x UART, 5x SPI, 3x I2C, 3x CAN. The pinout was chosen to expose all these devices on separate pins except CAN3 which shares a pin with UART1 and SPI1 which shares pins with DAC. --- .../boards/NUCLEO_F413ZH/mpconfigboard.h | 101 +++++ .../boards/NUCLEO_F413ZH/mpconfigboard.mk | 7 + ports/stm32/boards/NUCLEO_F413ZH/pins.csv | 118 +++++ .../boards/NUCLEO_F413ZH/stm32f4xx_hal_conf.h | 409 ++++++++++++++++++ 4 files changed, 635 insertions(+) create mode 100644 ports/stm32/boards/NUCLEO_F413ZH/mpconfigboard.h create mode 100644 ports/stm32/boards/NUCLEO_F413ZH/mpconfigboard.mk create mode 100644 ports/stm32/boards/NUCLEO_F413ZH/pins.csv create mode 100644 ports/stm32/boards/NUCLEO_F413ZH/stm32f4xx_hal_conf.h diff --git a/ports/stm32/boards/NUCLEO_F413ZH/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F413ZH/mpconfigboard.h new file mode 100644 index 0000000000..2f488159a4 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F413ZH/mpconfigboard.h @@ -0,0 +1,101 @@ +#define MICROPY_HW_BOARD_NAME "NUCLEO-F413ZH" +#define MICROPY_HW_MCU_NAME "STM32F413" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_USB (1) + +// HSE is 8MHz, CPU freq set to 96MHz +#define MICROPY_HW_CLK_PLLM (8) +#define MICROPY_HW_CLK_PLLN (192) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (4) + +// For 2.7 to 3.6 V, 75 to 100 MHz: 3 wait states. +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_3 + +// UART config +#define MICROPY_HW_UART1_TX (pin_B6) +#define MICROPY_HW_UART1_RX (pin_B3) // shared with CAN3 +#define MICROPY_HW_UART2_TX (pin_D5) +#define MICROPY_HW_UART2_RX (pin_D6) +#define MICROPY_HW_UART3_TX (pin_D8) +#define MICROPY_HW_UART3_RX (pin_D9) +#define MICROPY_HW_UART4_TX (pin_D1) +#define MICROPY_HW_UART4_RX (pin_D0) +#define MICROPY_HW_UART5_TX (pin_C12) +#define MICROPY_HW_UART5_RX (pin_D2) +#define MICROPY_HW_UART6_TX (pin_G14) +#define MICROPY_HW_UART6_RX (pin_G9) +#define MICROPY_HW_UART7_TX (pin_E8) +#define MICROPY_HW_UART7_RX (pin_E7) +#define MICROPY_HW_UART8_TX (pin_E1) +#define MICROPY_HW_UART8_RX (pin_E0) +#define MICROPY_HW_UART9_TX (pin_D15) +#define MICROPY_HW_UART9_RX (pin_D14) +#define MICROPY_HW_UART10_TX (pin_E3) +#define MICROPY_HW_UART10_RX (pin_E2) +#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_I2C2_SCL (pin_F1) +#define MICROPY_HW_I2C2_SDA (pin_F0) +#define MICROPY_HW_I2C3_SCL (pin_A8) +#define MICROPY_HW_I2C3_SDA (pin_C9) + +// SPI busses +#define MICROPY_HW_SPI1_NSS (pin_A4) // shared with DAC +#define MICROPY_HW_SPI1_SCK (pin_A5) // shared with DAC +#define MICROPY_HW_SPI1_MISO (pin_A6) +#define MICROPY_HW_SPI1_MOSI (pin_A7) +#define MICROPY_HW_SPI2_NSS (pin_B12) +#define MICROPY_HW_SPI2_SCK (pin_C7) +#define MICROPY_HW_SPI2_MISO (pin_C2) +#define MICROPY_HW_SPI2_MOSI (pin_C3) +#define MICROPY_HW_SPI3_NSS (pin_A15) +#define MICROPY_HW_SPI3_SCK (pin_C10) +#define MICROPY_HW_SPI3_MISO (pin_C11) +#define MICROPY_HW_SPI3_MOSI (pin_B5) +#define MICROPY_HW_SPI4_NSS (pin_E4) +#define MICROPY_HW_SPI4_SCK (pin_B13) +#define MICROPY_HW_SPI4_MISO (pin_E5) +#define MICROPY_HW_SPI4_MOSI (pin_E6) +#define MICROPY_HW_SPI5_NSS (pin_E11) +#define MICROPY_HW_SPI5_SCK (pin_E12) +#define MICROPY_HW_SPI5_MISO (pin_E13) +#define MICROPY_HW_SPI5_MOSI (pin_E14) + +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_G1) +#define MICROPY_HW_CAN1_RX (pin_G0) +#define MICROPY_HW_CAN2_TX (pin_G12) +#define MICROPY_HW_CAN2_RX (pin_G11) +#define MICROPY_HW_CAN3_TX (pin_B4) +#define MICROPY_HW_CAN3_RX (pin_B3) // shared with UART1 or use pin_A8 shared with I2C3 + +// 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_B14) // red +#define MICROPY_HW_LED2 (pin_B0) // green +#define MICROPY_HW_LED3 (pin_B7) // blue +#define MICROPY_HW_LED1_PWM { TIM12, 12, TIM_CHANNEL_1, GPIO_AF9_TIM12 } +#define MICROPY_HW_LED2_PWM { TIM3, 3, TIM_CHANNEL_3, GPIO_AF2_TIM3 } +#define MICROPY_HW_LED3_PWM { TIM4, 4, TIM_CHANNEL_2, GPIO_AF2_TIM4 } +#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_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_F413ZH/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F413ZH/mpconfigboard.mk new file mode 100644 index 0000000000..efc05dba84 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F413ZH/mpconfigboard.mk @@ -0,0 +1,7 @@ +MCU_SERIES = f4 +CMSIS_MCU = STM32F413xx +STARTUP_FILE = boards/startup_stm32f413xx.o +AF_FILE = boards/stm32f413_af.csv +LD_FILES = boards/stm32f413xh.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08060000 diff --git a/ports/stm32/boards/NUCLEO_F413ZH/pins.csv b/ports/stm32/boards/NUCLEO_F413ZH/pins.csv new file mode 100644 index 0000000000..31dcb99ed6 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F413ZH/pins.csv @@ -0,0 +1,118 @@ +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 +SW,C13 +LED_RED,B14 +LED_GREEN,B0 +LED_BLUE,B7 diff --git a/ports/stm32/boards/NUCLEO_F413ZH/stm32f4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F413ZH/stm32f4xx_hal_conf.h new file mode 100644 index 0000000000..5b5a8a3e43 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F413ZH/stm32f4xx_hal_conf.h @@ -0,0 +1,409 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_conf.h + * @author MCD Application Team + * @version V1.1.0 + * @date 19-June-2014 + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_HAL_CONF_H +#define __STM32F4xx_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_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_PCCARD_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_LTDC_MODULE_ENABLED */ +#define HAL_PWR_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_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 */ + + +/* ########################## 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)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 ((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)40000) +#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 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 */ + +/* ################## 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 0 +#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ + +/* DP83848 PHY Address*/ +#define DP83848_PHY_ADDRESS 0x01 +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY ((uint32_t)0x000000FF) +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) + +#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 "stm32f4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32f4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32f4xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32f4xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32f4xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32f4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32f4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_PCCARD_MODULE_ENABLED + #include "stm32f4xx_hal_pccard.h" +#endif /* HAL_PCCARD_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32f4xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f4xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32f4xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32f4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32f4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32f4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ From 9a6f6fd68d2563e0115b11c01c322aaa14a107bb Mon Sep 17 00:00:00 2001 From: Nguyen Hoan Hoang Date: Wed, 20 Mar 2019 17:38:03 +0700 Subject: [PATCH 0320/1788] nrf/boards: Add support for BLYST Nano module based boards. - IBK-BLYST-NANO: Breakout board - IDK-BLYST-NANO: DevKit board with builtin IDAP-M CMSIS-DAP Debug JTAG, RGB led - BLUEIO-TAG-EVIM: Sensor tag board (environmental sensor (T, H, P, Air quality) + 9 axis motion sensor) Also, the LED module has been updated to support individual base level configuration of each LED. If set, this will be used instead of the common configuration, MICROPY_HW_LED_PULLUP. The new configuration, MICROPY_HW_LEDX_LEVEL, where X is the LED number can be used to set the base level of the specific LED. --- ports/nrf/Makefile | 8 ++ ports/nrf/README.md | 14 ++ .../boards/blueio_tag_evim/mpconfigboard.h | 77 +++++++++++ .../boards/blueio_tag_evim/mpconfigboard.mk | 8 ++ ports/nrf/boards/blueio_tag_evim/pins.csv | 30 +++++ .../nrf/boards/ibk_blyst_nano/mpconfigboard.h | 69 ++++++++++ .../boards/ibk_blyst_nano/mpconfigboard.mk | 8 ++ ports/nrf/boards/ibk_blyst_nano/pins.csv | 30 +++++ .../nrf/boards/idk_blyst_nano/mpconfigboard.h | 70 ++++++++++ .../boards/idk_blyst_nano/mpconfigboard.mk | 8 ++ ports/nrf/boards/idk_blyst_nano/pins.csv | 30 +++++ ports/nrf/modules/board/led.c | 126 +++++++++++++++--- ports/nrf/modules/board/led.h | 4 + 13 files changed, 465 insertions(+), 17 deletions(-) create mode 100644 ports/nrf/boards/blueio_tag_evim/mpconfigboard.h create mode 100644 ports/nrf/boards/blueio_tag_evim/mpconfigboard.mk create mode 100644 ports/nrf/boards/blueio_tag_evim/pins.csv create mode 100644 ports/nrf/boards/ibk_blyst_nano/mpconfigboard.h create mode 100644 ports/nrf/boards/ibk_blyst_nano/mpconfigboard.mk create mode 100644 ports/nrf/boards/ibk_blyst_nano/pins.csv create mode 100644 ports/nrf/boards/idk_blyst_nano/mpconfigboard.h create mode 100644 ports/nrf/boards/idk_blyst_nano/mpconfigboard.mk create mode 100644 ports/nrf/boards/idk_blyst_nano/pins.csv diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index 80110f9704..cc7b4f1260 100644 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -296,6 +296,14 @@ sd: $(BUILD)/$(OUTPUT_FILENAME).hex pyocd-flashtool -t $(MCU_VARIANT) $(SOFTDEV_HEX) pyocd-flashtool -t $(MCU_VARIANT) $< +else ifeq ($(FLASHER), idap) + +flash: $(BUILD)/$(OUTPUT_FILENAME).hex + IDAPnRFPRog $< + +sd: $(BUILD)/$(OUTPUT_FILENAME).hex + IDAPnRFPRog $(SOFTDEV_HEX) $< + endif $(BUILD)/$(OUTPUT_FILENAME).elf: $(OBJ) diff --git a/ports/nrf/README.md b/ports/nrf/README.md index 659a556ae2..2a1667a3eb 100644 --- a/ports/nrf/README.md +++ b/ports/nrf/README.md @@ -34,6 +34,8 @@ This is a port of MicroPython to the Nordic Semiconductor nRF series of chips. * [Adafruit Feather nRF52](https://www.adafruit.com/product/3406) * [Thingy:52](http://www.nordicsemi.com/eng/Products/Nordic-Thingy-52) * [Arduino Primo](http://www.arduino.org/products/boards/arduino-primo) + * [IBK-BLYST-NANO breakout board](https://www.crowdsupply.com/i-syst/blyst-nano) + * [BLUEIO-TAG-EVIM BLYST Nano Sensor board](https://www.crowdsupply.com/i-syst/blyst-nano) * nRF52840 * [PCA10056](http://www.nordicsemi.com/eng/Products/nRF52840-Preview-DK) @@ -120,8 +122,20 @@ wt51822_s4at | s110 | Peripheral | Manual pca10040 | s132 | Peripheral and Central | [Segger](#segger-targets) feather52 | s132 | Peripheral and Central | Manual, SWDIO and SWCLK solder points on the bottom side of the board arduino_primo | s132 | Peripheral and Central | [PyOCD](#pyocdopenocd-targets) +ibk_blyst_nano | s132 | Peripheral and Central | [IDAP](#idap-midap-link-targets) +idk_blyst_nano | s132 | Peripheral and Central | [IDAP](#idap-midap-link-targets) +blueio_tag_evim | s132 | Peripheral and Central | [IDAP](#idap-midap-link-targets) pca10056 | s140 | Peripheral and Central | [Segger](#segger-targets) +## IDAP-M/IDAP-Link Targets + +Install the necessary tools to flash and debug using IDAP-M/IDAP-Link CMSIS-DAP Debug JTAG: + +[IDAPnRFProg for Linux](https://sourceforge.net/projects/idaplinkfirmware/files/Linux/IDAPnRFProg_1_7_190320.zip/download) +[IDAPnRFProg for OSX](https://sourceforge.net/projects/idaplinkfirmware/files/OSX/IDAPnRFProg_1_7_190320.zip/download) +[IDAPnRFProg for Windows](https://sourceforge.net/projects/idaplinkfirmware/files/Windows/IDAPnRFProg_1_7_190320.zip/download) + + ## Segger Targets Install the necessary tools to flash and debug using Segger: diff --git a/ports/nrf/boards/blueio_tag_evim/mpconfigboard.h b/ports/nrf/boards/blueio_tag_evim/mpconfigboard.h new file mode 100644 index 0000000000..afc3f00a81 --- /dev/null +++ b/ports/nrf/boards/blueio_tag_evim/mpconfigboard.h @@ -0,0 +1,77 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 I-SYST inc. + * + * 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. + */ + +#define MICROPY_HW_BOARD_NAME "BLUEIO-TAG-EVIM" +#define MICROPY_HW_MCU_NAME "NRF52832" +#define MICROPY_PY_SYS_PLATFORM "BLYST Nano" + +#define MICROPY_PY_MACHINE_SOFT_PWM (1) +#define MICROPY_PY_MUSIC (1) + +#define MICROPY_PY_MACHINE_UART (1) +#define MICROPY_PY_MACHINE_HW_PWM (1) +#define MICROPY_PY_MACHINE_HW_SPI (1) +#define MICROPY_PY_MACHINE_TIMER (1) +#define MICROPY_PY_MACHINE_RTCOUNTER (1) +#define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_ADC (1) +#define MICROPY_PY_MACHINE_TEMP (1) +#define MICROPY_PY_RANDOM_HW_RNG (1) + +#define MICROPY_HW_HAS_LED (1) +#define MICROPY_HW_LED_COUNT (4) +#define MICROPY_HW_LED_PULLUP (1) + +#define MICROPY_HW_LED1 (30) // LED1 +#define MICROPY_HW_LED1_LEVEL (0) +#define MICROPY_HW_LED2 (20) // LED2 +#define MICROPY_HW_LED2_LEVEL (1) +#define MICROPY_HW_LED3 (19) // LED3 +#define MICROPY_HW_LED3_LEVEL (1) +#define MICROPY_HW_LED4 (18) // LED4 +#define MICROPY_HW_LED4_LEVEL (1) + +// UART config +#define MICROPY_HW_UART1_RX (8) +#define MICROPY_HW_UART1_TX (7) +#define MICROPY_HW_UART1_CTS (12) +#define MICROPY_HW_UART1_RTS (11) +#define MICROPY_HW_UART1_HWFC (1) + +// SPI0 config +#define MICROPY_HW_SPI0_NAME "SPI0" +#define MICROPY_HW_SPI0_SCK (23) // +#define MICROPY_HW_SPI0_MOSI (24) // +#define MICROPY_HW_SPI0_MISO (25) // + +#define MICROPY_HW_PWM0_NAME "PWM0" +#define MICROPY_HW_PWM1_NAME "PWM1" +#define MICROPY_HW_PWM2_NAME "PWM2" + +// buzzer pin +#define MICROPY_HW_MUSIC_PIN (14) + +#define HELP_TEXT_BOARD_LED "1,2,3,4" diff --git a/ports/nrf/boards/blueio_tag_evim/mpconfigboard.mk b/ports/nrf/boards/blueio_tag_evim/mpconfigboard.mk new file mode 100644 index 0000000000..02a3177446 --- /dev/null +++ b/ports/nrf/boards/blueio_tag_evim/mpconfigboard.mk @@ -0,0 +1,8 @@ +MCU_SERIES = m4 +MCU_VARIANT = nrf52 +MCU_SUB_VARIANT = nrf52832 +SOFTDEV_VERSION = 6.1.1 +LD_FILES += boards/nrf52832_512k_64k.ld +FLASHER = idap + +NRF_DEFINES += -DNRF52832_XXAA diff --git a/ports/nrf/boards/blueio_tag_evim/pins.csv b/ports/nrf/boards/blueio_tag_evim/pins.csv new file mode 100644 index 0000000000..90bf84a04d --- /dev/null +++ b/ports/nrf/boards/blueio_tag_evim/pins.csv @@ -0,0 +1,30 @@ +P2,P2 +P3,P3 +P4,P4 +P5,P5 +P6,P6 +P7,P7 +P8,P8 +P9,P9 +P10,P10 +P11,P11 +P12,P12 +P13,P13 +P14,P14 +P15,P15 +P16,P16 +P17,P17 +P18,P18 +P19,P19 +P20,P20 +P21,P21 +P22,P22 +P23,P23 +P24,P24 +P25,P25 +P26,P26 +P27,P27 +P28,P28 +P29,P29 +P30,P30 +P31,P31 diff --git a/ports/nrf/boards/ibk_blyst_nano/mpconfigboard.h b/ports/nrf/boards/ibk_blyst_nano/mpconfigboard.h new file mode 100644 index 0000000000..11b8c28e38 --- /dev/null +++ b/ports/nrf/boards/ibk_blyst_nano/mpconfigboard.h @@ -0,0 +1,69 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 I-SYST inc. + * + * 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. + */ + +#define MICROPY_HW_BOARD_NAME "IBK-BLYST-NANO" +#define MICROPY_HW_MCU_NAME "NRF52832" +#define MICROPY_PY_SYS_PLATFORM "BLYST Nano" + +#define MICROPY_PY_MACHINE_SOFT_PWM (1) +#define MICROPY_PY_MUSIC (1) + +#define MICROPY_PY_MACHINE_UART (1) +#define MICROPY_PY_MACHINE_HW_PWM (1) +#define MICROPY_PY_MACHINE_HW_SPI (1) +#define MICROPY_PY_MACHINE_TIMER (1) +#define MICROPY_PY_MACHINE_RTCOUNTER (1) +#define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_ADC (1) +#define MICROPY_PY_MACHINE_TEMP (1) +#define MICROPY_PY_RANDOM_HW_RNG (1) + +#define MICROPY_HW_HAS_LED (1) +#define MICROPY_HW_LED_COUNT (3) +#define MICROPY_HW_LED_PULLUP (1) + +#define MICROPY_HW_LED1 (30) // LED1 +#define MICROPY_HW_LED2 (29) // LED2 +#define MICROPY_HW_LED3 (28) // LED3 + +// UART config +#define MICROPY_HW_UART1_RX (8) +#define MICROPY_HW_UART1_TX (7) +#define MICROPY_HW_UART1_CTS (12) +#define MICROPY_HW_UART1_RTS (11) +#define MICROPY_HW_UART1_HWFC (1) + +// SPI0 config +#define MICROPY_HW_SPI0_NAME "SPI0" +#define MICROPY_HW_SPI0_SCK (23) // +#define MICROPY_HW_SPI0_MOSI (24) // +#define MICROPY_HW_SPI0_MISO (25) // + +#define MICROPY_HW_PWM0_NAME "PWM0" +#define MICROPY_HW_PWM1_NAME "PWM1" +#define MICROPY_HW_PWM2_NAME "PWM2" + +#define HELP_TEXT_BOARD_LED "1,2,3" diff --git a/ports/nrf/boards/ibk_blyst_nano/mpconfigboard.mk b/ports/nrf/boards/ibk_blyst_nano/mpconfigboard.mk new file mode 100644 index 0000000000..02a3177446 --- /dev/null +++ b/ports/nrf/boards/ibk_blyst_nano/mpconfigboard.mk @@ -0,0 +1,8 @@ +MCU_SERIES = m4 +MCU_VARIANT = nrf52 +MCU_SUB_VARIANT = nrf52832 +SOFTDEV_VERSION = 6.1.1 +LD_FILES += boards/nrf52832_512k_64k.ld +FLASHER = idap + +NRF_DEFINES += -DNRF52832_XXAA diff --git a/ports/nrf/boards/ibk_blyst_nano/pins.csv b/ports/nrf/boards/ibk_blyst_nano/pins.csv new file mode 100644 index 0000000000..90bf84a04d --- /dev/null +++ b/ports/nrf/boards/ibk_blyst_nano/pins.csv @@ -0,0 +1,30 @@ +P2,P2 +P3,P3 +P4,P4 +P5,P5 +P6,P6 +P7,P7 +P8,P8 +P9,P9 +P10,P10 +P11,P11 +P12,P12 +P13,P13 +P14,P14 +P15,P15 +P16,P16 +P17,P17 +P18,P18 +P19,P19 +P20,P20 +P21,P21 +P22,P22 +P23,P23 +P24,P24 +P25,P25 +P26,P26 +P27,P27 +P28,P28 +P29,P29 +P30,P30 +P31,P31 diff --git a/ports/nrf/boards/idk_blyst_nano/mpconfigboard.h b/ports/nrf/boards/idk_blyst_nano/mpconfigboard.h new file mode 100644 index 0000000000..1d39ad7569 --- /dev/null +++ b/ports/nrf/boards/idk_blyst_nano/mpconfigboard.h @@ -0,0 +1,70 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 I-SYST inc. + * + * 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. + */ + +#define MICROPY_HW_BOARD_NAME "IDK-BLYST-NANO" +#define MICROPY_HW_MCU_NAME "NRF52832" +#define MICROPY_PY_SYS_PLATFORM "BLYST Nano" + +#define MICROPY_PY_MACHINE_SOFT_PWM (1) +#define MICROPY_PY_MUSIC (1) + +#define MICROPY_PY_MACHINE_UART (1) +#define MICROPY_PY_MACHINE_HW_PWM (1) +#define MICROPY_PY_MACHINE_HW_SPI (1) +#define MICROPY_PY_MACHINE_TIMER (1) +#define MICROPY_PY_MACHINE_RTCOUNTER (1) +#define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_ADC (1) +#define MICROPY_PY_MACHINE_TEMP (1) +#define MICROPY_PY_RANDOM_HW_RNG (1) + +#define MICROPY_HW_HAS_LED (1) +#define MICROPY_HW_LED_COUNT (4) +#define MICROPY_HW_LED_PULLUP (1) + +#define MICROPY_HW_LED1 (30) // LED1 +#define MICROPY_HW_LED2 (29) // LED2 +#define MICROPY_HW_LED3 (28) // LED3 +#define MICROPY_HW_LED4 (27) // LED4 + +// UART config +#define MICROPY_HW_UART1_RX (8) +#define MICROPY_HW_UART1_TX (7) +#define MICROPY_HW_UART1_CTS (12) +#define MICROPY_HW_UART1_RTS (11) +#define MICROPY_HW_UART1_HWFC (1) + +// SPI0 config +#define MICROPY_HW_SPI0_NAME "SPI0" +#define MICROPY_HW_SPI0_SCK (23) // +#define MICROPY_HW_SPI0_MOSI (24) // +#define MICROPY_HW_SPI0_MISO (25) // + +#define MICROPY_HW_PWM0_NAME "PWM0" +#define MICROPY_HW_PWM1_NAME "PWM1" +#define MICROPY_HW_PWM2_NAME "PWM2" + +#define HELP_TEXT_BOARD_LED "1,2,3,4" diff --git a/ports/nrf/boards/idk_blyst_nano/mpconfigboard.mk b/ports/nrf/boards/idk_blyst_nano/mpconfigboard.mk new file mode 100644 index 0000000000..02a3177446 --- /dev/null +++ b/ports/nrf/boards/idk_blyst_nano/mpconfigboard.mk @@ -0,0 +1,8 @@ +MCU_SERIES = m4 +MCU_VARIANT = nrf52 +MCU_SUB_VARIANT = nrf52832 +SOFTDEV_VERSION = 6.1.1 +LD_FILES += boards/nrf52832_512k_64k.ld +FLASHER = idap + +NRF_DEFINES += -DNRF52832_XXAA diff --git a/ports/nrf/boards/idk_blyst_nano/pins.csv b/ports/nrf/boards/idk_blyst_nano/pins.csv new file mode 100644 index 0000000000..90bf84a04d --- /dev/null +++ b/ports/nrf/boards/idk_blyst_nano/pins.csv @@ -0,0 +1,30 @@ +P2,P2 +P3,P3 +P4,P4 +P5,P5 +P6,P6 +P7,P7 +P8,P8 +P9,P9 +P10,P10 +P11,P11 +P12,P12 +P13,P13 +P14,P14 +P15,P15 +P16,P16 +P17,P17 +P18,P18 +P19,P19 +P20,P20 +P21,P21 +P22,P22 +P23,P23 +P24,P24 +P25,P25 +P26,P26 +P27,P27 +P28,P28 +P29,P29 +P30,P30 +P31,P31 diff --git a/ports/nrf/modules/board/led.c b/ports/nrf/modules/board/led.c index 687348cb86..8b1eb560ea 100644 --- a/ports/nrf/modules/board/led.c +++ b/ports/nrf/modules/board/led.c @@ -33,31 +33,122 @@ #if MICROPY_HW_HAS_LED -#define LED_OFF(pin) {(MICROPY_HW_LED_PULLUP) ? nrf_gpio_pin_set(pin) : nrf_gpio_pin_clear(pin); } -#define LED_ON(pin) {(MICROPY_HW_LED_PULLUP) ? nrf_gpio_pin_clear(pin) : nrf_gpio_pin_set(pin); } - typedef struct _board_led_obj_t { mp_obj_base_t base; mp_uint_t led_id; mp_uint_t hw_pin; uint8_t hw_pin_port; + bool act_level; } board_led_obj_t; -STATIC const board_led_obj_t board_led_obj[] = { +static inline void LED_OFF(board_led_obj_t * const led_obj) { + if (led_obj->act_level) { + nrf_gpio_pin_clear(led_obj->hw_pin); + } + else { + nrf_gpio_pin_set(led_obj->hw_pin); + } +} + +static inline void LED_ON(board_led_obj_t * const led_obj) { + if (led_obj->act_level) { + nrf_gpio_pin_set(led_obj->hw_pin); + } + else { + nrf_gpio_pin_clear(led_obj->hw_pin); + } +} + + +static const board_led_obj_t board_led_obj[] = { + #if MICROPY_HW_LED_TRICOLOR - {{&board_led_type}, BOARD_LED_RED, MICROPY_HW_LED_RED}, - {{&board_led_type}, BOARD_LED_GREEN, MICROPY_HW_LED_GREEN}, - {{&board_led_type}, BOARD_LED_BLUE, MICROPY_HW_LED_BLUE}, + + {{&board_led_type}, BOARD_LED_RED, MICROPY_HW_LED_RED, 0, MICROPY_HW_LED_PULLUP != 0 ? 0 : 1}, + {{&board_led_type}, BOARD_LED_GREEN, MICROPY_HW_LED_GREEN,0, MICROPY_HW_LED_PULLUP != 0 ? 0 : 1}, + {{&board_led_type}, BOARD_LED_BLUE, MICROPY_HW_LED_BLUE,0, MICROPY_HW_LED_PULLUP != 0 ? 0 : 1}, + #elif (MICROPY_HW_LED_COUNT == 1) - {{&board_led_type}, BOARD_LED1, MICROPY_HW_LED1}, + + {{&board_led_type}, BOARD_LED1, MICROPY_HW_LED1, 0, + #ifdef MICROPY_HW_LED1_LEVEL + MICROPY_HW_LED1_LEVEL, + #else + MICROPY_HW_LED_PULLUP != 0 ? 0 : 1 + #endif + }, + #elif (MICROPY_HW_LED_COUNT == 2) - {{&board_led_type}, BOARD_LED1, MICROPY_HW_LED1}, - {{&board_led_type}, BOARD_LED2, MICROPY_HW_LED2}, + + {{&board_led_type}, BOARD_LED1, MICROPY_HW_LED1, 0, + #ifdef MICROPY_HW_LED1_LEVEL + MICROPY_HW_LED1_LEVEL, + #else + MICROPY_HW_LED_PULLUP != 0 ? 0 : 1 + #endif + }, + {{&board_led_type}, BOARD_LED2, MICROPY_HW_LED2, 0, + #ifdef MICROPY_HW_LED2_LEVEL + MICROPY_HW_LED2_LEVEL, + #else + MICROPY_HW_LED_PULLUP != 0 ? 0 : 1 + #endif + }, + +#elif (MICROPY_HW_LED_COUNT == 3) + + {{&board_led_type}, BOARD_LED1, MICROPY_HW_LED1, 0, + #ifdef MICROPY_HW_LED1_LEVEL + MICROPY_HW_LED1_LEVEL, + #else + MICROPY_HW_LED_PULLUP != 0 ? 0 : 1 + #endif + }, + {{&board_led_type}, BOARD_LED2, MICROPY_HW_LED2, 0, + #ifdef MICROPY_HW_LED2_LEVEL + MICROPY_HW_LED2_LEVEL, + #else + MICROPY_HW_LED_PULLUP != 0 ? 0 : 1 + #endif + }, + {{&board_led_type}, BOARD_LED3, MICROPY_HW_LED3, 0, + #ifdef MICROPY_HW_LED3_LEVEL + MICROPY_HW_LED3_LEVEL, + #else + MICROPY_HW_LED_PULLUP != 0 ? 0 : 1 + #endif + }, + #else - {{&board_led_type}, BOARD_LED1, MICROPY_HW_LED1}, - {{&board_led_type}, BOARD_LED2, MICROPY_HW_LED2}, - {{&board_led_type}, BOARD_LED3, MICROPY_HW_LED3}, - {{&board_led_type}, BOARD_LED4, MICROPY_HW_LED4}, + + {{&board_led_type}, BOARD_LED1, MICROPY_HW_LED1, 0, + #ifdef MICROPY_HW_LED1_LEVEL + MICROPY_HW_LED1_LEVEL, + #else + MICROPY_HW_LED_PULLUP != 0 ? 0 : 1 + #endif + }, + {{&board_led_type}, BOARD_LED2, MICROPY_HW_LED2, 0, + #ifdef MICROPY_HW_LED2_LEVEL + MICROPY_HW_LED2_LEVEL, + #else + MICROPY_HW_LED_PULLUP != 0 ? 0 : 1 + #endif + }, + {{&board_led_type}, BOARD_LED3, MICROPY_HW_LED3, 0, + #ifdef MICROPY_HW_LED3_LEVEL + MICROPY_HW_LED3_LEVEL, + #else + MICROPY_HW_LED_PULLUP != 0 ? 0 : 1 + #endif + }, + {{&board_led_type}, BOARD_LED4, MICROPY_HW_LED4, 0, + #ifdef MICROPY_HW_LED4_LEVEL + MICROPY_HW_LED4_LEVEL, + #else + MICROPY_HW_LED_PULLUP != 0 ? 0 : 1 + #endif + }, #endif }; @@ -65,16 +156,17 @@ STATIC const board_led_obj_t board_led_obj[] = { void led_init(void) { for (uint8_t i = 0; i < NUM_LEDS; i++) { - LED_OFF(board_led_obj[i].hw_pin); + LED_OFF((board_led_obj_t*)&board_led_obj[i]); nrf_gpio_cfg_output(board_led_obj[i].hw_pin); } } void led_state(board_led_obj_t * led_obj, int state) { if (state == 1) { - LED_ON(led_obj->hw_pin); + LED_ON(led_obj); + } else { - LED_OFF(led_obj->hw_pin); + LED_OFF(led_obj); } } diff --git a/ports/nrf/modules/board/led.h b/ports/nrf/modules/board/led.h index 6210039f49..537b9ac546 100644 --- a/ports/nrf/modules/board/led.h +++ b/ports/nrf/modules/board/led.h @@ -38,6 +38,10 @@ typedef enum { #elif (MICROPY_HW_LED_COUNT == 2) BOARD_LED1 = 1, BOARD_LED2 = 2, +#elif (MICROPY_HW_LED_COUNT == 3) + BOARD_LED1 = 1, + BOARD_LED2 = 2, + BOARD_LED3 = 3, #else BOARD_LED1 = 1, BOARD_LED2 = 2, From 5ea38e4d7485aca5ce4e74bff1785c0d8e41fa1c Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 3 May 2019 23:18:30 +1000 Subject: [PATCH 0321/1788] py/native: Improve support for bool type in viper functions. Variables with type bool now act more like an int, and there is proper casting to/from Python objects. --- py/emitnative.c | 2 +- py/nativeglue.c | 2 +- tests/micropython/viper_types.py | 26 ++++++++++++++++++++++++++ tests/micropython/viper_types.py.exp | 8 ++++++++ 4 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 tests/micropython/viper_types.py create mode 100644 tests/micropython/viper_types.py.exp diff --git a/py/emitnative.c b/py/emitnative.c index da986dc5d9..cb6cc94d35 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -1356,7 +1356,7 @@ STATIC void emit_native_load_global(emit_t *emit, qstr qst, int kind) { if (emit->do_viper_types) { // check for builtin casting operators int native_type = mp_native_type_from_qstr(qst); - if (native_type >= MP_NATIVE_TYPE_INT) { + if (native_type >= MP_NATIVE_TYPE_BOOL) { emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, native_type); return; } diff --git a/py/nativeglue.c b/py/nativeglue.c index db54d12332..c810f31e60 100644 --- a/py/nativeglue.c +++ b/py/nativeglue.c @@ -60,7 +60,7 @@ mp_uint_t mp_native_from_obj(mp_obj_t obj, mp_uint_t type) { DEBUG_printf("mp_native_from_obj(%p, " UINT_FMT ")\n", obj, type); switch (type & 0xf) { case MP_NATIVE_TYPE_OBJ: return (mp_uint_t)obj; - case MP_NATIVE_TYPE_BOOL: + case MP_NATIVE_TYPE_BOOL: return mp_obj_is_true(obj); case MP_NATIVE_TYPE_INT: case MP_NATIVE_TYPE_UINT: return mp_obj_get_int_truncated(obj); default: { // cast obj to a pointer diff --git a/tests/micropython/viper_types.py b/tests/micropython/viper_types.py new file mode 100644 index 0000000000..ae72c0cf30 --- /dev/null +++ b/tests/micropython/viper_types.py @@ -0,0 +1,26 @@ +# test various type conversions + +import micropython + +# converting incoming arg to bool +@micropython.viper +def f1(x:bool): + print(x) +f1(0) +f1(1) +f1([]) +f1([1]) + +# taking and returning a bool +@micropython.viper +def f2(x:bool) -> bool: + return x +print(f2([])) +print(f2([1])) + +# converting to bool within function +@micropython.viper +def f3(x) -> bool: + return bool(x) +print(f3([])) +print(f3(-1)) diff --git a/tests/micropython/viper_types.py.exp b/tests/micropython/viper_types.py.exp new file mode 100644 index 0000000000..b7bef156ea --- /dev/null +++ b/tests/micropython/viper_types.py.exp @@ -0,0 +1,8 @@ +False +True +False +True +False +True +False +True From c2bb4519085fff1a30605e3f672635c21a747ed8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 3 May 2019 23:21:08 +1000 Subject: [PATCH 0322/1788] tests/basics/sys1.py: Add test for calling sys.exit() without any args. --- tests/basics/sys1.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/basics/sys1.py b/tests/basics/sys1.py index 0d74a1292b..30e36f81a8 100644 --- a/tests/basics/sys1.py +++ b/tests/basics/sys1.py @@ -24,6 +24,11 @@ try: except SystemExit as e: print("SystemExit", e.args) +try: + sys.exit() +except SystemExit as e: + print("SystemExit", e.args) + try: sys.exit(42) except SystemExit as e: From 906fb89fd778cb695ba81c871086fe1ce340e681 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 3 May 2019 23:21:28 +1000 Subject: [PATCH 0323/1788] unix/coverage: Add test for printing literal % character. --- 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 3c121a1538..538c32d614 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -161,6 +161,7 @@ STATIC mp_obj_t extra_coverage(void) { mp_printf(&mp_plat_print, "%x\n", 0x80000000); // should print unsigned mp_printf(&mp_plat_print, "%X\n", 0x80000000); // should print unsigned mp_printf(&mp_plat_print, "abc\n%"); // string ends in middle of format specifier + mp_printf(&mp_plat_print, "%%\n"); // literal % character } // GC diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index 2e23b24585..6c483f7e54 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -13,6 +13,7 @@ false true 80000000 80000000 abc +% # GC 0 0 From ef9843653b795b650e1fe77e22f87e3523bd0a08 Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Tue, 23 Apr 2019 12:39:05 +0300 Subject: [PATCH 0324/1788] extmod/moducryptolib: Add AES-CTR support. Selectable at compile time via MICROPY_PY_UCRYPTOLIB_CTR. Disabled by default. --- docs/library/ucryptolib.rst | 4 +- extmod/moducryptolib.c | 99 ++++++++++++++++++----- ports/unix/mpconfigport_coverage.h | 1 + py/mpconfig.h | 5 ++ tests/extmod/ucryptolib_aes128_ctr.py | 28 +++++++ tests/extmod/ucryptolib_aes128_ctr.py.exp | 3 + 6 files changed, 119 insertions(+), 21 deletions(-) create mode 100644 tests/extmod/ucryptolib_aes128_ctr.py create mode 100644 tests/extmod/ucryptolib_aes128_ctr.py.exp diff --git a/docs/library/ucryptolib.rst b/docs/library/ucryptolib.rst index c9e0bb71f7..79471c2e90 100644 --- a/docs/library/ucryptolib.rst +++ b/docs/library/ucryptolib.rst @@ -22,9 +22,11 @@ Classes * *mode* is: * ``1`` (or ``ucryptolib.MODE_ECB`` if it exists) for Electronic Code Book (ECB). - * ``2`` (or ``ucryptolib.MODE_CBC`` if it exists) for Cipher Block Chaining (CBC) + * ``2`` (or ``ucryptolib.MODE_CBC`` if it exists) for Cipher Block Chaining (CBC). + * ``6`` (or ``ucryptolib.MODE_CTR`` if it exists) for Counter mode (CTR). * *IV* is an initialization vector for CBC mode. + * For Counter mode, *IV* is the initial value for the counter. .. method:: encrypt(in_buf, [out_buf]) diff --git a/extmod/moducryptolib.c b/extmod/moducryptolib.c index af9eec624e..6c45c2fdef 100644 --- a/extmod/moducryptolib.c +++ b/extmod/moducryptolib.c @@ -41,10 +41,17 @@ // values follow PEP 272 enum { - UCRYPTOLIB_MODE_MIN = 0, - UCRYPTOLIB_MODE_ECB, - UCRYPTOLIB_MODE_CBC, - UCRYPTOLIB_MODE_MAX, + UCRYPTOLIB_MODE_ECB = 1, + UCRYPTOLIB_MODE_CBC = 2, + UCRYPTOLIB_MODE_CTR = 6, +}; + +struct ctr_params { + // counter is the IV of the AES context. + + size_t offset; // in encrypted_counter + // encrypted counter + uint8_t encrypted_counter[16]; }; #if MICROPY_SSL_AXTLS @@ -82,6 +89,19 @@ typedef struct _mp_obj_aes_t { uint8_t key_type: 2; } mp_obj_aes_t; +STATIC inline bool is_ctr_mode(int block_mode) { + #if MICROPY_PY_UCRYPTOLIB_CTR + return block_mode == UCRYPTOLIB_MODE_CTR; + #else + return false; + #endif +} + +STATIC inline struct ctr_params *ctr_params_from_aes(mp_obj_aes_t *o) { + // ctr_params follows aes object struct + return (struct ctr_params*)&o[1]; +} + #if MICROPY_SSL_AXTLS STATIC void aes_initial_set_key_impl(AES_CTX_IMPL *ctx, const uint8_t *key, size_t keysize, const uint8_t iv[16]) { assert(16 == keysize || 32 == keysize); @@ -155,20 +175,38 @@ STATIC void aes_process_ecb_impl(AES_CTX_IMPL *ctx, const uint8_t in[16], uint8_ STATIC void aes_process_cbc_impl(AES_CTX_IMPL *ctx, const uint8_t *in, uint8_t *out, size_t in_len, bool encrypt) { mbedtls_aes_crypt_cbc(&ctx->u.mbedtls_ctx, encrypt ? MBEDTLS_AES_ENCRYPT : MBEDTLS_AES_DECRYPT, in_len, ctx->iv, in, out); } + +#if MICROPY_PY_UCRYPTOLIB_CTR +STATIC void aes_process_ctr_impl(AES_CTX_IMPL *ctx, const uint8_t *in, uint8_t *out, size_t in_len, struct ctr_params *ctr_params) { + mbedtls_aes_crypt_ctr(&ctx->u.mbedtls_ctx, in_len, &ctr_params->offset, ctx->iv, ctr_params->encrypted_counter, in, out); +} +#endif + #endif STATIC mp_obj_t ucryptolib_aes_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); - mp_obj_aes_t *o = m_new_obj(mp_obj_aes_t); + + const mp_int_t block_mode = mp_obj_get_int(args[1]); + + switch (block_mode) { + case UCRYPTOLIB_MODE_ECB: + case UCRYPTOLIB_MODE_CBC: + #if MICROPY_PY_UCRYPTOLIB_CTR + case UCRYPTOLIB_MODE_CTR: + #endif + break; + + default: + mp_raise_ValueError("mode"); + } + + mp_obj_aes_t *o = m_new_obj_var(mp_obj_aes_t, struct ctr_params, !!is_ctr_mode(block_mode)); o->base.type = type; - o->block_mode = mp_obj_get_int(args[1]); + o->block_mode = block_mode; o->key_type = AES_KEYTYPE_NONE; - if (o->block_mode <= UCRYPTOLIB_MODE_MIN || o->block_mode >= UCRYPTOLIB_MODE_MAX) { - mp_raise_ValueError("mode"); - } - mp_buffer_info_t keyinfo; mp_get_buffer_raise(args[0], &keyinfo, MP_BUFFER_READ); if (32 != keyinfo.len && 16 != keyinfo.len) { @@ -183,10 +221,14 @@ STATIC mp_obj_t ucryptolib_aes_make_new(const mp_obj_type_t *type, size_t n_args if (16 != ivinfo.len) { mp_raise_ValueError("IV"); } - } else if (o->block_mode == UCRYPTOLIB_MODE_CBC) { + } else if (o->block_mode == UCRYPTOLIB_MODE_CBC || is_ctr_mode(o->block_mode)) { mp_raise_ValueError("IV"); } + if (is_ctr_mode(block_mode)) { + ctr_params_from_aes(o)->offset = 0; + } + aes_initial_set_key_impl(&o->ctx, keyinfo.buf, keyinfo.len, ivinfo.buf); return MP_OBJ_FROM_PTR(o); @@ -204,7 +246,7 @@ STATIC mp_obj_t aes_process(size_t n_args, const mp_obj_t *args, bool encrypt) { mp_buffer_info_t in_bufinfo; mp_get_buffer_raise(in_buf, &in_bufinfo, MP_BUFFER_READ); - if (in_bufinfo.len % 16 != 0) { + if (!is_ctr_mode(self->block_mode) && in_bufinfo.len % 16 != 0) { mp_raise_ValueError("blksize % 16"); } @@ -224,7 +266,9 @@ STATIC mp_obj_t aes_process(size_t n_args, const mp_obj_t *args, bool encrypt) { } if (AES_KEYTYPE_NONE == self->key_type) { - aes_final_set_key_impl(&self->ctx, encrypt); + // always set key for encryption if CTR mode. + const bool encrypt_mode = encrypt || is_ctr_mode(self->block_mode); + aes_final_set_key_impl(&self->ctx, encrypt_mode); self->key_type = encrypt ? AES_KEYTYPE_ENC : AES_KEYTYPE_DEC; } else { if ((encrypt && self->key_type == AES_KEYTYPE_DEC) || @@ -234,14 +278,26 @@ STATIC mp_obj_t aes_process(size_t n_args, const mp_obj_t *args, bool encrypt) { } } - if (self->block_mode == UCRYPTOLIB_MODE_ECB) { - uint8_t *in = in_bufinfo.buf, *out = out_buf_ptr; - uint8_t *top = in + in_bufinfo.len; - for (; in < top; in += 16, out += 16) { - aes_process_ecb_impl(&self->ctx, in, out, encrypt); + switch (self->block_mode) { + case UCRYPTOLIB_MODE_ECB: { + uint8_t *in = in_bufinfo.buf, *out = out_buf_ptr; + uint8_t *top = in + in_bufinfo.len; + for (; in < top; in += 16, out += 16) { + aes_process_ecb_impl(&self->ctx, in, out, encrypt); + } + break; } - } else { - aes_process_cbc_impl(&self->ctx, in_bufinfo.buf, out_buf_ptr, in_bufinfo.len, encrypt); + + case UCRYPTOLIB_MODE_CBC: + aes_process_cbc_impl(&self->ctx, in_bufinfo.buf, out_buf_ptr, in_bufinfo.len, encrypt); + break; + + #if MICROPY_PY_UCRYPTOLIB_CTR + case UCRYPTOLIB_MODE_CTR: + aes_process_ctr_impl(&self->ctx, in_bufinfo.buf, out_buf_ptr, in_bufinfo.len, + ctr_params_from_aes(self)); + break; + #endif } if (out_buf != MP_OBJ_NULL) { @@ -279,6 +335,9 @@ STATIC const mp_rom_map_elem_t mp_module_ucryptolib_globals_table[] = { #if MICROPY_PY_UCRYPTOLIB_CONSTS { MP_ROM_QSTR(MP_QSTR_MODE_ECB), MP_ROM_INT(UCRYPTOLIB_MODE_ECB) }, { MP_ROM_QSTR(MP_QSTR_MODE_CBC), MP_ROM_INT(UCRYPTOLIB_MODE_CBC) }, + #if MICROPY_PY_UCRYPTOLIB_CTR + { MP_ROM_QSTR(MP_QSTR_MODE_CTR), MP_ROM_INT(UCRYPTOLIB_MODE_CTR) }, + #endif #endif }; diff --git a/ports/unix/mpconfigport_coverage.h b/ports/unix/mpconfigport_coverage.h index 87bf8454ce..f3fbee6bfa 100644 --- a/ports/unix/mpconfigport_coverage.h +++ b/ports/unix/mpconfigport_coverage.h @@ -58,6 +58,7 @@ #define MICROPY_PY_FRAMEBUF (1) #define MICROPY_PY_COLLECTIONS_NAMEDTUPLE__ASDICT (1) #define MICROPY_PY_UCRYPTOLIB (1) +#define MICROPY_PY_UCRYPTOLIB_CTR (1) // TODO these should be generic, not bound to fatfs #define mp_type_fileio mp_type_vfs_posix_fileio diff --git a/py/mpconfig.h b/py/mpconfig.h index 893ac7dc7e..38b36a4b18 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -1281,6 +1281,11 @@ typedef double mp_float_t; #define MICROPY_PY_UCRYPTOLIB (0) #endif +// Depends on MICROPY_PY_UCRYPTOLIB +#ifndef MICROPY_PY_UCRYPTOLIB_CTR +#define MICROPY_PY_UCRYPTOLIB_CTR (0) +#endif + #ifndef MICROPY_PY_UCRYPTOLIB_CONSTS #define MICROPY_PY_UCRYPTOLIB_CONSTS (0) #endif diff --git a/tests/extmod/ucryptolib_aes128_ctr.py b/tests/extmod/ucryptolib_aes128_ctr.py new file mode 100644 index 0000000000..5a16b45297 --- /dev/null +++ b/tests/extmod/ucryptolib_aes128_ctr.py @@ -0,0 +1,28 @@ +try: + from ucryptolib import aes +except ImportError: + print("SKIP") + raise SystemExit + + +def _new(k, ctr_initial): + return aes(k, 6, ctr_initial) + + +try: + _new(b'x' * 16, b'x' * 16) +except ValueError as e: + # is CTR support disabled? + if e.args[0] == "mode": + print("SKIP") + raise SystemExit + raise e + +crypto = _new(b"1234" * 4, b"5678" * 4) +enc = crypto.encrypt(b'a') +print(enc) +enc += crypto.encrypt(b'b' * 1000) +print(enc) + +crypto = _new(b"1234" * 4, b"5678" * 4) +print(crypto.decrypt(enc)) diff --git a/tests/extmod/ucryptolib_aes128_ctr.py.exp b/tests/extmod/ucryptolib_aes128_ctr.py.exp new file mode 100644 index 0000000000..92e090fd39 --- /dev/null +++ b/tests/extmod/ucryptolib_aes128_ctr.py.exp @@ -0,0 +1,3 @@ +b'\x06' +b'\x06(F\x08\xc3hB\xfdO\x05;\xf6\x96\xfe\xad\xe0\xca\xe6\xd1\xa2m\t\x91v>|\xee\xe0q\xbc]\x9a`\xfal\x87\xa6e\xfb\x8a\xf4\xb2-\xc4x,\xfc@=,\x90\xf4\xe9h\xf0\xfc\xfb\xe6\x03\xf0d\xb6\xcdObZ\xde\x1b\xe2\x84-%=\xa9\xe4\x05\xab\xd7\x044\xf4$\xd0)\xfd\xd6\xdbL\xdd\xe6\x0cp\xca^p\xaaA\x8b\xb3!\xe3\x13\xfa\x7f#\xfa0\xbd\x0b\x9cX\xec\xed\x1c\xbc\x06\xa4\xa8\x17\xbfg\x98dW\xb9~\x04\xec\xe6lZ\xb0\xab\xd5\xc6v\xe4\x8f\x98G\xff\x9b\x8a\xae\xfd\xe5\xed\x96\x1b\xe2\x99u3\xeb\x9faYr;\xf0g\xf2\x9cq\x8dI\x1cL\xc9\xa8\xb0\xdeD\xd5\x06\x87u=\xcd\x10\x1c\xab\x14\x06n\x99\x13\x89\x9f5\xea\xd2\x08\x9e\xef$?\xb9\xdeQ\x0b\x90CH\xea@V\x94\x1a\xdd\x7f\x1dz\x82\xaay\xea$Lv\x07\x8e\xce\xb8oN\x15\xf8,\x05\x00\xd9H\xf4\xbe\xb8\xee\x0e\xd6Hjh\xc6\x11\xf8:\xfe\xed\xba_\xaf\x8e\'\x0c\x7fZ\xd5\xb7\xbc\xba\xd3+\xf1\x98i\xab\x0c-\xd9\xe6>\x9e\xd0\xe6>\x9f\xebn\xf0\x15\xd9:\xec\xf7aXa\xb2,CAB7\x18g\xcc#\xbc\xb8\xf9\xa7\xf4V\xba\x0baN\x88\xb1\xea\x94\x05\x0cV\x99_\xc4\xe6\xb2\xd1|\x92\x05*@U\xe4\\\x8dR\x98\xdf\xbfS\x97\x12^\tr\x1f\x12\x8f\xdfi\x8e=\xc4I\xfcB\r\x99f\xe3\xe31\xee\xa9\xcd\x91\x1a\x1ei\xfd\xf4\x84\xc6\xda\x9e\xf3\x8aKn\xaa\xf7\x9eS\xcc\xbaXZ\x0cpbk\x18\x1f\x9aAl>y\xad\xcb\xcf\xe1Wm\xe7\xdd\xcc\x10eW\xe4h\x1dY\xb5Zs\xf1\xe7\x16_\xdc:I1R\xd3\xfe\xb1)\t\xddE\xbax\x06R\xdc\x1dSdlu\xd1\x9c\x00\xaf\x87\x8d1\xbf$\x08\xc6/y\xdf\x1f\x97z(\xff\xb9\xcb\xf2,\x91\xd7\xa0W\xfc\xe3\xe2\x905\x17O\xaf\x18\xc7\xb8?\x94^\xf5@\x80\x8d\xaa*p\xbeR0i\x17\x1e\'-\xfa\xd9\xb2\x03\xb8\x1fY\x13\xc1{\x7f\xa9\x86\t\x99\xee\xa2\xba\xab\xc1\xbb\x07a\xa5J\x01\x98\xe8\x8e\xa1\x8aV\xc1)^A\xd9\xe7\xfej`\xb4\xe9\xd3C\xab\xd4\xdb\xb1\x8c\x83\xaa&\xf1\xe2\xfc\xa1Lb\xa8\xbb\xd6\x83\xb7\xd8\xc5\x9e\xb5\xed\x1b\xe6\x91\x90\xe4\xfa\xfdD\xc2\xcb\xb7U\xb3|?(\x86=\xc2\xff\xd3P\xd2\xc5y\x93\x13r\xcd>5\x80\xde\xdaJ\xdd\x8b\xfa\x14\xd1\x85\xa8P\x06(F\xb3?\xefm\x8e\xe5C\xfe\x98\xaf\xed\xd1!(\x1f.\xc6M\xba\x00\xcb\xbfg5\xc8\x9d\x97+\x14\x87\xf5\x9d4\xb4l\xd5\xc5>\x90\xf2\x06\xa2\xc1R\x89\xf0P\xb4\xe5\x97\xdb\x07\xd3\xc6q\x08\xb9\xe7\r\xf9\x13\x8215\xcb\x92\xed\x99\xc7"\x1e\xe3Zsh\x0e\xe7\xae\x10Xs&)\x1d\xe5\xd5\xbc\x95\x8e\xa3\xd6k[k\x9c\xa0%\xd4\x83%\x88}\x90\xf0\xa7\xc7\xa4(\xdaE\xb9~\xae\x05\xbd}\xe2\xd0\xa5Y\xc1aV[\xab\x93S\xa6\xacg\r\x14\xc6\xe2J\xd6\xcck"\xcc\xfb\xb3\x97\x14\x13\x0b\xd1\xf5\xe7)_\x1e\x0b\xbb\x01\xf7\x11u\x85b\xdf\xab\xe3\xbb:\x84zF\x14u\xfe\x89\x90\xbc\xcaF\x15y\xa3\xa4[\xce\xcf-\xae\x18\x97N\xaa\xed\x84A\xfc\x9e\xeb\xb3\xfcH\x8ej\xcc\x9f \x1b\xc1\x1f}\'q.\xc0^\xd99\x1e\x91b-\xf9\xed\xfd\x9a\x7f\xb6\rO\xea\xc8\x94\xea\xf6\xb4\xdb\xf5\xc7\xb3\xef\xf6D\x12>5\xf3\x9d*\xc9\xf8\x9f]\xb01{d\xe7\'\x8f\xc0\xfbKB\x8dd\xb1\x84\x804\xbe\xe2?AT\x14\xdb4eJ\x96\xc5\xb9%\xe5\x1c\xc0L\xae\xd6O\xde\x1fjJIRD\x96\xa2\xdb\xfc\xc6t\xce\xe6\xe8"\x81\xe6\xc7\x7fuz\xb3\x91\'D\xac\xb2\x93O\xee\x14\xaa7yT\xcf\x81p\x0b(\xa1d\xda\xf8\xcb\x01\x98\x07\'\xfe/\xe4\xca\xab\x03uR"zY\xfb\x1f\x02\xc5\x9c\xa0\'\x89\xffO\x88cK\xac\xb1+S0]%E\x1a\xeb\x04\xf7\x0b\xba\xa0\xbb\xbd|\x06@T\xee\xe7\x17\xa1T\xe3"\x07\x07q' +b'abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' From 32ba679924b8f5c8a81cff905e6bd295c6bb4df8 Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Sun, 28 Apr 2019 23:57:11 +0300 Subject: [PATCH 0325/1788] extmod/moducryptolib: Add AES-CTR support for axTLS builds. --- extmod/moducryptolib.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/extmod/moducryptolib.c b/extmod/moducryptolib.c index 6c45c2fdef..15cd4535f8 100644 --- a/extmod/moducryptolib.c +++ b/extmod/moducryptolib.c @@ -139,6 +139,33 @@ STATIC void aes_process_cbc_impl(AES_CTX_IMPL *ctx, const uint8_t *in, uint8_t * AES_cbc_decrypt(ctx, in, out, in_len); } } + +#if MICROPY_PY_UCRYPTOLIB_CTR +// axTLS doesn't have CTR support out of the box. This implements the counter part using the ECB primitive. +STATIC void aes_process_ctr_impl(AES_CTX_IMPL *ctx, const uint8_t *in, uint8_t *out, size_t in_len, struct ctr_params *ctr_params) { + size_t n = ctr_params->offset; + uint8_t *const counter = ctx->iv; + + while (in_len--) { + if (n == 0) { + aes_process_ecb_impl(ctx, counter, ctr_params->encrypted_counter, true); + + // increment the 128-bit counter + for (int i = 15; i >= 0; --i) { + if (++counter[i] != 0) { + break; + } + } + } + + *out++ = *in++ ^ ctr_params->encrypted_counter[n]; + n = (n + 1) & 0xf; + } + + ctr_params->offset = n; +} +#endif + #endif #if MICROPY_SSL_MBEDTLS From 089c9b71d10bd66549858254cc10803cba45453a Mon Sep 17 00:00:00 2001 From: Jun Wu Date: Sat, 4 May 2019 20:29:43 -0700 Subject: [PATCH 0326/1788] py: remove "if (0)" and "if (false)" branches. Prior to this commit, building the unix port with `DEBUG=1` and `-finstrument-functions` the compilation would fail with an error like "control reaches end of non-void function". This change fixes this by removing the problematic "if (0)" branches. Not all branches affect compilation, but they are all removed for consistency. --- py/compile.c | 15 ++++++--------- py/emitnative.c | 7 +++---- py/objarray.c | 13 ++++++------- py/objfun.c | 6 +++--- py/objint_mpz.c | 6 +++--- py/runtime.c | 7 +++---- 6 files changed, 24 insertions(+), 30 deletions(-) diff --git a/py/compile.c b/py/compile.c index 01e4ff9b65..27b706c8fe 100644 --- a/py/compile.c +++ b/py/compile.c @@ -3457,12 +3457,12 @@ mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_f #endif uint max_num_labels = 0; for (scope_t *s = comp->scope_head; s != NULL && comp->compile_error == MP_OBJ_NULL; s = s->next) { - if (false) { #if MICROPY_EMIT_INLINE_ASM - } else if (s->emit_options == MP_EMIT_OPT_ASM) { + if (s->emit_options == MP_EMIT_OPT_ASM) { compile_scope_inline_asm(comp, s, MP_PASS_SCOPE); + } else #endif - } else { + { compile_scope(comp, s, MP_PASS_SCOPE); // Check if any implicitly declared variables should be closed over @@ -3493,11 +3493,8 @@ mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_f emit_t *emit_native = NULL; #endif for (scope_t *s = comp->scope_head; s != NULL && comp->compile_error == MP_OBJ_NULL; s = s->next) { - if (false) { - // dummy - #if MICROPY_EMIT_INLINE_ASM - } else if (s->emit_options == MP_EMIT_OPT_ASM) { + if (s->emit_options == MP_EMIT_OPT_ASM) { // inline assembly if (comp->emit_inline_asm == NULL) { comp->emit_inline_asm = ASM_EMITTER(new)(max_num_labels); @@ -3519,9 +3516,9 @@ mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_f if (comp->compile_error == MP_OBJ_NULL) { compile_scope_inline_asm(comp, s, MP_PASS_EMIT); } + } else #endif - - } else { + { // choose the emit type diff --git a/py/emitnative.c b/py/emitnative.c index cb6cc94d35..f123ecbb58 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -2227,17 +2227,16 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) { int reg_rhs = REG_ARG_3; emit_pre_pop_reg_flexible(emit, &vtype_rhs, ®_rhs, REG_RET, REG_ARG_2); emit_pre_pop_reg(emit, &vtype_lhs, REG_ARG_2); - if (0) { - // dummy #if !(N_X64 || N_X86) - } else if (op == MP_BINARY_OP_LSHIFT) { + if (op == MP_BINARY_OP_LSHIFT) { ASM_LSL_REG_REG(emit->as, REG_ARG_2, reg_rhs); emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2); } else if (op == MP_BINARY_OP_RSHIFT) { ASM_ASR_REG_REG(emit->as, REG_ARG_2, reg_rhs); emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2); + } else #endif - } else if (op == MP_BINARY_OP_OR) { + if (op == MP_BINARY_OP_OR) { ASM_OR_REG_REG(emit->as, REG_ARG_2, reg_rhs); emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2); } else if (op == MP_BINARY_OP_XOR) { diff --git a/py/objarray.c b/py/objarray.c index 4a8d0af3cc..02f6dff528 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -375,9 +375,8 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value return MP_OBJ_NULL; // op not supported } else { mp_obj_array_t *o = MP_OBJ_TO_PTR(self_in); - if (0) { #if MICROPY_PY_BUILTINS_SLICE - } else if (mp_obj_is_type(index_in, &mp_type_slice)) { + if (mp_obj_is_type(index_in, &mp_type_slice)) { mp_bound_slice_t slice; if (!mp_seq_get_fast_slice_indexes(o->len, index_in, &slice)) { mp_raise_NotImplementedError("only slices with step=1 (aka None) are supported"); @@ -456,22 +455,22 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value mp_obj_array_t *res; size_t sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL); assert(sz > 0); - if (0) { - // dummy #if MICROPY_PY_BUILTINS_MEMORYVIEW - } else if (o->base.type == &mp_type_memoryview) { + if (o->base.type == &mp_type_memoryview) { res = m_new_obj(mp_obj_array_t); *res = *o; res->memview_offset += slice.start; res->len = slice.stop - slice.start; + } else #endif - } else { + { res = array_new(o->typecode, slice.stop - slice.start); memcpy(res->items, (uint8_t*)o->items + slice.start * sz, (slice.stop - slice.start) * sz); } return MP_OBJ_FROM_PTR(res); + } else #endif - } else { + { size_t index = mp_get_index(o->base.type, o->len, index_in, false); #if MICROPY_PY_BUILTINS_MEMORYVIEW if (o->base.type == &mp_type_memoryview) { diff --git a/py/objfun.c b/py/objfun.c index d50b7fa25d..d96c79ede4 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -458,13 +458,13 @@ STATIC mp_uint_t convert_obj_for_inline_asm(mp_obj_t obj) { return (mp_uint_t)mp_obj_str_get_data(obj, &l); } else { mp_obj_type_t *type = mp_obj_get_type(obj); - if (0) { #if MICROPY_PY_BUILTINS_FLOAT - } else if (type == &mp_type_float) { + if (type == &mp_type_float) { // convert float to int (could also pass in float registers) return (mp_int_t)mp_obj_float_get(obj); + } else #endif - } else if (type == &mp_type_tuple || type == &mp_type_list) { + if (type == &mp_type_tuple || type == &mp_type_list) { // pointer to start of tuple (could pass length, but then could use len(x) for that) size_t len; mp_obj_t *items; diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 288e9f86d6..121fd03424 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -194,18 +194,18 @@ 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_int_binary_op_extra_cases(op, lhs_in, rhs_in); } - if (0) { #if MICROPY_PY_BUILTINS_FLOAT - } else if (op == MP_BINARY_OP_TRUE_DIVIDE || op == MP_BINARY_OP_INPLACE_TRUE_DIVIDE) { + if (op == MP_BINARY_OP_TRUE_DIVIDE || op == MP_BINARY_OP_INPLACE_TRUE_DIVIDE) { if (mpz_is_zero(zrhs)) { goto zero_division_error; } mp_float_t flhs = mpz_as_float(zlhs); mp_float_t frhs = mpz_as_float(zrhs); return mp_obj_new_float(flhs / frhs); + } else #endif - } else if (op >= MP_BINARY_OP_INPLACE_OR && op < MP_BINARY_OP_CONTAINS) { + 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/runtime.c b/py/runtime.c index a3628eecb4..e502566059 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -1049,14 +1049,13 @@ void mp_load_method_maybe(mp_obj_t obj, qstr attr, mp_obj_t *dest) { mp_obj_type_t *type = mp_obj_get_type(obj); // look for built-in names - if (0) { #if MICROPY_CPYTHON_COMPAT - } else if (attr == MP_QSTR___class__) { + if (attr == MP_QSTR___class__) { // a.__class__ is equivalent to type(a) dest[0] = MP_OBJ_FROM_PTR(type); + } else #endif - - } else if (attr == MP_QSTR___next__ && type->iternext != NULL) { + if (attr == MP_QSTR___next__ && type->iternext != NULL) { dest[0] = MP_OBJ_FROM_PTR(&mp_builtin_next_obj); dest[1] = obj; From 6323cbda4fd82f2396a19e18a224a2579a392303 Mon Sep 17 00:00:00 2001 From: Mike Causer Date: Tue, 12 Feb 2019 23:28:49 +1100 Subject: [PATCH 0327/1788] docs/esp8266: Add tutorial for APA102 LEDs. --- docs/esp8266/tutorial/apa102.rst | 91 ++++++++++++++++++++++++++++++++ docs/esp8266/tutorial/index.rst | 1 + 2 files changed, 92 insertions(+) create mode 100644 docs/esp8266/tutorial/apa102.rst diff --git a/docs/esp8266/tutorial/apa102.rst b/docs/esp8266/tutorial/apa102.rst new file mode 100644 index 0000000000..1c775daae3 --- /dev/null +++ b/docs/esp8266/tutorial/apa102.rst @@ -0,0 +1,91 @@ +Controlling APA102 LEDs +======================= + +APA102 LEDs, also known as DotStar LEDs, are individually addressable +full-colour RGB LEDs, generally in a string formation. They differ from +NeoPixels in that they require two pins to control - both a Clock and Data pin. +They can operate at a much higher data and PWM frequencies than NeoPixels and +are more suitable for persistence-of-vision effects. + +To create an APA102 object do the following:: + + >>> import machine, apa102 + >>> strip = apa102.APA102(machine.Pin(5), machine.Pin(4), 60) + +This configures an 60 pixel APA102 strip with clock on GPIO5 and data on GPIO4. +You can adjust the pin numbers and the number of pixels to suit your needs. + +The RGB colour data, as well as a brightness level, is sent to the APA102 in a +certain order. Usually this is ``(Red, Green, Blue, Brightness)``. +If you are using one of the newer APA102C LEDs the green and blue are swapped, +so the order is ``(Red, Blue, Green, Brightness)``. +The APA102 has more of a square lens while the APA102C has more of a round one. +If you are using a APA102C strip and would prefer to provide colours in RGB +order instead of RBG, you can customise the tuple colour order like so:: + + >>> strip.ORDER = (0, 2, 1, 3) + +To set the colour of pixels use:: + + >>> strip[0] = (255, 255, 255, 31) # set to white, full brightness + >>> strip[1] = (255, 0, 0, 31) # set to red, full brightness + >>> strip[2] = (0, 255, 0, 15) # set to green, half brightness + >>> strip[3] = (0, 0, 255, 7) # set to blue, quarter brightness + +Use the ``write()`` method to output the colours to the LEDs:: + + >>> strip.write() + +Demonstration:: + + import time + import machine, apa102 + + # 1M strip with 60 LEDs + strip = apa102.APA102(machine.Pin(5), machine.Pin(4), 60) + + brightness = 1 # 0 is off, 1 is dim, 31 is max + + # Helper for converting 0-255 offset to a colour tuple + def wheel(offset, brightness): + # The colours are a transition r - g - b - back to r + offset = 255 - offset + if offset < 85: + return (255 - offset * 3, 0, offset * 3, brightness) + if offset < 170: + offset -= 85 + return (0, offset * 3, 255 - offset * 3, brightness) + offset -= 170 + return (offset * 3, 255 - offset * 3, 0, brightness) + + # Demo 1: RGB RGB RGB + red = 0xff0000 + green = red >> 8 + blue = red >> 16 + for i in range(strip.n): + colour = red >> (i % 3) * 8 + strip[i] = ((colour & red) >> 16, (colour & green) >> 8, (colour & blue), brightness) + strip.write() + + # Demo 2: Show all colours of the rainbow + for i in range(strip.n): + strip[i] = wheel((i * 256 // strip.n) % 255, brightness) + strip.write() + + # Demo 3: Fade all pixels together through rainbow colours, offset each pixel + for r in range(5): + for n in range(256): + for i in range(strip.n): + strip[i] = wheel(((i * 256 // strip.n) + n) & 255, brightness) + strip.write() + time.sleep_ms(25) + + # Demo 4: Same colour, different brightness levels + for b in range(31,-1,-1): + strip[0] = (255, 153, 0, b) + strip.write() + time.sleep_ms(250) + + # End: Turn off all the LEDs + strip.fill((0, 0, 0, 0)) + strip.write() diff --git a/docs/esp8266/tutorial/index.rst b/docs/esp8266/tutorial/index.rst index 0a4b5f2a66..4ba211a4b2 100644 --- a/docs/esp8266/tutorial/index.rst +++ b/docs/esp8266/tutorial/index.rst @@ -29,5 +29,6 @@ to ``__. powerctrl.rst onewire.rst neopixel.rst + apa102.rst dht.rst nextsteps.rst From 7e90e22ea52665e38138d1e704d5e527439b663c Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 2 May 2019 09:59:21 +1000 Subject: [PATCH 0328/1788] mpy-cross: Add --version command line option to print version info. Prints something like: MicroPython v1.10-304-g8031b7a25 on 2019-05-02; mpy-cross emitting mpy v4 --- mpy-cross/main.c | 6 ++++++ py/persistentcode.c | 3 --- py/persistentcode.h | 3 +++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/mpy-cross/main.c b/mpy-cross/main.c index 7bf2075962..970ad2d75f 100644 --- a/mpy-cross/main.c +++ b/mpy-cross/main.c @@ -34,6 +34,7 @@ #include "py/runtime.h" #include "py/gc.h" #include "py/stackctrl.h" +#include "genhdr/mpversion.h" #ifdef _WIN32 #include "ports/windows/fmode.h" #endif @@ -98,6 +99,7 @@ STATIC int usage(char **argv) { printf( "usage: %s [] [-X ] \n" "Options:\n" +"--version : show version information\n" "-o : output file for compiled bytecode (defaults to input with .mpy extension)\n" "-s : source filename to embed in the compiled bytecode (defaults to input file)\n" "-v : verbose (trace various operations); can be multiple\n" @@ -211,6 +213,10 @@ MP_NOINLINE int main_(int argc, char **argv) { if (argv[a][0] == '-') { if (strcmp(argv[a], "-X") == 0) { a += 1; + } else if (strcmp(argv[a], "--version") == 0) { + printf("MicroPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE + "; mpy-cross emitting mpy v" MP_STRINGIFY(MPY_VERSION) "\n"); + return 0; } else if (strcmp(argv[a], "-v") == 0) { mp_verbose_flag++; } else if (strncmp(argv[a], "-O", 2) == 0) { diff --git a/py/persistentcode.c b/py/persistentcode.c index 70ec2ddd65..c8d3bb8a66 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -40,9 +40,6 @@ #define QSTR_LAST_STATIC MP_QSTR_zip -// The current version of .mpy files -#define MPY_VERSION (4) - // Macros to encode/decode flags to/from the feature byte #define MPY_FEATURE_ENCODE_FLAGS(flags) (flags) #define MPY_FEATURE_DECODE_FLAGS(feat) ((feat) & 3) diff --git a/py/persistentcode.h b/py/persistentcode.h index b27c3de2f0..2074c64fe2 100644 --- a/py/persistentcode.h +++ b/py/persistentcode.h @@ -30,6 +30,9 @@ #include "py/reader.h" #include "py/emitglue.h" +// The current version of .mpy files +#define MPY_VERSION 4 + enum { MP_NATIVE_ARCH_NONE = 0, MP_NATIVE_ARCH_X86, From 34942d0a72980173eca51b201f271f67bcae46b5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 2 May 2019 22:04:55 +1000 Subject: [PATCH 0329/1788] stm32/machine_uart: Change default UART timeout to 0, for non blocking. It's more common to need non-blocking behaviour when reading from a UART, rather than having a large timeout like 1000ms (the original behaviour). With a large timeout it's 1) likely that the function will read forever if characters keep trickling it; or 2) the function will unnecessarily wait when characters come sporadically, eg at a REPL prompt. --- docs/library/pyb.UART.rst | 2 +- ports/stm32/machine_uart.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/library/pyb.UART.rst b/docs/library/pyb.UART.rst index 4359f1d9d6..ab7ab2fb88 100644 --- a/docs/library/pyb.UART.rst +++ b/docs/library/pyb.UART.rst @@ -69,7 +69,7 @@ Constructors Methods ------- -.. method:: UART.init(baudrate, bits=8, parity=None, stop=1, \*, timeout=1000, flow=0, timeout_char=0, read_buf_len=64) +.. method:: UART.init(baudrate, bits=8, parity=None, stop=1, \*, timeout=0, flow=0, timeout_char=0, read_buf_len=64) Initialise the UART bus with the given parameters: diff --git a/ports/stm32/machine_uart.c b/ports/stm32/machine_uart.c index 169e8c589d..29369c0c14 100644 --- a/ports/stm32/machine_uart.c +++ b/ports/stm32/machine_uart.c @@ -224,7 +224,7 @@ STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, size_t n_args, const { MP_QSTR_parity, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, { MP_QSTR_stop, MP_ARG_INT, {.u_int = 1} }, { MP_QSTR_flow, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_HWCONTROL_NONE} }, - { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000} }, + { 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_QSTR_rxbuf, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_read_buf_len, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} }, // legacy From 97753a1bbc5a20003bcf2a7f90cff2ca5c81ee92 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 6 May 2019 15:46:52 +1000 Subject: [PATCH 0330/1788] stm32: Move factory reset files and code to separate source file. The new function factory_reset_make_files() populates the given filesystem with the default factory files. It is defined with weak linkage so it can be overridden by a board. This commit also brings some minor user-facing changes: - boot.py is now no longer created unconditionally if it doesn't exist, it is now only created when the filesystem is formatted and the other files are populated (so, before, if the user deleted boot.py it would be recreated at next boot; now it won't be). - pybcdc.inf and README.txt are only created if the board has USB, because they only really make sense if the filesystem is exposed via USB. --- ports/stm32/Makefile | 1 + ports/stm32/factoryreset.c | 98 ++++++++++++++++++++++++++++++++++++++ ports/stm32/factoryreset.h | 33 +++++++++++++ ports/stm32/main.c | 78 ++---------------------------- 4 files changed, 135 insertions(+), 75 deletions(-) create mode 100644 ports/stm32/factoryreset.c create mode 100644 ports/stm32/factoryreset.h diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index d90a7c2e4f..943acd4943 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -229,6 +229,7 @@ SRC_C = \ systick.c \ powerctrl.c \ pybthread.c \ + factoryreset.c \ timer.c \ led.c \ pin.c \ diff --git a/ports/stm32/factoryreset.c b/ports/stm32/factoryreset.c new file mode 100644 index 0000000000..6b0c289a78 --- /dev/null +++ b/ports/stm32/factoryreset.c @@ -0,0 +1,98 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2019 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 "factoryreset.h" + +#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" +"\r\n" +"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[] = +"# main.py -- put your code here!\r\n" +; + +#if MICROPY_HW_ENABLE_USB +static const char fresh_pybcdc_inf[] = +#include "genhdr/pybcdc_inf.h" +; + +static const char fresh_readme_txt[] = +"This is a MicroPython board\r\n" +"\r\n" +"You can get started right away by writing your Python code in 'main.py'.\r\n" +"\r\n" +"For a serial prompt:\r\n" +" - Windows: you need to go to 'Device manager', right click on the unknown device,\r\n" +" then update the driver software, using the 'pybcdc.inf' file found on this drive.\r\n" +" Then use a terminal program like Hyperterminal or putty.\r\n" +" - Mac OS X: use the command: screen /dev/tty.usbmodem*\r\n" +" - Linux: use the command: screen /dev/ttyACM0\r\n" +"\r\n" +"Please visit http://micropython.org/help/ for further help.\r\n" +; +#endif + +typedef struct _factory_file_t { + const char *name; + size_t len; + const char *data; +} factory_file_t; + +static const factory_file_t factory_files[] = { + {"boot.py", sizeof(fresh_boot_py) - 1, fresh_boot_py}, + {"main.py", sizeof(fresh_main_py) - 1, fresh_main_py}, + #if MICROPY_HW_ENABLE_USB + {"pybcdc.inf", sizeof(fresh_pybcdc_inf) - 1, fresh_pybcdc_inf}, + {"README.txt", sizeof(fresh_readme_txt) - 1, fresh_readme_txt}, + #endif +}; + +MP_WEAK void factory_reset_make_files(FATFS *fatfs) { + for (int i = 0; i < MP_ARRAY_SIZE(factory_files); ++i) { + const factory_file_t *f = &factory_files[i]; + FIL fp; + FRESULT res = f_open(fatfs, &fp, f->name, FA_WRITE | FA_CREATE_ALWAYS); + if (res == FR_OK) { + UINT n; + f_write(&fp, f->data, f->len, &n); + f_close(&fp); + } + } +} + +#endif // MICROPY_HW_ENABLE_STORAGE diff --git a/ports/stm32/factoryreset.h b/ports/stm32/factoryreset.h new file mode 100644 index 0000000000..85226f880b --- /dev/null +++ b/ports/stm32/factoryreset.h @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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_FACTORYRESET_H +#define MICROPY_INCLUDED_STM32_FACTORYRESET_H + +#include "lib/oofatfs/ff.h" + +void factory_reset_make_files(FATFS *fatfs); + +#endif // MICROPY_INCLUDED_STM32_FACTORYRESET_H diff --git a/ports/stm32/main.c b/ports/stm32/main.c index a37c6f8979..ff4589f9d4 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -45,6 +45,7 @@ #include "pendsv.h" #include "pybthread.h" #include "gccollect.h" +#include "factoryreset.h" #include "modmachine.h" #include "i2c.h" #include "spi.h" @@ -148,42 +149,6 @@ 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" -"\r\n" -"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[] = -"# main.py -- put your code here!\r\n" -; - -static const char fresh_pybcdc_inf[] = -#include "genhdr/pybcdc_inf.h" -; - -static const char fresh_readme_txt[] = -"This is a MicroPython board\r\n" -"\r\n" -"You can get started right away by writing your Python code in 'main.py'.\r\n" -"\r\n" -"For a serial prompt:\r\n" -" - Windows: you need to go to 'Device manager', right click on the unknown device,\r\n" -" then update the driver software, using the 'pybcdc.inf' file found on this drive.\r\n" -" Then use a terminal program like Hyperterminal or putty.\r\n" -" - Mac OS X: use the command: screen /dev/tty.usbmodem*\r\n" -" - Linux: use the command: screen /dev/ttyACM0\r\n" -"\r\n" -"Please visit http://micropython.org/help/ for further help.\r\n" -; - // avoid inlining to avoid stack usage within main() MP_NOINLINE STATIC bool init_flash_fs(uint reset_mode) { // init the vfs object @@ -213,23 +178,8 @@ MP_NOINLINE STATIC bool init_flash_fs(uint reset_mode) { // set label f_setlabel(&vfs_fat->fatfs, MICROPY_HW_FLASH_FS_LABEL); - // create empty main.py - FIL fp; - f_open(&vfs_fat->fatfs, &fp, "/main.py", FA_WRITE | FA_CREATE_ALWAYS); - UINT n; - f_write(&fp, fresh_main_py, sizeof(fresh_main_py) - 1 /* don't count null terminator */, &n); - // TODO check we could write n bytes - f_close(&fp); - - // create .inf driver file - f_open(&vfs_fat->fatfs, &fp, "/pybcdc.inf", FA_WRITE | FA_CREATE_ALWAYS); - f_write(&fp, fresh_pybcdc_inf, sizeof(fresh_pybcdc_inf) - 1 /* don't count null terminator */, &n); - f_close(&fp); - - // create readme file - f_open(&vfs_fat->fatfs, &fp, "/README.txt", FA_WRITE | FA_CREATE_ALWAYS); - f_write(&fp, fresh_readme_txt, sizeof(fresh_readme_txt) - 1 /* don't count null terminator */, &n); - f_close(&fp); + // populate the filesystem with factory files + factory_reset_make_files(&vfs_fat->fatfs); // keep LED on for at least 200ms systick_wait_at_least(start_tick, 200); @@ -258,28 +208,6 @@ MP_NOINLINE STATIC bool init_flash_fs(uint reset_mode) { // It is set to the internal flash filesystem by default. MP_STATE_PORT(vfs_cur) = vfs; - // Make sure we have a /flash/boot.py. Create it if needed. - FILINFO fno; - res = f_stat(&vfs_fat->fatfs, "/boot.py", &fno); - if (res != FR_OK) { - // doesn't exist, create fresh file - - // LED on to indicate creation of boot.py - led_state(PYB_LED_GREEN, 1); - uint32_t start_tick = HAL_GetTick(); - - FIL fp; - f_open(&vfs_fat->fatfs, &fp, "/boot.py", FA_WRITE | FA_CREATE_ALWAYS); - UINT n; - f_write(&fp, fresh_boot_py, sizeof(fresh_boot_py) - 1 /* don't count null terminator */, &n); - // TODO check we could write n bytes - f_close(&fp); - - // keep LED on for at least 200ms - systick_wait_at_least(start_tick, 200); - led_state(PYB_LED_GREEN, 0); - } - return true; } #endif From b8c74014e42331afca3db5911b30032a109f73f1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 8 May 2019 12:45:24 +1000 Subject: [PATCH 0331/1788] stm32/usbd_cdc_interface: Don't retransmit chars if USB is reconnected. Before this change, if the USB was reconnected it was possible that some characters in the TX buffer were retransmitted because tx_buf_ptr_out and tx_buf_ptr_out_shadow were reset while tx_buf_ptr_in wasn't. That behaviour is fixed here by retaining the TX buffer state across reconnects. Fixes issue #4761. --- ports/stm32/usb.c | 2 +- ports/stm32/usbd_cdc_interface.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index 18841fdee4..8b7608a150 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -69,7 +69,7 @@ typedef struct _usb_device_t { usbd_hid_itf_t usbd_hid_itf; } usb_device_t; -usb_device_t usb_device; +usb_device_t usb_device = {0}; pyb_usb_storage_medium_t pyb_usb_storage_medium = PYB_USB_STORAGE_MEDIUM_NONE; // predefined hid mouse data diff --git a/ports/stm32/usbd_cdc_interface.c b/ports/stm32/usbd_cdc_interface.c index 586f2d525e..4a4a8beb85 100644 --- a/ports/stm32/usbd_cdc_interface.c +++ b/ports/stm32/usbd_cdc_interface.c @@ -64,14 +64,14 @@ static uint8_t usbd_cdc_connect_tx_timer; 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 - // be filled (by usbd_cdc_tx_always) before the USB device is connected. + // Reset the CDC state due to a new USB host connection + // Note: we don't reset tx_buf_ptr_* in order to allow the output buffer to + // be filled (by usbd_cdc_tx_always) before the USB device is connected, and + // to retain transmit buffer state across multiple USB connections (they will + // be 0 at MCU reset since the variables live in the BSS). cdc->rx_buf_put = 0; cdc->rx_buf_get = 0; cdc->rx_buf_full = false; - cdc->tx_buf_ptr_out = 0; - cdc->tx_buf_ptr_out_shadow = 0; cdc->tx_need_empty_packet = 0; cdc->connect_state = USBD_CDC_CONNECT_STATE_DISCONNECTED; From 3f54462adddb3210b46f3dba3f1879cd01e2f16e Mon Sep 17 00:00:00 2001 From: Elad Namdar Date: Tue, 7 May 2019 00:24:22 +0300 Subject: [PATCH 0332/1788] unix/modusocket: Fix use of setsockopt in usocket.settimeout impl. The original code called setsockopt(SO_RCVTIMEO/SO_SNDTIMEO) with NULL timeout structure argument, which is an illegal usage of that function. The old code also didn't validate the return value of setsockopt, missing the bug completely. --- ports/unix/modusocket.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/ports/unix/modusocket.c b/ports/unix/modusocket.c index fd4092a622..a0f0fc25b1 100644 --- a/ports/unix/modusocket.c +++ b/ports/unix/modusocket.c @@ -337,10 +337,9 @@ STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) { struct timeval tv = {0,}; bool new_blocking = true; - if (timeout_in == mp_const_none) { - setsockopt(self->fd, SOL_SOCKET, SO_RCVTIMEO, NULL, 0); - setsockopt(self->fd, SOL_SOCKET, SO_SNDTIMEO, NULL, 0); - } else { + // Timeout of None means no timeout, which in POSIX is signified with 0 timeout, + // and that's how 'tv' is initialized above + if (timeout_in != mp_const_none) { #if MICROPY_PY_BUILTINS_FLOAT mp_float_t val = mp_obj_get_float(timeout_in); double ipart; @@ -354,14 +353,17 @@ STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) { // for Python API it means non-blocking. if (tv.tv_sec == 0 && tv.tv_usec == 0) { new_blocking = false; - } else { - setsockopt(self->fd, SOL_SOCKET, SO_RCVTIMEO, - &tv, sizeof(struct timeval)); - setsockopt(self->fd, SOL_SOCKET, SO_SNDTIMEO, - &tv, sizeof(struct timeval)); } } + if (new_blocking) { + int r; + r = setsockopt(self->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval)); + RAISE_ERRNO(r, errno); + r = setsockopt(self->fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(struct timeval)); + RAISE_ERRNO(r, errno); + } + if (self->blocking != new_blocking) { socket_setblocking(self_in, mp_obj_new_bool(new_blocking)); } From 29865e3e58a89eace83fc1910221724363f55d64 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Wed, 8 May 2019 15:33:32 +1000 Subject: [PATCH 0333/1788] stm32/rtc: Allow overriding startup timeouts from mpconfigboard. --- ports/stm32/rtc.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/ports/stm32/rtc.c b/ports/stm32/rtc.c index 4b9fbbda52..a7c3f2068b 100644 --- a/ports/stm32/rtc.c +++ b/ports/stm32/rtc.c @@ -342,18 +342,24 @@ STATIC void PYB_RTC_MspInit_Kick(RTC_HandleTypeDef *hrtc, bool rtc_use_lse, bool rtc_need_init_finalise = true; } -#define PYB_LSE_TIMEOUT_VALUE 1000 // ST docs spec 2000 ms LSE startup, seems to be too pessimistic -#define PYB_LSI_TIMEOUT_VALUE 500 // this is way too pessimistic, typ. < 1ms -#define PYB_BYP_TIMEOUT_VALUE 150 +#ifndef MICROPY_HW_RTC_LSE_TIMEOUT_MS +#define MICROPY_HW_RTC_LSE_TIMEOUT_MS 1000 // ST docs spec 2000 ms LSE startup, seems to be too pessimistic +#endif +#ifndef MICROPY_HW_RTC_LSI_TIMEOUT_MS +#define MICROPY_HW_RTC_LSI_TIMEOUT_MS 500 // this is way too pessimistic, typ. < 1ms +#endif +#ifndef MICROPY_HW_RTC_BYP_TIMEOUT_MS +#define MICROPY_HW_RTC_BYP_TIMEOUT_MS 150 +#endif STATIC HAL_StatusTypeDef PYB_RTC_MspInit_Finalise(RTC_HandleTypeDef *hrtc) { // we already had a kick so now wait for the corresponding ready state... if (rtc_use_lse) { // we now have to wait for LSE ready or timeout - uint32_t timeout = PYB_LSE_TIMEOUT_VALUE; + uint32_t timeout = MICROPY_HW_RTC_LSE_TIMEOUT_MS; #if MICROPY_HW_RTC_USE_BYPASS if (RCC->BDCR & RCC_BDCR_LSEBYP) { - timeout = PYB_BYP_TIMEOUT_VALUE; + timeout = MICROPY_HW_RTC_BYP_TIMEOUT_MS; } #endif uint32_t tickstart = rtc_startup_tick; @@ -366,7 +372,7 @@ STATIC HAL_StatusTypeDef PYB_RTC_MspInit_Finalise(RTC_HandleTypeDef *hrtc) { // we now have to wait for LSI ready or timeout uint32_t tickstart = rtc_startup_tick; while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSIRDY) == RESET) { - if ((HAL_GetTick() - tickstart ) > PYB_LSI_TIMEOUT_VALUE) { + if ((HAL_GetTick() - tickstart ) > MICROPY_HW_RTC_LSI_TIMEOUT_MS) { return HAL_TIMEOUT; } } From dac9d4767175541aaaaf0e2f873322f5f1db3b0c Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 21 Feb 2019 14:07:44 +1100 Subject: [PATCH 0334/1788] py/objgenerator: Fix handling of None passed as 2nd arg to throw(). Fixes issue #4527. --- py/objgenerator.c | 17 ++++++++++++++++- tests/basics/gen_yield_from_throw.py | 22 ++++++++++++++++++++-- tests/basics/generator_throw.py | 14 ++++++++++++-- 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/py/objgenerator.c b/py/objgenerator.c index c306bb0c58..92bafea6a9 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -252,7 +252,22 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(gen_instance_send_obj, gen_instance_send); STATIC mp_obj_t gen_instance_close(mp_obj_t self_in); STATIC mp_obj_t gen_instance_throw(size_t n_args, const mp_obj_t *args) { - mp_obj_t exc = (n_args == 2) ? args[1] : args[2]; + // The signature of this function is: throw(type[, value[, traceback]]) + // CPython will pass all given arguments through the call chain and process them + // at the point they are used (native generators will handle them differently to + // user-defined generators with a throw() method). To save passing multiple + // values, MicroPython instead does partial processing here to reduce it down to + // one argument and passes that through: + // - if only args[1] is given, or args[2] is given but is None, args[1] is + // passed through (in the standard case it is an exception class or instance) + // - if args[2] is given and not None it is passed through (in the standard + // case it would be an exception instance and args[1] its corresponding class) + // - args[3] is always ignored + + mp_obj_t exc = args[1]; + if (n_args > 2 && args[2] != mp_const_none) { + exc = args[2]; + } mp_obj_t ret = gen_resume_and_raise(args[0], mp_const_none, exc); if (ret == MP_OBJ_STOP_ITERATION) { diff --git a/tests/basics/gen_yield_from_throw.py b/tests/basics/gen_yield_from_throw.py index 703158f4d4..804c53dda0 100644 --- a/tests/basics/gen_yield_from_throw.py +++ b/tests/basics/gen_yield_from_throw.py @@ -1,8 +1,8 @@ def gen(): try: yield 1 - except ValueError: - print("got ValueError from upstream!") + except ValueError as e: + print("got ValueError from upstream!", repr(e.args)) yield "str1" raise TypeError @@ -16,3 +16,21 @@ try: print(next(g)) except TypeError: print("got TypeError from downstream!") + +# passing None as second argument to throw +g = gen2() +print(next(g)) +print(g.throw(ValueError, None)) +try: + print(next(g)) +except TypeError: + print("got TypeError from downstream!") + +# passing an exception instance as second argument to throw +g = gen2() +print(next(g)) +print(g.throw(ValueError, ValueError(123))) +try: + print(next(g)) +except TypeError: + print("got TypeError from downstream!") diff --git a/tests/basics/generator_throw.py b/tests/basics/generator_throw.py index bf5ff33a25..1b43c125ea 100644 --- a/tests/basics/generator_throw.py +++ b/tests/basics/generator_throw.py @@ -28,8 +28,8 @@ except StopIteration: def gen(): try: yield 123 - except GeneratorExit: - print('GeneratorExit') + except GeneratorExit as e: + print('GeneratorExit', repr(e.args)) yield 456 # thrown a class @@ -41,3 +41,13 @@ print(g.throw(GeneratorExit)) g = gen() print(next(g)) print(g.throw(GeneratorExit())) + +# thrown an instance with None as second arg +g = gen() +print(next(g)) +print(g.throw(GeneratorExit(), None)) + +# thrown a class and instance +g = gen() +print(next(g)) +print(g.throw(GeneratorExit, GeneratorExit(123))) From 4268d0e1ace8ec42f08c7be328a5e5de21653b48 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 9 May 2019 13:49:07 +1000 Subject: [PATCH 0335/1788] py/objgenerator: Remove unneeded forward decl and clean up white space. --- py/objgenerator.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/py/objgenerator.c b/py/objgenerator.c index 92bafea6a9..29c7cb16d0 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2013-2019 Damien P. George * Copyright (c) 2014-2017 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -247,10 +247,8 @@ STATIC mp_obj_t gen_instance_send(mp_obj_t self_in, mp_obj_t send_value) { return ret; } } - STATIC MP_DEFINE_CONST_FUN_OBJ_2(gen_instance_send_obj, gen_instance_send); -STATIC mp_obj_t gen_instance_close(mp_obj_t self_in); STATIC mp_obj_t gen_instance_throw(size_t n_args, const mp_obj_t *args) { // The signature of this function is: throw(type[, value[, traceback]]) // CPython will pass all given arguments through the call chain and process them @@ -276,7 +274,6 @@ STATIC mp_obj_t gen_instance_throw(size_t n_args, const mp_obj_t *args) { return ret; } } - STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(gen_instance_throw_obj, 2, 4, gen_instance_throw); STATIC mp_obj_t gen_instance_close(mp_obj_t self_in) { @@ -298,7 +295,6 @@ STATIC mp_obj_t gen_instance_close(mp_obj_t self_in) { return mp_const_none; } } - 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) { From c0a1de3c216e86e679520fa50daf41dd9ac3ea78 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 9 May 2019 17:11:33 +1000 Subject: [PATCH 0336/1788] py/misc.h: Rename _MP_STRINGIFY to not use leading underscore in ident. Macro identifiers with a leading underscore are reserved. --- py/misc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/py/misc.h b/py/misc.h index e6d25b8509..0aa4a5d2c6 100644 --- a/py/misc.h +++ b/py/misc.h @@ -47,8 +47,8 @@ typedef unsigned int uint; #endif // Classical double-indirection stringification of preprocessor macro's value -#define _MP_STRINGIFY(x) #x -#define MP_STRINGIFY(x) _MP_STRINGIFY(x) +#define MP_STRINGIFY_HELPER(x) #x +#define MP_STRINGIFY(x) MP_STRINGIFY_HELPER(x) // Static assertion macro #define MP_STATIC_ASSERT(cond) ((void)sizeof(char[1 - 2 * !(cond)])) From 99a8fa794089de2ca7292a49bdcb8a4550a06f4c Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 8 May 2019 23:30:57 +1000 Subject: [PATCH 0337/1788] esp8266/modmachine: Handle overflow of timer to get longer periods. Can now handle up to about 298 days maximum for millisecond periods. Fixes issue #4664. --- ports/esp8266/modmachine.c | 67 +++++++++++++++++++++++++++++++++----- 1 file changed, 59 insertions(+), 8 deletions(-) diff --git a/ports/esp8266/modmachine.c b/ports/esp8266/modmachine.c index 58368b8f0b..ccde1e5ed8 100644 --- a/ports/esp8266/modmachine.c +++ b/ports/esp8266/modmachine.c @@ -167,12 +167,49 @@ STATIC mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_deepsleep_obj, 0, 1, machine_deepsleep); +// These values are from the datasheet +#define ESP_TIMER_US_MIN (100) +#define ESP_TIMER_US_MAX (0xfffffff) +#define ESP_TIMER_MS_MAX (0x689d0) + typedef struct _esp_timer_obj_t { mp_obj_base_t base; os_timer_t timer; + uint32_t remain_ms; // if non-zero, remaining time to handle large periods + uint32_t period_ms; // if non-zero, periodic timer with a large period mp_obj_t callback; } esp_timer_obj_t; +STATIC void esp_timer_arm_ms(esp_timer_obj_t *self, uint32_t ms, bool repeat) { + if (ms <= ESP_TIMER_MS_MAX) { + self->remain_ms = 0; + self->period_ms = 0; + } else { + self->remain_ms = ms - ESP_TIMER_MS_MAX; + if (repeat) { + repeat = false; + self->period_ms = ms; + } else { + self->period_ms = 0; + } + ms = ESP_TIMER_MS_MAX; + } + os_timer_arm(&self->timer, ms, repeat); +} + +STATIC void esp_timer_arm_us(esp_timer_obj_t *self, uint32_t us, bool repeat) { + if (us < ESP_TIMER_US_MIN) { + us = ESP_TIMER_US_MIN; + } + if (us <= ESP_TIMER_US_MAX) { + self->remain_ms = 0; + self->period_ms = 0; + os_timer_arm_us(&self->timer, us, repeat); + } else { + esp_timer_arm_ms(self, us / 1000, repeat); + } +} + const mp_obj_type_t esp_timer_type; STATIC void esp_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { @@ -189,7 +226,21 @@ STATIC mp_obj_t esp_timer_make_new(const mp_obj_type_t *type, size_t n_args, siz STATIC void esp_timer_cb(void *arg) { esp_timer_obj_t *self = arg; - mp_sched_schedule(self->callback, self); + if (self->remain_ms != 0) { + // Handle periods larger than the maximum system period + uint32_t next_period_ms = self->remain_ms; + if (next_period_ms > ESP_TIMER_MS_MAX) { + next_period_ms = ESP_TIMER_MS_MAX; + } + self->remain_ms -= next_period_ms; + os_timer_arm(&self->timer, next_period_ms, false); + } else { + mp_sched_schedule(self->callback, self); + if (self->period_ms != 0) { + // A periodic timer with a larger period: reschedule it + esp_timer_arm_ms(self, self->period_ms, true); + } + } } STATIC mp_obj_t esp_timer_init_helper(esp_timer_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { @@ -225,30 +276,30 @@ STATIC mp_obj_t esp_timer_init_helper(esp_timer_obj_t *self, size_t n_args, cons if (args[ARG_freq].u_obj != mp_const_none) { mp_float_t freq = mp_obj_get_float(args[ARG_freq].u_obj); if (freq < 0.001) { - os_timer_arm(&self->timer, (mp_int_t)(1000 / freq), args[ARG_mode].u_int); + esp_timer_arm_ms(self, (mp_int_t)(1000 / freq), args[ARG_mode].u_int); } else { - os_timer_arm_us(&self->timer, (mp_int_t)(1000000 / freq), args[ARG_mode].u_int); + esp_timer_arm_us(self, (mp_int_t)(1000000 / freq), args[ARG_mode].u_int); } } #else if (args[ARG_freq].u_int != 0xffffffff) { - os_timer_arm_us(&self->timer, 1000000 / args[ARG_freq].u_int, args[ARG_mode].u_int); + esp_timer_arm_us(self, 1000000 / args[ARG_freq].u_int, args[ARG_mode].u_int); } #endif else { mp_int_t period = args[ARG_period].u_int; mp_int_t hz = args[ARG_tick_hz].u_int; if (hz == 1000) { - os_timer_arm(&self->timer, period, args[ARG_mode].u_int); + esp_timer_arm_ms(self, period, args[ARG_mode].u_int); } else if (hz == 1000000) { - os_timer_arm_us(&self->timer, period, args[ARG_mode].u_int); + esp_timer_arm_us(self, period, args[ARG_mode].u_int); } else { // Use a long long to ensure that we don't either overflow or loose accuracy uint64_t period_us = (((uint64_t)period) * 1000000) / hz; if (period_us < 0x80000000ull) { - os_timer_arm_us(&self->timer, (mp_int_t)period_us, args[ARG_mode].u_int); + esp_timer_arm_us(self, (mp_int_t)period_us, args[ARG_mode].u_int); } else { - os_timer_arm(&self->timer, (mp_int_t)(period_us / 1000), args[ARG_mode].u_int); + esp_timer_arm_ms(self, (mp_int_t)(period_us / 1000), args[ARG_mode].u_int); } } } From f812394c33b0484f4bd24ef101c3c9250a74ab24 Mon Sep 17 00:00:00 2001 From: Nicko van Someren Date: Thu, 9 May 2019 13:57:45 -0600 Subject: [PATCH 0338/1788] docs/esp32: Correct quickref for ESP32 hardware SPI with non-default IO. --- docs/esp32/quickref.rst | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst index 5ac8aa3b2f..76fe0d9f9e 100644 --- a/docs/esp32/quickref.rst +++ b/docs/esp32/quickref.rst @@ -128,6 +128,8 @@ with timer ID of -1:: The period is in milliseconds. +.. _Pins_and_GPIO: + Pins and GPIO ------------- @@ -274,8 +276,13 @@ class:: Hardware SPI bus ---------------- -There are two hardware SPI channels that allow faster (up to 80Mhz) -transmission rates, but are only supported on a subset of pins. +There are two hardware SPI channels that allow faster transmission +rates (up to 80Mhz). These may be used on any IO pins that support the +required direction and are otherwise unused (see :ref:`Pins_and_GPIO`) +but if they are not configured to their default pins then they need to +pass through an extra layer of GPIO multiplexing, which can impact +their reliability at high speeds. Hardware SPI channels are limited +to 40MHz when used on pins other than the default ones listed below. ===== =========== ============ \ HSPI (id=1) VSPI (id=2) From ab93321e3160f2b688e8a60ad224debbdbd68c66 Mon Sep 17 00:00:00 2001 From: Henrik Vendelbo Date: Sun, 12 May 2019 11:22:48 +0200 Subject: [PATCH 0339/1788] py/persistentcode: Change "len" type to size_t for mp_obj_str_get_data. --- py/persistentcode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/persistentcode.c b/py/persistentcode.c index c8d3bb8a66..cc6e161f42 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -560,7 +560,7 @@ STATIC void save_obj(mp_print_t *print, mp_obj_t o) { } else { obj_type = 'b'; } - mp_uint_t len; + size_t len; const char *str = mp_obj_str_get_data(o, &len); mp_print_bytes(print, &obj_type, 1); mp_print_uint(print, len); From 8586afa6f592cd8b886d5df04f587d1a92ad1bfc Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 13 May 2019 12:39:03 +1000 Subject: [PATCH 0340/1788] esp32/modnetwork: Change type to size_t for uses of mp_obj_str_get_data. --- ports/esp32/modnetwork.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index 5d3c19b802..b93715b6e6 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -312,7 +312,7 @@ STATIC mp_obj_t esp_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k // configure any parameters that are given if (n_args > 1) { - mp_uint_t len; + size_t len; const char *p; if (args[ARG_ssid].u_obj != mp_const_none) { p = mp_obj_str_get_data(args[ARG_ssid].u_obj, &len); @@ -553,7 +553,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 = WIFI_IF_AP; - mp_uint_t len; + size_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); @@ -572,7 +572,7 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs } case QS(MP_QSTR_password): { req_if = WIFI_IF_AP; - mp_uint_t len; + size_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); From 7e21cf723a42321e759fdf77b24c04ce0a6afb29 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 13 May 2019 12:39:56 +1000 Subject: [PATCH 0341/1788] nrf: Change types to size_t for all uses of mp_obj_str_get_data. --- ports/nrf/boards/microbit/modules/microbitdisplay.c | 6 +++--- ports/nrf/boards/microbit/modules/microbitimage.c | 6 +++--- ports/nrf/modules/music/modmusic.c | 2 +- ports/nrf/modules/uos/microbitfs.c | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ports/nrf/boards/microbit/modules/microbitdisplay.c b/ports/nrf/boards/microbit/modules/microbitdisplay.c index 11ec004d07..936a3ec977 100644 --- a/ports/nrf/boards/microbit/modules/microbitdisplay.c +++ b/ports/nrf/boards/microbit/modules/microbitdisplay.c @@ -90,7 +90,7 @@ mp_obj_t microbit_display_show_func(mp_uint_t n_args, const mp_obj_t *pos_args, if (mp_obj_is_str(image)) { // arg is a string object - mp_uint_t len; + size_t len; const char *str = mp_obj_str_get_data(image, &len); if (len == 0) { // There are no chars; do nothing. @@ -297,7 +297,7 @@ static void draw_object(mp_obj_t obj) { } else if (mp_obj_get_type(obj) == µbit_image_type) { microbit_display_show(display, (microbit_image_obj_t *)obj); } else if (mp_obj_is_str(obj)) { - mp_uint_t len; + size_t len; const char *str = mp_obj_str_get_data(obj, &len); if (len == 1) { microbit_display_show(display, microbit_image_for_char(str[0])); @@ -415,7 +415,7 @@ mp_obj_t microbit_display_scroll_func(mp_uint_t n_args, const mp_obj_t *pos_args microbit_display_obj_t *self = (microbit_display_obj_t*)pos_args[0]; mp_arg_val_t args[MP_ARRAY_SIZE(scroll_allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(scroll_allowed_args), scroll_allowed_args, args); - mp_uint_t len; + size_t len; const char* str = mp_obj_str_get_data(args[0].u_obj, &len); mp_obj_t iterable = scrolling_string_image_iterable(str, len, args[0].u_obj, args[3].u_bool /*monospace?*/, args[4].u_bool /*loop*/); microbit_display_animate(self, iterable, args[1].u_int /*delay*/, false/*clear*/, args[2].u_bool/*wait?*/); diff --git a/ports/nrf/boards/microbit/modules/microbitimage.c b/ports/nrf/boards/microbit/modules/microbitimage.c index aa519b4a2a..9cba30f878 100644 --- a/ports/nrf/boards/microbit/modules/microbitimage.c +++ b/ports/nrf/boards/microbit/modules/microbitimage.c @@ -216,7 +216,7 @@ STATIC mp_obj_t microbit_image_make_new(const mp_obj_type_t *type_in, mp_uint_t case 1: { if (mp_obj_is_str(args[0])) { // arg is a string object - mp_uint_t len; + size_t len; const char *str = mp_obj_str_get_data(args[0], &len); // make image from string if (len == 1) { @@ -880,7 +880,7 @@ static mp_obj_t string_image_facade_subscr(mp_obj_t self_in, mp_obj_t index_in, if (value == MP_OBJ_SENTINEL) { // Fill in image string_image_facade_t *self = (string_image_facade_t *)self_in; - mp_uint_t len; + size_t len; const char *text = mp_obj_str_get_data(self->string, &len); mp_uint_t index = mp_get_index(self->base.type, len, index_in, false); microbit_image_set_from_char(self->image, text[index]); @@ -935,7 +935,7 @@ mp_obj_t microbit_string_facade(mp_obj_t string) { static mp_obj_t microbit_facade_iter_next(mp_obj_t iter_in) { facade_iterator_t *iter = (facade_iterator_t *)iter_in; - mp_uint_t len; + size_t len; const char *text = mp_obj_str_get_data(iter->string, &len); if (iter->index >= len) { return MP_OBJ_STOP_ITERATION; diff --git a/ports/nrf/modules/music/modmusic.c b/ports/nrf/modules/music/modmusic.c index 84a014c12d..3730b3a72c 100644 --- a/ports/nrf/modules/music/modmusic.c +++ b/ports/nrf/modules/music/modmusic.c @@ -126,7 +126,7 @@ void microbit_music_tick(void) { music_data->async_state = ASYNC_MUSIC_STATE_NEXT_NOTE; } else { // a note - mp_uint_t note_len; + size_t note_len; const char *note_str = mp_obj_str_get_data(note, ¬e_len); uint32_t delay_on = start_note(note_str, note_len, music_data->async_pin); music_data->async_wait_ticks = ticks + delay_on; diff --git a/ports/nrf/modules/uos/microbitfs.c b/ports/nrf/modules/uos/microbitfs.c index d4c5a119a1..2ddf653cd7 100644 --- a/ports/nrf/modules/uos/microbitfs.c +++ b/ports/nrf/modules/uos/microbitfs.c @@ -377,7 +377,7 @@ STATIC file_descriptor_obj *microbit_file_descriptor_new(uint8_t start_chunk, bo } STATIC mp_obj_t microbit_remove(mp_obj_t filename) { - mp_uint_t name_len; + size_t name_len; const char *name = mp_obj_str_get_data(filename, &name_len); mp_uint_t index = microbit_find_file(name, name_len); if (index == 255) { @@ -487,7 +487,7 @@ STATIC mp_obj_t microbit_file_list(void) { } STATIC mp_obj_t microbit_file_size(mp_obj_t filename) { - mp_uint_t name_len; + size_t name_len; const char *name = mp_obj_str_get_data(filename, &name_len); uint8_t chunk = microbit_find_file(name, name_len); if (chunk == 255) { @@ -659,7 +659,7 @@ mp_obj_t uos_mbfs_open(size_t n_args, const mp_obj_t *args) { int read = -1; int text = -1; if (n_args == 2) { - mp_uint_t len; + size_t len; const char *mode = mp_obj_str_get_data(args[1], &len); for (mp_uint_t i = 0; i < len; i++) { if (mode[i] == 'r' || mode[i] == 'w') { @@ -677,7 +677,7 @@ mp_obj_t uos_mbfs_open(size_t n_args, const mp_obj_t *args) { } } } - mp_uint_t name_len; + size_t name_len; const char *filename = mp_obj_str_get_data(args[0], &name_len); file_descriptor_obj *res = microbit_file_open(filename, name_len, read == 0, text == 0); if (res == NULL) { From 7359a9e2f205008e05e99032a0b94fdc20281e0f Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Mon, 13 May 2019 00:42:17 +0200 Subject: [PATCH 0342/1788] stm32/dma: Initialise all members of DMA structs for H7 MCUs. --- ports/stm32/dma.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c index a4ddcc42f9..0ccc66a2cf 100644 --- a/ports/stm32/dma.c +++ b/ports/stm32/dma.c @@ -85,7 +85,7 @@ struct _dma_descr_t { static const DMA_InitTypeDef dma_init_struct_spi_i2c = { #if defined(STM32F4) || defined(STM32F7) .Channel = 0, - #elif defined(STM32L4) + #elif defined(STM32H7) || defined(STM32L4) .Request = 0, #endif .Direction = 0, @@ -95,7 +95,7 @@ static const DMA_InitTypeDef dma_init_struct_spi_i2c = { .MemDataAlignment = DMA_MDATAALIGN_BYTE, .Mode = DMA_NORMAL, .Priority = DMA_PRIORITY_LOW, - #if defined(STM32F4) || defined(STM32F7) + #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) .FIFOMode = DMA_FIFOMODE_DISABLE, .FIFOThreshold = DMA_FIFO_THRESHOLD_FULL, .MemBurst = DMA_MBURST_INC4, @@ -136,7 +136,7 @@ static const DMA_InitTypeDef dma_init_struct_sdio = { static const DMA_InitTypeDef dma_init_struct_dac = { #if defined(STM32F4) || defined(STM32F7) .Channel = 0, - #elif defined(STM32L4) + #elif defined(STM32H7) || defined(STM32L4) .Request = 0, #endif .Direction = 0, @@ -146,7 +146,7 @@ static const DMA_InitTypeDef dma_init_struct_dac = { .MemDataAlignment = DMA_MDATAALIGN_BYTE, .Mode = DMA_NORMAL, .Priority = DMA_PRIORITY_HIGH, - #if defined(STM32F4) || defined(STM32F7) + #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) .FIFOMode = DMA_FIFOMODE_DISABLE, .FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL, .MemBurst = DMA_MBURST_SINGLE, From 7c5cf59f8b9a5e62534e78558eb654bc664a3a6f Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 14 May 2019 14:45:54 +1000 Subject: [PATCH 0343/1788] extmod/modujson: Handle parsing of floats with + in the exponent. Fixes issue #4780. --- extmod/modujson.c | 2 +- tests/extmod/ujson_loads_float.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/extmod/modujson.c b/extmod/modujson.c index 830b588fdc..f5c6428ef9 100644 --- a/extmod/modujson.c +++ b/extmod/modujson.c @@ -185,7 +185,7 @@ STATIC mp_obj_t mod_ujson_load(mp_obj_t stream_obj) { cur = S_CUR(s); if (cur == '.' || cur == 'E' || cur == 'e') { flt = true; - } else if (cur == '-' || unichar_isdigit(cur)) { + } else if (cur == '+' || cur == '-' || unichar_isdigit(cur)) { // pass } else { break; diff --git a/tests/extmod/ujson_loads_float.py b/tests/extmod/ujson_loads_float.py index f1b8cc364c..086853a2d4 100644 --- a/tests/extmod/ujson_loads_float.py +++ b/tests/extmod/ujson_loads_float.py @@ -14,4 +14,5 @@ my_print(json.loads('1.2')) my_print(json.loads('1e2')) my_print(json.loads('-2.3')) my_print(json.loads('-2e3')) +my_print(json.loads('-2e+3')) my_print(json.loads('-2e-3')) From 38cb95710a97fe65e901043ff435d4e3a90530e4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 14 May 2019 14:49:18 +1000 Subject: [PATCH 0344/1788] tests/pyb: Update UART expected output now that default timeout is 0. Follow up to commit 34942d0a72980173eca51b201f271f67bcae46b5 --- tests/pyb/uart.py.exp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/pyb/uart.py.exp b/tests/pyb/uart.py.exp index f3e6bbe282..d302468ed2 100644 --- a/tests/pyb/uart.py.exp +++ b/tests/pyb/uart.py.exp @@ -12,8 +12,8 @@ UART XB UART YA UART YB ValueError Z -UART(1, baudrate=9600, bits=8, parity=None, stop=1, flow=0, timeout=1000, timeout_char=3, rxbuf=64) -UART(1, baudrate=2400, bits=8, parity=None, stop=1, flow=0, timeout=1000, timeout_char=7, rxbuf=64) +UART(1, baudrate=9600, bits=8, parity=None, stop=1, flow=0, timeout=0, timeout_char=3, rxbuf=64) +UART(1, baudrate=2400, bits=8, parity=None, stop=1, flow=0, timeout=0, timeout_char=7, rxbuf=64) 0 3 4 @@ -22,7 +22,7 @@ None 4 None None -UART(1, baudrate=9600, bits=8, parity=None, stop=1, flow=0, timeout=1000, timeout_char=3, rxbuf=8) -UART(1, baudrate=9600, bits=8, parity=None, stop=1, flow=0, timeout=1000, timeout_char=3, rxbuf=0) -UART(1, baudrate=9600, bits=8, parity=None, stop=1, flow=0, timeout=1000, timeout_char=3, rxbuf=4) -UART(1, baudrate=9600, bits=8, parity=None, stop=1, flow=0, timeout=1000, timeout_char=3, rxbuf=0) +UART(1, baudrate=9600, bits=8, parity=None, stop=1, flow=0, timeout=0, timeout_char=3, rxbuf=8) +UART(1, baudrate=9600, bits=8, parity=None, stop=1, flow=0, timeout=0, timeout_char=3, rxbuf=0) +UART(1, baudrate=9600, bits=8, parity=None, stop=1, flow=0, timeout=0, timeout_char=3, rxbuf=4) +UART(1, baudrate=9600, bits=8, parity=None, stop=1, flow=0, timeout=0, timeout_char=3, rxbuf=0) From 90fae9172a67f44e1fac967f628f26ddf90da963 Mon Sep 17 00:00:00 2001 From: stijn Date: Wed, 8 May 2019 16:16:17 +0200 Subject: [PATCH 0345/1788] py/objarray: Add support for memoryview.itemsize attribute. This allows figuring out the number of bytes in the memoryview object as len(memview) * memview.itemsize. The feature is enabled via MICROPY_PY_BUILTINS_MEMORYVIEW_ITEMSIZE and is disabled by default. --- ports/unix/mpconfigport_coverage.h | 1 + py/mpconfig.h | 5 +++++ py/objarray.c | 16 ++++++++++++++++ tests/basics/memoryview_itemsize.py | 9 +++++++++ 4 files changed, 31 insertions(+) create mode 100644 tests/basics/memoryview_itemsize.py diff --git a/ports/unix/mpconfigport_coverage.h b/ports/unix/mpconfigport_coverage.h index f3fbee6bfa..b2f1d6e88e 100644 --- a/ports/unix/mpconfigport_coverage.h +++ b/ports/unix/mpconfigport_coverage.h @@ -40,6 +40,7 @@ #define MICROPY_MODULE_GETATTR (1) #define MICROPY_PY_DELATTR_SETATTR (1) #define MICROPY_PY_REVERSE_SPECIAL_METHODS (1) +#define MICROPY_PY_BUILTINS_MEMORYVIEW_ITEMSIZE (1) #define MICROPY_PY_BUILTINS_NEXT2 (1) #define MICROPY_PY_BUILTINS_RANGE_BINOP (1) #define MICROPY_PY_BUILTINS_HELP (1) diff --git a/py/mpconfig.h b/py/mpconfig.h index 38b36a4b18..2d857d8f6d 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -856,6 +856,11 @@ typedef double mp_float_t; #define MICROPY_PY_BUILTINS_MEMORYVIEW (0) #endif +// Whether to support memoryview.itemsize attribute +#ifndef MICROPY_PY_BUILTINS_MEMORYVIEW_ITEMSIZE +#define MICROPY_PY_BUILTINS_MEMORYVIEW_ITEMSIZE (0) +#endif + // Whether to support set object #ifndef MICROPY_PY_BUILTINS_SET #define MICROPY_PY_BUILTINS_SET (1) diff --git a/py/objarray.c b/py/objarray.c index 02f6dff528..89d2f21806 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -231,6 +231,19 @@ STATIC mp_obj_t memoryview_make_new(const mp_obj_type_t *type_in, size_t n_args, return MP_OBJ_FROM_PTR(self); } + +#if MICROPY_PY_BUILTINS_MEMORYVIEW_ITEMSIZE +STATIC void memoryview_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + if (dest[0] != MP_OBJ_NULL) { + return; + } + if (attr == MP_QSTR_itemsize) { + mp_obj_array_t *self = MP_OBJ_TO_PTR(self_in); + dest[0] = MP_OBJ_NEW_SMALL_INT(mp_binary_get_size('@', self->typecode & TYPECODE_MASK, NULL)); + } +} +#endif + #endif STATIC mp_obj_t array_unary_op(mp_unary_op_t op, mp_obj_t o_in) { @@ -560,6 +573,9 @@ const mp_obj_type_t mp_type_memoryview = { .getiter = array_iterator_new, .unary_op = array_unary_op, .binary_op = array_binary_op, + #if MICROPY_PY_BUILTINS_MEMORYVIEW_ITEMSIZE + .attr = memoryview_attr, + #endif .subscr = array_subscr, .buffer_p = { .get_buffer = array_get_buffer }, }; diff --git a/tests/basics/memoryview_itemsize.py b/tests/basics/memoryview_itemsize.py new file mode 100644 index 0000000000..108c69cfdc --- /dev/null +++ b/tests/basics/memoryview_itemsize.py @@ -0,0 +1,9 @@ +try: + memoryview(b'a').itemsize + from array import array +except: + print("SKIP") + raise SystemExit + +for code in ['b', 'h', 'i', 'l', 'q', 'f', 'd']: + print(memoryview(array(code)).itemsize) From a474ddf959fab641ab65631a8e140cf5bbda2541 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 14 May 2019 17:22:49 +1000 Subject: [PATCH 0346/1788] tests/basics: Add coverage tests for memoryview attributes. --- tests/basics/memoryview1.py | 6 ++++++ tests/basics/memoryview_itemsize.py | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/tests/basics/memoryview1.py b/tests/basics/memoryview1.py index c4cc6ffab7..a0ac9e3449 100644 --- a/tests/basics/memoryview1.py +++ b/tests/basics/memoryview1.py @@ -94,3 +94,9 @@ try: memoryview(array.array('i'))[0:2] = b'1234' except ValueError: print('ValueError') + +# invalid attribute +try: + memoryview(b'a').noexist +except AttributeError: + print('AttributeError') diff --git a/tests/basics/memoryview_itemsize.py b/tests/basics/memoryview_itemsize.py index 108c69cfdc..60cb823087 100644 --- a/tests/basics/memoryview_itemsize.py +++ b/tests/basics/memoryview_itemsize.py @@ -7,3 +7,9 @@ except: for code in ['b', 'h', 'i', 'l', 'q', 'f', 'd']: print(memoryview(array(code)).itemsize) + +# shouldn't be able to store to the itemsize attribute +try: + memoryview(b'a').itemsize = 1 +except AttributeError: + print('AttributeError') From 993ca572ca122811e93167617625afd0b3a5d751 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 15 May 2019 15:46:16 +1000 Subject: [PATCH 0347/1788] tools/upip.py: Add support for multiple index URLs with custom default. The user can now select their own package index by either passing the "-i" command line option, or setting the upip.index_urls variable (before doing an install). The https://micropython.org/pi package index hosts packages from micropython-lib and will be searched first when installing a package. If a package is not found here then it will fallback to PyPI. --- tools/upip.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/tools/upip.py b/tools/upip.py index 7ecf61e54b..e3b8885169 100644 --- a/tools/upip.py +++ b/tools/upip.py @@ -16,6 +16,7 @@ gc.collect() debug = False +index_urls = ["https://micropython.org/pi", "https://pypi.org/pypi"] install_path = None cleanup_files = [] gzdict_sz = 16 + 15 @@ -156,11 +157,16 @@ def url_open(url): def get_pkg_metadata(name): - f = url_open("https://pypi.org/pypi/%s/json" % name) - try: - return json.load(f) - finally: - f.close() + for url in index_urls: + try: + f = url_open("%s/%s/json" % (url, name)) + except NotFoundError: + continue + try: + return json.load(f) + finally: + f.close() + raise NotFoundError("Package not found") def fatal(msg, exc=None): @@ -261,6 +267,7 @@ for installation, upip does not support arbitrary code in setup.py. def main(): global debug + global index_urls global install_path install_path = None @@ -294,6 +301,9 @@ def main(): if l[0] == "#": continue to_install.append(l.rstrip()) + elif opt == "-i": + index_urls = [sys.argv[i]] + i += 1 elif opt == "--debug": debug = True else: From 123c065131e4933a237f17f180f1a01cbd07ee1e Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Mon, 13 May 2019 19:32:45 +0200 Subject: [PATCH 0348/1788] stm32/dma: Always reset and configure the H7 DMA peripheral. This is required for the H7 DMA to work. --- 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 0ccc66a2cf..a1dd40c352 100644 --- a/ports/stm32/dma.c +++ b/ports/stm32/dma.c @@ -626,8 +626,8 @@ void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint32_t dir dma_enable_clock(dma_id); - #if defined(STM32L4) - // Always reset and configure the L4 DMA peripheral + #if defined(STM32H7) || defined(STM32L4) + // Always reset and configure the H7 and 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); From 07af74daef4398540fa623244b4802c22cee3a12 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Mon, 13 May 2019 19:33:22 +0200 Subject: [PATCH 0349/1788] stm32/spi: Enable SPI IRQs and add IRQHandlers for H7 MCUs. The H7 HAL uses SPI IRQs when the SPI is running in DMA mode. --- ports/stm32/irq.h | 2 ++ ports/stm32/spi.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/ports/stm32/irq.h b/ports/stm32/irq.h index 9919013f89..bfed17ecff 100644 --- a/ports/stm32/irq.h +++ b/ports/stm32/irq.h @@ -144,6 +144,8 @@ MP_DECLARE_CONST_FUN_OBJ_0(pyb_irq_stats_obj); #define IRQ_PRI_CAN NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 7, 0) +#define IRQ_PRI_SPI NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 8, 0) + // Interrupt priority for non-special timers. #define IRQ_PRI_TIMX NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 13, 0) diff --git a/ports/stm32/spi.c b/ports/stm32/spi.c index b7298b4aaa..545cb3365e 100644 --- a/ports/stm32/spi.c +++ b/ports/stm32/spi.c @@ -97,6 +97,28 @@ const spi_t spi_obj[6] = { #endif }; +#if defined(STM32H7) +// STM32H7 HAL requires SPI IRQs to be enabled and handled. +#if defined(MICROPY_HW_SPI1_SCK) +void SPI1_IRQHandler(void) { IRQ_ENTER(SPI1_IRQn); HAL_SPI_IRQHandler(&SPIHandle1); IRQ_EXIT(SPI1_IRQn); } +#endif +#if defined(MICROPY_HW_SPI2_SCK) +void SPI2_IRQHandler(void) { IRQ_ENTER(SPI2_IRQn); HAL_SPI_IRQHandler(&SPIHandle2); IRQ_EXIT(SPI2_IRQn); } +#endif +#if defined(MICROPY_HW_SPI3_SCK) +void SPI3_IRQHandler(void) { IRQ_ENTER(SPI3_IRQn); HAL_SPI_IRQHandler(&SPIHandle3); IRQ_EXIT(SPI3_IRQn); } +#endif +#if defined(MICROPY_HW_SPI4_SCK) +void SPI4_IRQHandler(void) { IRQ_ENTER(SPI4_IRQn); HAL_SPI_IRQHandler(&SPIHandle4); IRQ_EXIT(SPI4_IRQn); } +#endif +#if defined(MICROPY_HW_SPI5_SCK) +void SPI5_IRQHandler(void) { IRQ_ENTER(SPI5_IRQn); HAL_SPI_IRQHandler(&SPIHandle5); IRQ_EXIT(SPI5_IRQn); } +#endif +#if defined(MICROPY_HW_SPI6_SCK) +void SPI6_IRQHandler(void) { IRQ_ENTER(SPI6_IRQn); HAL_SPI_IRQHandler(&SPIHandle6); IRQ_EXIT(SPI6_IRQn); } +#endif +#endif + void spi_init0(void) { // Initialise the SPI handles. // The structs live on the BSS so all other fields will be zero after a reset. @@ -231,11 +253,13 @@ void spi_set_params(const spi_t *spi_obj, uint32_t prescale, int32_t baudrate, // TODO allow to take a list of pins to use void spi_init(const spi_t *self, bool enable_nss_pin) { SPI_HandleTypeDef *spi = self->spi; + uint32_t irqn = 0; const pin_obj_t *pins[4] = { NULL, NULL, NULL, NULL }; if (0) { #if defined(MICROPY_HW_SPI1_SCK) } else if (spi->Instance == SPI1) { + irqn = SPI1_IRQn; #if defined(MICROPY_HW_SPI1_NSS) pins[0] = MICROPY_HW_SPI1_NSS; #endif @@ -249,6 +273,7 @@ void spi_init(const spi_t *self, bool enable_nss_pin) { #endif #if defined(MICROPY_HW_SPI2_SCK) } else if (spi->Instance == SPI2) { + irqn = SPI2_IRQn; #if defined(MICROPY_HW_SPI2_NSS) pins[0] = MICROPY_HW_SPI2_NSS; #endif @@ -262,6 +287,7 @@ void spi_init(const spi_t *self, bool enable_nss_pin) { #endif #if defined(MICROPY_HW_SPI3_SCK) } else if (spi->Instance == SPI3) { + irqn = SPI3_IRQn; #if defined(MICROPY_HW_SPI3_NSS) pins[0] = MICROPY_HW_SPI3_NSS; #endif @@ -275,6 +301,7 @@ void spi_init(const spi_t *self, bool enable_nss_pin) { #endif #if defined(MICROPY_HW_SPI4_SCK) } else if (spi->Instance == SPI4) { + irqn = SPI4_IRQn; #if defined(MICROPY_HW_SPI4_NSS) pins[0] = MICROPY_HW_SPI4_NSS; #endif @@ -288,6 +315,7 @@ void spi_init(const spi_t *self, bool enable_nss_pin) { #endif #if defined(MICROPY_HW_SPI5_SCK) } else if (spi->Instance == SPI5) { + irqn = SPI5_IRQn; #if defined(MICROPY_HW_SPI5_NSS) pins[0] = MICROPY_HW_SPI5_NSS; #endif @@ -301,6 +329,7 @@ void spi_init(const spi_t *self, bool enable_nss_pin) { #endif #if defined(MICROPY_HW_SPI6_SCK) } else if (spi->Instance == SPI6) { + irqn = SPI6_IRQn; #if defined(MICROPY_HW_SPI6_NSS) pins[0] = MICROPY_HW_SPI6_NSS; #endif @@ -341,6 +370,13 @@ void spi_init(const spi_t *self, bool enable_nss_pin) { // an initialisation the next time we use it. dma_invalidate_channel(self->tx_dma_descr); dma_invalidate_channel(self->rx_dma_descr); + + #if defined(STM32H7) + NVIC_SetPriority(irqn, IRQ_PRI_SPI); + HAL_NVIC_EnableIRQ(irqn); + #else + (void)irqn; + #endif } void spi_deinit(const spi_t *spi_obj) { @@ -352,36 +388,42 @@ void spi_deinit(const spi_t *spi_obj) { __HAL_RCC_SPI1_FORCE_RESET(); __HAL_RCC_SPI1_RELEASE_RESET(); __HAL_RCC_SPI1_CLK_DISABLE(); + HAL_NVIC_DisableIRQ(SPI1_IRQn); #endif #if defined(MICROPY_HW_SPI2_SCK) } else if (spi->Instance == SPI2) { __HAL_RCC_SPI2_FORCE_RESET(); __HAL_RCC_SPI2_RELEASE_RESET(); __HAL_RCC_SPI2_CLK_DISABLE(); + HAL_NVIC_DisableIRQ(SPI2_IRQn); #endif #if defined(MICROPY_HW_SPI3_SCK) } else if (spi->Instance == SPI3) { __HAL_RCC_SPI3_FORCE_RESET(); __HAL_RCC_SPI3_RELEASE_RESET(); __HAL_RCC_SPI3_CLK_DISABLE(); + HAL_NVIC_DisableIRQ(SPI3_IRQn); #endif #if defined(MICROPY_HW_SPI4_SCK) } else if (spi->Instance == SPI4) { __HAL_RCC_SPI4_FORCE_RESET(); __HAL_RCC_SPI4_RELEASE_RESET(); __HAL_RCC_SPI4_CLK_DISABLE(); + HAL_NVIC_DisableIRQ(SPI4_IRQn); #endif #if defined(MICROPY_HW_SPI5_SCK) } else if (spi->Instance == SPI5) { __HAL_RCC_SPI5_FORCE_RESET(); __HAL_RCC_SPI5_RELEASE_RESET(); __HAL_RCC_SPI5_CLK_DISABLE(); + HAL_NVIC_DisableIRQ(SPI5_IRQn); #endif #if defined(MICROPY_HW_SPI6_SCK) } else if (spi->Instance == SPI6) { __HAL_RCC_SPI6_FORCE_RESET(); __HAL_RCC_SPI6_RELEASE_RESET(); __HAL_RCC_SPI6_CLK_DISABLE(); + HAL_NVIC_DisableIRQ(SPI6_IRQn); #endif } } From 1646eff8647d6665cb05cf56384299b49fbeb126 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Mon, 13 May 2019 19:44:14 +0200 Subject: [PATCH 0350/1788] stm32/irq: Fix IRQ_ENABLE_STATS stats config to work on all MCUs. Only the M4 and M7 MCUs have an FPU and FPU_IRQn, and FPU_IRQn is not always the last entry/IRQ number. --- ports/stm32/irq.c | 2 +- ports/stm32/irq.h | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ports/stm32/irq.c b/ports/stm32/irq.c index 7298a4b504..0100899733 100644 --- a/ports/stm32/irq.c +++ b/ports/stm32/irq.c @@ -31,7 +31,7 @@ /// \moduleref pyb #if IRQ_ENABLE_STATS -uint32_t irq_stats[FPU_IRQn + 1] = {0}; +uint32_t irq_stats[IRQ_STATS_MAX] = {0}; #endif /// \function wfi() diff --git a/ports/stm32/irq.h b/ports/stm32/irq.h index bfed17ecff..075791357c 100644 --- a/ports/stm32/irq.h +++ b/ports/stm32/irq.h @@ -39,7 +39,12 @@ #define IRQ_ENABLE_STATS (0) #if IRQ_ENABLE_STATS -extern uint32_t irq_stats[FPU_IRQn + 1]; +#if defined(STM32H7) +#define IRQ_STATS_MAX (256) +#else +#define IRQ_STATS_MAX (128) +#endif +extern uint32_t irq_stats[IRQ_STATS_MAX]; #define IRQ_ENTER(irq) ++irq_stats[irq] #define IRQ_EXIT(irq) #else From 746fcea7f88ee0cad6a9c0c98f6d5ba8de5b3fb7 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Tue, 14 May 2019 15:56:40 +0200 Subject: [PATCH 0351/1788] stm32/boards/NUCLEO_H743ZI: Enable SPI3 on this board. --- ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h | 8 ++++---- ports/stm32/boards/NUCLEO_H743ZI/pins.csv | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h index 68dece24ff..8e227f1ba4 100644 --- a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h @@ -43,10 +43,10 @@ void NUCLEO_H743ZI_board_early_init(void); #define MICROPY_HW_I2C2_SDA (pin_F0) // 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) +#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) diff --git a/ports/stm32/boards/NUCLEO_H743ZI/pins.csv b/ports/stm32/boards/NUCLEO_H743ZI/pins.csv index 30910c4dd5..6a0532dbfe 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 +D22,PB5 +D23,PB3 DAC1,PA4 DAC2,PA5 LED1,PB0 From 2630d3e51f3f4ac933e556bb3df2953698ac74fc Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 15 May 2019 17:01:54 +1000 Subject: [PATCH 0352/1788] esp32/machine_uart: Implement UART.deinit() method. --- ports/esp32/machine_uart.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ports/esp32/machine_uart.c b/ports/esp32/machine_uart.c index b3c70de1e7..38cc1a8a9a 100644 --- a/ports/esp32/machine_uart.c +++ b/ports/esp32/machine_uart.c @@ -286,6 +286,13 @@ STATIC mp_obj_t machine_uart_init(size_t n_args, const mp_obj_t *args, mp_map_t } MP_DEFINE_CONST_FUN_OBJ_KW(machine_uart_init_obj, 1, machine_uart_init); +STATIC mp_obj_t machine_uart_deinit(mp_obj_t self_in) { + machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + uart_driver_delete(self->uart_num); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_deinit_obj, machine_uart_deinit); + 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; @@ -327,7 +334,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_sendbreak_obj, machine_uart_sendbr 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_deinit), MP_ROM_PTR(&machine_uart_deinit_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) }, From 0557f0b74b67f91e4ced1c0ffd5d677f1699e64f Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 9 May 2019 00:30:04 +1000 Subject: [PATCH 0353/1788] esp32/network_ppp: Add a timeout for closing PPP connection. This also fixes deleting the PPP task, since eTaskGetState() never returns eDeleted. A limitation with this patch: once the PPP is deactivated (ppp.active(0)) it cannot be used again. A new PPP instance must be created instead. --- ports/esp32/network_ppp.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/ports/esp32/network_ppp.c b/ports/esp32/network_ppp.c index da821478b8..96d9ead305 100644 --- a/ports/esp32/network_ppp.c +++ b/ports/esp32/network_ppp.c @@ -42,14 +42,17 @@ #include "lwip/dns.h" #include "netif/ppp/pppapi.h" +#define PPP_CLOSE_TIMEOUT_MS (4000) + typedef struct _ppp_if_obj_t { mp_obj_base_t base; bool active; bool connected; + volatile bool clean_close; ppp_pcb *pcb; mp_obj_t stream; SemaphoreHandle_t inactiveWaitSem; - TaskHandle_t client_task_handle; + volatile TaskHandle_t client_task_handle; struct netif pppif; } ppp_if_obj_t; @@ -64,7 +67,7 @@ static void ppp_status_cb(ppp_pcb *pcb, int err_code, void *ctx) { self->connected = (pppif->ip_addr.u_addr.ip4.addr != 0); break; case PPPERR_USER: - xSemaphoreGive(self->inactiveWaitSem); + self->clean_close = true; break; case PPPERR_CONNECT: self->connected = false; @@ -83,10 +86,9 @@ STATIC mp_obj_t ppp_make_new(mp_obj_t stream) { self->stream = stream; self->active = false; self->connected = false; - self->inactiveWaitSem = xSemaphoreCreateBinary(); + self->clean_close = false; self->client_task_handle = NULL; - assert(self->inactiveWaitSem != NULL); return MP_OBJ_FROM_PTR(self); } MP_DEFINE_CONST_FUN_OBJ_1(ppp_make_new_obj, ppp_make_new); @@ -108,6 +110,8 @@ static void pppos_client_task(void *self_in) { pppos_input_tcpip(self->pcb, (u8_t*)buf, len); } } + + self->client_task_handle = NULL; vTaskDelete(NULL); } @@ -128,21 +132,24 @@ STATIC mp_obj_t ppp_active(size_t n_args, const mp_obj_t *args) { pppapi_set_default(self->pcb); pppapi_connect(self->pcb, 0); - xTaskCreate(pppos_client_task, "ppp", 2048, self, 1, &self->client_task_handle); + xTaskCreate(pppos_client_task, "ppp", 2048, self, 1, (TaskHandle_t*)&self->client_task_handle); self->active = true; } else { if (!self->active) { return mp_const_false; } - // Wait for PPPERR_USER + // Wait for PPPERR_USER, with timeout pppapi_close(self->pcb, 0); - xSemaphoreTake(self->inactiveWaitSem, portMAX_DELAY); - xSemaphoreGive(self->inactiveWaitSem); + uint32_t t0 = mp_hal_ticks_ms(); + while (!self->clean_close && mp_hal_ticks_ms() - t0 < PPP_CLOSE_TIMEOUT_MS) { + mp_hal_delay_ms(10); + } // Shutdown task xTaskNotifyGive(self->client_task_handle); - while (eTaskGetState(self->client_task_handle) != eDeleted) { + t0 = mp_hal_ticks_ms(); + while (self->client_task_handle != NULL && mp_hal_ticks_ms() - t0 < PPP_CLOSE_TIMEOUT_MS) { mp_hal_delay_ms(10); } @@ -151,6 +158,7 @@ STATIC mp_obj_t ppp_active(size_t n_args, const mp_obj_t *args) { self->pcb = NULL; self->active = false; self->connected = false; + self->clean_close = false; } } return mp_obj_new_bool(self->active); From e1e3704aa1406f9511728f54e62569ea08762d4b Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 15 May 2019 16:35:09 +1000 Subject: [PATCH 0354/1788] stm32/modmachine: Create dedicated asm function to branch to bootloader. Recent gcc versions (at least 9.1) give a warning about using "sp" in the clobber list. Such code is removed by this patch. A dedicated function is instead used to set SP and branch to the bootloader so the code has full control over what happens. Fixes issue #4785. --- ports/stm32/modmachine.c | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index f7b84bae67..7031dea91c 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -247,6 +247,15 @@ STATIC mp_obj_t machine_soft_reset(void) { } MP_DEFINE_CONST_FUN_OBJ_0(machine_soft_reset_obj, machine_soft_reset); +__attribute__((naked)) void branch_to_bootloader(uint32_t r0, uint32_t addr) { + __asm volatile ( + "ldr r2, [r1, #0]\n" // get address of stack pointer + "msr msp, r2\n" // get stack pointer + "ldr r2, [r1, #4]\n" // get address of destination + "bx r2\n" // branch to bootloader + ); +} + // Activate the bootloader without BOOT* pins. STATIC NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args) { #if MICROPY_HW_ENABLE_USB @@ -271,8 +280,7 @@ STATIC NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args) SCB_DisableICache(); SCB_DisableDCache(); #endif - __set_MSP(*(volatile uint32_t*)0x08000000); - ((void (*)(uint32_t)) *((volatile uint32_t*)(0x08000000 + 4)))(0x70ad0000); + branch_to_bootloader(0x70ad0000, 0x08000000); } if (n_args == 1 && mp_obj_is_str_or_bytes(args[0])) { @@ -285,28 +293,16 @@ STATIC NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args) SCB_DisableICache(); SCB_DisableDCache(); #endif - __set_MSP(*(volatile uint32_t*)0x08000000); - ((void (*)(uint32_t)) *((volatile uint32_t*)(0x08000000 + 4)))(0x70ad0080); + branch_to_bootloader(0x70ad0080, 0x08000000); } #endif -#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)); - __ASM volatile ("movw r3, #0x0000\nmovt r3, #0x1FF0\nldr r3, [r3, #0]\nMSR msp, r3\n" : : : "r3", "sp"); - - ((void (*)(void)) *((uint32_t*) 0x1FF00004))(); -#else + #if defined(STM32F7) || defined(STM32H7) + branch_to_bootloader(0, 0x1ff00000); + #else __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. - //__set_MSP(*((uint32_t*) 0x00000000)); - __ASM volatile ("movs r3, #0\nldr r3, [r3, #0]\nMSR msp, r3\n" : : : "r3", "sp"); - - ((void (*)(void)) *((uint32_t*) 0x00000004))(); -#endif + branch_to_bootloader(0, 0x00000000); + #endif while (1); } From 016d9a40fe822a624449ad10486706991a97be29 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 14 May 2019 15:51:57 +0300 Subject: [PATCH 0355/1788] various: Add and update my copyright line based on git history. For modules I initially created or made substantial contributions to. --- extmod/moduselect.c | 1 + ports/esp8266/main.c | 1 + ports/esp8266/moduos.c | 1 + ports/unix/main.c | 1 + ports/unix/modffi.c | 2 +- ports/unix/modmachine.c | 1 + ports/unix/modos.c | 2 +- ports/unix/modtermios.c | 2 +- ports/unix/modtime.c | 1 + ports/unix/modusocket.c | 2 +- py/bc.h | 1 + py/binary.c | 1 + py/binary.h | 1 + py/frozenmod.h | 1 + py/gc.c | 1 + py/objdict.c | 1 + py/objexcept.c | 1 + py/objmodule.c | 1 + py/stream.h | 1 + py/vstr.c | 1 + 20 files changed, 20 insertions(+), 4 deletions(-) diff --git a/extmod/moduselect.c b/extmod/moduselect.c index a65fa6df29..4963b4d5c6 100644 --- a/extmod/moduselect.c +++ b/extmod/moduselect.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2014 Damien P. George + * Copyright (c) 2015-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 diff --git a/ports/esp8266/main.c b/ports/esp8266/main.c index 3465e0446e..8bfb2a0d8f 100644 --- a/ports/esp8266/main.c +++ b/ports/esp8266/main.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2014 Damien P. George + * Copyright (c) 2015-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 diff --git a/ports/esp8266/moduos.c b/ports/esp8266/moduos.c index 7a32c11c07..eab70e0638 100644 --- a/ports/esp8266/moduos.c +++ b/ports/esp8266/moduos.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2015 Josef Gajdusek + * 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 diff --git a/ports/unix/main.c b/ports/unix/main.c index 8d455fa834..cd2dc49a52 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George + * 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 diff --git a/ports/unix/modffi.c b/ports/unix/modffi.c index 0f8551e0a0..75d70e202b 100644 --- a/ports/unix/modffi.c +++ b/ports/unix/modffi.c @@ -4,7 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George - * Copyright (c) 2014 Paul Sokolovsky + * Copyright (c) 2014-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 diff --git a/ports/unix/modmachine.c b/ports/unix/modmachine.c index e2c44f94c2..392ce49258 100644 --- a/ports/unix/modmachine.c +++ b/ports/unix/modmachine.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 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 diff --git a/ports/unix/modos.c b/ports/unix/modos.c index d7ba1cfa1e..41ad3c1474 100644 --- a/ports/unix/modos.c +++ b/ports/unix/modos.c @@ -3,8 +3,8 @@ * * The MIT License (MIT) * + * Copyright (c) 2014-2018 Paul Sokolovsky * Copyright (c) 2013, 2014 Damien P. George - * 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 diff --git a/ports/unix/modtermios.c b/ports/unix/modtermios.c index 7e46ba2f52..d8a742a00e 100644 --- a/ports/unix/modtermios.c +++ b/ports/unix/modtermios.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2014 Paul Sokolovsky + * Copyright (c) 2014-2015 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 diff --git a/ports/unix/modtime.c b/ports/unix/modtime.c index a74b81f374..542c8196be 100644 --- a/ports/unix/modtime.c +++ b/ports/unix/modtime.c @@ -3,6 +3,7 @@ * * The MIT License (MIT) * + * Copyright (c) 2014-2017 Paul Sokolovsky * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/ports/unix/modusocket.c b/ports/unix/modusocket.c index a0f0fc25b1..dd493b5ea6 100644 --- a/ports/unix/modusocket.c +++ b/ports/unix/modusocket.c @@ -3,8 +3,8 @@ * * The MIT License (MIT) * + * Copyright (c) 2014-2018 Paul Sokolovsky * Copyright (c) 2013, 2014 Damien P. George - * 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 diff --git a/py/bc.h b/py/bc.h index 6d86fbdea9..0aadfa8a30 100644 --- a/py/bc.h +++ b/py/bc.h @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George + * 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 diff --git a/py/binary.c b/py/binary.c index bb2b718ced..eecded393d 100644 --- a/py/binary.c +++ b/py/binary.c @@ -3,6 +3,7 @@ * * The MIT License (MIT) * + * Copyright (c) 2014-2017 Paul Sokolovsky * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/py/binary.h b/py/binary.h index 0dae6a29e6..4858c56279 100644 --- a/py/binary.h +++ b/py/binary.h @@ -3,6 +3,7 @@ * * The MIT License (MIT) * + * Copyright (c) 2014 Paul Sokolovsky * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/py/frozenmod.h b/py/frozenmod.h index 8cddef6819..9848a9afb8 100644 --- a/py/frozenmod.h +++ b/py/frozenmod.h @@ -3,6 +3,7 @@ * * The MIT License (MIT) * + * Copyright (c) 2015 Paul Sokolovsky * Copyright (c) 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/py/gc.c b/py/gc.c index 2965059a1a..c763a839ec 100644 --- a/py/gc.c +++ b/py/gc.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George + * 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 diff --git a/py/objdict.c b/py/objdict.c index 015c2c72fe..0a223f7314 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George + * 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 diff --git a/py/objexcept.c b/py/objexcept.c index d9258f9b5f..1fb636f666 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014-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 diff --git a/py/objmodule.c b/py/objmodule.c index 9191c73ec3..4a07913c5e 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014-2015 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 diff --git a/py/stream.h b/py/stream.h index f4c6d30bdc..b6019bb38a 100644 --- a/py/stream.h +++ b/py/stream.h @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014-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 diff --git a/py/vstr.c b/py/vstr.c index 869b278057..6f480186e1 100644 --- a/py/vstr.c +++ b/py/vstr.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George + * 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 From 653e1756c095a761dfea5bd91b94b9b2a150702c Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 17 May 2019 18:02:44 +1000 Subject: [PATCH 0356/1788] various: Update early copyright years to match actual edit history. --- ports/unix/modos.c | 2 +- ports/unix/modtime.c | 2 +- ports/unix/modusocket.c | 2 +- py/binary.c | 2 +- py/binary.h | 2 +- py/frozenmod.h | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ports/unix/modos.c b/ports/unix/modos.c index 41ad3c1474..161918d4dc 100644 --- a/ports/unix/modos.c +++ b/ports/unix/modos.c @@ -4,7 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2014-2018 Paul Sokolovsky - * Copyright (c) 2013, 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 diff --git a/ports/unix/modtime.c b/ports/unix/modtime.c index 542c8196be..0a463014dc 100644 --- a/ports/unix/modtime.c +++ b/ports/unix/modtime.c @@ -4,7 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2014-2017 Paul Sokolovsky - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014-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 diff --git a/ports/unix/modusocket.c b/ports/unix/modusocket.c index dd493b5ea6..8cbd3d077d 100644 --- a/ports/unix/modusocket.c +++ b/ports/unix/modusocket.c @@ -4,7 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2014-2018 Paul Sokolovsky - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014-2019 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 diff --git a/py/binary.c b/py/binary.c index eecded393d..a142776c37 100644 --- a/py/binary.c +++ b/py/binary.c @@ -4,7 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2014-2017 Paul Sokolovsky - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014-2019 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 diff --git a/py/binary.h b/py/binary.h index 4858c56279..71182042f9 100644 --- a/py/binary.h +++ b/py/binary.h @@ -4,7 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2014 Paul Sokolovsky - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014-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 diff --git a/py/frozenmod.h b/py/frozenmod.h index 9848a9afb8..8a477d028e 100644 --- a/py/frozenmod.h +++ b/py/frozenmod.h @@ -4,7 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2015 Paul Sokolovsky - * Copyright (c) 2014 Damien P. George + * 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 From 1f63e9b701aa6398ddb2e0db5e3a0f7f5adb4fcf Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 20 May 2019 14:37:28 +1000 Subject: [PATCH 0357/1788] stm32/adc: Fix VBAT_DIV to be 4 for STM32F411. Fixes issue #4794. --- ports/stm32/adc.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index 4f92324562..46fbbe7364 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -131,14 +131,15 @@ #if defined(STM32F091xC) #define VBAT_DIV (2) #elif defined(STM32F405xx) || defined(STM32F415xx) || \ - defined(STM32F407xx) || defined(STM32F417xx) || \ - defined(STM32F401xC) || defined(STM32F401xE) || \ - defined(STM32F411xE) + defined(STM32F407xx) || defined(STM32F417xx) || \ + defined(STM32F401xC) || defined(STM32F401xE) #define VBAT_DIV (2) -#elif defined(STM32F427xx) || defined(STM32F429xx) || \ +#elif defined(STM32F411xE) || defined(STM32F413xx) || \ + defined(STM32F427xx) || defined(STM32F429xx) || \ defined(STM32F437xx) || defined(STM32F439xx) || \ - defined(STM32F446xx) || defined(STM32F413xx) || \ - defined(STM32F722xx) || defined(STM32F723xx) || \ + defined(STM32F446xx) +#define VBAT_DIV (4) +#elif defined(STM32F722xx) || defined(STM32F723xx) || \ defined(STM32F732xx) || defined(STM32F733xx) || \ defined(STM32F746xx) || defined(STM32F765xx) || \ defined(STM32F767xx) || defined(STM32F769xx) From 8bec0e869d2285275487faebcc21a6278ebd311e Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 4 Aug 2018 16:18:52 +1000 Subject: [PATCH 0358/1788] docs/machine.I2C: Add writevto method to write a vector of byte bufs. This allows to efficiently send to an I2C slave data that is made up of more than one buffer. Instead of needing to allocate temporary memory to combine buffers together this new method allows to pass in a tuple or list of buffers. The name is based on the POSIX function writev() which has similar intentions and signature. The reasons for taking this approach (compared to having an interface with separate start/write/stop methods) are: - It's a backwards compatible extension. - It's convenient for the user. - It's efficient because there is only one Python call, then the C code can do everything in one go. - It's efficient on the I2C bus because the implementation can do everything in one go without pauses between blocks of bytes. - It should be possible to implement this extension in all ports, for hardware and software I2C. Further discussion is found in issue #3482, PR #4020 and PR #4763. --- docs/library/machine.I2C.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/library/machine.I2C.rst b/docs/library/machine.I2C.rst index 71ca9b0d3b..f589124378 100644 --- a/docs/library/machine.I2C.rst +++ b/docs/library/machine.I2C.rst @@ -131,6 +131,20 @@ operations that target a given slave device. generated at the end of the transfer, even if a NACK is received. The function returns the number of ACKs that were received. +.. method:: I2C.writevto(addr, vector, stop=True) + + Write the bytes contained in *vector* to the slave specified by *addr*. + *vector* should be a tuple or list of objects with the buffer protocol. + The *addr* is sent once and then the bytes from each object in *vector* + are written out sequentially. The objects in *vector* may be zero bytes + in length in which case they don't contribute to the output. + + If a NACK is received following the write of a byte from one of the + objects in *vector* then the remaining bytes, and any remaining objects, + are not sent. If *stop* is true then a STOP condition is generated at + the end of the transfer, even if a NACK is received. The function + returns the number of ACKs that were received. + Memory operations ----------------- From 606ea2b10faccd94b2d9724055c0f6020b9c2fc6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 8 May 2019 14:27:18 +1000 Subject: [PATCH 0359/1788] extmod/machine_i2c: Change C-level API to allow split I2C transactions. API is: int transfer( mp_obj_base_t *obj, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags ) --- extmod/machine_i2c.c | 152 +++++++++++++++++++++++++------------------ extmod/machine_i2c.h | 17 +++-- 2 files changed, 102 insertions(+), 67 deletions(-) diff --git a/extmod/machine_i2c.c b/extmod/machine_i2c.c index c1a93ab041..0202fc2bb8 100644 --- a/extmod/machine_i2c.c +++ b/extmod/machine_i2c.c @@ -180,9 +180,9 @@ STATIC int mp_hal_i2c_read_byte(machine_i2c_obj_t *self, uint8_t *val, int nack) } // return value: -// >=0 - number of acks received +// >=0 - success; for read it's 0, for write it's number of acks received // <0 - error, with errno being the negative of the return value -int mp_machine_soft_i2c_writeto(mp_obj_base_t *self_in, uint16_t addr, const uint8_t *src, size_t len, bool stop) { +int mp_machine_soft_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags) { machine_i2c_obj_t *self = (machine_i2c_obj_t*)self_in; // start the I2C transaction @@ -192,7 +192,7 @@ int mp_machine_soft_i2c_writeto(mp_obj_base_t *self_in, uint16_t addr, const uin } // write the slave address - ret = mp_hal_i2c_write_byte(self, addr << 1); + ret = mp_hal_i2c_write_byte(self, (addr << 1) | (flags & MP_MACHINE_I2C_FLAG_READ)); if (ret < 0) { return ret; } else if (ret != 0) { @@ -201,69 +201,102 @@ int mp_machine_soft_i2c_writeto(mp_obj_base_t *self_in, uint16_t addr, const uin return -MP_ENODEV; } - // write the buffer to the I2C memory - int num_acks = 0; - while (len--) { - ret = mp_hal_i2c_write_byte(self, *src++); - if (ret < 0) { - return ret; - } else if (ret != 0) { - // nack received, stop sending - break; + int transfer_ret = 0; + for (; n--; ++bufs) { + size_t len = bufs->len; + uint8_t *buf = bufs->buf; + if (flags & MP_MACHINE_I2C_FLAG_READ) { + // read bytes from the slave into the given buffer(s) + while (len--) { + ret = mp_hal_i2c_read_byte(self, buf++, (n | len) == 0); + if (ret != 0) { + return ret; + } + } + } else { + // write bytes from the given buffer(s) to the slave + while (len--) { + ret = mp_hal_i2c_write_byte(self, *buf++); + if (ret < 0) { + return ret; + } else if (ret != 0) { + // nack received, stop sending + n = 0; + break; + } + ++transfer_ret; // count the number of acks + } } - ++num_acks; } // finish the I2C transaction - if (stop) { + if (flags & MP_MACHINE_I2C_FLAG_STOP) { ret = mp_hal_i2c_stop(self); if (ret != 0) { return ret; } } - return num_acks; + return transfer_ret; } -// return value: -// 0 - success -// <0 - error, with errno being the negative of the return value -int mp_machine_soft_i2c_readfrom(mp_obj_base_t *self_in, uint16_t addr, uint8_t *dest, size_t len, bool stop) { - machine_i2c_obj_t *self = (machine_i2c_obj_t*)self_in; +/******************************************************************************/ +// Generic helper functions - // start the I2C transaction - int ret = mp_hal_i2c_start(self); - if (ret != 0) { - return ret; - } - - // write the slave address - ret = mp_hal_i2c_write_byte(self, (addr << 1) | 1); - if (ret < 0) { - return ret; - } else if (ret != 0) { - // nack received, release the bus cleanly - mp_hal_i2c_stop(self); - return -MP_ENODEV; - } - - // read the bytes from the slave - while (len--) { - ret = mp_hal_i2c_read_byte(self, dest++, len == 0); - if (ret != 0) { - return ret; +// For use by ports that require a single buffer of data for a read/write transfer +int mp_machine_i2c_transfer_adaptor(mp_obj_base_t *self, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags) { + size_t len; + uint8_t *buf; + if (n == 1) { + // Use given single buffer + len = bufs[0].len; + buf = bufs[0].buf; + } else { + // Combine buffers into a single one + len = 0; + for (size_t i = 0; i < n; ++i) { + len += bufs[i].len; + } + buf = m_new(uint8_t, len); + if (!(flags & MP_MACHINE_I2C_FLAG_READ)) { + len = 0; + for (size_t i = 0; i < n; ++i) { + memcpy(buf + len, bufs[i].buf, bufs[i].len); + len += bufs[i].len; + } } } - // finish the I2C transaction - if (stop) { - ret = mp_hal_i2c_stop(self); - if (ret != 0) { - return ret; + mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol; + int ret = i2c_p->transfer_single(self, addr, len, buf, flags); + + if (n > 1) { + if (flags & MP_MACHINE_I2C_FLAG_READ) { + // Copy data from single buffer to individual ones + len = 0; + for (size_t i = 0; i < n; ++i) { + memcpy(bufs[i].buf, buf + len, bufs[i].len); + len += bufs[i].len; + } } + m_del(uint8_t, buf, len); } - return 0; // success + return ret; +} + +STATIC int mp_machine_i2c_readfrom(mp_obj_base_t *self, uint16_t addr, uint8_t *dest, size_t len, bool stop) { + mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol; + mp_machine_i2c_buf_t buf = {.len = len, .buf = dest}; + unsigned int flags = MP_MACHINE_I2C_FLAG_READ | (stop ? MP_MACHINE_I2C_FLAG_STOP : 0); + return i2c_p->transfer(self, addr, 1, &buf, flags); +} + +STATIC int mp_machine_i2c_writeto(mp_obj_base_t *self, uint16_t addr, const uint8_t *src, size_t len, bool stop) { + mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol; + mp_machine_i2c_buf_t buf = {.len = len, .buf = (uint8_t*)src}; + unsigned int flags = stop ? MP_MACHINE_I2C_FLAG_STOP : 0; + return i2c_p->transfer(self, addr, 1, &buf, flags); } /******************************************************************************/ @@ -318,11 +351,10 @@ MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_init_obj, 1, machine_i2c_obj_init); STATIC mp_obj_t machine_i2c_scan(mp_obj_t self_in) { mp_obj_base_t *self = MP_OBJ_TO_PTR(self_in); - mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol; mp_obj_t list = mp_obj_new_list(0, NULL); // 7-bit addresses 0b0000xxx and 0b1111xxx are reserved for (int addr = 0x08; addr < 0x78; ++addr) { - int ret = i2c_p->writeto(self, addr, NULL, 0, true); + int ret = mp_machine_i2c_writeto(self, addr, NULL, 0, true); if (ret == 0) { mp_obj_list_append(list, MP_OBJ_NEW_SMALL_INT(addr)); } @@ -407,12 +439,11 @@ MP_DEFINE_CONST_FUN_OBJ_2(machine_i2c_write_obj, machine_i2c_write); STATIC mp_obj_t machine_i2c_readfrom(size_t n_args, const mp_obj_t *args) { mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]); - mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol; mp_int_t addr = mp_obj_get_int(args[1]); vstr_t vstr; vstr_init_len(&vstr, mp_obj_get_int(args[2])); bool stop = (n_args == 3) ? true : mp_obj_is_true(args[3]); - int ret = i2c_p->readfrom(self, addr, (uint8_t*)vstr.buf, vstr.len, stop); + int ret = mp_machine_i2c_readfrom(self, addr, (uint8_t*)vstr.buf, vstr.len, stop); if (ret < 0) { mp_raise_OSError(-ret); } @@ -422,12 +453,11 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_i2c_readfrom_obj, 3, 4, machine_i2c_ STATIC mp_obj_t machine_i2c_readfrom_into(size_t n_args, const mp_obj_t *args) { mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]); - mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol; mp_int_t addr = mp_obj_get_int(args[1]); mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_WRITE); bool stop = (n_args == 3) ? true : mp_obj_is_true(args[3]); - int ret = i2c_p->readfrom(self, addr, bufinfo.buf, bufinfo.len, stop); + int ret = mp_machine_i2c_readfrom(self, addr, bufinfo.buf, bufinfo.len, stop); if (ret < 0) { mp_raise_OSError(-ret); } @@ -437,12 +467,11 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_i2c_readfrom_into_obj, 3, 4, machine STATIC mp_obj_t machine_i2c_writeto(size_t n_args, const mp_obj_t *args) { mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]); - mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol; mp_int_t addr = mp_obj_get_int(args[1]); mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ); bool stop = (n_args == 3) ? true : mp_obj_is_true(args[3]); - int ret = i2c_p->writeto(self, addr, bufinfo.buf, bufinfo.len, stop); + int ret = mp_machine_i2c_writeto(self, addr, bufinfo.buf, bufinfo.len, stop); if (ret < 0) { mp_raise_OSError(-ret); } @@ -453,19 +482,18 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_i2c_writeto_obj, 3, 4, machin STATIC int read_mem(mp_obj_t self_in, uint16_t addr, uint32_t memaddr, uint8_t addrsize, uint8_t *buf, size_t len) { mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(self_in); - mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol; uint8_t memaddr_buf[4]; size_t memaddr_len = 0; for (int16_t i = addrsize - 8; i >= 0; i -= 8) { memaddr_buf[memaddr_len++] = memaddr >> i; } - int ret = i2c_p->writeto(self, addr, memaddr_buf, memaddr_len, false); + int ret = mp_machine_i2c_writeto(self, addr, memaddr_buf, memaddr_len, false); if (ret != memaddr_len) { // must generate STOP - i2c_p->writeto(self, addr, NULL, 0, true); + mp_machine_i2c_writeto(self, addr, NULL, 0, true); return ret; } - return i2c_p->readfrom(self, addr, buf, len, true); + return mp_machine_i2c_readfrom(self, addr, buf, len, true); } #define MAX_MEMADDR_SIZE (4) @@ -473,7 +501,6 @@ STATIC int read_mem(mp_obj_t self_in, uint16_t addr, uint32_t memaddr, uint8_t a STATIC int write_mem(mp_obj_t self_in, uint16_t addr, uint32_t memaddr, uint8_t addrsize, const uint8_t *buf, size_t len) { mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(self_in); - mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol; // need some memory to create the buffer to send; try to use stack if possible uint8_t buf2_stack[MAX_MEMADDR_SIZE + BUF_STACK_SIZE]; @@ -493,7 +520,7 @@ STATIC int write_mem(mp_obj_t self_in, uint16_t addr, uint32_t memaddr, uint8_t } memcpy(buf2 + memaddr_len, buf, len); - int ret = i2c_p->writeto(self, addr, buf2, memaddr_len + len, true); + int ret = mp_machine_i2c_writeto(self, addr, buf2, memaddr_len + len, true); if (buf2_alloc != 0) { m_del(uint8_t, buf2, buf2_alloc); } @@ -625,8 +652,7 @@ STATIC const mp_machine_i2c_p_t mp_machine_soft_i2c_p = { .stop = (int(*)(mp_obj_base_t*))mp_hal_i2c_stop, .read = mp_machine_soft_i2c_read, .write = mp_machine_soft_i2c_write, - .readfrom = mp_machine_soft_i2c_readfrom, - .writeto = mp_machine_soft_i2c_writeto, + .transfer = mp_machine_soft_i2c_transfer, }; const mp_obj_type_t machine_i2c_type = { diff --git a/extmod/machine_i2c.h b/extmod/machine_i2c.h index f5af6656f5..f951c1f214 100644 --- a/extmod/machine_i2c.h +++ b/extmod/machine_i2c.h @@ -28,15 +28,24 @@ #include "py/obj.h" +#define MP_MACHINE_I2C_FLAG_READ (0x01) // if not set then it's a write +#define MP_MACHINE_I2C_FLAG_STOP (0x02) + +typedef struct _mp_machine_i2c_buf_t { + size_t len; + uint8_t *buf; +} mp_machine_i2c_buf_t; + // I2C protocol // the first 4 methods can be NULL, meaning operation is not supported +// transfer_single only needs to be set if transfer=mp_machine_i2c_transfer_adaptor typedef struct _mp_machine_i2c_p_t { int (*start)(mp_obj_base_t *obj); int (*stop)(mp_obj_base_t *obj); int (*read)(mp_obj_base_t *obj, uint8_t *dest, size_t len, bool nack); int (*write)(mp_obj_base_t *obj, const uint8_t *src, size_t len); - int (*readfrom)(mp_obj_base_t *obj, uint16_t addr, uint8_t *dest, size_t len, bool stop); - int (*writeto)(mp_obj_base_t *obj, uint16_t addr, const uint8_t *src, size_t len, bool stop); + int (*transfer)(mp_obj_base_t *obj, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags); + int (*transfer_single)(mp_obj_base_t *obj, uint16_t addr, size_t len, uint8_t *buf, unsigned int flags); } mp_machine_i2c_p_t; typedef struct _mp_machine_soft_i2c_obj_t { @@ -50,7 +59,7 @@ typedef struct _mp_machine_soft_i2c_obj_t { extern const mp_obj_type_t machine_i2c_type; extern const mp_obj_dict_t mp_machine_soft_i2c_locals_dict; -int mp_machine_soft_i2c_readfrom(mp_obj_base_t *self_in, uint16_t addr, uint8_t *dest, size_t len, bool stop); -int mp_machine_soft_i2c_writeto(mp_obj_base_t *self_in, uint16_t addr, const uint8_t *src, size_t len, bool stop); +int mp_machine_i2c_transfer_adaptor(mp_obj_base_t *self, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags); +int mp_machine_soft_i2c_transfer(mp_obj_base_t *self, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags); #endif // MICROPY_INCLUDED_EXTMOD_MACHINE_I2C_H From 38ac697b451a5111075cdcaf305e1bdf28d268b2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 8 May 2019 14:39:27 +1000 Subject: [PATCH 0360/1788] stm32/machine_i2c: Update to support new C-level I2C API. --- ports/stm32/machine_i2c.c | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/ports/stm32/machine_i2c.c b/ports/stm32/machine_i2c.c index 940e98d715..037401d862 100644 --- a/ports/stm32/machine_i2c.c +++ b/ports/stm32/machine_i2c.c @@ -109,14 +109,34 @@ void machine_hard_i2c_init(machine_hard_i2c_obj_t *self, uint32_t freq, uint32_t 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) { +int machine_hard_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags) { 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); + size_t remain_len = 0; + for (size_t i = 0; i < n; ++i) { + remain_len += bufs[i].len; + } + + int ret = i2c_start_addr(self->i2c, flags & MP_MACHINE_I2C_FLAG_READ, addr, remain_len, flags & MP_MACHINE_I2C_FLAG_STOP); + if (ret < 0) { + return ret; + } + + int num_acks = 0; // only valid for write; for read it'll be 0 + for (; n--; ++bufs) { + remain_len -= bufs->len; + if (flags & MP_MACHINE_I2C_FLAG_READ) { + ret = i2c_read(self->i2c, bufs->buf, bufs->len, remain_len); + } else { + ret = i2c_write(self->i2c, bufs->buf, bufs->len, remain_len); + } + if (ret < 0) { + return ret; + } + num_acks += ret; + } + + return num_acks; } #else @@ -174,8 +194,7 @@ STATIC void machine_hard_i2c_init(machine_hard_i2c_obj_t *self, uint32_t freq, u mp_hal_pin_open_drain(self->sda); } -#define machine_hard_i2c_readfrom mp_machine_soft_i2c_readfrom -#define machine_hard_i2c_writeto mp_machine_soft_i2c_writeto +#define machine_hard_i2c_transfer mp_machine_soft_i2c_transfer #endif @@ -240,8 +259,7 @@ mp_obj_t machine_hard_i2c_make_new(const mp_obj_type_t *type, size_t n_args, siz } STATIC const mp_machine_i2c_p_t machine_hard_i2c_p = { - .readfrom = machine_hard_i2c_readfrom, - .writeto = machine_hard_i2c_writeto, + .transfer = machine_hard_i2c_transfer, }; STATIC const mp_obj_type_t machine_hard_i2c_type = { From bb29bde102e089341db27c431cd10362bb8f825f Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 8 May 2019 18:19:53 +1000 Subject: [PATCH 0361/1788] nrf/machine/i2c: Update to support new C-level I2C API. --- ports/nrf/modules/machine/i2c.c | 39 ++++++++++----------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/ports/nrf/modules/machine/i2c.c b/ports/nrf/modules/machine/i2c.c index 8b79342a30..1d89716121 100644 --- a/ports/nrf/modules/machine/i2c.c +++ b/ports/nrf/modules/machine/i2c.c @@ -99,12 +99,19 @@ mp_obj_t machine_hard_i2c_make_new(const mp_obj_type_t *type, size_t n_args, siz return MP_OBJ_FROM_PTR(self); } -int machine_hard_i2c_readfrom(mp_obj_base_t *self_in, uint16_t addr, uint8_t *dest, size_t len, bool stop) { +int machine_hard_i2c_transfer_single(mp_obj_base_t *self_in, uint16_t addr, size_t len, uint8_t *buf, unsigned int flags) { machine_hard_i2c_obj_t *self = (machine_hard_i2c_obj_t *)self_in; nrfx_twi_enable(&self->p_twi); - nrfx_err_t err_code = nrfx_twi_rx(&self->p_twi, addr, dest, len); + nrfx_err_t err_code; + int transfer_ret = 0; + if (flags & MP_MACHINE_I2C_FLAG_READ) { + err_code = nrfx_twi_rx(&self->p_twi, addr, buf, len); + } else { + err_code = nrfx_twi_tx(&self->p_twi, addr, buf, len, (flags & MP_MACHINE_I2C_FLAG_STOP) == 0); + transfer_ret = len; + } if (err_code != NRFX_SUCCESS) { if (err_code == NRFX_ERROR_DRV_TWI_ERR_ANACK) { @@ -118,34 +125,12 @@ int machine_hard_i2c_readfrom(mp_obj_base_t *self_in, uint16_t addr, uint8_t *de nrfx_twi_disable(&self->p_twi); - return 0; -} - -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; - - nrfx_twi_enable(&self->p_twi); - - nrfx_err_t err_code = nrfx_twi_tx(&self->p_twi, addr, src, len, !stop); - - if (err_code != NRFX_SUCCESS) { - if (err_code == NRFX_ERROR_DRV_TWI_ERR_ANACK) { - return -MP_ENODEV; - } - else if (err_code == NRFX_ERROR_DRV_TWI_ERR_DNACK) { - return -MP_EIO; - } - return -MP_ETIMEDOUT; - } - - nrfx_twi_disable(&self->p_twi); - - return len; + return transfer_ret; } STATIC const mp_machine_i2c_p_t machine_hard_i2c_p = { - .readfrom = machine_hard_i2c_readfrom, - .writeto = machine_hard_i2c_writeto, + .transfer = mp_machine_i2c_transfer_adaptor, + .transfer_single = machine_hard_i2c_transfer_single, }; STATIC const mp_obj_type_t machine_hard_i2c_type = { From 647b27d02891798a0d9a89b465056b1d37786d66 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 8 May 2019 18:20:19 +1000 Subject: [PATCH 0362/1788] zephyr/machine_i2c: Update to support new C-level I2C API. --- ports/zephyr/machine_i2c.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/ports/zephyr/machine_i2c.c b/ports/zephyr/machine_i2c.c index bc9851a00c..0a9e9cfaba 100644 --- a/ports/zephyr/machine_i2c.c +++ b/ports/zephyr/machine_i2c.c @@ -92,7 +92,7 @@ mp_obj_t machine_hard_i2c_make_new(const mp_obj_type_t *type, size_t n_args, siz return MP_OBJ_FROM_PTR(self); } -STATIC int machine_hard_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, uint8_t *buf, size_t len, bool stop, bool read) { +STATIC int machine_hard_i2c_transfer_single(mp_obj_base_t *self_in, uint16_t addr, size_t len, uint8_t *buf, unsigned int flags) { machine_hard_i2c_obj_t *self = (machine_hard_i2c_obj_t *)self_in; struct i2c_msg msg; int ret; @@ -101,7 +101,7 @@ STATIC int machine_hard_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, uint msg.len = len; msg.flags = 0; - if (read) { + if (flags & MP_MACHINE_I2C_FLAG_READ) { msg.flags |= I2C_MSG_READ; } else { msg.flags |= I2C_MSG_WRITE; @@ -111,7 +111,7 @@ STATIC int machine_hard_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, uint msg.flags |= I2C_MSG_RESTART; } - if (stop) { + if (flags & MP_MACHINE_I2C_FLAG_STOP) { msg.flags |= I2C_MSG_STOP; self->restart = false; } else { @@ -122,17 +122,9 @@ STATIC int machine_hard_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, uint return (ret < 0) ? -MP_EIO : len; } -STATIC int machine_hard_i2c_readfrom(mp_obj_base_t *self_in, uint16_t addr, uint8_t *dest, size_t len, bool stop) { - return machine_hard_i2c_transfer(self_in, addr, dest, len, stop, true); -} - -STATIC int machine_hard_i2c_writeto(mp_obj_base_t *self_in, uint16_t addr, const uint8_t *src, size_t len, bool stop) { - return machine_hard_i2c_transfer(self_in, addr, (uint8_t*)src, len, stop, false); -} - STATIC const mp_machine_i2c_p_t machine_hard_i2c_p = { - .readfrom = machine_hard_i2c_readfrom, - .writeto = machine_hard_i2c_writeto, + .transfer = mp_machine_i2c_transfer_adaptor, + .transfer_single = machine_hard_i2c_transfer_single, }; STATIC const mp_obj_type_t machine_hard_i2c_type = { From 8bcb552d9755c63d819dc81b901c5b5dc8e3cc8f Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 8 May 2019 18:25:18 +1000 Subject: [PATCH 0363/1788] extmod/machine_i2c: Remove need for temporary memory in writemem() call. --- extmod/machine_i2c.c | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/extmod/machine_i2c.c b/extmod/machine_i2c.c index 0202fc2bb8..63493141cb 100644 --- a/extmod/machine_i2c.c +++ b/extmod/machine_i2c.c @@ -496,35 +496,25 @@ STATIC int read_mem(mp_obj_t self_in, uint16_t addr, uint32_t memaddr, uint8_t a return mp_machine_i2c_readfrom(self, addr, buf, len, true); } -#define MAX_MEMADDR_SIZE (4) -#define BUF_STACK_SIZE (12) - STATIC int write_mem(mp_obj_t self_in, uint16_t addr, uint32_t memaddr, uint8_t addrsize, const uint8_t *buf, size_t len) { mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(self_in); - // need some memory to create the buffer to send; try to use stack if possible - uint8_t buf2_stack[MAX_MEMADDR_SIZE + BUF_STACK_SIZE]; - uint8_t *buf2; - size_t buf2_alloc = 0; - if (len <= BUF_STACK_SIZE) { - buf2 = buf2_stack; - } else { - buf2_alloc = MAX_MEMADDR_SIZE + len; - buf2 = m_new(uint8_t, buf2_alloc); - } - - // create the buffer to send + // Create buffer with memory address size_t memaddr_len = 0; + uint8_t memaddr_buf[4]; for (int16_t i = addrsize - 8; i >= 0; i -= 8) { - buf2[memaddr_len++] = memaddr >> i; + memaddr_buf[memaddr_len++] = memaddr >> i; } - memcpy(buf2 + memaddr_len, buf, len); - int ret = mp_machine_i2c_writeto(self, addr, buf2, memaddr_len + len, true); - if (buf2_alloc != 0) { - m_del(uint8_t, buf2, buf2_alloc); - } - return ret; + // Create partial write buffers + mp_machine_i2c_buf_t bufs[2] = { + {.len = memaddr_len, .buf = memaddr_buf}, + {.len = len, .buf = (uint8_t*)buf}, + }; + + // Do I2C transfer + mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol; + return i2c_p->transfer(self, addr, 2, bufs, MP_MACHINE_I2C_FLAG_STOP); } STATIC const mp_arg_t machine_i2c_mem_allowed_args[] = { From b10d0664be04d0ff242fc11e7d246b97e3101f1b Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 8 May 2019 18:33:54 +1000 Subject: [PATCH 0364/1788] extmod/machine_i2c: Add i2c.writevto() that can write a vector of bufs. For example: i2c.writevto(addr, (buf1, buf2)). This allows to efficiently (wrt memory) write data composed of separate buffers, such as a command followed by a large amount of data. --- extmod/machine_i2c.c | 47 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/extmod/machine_i2c.c b/extmod/machine_i2c.c index 63493141cb..0687aa9d2d 100644 --- a/extmod/machine_i2c.c +++ b/extmod/machine_i2c.c @@ -480,6 +480,52 @@ STATIC mp_obj_t machine_i2c_writeto(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_i2c_writeto_obj, 3, 4, machine_i2c_writeto); +STATIC mp_obj_t machine_i2c_writevto(size_t n_args, const mp_obj_t *args) { + mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]); + mp_int_t addr = mp_obj_get_int(args[1]); + + // Get the list of data buffer(s) to write + size_t nitems; + const mp_obj_t *items; + mp_obj_get_array(args[2], &nitems, (mp_obj_t**)&items); + + // Get the stop argument + bool stop = (n_args == 3) ? true : mp_obj_is_true(args[3]); + + // Extract all buffer data, skipping zero-length buffers + size_t alloc = nitems == 0 ? 1 : nitems; + size_t nbufs = 0; + mp_machine_i2c_buf_t *bufs = mp_local_alloc(alloc * sizeof(mp_machine_i2c_buf_t)); + for (; nitems--; ++items) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(*items, &bufinfo, MP_BUFFER_READ); + if (bufinfo.len > 0) { + bufs[nbufs].len = bufinfo.len; + bufs[nbufs++].buf = bufinfo.buf; + } + } + + // Make sure there is at least one buffer, empty if needed + if (nbufs == 0) { + bufs[0].len = 0; + bufs[0].buf = NULL; + nbufs = 1; + } + + // Do the I2C transfer + mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol; + int ret = i2c_p->transfer(self, addr, nbufs, bufs, stop ? MP_MACHINE_I2C_FLAG_STOP : 0); + mp_local_free(bufs); + + if (ret < 0) { + mp_raise_OSError(-ret); + } + + // Return number of acks received + return MP_OBJ_NEW_SMALL_INT(ret); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_i2c_writevto_obj, 3, 4, machine_i2c_writevto); + STATIC int read_mem(mp_obj_t self_in, uint16_t addr, uint32_t memaddr, uint8_t addrsize, uint8_t *buf, size_t len) { mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(self_in); uint8_t memaddr_buf[4]; @@ -601,6 +647,7 @@ STATIC const mp_rom_map_elem_t machine_i2c_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_readfrom), MP_ROM_PTR(&machine_i2c_readfrom_obj) }, { MP_ROM_QSTR(MP_QSTR_readfrom_into), MP_ROM_PTR(&machine_i2c_readfrom_into_obj) }, { MP_ROM_QSTR(MP_QSTR_writeto), MP_ROM_PTR(&machine_i2c_writeto_obj) }, + { MP_ROM_QSTR(MP_QSTR_writevto), MP_ROM_PTR(&machine_i2c_writevto_obj) }, // memory operations { MP_ROM_QSTR(MP_QSTR_readfrom_mem), MP_ROM_PTR(&machine_i2c_readfrom_mem_obj) }, From 02afc0d241dbd0efb985ba5a7ded9cea616ffcd7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 8 May 2019 18:46:37 +1000 Subject: [PATCH 0365/1788] drivers/display/ssd1306.py: Change to use new i2c.writevto() method. Fixes issue #3482. --- drivers/display/ssd1306.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/display/ssd1306.py b/drivers/display/ssd1306.py index 178b4911d7..f93a451e85 100644 --- a/drivers/display/ssd1306.py +++ b/drivers/display/ssd1306.py @@ -96,6 +96,7 @@ class SSD1306_I2C(SSD1306): self.i2c = i2c self.addr = addr self.temp = bytearray(2) + self.write_list = [b'\x40', None] # Co=0, D/C#=1 super().__init__(width, height, external_vcc) def write_cmd(self, cmd): @@ -104,12 +105,8 @@ class SSD1306_I2C(SSD1306): self.i2c.writeto(self.addr, self.temp) def write_data(self, buf): - self.temp[0] = self.addr << 1 - self.temp[1] = 0x40 # Co=0, D/C#=1 - self.i2c.start() - self.i2c.write(self.temp) - self.i2c.write(buf) - self.i2c.stop() + self.write_list[1] = buf + self.i2c.writevto(self.addr, self.write_list) class SSD1306_SPI(SSD1306): From 1b3c1f9e6bf4669d2eb9c85c07bc83105aa97556 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 20 May 2019 15:16:14 +1000 Subject: [PATCH 0366/1788] lib/stm32lib: Update library to fix UART9/10 baudrate on F4 MCUs. --- lib/stm32lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/stm32lib b/lib/stm32lib index a5e93de184..615329f1a6 160000 --- a/lib/stm32lib +++ b/lib/stm32lib @@ -1 +1 @@ -Subproject commit a5e93de18479879dd129cf6272cfd75e0c794bd4 +Subproject commit 615329f1a61bd0689bfb095cb3fd74865cca88ff From e5e472198c0cf5cbac8fdf0a9ad5037a9c995f02 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 20 May 2019 15:46:01 +1000 Subject: [PATCH 0367/1788] docs/pyboard/quickref: Refer to new machine.I2C instead of old pyb.I2C. On stm32 boards, machine.I2C is now preferred over pyb.I2C. --- docs/pyboard/quickref.rst | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/docs/pyboard/quickref.rst b/docs/pyboard/quickref.rst index 5d4985f587..b1195ce7c8 100644 --- a/docs/pyboard/quickref.rst +++ b/docs/pyboard/quickref.rst @@ -199,16 +199,25 @@ See :ref:`pyb.SPI `. :: I2C bus ------- -See :ref:`pyb.I2C `. :: +Hardware I2C is available on the X and Y halves of the pyboard via ``I2C('X')`` +and ``I2C('Y')``. Alternatively pass in the integer identifier of the peripheral, +eg ``I2C(1)``. Software I2C is also available by explicitly specifying the +``scl`` and ``sda`` pins instead of the bus name. For more details see +:ref:`machine.I2C `. :: - from pyb import I2C + from machine import I2C - i2c = I2C(1, I2C.MASTER, baudrate=100000) - i2c.scan() # returns list of slave addresses - i2c.send('hello', 0x42) # send 5 bytes to slave with address 0x42 - i2c.recv(5, 0x42) # receive 5 bytes from slave - i2c.mem_read(2, 0x42, 0x10) # read 2 bytes from slave 0x42, slave memory 0x10 - i2c.mem_write('xy', 0x42, 0x10) # write 2 bytes to slave 0x42, slave memory 0x10 + i2c = I2C('X', freq=400000) # create hardware I2c object + i2c = I2C(scl='X1', sda='X2', freq=100000) # create software I2C object + + i2c.scan() # returns list of slave addresses + i2c.writeto(0x42, 'hello') # write 5 bytes to slave with address 0x42 + i2c.readfrom(0x42, 5) # read 5 bytes from slave + + i2c.readfrom_mem(0x42, 0x10, 2) # read 2 bytes from slave 0x42, slave memory 0x10 + i2c.writeto_mem(0x42, 0x10, 'xy') # write 2 bytes to slave 0x42, slave memory 0x10 + +Note: for legacy I2C support see :ref:`pyb.I2C `. CAN bus (controller area network) --------------------------------- From ed2b6ea0a8f4d55a373af032faeca128c0741317 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Thu, 18 Apr 2019 10:31:44 +1000 Subject: [PATCH 0368/1788] stm32/i2c: Make timeout for hardware I2C configurable. Previously the hardware I2C timeout was hard coded to 50ms which isn't guaranteed to be enough depending on the clock stretching specs of the I2C device(s) in use. This patch ensures the hardware I2C implementation honors the existing timeout argument passed to the machine.I2C constructor. The default timeout for software and hardware I2C is now 50ms. --- ports/stm32/accel.c | 4 +++- ports/stm32/i2c.c | 28 ++++++++++++++++++++-------- ports/stm32/i2c.h | 2 +- ports/stm32/machine_i2c.c | 18 ++++++++++-------- ports/stm32/mpconfigboard_common.h | 3 +++ 5 files changed, 37 insertions(+), 18 deletions(-) diff --git a/ports/stm32/accel.c b/ports/stm32/accel.c index 0d7708c093..73ddcf8cfa 100644 --- a/ports/stm32/accel.c +++ b/ports/stm32/accel.c @@ -46,6 +46,8 @@ /// /// Raw values are between -32 and 31. +#define I2C_TIMEOUT_MS (50) + #define MMA_ADDR (76) #define MMA_REG_X (0) #define MMA_REG_Y (1) @@ -62,7 +64,7 @@ void accel_init(void) { STATIC void accel_start(void) { // start the I2C bus in master mode - i2c_init(I2C1, MICROPY_HW_I2C1_SCL, MICROPY_HW_I2C1_SDA, 400000); + i2c_init(I2C1, MICROPY_HW_I2C1_SCL, MICROPY_HW_I2C1_SDA, 400000, I2C_TIMEOUT_MS); // 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.c b/ports/stm32/i2c.c index 109b9418f8..06e26d9124 100644 --- a/ports/stm32/i2c.c +++ b/ports/stm32/i2c.c @@ -30,11 +30,11 @@ #if MICROPY_HW_ENABLE_HW_I2C -#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) { +STATIC uint16_t i2c_timeout_ms[MICROPY_HW_MAX_I2C]; + +int i2c_init(i2c_t *i2c, mp_hal_pin_obj_t scl, mp_hal_pin_obj_t sda, uint32_t freq, uint16_t timeout_ms) { uint32_t i2c_id = ((uint32_t)i2c - I2C1_BASE) / (I2C2_BASE - I2C1_BASE); // Init pins @@ -45,6 +45,9 @@ int i2c_init(i2c_t *i2c, mp_hal_pin_obj_t scl, mp_hal_pin_obj_t sda, uint32_t fr return -MP_EPERM; } + // Save timeout value + i2c_timeout_ms[i2c_id] = timeout_ms; + // Force reset I2C peripheral RCC->APB1RSTR |= RCC_APB1RSTR_I2C1RST << i2c_id; RCC->APB1RSTR &= ~(RCC_APB1RSTR_I2C1RST << i2c_id); @@ -88,9 +91,10 @@ int i2c_init(i2c_t *i2c, mp_hal_pin_obj_t scl, mp_hal_pin_obj_t sda, uint32_t fr } STATIC int i2c_wait_sr1_set(i2c_t *i2c, uint32_t mask) { + uint32_t i2c_id = ((uint32_t)i2c - I2C1_BASE) / (I2C2_BASE - I2C1_BASE); uint32_t t0 = HAL_GetTick(); while (!(i2c->SR1 & mask)) { - if (HAL_GetTick() - t0 >= I2C_POLL_TIMEOUT_MS) { + if (HAL_GetTick() - t0 >= i2c_timeout_ms[i2c_id]) { i2c->CR1 &= ~I2C_CR1_PE; return -MP_ETIMEDOUT; } @@ -99,9 +103,10 @@ STATIC int i2c_wait_sr1_set(i2c_t *i2c, uint32_t mask) { } STATIC int i2c_wait_stop(i2c_t *i2c) { + uint32_t i2c_id = ((uint32_t)i2c - I2C1_BASE) / (I2C2_BASE - I2C1_BASE); uint32_t t0 = HAL_GetTick(); while (i2c->CR1 & I2C_CR1_STOP) { - if (HAL_GetTick() - t0 >= I2C_POLL_TIMEOUT_MS) { + if (HAL_GetTick() - t0 >= i2c_timeout_ms[i2c_id]) { i2c->CR1 &= ~I2C_CR1_PE; return -MP_ETIMEDOUT; } @@ -264,7 +269,9 @@ int i2c_write(i2c_t *i2c, const uint8_t *src, size_t len, size_t next_len) { #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) { +STATIC uint16_t i2c_timeout_ms[MICROPY_HW_MAX_I2C]; + +int i2c_init(i2c_t *i2c, mp_hal_pin_obj_t scl, mp_hal_pin_obj_t sda, uint32_t freq, uint16_t timeout_ms) { uint32_t i2c_id = ((uint32_t)i2c - I2C1_BASE) / (I2C2_BASE - I2C1_BASE); // Init pins @@ -275,6 +282,9 @@ int i2c_init(i2c_t *i2c, mp_hal_pin_obj_t scl, mp_hal_pin_obj_t sda, uint32_t fr return -MP_EPERM; } + // Save timeout value + i2c_timeout_ms[i2c_id] = timeout_ms; + // Enable I2C peripheral clock RCC->APB1ENR |= RCC_APB1ENR_I2C1EN << i2c_id; volatile uint32_t tmp = RCC->APB1ENR; // delay after RCC clock enable @@ -303,9 +313,10 @@ int i2c_init(i2c_t *i2c, mp_hal_pin_obj_t scl, mp_hal_pin_obj_t sda, uint32_t fr } STATIC int i2c_wait_cr2_clear(i2c_t *i2c, uint32_t mask) { + uint32_t i2c_id = ((uint32_t)i2c - I2C1_BASE) / (I2C2_BASE - I2C1_BASE); uint32_t t0 = HAL_GetTick(); while (i2c->CR2 & mask) { - if (HAL_GetTick() - t0 >= I2C_POLL_TIMEOUT_MS) { + if (HAL_GetTick() - t0 >= i2c_timeout_ms[i2c_id]) { i2c->CR1 &= ~I2C_CR1_PE; return -MP_ETIMEDOUT; } @@ -314,9 +325,10 @@ STATIC int i2c_wait_cr2_clear(i2c_t *i2c, uint32_t mask) { } STATIC int i2c_wait_isr_set(i2c_t *i2c, uint32_t mask) { + uint32_t i2c_id = ((uint32_t)i2c - I2C1_BASE) / (I2C2_BASE - I2C1_BASE); uint32_t t0 = HAL_GetTick(); while (!(i2c->ISR & mask)) { - if (HAL_GetTick() - t0 >= I2C_POLL_TIMEOUT_MS) { + if (HAL_GetTick() - t0 >= i2c_timeout_ms[i2c_id]) { i2c->CR1 &= ~I2C_CR1_PE; return -MP_ETIMEDOUT; } diff --git a/ports/stm32/i2c.h b/ports/stm32/i2c.h index 5599f41235..4846f1cf3a 100644 --- a/ports/stm32/i2c.h +++ b/ports/stm32/i2c.h @@ -55,7 +55,7 @@ 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_init(i2c_t *i2c, mp_hal_pin_obj_t scl, mp_hal_pin_obj_t sda, uint32_t freq, uint16_t timeout); 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); diff --git a/ports/stm32/machine_i2c.c b/ports/stm32/machine_i2c.c index 037401d862..5acf9c7d6e 100644 --- a/ports/stm32/machine_i2c.c +++ b/ports/stm32/machine_i2c.c @@ -37,6 +37,8 @@ STATIC const mp_obj_type_t machine_hard_i2c_type; +#define I2C_POLL_DEFAULT_TIMEOUT_US (50000) // 50ms + #if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) typedef struct _machine_hard_i2c_obj_t { @@ -104,9 +106,9 @@ STATIC void machine_hard_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp #endif } -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); +void machine_hard_i2c_init(machine_hard_i2c_obj_t *self, uint32_t freq, uint32_t timeout_us) { + uint32_t timeout_ms = (timeout_us + 999) / 1000; + i2c_init(self->i2c, self->scl, self->sda, freq, timeout_ms); } int machine_hard_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags) { @@ -147,22 +149,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, I2C_POLL_DEFAULT_TIMEOUT_US, 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, I2C_POLL_DEFAULT_TIMEOUT_US, 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, I2C_POLL_DEFAULT_TIMEOUT_US, 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, I2C_POLL_DEFAULT_TIMEOUT_US, MICROPY_HW_I2C4_SCL, MICROPY_HW_I2C4_SDA}, #else {{NULL}, 0, 0, NULL, NULL}, #endif @@ -209,7 +211,7 @@ mp_obj_t machine_hard_i2c_make_new(const mp_obj_type_t *type, size_t n_args, siz { MP_QSTR_scl, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_sda, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} }, - { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = I2C_POLL_DEFAULT_TIMEOUT_US} }, }; 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); diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index 4348f50bdd..f3a3d48e7f 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -138,6 +138,7 @@ #define MP_HAL_UNIQUE_ID_ADDRESS (0x1ffff7ac) #define PYB_EXTI_NUM_VECTORS (23) +#define MICROPY_HW_MAX_I2C (2) #define MICROPY_HW_MAX_TIMER (17) #define MICROPY_HW_MAX_UART (8) @@ -146,6 +147,7 @@ #define MP_HAL_UNIQUE_ID_ADDRESS (0x1fff7a10) #define PYB_EXTI_NUM_VECTORS (23) +#define MICROPY_HW_MAX_I2C (3) #define MICROPY_HW_MAX_TIMER (14) #if defined(UART10) #define MICROPY_HW_MAX_UART (10) @@ -169,6 +171,7 @@ #endif #define PYB_EXTI_NUM_VECTORS (24) +#define MICROPY_HW_MAX_I2C (4) #define MICROPY_HW_MAX_TIMER (17) #define MICROPY_HW_MAX_UART (8) From ddc657658af9ef74a7d891700a6e576c4fb5ff8e Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 21 May 2019 12:38:34 +1000 Subject: [PATCH 0369/1788] stm32/machine_i2c: Simplify ROM initialisation of static HW I2C objects. --- ports/stm32/machine_i2c.c | 36 +++++++++--------------------- ports/stm32/mpconfigboard_common.h | 2 ++ 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/ports/stm32/machine_i2c.c b/ports/stm32/machine_i2c.c index 5acf9c7d6e..2aebb9426e 100644 --- a/ports/stm32/machine_i2c.c +++ b/ports/stm32/machine_i2c.c @@ -48,26 +48,18 @@ typedef struct _machine_hard_i2c_obj_t { mp_hal_pin_obj_t sda; } machine_hard_i2c_obj_t; -STATIC const machine_hard_i2c_obj_t machine_hard_i2c_obj[] = { +STATIC const machine_hard_i2c_obj_t machine_hard_i2c_obj[MICROPY_HW_MAX_I2C] = { #if defined(MICROPY_HW_I2C1_SCL) - {{&machine_hard_i2c_type}, I2C1, MICROPY_HW_I2C1_SCL, MICROPY_HW_I2C1_SDA}, - #else - {{NULL}, NULL, NULL, NULL}, + [0] = {{&machine_hard_i2c_type}, I2C1, MICROPY_HW_I2C1_SCL, MICROPY_HW_I2C1_SDA}, #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}, + [1] = {{&machine_hard_i2c_type}, I2C2, MICROPY_HW_I2C2_SCL, MICROPY_HW_I2C2_SDA}, #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}, + [2] = {{&machine_hard_i2c_type}, I2C3, MICROPY_HW_I2C3_SCL, MICROPY_HW_I2C3_SDA}, #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}, + [3] = {{&machine_hard_i2c_type}, I2C4, MICROPY_HW_I2C4_SCL, MICROPY_HW_I2C4_SDA}, #endif }; @@ -147,26 +139,18 @@ int machine_hard_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t n, m typedef mp_machine_soft_i2c_obj_t machine_hard_i2c_obj_t; -STATIC machine_hard_i2c_obj_t machine_hard_i2c_obj[] = { +STATIC machine_hard_i2c_obj_t machine_hard_i2c_obj[MICROPY_HW_MAX_I2C] = { #if defined(MICROPY_HW_I2C1_SCL) - {{&machine_hard_i2c_type}, 1, I2C_POLL_DEFAULT_TIMEOUT_US, MICROPY_HW_I2C1_SCL, MICROPY_HW_I2C1_SDA}, - #else - {{NULL}, 0, 0, NULL, NULL}, + [0] = {{&machine_hard_i2c_type}, 1, I2C_POLL_DEFAULT_TIMEOUT_US, MICROPY_HW_I2C1_SCL, MICROPY_HW_I2C1_SDA}, #endif #if defined(MICROPY_HW_I2C2_SCL) - {{&machine_hard_i2c_type}, 1, I2C_POLL_DEFAULT_TIMEOUT_US, MICROPY_HW_I2C2_SCL, MICROPY_HW_I2C2_SDA}, - #else - {{NULL}, 0, 0, NULL, NULL}, + [1] = {{&machine_hard_i2c_type}, 1, I2C_POLL_DEFAULT_TIMEOUT_US, MICROPY_HW_I2C2_SCL, MICROPY_HW_I2C2_SDA}, #endif #if defined(MICROPY_HW_I2C3_SCL) - {{&machine_hard_i2c_type}, 1, I2C_POLL_DEFAULT_TIMEOUT_US, MICROPY_HW_I2C3_SCL, MICROPY_HW_I2C3_SDA}, - #else - {{NULL}, 0, 0, NULL, NULL}, + [2] = {{&machine_hard_i2c_type}, 1, I2C_POLL_DEFAULT_TIMEOUT_US, MICROPY_HW_I2C3_SCL, MICROPY_HW_I2C3_SDA}, #endif #if defined(MICROPY_HW_I2C4_SCL) - {{&machine_hard_i2c_type}, 1, I2C_POLL_DEFAULT_TIMEOUT_US, MICROPY_HW_I2C4_SCL, MICROPY_HW_I2C4_SDA}, - #else - {{NULL}, 0, 0, NULL, NULL}, + [3] = {{&machine_hard_i2c_type}, 1, I2C_POLL_DEFAULT_TIMEOUT_US, MICROPY_HW_I2C4_SCL, MICROPY_HW_I2C4_SDA}, #endif }; diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index f3a3d48e7f..b9fa3833ec 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -180,6 +180,7 @@ #define MP_HAL_UNIQUE_ID_ADDRESS (0x1ff1e800) #define PYB_EXTI_NUM_VECTORS (24) +#define MICROPY_HW_MAX_I2C (4) #define MICROPY_HW_MAX_TIMER (17) #define MICROPY_HW_MAX_UART (8) @@ -188,6 +189,7 @@ #define MP_HAL_UNIQUE_ID_ADDRESS (0x1fff7590) #define PYB_EXTI_NUM_VECTORS (23) +#define MICROPY_HW_MAX_I2C (4) #define MICROPY_HW_MAX_TIMER (17) #define MICROPY_HW_MAX_UART (6) From c769da1aaa28fb0eba9fabfba84c39cbc09e23da Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 21 May 2019 13:45:17 +1000 Subject: [PATCH 0370/1788] stm32/i2c: Support setting the I2C TIMINGR value via keyword arg. On MCUs that have an I2C TIMINGR register, this can now be explicitly set via the "timingr" keyword argument to the I2C constructor, for both machine.I2C and pyb.I2C. This allows to configure precise timing values when the defaults are inadequate. --- ports/stm32/machine_i2c.c | 18 +++++++++++++++++- ports/stm32/pyb_i2c.c | 28 ++++++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/ports/stm32/machine_i2c.c b/ports/stm32/machine_i2c.c index 2aebb9426e..b423ec1c8c 100644 --- a/ports/stm32/machine_i2c.c +++ b/ports/stm32/machine_i2c.c @@ -187,15 +187,24 @@ STATIC void machine_hard_i2c_init(machine_hard_i2c_obj_t *self, uint32_t freq, u /******************************************************************************/ /* MicroPython bindings for machine API */ +#if defined(STM32F0) || defined(STM32F7) +#define MACHINE_I2C_TIMINGR (1) +#else +#define MACHINE_I2C_TIMINGR (0) +#endif + mp_obj_t machine_hard_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { // parse args - enum { ARG_id, ARG_scl, ARG_sda, ARG_freq, ARG_timeout }; + enum { ARG_id, ARG_scl, ARG_sda, ARG_freq, ARG_timeout, ARG_timingr }; static const mp_arg_t allowed_args[] = { { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_scl, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_sda, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} }, { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = I2C_POLL_DEFAULT_TIMEOUT_US} }, + #if MACHINE_I2C_TIMINGR + { MP_QSTR_timingr, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + #endif }; 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); @@ -241,6 +250,13 @@ mp_obj_t machine_hard_i2c_make_new(const mp_obj_type_t *type, size_t n_args, siz // initialise the I2C peripheral machine_hard_i2c_init(self, args[ARG_freq].u_int, args[ARG_timeout].u_int); + #if MACHINE_I2C_TIMINGR + // If given, explicitly set the TIMINGR value + if (args[ARG_timingr].u_obj != mp_const_none) { + self->i2c->TIMINGR = mp_obj_get_int_truncated(args[ARG_timingr].u_obj); + } + #endif + return MP_OBJ_FROM_PTR(self); } diff --git a/ports/stm32/pyb_i2c.c b/ports/stm32/pyb_i2c.c index 233cbba512..8b816a25b1 100644 --- a/ports/stm32/pyb_i2c.c +++ b/ports/stm32/pyb_i2c.c @@ -135,6 +135,8 @@ const pyb_i2c_obj_t pyb_i2c_obj[] = { // The STM32F0, F3, F7, H7 and L4 use a TIMINGR register rather than ClockSpeed and // DutyCycle. +#define PYB_I2C_TIMINGR (1) + #if defined(STM32F746xx) // The value 0x40912732 was obtained from the DISCOVERY_I2Cx_TIMING constant @@ -213,6 +215,8 @@ uint32_t pyb_i2c_get_baudrate(I2C_HandleTypeDef *i2c) { #else +#define PYB_I2C_TIMINGR (0) + #define MICROPY_HW_I2C_BAUDRATE_DEFAULT (PYB_I2C_SPEED_FULL) #define MICROPY_HW_I2C_BAUDRATE_MAX (PYB_I2C_SPEED_FULL) @@ -564,7 +568,15 @@ 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, pyb_i2c_get_baudrate(self->i2c)); + mp_printf(print, "I2C(%u, I2C.MASTER, baudrate=%u" + #if PYB_I2C_TIMINGR + ", timingr=0x%08x" + #endif + ")", i2c_num, pyb_i2c_get_baudrate(self->i2c) + #if PYB_I2C_TIMINGR + , self->i2c->Init.Timing + #endif + ); } else { mp_printf(print, "I2C(%u, I2C.SLAVE, addr=0x%02x)", i2c_num, (self->i2c->Instance->OAR1 >> 1) & 0x7f); } @@ -586,6 +598,9 @@ STATIC mp_obj_t pyb_i2c_init_helper(const pyb_i2c_obj_t *self, size_t n_args, co { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = MICROPY_HW_I2C_BAUDRATE_DEFAULT} }, { MP_QSTR_gencall, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, { MP_QSTR_dma, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + #if PYB_I2C_TIMINGR + { MP_QSTR_timingr, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + #endif }; // parse args @@ -602,7 +617,16 @@ STATIC mp_obj_t pyb_i2c_init_helper(const pyb_i2c_obj_t *self, size_t n_args, co init->OwnAddress1 = (args[1].u_int << 1) & 0xfe; } - i2c_set_baudrate(init, MIN(args[2].u_int, MICROPY_HW_I2C_BAUDRATE_MAX)); + // Set baudrate or timing value (if supported) + #if PYB_I2C_TIMINGR + if (args[5].u_obj != mp_const_none) { + init->Timing = mp_obj_get_int_truncated(args[5].u_obj); + } else + #endif + { + i2c_set_baudrate(init, MIN(args[2].u_int, MICROPY_HW_I2C_BAUDRATE_MAX)); + } + init->AddressingMode = I2C_ADDRESSINGMODE_7BIT; init->DualAddressMode = I2C_DUALADDRESS_DISABLED; init->GeneralCallMode = args[3].u_bool ? I2C_GENERALCALL_ENABLED : I2C_GENERALCALL_DISABLED; From fb54736bdb5c01a4051a77c8b048502c6a41e044 Mon Sep 17 00:00:00 2001 From: stijn Date: Mon, 20 May 2019 10:35:31 +0200 Subject: [PATCH 0371/1788] py/objarray: Add decode method to bytearray. Reuse the implementation for bytes since it works the same way regardless of the underlying type. This method gets added for CPython compatibility of bytearray, but to keep the code simple and small array.array now also has a working decode method, which is non-standard but doesn't hurt. --- py/objarray.c | 3 +++ py/objstr.h | 1 + tests/basics/bytearray_decode.py | 6 ++++++ 3 files changed, 10 insertions(+) create mode 100644 tests/basics/bytearray_decode.py diff --git a/py/objarray.c b/py/objarray.c index 89d2f21806..4e58d8e5da 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -530,6 +530,9 @@ STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_ui STATIC const mp_rom_map_elem_t array_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_append), MP_ROM_PTR(&array_append_obj) }, { MP_ROM_QSTR(MP_QSTR_extend), MP_ROM_PTR(&array_extend_obj) }, + #if MICROPY_CPYTHON_COMPAT + { MP_ROM_QSTR(MP_QSTR_decode), MP_ROM_PTR(&bytes_decode_obj) }, + #endif }; STATIC MP_DEFINE_CONST_DICT(array_locals_dict, array_locals_dict_table); diff --git a/py/objstr.h b/py/objstr.h index a10d0df8be..15ed7a2256 100644 --- a/py/objstr.h +++ b/py/objstr.h @@ -102,5 +102,6 @@ MP_DECLARE_CONST_FUN_OBJ_1(str_isalpha_obj); MP_DECLARE_CONST_FUN_OBJ_1(str_isdigit_obj); MP_DECLARE_CONST_FUN_OBJ_1(str_isupper_obj); MP_DECLARE_CONST_FUN_OBJ_1(str_islower_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(bytes_decode_obj); #endif // MICROPY_INCLUDED_PY_OBJSTR_H diff --git a/tests/basics/bytearray_decode.py b/tests/basics/bytearray_decode.py new file mode 100644 index 0000000000..b5e1cb419b --- /dev/null +++ b/tests/basics/bytearray_decode.py @@ -0,0 +1,6 @@ +try: + print(bytearray(b'').decode()) + print(bytearray(b'abc').decode()) +except AttributeError: + print("SKIP") + raise SystemExit From c03f81c633ace3c563f5ace2e906737e98b259d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Rinsoz?= Date: Mon, 20 May 2019 18:47:23 +0200 Subject: [PATCH 0372/1788] py: Update makefiles to use $(CAT) variable instead of hard coded "cat". The variable $(CAT) is initialised with the "cat" value in mkenv.mk like for the other command line tools (rm, echo, cp, mkdir etc). With this, for example, Windows users can specify the path of cat.exe. --- py/mkenv.mk | 1 + py/py.mk | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/py/mkenv.mk b/py/mkenv.mk index 87e92ec6f9..04e7acc1bf 100644 --- a/py/mkenv.mk +++ b/py/mkenv.mk @@ -42,6 +42,7 @@ ECHO = @echo CP = cp MKDIR = mkdir SED = sed +CAT = cat PYTHON = python3 AS = $(CROSS_COMPILE)as diff --git a/py/py.mk b/py/py.mk index 0fbc9f14bb..3d8d849e2b 100644 --- a/py/py.mk +++ b/py/py.mk @@ -338,7 +338,7 @@ MPCONFIGPORT_MK = $(wildcard mpconfigport.mk) # the lines in "" and then unwrap after the preprocessor is finished. $(HEADER_BUILD)/qstrdefs.generated.h: $(PY_QSTR_DEFS) $(QSTR_DEFS) $(QSTR_DEFS_COLLECTED) $(PY_SRC)/makeqstrdata.py mpconfigport.h $(MPCONFIGPORT_MK) $(PY_SRC)/mpconfig.h | $(HEADER_BUILD) $(ECHO) "GEN $@" - $(Q)cat $(PY_QSTR_DEFS) $(QSTR_DEFS) $(QSTR_DEFS_COLLECTED) | $(SED) 's/^Q(.*)/"&"/' | $(CPP) $(CFLAGS) - | $(SED) 's/^"\(Q(.*)\)"/\1/' > $(HEADER_BUILD)/qstrdefs.preprocessed.h + $(Q)$(CAT) $(PY_QSTR_DEFS) $(QSTR_DEFS) $(QSTR_DEFS_COLLECTED) | $(SED) 's/^Q(.*)/"&"/' | $(CPP) $(CFLAGS) - | $(SED) 's/^\"\(Q(.*)\)\"/\1/' > $(HEADER_BUILD)/qstrdefs.preprocessed.h $(Q)$(PYTHON) $(PY_SRC)/makeqstrdata.py $(HEADER_BUILD)/qstrdefs.preprocessed.h > $@ # build a list of registered modules for py/objmodule.c. From 85bde0889da8cc3315a3c96ff6933ca19e356569 Mon Sep 17 00:00:00 2001 From: Glenn Ruben Bakke Date: Tue, 21 May 2019 17:44:58 +0200 Subject: [PATCH 0373/1788] lib/nrfx: Upgrade nrfx to master. Updating the nrfx git submodule containing HAL drivers for nrf-port from v1.3.1 to current master. The version pointed to is one commit ahead of v1.7.1 release. The extra commit contains a bugfix for nrfx_uart_tx_in_progress() making it report correctly. The general upgrade of nrfx is considered to be safe, as almost all changes in between 1.3.1 and 1.7.1 are related to peripherals and target devices not used by the nrf-port as of today. --- lib/nrfx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/nrfx b/lib/nrfx index d4ebe15f58..7513fc9d5c 160000 --- a/lib/nrfx +++ b/lib/nrfx @@ -1 +1 @@ -Subproject commit d4ebe15f58de1442e3eed93b40d13930e7785903 +Subproject commit 7513fc9d5c10dc28b25bf2bb6ff0ba66cb2a3c3d From d80abd035e209b8fcc399b142352a49702f701fc Mon Sep 17 00:00:00 2001 From: Glenn Ruben Bakke Date: Tue, 21 May 2019 18:18:44 +0200 Subject: [PATCH 0374/1788] nrf/nrfx_glue: Adapt to nrfx v.1.7.1. Defining NRFX_STATIC_ASSERT macro to be empty, but available to nrfx. --- ports/nrf/nrfx_glue.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/nrf/nrfx_glue.h b/ports/nrf/nrfx_glue.h index 0108e3242f..316e02df1d 100644 --- a/ports/nrf/nrfx_glue.h +++ b/ports/nrf/nrfx_glue.h @@ -29,6 +29,8 @@ #include +#define NRFX_STATIC_ASSERT(expression) + #define NRFX_ASSERT(expression) do { bool res = expression; (void)res; } while (0) #define NRFX_DELAY_US mp_hal_delay_us From 302ffdba7f06e8827532834b5902406cd7bf4ea0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 3 May 2019 12:35:33 +1000 Subject: [PATCH 0375/1788] nrf/uart: Change UART driver to be non-blocking and use IRQs. As part of this, ctrl-C is now able to interrupt a running program. --- ports/nrf/modules/machine/uart.c | 55 ++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/ports/nrf/modules/machine/uart.c b/ports/nrf/modules/machine/uart.c index cef98fb07f..95921c055d 100644 --- a/ports/nrf/modules/machine/uart.c +++ b/ports/nrf/modules/machine/uart.c @@ -35,8 +35,10 @@ #include "py/stream.h" #include "py/mperrno.h" #include "py/mphal.h" +#include "py/ringbuf.h" #include "pin.h" #include "genhdr/pins.h" +#include "lib/utils/interrupt_char.h" #include "uart.h" #include "mpconfigboard.h" @@ -47,15 +49,25 @@ #if MICROPY_PY_MACHINE_UART +typedef struct _machine_hard_uart_buf_t { + uint8_t tx_buf[1]; + uint8_t rx_buf[1]; + uint8_t rx_ringbuf_array[64]; + volatile ringbuf_t rx_ringbuf; +} machine_hard_uart_buf_t; + typedef struct _machine_hard_uart_obj_t { mp_obj_base_t base; const nrfx_uart_t * p_uart; // Driver instance + machine_hard_uart_buf_t *buf; } machine_hard_uart_obj_t; static const nrfx_uart_t instance0 = NRFX_UART_INSTANCE(0); +STATIC machine_hard_uart_buf_t machine_hard_uart_buf[1]; + STATIC const machine_hard_uart_obj_t machine_hard_uart_obj[] = { - {{&machine_hard_uart_type}, .p_uart = &instance0}, + {{&machine_hard_uart_type}, .p_uart = &instance0, .buf = &machine_hard_uart_buf[0]}, }; void uart_init0(void) { @@ -70,27 +82,36 @@ STATIC int uart_find(mp_obj_t id) { mp_raise_ValueError("UART doesn't exist"); } -void uart_irq_handler(mp_uint_t uart_id) { - +STATIC void uart_event_handler(nrfx_uart_event_t const *p_event, void *p_context) { + machine_hard_uart_obj_t *self = p_context; + if (p_event->type == NRFX_UART_EVT_RX_DONE) { + int chr = self->buf->rx_buf[0]; + nrfx_uart_rx(self->p_uart, &self->buf->rx_buf[0], 1); + #if !MICROPY_PY_BLE_NUS && MICROPY_KBD_EXCEPTION + if (chr == mp_interrupt_char) { + mp_keyboard_interrupt(); + } else + #endif + { + ringbuf_put((ringbuf_t*)&self->buf->rx_ringbuf, chr); + } + } } -bool uart_rx_any(const machine_hard_uart_obj_t *uart_obj) { - // TODO: uart will block for now. - return true; +bool uart_rx_any(const machine_hard_uart_obj_t *self) { + return self->buf->rx_ringbuf.iput != self->buf->rx_ringbuf.iget; } int uart_rx_char(const machine_hard_uart_obj_t * self) { - uint8_t ch; - nrfx_uart_rx(self->p_uart, &ch, 1); - return (int)ch; + return ringbuf_get((ringbuf_t*)&self->buf->rx_ringbuf); } STATIC nrfx_err_t uart_tx_char(const machine_hard_uart_obj_t * self, int c) { while (nrfx_uart_tx_in_progress(self->p_uart)) { ; } - - return nrfx_uart_tx(self->p_uart, (uint8_t *)&c, 1); + self->buf->tx_buf[0] = c; + return nrfx_uart_tx(self->p_uart, &self->buf->tx_buf[0], 1); } @@ -181,9 +202,15 @@ STATIC mp_obj_t machine_hard_uart_make_new(const mp_obj_type_t *type, size_t n_a // Set context to this instance of UART config.p_context = (void *)self; - // Set NULL as callback function to keep it blocking - nrfx_uart_init(self->p_uart, &config, NULL); + // Initialise ring buffer + self->buf->rx_ringbuf.buf = self->buf->rx_ringbuf_array; + self->buf->rx_ringbuf.size = sizeof(self->buf->rx_ringbuf_array); + self->buf->rx_ringbuf.iget = 0; + self->buf->rx_ringbuf.iput = 0; + // Enable event callback and start asynchronous receive + nrfx_uart_init(self->p_uart, &config, uart_event_handler); + nrfx_uart_rx(self->p_uart, &self->buf->rx_buf[0], 1); nrfx_uart_rx_enable(self->p_uart); return MP_OBJ_FROM_PTR(self); @@ -250,6 +277,8 @@ STATIC mp_uint_t machine_hard_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_ // read the data for (size_t i = 0; i < size; i++) { + while (!uart_rx_any(self)) { + } buf[i] = uart_rx_char(self); } From 50d5114fcd5f3b81d400c1297d0ce754c1dcd2e6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 3 May 2019 12:36:56 +1000 Subject: [PATCH 0376/1788] nrf/mpconfigport.h: Enable MICROPY_KBD_EXCEPTION by default. --- ports/nrf/mpconfigport.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/nrf/mpconfigport.h b/ports/nrf/mpconfigport.h index 0e3cf7b39d..da9a03e1d0 100644 --- a/ports/nrf/mpconfigport.h +++ b/ports/nrf/mpconfigport.h @@ -47,7 +47,7 @@ #define MICROPY_HELPER_REPL (1) #define MICROPY_REPL_EMACS_KEYS (0) #define MICROPY_REPL_AUTO_INDENT (1) -#define MICROPY_KBD_EXCEPTION (0) +#define MICROPY_KBD_EXCEPTION (1) #define MICROPY_ENABLE_SOURCE_LINE (0) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) #if NRF51 From 456c89f7497d55e641e4374a1860ba08f3b84688 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 22 May 2019 12:45:27 +1000 Subject: [PATCH 0377/1788] nrf/uart: Make UART print output something, and add write method. --- ports/nrf/modules/machine/uart.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/ports/nrf/modules/machine/uart.c b/ports/nrf/modules/machine/uart.c index 95921c055d..b9c018fc84 100644 --- a/ports/nrf/modules/machine/uart.c +++ b/ports/nrf/modules/machine/uart.c @@ -134,10 +134,9 @@ void uart_tx_strn_cooked(const machine_hard_uart_obj_t *uart_obj, const char *st /* MicroPython bindings */ STATIC void machine_hard_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + mp_printf(print, "UART(0)"); } - - /// \method init(id, baudrate) /// /// Initialise the UART bus with the given parameters: @@ -251,13 +250,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_hard_uart_sendbreak_obj, machine_hard_u STATIC const mp_rom_map_elem_t machine_hard_uart_locals_dict_table[] = { // instance methods - /// \method read([nbytes]) { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, - /// \method readline() { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, - /// \method readinto(buf[, nbytes]) { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, - /// \method writechar(buf) + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_writechar), MP_ROM_PTR(&machine_hard_uart_writechar_obj) }, { MP_ROM_QSTR(MP_QSTR_readchar), MP_ROM_PTR(&machine_hard_uart_readchar_obj) }, { MP_ROM_QSTR(MP_QSTR_sendbreak), MP_ROM_PTR(&machine_hard_uart_sendbreak_obj) }, From 9cf1cbb0575387d79b496b6ff14736ca9239c0a1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 22 May 2019 12:46:09 +1000 Subject: [PATCH 0378/1788] nrf/mphalport: Use wfi to save power while waiting at the UART REPL. --- ports/nrf/mphalport.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/nrf/mphalport.c b/ports/nrf/mphalport.c index 9ce904514e..a050df1470 100644 --- a/ports/nrf/mphalport.c +++ b/ports/nrf/mphalport.c @@ -58,6 +58,7 @@ int mp_hal_stdin_rx_chr(void) { if (MP_STATE_PORT(board_stdio_uart) != NULL && uart_rx_any(MP_STATE_PORT(board_stdio_uart))) { return uart_rx_char(MP_STATE_PORT(board_stdio_uart)); } + __WFI(); } return 0; From a4f4239e9589c49ff621a76cd860ca6fa6b7efe4 Mon Sep 17 00:00:00 2001 From: Sebastien Rinsoz Date: Tue, 21 May 2019 11:35:09 +0200 Subject: [PATCH 0379/1788] py: Update makefiles to use $(TOUCH) instead of hard coded "touch". The variable $(TOUCH) is initialized with the "touch" value in mkenv.mk like for the other command line tools (rm, echo, cp, mkdir etc). With this, for example, Windows users can specify the path of touch.exe. --- py/mkenv.mk | 1 + py/mkrules.mk | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/py/mkenv.mk b/py/mkenv.mk index 04e7acc1bf..46eedf988a 100644 --- a/py/mkenv.mk +++ b/py/mkenv.mk @@ -43,6 +43,7 @@ CP = cp MKDIR = mkdir SED = sed CAT = cat +TOUCH = touch PYTHON = python3 AS = $(CROSS_COMPILE)as diff --git a/py/mkrules.mk b/py/mkrules.mk index caa9527c70..3f310c1958 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -77,7 +77,7 @@ $(HEADER_BUILD)/qstr.i.last: $(SRC_QSTR) $(QSTR_GLOBAL_DEPENDENCIES) | $(HEADER_ $(HEADER_BUILD)/qstr.split: $(HEADER_BUILD)/qstr.i.last $(ECHO) "GEN $@" $(Q)$(PYTHON) $(PY_SRC)/makeqstrdefs.py split $(HEADER_BUILD)/qstr.i.last $(HEADER_BUILD)/qstr $(QSTR_DEFS_COLLECTED) - $(Q)touch $@ + $(Q)$(TOUCH) $@ $(QSTR_DEFS_COLLECTED): $(HEADER_BUILD)/qstr.split $(ECHO) "GEN $@" @@ -190,7 +190,7 @@ print-cfg: print-def: @$(ECHO) "The following defines are built into the $(CC) compiler" - touch __empty__.c + $(TOUCH) __empty__.c @$(CC) -E -Wp,-dM __empty__.c @$(RM) -f __empty__.c From 6cf4e9675b11de43fe99844919670ba0c3ff544a Mon Sep 17 00:00:00 2001 From: Sebastien Rinsoz Date: Tue, 21 May 2019 14:27:05 +0200 Subject: [PATCH 0380/1788] py/mkrules.mk: Remove unnecessary ; in makefile. This ; make Windows compilation fail with GNU makefile 4.2.1. It was added in 0dc85c9f86735c35cf14555482b2c8923cf31a6a as part of a shell if- statement, but this if-statement was subsequently removed in 23a693ec2d8c2a194f61482dc0e1adb070fb6ad4 so the semicolon is not needed. --- py/mkrules.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/mkrules.mk b/py/mkrules.mk index 3f310c1958..4e4fdef55c 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -72,7 +72,7 @@ $(OBJ): | $(HEADER_BUILD)/qstrdefs.generated.h $(HEADER_BUILD)/mpversion.h # - 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 $(filter $?,$(QSTR_GLOBAL_DEPENDENCIES)),$^,$(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 $@" From 4f4477872861927f7d9230248dcf43d15bc7b57c Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Thu, 23 May 2019 13:55:19 +1000 Subject: [PATCH 0381/1788] stm32/sdcard: Add switch break to ensure only correct SD/MMC IRQ is run. --- ports/stm32/sdcard.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/stm32/sdcard.c b/ports/stm32/sdcard.c index 16e6506156..8ffba0b4c5 100644 --- a/ports/stm32/sdcard.c +++ b/ports/stm32/sdcard.c @@ -370,10 +370,12 @@ STATIC void sdmmc_irq_handler(void) { #if MICROPY_HW_ENABLE_SDCARD case PYB_SDMMC_FLAG_ACTIVE | PYB_SDMMC_FLAG_SD: HAL_SD_IRQHandler(&sdmmc_handle.sd); + break; #endif #if MICROPY_HW_ENABLE_MMCARD case PYB_SDMMC_FLAG_ACTIVE | PYB_SDMMC_FLAG_MMC: HAL_MMC_IRQHandler(&sdmmc_handle.mmc); + break; #endif } } From 2762f323bf6407093dc814591e7c6d08ca82bc6f Mon Sep 17 00:00:00 2001 From: stijn Date: Thu, 21 Jun 2018 11:54:49 +0200 Subject: [PATCH 0382/1788] windows: Fix line wrapping behaviour on the REPL. This enables going back to previous wrapped lines using backspace or left arrow: instead of just sticking to the beginning of a line, the cursor will move a line up. --- ports/windows/windows_mphal.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/ports/windows/windows_mphal.c b/ports/windows/windows_mphal.c index 153b044235..1e3a092910 100644 --- a/ports/windows/windows_mphal.c +++ b/ports/windows/windows_mphal.c @@ -106,12 +106,23 @@ void mp_hal_set_interrupt_char(char c) { } void mp_hal_move_cursor_back(uint pos) { + if (!pos) { + return; + } assure_conout_handle(); CONSOLE_SCREEN_BUFFER_INFO info; GetConsoleScreenBufferInfo(con_out, &info); info.dwCursorPosition.X -= (short)pos; - if (info.dwCursorPosition.X < 0) { + // Move up a line if needed. + while (info.dwCursorPosition.X < 0) { + info.dwCursorPosition.X = info.dwSize.X + info.dwCursorPosition.X; + info.dwCursorPosition.Y -= 1; + } + // Caller requested to move out of the screen. That's not possible so just clip, + // it's the caller's responsibility to not let this happen. + if (info.dwCursorPosition.Y < 0) { info.dwCursorPosition.X = 0; + info.dwCursorPosition.Y = 0; } SetConsoleCursorPosition(con_out, info.dwCursorPosition); } From c066dadc5b91d000e2f7bba9f3e3edbf0bf33a3d Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 24 May 2019 14:51:48 +1000 Subject: [PATCH 0383/1788] mpy-cross/mpconfigport.h: Remove defn of MP_NOINLINE to use global one. A global definition of MP_NOINLINE was added to py/mpconfig.h long ago in 0f5bf1aafe0ca073d958f271bd96addc6da8fe10 --- mpy-cross/mpconfigport.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/mpy-cross/mpconfigport.h b/mpy-cross/mpconfigport.h index 6aa013a134..125303afd2 100644 --- a/mpy-cross/mpconfigport.h +++ b/mpy-cross/mpconfigport.h @@ -112,10 +112,6 @@ typedef long mp_off_t; #define MP_PLAT_PRINT_STRN(str, len) (void)0 -#ifndef MP_NOINLINE -#define MP_NOINLINE __attribute__((noinline)) -#endif - // We need to provide a declaration/definition of alloca() #ifdef __FreeBSD__ #include From b88bf42793d7469acaeb8b9bd279c0a8c9d20558 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 28 Mar 2019 16:12:20 +0200 Subject: [PATCH 0384/1788] zephyr/README: Reorder content related to recently added I2C. So it fits better with existing narrative. --- ports/zephyr/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ports/zephyr/README.md b/ports/zephyr/README.md index 3d2e883adc..6bcbccd8b3 100644 --- a/ports/zephyr/README.md +++ b/ports/zephyr/README.md @@ -12,8 +12,8 @@ Features supported at this time: * REPL (interactive prompt) over Zephyr UART console. * `utime` module for time measurements and delays. -* `machine.I2C` class for I2C control. * `machine.Pin` class for GPIO control. +* `machine.I2C` class for I2C control. * `usocket` module for networking (IPv4/IPv6). * "Frozen modules" support to allow to bundle Python modules together with firmware. Including complete applications, including with @@ -82,13 +82,6 @@ To blink an LED: LED.value(0) time.sleep(0.5) -To scan for I2C slaves: - - from machine import I2C - - i2c = I2C("I2C_0") - i2c.scan() - The above code uses an LED location for a FRDM-K64F board (port B, pin 21; following Zephyr conventions port are identified by "GPIO_x", where *x* starts from 0). You will need to adjust it for another board (using board's @@ -96,6 +89,13 @@ reference materials). To execute the above sample, copy it to clipboard, in MicroPython REPL enter "paste mode" using Ctrl+E, paste clipboard, press Ctrl+D to finish paste mode and start execution. +Example of using I2C to scan for I2C slaves: + + from machine import I2C + + i2c = I2C("I2C_0") + i2c.scan() + Minimal build ------------- From c4a6d9c631a3e529aeedeaf5c24fa1bd748d493f Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 28 Mar 2019 16:15:42 +0200 Subject: [PATCH 0385/1788] zephyr: Switch back to enabling I2C in board-specific configs. I2C can't be enabled in prj_base.conf because it's a board-specific feature. For example, if a board doesn't have I2C but CONFIG_I2C=y then the build will fail (on Zephyr build system side). The patch here gets the qemu_cortex_m3 build working again. --- ports/zephyr/prj_base.conf | 3 --- ports/zephyr/prj_frdm_k64f.conf | 3 +++ ports/zephyr/prj_frdm_kw41z.conf | 3 +++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ports/zephyr/prj_base.conf b/ports/zephyr/prj_base.conf index 58206a0bc2..993dfdc26f 100644 --- a/ports/zephyr/prj_base.conf +++ b/ports/zephyr/prj_base.conf @@ -14,9 +14,6 @@ CONFIG_NEWLIB_LIBC=y CONFIG_FLOAT=y CONFIG_MAIN_STACK_SIZE=4736 -# Drivers -CONFIG_I2C=y - # Enable sensor subsystem (doesn't add code if not used). # Specific sensors should be enabled per-board. CONFIG_SENSOR=y diff --git a/ports/zephyr/prj_frdm_k64f.conf b/ports/zephyr/prj_frdm_k64f.conf index 477f3b8257..c2166c00df 100644 --- a/ports/zephyr/prj_frdm_k64f.conf +++ b/ports/zephyr/prj_frdm_k64f.conf @@ -1,6 +1,9 @@ # Networking drivers CONFIG_NET_L2_ETHERNET=y +# Hardware features +CONFIG_I2C=y + # Sensor drivers CONFIG_FXOS8700=y CONFIG_FXOS8700_MODE_HYBRID=y diff --git a/ports/zephyr/prj_frdm_kw41z.conf b/ports/zephyr/prj_frdm_kw41z.conf index 486ece2bd8..ff7b7887e1 100644 --- a/ports/zephyr/prj_frdm_kw41z.conf +++ b/ports/zephyr/prj_frdm_kw41z.conf @@ -1,3 +1,6 @@ +# Hardware features +CONFIG_I2C=y + # Sensor drivers CONFIG_FXOS8700=y CONFIG_FXOS8700_MODE_HYBRID=y From 5357dad52efbe5773f4beda7ad014dc62ad8e44f Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 22 May 2019 15:05:03 +1000 Subject: [PATCH 0386/1788] esp8266: Fix ticks_ms to correctly handle wraparound of system counter. Fixes issue #4795. --- ports/esp8266/esp_mphal.c | 4 +++- ports/esp8266/ets_alt_task.c | 23 ++++++++++++++--------- ports/esp8266/ets_alt_task.h | 2 ++ 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/ports/esp8266/esp_mphal.c b/ports/esp8266/esp_mphal.c index df97a73430..351bf522c8 100644 --- a/ports/esp8266/esp_mphal.c +++ b/ports/esp8266/esp_mphal.c @@ -120,7 +120,9 @@ void mp_hal_debug_tx_strn_cooked(void *env, const char *str, uint32_t len) { } uint32_t mp_hal_ticks_ms(void) { - return ((uint64_t)system_time_high_word << 32 | (uint64_t)system_get_time()) / 1000; + // Compute milliseconds from 64-bit microsecond counter + system_time_update(); + return ((uint64_t)system_time_high_word << 32 | (uint64_t)system_time_low_word) / 1000; } uint32_t mp_hal_ticks_us(void) { diff --git a/ports/esp8266/ets_alt_task.c b/ports/esp8266/ets_alt_task.c index b724b8f14a..0b1615d658 100644 --- a/ports/esp8266/ets_alt_task.c +++ b/ports/esp8266/ets_alt_task.c @@ -112,22 +112,27 @@ int ets_loop_iter_disable = 0; int ets_loop_dont_feed_sw_wdt = 0; // to implement a 64-bit wide microsecond counter -static uint32_t system_time_prev = 0; +uint32_t system_time_low_word = 0; uint32_t system_time_high_word = 0; +void system_time_update(void) { + // Handle overflow of system microsecond counter + ets_intr_lock(); + uint32_t system_time_cur = system_get_time(); + if (system_time_cur < system_time_low_word) { + system_time_high_word += 1; // record overflow of low 32-bits + } + system_time_low_word = system_time_cur; + ets_intr_unlock(); +} + bool ets_loop_iter(void) { if (ets_loop_iter_disable) { return false; } - // handle overflow of system microsecond counter - ets_intr_lock(); - uint32_t system_time_cur = system_get_time(); - if (system_time_cur < system_time_prev) { - system_time_high_word += 1; // record overflow of low 32-bits - } - system_time_prev = system_time_cur; - ets_intr_unlock(); + // Update 64-bit microsecond counter + system_time_update(); // 6 words before pend_flag_noise_check is a variable that is used by // the software WDT. A 1.6 second period timer will increment this diff --git a/ports/esp8266/ets_alt_task.h b/ports/esp8266/ets_alt_task.h index e7a15c3ad5..7eb8ff3a54 100644 --- a/ports/esp8266/ets_alt_task.h +++ b/ports/esp8266/ets_alt_task.h @@ -3,8 +3,10 @@ extern int ets_loop_iter_disable; extern int ets_loop_dont_feed_sw_wdt; +extern uint32_t system_time_low_word; extern uint32_t system_time_high_word; +void system_time_update(void); bool ets_loop_iter(void); #endif // MICROPY_INCLUDED_ESP8266_ETS_ALT_TASK_H From 1470184bddcdb7f325a42a25ad76b8cd3714606f Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Thu, 2 May 2019 15:59:38 +1000 Subject: [PATCH 0387/1788] stm32/sdram: Update MPU settings to block invalid region, change attrs. Set the active MPU region to the actual size of SDRAM configured and invalidate the rest of the memory-mapped region, to prevent errors due to CPU speculation. Also update the attributes of the SDRAM region as per ST recommendations, and change region numbers to avoid conflicts elsewhere in the codebase (see eth usage). --- ports/stm32/sdram.c | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/ports/stm32/sdram.c b/ports/stm32/sdram.c index e2b29c56e2..b3c5bbeeed 100644 --- a/ports/stm32/sdram.c +++ b/ports/stm32/sdram.c @@ -39,6 +39,13 @@ #define SDRAM_START_ADDRESS 0xD0000000 #endif +// Provides the MPU_REGION_SIZE_X value when passed the size of region in bytes +// "m" must be a power of 2 between 32 and 4G (2**5 and 2**32) and this formula +// computes the log2 of "m", minus 1 +#define MPU_REGION_SIZE(m) (((m) - 1) / (((m) - 1) % 255 + 1) / 255 % 255 * 8 + 7 - 86 / (((m) - 1) % 255 + 12) - 1) + +#define SDRAM_MPU_REGION_SIZE (MPU_REGION_SIZE(MICROPY_HW_SDRAM_SIZE)) + #ifdef FMC_SDRAM_BANK static void sdram_init_seq(SDRAM_HandleTypeDef @@ -244,16 +251,32 @@ static void sdram_init_seq(SDRAM_HandleTypeDef /* Disable the MPU */ HAL_MPU_Disable(); - /* Configure the MPU attributes as Write-Through for External SDRAM */ + /* Configure the MPU attributes for External SDRAM + Initially disable all access for the entire SDRAM memory space, + then enable access/caching for the size used + */ MPU_InitStruct.Enable = MPU_REGION_ENABLE; + MPU_InitStruct.Number = MPU_REGION_NUMBER4; MPU_InitStruct.BaseAddress = SDRAM_START_ADDRESS; - MPU_InitStruct.Size = MPU_REGION_SIZE_256MB; - MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; + MPU_InitStruct.Size = MPU_REGION_SIZE_512MB; + MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS; MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE; + MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; + MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; + MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0; + MPU_InitStruct.SubRegionDisable = 0x00; + MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE; + HAL_MPU_ConfigRegion(&MPU_InitStruct); + + MPU_InitStruct.Enable = MPU_REGION_ENABLE; + MPU_InitStruct.Number = MPU_REGION_NUMBER5; + MPU_InitStruct.BaseAddress = SDRAM_START_ADDRESS; + MPU_InitStruct.Size = SDRAM_MPU_REGION_SIZE; + MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; + MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE; MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; - MPU_InitStruct.Number = MPU_REGION_NUMBER0; - MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0; + MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1; MPU_InitStruct.SubRegionDisable = 0x00; MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE; HAL_MPU_ConfigRegion(&MPU_InitStruct); From ab265537593ed10d075c2b8ea8b5e0b193c13094 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 27 May 2019 11:55:40 +1000 Subject: [PATCH 0388/1788] py/vm: Remove obsolete comments about matching of exception opcodes. These are incorrect since 5a2599d96299ad37cda954f1de345159f9acf11c --- py/vm.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/py/vm.c b/py/vm.c index 901a23f225..260a7f38ba 100644 --- a/py/vm.c +++ b/py/vm.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2013-2019 Damien P. George * Copyright (c) 2014-2015 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -675,7 +675,6 @@ unwind_jump:; DISPATCH_WITH_PEND_EXC_CHECK(); } - // matched against: POP_BLOCK or POP_EXCEPT (anything else?) ENTRY(MP_BC_SETUP_EXCEPT): ENTRY(MP_BC_SETUP_FINALLY): { MARK_EXC_IP_SELECTIVE(); @@ -758,7 +757,6 @@ unwind_jump:; DISPATCH(); } - // matched against: SETUP_EXCEPT, SETUP_FINALLY, SETUP_WITH ENTRY(MP_BC_POP_EXCEPT_JUMP): { assert(exc_sp >= exc_stack); POP_EXC_BLOCK(); From 887a6712c2a302bd0bdeceb8ee9bc33a6de64dae Mon Sep 17 00:00:00 2001 From: Tom Manning Date: Wed, 15 May 2019 05:50:53 -0400 Subject: [PATCH 0389/1788] esp32/machine_touchpad: Use HW timer for FSM to enable wake-on-touch. --- ports/esp32/machine_touchpad.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/esp32/machine_touchpad.c b/ports/esp32/machine_touchpad.c index 96de1a2a1d..dd36bdd764 100644 --- a/ports/esp32/machine_touchpad.c +++ b/ports/esp32/machine_touchpad.c @@ -69,6 +69,7 @@ STATIC mp_obj_t mtp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ static int initialized = 0; if (!initialized) { touch_pad_init(); + touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); initialized = 1; } esp_err_t err = touch_pad_config(self->touchpad_id, 0); From 8c9758ff2ee5c5b70e4eab5fe0396de2e21299b0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 28 May 2019 17:22:54 +1000 Subject: [PATCH 0390/1788] unix/modusocket: Raise ETIMEDOUT when connect or accept has timeout. --- ports/unix/modusocket.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/ports/unix/modusocket.c b/ports/unix/modusocket.c index 8cbd3d077d..9b82378bb4 100644 --- a/ports/unix/modusocket.c +++ b/ports/unix/modusocket.c @@ -160,7 +160,12 @@ STATIC mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(addr_in, &bufinfo, MP_BUFFER_READ); int r = connect(self->fd, (const struct sockaddr *)bufinfo.buf, bufinfo.len); - RAISE_ERRNO(r, errno); + int err = errno; + if (r == -1 && self->blocking && err == EINPROGRESS) { + // EINPROGRESS on a blocking socket means the operation timed out + err = MP_ETIMEDOUT; + } + RAISE_ERRNO(r, err); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect); @@ -190,7 +195,12 @@ STATIC mp_obj_t socket_accept(mp_obj_t self_in) { byte addr[32]; socklen_t addr_len = sizeof(addr); int fd = accept(self->fd, (struct sockaddr*)&addr, &addr_len); - RAISE_ERRNO(fd, errno); + int err = errno; + if (fd == -1 && self->blocking && err == EAGAIN) { + // EAGAIN on a blocking socket means the operation timed out + err = MP_ETIMEDOUT; + } + RAISE_ERRNO(fd, err); mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL)); t->items[0] = MP_OBJ_FROM_PTR(socket_new(fd)); From 883e987b90e82f0a9ab223910890da2c5d50b9d3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 28 May 2019 17:43:00 +1000 Subject: [PATCH 0391/1788] esp32/modsocket: Raise EAGAIN when accept fails in non-blocking mode. EAGAIN should be for pure non-blocking mode and ETIMEDOUT for when there is a finite (but non-zero) timeout enabled. --- ports/esp32/modsocket.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c index 1d7aec5efa..8b80e631db 100644 --- a/ports/esp32/modsocket.c +++ b/ports/esp32/modsocket.c @@ -253,7 +253,13 @@ STATIC mp_obj_t socket_accept(const mp_obj_t arg0) { if (errno != EAGAIN) exception_from_errno(errno); check_for_exceptions(); } - if (new_fd < 0) mp_raise_OSError(MP_ETIMEDOUT); + if (new_fd < 0) { + if (self->retries == 0) { + mp_raise_OSError(MP_EAGAIN); + } else { + mp_raise_OSError(MP_ETIMEDOUT); + } + } // create new socket object socket_obj_t *sock = m_new_obj_with_finaliser(socket_obj_t); From 734ada3e2980d1bbf5c7a1ea5c624b34be16dfa9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 29 May 2019 01:24:43 +1000 Subject: [PATCH 0392/1788] extmod/modlwip: Free any incoming bufs/connections before closing PCB. Commit 2848a613ac61fce209962354c2698ee587a2c26a introduced a bug where lwip_socket_free_incoming() accessed pcb.tcp->state after the PCB was closed. The state may have changed due to that close call, or the PCB may be freed and therefore invalid. This commit fixes that by calling lwip_socket_free_incoming() before the PCB is closed. --- extmod/modlwip.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index e0bf17db8c..06ed764b53 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -1416,6 +1416,9 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ tcp_err(socket->pcb.tcp, NULL); tcp_recv(socket->pcb.tcp, NULL); + // Free any incoming buffers or connections that are stored + lwip_socket_free_incoming(socket); + switch (socket->type) { case MOD_NETWORK_SOCK_STREAM: { if (tcp_close(socket->pcb.tcp) != ERR_OK) { @@ -1430,7 +1433,7 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ case MOD_NETWORK_SOCK_DGRAM: udp_remove(socket->pcb.udp); break; //case MOD_NETWORK_SOCK_RAW: raw_remove(socket->pcb.raw); break; } - lwip_socket_free_incoming(socket); + socket->pcb.tcp = NULL; socket->state = _ERR_BADF; ret = 0; From 019dd84af1e8e9bbdbbb6377c28950d31f05a77c Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 29 May 2019 01:29:48 +1000 Subject: [PATCH 0393/1788] extmod/modlwip: Register TCP close-timeout callback before closing PCB. In d5f0c87bb985ae344014dc2041fbaad5c522f638 this call to tcp_poll() was added to put a timeout on closing TCP sockets. But after calling tcp_close() the PCB may be freed and therefore invalid, so tcp_poll() can not be used at that point. As a fix this commit calls tcp_poll() before closing the TCP PCB. If the PCB is subsequently closed and freed by tcp_close() or tcp_abort() then the PCB will not be on any active list and the callback will not be executed, which is the desired behaviour (the _lwip_tcp_close_poll() callback only needs to be called if the PCB remains active for longer than the timeout). --- extmod/modlwip.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index 06ed764b53..4127d21add 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -1421,12 +1421,15 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ switch (socket->type) { case MOD_NETWORK_SOCK_STREAM: { + if (socket->pcb.tcp->state != LISTEN) { + // Schedule a callback to abort the connection if it's not cleanly closed after + // the given timeout. The callback must be set before calling tcp_close since + // the latter may free the pcb; if it doesn't then the callback will be active. + tcp_poll(socket->pcb.tcp, _lwip_tcp_close_poll, MICROPY_PY_LWIP_TCP_CLOSE_TIMEOUT_MS / 500); + } if (tcp_close(socket->pcb.tcp) != ERR_OK) { DEBUG_printf("lwip_close: had to call tcp_abort()\n"); tcp_abort(socket->pcb.tcp); - } else { - // If connection not cleanly closed after timeout then abort the connection - tcp_poll(socket->pcb.tcp, _lwip_tcp_close_poll, MICROPY_PY_LWIP_TCP_CLOSE_TIMEOUT_MS / 500); } break; } From 66bcb5596aae3e2f7748ae6b2379e5c542647052 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Wed, 29 May 2019 11:11:20 +1000 Subject: [PATCH 0394/1788] stm32/modmachine: In bootloader() disable caches before reset of periphs Otherwise flushing and disabling the D-cache will give a hard-fault when SDRAM is used. Fixes #4818. --- ports/stm32/modmachine.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index 7031dea91c..eca8322eac 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -265,6 +265,12 @@ STATIC NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args) storage_flush(); #endif + #if __DCACHE_PRESENT == 1 + // Flush and disable caches before turning off peripherals (eg SDRAM) + SCB_DisableICache(); + SCB_DisableDCache(); + #endif + HAL_RCC_DeInit(); HAL_DeInit(); @@ -276,10 +282,6 @@ STATIC NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args) #if MICROPY_HW_USES_BOOTLOADER if (n_args == 0 || !mp_obj_is_true(args[0])) { // By default, with no args given, we enter the custom bootloader (mboot) - #if __DCACHE_PRESENT == 1 - SCB_DisableICache(); - SCB_DisableDCache(); - #endif branch_to_bootloader(0x70ad0000, 0x08000000); } @@ -289,10 +291,6 @@ STATIC NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args) const char *data = mp_obj_str_get_data(args[0], &len); void *mboot_region = (void*)*((volatile uint32_t*)0x08000000); memmove(mboot_region, data, len); - #if __DCACHE_PRESENT == 1 - SCB_DisableICache(); - SCB_DisableDCache(); - #endif branch_to_bootloader(0x70ad0080, 0x08000000); } #endif From 0bb6b63e662fa688e448e41e4bafe0c146568e78 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 29 May 2019 16:26:02 +1000 Subject: [PATCH 0395/1788] stm32/mboot/README: Fix some typos, describe bootloader and fwupdate.py. --- ports/stm32/mboot/README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ports/stm32/mboot/README.md b/ports/stm32/mboot/README.md index 14bfc66f9c..3128307b1e 100644 --- a/ports/stm32/mboot/README.md +++ b/ports/stm32/mboot/README.md @@ -46,14 +46,14 @@ How to use 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 + `MBOOT_SPIFLASH_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. + must be changed to `16 / 4` to match the `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 @@ -115,6 +115,10 @@ The last element in the data sequence must be the end element: * END: type=1, len=0 +Note: MicroPython's `machine.bootloader()` function performs steps 1-4 +above, and also accepts an optional bytes argument as additional data to +pass through to Mboot. + Loading firmware from a filesystem ---------------------------------- @@ -130,6 +134,9 @@ are located and what filename to program. The elements to use are: The firmware to load must be a gzip'd DfuSe file (.dfu.gz). +The provided fwupdate.py script contains helper functions to call into Mboot +with the correct data, and also to update Mboot itself. + Example: Mboot on PYBv1.x ------------------------- From 2715f3b696da7dc3a2ad6cf8da898de341c863ee Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 29 May 2019 16:28:20 +1000 Subject: [PATCH 0396/1788] LICENSE: Update year range in top-level license. --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index e3474e33dd..e6a54cf269 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013, 2014 Damien P. George +Copyright (c) 2013-2019 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 From 6f75c4f3cd393131579db70cdf0b35d1fe5b95ab Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 29 May 2019 16:38:10 +1000 Subject: [PATCH 0397/1788] all: Bump version to 1.11. --- docs/conf.py | 2 +- py/mpconfig.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 61c660aa66..71e561c9c0 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -74,7 +74,7 @@ copyright = '2014-2019, 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.10' +version = release = '1.11' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/py/mpconfig.h b/py/mpconfig.h index 2d857d8f6d..219f8de44b 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -28,7 +28,7 @@ // Current version of MicroPython #define MICROPY_VERSION_MAJOR 1 -#define MICROPY_VERSION_MINOR 10 +#define MICROPY_VERSION_MINOR 11 #define MICROPY_VERSION_MICRO 0 // Combined version as a 32-bit number for convenience From bff4e130099e2ec17478bb00f7eaa5d85fb763dc Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 29 May 2019 21:14:24 +1000 Subject: [PATCH 0398/1788] py/nativeglue: Make private glue funs all static, remove commented code. --- py/nativeglue.c | 12 +++--------- py/runtime.h | 3 --- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/py/nativeglue.c b/py/nativeglue.c index c810f31e60..8f38ecd16e 100644 --- a/py/nativeglue.c +++ b/py/nativeglue.c @@ -97,7 +97,7 @@ mp_obj_t mp_native_to_obj(mp_uint_t val, mp_uint_t type) { #if MICROPY_EMIT_NATIVE -mp_obj_dict_t *mp_native_swap_globals(mp_obj_dict_t *new_globals) { +STATIC mp_obj_dict_t *mp_native_swap_globals(mp_obj_dict_t *new_globals) { if (new_globals == NULL) { // Globals were the originally the same so don't restore them return NULL; @@ -113,13 +113,13 @@ mp_obj_dict_t *mp_native_swap_globals(mp_obj_dict_t *new_globals) { // wrapper that accepts n_args and n_kw in one argument // (native emitter can only pass at most 3 arguments to a function) -mp_obj_t mp_native_call_function_n_kw(mp_obj_t fun_in, size_t n_args_kw, const mp_obj_t *args) { +STATIC mp_obj_t mp_native_call_function_n_kw(mp_obj_t fun_in, size_t n_args_kw, const mp_obj_t *args) { return mp_call_function_n_kw(fun_in, n_args_kw & 0xff, (n_args_kw >> 8) & 0xff, args); } // wrapper that makes raise obj and raises it // END_FINALLY opcode requires that we don't raise if o==None -void mp_native_raise(mp_obj_t o) { +STATIC void mp_native_raise(mp_obj_t o) { if (o != MP_OBJ_NULL && o != mp_const_none) { nlr_raise(mp_make_raise_obj(o)); } @@ -245,10 +245,4 @@ const void *const mp_fun_table[MP_F_NUMBER_OF] = { mp_native_yield_from, }; -/* -void mp_f_vector(mp_fun_kind_t fun_kind) { - (mp_f_table[fun_kind])(); -} -*/ - #endif // MICROPY_EMIT_NATIVE diff --git a/py/runtime.h b/py/runtime.h index 0eb15d4617..1ac383ca71 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -172,9 +172,6 @@ NORETURN void mp_raise_recursion_depth(void); int mp_native_type_from_qstr(qstr qst); mp_uint_t mp_native_from_obj(mp_obj_t obj, mp_uint_t type); mp_obj_t mp_native_to_obj(mp_uint_t val, mp_uint_t type); -mp_obj_dict_t *mp_native_swap_globals(mp_obj_dict_t *new_globals); -mp_obj_t mp_native_call_function_n_kw(mp_obj_t fun_in, size_t n_args_kw, const mp_obj_t *args); -void mp_native_raise(mp_obj_t o); #define mp_sys_path (MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_sys_path_obj))) #define mp_sys_argv (MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_sys_argv_obj))) From a4f1d82757b8e95c21a095c99b7c3f04ded88104 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 29 May 2019 21:17:29 +1000 Subject: [PATCH 0399/1788] py/nativeglue: Remove dependency on mp_fun_table in dyn-compiler mode. mpy-cross uses MICROPY_DYNAMIC_COMPILER and MICROPY_EMIT_NATIVE but does not actually need to execute native functions, and does not need mp_fun_table. This commit makes it so mp_fun_table and all its entries are not built when MICROPY_DYNAMIC_COMPILER is enabled, significantly reducing the size of the mpy-cross executable and allowing it to be built on more machines/OS's. --- py/emitnative.c | 3 +++ py/mpconfig.h | 1 + py/nativeglue.c | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/py/emitnative.c b/py/emitnative.c index f123ecbb58..278cc21e78 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -609,8 +609,11 @@ STATIC void emit_native_end_pass(emit_t *emit) { const_table_alloc += nqstr; } emit->const_table = m_new(mp_uint_t, const_table_alloc); + #if !MICROPY_DYNAMIC_COMPILER // Store mp_fun_table pointer just after qstrs + // (but in dynamic-compiler mode eliminate dependency on mp_fun_table) emit->const_table[nqstr] = (mp_uint_t)(uintptr_t)mp_fun_table; + #endif #if MICROPY_PERSISTENT_CODE_SAVE size_t qstr_link_alloc = emit->qstr_link_cur; diff --git a/py/mpconfig.h b/py/mpconfig.h index 219f8de44b..4172e175b2 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -338,6 +338,7 @@ #endif // Whether the compiler is dynamically configurable (ie at runtime) +// This will disable the ability to execute native/viper code #ifndef MICROPY_DYNAMIC_COMPILER #define MICROPY_DYNAMIC_COMPILER (0) #endif diff --git a/py/nativeglue.c b/py/nativeglue.c index 8f38ecd16e..11d7a283a2 100644 --- a/py/nativeglue.c +++ b/py/nativeglue.c @@ -95,7 +95,7 @@ mp_obj_t mp_native_to_obj(mp_uint_t val, mp_uint_t type) { #endif -#if MICROPY_EMIT_NATIVE +#if MICROPY_EMIT_NATIVE && !MICROPY_DYNAMIC_COMPILER STATIC mp_obj_dict_t *mp_native_swap_globals(mp_obj_dict_t *new_globals) { if (new_globals == NULL) { From 0c29502ad995cfacc3b11f26a135707a06b8c27d Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 18 May 2019 23:01:36 +1000 Subject: [PATCH 0400/1788] stm32/usb: Refactor CDC VCP code to enable N CDC interfaces. The board config option MICROPY_HW_USB_ENABLE_CDC2 is now changed to MICROPY_HW_USB_CDC_NUM, and the latter should be defined to the maximum number of CDC interfaces to support (defaults to 1). --- ports/stm32/main.c | 4 - ports/stm32/mpconfigboard_common.h | 4 + ports/stm32/usb.c | 79 +++--- ports/stm32/usb.h | 3 +- ports/stm32/usbd_cdc_interface.c | 17 +- ports/stm32/usbd_conf.c | 4 +- .../stm32/usbdev/class/inc/usbd_cdc_msc_hid.h | 14 +- .../usbdev/class/inc/usbd_cdc_msc_hid0.h | 28 +- .../stm32/usbdev/class/src/usbd_cdc_msc_hid.c | 255 ++++++++---------- 9 files changed, 183 insertions(+), 225 deletions(-) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index ff4589f9d4..02449a1b80 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -558,10 +558,6 @@ soft_reset: #if MICROPY_HW_ENABLE_USB pyb_usb_init0(); - - // Activate USB_VCP(0) on dupterm slot 1 for the REPL - MP_STATE_VM(dupterm_objs[1]) = MP_OBJ_FROM_PTR(&pyb_usb_vcp_obj); - usb_vcp_attach_to_repl(&pyb_usb_vcp_obj, true); #endif // Initialise the local flash filesystem. diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index b9fa3833ec..036e1f6ccd 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -264,6 +264,10 @@ #define MICROPY_HW_MAX_CAN (1) #endif +// Configure maximum number of CDC VCP interfaces +#ifndef MICROPY_HW_USB_CDC_NUM +#define MICROPY_HW_USB_CDC_NUM (1) +#endif // Pin definition header file #define MICROPY_PIN_DEFS_PORT_H "pin_defs_stm32.h" diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index 8b7608a150..c9c22d5d2b 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -55,6 +55,8 @@ #endif #endif +STATIC void pyb_usb_vcp_init0(void); + // this will be persistent across a soft-reset mp_uint_t pyb_usb_flags = 0; @@ -62,10 +64,7 @@ typedef struct _usb_device_t { uint32_t enabled; 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_cdc_itf_t usbd_cdc_itf[MICROPY_HW_USB_CDC_NUM]; usbd_hid_itf_t usbd_hid_itf; } usb_device_t; @@ -111,16 +110,15 @@ const mp_rom_obj_tuple_t pyb_usb_hid_keyboard_obj = { }; void pyb_usb_init0(void) { - usb_device.usbd_cdc_itf.attached_to_repl = false; - #if MICROPY_HW_USB_ENABLE_CDC2 - usb_device.usbd_cdc2_itf.attached_to_repl = false; - #endif + for (int i = 0; i < MICROPY_HW_USB_CDC_NUM; ++i) { + usb_device.usbd_cdc_itf[i].attached_to_repl = false; + } MP_STATE_PORT(pyb_hid_report_desc) = MP_OBJ_NULL; + + pyb_usb_vcp_init0(); } -bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, usb_device_mode_t mode, USBD_HID_ModeInfoTypeDef *hid_info) { - bool high_speed = (mode & USBD_MODE_HIGH_SPEED) != 0; - mode &= 0x7f; +bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, uint8_t mode, USBD_HID_ModeInfoTypeDef *hid_info) { usb_device_t *usb_dev = &usb_device; if (!usb_dev->enabled) { // only init USB once in the device's power-lifetime @@ -132,15 +130,15 @@ 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.base; - #if MICROPY_HW_USB_ENABLE_CDC2 - usb_dev->usbd_cdc_msc_hid_state.cdc2 = &usb_dev->usbd_cdc2_itf.base; - #endif + for (int i = 0; i < MICROPY_HW_USB_CDC_NUM; ++i) { + usb_dev->usbd_cdc_msc_hid_state.cdc[i] = &usb_dev->usbd_cdc_itf[i].base; + } 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) - USBD_SetVIDPIDRelease(&usb_dev->usbd_cdc_msc_hid_state, vid, pid, 0x0200, mode == USBD_MODE_CDC); + int cdc_only = (mode & USBD_MODE_IFACE_MASK) == USBD_MODE_CDC; + USBD_SetVIDPIDRelease(&usb_dev->usbd_cdc_msc_hid_state, vid, pid, 0x0200, cdc_only); if (USBD_SelectMode(&usb_dev->usbd_cdc_msc_hid_state, mode, hid_info) != 0) { return false; } @@ -157,7 +155,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, high_speed); + USBD_LL_Init(usbd, (mode & USBD_MODE_HIGH_SPEED) != 0); USBD_LL_Start(usbd); usb_dev->enabled = true; } @@ -179,22 +177,17 @@ bool usb_vcp_is_enabled(void) { } int usb_vcp_recv_byte(uint8_t *c) { - return usbd_cdc_rx(&usb_device.usbd_cdc_itf, c, 1, 0); + return usbd_cdc_rx(&usb_device.usbd_cdc_itf[0], c, 1, 0); } void usb_vcp_send_strn(const char *str, int len) { if (usb_device.enabled) { - usbd_cdc_tx_always(&usb_device.usbd_cdc_itf, (const uint8_t*)str, len); + usbd_cdc_tx_always(&usb_device.usbd_cdc_itf[0], (const uint8_t*)str, 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; + return &usb_device.usbd_cdc_itf[idx]; } /******************************************************************************/ @@ -243,7 +236,7 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * return MP_OBJ_NEW_QSTR(MP_QSTR_host); #else uint8_t mode = USBD_GetMode(&usb_device.usbd_cdc_msc_hid_state); - switch (mode) { + switch (mode & USBD_MODE_IFACE_MASK) { case USBD_MODE_CDC: return MP_OBJ_NEW_QSTR(MP_QSTR_VCP); case USBD_MODE_MSC: @@ -298,13 +291,13 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * // note: we support CDC as a synonym for VCP for backward compatibility uint16_t vid = args[1].u_int; uint16_t pid = args[2].u_int; - usb_device_mode_t mode; + uint8_t mode; if (strcmp(mode_str, "CDC+MSC") == 0 || strcmp(mode_str, "VCP+MSC") == 0) { if (args[2].u_int == -1) { pid = USBD_PID_CDC_MSC; } mode = USBD_MODE_CDC_MSC; - #if MICROPY_HW_USB_ENABLE_CDC2 + #if MICROPY_HW_USB_CDC_NUM >= 2 } else if (strcmp(mode_str, "VCP+VCP") == 0) { if (args[2].u_int == -1) { pid = USBD_PID_CDC2; @@ -337,7 +330,7 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * // get hid info if user selected such a mode USBD_HID_ModeInfoTypeDef hid_info; - if (mode & USBD_MODE_HID) { + if (mode & USBD_MODE_IFACE_HID) { mp_obj_t *items; mp_obj_get_array_fixed_n(args[3].u_obj, 5, &items); hid_info.subclass = mp_obj_get_int(items[0]); @@ -388,13 +381,21 @@ typedef struct _pyb_usb_vcp_obj_t { usbd_cdc_itf_t *cdc_itf; } pyb_usb_vcp_obj_t; -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 +const pyb_usb_vcp_obj_t pyb_usb_vcp_obj[MICROPY_HW_USB_CDC_NUM] = { + {{&pyb_usb_vcp_type}, &usb_device.usbd_cdc_itf[0]}, + #if MICROPY_HW_USB_CDC_NUM >= 2 + {{&pyb_usb_vcp_type}, &usb_device.usbd_cdc_itf[1]}, + #endif +}; + +STATIC void pyb_usb_vcp_init0(void) { + // Activate USB_VCP(0) on dupterm slot 1 for the REPL + MP_STATE_VM(dupterm_objs[1]) = MP_OBJ_FROM_PTR(&pyb_usb_vcp_obj[0]); + usb_vcp_attach_to_repl(&pyb_usb_vcp_obj[0], true); +} STATIC void pyb_usb_vcp_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - int id = ((pyb_usb_vcp_obj_t*)MP_OBJ_TO_PTR(self_in))->cdc_itf - &usb_device.usbd_cdc_itf; + int id = ((pyb_usb_vcp_obj_t*)MP_OBJ_TO_PTR(self_in))->cdc_itf - &usb_device.usbd_cdc_itf[0]; mp_printf(print, "USB_VCP(%u)", id); } @@ -411,12 +412,8 @@ STATIC mp_obj_t pyb_usb_vcp_make_new(const mp_obj_type_t *type, size_t n_args, s // TODO raise exception if USB is not configured for VCP 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 + if (0 <= id && id < MICROPY_HW_USB_CDC_NUM) { + return MP_OBJ_FROM_PTR(&pyb_usb_vcp_obj[id]); } else { mp_raise_ValueError(NULL); } @@ -457,7 +454,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_FROM_PTR(&pyb_usb_vcp_obj)); + return pyb_usb_vcp_isconnected(MP_OBJ_FROM_PTR(&pyb_usb_vcp_obj[0])); } MP_DEFINE_CONST_FUN_OBJ_0(pyb_have_cdc_obj, pyb_have_cdc); diff --git a/ports/stm32/usb.h b/ports/stm32/usb.h index 3d57bf9129..6678e1e173 100644 --- a/ports/stm32/usb.h +++ b/ports/stm32/usb.h @@ -58,14 +58,13 @@ extern const struct _mp_rom_obj_tuple_t pyb_usb_hid_mouse_obj; extern const struct _mp_rom_obj_tuple_t pyb_usb_hid_keyboard_obj; extern const mp_obj_type_t pyb_usb_vcp_type; extern const mp_obj_type_t pyb_usb_hid_type; -extern const pyb_usb_vcp_obj_t pyb_usb_vcp_obj; MP_DECLARE_CONST_FUN_OBJ_KW(pyb_usb_mode_obj); MP_DECLARE_CONST_FUN_OBJ_0(pyb_have_cdc_obj); // deprecated MP_DECLARE_CONST_FUN_OBJ_1(pyb_hid_send_report_obj); // deprecated 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); +bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, uint8_t mode, USBD_HID_ModeInfoTypeDef *hid_info); void pyb_usb_dev_deinit(void); bool usb_vcp_is_enabled(void); int usb_vcp_recv_byte(uint8_t *c); // if a byte is available, return 1 and put the byte in *c, else return 0 diff --git a/ports/stm32/usbd_cdc_interface.c b/ports/stm32/usbd_cdc_interface.c index 4a4a8beb85..49f0deec71 100644 --- a/ports/stm32/usbd_cdc_interface.c +++ b/ports/stm32/usbd_cdc_interface.c @@ -217,18 +217,13 @@ void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) { } else { usbd_cdc_msc_hid_state_t *usbd = ((USBD_HandleTypeDef*)hpcd->pData)->pClassData; hpcd->Instance->GINTMSK &= ~USB_OTG_GINTMSK_SOFM; - usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t*)usbd->cdc; - if (cdc->connect_state == USBD_CDC_CONNECT_STATE_CONNECTING) { - cdc->connect_state = USBD_CDC_CONNECT_STATE_CONNECTED; - usbd_cdc_try_tx(cdc); + for (int i = 0; i < MICROPY_HW_USB_CDC_NUM; ++i) { + usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t*)usbd->cdc[i]; + if (cdc->connect_state == USBD_CDC_CONNECT_STATE_CONNECTING) { + cdc->connect_state = USBD_CDC_CONNECT_STATE_CONNECTED; + usbd_cdc_try_tx(cdc); + } } - #if MICROPY_HW_USB_ENABLE_CDC2 - cdc = (usbd_cdc_itf_t*)usbd->cdc2; - if (cdc->connect_state == USBD_CDC_CONNECT_STATE_CONNECTING) { - cdc->connect_state = USBD_CDC_CONNECT_STATE_CONNECTED; - usbd_cdc_try_tx(cdc); - } - #endif } } diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c index b7c1665f0a..c2e86ccb5b 100644 --- a/ports/stm32/usbd_conf.c +++ b/ports/stm32/usbd_conf.c @@ -334,7 +334,7 @@ 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 + #if MICROPY_HW_USB_CDC_NUM == 2 pcd_fs_handle.Init.dev_endpoints = 6; #else pcd_fs_handle.Init.dev_endpoints = 4; @@ -364,7 +364,7 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { HAL_PCD_Init(&pcd_fs_handle); // We have 320 32-bit words in total to use here - #if MICROPY_HW_USB_ENABLE_CDC2 + #if MICROPY_HW_USB_CDC_NUM == 2 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 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 1857273e07..f20485a7c0 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h @@ -18,12 +18,13 @@ #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 -#if MICROPY_HW_USB_ENABLE_CDC2 +// Should be maximum of possible config descriptors that might be configured +#if MICROPY_HW_USB_CDC_NUM == 2 +// Maximum is MSC+CDC+CDC #define MAX_TEMPLATE_CONFIG_DESC_SIZE (9 + 23 + (8 + 58) + (8 + 58)) #else -#define MAX_TEMPLATE_CONFIG_DESC_SIZE (107) +// Maximum is HID+CDC +#define MAX_TEMPLATE_CONFIG_DESC_SIZE (9 + 32 + (8 + 58)) #endif // CDC, MSC and HID packet sizes @@ -124,10 +125,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; - usbd_cdc_state_t *cdc; - #if MICROPY_HW_USB_ENABLE_CDC2 - usbd_cdc_state_t *cdc2; - #endif + usbd_cdc_state_t *cdc[MICROPY_HW_USB_CDC_NUM]; 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 c876dcf298..1cb879180d 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h @@ -29,18 +29,22 @@ // these are exports for the CDC/MSC/HID interface that are independent // from any other definitions/declarations -// only CDC_MSC and CDC_HID are available -typedef enum { - USBD_MODE_CDC = 0x01, - USBD_MODE_MSC = 0x02, - USBD_MODE_HID = 0x04, - 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; +// These can be or'd together (but not all combinations may be available) +#define USBD_MODE_IFACE_MASK (0x7f) +#define USBD_MODE_IFACE_CDC(i) (0x01 << (i)) +#define USBD_MODE_IFACE_HID (0x10) +#define USBD_MODE_IFACE_MSC (0x20) +#define USBD_MODE_HIGH_SPEED (0x80) + +// Convenience macros for supported mode combinations +#define USBD_MODE_CDC (USBD_MODE_IFACE_CDC(0)) +#define USBD_MODE_CDC2 (USBD_MODE_IFACE_CDC(0) | USBD_MODE_IFACE_CDC(1)) +#define USBD_MODE_CDC_HID (USBD_MODE_IFACE_CDC(0) | USBD_MODE_IFACE_HID) +#define USBD_MODE_CDC_MSC (USBD_MODE_IFACE_CDC(0) | USBD_MODE_IFACE_MSC) +#define USBD_MODE_CDC2_MSC (USBD_MODE_IFACE_CDC(0) | USBD_MODE_IFACE_CDC(1) | USBD_MODE_IFACE_MSC) +#define USBD_MODE_HID (USBD_MODE_IFACE_HID) +#define USBD_MODE_MSC (USBD_MODE_IFACE_MSC) +#define USBD_MODE_MSC_HID (USBD_MODE_IFACE_MSC | USBD_MODE_IFACE_HID) typedef struct _USBD_HID_ModeInfoTypeDef { uint8_t subclass; // 0=no sub class, 1=boot 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 47436a4b63..bfb5d3058a 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -38,6 +38,8 @@ #define MSC_TEMPLATE_MSC_DESC_OFFSET (9) #define CDC_MSC_TEMPLATE_MSC_DESC_OFFSET (9) #define CDC_MSC_TEMPLATE_CDC_DESC_OFFSET (40) +#define CDC2_TEMPLATE_CDC_DESC_OFFSET (9 + 8) +#define CDC2_TEMPLATE_CDC2_DESC_OFFSET (9 + (8 + 58) + 8) #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) @@ -69,13 +71,9 @@ #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 CDC2_IN_EP (0x85) -#define CDC2_OUT_EP (0x05) -#define CDC2_CMD_EP (0x84) +#define CDC_IN_EP(i) (0x83 + 2 * (i)) +#define CDC_OUT_EP(i) (0x03 + 2 * (i)) +#define CDC_CMD_EP(i) (0x82 + 2 * (i)) #define HID_IN_EP_WITH_CDC (0x81) #define HID_OUT_EP_WITH_CDC (0x01) @@ -232,7 +230,7 @@ static const uint8_t cdc_class_desc_data[CDC_CLASS_DESC_SIZE] = { // Endpoint CMD Descriptor 0x07, // bLength: Endpoint Descriptor size USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint - CDC_CMD_EP, // bEndpointAddress + CDC_CMD_EP(0), // bEndpointAddress 0x03, // bmAttributes: Interrupt LOBYTE(CDC_CMD_PACKET_SIZE), // wMaxPacketSize: HIBYTE(CDC_CMD_PACKET_SIZE), @@ -253,7 +251,7 @@ static const uint8_t cdc_class_desc_data[CDC_CLASS_DESC_SIZE] = { // Endpoint OUT Descriptor 0x07, // bLength: Endpoint Descriptor size USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint - CDC_OUT_EP, // bEndpointAddress + CDC_OUT_EP(0), // bEndpointAddress 0x02, // bmAttributes: Bulk LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),// wMaxPacketSize: HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), @@ -262,7 +260,7 @@ static const uint8_t cdc_class_desc_data[CDC_CLASS_DESC_SIZE] = { // Endpoint IN Descriptor 0x07, // bLength: Endpoint Descriptor size USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint - CDC_IN_EP, // bEndpointAddress + CDC_IN_EP(0), // bEndpointAddress 0x02, // bmAttributes: Bulk LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),// wMaxPacketSize: HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), @@ -421,7 +419,7 @@ static size_t make_cdc_desc(uint8_t *dest, int need_iad, uint8_t iface_num) { return need_iad ? 8 + 58 : 58; } -#if MICROPY_HW_USB_ENABLE_CDC2 +#if MICROPY_HW_USB_CDC_NUM >= 2 static size_t make_cdc_desc_ep(uint8_t *dest, int need_iad, uint8_t iface_num, uint8_t cmd_ep, uint8_t out_ep, uint8_t in_ep) { size_t n = make_cdc_desc(dest, need_iad, iface_num); if (need_iad) { @@ -461,7 +459,7 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode size_t n = HEAD_DESC_SIZE; uint8_t *d = usbd->usbd_config_desc; uint8_t num_itf = 0; - switch (usbd->usbd_mode) { + switch (usbd->usbd_mode & USBD_MODE_IFACE_MASK) { case USBD_MODE_MSC: n += make_msc_desc(d + n); num_itf = 1; @@ -470,19 +468,16 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode case USBD_MODE_CDC_MSC: n += make_msc_desc(d + n); n += make_cdc_desc(d + n, 1, CDC_IFACE_NUM_WITH_MSC); - usbd->cdc->iface_num = CDC_IFACE_NUM_WITH_MSC; + usbd->cdc[0]->iface_num = CDC_IFACE_NUM_WITH_MSC; num_itf = 3; break; - #if MICROPY_HW_USB_ENABLE_CDC2 + #if MICROPY_HW_USB_CDC_NUM >= 2 case USBD_MODE_CDC2: { - // Ensure the first interface is also enabled - usbd->usbd_mode |= USBD_MODE_CDC; - n += make_cdc_desc(d + n, 1, CDC_IFACE_NUM_ALONE); - n += make_cdc_desc_ep(d + n, 1, CDC2_IFACE_NUM_WITH_CDC, CDC2_CMD_EP, CDC2_OUT_EP, CDC2_IN_EP); - usbd->cdc->iface_num = CDC_IFACE_NUM_ALONE; - usbd->cdc2->iface_num = CDC2_IFACE_NUM_WITH_CDC; + n += make_cdc_desc_ep(d + n, 1, CDC2_IFACE_NUM_WITH_CDC, CDC_CMD_EP(1), CDC_OUT_EP(1), CDC_IN_EP(1)); + usbd->cdc[0]->iface_num = CDC_IFACE_NUM_ALONE; + usbd->cdc[1]->iface_num = CDC2_IFACE_NUM_WITH_CDC; num_itf = 4; break; } @@ -490,9 +485,9 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode case USBD_MODE_CDC2_MSC: { n += make_msc_desc(d + n); n += make_cdc_desc(d + n, 1, CDC_IFACE_NUM_WITH_MSC); - n += make_cdc_desc_ep(d + n, 1, CDC2_IFACE_NUM_WITH_MSC, CDC2_CMD_EP, CDC2_OUT_EP, CDC2_IN_EP); - usbd->cdc->iface_num = CDC_IFACE_NUM_WITH_MSC; - usbd->cdc2->iface_num = CDC2_IFACE_NUM_WITH_MSC; + n += make_cdc_desc_ep(d + n, 1, CDC2_IFACE_NUM_WITH_MSC, CDC_CMD_EP(1), CDC_OUT_EP(1), CDC_IN_EP(1)); + usbd->cdc[0]->iface_num = CDC_IFACE_NUM_WITH_MSC; + usbd->cdc[1]->iface_num = CDC2_IFACE_NUM_WITH_MSC; num_itf = 5; break; } @@ -502,7 +497,7 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode usbd->hid->desc = d + n; n += make_hid_desc(d + n, hid_info); n += make_cdc_desc(d + n, 1, CDC_IFACE_NUM_WITH_HID); - usbd->cdc->iface_num = CDC_IFACE_NUM_WITH_HID; + usbd->cdc[0]->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; @@ -512,7 +507,7 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode case USBD_MODE_CDC: n += make_cdc_desc(d + n, 0, CDC_IFACE_NUM_ALONE); - usbd->cdc->iface_num = CDC_IFACE_NUM_ALONE; + usbd->cdc[0]->iface_num = CDC_IFACE_NUM_ALONE; num_itf = 2; break; @@ -533,18 +528,13 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode make_head_desc(d, n, num_itf); usbd->usbd_config_desc_size = n; - if (usbd->usbd_mode & USBD_MODE_CDC) { - usbd->cdc->in_ep = CDC_IN_EP; - usbd->cdc->out_ep = CDC_OUT_EP; + for (int i = 0; i < MICROPY_HW_USB_CDC_NUM; ++i) { + if (usbd->usbd_mode & USBD_MODE_IFACE_CDC(i)) { + usbd->cdc[i]->in_ep = CDC_IN_EP(i); + usbd->cdc[i]->out_ep = CDC_OUT_EP(i); + } } - #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 - return 0; } @@ -578,19 +568,14 @@ static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData; - if (usbd->usbd_mode & USBD_MODE_CDC) { - // CDC VCP component - usbd_cdc_state_init(pdev, usbd, usbd->cdc, CDC_CMD_EP); + // CDC VCP component(s) + for (int i = 0; i < MICROPY_HW_USB_CDC_NUM; ++i) { + if (usbd->usbd_mode & USBD_MODE_IFACE_CDC(i)) { + usbd_cdc_state_init(pdev, usbd, usbd->cdc[i], CDC_CMD_EP(i)); + } } - #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) { + if (usbd->usbd_mode & USBD_MODE_IFACE_MSC) { // MSC component int mp = usbd_msc_max_packet(pdev); @@ -611,7 +596,7 @@ static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { MSC_BOT_Init(pdev); } - if (usbd->usbd_mode & USBD_MODE_HID) { + if (usbd->usbd_mode & USBD_MODE_IFACE_HID) { // HID component // get max packet lengths from descriptor @@ -644,31 +629,20 @@ static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { static uint8_t USBD_CDC_MSC_HID_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData; - if ((usbd->usbd_mode & USBD_MODE_CDC) && usbd->cdc) { - // CDC VCP component + for (int i = 0; i < MICROPY_HW_USB_CDC_NUM; ++i) { + if ((usbd->usbd_mode & USBD_MODE_IFACE_CDC(i)) && usbd->cdc[i]) { + // CDC VCP component - usbd_cdc_deinit(usbd->cdc); + usbd_cdc_deinit(usbd->cdc[i]); - // close endpoints - USBD_LL_CloseEP(pdev, CDC_IN_EP); - USBD_LL_CloseEP(pdev, CDC_OUT_EP); - USBD_LL_CloseEP(pdev, CDC_CMD_EP); + // close endpoints + USBD_LL_CloseEP(pdev, CDC_IN_EP(i)); + USBD_LL_CloseEP(pdev, CDC_OUT_EP(i)); + USBD_LL_CloseEP(pdev, CDC_CMD_EP(i)); + } } - #if MICROPY_HW_USB_ENABLE_CDC2 - if ((usbd->usbd_mode & USBD_MODE_CDC2) && usbd->cdc2) { - // CDC VCP #2 component - - usbd_cdc_deinit(usbd->cdc2); - - // 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) { + if (usbd->usbd_mode & USBD_MODE_IFACE_MSC) { // MSC component // close endpoints @@ -679,7 +653,7 @@ static uint8_t USBD_CDC_MSC_HID_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx) MSC_BOT_DeInit(pdev); } - if (usbd->usbd_mode & USBD_MODE_HID) { + if (usbd->usbd_mode & USBD_MODE_IFACE_HID) { // HID component // close endpoints @@ -717,35 +691,35 @@ 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) { - 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) { + if ((mode & USBD_MODE_IFACE_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_IFACE_HID) && iface == usbd->hid->iface_num) { recipient = USBD_MODE_HID; + } else { + for (int i = 0; i < MICROPY_HW_USB_CDC_NUM; ++i) { + if ((mode & USBD_MODE_IFACE_CDC(i)) && iface == usbd->cdc[i]->iface_num) { + recipient = USBD_MODE_CDC; + cdc = usbd->cdc[i]; + break; + } + } } 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; - 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) { + if ((mode & USBD_MODE_IFACE_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_IFACE_HID) && ep == usbd->hid->out_ep) { recipient = USBD_MODE_HID; + } else { + for (int i = 0; i < MICROPY_HW_USB_CDC_NUM; ++i) { + if ((mode & USBD_MODE_IFACE_CDC(i)) && (ep == CDC_OUT_EP(i) || ep == (CDC_CMD_EP(i) & 0x7f))) { + recipient = USBD_MODE_CDC; + cdc = usbd->cdc[i]; + break; + } + } } break; } @@ -894,36 +868,32 @@ 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->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; + for (int i = 0; i < MICROPY_HW_USB_CDC_NUM; ++i) { + if (usbd->cdc[i] != NULL && usbd->cdc[i]->cur_request != 0xff) { + usbd_cdc_control(usbd->cdc[i], usbd->cdc[i]->cur_request, (uint8_t*)usbd->cdc[i]->ctl_packet_buf, usbd->cdc[i]->cur_length); + usbd->cdc[i]->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; } 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->tx_in_progress = 0; - usbd_cdc_tx_ready(usbd->cdc); - 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; - usbd_cdc_tx_ready(usbd->cdc2); - return USBD_OK; - #endif - } else if ((usbd->usbd_mode & USBD_MODE_MSC) && epnum == (MSC_IN_EP & 0x7f)) { + + for (int i = 0; i < MICROPY_HW_USB_CDC_NUM; ++i) { + if ((usbd->usbd_mode & USBD_MODE_IFACE_CDC(i)) && (epnum == (CDC_IN_EP(i) & 0x7f) || epnum == (CDC_CMD_EP(i) & 0x7f))) { + usbd->cdc[i]->tx_in_progress = 0; + usbd_cdc_tx_ready(usbd->cdc[i]); + return USBD_OK; + } + } + + if ((usbd->usbd_mode & USBD_MODE_IFACE_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)) { + } + + if ((usbd->usbd_mode & USBD_MODE_IFACE_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->state = HID_IDLE; @@ -935,26 +905,23 @@ static uint8_t USBD_CDC_MSC_HID_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum) static uint8_t USBD_CDC_MSC_HID_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) { usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData; - if ((usbd->usbd_mode & USBD_MODE_CDC) && epnum == (CDC_OUT_EP & 0x7f)) { - /* Get the received data length */ - size_t len = USBD_LL_GetRxDataSize (pdev, epnum); - /* USB data will be immediately processed, this allow next USB traffic being - NAKed till the end of the application Xfer */ - return usbd_cdc_receive(usbd->cdc, len); + for (int i = 0; i < MICROPY_HW_USB_CDC_NUM; ++i) { + if ((usbd->usbd_mode & USBD_MODE_IFACE_CDC(i)) && epnum == (CDC_OUT_EP(i) & 0x7f)) { + size_t len = USBD_LL_GetRxDataSize(pdev, epnum); + // USB data will be immediately processed, and next USB traffic is NAKed until it's done + return usbd_cdc_receive(usbd->cdc[i], len); + } + } - #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); - return usbd_cdc_receive(usbd->cdc2, len); - - #endif - } else if ((usbd->usbd_mode & USBD_MODE_MSC) && epnum == (MSC_OUT_EP & 0x7f)) { + if ((usbd->usbd_mode & USBD_MODE_IFACE_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)) { + } + + if ((usbd->usbd_mode & USBD_MODE_IFACE_HID) && epnum == (usbd->hid->out_ep & 0x7f)) { size_t len = USBD_LL_GetRxDataSize(pdev, epnum); - usbd_hid_receive(usbd->hid, len); + return usbd_hid_receive(usbd->hid, len); } return USBD_OK; @@ -981,49 +948,47 @@ static uint8_t *USBD_CDC_MSC_HID_GetCfgDesc(USBD_HandleTypeDef *pdev, uint16_t * 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 *cdc_desc[MICROPY_HW_USB_CDC_NUM] = {0}; uint8_t *msc_desc = NULL; - switch (usbd->usbd_mode) { + switch (usbd->usbd_mode & USBD_MODE_IFACE_MASK) { 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; + cdc_desc[0] = usbd->usbd_config_desc + CDC_MSC_TEMPLATE_CDC_DESC_OFFSET; msc_desc = usbd->usbd_config_desc + CDC_MSC_TEMPLATE_MSC_DESC_OFFSET; break; - #if MICROPY_HW_USB_ENABLE_CDC2 + #if MICROPY_HW_USB_CDC_NUM >= 2 + case USBD_MODE_CDC2: + cdc_desc[0] = usbd->usbd_config_desc + CDC2_TEMPLATE_CDC_DESC_OFFSET; + cdc_desc[1] = usbd->usbd_config_desc + CDC2_TEMPLATE_CDC2_DESC_OFFSET; + break; + 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; + cdc_desc[0] = usbd->usbd_config_desc + CDC2_MSC_TEMPLATE_CDC_DESC_OFFSET; + cdc_desc[1] = 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; + cdc_desc[0] = 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; + cdc_desc[0] = usbd->usbd_config_desc + CDC_TEMPLATE_CDC_DESC_OFFSET; break; } // configure CDC descriptors, if needed - if (cdc_desc != NULL) { - usbd_cdc_desc_config_max_packet(pdev, cdc_desc); + for (int i = 0; i < MICROPY_HW_USB_CDC_NUM; ++i) { + if (cdc_desc[i] != NULL) { + usbd_cdc_desc_config_max_packet(pdev, cdc_desc[i]); + } } - #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); From ff91b05cfa8154d1a4d098423dfa95d14ade4271 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 30 May 2019 17:16:15 +1000 Subject: [PATCH 0401/1788] stm32/usb: Support up to 3 VCP interfaces on USB device peripheral. To enable define MICROPY_HW_USB_CDC_NUM to 3. --- ports/stm32/usb.c | 15 ++++++ ports/stm32/usb.h | 2 + ports/stm32/usbd_conf.c | 12 +++++ ports/stm32/usbd_conf.h | 2 +- .../stm32/usbdev/class/inc/usbd_cdc_msc_hid.h | 5 +- .../usbdev/class/inc/usbd_cdc_msc_hid0.h | 2 + .../stm32/usbdev/class/src/usbd_cdc_msc_hid.c | 49 +++++++++++++++++++ 7 files changed, 85 insertions(+), 2 deletions(-) diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index c9c22d5d2b..ace090f804 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -309,6 +309,18 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * } mode = USBD_MODE_CDC2_MSC; #endif + #if MICROPY_HW_USB_CDC_NUM >= 3 + } else if (strcmp(mode_str, "3xVCP") == 0) { + if (args[2].u_int == -1) { + pid = USBD_PID_CDC3; + } + mode = USBD_MODE_CDC3; + } else if (strcmp(mode_str, "3xVCP+MSC") == 0) { + if (args[2].u_int == -1) { + pid = USBD_PID_CDC3_MSC; + } + mode = USBD_MODE_CDC3_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; @@ -386,6 +398,9 @@ const pyb_usb_vcp_obj_t pyb_usb_vcp_obj[MICROPY_HW_USB_CDC_NUM] = { #if MICROPY_HW_USB_CDC_NUM >= 2 {{&pyb_usb_vcp_type}, &usb_device.usbd_cdc_itf[1]}, #endif + #if MICROPY_HW_USB_CDC_NUM >= 3 + {{&pyb_usb_vcp_type}, &usb_device.usbd_cdc_itf[2]}, + #endif }; STATIC void pyb_usb_vcp_init0(void) { diff --git a/ports/stm32/usb.h b/ports/stm32/usb.h index 6678e1e173..0aa50f9e77 100644 --- a/ports/stm32/usb.h +++ b/ports/stm32/usb.h @@ -38,6 +38,8 @@ #define USBD_PID_MSC (0x9803) #define USBD_PID_CDC2_MSC (0x9804) #define USBD_PID_CDC2 (0x9805) +#define USBD_PID_CDC3 (0x9806) +#define USBD_PID_CDC3_MSC (0x9807) typedef enum { PYB_USB_STORAGE_MEDIUM_NONE = 0, diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c index c2e86ccb5b..ed99700e99 100644 --- a/ports/stm32/usbd_conf.c +++ b/ports/stm32/usbd_conf.c @@ -385,7 +385,11 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { if (pdev->id == USB_PHY_HS_ID) { // Set LL Driver parameters pcd_hs_handle.Instance = USB_OTG_HS; + #if MICROPY_HW_USB_CDC_NUM == 3 + pcd_hs_handle.Init.dev_endpoints = 8; + #else pcd_hs_handle.Init.dev_endpoints = 6; + #endif pcd_hs_handle.Init.use_dedicated_ep1 = 0; pcd_hs_handle.Init.ep0_mps = 0x40; pcd_hs_handle.Init.dma_enable = 0; @@ -431,13 +435,21 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { HAL_PCD_Init(&pcd_hs_handle); // We have 1024 32-bit words in total to use here + #if MICROPY_HW_USB_CDC_NUM == 3 + HAL_PCD_SetRxFiFo(&pcd_hs_handle, 328); + #else HAL_PCD_SetRxFiFo(&pcd_hs_handle, 464); + #endif 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, 8); // CDC CMD HAL_PCD_SetTxFiFo(&pcd_hs_handle, 3, 128); // CDC DATA HAL_PCD_SetTxFiFo(&pcd_hs_handle, 4, 8); // CDC2 CMD HAL_PCD_SetTxFiFo(&pcd_hs_handle, 5, 128); // CDC2 DATA + #if MICROPY_HW_USB_CDC_NUM == 3 + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 6, 8); // CDC3 CMD + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 7, 128); // CDC3 DATA + #endif } #endif // MICROPY_HW_USB_HS diff --git a/ports/stm32/usbd_conf.h b/ports/stm32/usbd_conf.h index c5faf6c8c8..639b54d9f3 100644 --- a/ports/stm32/usbd_conf.h +++ b/ports/stm32/usbd_conf.h @@ -39,7 +39,7 @@ #include "py/mpconfig.h" -#define USBD_MAX_NUM_INTERFACES 4 +#define USBD_MAX_NUM_INTERFACES 5 #define USBD_MAX_NUM_CONFIGURATION 1 #define USBD_MAX_STR_DESC_SIZ 0x100 #if MICROPY_HW_USB_SELF_POWERED 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 f20485a7c0..d4a218a4a6 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h @@ -19,7 +19,10 @@ #endif // Should be maximum of possible config descriptors that might be configured -#if MICROPY_HW_USB_CDC_NUM == 2 +#if MICROPY_HW_USB_CDC_NUM == 3 +// Maximum is MSC+CDC+CDC+CDC +#define MAX_TEMPLATE_CONFIG_DESC_SIZE (9 + 23 + (8 + 58) + (8 + 58) + (8 + 58)) +#elif MICROPY_HW_USB_CDC_NUM == 2 // Maximum is MSC+CDC+CDC #define MAX_TEMPLATE_CONFIG_DESC_SIZE (9 + 23 + (8 + 58) + (8 + 58)) #else 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 1cb879180d..63fe8ecefc 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h @@ -39,9 +39,11 @@ // Convenience macros for supported mode combinations #define USBD_MODE_CDC (USBD_MODE_IFACE_CDC(0)) #define USBD_MODE_CDC2 (USBD_MODE_IFACE_CDC(0) | USBD_MODE_IFACE_CDC(1)) +#define USBD_MODE_CDC3 (USBD_MODE_IFACE_CDC(0) | USBD_MODE_IFACE_CDC(1) | USBD_MODE_IFACE_CDC(2)) #define USBD_MODE_CDC_HID (USBD_MODE_IFACE_CDC(0) | USBD_MODE_IFACE_HID) #define USBD_MODE_CDC_MSC (USBD_MODE_IFACE_CDC(0) | USBD_MODE_IFACE_MSC) #define USBD_MODE_CDC2_MSC (USBD_MODE_IFACE_CDC(0) | USBD_MODE_IFACE_CDC(1) | USBD_MODE_IFACE_MSC) +#define USBD_MODE_CDC3_MSC (USBD_MODE_IFACE_CDC(0) | USBD_MODE_IFACE_CDC(1) | USBD_MODE_IFACE_CDC(2) | USBD_MODE_IFACE_MSC) #define USBD_MODE_HID (USBD_MODE_IFACE_HID) #define USBD_MODE_MSC (USBD_MODE_IFACE_MSC) #define USBD_MODE_MSC_HID (USBD_MODE_IFACE_MSC | USBD_MODE_IFACE_HID) 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 bfb5d3058a..d982fe8e6f 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -43,6 +43,13 @@ #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 CDC3_TEMPLATE_CDC_DESC_OFFSET (9 + 8) +#define CDC3_TEMPLATE_CDC2_DESC_OFFSET (9 + (8 + 58) + 8) +#define CDC3_TEMPLATE_CDC3_DESC_OFFSET (9 + (8 + 58) + (8 + 58) + 8) +#define CDC3_MSC_TEMPLATE_MSC_DESC_OFFSET (9) +#define CDC3_MSC_TEMPLATE_CDC_DESC_OFFSET (9 + 23 + 8) +#define CDC3_MSC_TEMPLATE_CDC2_DESC_OFFSET (9 + 23 + (8 + 58) + 8) +#define CDC3_MSC_TEMPLATE_CDC3_DESC_OFFSET (9 + 23 + (8 + 58) + (8 + 58) + 8) #define CDC_HID_TEMPLATE_CDC_DESC_OFFSET (49) #define CDC_TEMPLATE_CDC_DESC_OFFSET (9) #define CDC_DESC_OFFSET_INTR_INTERVAL (34) @@ -65,7 +72,9 @@ #define CDC_IFACE_NUM_ALONE (0) #define CDC_IFACE_NUM_WITH_MSC (1) #define CDC2_IFACE_NUM_WITH_CDC (2) +#define CDC3_IFACE_NUM_WITH_CDC (4) #define CDC2_IFACE_NUM_WITH_MSC (3) +#define CDC3_IFACE_NUM_WITH_MSC (5) #define CDC_IFACE_NUM_WITH_HID (1) #define MSC_IFACE_NUM_WITH_CDC (0) #define HID_IFACE_NUM_WITH_CDC (0) @@ -493,6 +502,31 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode } #endif + #if MICROPY_HW_USB_CDC_NUM >= 3 + case USBD_MODE_CDC3: { + n += make_cdc_desc(d + n, 1, CDC_IFACE_NUM_ALONE); + n += make_cdc_desc_ep(d + n, 1, CDC2_IFACE_NUM_WITH_CDC, CDC_CMD_EP(1), CDC_OUT_EP(1), CDC_IN_EP(1)); + n += make_cdc_desc_ep(d + n, 1, CDC3_IFACE_NUM_WITH_CDC, CDC_CMD_EP(2), CDC_OUT_EP(2), CDC_IN_EP(2)); + usbd->cdc[0]->iface_num = CDC_IFACE_NUM_ALONE; + usbd->cdc[1]->iface_num = CDC2_IFACE_NUM_WITH_CDC; + usbd->cdc[2]->iface_num = CDC3_IFACE_NUM_WITH_CDC; + num_itf = 6; + break; + } + + case USBD_MODE_CDC3_MSC: { + n += make_msc_desc(d + n); + n += make_cdc_desc(d + n, 1, CDC_IFACE_NUM_WITH_MSC); + n += make_cdc_desc_ep(d + n, 1, CDC2_IFACE_NUM_WITH_MSC, CDC_CMD_EP(1), CDC_OUT_EP(1), CDC_IN_EP(1)); + n += make_cdc_desc_ep(d + n, 1, CDC3_IFACE_NUM_WITH_MSC, CDC_CMD_EP(2), CDC_OUT_EP(2), CDC_IN_EP(2)); + usbd->cdc[0]->iface_num = CDC_IFACE_NUM_WITH_MSC; + usbd->cdc[1]->iface_num = CDC2_IFACE_NUM_WITH_MSC; + usbd->cdc[2]->iface_num = CDC3_IFACE_NUM_WITH_MSC; + num_itf = 7; + break; + } + #endif + case USBD_MODE_CDC_HID: usbd->hid->desc = d + n; n += make_hid_desc(d + n, hid_info); @@ -973,6 +1007,21 @@ static uint8_t *USBD_CDC_MSC_HID_GetCfgDesc(USBD_HandleTypeDef *pdev, uint16_t * break; #endif + #if MICROPY_HW_USB_CDC_NUM >= 3 + case USBD_MODE_CDC3: + cdc_desc[0] = usbd->usbd_config_desc + CDC3_TEMPLATE_CDC_DESC_OFFSET; + cdc_desc[1] = usbd->usbd_config_desc + CDC3_TEMPLATE_CDC2_DESC_OFFSET; + cdc_desc[2] = usbd->usbd_config_desc + CDC3_TEMPLATE_CDC3_DESC_OFFSET; + break; + + case USBD_MODE_CDC3_MSC: + cdc_desc[0] = usbd->usbd_config_desc + CDC3_MSC_TEMPLATE_CDC_DESC_OFFSET; + cdc_desc[1] = usbd->usbd_config_desc + CDC3_MSC_TEMPLATE_CDC2_DESC_OFFSET; + cdc_desc[2] = usbd->usbd_config_desc + CDC3_MSC_TEMPLATE_CDC3_DESC_OFFSET; + msc_desc = usbd->usbd_config_desc + CDC3_MSC_TEMPLATE_MSC_DESC_OFFSET; + break; + #endif + case USBD_MODE_CDC_HID: cdc_desc[0] = usbd->usbd_config_desc + CDC_HID_TEMPLATE_CDC_DESC_OFFSET; break; From de76f73d34a63fa34c520125f226e0c159ce0b10 Mon Sep 17 00:00:00 2001 From: Martin Dybdal Date: Fri, 24 May 2019 13:19:26 +0200 Subject: [PATCH 0402/1788] esp32/machine_timer: Reuse Timer handles, deallocate only on soft-reset. The patch solves the problem where multiple Timer objects (e.g. multiple Timer(0) instances) could initialise multiple handles to the same internal timer. The list of timers is now maintained not for "active" timers (where init is called), but for all timers created. The timers are only removed from the list of timers on soft-reset (machine_timer_deinit_all). Fixes #4078. --- ports/esp32/machine_timer.c | 40 ++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/ports/esp32/machine_timer.c b/ports/esp32/machine_timer.c index 081a46b9c1..c941d943bc 100644 --- a/ports/esp32/machine_timer.c +++ b/ports/esp32/machine_timer.c @@ -73,8 +73,13 @@ STATIC esp_err_t check_esp_err(esp_err_t code) { } void machine_timer_deinit_all(void) { - while (MP_STATE_PORT(machine_timer_obj_head) != NULL) { - machine_timer_disable(MP_STATE_PORT(machine_timer_obj_head)); + // Disable, deallocate and remove all timers from list + machine_timer_obj_t **t = &MP_STATE_PORT(machine_timer_obj_head); + while (*t != NULL) { + machine_timer_disable(*t); + machine_timer_obj_t *next = (*t)->next; + m_del_obj(machine_timer_obj_t, *t); + *t = next; } } @@ -93,12 +98,24 @@ STATIC void machine_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_pr 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); + mp_uint_t group = (mp_obj_get_int(args[0]) >> 1) & 1; + mp_uint_t index = mp_obj_get_int(args[0]) & 1; + + // Check whether the timer is already initialized, if so return it + for (machine_timer_obj_t *t = MP_STATE_PORT(machine_timer_obj_head); t; t = t->next) { + if (t->group == group && t->index == index) { + return t; + } + } + machine_timer_obj_t *self = m_new_obj(machine_timer_obj_t); self->base.type = &machine_timer_type; + self->group = group; + self->index = index; - self->group = (mp_obj_get_int(args[0]) >> 1) & 1; - self->index = mp_obj_get_int(args[0]) & 1; - self->next = NULL; + // Add the timer to the linked-list of timers + self->next = MP_STATE_PORT(machine_timer_obj_head); + MP_STATE_PORT(machine_timer_obj_head) = self; return self; } @@ -110,13 +127,8 @@ STATIC void machine_timer_disable(machine_timer_obj_t *self) { self->handle = NULL; } - // Remove the timer from the linked-list of active timers - for (machine_timer_obj_t **t = &MP_STATE_PORT(machine_timer_obj_head); *t; t = &(*t)->next) { - if (*t == self) { - *t = (*t)->next; - break; - } - } + // We let the disabled timer stay in the list, as it might be + // referenced elsewhere } STATIC void machine_timer_isr(void *self_in) { @@ -150,10 +162,6 @@ STATIC void machine_timer_enable(machine_timer_obj_t *self) { 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)); - - // Add the timer to the linked-list of active timers - self->next = MP_STATE_PORT(machine_timer_obj_head); - MP_STATE_PORT(machine_timer_obj_head) = self; } 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) { From 3fc7c8e35c24942f1b44eb99e0aba9cf77ab984c Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 31 May 2019 21:39:34 +1000 Subject: [PATCH 0403/1788] stm32/usb: Include py/mpconfig.h instead of mpconfigboard.h. Because py/mpconfig.h has header include guards. --- ports/stm32/usbd_desc.c | 2 +- ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/ports/stm32/usbd_desc.c b/ports/stm32/usbd_desc.c index a7de71ef20..d28f9aec6f 100644 --- a/ports/stm32/usbd_desc.c +++ b/ports/stm32/usbd_desc.c @@ -37,7 +37,7 @@ #include "py/mphal.h" // need this header for any overrides to the below constants -#include "mpconfigboard.h" +#include "py/mpconfig.h" #ifndef USBD_LANGID_STRING #define USBD_LANGID_STRING 0x409 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 d4a218a4a6..d46f763d1d 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h @@ -7,8 +7,7 @@ #include "usbd_ioreq.h" // These are included to get direct access the MICROPY_HW_USB_xxx config -#include "mpconfigboard.h" -#include "mpconfigboard_common.h" +#include "py/mpconfig.h" // Work out if we should support USB high-speed device mode #if MICROPY_HW_USB_HS \ From f8274d5e7d95283f39bd73e521b0edd820765541 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 31 May 2019 21:41:30 +1000 Subject: [PATCH 0404/1788] stm32/boards/make-pins.py: Allow pins.csv to skip or hide board-pin name If the board-pin name is left empty then only the cpu-pin name is used, eg ",PA0". If the board-pin name starts with a hyphen then it's available as a C definition but not in the firmware, eg "-X1,PA0". --- ports/stm32/boards/make-pins.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/ports/stm32/boards/make-pins.py b/ports/stm32/boards/make-pins.py index ed112e05f0..3819b47244 100755 --- a/ports/stm32/boards/make-pins.py +++ b/ports/stm32/boards/make-pins.py @@ -251,9 +251,17 @@ class Pin(object): class NamedPin(object): def __init__(self, name, pin): - self._name = name + if name.startswith('-'): + self._is_hidden = True + self._name = name[1:] + else: + self._is_hidden = False + self._name = name self._pin = pin + def is_hidden(self): + return self._is_hidden + def pin(self): return self._pin @@ -300,13 +308,14 @@ class Pins(object): pin = self.find_pin(port_num, pin_num) if pin: pin.set_is_board_pin() - self.board_pins.append(NamedPin(row[0], pin)) + if row[0]: # Only add board pins that have a name + self.board_pins.append(NamedPin(row[0], pin)) def print_named(self, label, named_pins): print('STATIC const mp_rom_map_elem_t pin_{:s}_pins_locals_dict_table[] = {{'.format(label)) for named_pin in named_pins: pin = named_pin.pin() - if pin.is_board_pin(): + if pin.is_board_pin() and not named_pin.is_hidden(): 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)) @@ -364,7 +373,8 @@ class Pins(object): qstr_set |= set(pin.qstr_list()) qstr_set |= set([named_pin.name()]) for named_pin in self.board_pins: - qstr_set |= set([named_pin.name()]) + if not named_pin.is_hidden(): + qstr_set |= set([named_pin.name()]) for qstr in sorted(qstr_set): cond_var = None if qstr.startswith('AF'): @@ -429,6 +439,8 @@ class Pins(object): with open(af_py_filename, 'wt') as af_py_file: print('PINS_AF = (', file=af_py_file) for named_pin in self.board_pins: + if named_pin.is_hidden(): + continue print(" ('%s', " % named_pin.name(), end='', file=af_py_file) for af in named_pin.pin().alt_fn: if af.is_supported(): From 34cae24e3030456534abda794cc870051ac0491d Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 31 May 2019 21:44:53 +1000 Subject: [PATCH 0405/1788] stm32/boards/pllvalues.py: Search nested headers for HSx_VALUE defines. --- ports/stm32/boards/pllvalues.py | 43 +++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/ports/stm32/boards/pllvalues.py b/ports/stm32/boards/pllvalues.py index da1b81216f..a628dea8a9 100644 --- a/ports/stm32/boards/pllvalues.py +++ b/ports/stm32/boards/pllvalues.py @@ -135,6 +135,27 @@ def print_table(hse, valid_plls): print(out_format % ((sys,) + pll + compute_derived(hse, pll))) print("found %u valid configurations" % len(valid_plls)) +def search_header_for_hsx_values(filename, vals): + regex_inc = re.compile(r'#include "(boards/[A-Za-z0-9_./]+)"') + regex_def = re.compile(r'#define +(HSE_VALUE|HSI_VALUE) +\(\(uint32_t\)([0-9]+)\)') + with open(filename) as f: + for line in f: + line = line.strip() + m = regex_inc.match(line) + if m: + # Search included file + search_header_for_hsx_values(m.group(1), vals) + continue + m = regex_def.match(line) + if m: + # Found HSE_VALUE or HSI_VALUE + val = int(m.group(2)) // 1000000 + if m.group(1) == 'HSE_VALUE': + vals[0] = val + else: + vals[1] = val + return vals + def main(): global out_format @@ -163,22 +184,12 @@ def main(): if argv[0].startswith("file:"): # extract HSE_VALUE, and optionally HSI_VALUE, from header file - regex = re.compile(r'#define +(HSE_VALUE|HSI_VALUE) +\(\(uint32_t\)([0-9]+)\)') - with open(argv[0][5:]) as f: - for line in f: - line = line.strip() - m = regex.match(line) - if m: - val = int(m.group(2)) // 1000000 - if m.group(1) == 'HSE_VALUE': - hse = val - else: - hsi = val - if hse is None: - raise ValueError("%s does not contain a definition of HSE_VALUE" % argv[0]) - if hsi is not None and hsi > 16: - # Currently, a HSI value greater than 16MHz is not supported - hsi = None + hse, hsi = search_header_for_hsx_values(argv[0][5:], [None, None]) + if hse is None: + raise ValueError("%s does not contain a definition of HSE_VALUE" % argv[0]) + if hsi is not None and hsi > 16: + # Currently, a HSI value greater than 16MHz is not supported + hsi = None else: # HSE given directly as an integer hse = int(argv[0]) From 8f55c74533b7106daddbfccb38b85056c8a549f5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 31 May 2019 22:17:02 +1000 Subject: [PATCH 0406/1788] stm32/boards: Add board definition files for PYBD -SF2, -SF3, -SF6. These are core configurations providing PYBv1.x-level features. --- ports/stm32/boards/PYBD_SF2/bdev.c | 62 ++++++ ports/stm32/boards/PYBD_SF2/board_init.c | 38 ++++ ports/stm32/boards/PYBD_SF2/f722_qspi.ld | 97 +++++++++ ports/stm32/boards/PYBD_SF2/mpconfigboard.h | 201 ++++++++++++++++++ ports/stm32/boards/PYBD_SF2/mpconfigboard.mk | 10 + ports/stm32/boards/PYBD_SF2/pins.csv | 189 ++++++++++++++++ .../boards/PYBD_SF2/stm32f7xx_hal_conf.h | 88 ++++++++ ports/stm32/boards/PYBD_SF3/bdev.c | 1 + ports/stm32/boards/PYBD_SF3/board_init.c | 1 + ports/stm32/boards/PYBD_SF3/mpconfigboard.h | 34 +++ ports/stm32/boards/PYBD_SF3/mpconfigboard.mk | 13 ++ ports/stm32/boards/PYBD_SF3/pins.csv | 189 ++++++++++++++++ .../boards/PYBD_SF3/stm32f7xx_hal_conf.h | 1 + ports/stm32/boards/PYBD_SF6/bdev.c | 1 + ports/stm32/boards/PYBD_SF6/board_init.c | 1 + ports/stm32/boards/PYBD_SF6/f767.ld | 96 +++++++++ ports/stm32/boards/PYBD_SF6/mpconfigboard.h | 66 ++++++ ports/stm32/boards/PYBD_SF6/mpconfigboard.mk | 10 + ports/stm32/boards/PYBD_SF6/pins.csv | 189 ++++++++++++++++ .../boards/PYBD_SF6/stm32f7xx_hal_conf.h | 1 + 20 files changed, 1288 insertions(+) create mode 100644 ports/stm32/boards/PYBD_SF2/bdev.c create mode 100644 ports/stm32/boards/PYBD_SF2/board_init.c create mode 100644 ports/stm32/boards/PYBD_SF2/f722_qspi.ld create mode 100644 ports/stm32/boards/PYBD_SF2/mpconfigboard.h create mode 100644 ports/stm32/boards/PYBD_SF2/mpconfigboard.mk create mode 100644 ports/stm32/boards/PYBD_SF2/pins.csv create mode 100644 ports/stm32/boards/PYBD_SF2/stm32f7xx_hal_conf.h create mode 100644 ports/stm32/boards/PYBD_SF3/bdev.c create mode 100644 ports/stm32/boards/PYBD_SF3/board_init.c create mode 100644 ports/stm32/boards/PYBD_SF3/mpconfigboard.h create mode 100644 ports/stm32/boards/PYBD_SF3/mpconfigboard.mk create mode 100644 ports/stm32/boards/PYBD_SF3/pins.csv create mode 100644 ports/stm32/boards/PYBD_SF3/stm32f7xx_hal_conf.h create mode 100644 ports/stm32/boards/PYBD_SF6/bdev.c create mode 100644 ports/stm32/boards/PYBD_SF6/board_init.c create mode 100644 ports/stm32/boards/PYBD_SF6/f767.ld create mode 100644 ports/stm32/boards/PYBD_SF6/mpconfigboard.h create mode 100644 ports/stm32/boards/PYBD_SF6/mpconfigboard.mk create mode 100644 ports/stm32/boards/PYBD_SF6/pins.csv create mode 100644 ports/stm32/boards/PYBD_SF6/stm32f7xx_hal_conf.h diff --git a/ports/stm32/boards/PYBD_SF2/bdev.c b/ports/stm32/boards/PYBD_SF2/bdev.c new file mode 100644 index 0000000000..6c5ff721ec --- /dev/null +++ b/ports/stm32/boards/PYBD_SF2/bdev.c @@ -0,0 +1,62 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2019 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 "storage.h" +#include "qspi.h" + +// Shared cache for first and second SPI block devices +STATIC mp_spiflash_cache_t spi_bdev_cache; + +// First external SPI flash uses software QSPI interface + +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, + .cache = &spi_bdev_cache, +}; + +spi_bdev_t spi_bdev; + +// Second external SPI flash uses hardware QSPI interface + +const mp_spiflash_config_t spiflash2_config = { + .bus_kind = MP_SPIFLASH_BUS_QSPI, + .bus.u_qspi.data = NULL, + .bus.u_qspi.proto = &qspi_proto, + .cache = &spi_bdev_cache, +}; + +spi_bdev_t spi_bdev2; diff --git a/ports/stm32/boards/PYBD_SF2/board_init.c b/ports/stm32/boards/PYBD_SF2/board_init.c new file mode 100644 index 0000000000..3dc2c85e22 --- /dev/null +++ b/ports/stm32/boards/PYBD_SF2/board_init.c @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2019 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 "storage.h" + +void mboot_board_early_init(void) { + // Enable 500mA on WBUS-DIP28 + mp_hal_pin_config(pyb_pin_W23, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_UP, 0); +} + +void board_early_init(void) { + // Explicitly init SPI2 because it's not enabled as a block device + spi_bdev_ioctl(&spi_bdev2, BDEV_IOCTL_INIT, (uint32_t)&spiflash2_config); +} diff --git a/ports/stm32/boards/PYBD_SF2/f722_qspi.ld b/ports/stm32/boards/PYBD_SF2/f722_qspi.ld new file mode 100644 index 0000000000..8cafb0abe6 --- /dev/null +++ b/ports/stm32/boards/PYBD_SF2/f722_qspi.ld @@ -0,0 +1,97 @@ +/* + Linker script for PYBD with STM32F722/STM32F723/STM32F732/STM32F733 + + Memory layout for mboot 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 +*/ + +/* 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 */ + FLASH_EXT (rx) : ORIGIN = 0x90000000, LENGTH = 2048K /* external QSPI */ + RAM (rwx) : 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 = _ram_end - 16K; /* 16k stack */ + +ENTRY(Reset_Handler) + +/* Define output sections */ +SECTIONS +{ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) + . = ALIGN(4); + } >FLASH_APP + + .text : + { + . = ALIGN(4); + *(.text*) + *(.rodata*) + . = ALIGN(4); + _etext = .; + } >FLASH_APP + + _sidata = LOADADDR(.data); + + .data : + { + . = ALIGN(4); + _sdata = .; + *(.data*) + + . = ALIGN(4); + _edata = .; + } >RAM AT> FLASH_APP + + .bss : + { + . = ALIGN(4); + _sbss = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >RAM + + .heap : + { + . = ALIGN(4); + . = . + _minimum_heap_size; + . = ALIGN(4); + } >RAM + + .stack : + { + . = ALIGN(4); + . = . + _minimum_stack_size; + . = ALIGN(4); + } >RAM +} diff --git a/ports/stm32/boards/PYBD_SF2/mpconfigboard.h b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h new file mode 100644 index 0000000000..56650ba158 --- /dev/null +++ b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h @@ -0,0 +1,201 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2019 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. + */ + +#define MICROPY_HW_BOARD_NAME "PYBD-SF2W" +#define MICROPY_HW_MCU_NAME "STM32F722IEK" + +#define MICROPY_PY_PYB_LEGACY (1) +#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) +#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_USB (1) +#define MICROPY_HW_ENABLE_SDCARD (1) +#define MICROPY_HW_ENABLE_MMCARD (1) + +#define MICROPY_BOARD_EARLY_INIT board_early_init +void board_early_init(void); + +// HSE is 25MHz, run SYS at 120MHz +#define MICROPY_HW_CLK_PLLM (20) +#define MICROPY_HW_CLK_PLLN (192) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (5) +#define MICROPY_HW_FLASH_LATENCY (FLASH_LATENCY_3) + +// There is an external 32kHz oscillator +#define RTC_ASYNCH_PREDIV (0) +#define RTC_SYNCH_PREDIV (0x7fff) +#define MICROPY_HW_RTC_USE_BYPASS (1) +#define MICROPY_HW_RTC_USE_US (1) +#define MICROPY_HW_RTC_USE_CALOUT (1) + +// SPI flash #1, for R/W storage +#define MICROPY_HW_SOFTQSPI_SCK_LOW(self) (GPIOE->BSRR = (0x10000 << 11)) +#define MICROPY_HW_SOFTQSPI_SCK_HIGH(self) (GPIOE->BSRR = (1 << 11)) +#define MICROPY_HW_SOFTQSPI_NIBBLE_READ(self) ((GPIOE->IDR >> 7) & 0xf) +#define MICROPY_HW_SPIFLASH_SIZE_BITS (16 * 1024 * 1024) +#define MICROPY_HW_SPIFLASH_CS (pyb_pin_QSPI1_CS) +#define MICROPY_HW_SPIFLASH_SCK (pyb_pin_QSPI1_CLK) +#define MICROPY_HW_SPIFLASH_IO0 (pyb_pin_QSPI1_D0) +#define MICROPY_HW_SPIFLASH_IO1 (pyb_pin_QSPI1_D1) +#define MICROPY_HW_SPIFLASH_IO2 (pyb_pin_QSPI1_D2) +#define MICROPY_HW_SPIFLASH_IO3 (pyb_pin_QSPI1_D3) + +// SPI flash #1, block device config +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)) + +// SPI flash #2, to be memory mapped +#define MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2 (24) +#define MICROPY_HW_QSPIFLASH_CS (pyb_pin_QSPI2_CS) +#define MICROPY_HW_QSPIFLASH_SCK (pyb_pin_QSPI2_CLK) +#define MICROPY_HW_QSPIFLASH_IO0 (pyb_pin_QSPI2_D0) +#define MICROPY_HW_QSPIFLASH_IO1 (pyb_pin_QSPI2_D1) +#define MICROPY_HW_QSPIFLASH_IO2 (pyb_pin_QSPI2_D2) +#define MICROPY_HW_QSPIFLASH_IO3 (pyb_pin_QSPI2_D3) + +// SPI flash #2, block device config +extern const struct _mp_spiflash_config_t spiflash2_config; +extern struct _spi_bdev_t spi_bdev2; + +// UART config +#define MICROPY_HW_UART1_NAME "YA" +#define MICROPY_HW_UART1_TX (pyb_pin_Y1) +#define MICROPY_HW_UART1_RX (pyb_pin_Y2) +#define MICROPY_HW_UART2_TX (pyb_pin_X3) +#define MICROPY_HW_UART2_RX (pyb_pin_X4) +#define MICROPY_HW_UART2_RTS (pyb_pin_X2) +#define MICROPY_HW_UART2_CTS (pyb_pin_X1) +#define MICROPY_HW_UART3_NAME "YB" +#define MICROPY_HW_UART3_TX (pyb_pin_Y9) +#define MICROPY_HW_UART3_RX (pyb_pin_Y10) +#define MICROPY_HW_UART4_NAME "XA" +#define MICROPY_HW_UART4_TX (pyb_pin_X1) +#define MICROPY_HW_UART4_RX (pyb_pin_X2) +#define MICROPY_HW_UART6_TX (pyb_pin_BT_TXD) +#define MICROPY_HW_UART6_RX (pyb_pin_BT_RXD) +#define MICROPY_HW_UART6_RTS (pyb_pin_BT_RTS) +#define MICROPY_HW_UART6_CTS (pyb_pin_BT_CTS) + +// I2C busses +#define MICROPY_HW_I2C1_NAME "X" +#define MICROPY_HW_I2C1_SCL (pyb_pin_X9) +#define MICROPY_HW_I2C1_SDA (pyb_pin_X10) +#define MICROPY_HW_I2C2_NAME "Y" +#define MICROPY_HW_I2C2_SCL (pyb_pin_Y9) +#define MICROPY_HW_I2C2_SDA (pyb_pin_Y10) + +// SPI busses +#define MICROPY_HW_SPI1_NAME "X" +#define MICROPY_HW_SPI1_NSS (pyb_pin_X5) +#define MICROPY_HW_SPI1_SCK (pyb_pin_X6) +#define MICROPY_HW_SPI1_MISO (pyb_pin_X7) +#define MICROPY_HW_SPI1_MOSI (pyb_pin_X8) +#define MICROPY_HW_SPI2_NAME "Y" +#define MICROPY_HW_SPI2_NSS (pyb_pin_Y5) +#define MICROPY_HW_SPI2_SCK (pyb_pin_Y6) +#define MICROPY_HW_SPI2_MISO (pyb_pin_Y7) +#define MICROPY_HW_SPI2_MOSI (pyb_pin_Y8) +#define MICROPY_HW_SPI3_NSS (pyb_pin_W16) +#define MICROPY_HW_SPI3_SCK (pyb_pin_W29) +#define MICROPY_HW_SPI3_MISO (pyb_pin_W50) +#define MICROPY_HW_SPI3_MOSI (pyb_pin_W46) + +// CAN busses +#define MICROPY_HW_CAN1_NAME "X" +#define MICROPY_HW_CAN1_TX (pyb_pin_X10) +#define MICROPY_HW_CAN1_RX (pyb_pin_X9) + +// USRSW is not pulled, and pressing the button makes the input go low. +#define MICROPY_HW_USRSW_PIN (pyb_pin_USR) +#define MICROPY_HW_USRSW_PULL (GPIO_PULLUP) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_FALLING) +#define MICROPY_HW_USRSW_PRESSED (0) + +// LEDs +#define MICROPY_HW_LED1 (pyb_pin_LED_RED) +#define MICROPY_HW_LED2 (pyb_pin_LED_GREEN) +#define MICROPY_HW_LED3 (pyb_pin_LED_BLUE) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin)) + +// SD card +#define MICROPY_HW_SDMMC2_CK (pyb_pin_SD_CK) +#define MICROPY_HW_SDMMC2_CMD (pyb_pin_SD_CMD) +#define MICROPY_HW_SDMMC2_D0 (pyb_pin_SD_D0) +#define MICROPY_HW_SDMMC2_D1 (pyb_pin_SD_D1) +#define MICROPY_HW_SDMMC2_D2 (pyb_pin_SD_D2) +#define MICROPY_HW_SDMMC2_D3 (pyb_pin_SD_D3) +#define MICROPY_HW_SDCARD_DETECT_PIN (pyb_pin_SD_SW) +#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP) +#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) +#define MICROPY_HW_SDCARD_MOUNT_AT_BOOT (0) + +// USB config +#define MICROPY_HW_USB_FS (1) +#define MICROPY_HW_USB_HS (1) +#define MICROPY_HW_USB_HS_IN_FS (1) +#define MICROPY_HW_USB_MAIN_DEV (USB_PHY_HS_ID) + +/******************************************************************************/ +// Bootloader configuration + +#define MBOOT_USB_AUTODETECT_PORT (1) +#define MBOOT_FSLOAD (1) + +#define MBOOT_I2C_PERIPH_ID 1 +#define MBOOT_I2C_SCL (pin_B8) +#define MBOOT_I2C_SDA (pin_B9) +#define MBOOT_I2C_ALTFUNC (4) + +#define MBOOT_SPIFLASH_ADDR (0x80000000) +#define MBOOT_SPIFLASH_BYTE_SIZE (64 * 32 * 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) + +#define MBOOT_SPIFLASH2_ADDR (0x90000000) +#define MBOOT_SPIFLASH2_BYTE_SIZE (64 * 32 * 1024) +#define MBOOT_SPIFLASH2_LAYOUT "/0x90000000/64*32Kg" +#define MBOOT_SPIFLASH2_ERASE_BLOCKS_PER_PAGE (32 / 4) +#define MBOOT_SPIFLASH2_SPIFLASH (&spi_bdev2.spiflash) +#define MBOOT_SPIFLASH2_CONFIG (&spiflash2_config) + +#define MBOOT_BOARD_EARLY_INIT mboot_board_early_init +void mboot_board_early_init(void); diff --git a/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk b/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk new file mode 100644 index 0000000000..87e3970656 --- /dev/null +++ b/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk @@ -0,0 +1,10 @@ +# MCU settings +MCU_SERIES = f7 +CMSIS_MCU = STM32F722xx +MICROPY_FLOAT_IMPL = single +AF_FILE = boards/stm32f722_af.csv +LD_FILES = boards/PYBD_SF2/f722_qspi.ld +TEXT0_ADDR = 0x08008000 + +# MicroPython settings +MICROPY_PY_LWIP = 1 diff --git a/ports/stm32/boards/PYBD_SF2/pins.csv b/ports/stm32/boards/PYBD_SF2/pins.csv new file mode 100644 index 0000000000..c11f3fe906 --- /dev/null +++ b/ports/stm32/boards/PYBD_SF2/pins.csv @@ -0,0 +1,189 @@ +W3,PE3 +W5,PA11 +W5B,PI0 +W6,PA5 +W7,PA4 +W7B,PG7 +W8,PB11 +W9,PA12 +W9B,PI1 +W10,PA6 +W11,PA3 +W12,PB10 +W14,PA7 +W15,PA2 +W16,PA15 +W17,PA1 +W18,PD3 +W19,PA0 +W20,PD0 +W21,PC14 +W22,PE12 +W22B,PF6 +W22C,PF7 +W22D,PF10 +W23,PE1 +W24,PC1 +W25,PE0 +W26,PC13 +W27,PA8 +W27B,PC6 +W28,PE6 +W29,PB3 +W30,PE5 +W32,PE4 +W33,PH2 +W34,PH3 +W43,PB0 +W43B,PC0 +W43C,PF9 +W43D,PF11 +W45,PB12 +W45B,PE14 +W45C,PH8 +W46,PB5 +W47,PC5 +W47B,PF14 +W49,PB13 +W50,PB4 +W51,PC4 +W51B,PF15 +W52,PA10 +W53,PC2 +W53B,PF8 +W54,PA9 +W55,PB9 +W56,PA14 +W57,PC3 +W57B,PF13 +W58,PG11 +W59,PB8 +W60,PG12 +W61,PB7 +W62,PD7 +W63,PB1 +W63B,PD9 +W64,PD6 +W65,PD8 +W66,PG9 +W67,PA13 +W68,PG10 +W70,PB14 +W71,PE15 +W72,PB15 +W73,PH6 +W74,PH7 +X1,PA0 +X2,PA1 +X3,PA2 +X4,PA3 +X5,PA4 +X5B,PG7 +X6,PA5 +X7,PA6 +X8,PA7 +X9,PB8 +X10,PB9 +X11,PC4 +X11B,PF15 +X12,PC5 +X12B,PF14 +Y1,PA9 +Y2,PA10 +Y3,PB4 +Y4,PB5 +Y5,PB12 +Y5B,PE14 +Y5C,PH8 +Y6,PB13 +Y7,PC2 +Y7B,PF8 +Y8,PC3 +Y8B,PF13 +Y9,PB10 +Y10,PB11 +Y11,PB0 +Y11B,PC0 +Y11C,PF9 +Y11D,PF11 +Y12,PB1 +Y12B,PD9 +EN_3V3,PF2 +PULL_SCL,PF1 +PULL_SDA,PH5 +LED_RED,PF3 +LED_GREEN,PF4 +LED_BLUE,PF5 +USR,PA13 +USB_DM,PA11 +USB_DP,PA12 +USB_HS_DM,PB14 +USB_HS_DP,PB15 +-QSPI1_CS,PE13 +-QSPI1_CLK,PE11 +-QSPI1_D0,PE7 +-QSPI1_D1,PE8 +-QSPI1_D2,PE9 +-QSPI1_D3,PE10 +-QSPI2_CS,PB6 +-QSPI2_CLK,PB2 +-QSPI2_D0,PD11 +-QSPI2_D1,PD12 +-QSPI2_D2,PE2 +-QSPI2_D3,PD13 +-SD_D0,PG9 +-SD_D1,PG10 +-SD_D2,PG11 +-SD_D3,PG12 +-SD_CMD,PD7 +-SD_CK,PD6 +SD_SW,PA14 +-WL_REG_ON,PD4 +-WL_HOST_WAKE,PI8 +-WL_RFSW_VDD,PI9 +-WL_GPIO_1,PI11 +-WL_GPIO_2,PI7 +-WL_GPIO_4,PI9 +-WL_SDIO_0,PC8 +-WL_SDIO_1,PC9 +-WL_SDIO_2,PC10 +-WL_SDIO_3,PC11 +-WL_SDIO_CMD,PD2 +-WL_SDIO_CLK,PC12 +-BT_RXD,PC7 +-BT_TXD,PG14 +-BT_CTS,PG13 +-BT_RTS,PG8 +-BT_GPIO_3,PG15 +-BT_GPIO_4,PI5 +-BT_GPIO_5,PI4 +-BT_PCM_SYNC,PE4 +-BT_PCM_IN,PE6 +-BT_PCM_OUT,PE3 +-BT_PCM_CLK,PE5 +-BT_I2C_D0,PI10 +-BT_REG_ON,PI6 +-BT_HOST_WAKE,PD10 +-BT_DEV_WAKE,PD5 +,PD1 +,PD14 +,PD15 +,PF0 +,PF12 +,PG0 +,PG1 +,PG2 +,PG3 +,PG4 +,PG5 +,PG6 +,PH4 +,PH9 +,PH10 +,PH11 +,PH12 +,PH13 +,PH14 +,PH15 +,PI2 +,PI3 diff --git a/ports/stm32/boards/PYBD_SF2/stm32f7xx_hal_conf.h b/ports/stm32/boards/PYBD_SF2/stm32f7xx_hal_conf.h new file mode 100644 index 0000000000..c820dafc44 --- /dev/null +++ b/ports/stm32/boards/PYBD_SF2/stm32f7xx_hal_conf.h @@ -0,0 +1,88 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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_STM32F7XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F7XX_HAL_CONF_H + +// Include various HAL modules for convenience +#include "stm32f7xx_hal_dma.h" +#include "stm32f7xx_hal_adc.h" +#include "stm32f7xx_hal_can.h" +#include "stm32f7xx_hal_cortex.h" +#include "stm32f7xx_hal_dac.h" +#include "stm32f7xx_hal_flash.h" +#include "stm32f7xx_hal_gpio.h" +#include "stm32f7xx_hal_i2c.h" +#include "stm32f7xx_hal_mmc.h" +#include "stm32f7xx_hal_pcd.h" +#include "stm32f7xx_hal_pwr.h" +#include "stm32f7xx_hal_rcc.h" +#include "stm32f7xx_hal_rtc.h" +#include "stm32f7xx_hal_sd.h" +#include "stm32f7xx_hal_spi.h" +#include "stm32f7xx_hal_tim.h" +#include "stm32f7xx_hal_uart.h" + +// Enable various HAL modules +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +#define HAL_CORTEX_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_MMC_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +#define HAL_SD_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED + +// Oscillator values in Hz +#define HSI_VALUE (16000000) +#define HSE_VALUE ((uint32_t)25000000) +#define LSI_VALUE (32000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) + +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (5000) +#define LSE_STARTUP_TIMEOUT (5000) + +// SysTick has the highest priority +#define TICK_INT_PRIORITY (0x00) + +// No RTOS is used +#define USE_RTOS 0 + +// HAL parameter assertions are disabled +#define assert_param(expr) ((void)0) + +#endif // MICROPY_INCLUDED_STM32F7XX_HAL_CONF_H diff --git a/ports/stm32/boards/PYBD_SF3/bdev.c b/ports/stm32/boards/PYBD_SF3/bdev.c new file mode 100644 index 0000000000..b43028c06b --- /dev/null +++ b/ports/stm32/boards/PYBD_SF3/bdev.c @@ -0,0 +1 @@ +#include "boards/PYBD_SF2/bdev.c" diff --git a/ports/stm32/boards/PYBD_SF3/board_init.c b/ports/stm32/boards/PYBD_SF3/board_init.c new file mode 100644 index 0000000000..c7a9f28006 --- /dev/null +++ b/ports/stm32/boards/PYBD_SF3/board_init.c @@ -0,0 +1 @@ +#include "boards/PYBD_SF2/board_init.c" diff --git a/ports/stm32/boards/PYBD_SF3/mpconfigboard.h b/ports/stm32/boards/PYBD_SF3/mpconfigboard.h new file mode 100644 index 0000000000..8c79e6fe64 --- /dev/null +++ b/ports/stm32/boards/PYBD_SF3/mpconfigboard.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2019 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. + */ + +// Take PYBD_SF2 as base configuration +#include "boards/PYBD_SF2/mpconfigboard.h" + +#undef MICROPY_HW_BOARD_NAME +#undef MICROPY_HW_MCU_NAME + +#define MICROPY_HW_BOARD_NAME "PYBD-SF3W" +#define MICROPY_HW_MCU_NAME "STM32F733IEK" diff --git a/ports/stm32/boards/PYBD_SF3/mpconfigboard.mk b/ports/stm32/boards/PYBD_SF3/mpconfigboard.mk new file mode 100644 index 0000000000..6104ed2475 --- /dev/null +++ b/ports/stm32/boards/PYBD_SF3/mpconfigboard.mk @@ -0,0 +1,13 @@ +# MCU settings +MCU_SERIES = f7 +CMSIS_MCU = STM32F733xx +MICROPY_FLOAT_IMPL = single +AF_FILE = boards/stm32f722_af.csv +LD_FILES = boards/PYBD_SF2/f722_qspi.ld +TEXT0_ADDR = 0x08008000 +TEXT1_ADDR = 0x90000000 +TEXT0_SECTIONS = .isr_vector .text .data +TEXT1_SECTIONS = .text_ext + +# MicroPython settings +MICROPY_PY_LWIP = 1 diff --git a/ports/stm32/boards/PYBD_SF3/pins.csv b/ports/stm32/boards/PYBD_SF3/pins.csv new file mode 100644 index 0000000000..c11f3fe906 --- /dev/null +++ b/ports/stm32/boards/PYBD_SF3/pins.csv @@ -0,0 +1,189 @@ +W3,PE3 +W5,PA11 +W5B,PI0 +W6,PA5 +W7,PA4 +W7B,PG7 +W8,PB11 +W9,PA12 +W9B,PI1 +W10,PA6 +W11,PA3 +W12,PB10 +W14,PA7 +W15,PA2 +W16,PA15 +W17,PA1 +W18,PD3 +W19,PA0 +W20,PD0 +W21,PC14 +W22,PE12 +W22B,PF6 +W22C,PF7 +W22D,PF10 +W23,PE1 +W24,PC1 +W25,PE0 +W26,PC13 +W27,PA8 +W27B,PC6 +W28,PE6 +W29,PB3 +W30,PE5 +W32,PE4 +W33,PH2 +W34,PH3 +W43,PB0 +W43B,PC0 +W43C,PF9 +W43D,PF11 +W45,PB12 +W45B,PE14 +W45C,PH8 +W46,PB5 +W47,PC5 +W47B,PF14 +W49,PB13 +W50,PB4 +W51,PC4 +W51B,PF15 +W52,PA10 +W53,PC2 +W53B,PF8 +W54,PA9 +W55,PB9 +W56,PA14 +W57,PC3 +W57B,PF13 +W58,PG11 +W59,PB8 +W60,PG12 +W61,PB7 +W62,PD7 +W63,PB1 +W63B,PD9 +W64,PD6 +W65,PD8 +W66,PG9 +W67,PA13 +W68,PG10 +W70,PB14 +W71,PE15 +W72,PB15 +W73,PH6 +W74,PH7 +X1,PA0 +X2,PA1 +X3,PA2 +X4,PA3 +X5,PA4 +X5B,PG7 +X6,PA5 +X7,PA6 +X8,PA7 +X9,PB8 +X10,PB9 +X11,PC4 +X11B,PF15 +X12,PC5 +X12B,PF14 +Y1,PA9 +Y2,PA10 +Y3,PB4 +Y4,PB5 +Y5,PB12 +Y5B,PE14 +Y5C,PH8 +Y6,PB13 +Y7,PC2 +Y7B,PF8 +Y8,PC3 +Y8B,PF13 +Y9,PB10 +Y10,PB11 +Y11,PB0 +Y11B,PC0 +Y11C,PF9 +Y11D,PF11 +Y12,PB1 +Y12B,PD9 +EN_3V3,PF2 +PULL_SCL,PF1 +PULL_SDA,PH5 +LED_RED,PF3 +LED_GREEN,PF4 +LED_BLUE,PF5 +USR,PA13 +USB_DM,PA11 +USB_DP,PA12 +USB_HS_DM,PB14 +USB_HS_DP,PB15 +-QSPI1_CS,PE13 +-QSPI1_CLK,PE11 +-QSPI1_D0,PE7 +-QSPI1_D1,PE8 +-QSPI1_D2,PE9 +-QSPI1_D3,PE10 +-QSPI2_CS,PB6 +-QSPI2_CLK,PB2 +-QSPI2_D0,PD11 +-QSPI2_D1,PD12 +-QSPI2_D2,PE2 +-QSPI2_D3,PD13 +-SD_D0,PG9 +-SD_D1,PG10 +-SD_D2,PG11 +-SD_D3,PG12 +-SD_CMD,PD7 +-SD_CK,PD6 +SD_SW,PA14 +-WL_REG_ON,PD4 +-WL_HOST_WAKE,PI8 +-WL_RFSW_VDD,PI9 +-WL_GPIO_1,PI11 +-WL_GPIO_2,PI7 +-WL_GPIO_4,PI9 +-WL_SDIO_0,PC8 +-WL_SDIO_1,PC9 +-WL_SDIO_2,PC10 +-WL_SDIO_3,PC11 +-WL_SDIO_CMD,PD2 +-WL_SDIO_CLK,PC12 +-BT_RXD,PC7 +-BT_TXD,PG14 +-BT_CTS,PG13 +-BT_RTS,PG8 +-BT_GPIO_3,PG15 +-BT_GPIO_4,PI5 +-BT_GPIO_5,PI4 +-BT_PCM_SYNC,PE4 +-BT_PCM_IN,PE6 +-BT_PCM_OUT,PE3 +-BT_PCM_CLK,PE5 +-BT_I2C_D0,PI10 +-BT_REG_ON,PI6 +-BT_HOST_WAKE,PD10 +-BT_DEV_WAKE,PD5 +,PD1 +,PD14 +,PD15 +,PF0 +,PF12 +,PG0 +,PG1 +,PG2 +,PG3 +,PG4 +,PG5 +,PG6 +,PH4 +,PH9 +,PH10 +,PH11 +,PH12 +,PH13 +,PH14 +,PH15 +,PI2 +,PI3 diff --git a/ports/stm32/boards/PYBD_SF3/stm32f7xx_hal_conf.h b/ports/stm32/boards/PYBD_SF3/stm32f7xx_hal_conf.h new file mode 100644 index 0000000000..0f178c2ba3 --- /dev/null +++ b/ports/stm32/boards/PYBD_SF3/stm32f7xx_hal_conf.h @@ -0,0 +1 @@ +#include "boards/PYBD_SF2/stm32f7xx_hal_conf.h" diff --git a/ports/stm32/boards/PYBD_SF6/bdev.c b/ports/stm32/boards/PYBD_SF6/bdev.c new file mode 100644 index 0000000000..b43028c06b --- /dev/null +++ b/ports/stm32/boards/PYBD_SF6/bdev.c @@ -0,0 +1 @@ +#include "boards/PYBD_SF2/bdev.c" diff --git a/ports/stm32/boards/PYBD_SF6/board_init.c b/ports/stm32/boards/PYBD_SF6/board_init.c new file mode 100644 index 0000000000..c7a9f28006 --- /dev/null +++ b/ports/stm32/boards/PYBD_SF6/board_init.c @@ -0,0 +1 @@ +#include "boards/PYBD_SF2/board_init.c" diff --git a/ports/stm32/boards/PYBD_SF6/f767.ld b/ports/stm32/boards/PYBD_SF6/f767.ld new file mode 100644 index 0000000000..d910438a7e --- /dev/null +++ b/ports/stm32/boards/PYBD_SF6/f767.ld @@ -0,0 +1,96 @@ +/* + Linker script for PYBD with STM32F767 + + Memory layout for mboot 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 +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K + 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_EXT (rx) : ORIGIN = 0x90000000, LENGTH = 2048K /* external QSPI */ + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 512K /* DTCM=128k, SRAM1=368K, SRAM2=16K */ +} + +/* 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 = _ram_end - 24K; /* 24k stack */ + +ENTRY(Reset_Handler) + +/* Define output sections */ +SECTIONS +{ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) + . = ALIGN(4); + } >FLASH_APP + + .text : + { + . = ALIGN(4); + *(.text*) + *(.rodata*) + . = ALIGN(4); + _etext = .; + } >FLASH_APP + + _sidata = LOADADDR(.data); + + .data : + { + . = ALIGN(4); + _sdata = .; + *(.data*) + . = ALIGN(4); + _edata = .; + } >RAM AT> FLASH_APP + + .bss : + { + . = ALIGN(4); + _sbss = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >RAM + + .heap : + { + . = ALIGN(4); + . = . + _minimum_heap_size; + . = ALIGN(4); + } >RAM + + .stack : + { + . = ALIGN(4); + . = . + _minimum_stack_size; + . = ALIGN(4); + } >RAM +} diff --git a/ports/stm32/boards/PYBD_SF6/mpconfigboard.h b/ports/stm32/boards/PYBD_SF6/mpconfigboard.h new file mode 100644 index 0000000000..cbfbe39945 --- /dev/null +++ b/ports/stm32/boards/PYBD_SF6/mpconfigboard.h @@ -0,0 +1,66 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2019 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. + */ + +// Take PYBD_SF2 as base configuration +#include "boards/PYBD_SF2/mpconfigboard.h" + +#undef MICROPY_HW_BOARD_NAME +#undef MICROPY_HW_MCU_NAME +#undef MICROPY_HW_CLK_PLLM +#undef MICROPY_HW_CLK_PLLN +#undef MICROPY_HW_CLK_PLLP +#undef MICROPY_HW_CLK_PLLQ +#undef MICROPY_HW_FLASH_LATENCY + +#define MICROPY_HW_BOARD_NAME "PYBD-SF6W" +#define MICROPY_HW_MCU_NAME "STM32F767IIK" + +// HSE is 25MHz, run SYS at 144MHz +#define MICROPY_HW_CLK_PLLM (25) +#define MICROPY_HW_CLK_PLLN (288) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (6) +#define MICROPY_HW_FLASH_LATENCY (FLASH_LATENCY_4) + +// Extra UART config +#define MICROPY_HW_UART7_TX (pyb_pin_W16) +#define MICROPY_HW_UART7_RX (pyb_pin_W22B) + +// Extra CAN busses +#define MICROPY_HW_CAN2_NAME "Y" +#define MICROPY_HW_CAN2_TX (pyb_pin_Y6) +#define MICROPY_HW_CAN2_RX (pyb_pin_Y5) + +// Ethernet via RMII +#define MICROPY_HW_ETH_MDC (pyb_pin_W24) +#define MICROPY_HW_ETH_MDIO (pyb_pin_W15) +#define MICROPY_HW_ETH_RMII_REF_CLK (pyb_pin_W17) +#define MICROPY_HW_ETH_RMII_CRS_DV (pyb_pin_W14) +#define MICROPY_HW_ETH_RMII_RXD0 (pyb_pin_W51) +#define MICROPY_HW_ETH_RMII_RXD1 (pyb_pin_W47) +#define MICROPY_HW_ETH_RMII_TX_EN (pyb_pin_W8) +#define MICROPY_HW_ETH_RMII_TXD0 (pyb_pin_W45) +#define MICROPY_HW_ETH_RMII_TXD1 (pyb_pin_W49) diff --git a/ports/stm32/boards/PYBD_SF6/mpconfigboard.mk b/ports/stm32/boards/PYBD_SF6/mpconfigboard.mk new file mode 100644 index 0000000000..0288b9142c --- /dev/null +++ b/ports/stm32/boards/PYBD_SF6/mpconfigboard.mk @@ -0,0 +1,10 @@ +# MCU settings +MCU_SERIES = f7 +CMSIS_MCU = STM32F767xx +MICROPY_FLOAT_IMPL = double +AF_FILE = boards/stm32f767_af.csv +LD_FILES = boards/PYBD_SF6/f767.ld +TEXT0_ADDR = 0x08008000 + +# MicroPython settings +MICROPY_PY_LWIP = 1 diff --git a/ports/stm32/boards/PYBD_SF6/pins.csv b/ports/stm32/boards/PYBD_SF6/pins.csv new file mode 100644 index 0000000000..c11f3fe906 --- /dev/null +++ b/ports/stm32/boards/PYBD_SF6/pins.csv @@ -0,0 +1,189 @@ +W3,PE3 +W5,PA11 +W5B,PI0 +W6,PA5 +W7,PA4 +W7B,PG7 +W8,PB11 +W9,PA12 +W9B,PI1 +W10,PA6 +W11,PA3 +W12,PB10 +W14,PA7 +W15,PA2 +W16,PA15 +W17,PA1 +W18,PD3 +W19,PA0 +W20,PD0 +W21,PC14 +W22,PE12 +W22B,PF6 +W22C,PF7 +W22D,PF10 +W23,PE1 +W24,PC1 +W25,PE0 +W26,PC13 +W27,PA8 +W27B,PC6 +W28,PE6 +W29,PB3 +W30,PE5 +W32,PE4 +W33,PH2 +W34,PH3 +W43,PB0 +W43B,PC0 +W43C,PF9 +W43D,PF11 +W45,PB12 +W45B,PE14 +W45C,PH8 +W46,PB5 +W47,PC5 +W47B,PF14 +W49,PB13 +W50,PB4 +W51,PC4 +W51B,PF15 +W52,PA10 +W53,PC2 +W53B,PF8 +W54,PA9 +W55,PB9 +W56,PA14 +W57,PC3 +W57B,PF13 +W58,PG11 +W59,PB8 +W60,PG12 +W61,PB7 +W62,PD7 +W63,PB1 +W63B,PD9 +W64,PD6 +W65,PD8 +W66,PG9 +W67,PA13 +W68,PG10 +W70,PB14 +W71,PE15 +W72,PB15 +W73,PH6 +W74,PH7 +X1,PA0 +X2,PA1 +X3,PA2 +X4,PA3 +X5,PA4 +X5B,PG7 +X6,PA5 +X7,PA6 +X8,PA7 +X9,PB8 +X10,PB9 +X11,PC4 +X11B,PF15 +X12,PC5 +X12B,PF14 +Y1,PA9 +Y2,PA10 +Y3,PB4 +Y4,PB5 +Y5,PB12 +Y5B,PE14 +Y5C,PH8 +Y6,PB13 +Y7,PC2 +Y7B,PF8 +Y8,PC3 +Y8B,PF13 +Y9,PB10 +Y10,PB11 +Y11,PB0 +Y11B,PC0 +Y11C,PF9 +Y11D,PF11 +Y12,PB1 +Y12B,PD9 +EN_3V3,PF2 +PULL_SCL,PF1 +PULL_SDA,PH5 +LED_RED,PF3 +LED_GREEN,PF4 +LED_BLUE,PF5 +USR,PA13 +USB_DM,PA11 +USB_DP,PA12 +USB_HS_DM,PB14 +USB_HS_DP,PB15 +-QSPI1_CS,PE13 +-QSPI1_CLK,PE11 +-QSPI1_D0,PE7 +-QSPI1_D1,PE8 +-QSPI1_D2,PE9 +-QSPI1_D3,PE10 +-QSPI2_CS,PB6 +-QSPI2_CLK,PB2 +-QSPI2_D0,PD11 +-QSPI2_D1,PD12 +-QSPI2_D2,PE2 +-QSPI2_D3,PD13 +-SD_D0,PG9 +-SD_D1,PG10 +-SD_D2,PG11 +-SD_D3,PG12 +-SD_CMD,PD7 +-SD_CK,PD6 +SD_SW,PA14 +-WL_REG_ON,PD4 +-WL_HOST_WAKE,PI8 +-WL_RFSW_VDD,PI9 +-WL_GPIO_1,PI11 +-WL_GPIO_2,PI7 +-WL_GPIO_4,PI9 +-WL_SDIO_0,PC8 +-WL_SDIO_1,PC9 +-WL_SDIO_2,PC10 +-WL_SDIO_3,PC11 +-WL_SDIO_CMD,PD2 +-WL_SDIO_CLK,PC12 +-BT_RXD,PC7 +-BT_TXD,PG14 +-BT_CTS,PG13 +-BT_RTS,PG8 +-BT_GPIO_3,PG15 +-BT_GPIO_4,PI5 +-BT_GPIO_5,PI4 +-BT_PCM_SYNC,PE4 +-BT_PCM_IN,PE6 +-BT_PCM_OUT,PE3 +-BT_PCM_CLK,PE5 +-BT_I2C_D0,PI10 +-BT_REG_ON,PI6 +-BT_HOST_WAKE,PD10 +-BT_DEV_WAKE,PD5 +,PD1 +,PD14 +,PD15 +,PF0 +,PF12 +,PG0 +,PG1 +,PG2 +,PG3 +,PG4 +,PG5 +,PG6 +,PH4 +,PH9 +,PH10 +,PH11 +,PH12 +,PH13 +,PH14 +,PH15 +,PI2 +,PI3 diff --git a/ports/stm32/boards/PYBD_SF6/stm32f7xx_hal_conf.h b/ports/stm32/boards/PYBD_SF6/stm32f7xx_hal_conf.h new file mode 100644 index 0000000000..0f178c2ba3 --- /dev/null +++ b/ports/stm32/boards/PYBD_SF6/stm32f7xx_hal_conf.h @@ -0,0 +1 @@ +#include "boards/PYBD_SF2/stm32f7xx_hal_conf.h" From 84f1067f7fa3d61bd9e732eb46e8c52ff3d03be2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 31 May 2019 22:47:00 +1000 Subject: [PATCH 0407/1788] travis: Build PYBD_SF2 board as part of the stm32 job. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 0ba9a00223..4ec5069050 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,6 +33,7 @@ jobs: - make ${MAKEOPTS} -C mpy-cross - 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=PYBD_SF2 - make ${MAKEOPTS} -C ports/stm32 BOARD=STM32F769DISC - make ${MAKEOPTS} -C ports/stm32 BOARD=STM32L476DISC From 8e3af7d4c80bfd9047431eb62804ecd4f60cdb9f Mon Sep 17 00:00:00 2001 From: Nicko van Someren Date: Sat, 4 May 2019 19:00:35 -0600 Subject: [PATCH 0408/1788] esp32: Add machine.SDCard class using built-in HW SD/MMC controller. This adds support for SD cards using the ESP32's built-in hardware SD/MMC host controller, over either the SDIO bus or SPI. The class is available as machine.SDCard and using it can be as simple as: uos.mount(machine.SDCard(), '/sd') --- ports/esp32/Makefile | 20 ++ ports/esp32/machine_sdcard.c | 391 +++++++++++++++++++++++++++++++++++ ports/esp32/modmachine.c | 3 + ports/esp32/modmachine.h | 1 + ports/esp32/mpconfigport.h | 1 + 5 files changed, 416 insertions(+) create mode 100644 ports/esp32/machine_sdcard.c diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index ea90c9f3f5..98ad196c1d 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -111,6 +111,7 @@ INC_ESPCOMP += -I$(ESPCOMP)/app_trace/include INC_ESPCOMP += -I$(ESPCOMP)/app_update/include INC_ESPCOMP += -I$(ESPCOMP)/pthread/include INC_ESPCOMP += -I$(ESPCOMP)/smartconfig_ack/include +INC_ESPCOMP += -I$(ESPCOMP)/sdmmc/include # these flags are common to C and C++ compilation CFLAGS_COMMON = -Os -ffunction-sections -fdata-sections -fstrict-volatile-bitfields \ @@ -192,6 +193,7 @@ SRC_C = \ machine_wdt.c \ mpthreadport.c \ machine_rtc.c \ + machine_sdcard.c \ $(SRC_MOD) EXTMOD_SRC_C = $(addprefix extmod/,\ @@ -257,6 +259,11 @@ ESPIDF_DRIVER_O = $(addprefix $(ESPCOMP)/driver/,\ ledc.o \ gpio.o \ timer.o \ + sdmmc_host.o \ + sdmmc_transaction.o \ + sdspi_crc.o \ + sdspi_host.o \ + sdspi_transaction.o \ spi_master.o \ spi_common.o \ rtc_module.o \ @@ -329,6 +336,7 @@ ESPIDF_SOC_O = $(addprefix $(ESPCOMP)/soc/,\ esp32/rtc_sleep.o \ esp32/rtc_time.o \ esp32/rtc_wdt.o \ + esp32/sdmmc_periph.o \ esp32/soc_memory_layout.o \ esp32/spi_periph.o \ src/memory_layout_utils.o \ @@ -665,6 +673,15 @@ ESPIDF_WPA_SUPPLICANT_O = $(addprefix $(ESPCOMP)/wpa_supplicant/,\ port/os_xtensa.o \ ) +ESPIDF_SDMMC_O = $(addprefix $(ESPCOMP)/sdmmc/,\ + sdmmc_cmd.o \ + sdmmc_common.o \ + sdmmc_init.o \ + sdmmc_mmc.o \ + sdmmc_sd.o \ + sdmmc_io.o \ + ) + OBJ_ESPIDF = OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NEWLIB_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_DRIVER_O)) @@ -693,6 +710,7 @@ 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)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_SDMMC_O)) $(OBJ_ESPIDF): $(SDKCONFIG_H) @@ -723,6 +741,7 @@ LIB_ESPIDF += ulp LIB_ESPIDF += lwip LIB_ESPIDF += mbedtls LIB_ESPIDF += wpa_supplicant +LIB_ESPIDF += sdmmc BUILD_ESPIDF_LIB = $(BUILD)/esp-idf @@ -763,6 +782,7 @@ $(eval $(call gen_espidf_lib_rule,ulp,$(ESPIDF_ULP_O))) $(eval $(call gen_espidf_lib_rule,lwip,$(ESPIDF_LWIP_O))) $(eval $(call gen_espidf_lib_rule,mbedtls,$(ESPIDF_MBEDTLS_O))) $(eval $(call gen_espidf_lib_rule,wpa_supplicant,$(ESPIDF_WPA_SUPPLICANT_O))) +$(eval $(call gen_espidf_lib_rule,sdmmc,$(ESPIDF_SDMMC_O))) LIB = $(foreach lib,$(LIB_ESPIDF),$(BUILD_ESPIDF_LIB)/$(lib)/lib$(lib).a) diff --git a/ports/esp32/machine_sdcard.c b/ports/esp32/machine_sdcard.c new file mode 100644 index 0000000000..633d4031d6 --- /dev/null +++ b/ports/esp32/machine_sdcard.c @@ -0,0 +1,391 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Nicko van Someren + * + * 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 "py/mperrno.h" +#include "extmod/vfs_fat.h" + +#include "driver/sdmmc_host.h" +#include "driver/sdspi_host.h" +#include "sdmmc_cmd.h" +#include "esp_log.h" + +#define DEBUG 0 +#if DEBUG +#define DEBUG_printf(...) ESP_LOGI("modsdcard", __VA_ARGS__) +#else +#define DEBUG_printf(...) (void)0 +#endif + +// +// There are three layers of abstraction: host, slot and card. +// Creating an SD Card object will initialise the host and slot. +// Cards gets initialised by ioctl op==1 and de-inited by ioctl 2 +// Hosts are de-inited in __del__. Slots do not need de-initing. +// + +// Currently the ESP32 Library doesn't support MMC cards, so +// we don't enable on MICROPY_HW_ENABLE_MMCARD. +#if MICROPY_HW_ENABLE_SDCARD + +// Forward declaration +const mp_obj_type_t machine_sdcard_type; + +typedef struct _sdcard_obj_t { + mp_obj_base_t base; + mp_int_t flags; + sdmmc_host_t host; + // The card structure duplicates the host. It's not clear if we + // can avoid this given the way that it is copied. + sdmmc_card_t card; +} sdcard_card_obj_t; + +#define SDCARD_CARD_FLAGS_HOST_INIT_DONE 0x01 +#define SDCARD_CARD_FLAGS_CARD_INIT_DONE 0x02 + +#define _SECTOR_SIZE(self) (self->card.csd.sector_size) + +STATIC esp_err_t check_esp_err(esp_err_t code) { + switch(code) { + case ESP_OK: + return ESP_OK; + case ESP_ERR_NO_MEM: + code = MP_ENOMEM; + break; + case ESP_ERR_TIMEOUT: + code = MP_ETIMEDOUT; + break; + case ESP_ERR_NOT_SUPPORTED: + code = MP_EOPNOTSUPP; + break; + } + + mp_raise_OSError(code); +} + +STATIC gpio_num_t pin_or_int(const mp_obj_t arg) { + if (mp_obj_is_small_int(arg)) { + return MP_OBJ_SMALL_INT_VALUE(arg); + } else { + // This raises a value error if the argument is not a Pin. + return machine_pin_get_id(arg); + } +} + +#define SET_CONFIG_PIN(config, pin_var, arg_id) \ + if (arg_vals[arg_id].u_obj != mp_const_none) \ + config.pin_var = pin_or_int(arg_vals[arg_id].u_obj) + +STATIC esp_err_t sdcard_ensure_card_init(sdcard_card_obj_t *self, bool force) { + if (force || !(self->flags & SDCARD_CARD_FLAGS_CARD_INIT_DONE)) { + DEBUG_printf(" Calling card init"); + + esp_err_t err = sdmmc_card_init(&(self->host), &(self->card)); + if (err == ESP_OK) { + self->flags |= SDCARD_CARD_FLAGS_CARD_INIT_DONE; + } else { + self->flags &= ~SDCARD_CARD_FLAGS_CARD_INIT_DONE; + } + DEBUG_printf(" Card init returned: %i", err); + + return err; + } else { + return ESP_OK; + } +} + +/******************************************************************************/ +// MicroPython bindings +// +// Expose the SD card or MMC as an object with the block protocol. + +// Create a new SDCard object +// The driver supports either the host SD/MMC controller (default) or SPI mode +// In both cases there are two "slots". Slot 0 on the SD/MMC controller is +// typically tied up with the flash interface in most ESP32 modules but in +// theory supports 1, 4 or 8-bit transfers. Slot 1 supports only 1 and 4-bit +// transfers. Only 1-bit is supported on the SPI interfaces. +// card = SDCard(slot=1, width=None, present_pin=None, wp_pin=None) + +STATIC mp_obj_t machine_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + enum { + ARG_slot, + ARG_width, + ARG_cd, + ARG_wp, + ARG_miso, + ARG_mosi, + ARG_sck, + ARG_cs, + }; + STATIC const mp_arg_t allowed_args[] = { + { MP_QSTR_slot, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_width, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_cd, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_wp, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + // These are only needed if using SPI mode + { MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_cs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + mp_arg_val_t arg_vals[MP_ARRAY_SIZE(allowed_args)]; + mp_map_t kw_args; + + DEBUG_printf("Making new SDCard:n"); + DEBUG_printf(" Unpacking arguments"); + + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + + mp_arg_parse_all(n_args, args, &kw_args, + MP_ARRAY_SIZE(allowed_args), allowed_args, arg_vals); + + DEBUG_printf(" slot=%d, width=%d, cd=%p, wp=%p", + arg_vals[ARG_slot].u_int, arg_vals[ARG_width].u_int, + arg_vals[ARG_cd].u_obj, arg_vals[ARG_wp].u_obj); + + DEBUG_printf(" miso=%p, mosi=%p, sck=%p, cs=%p", + arg_vals[ARG_miso].u_obj, arg_vals[ARG_mosi].u_obj, + arg_vals[ARG_sck].u_obj, arg_vals[ARG_cs].u_obj); + + int slot_num = arg_vals[ARG_slot].u_int; + if (slot_num < 0 || slot_num > 3) { + mp_raise_ValueError("Slot number must be between 0 and 3 inclusive"); + } + + // Slots 0 and 1 are native SD/MMC, slots 2 and 3 are SPI + bool is_spi = (slot_num >= 2); + if (is_spi) { + slot_num -= 2; + } + + DEBUG_printf(" Setting up host configuration"); + + sdcard_card_obj_t *self = m_new_obj_with_finaliser(sdcard_card_obj_t); + self->base.type = &machine_sdcard_type; + self->flags = 0; + // Note that these defaults are macros that expand to structure + // constants so we can't directly assign them to fields. + if (is_spi) { + sdmmc_host_t _temp_host = SDSPI_HOST_DEFAULT(); + self->host = _temp_host; + } else { + sdmmc_host_t _temp_host = SDMMC_HOST_DEFAULT(); + self->host = _temp_host; + } + + if (is_spi) { + self->host.slot = slot_num ? HSPI_HOST : VSPI_HOST; + slot_num -= 2; + } + + DEBUG_printf(" Calling host.init()"); + + check_esp_err(self->host.init()); + self->flags |= SDCARD_CARD_FLAGS_HOST_INIT_DONE; + + if (is_spi) { + // SPI interface + STATIC const sdspi_slot_config_t slot_defaults[2] = { + { + .gpio_miso = GPIO_NUM_19, + .gpio_mosi = GPIO_NUM_23, + .gpio_sck = GPIO_NUM_18, + .gpio_cs = GPIO_NUM_5, + .gpio_cd = SDSPI_SLOT_NO_CD, + .gpio_wp = SDSPI_SLOT_NO_WP, + .dma_channel = 2 + }, + SDSPI_SLOT_CONFIG_DEFAULT() }; + + DEBUG_printf(" Setting up SPI slot configuration"); + sdspi_slot_config_t slot_config = slot_defaults[slot_num]; + + SET_CONFIG_PIN(slot_config, gpio_cd, ARG_cd); + SET_CONFIG_PIN(slot_config, gpio_wp, ARG_wp); + SET_CONFIG_PIN(slot_config, gpio_miso, ARG_miso); + SET_CONFIG_PIN(slot_config, gpio_mosi, ARG_mosi); + SET_CONFIG_PIN(slot_config, gpio_sck, ARG_sck); + SET_CONFIG_PIN(slot_config, gpio_cs, ARG_cs); + + DEBUG_printf(" Calling init_slot()"); + check_esp_err(sdspi_host_init_slot(self->host.slot, &slot_config)); + } else { + // SD/MMC interface + DEBUG_printf(" Setting up SDMMC slot configuration"); + sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); + + // Stronger external pull-ups are still needed but apparently + // it is a good idea to set the internal pull-ups anyway. + // slot_config.flags = SDMMC_SLOT_FLAG_INTERNAL_PULLUP; + + SET_CONFIG_PIN(slot_config, gpio_cd, ARG_cd); + SET_CONFIG_PIN(slot_config, gpio_wp, ARG_wp); + + int width = arg_vals[ARG_width].u_int; + if (width == 1 || width == 4 || (width == 8 && slot_num == 0)) { + slot_config.width = width; + } else { + mp_raise_ValueError("Width must be 1 or 4 (or 8 on slot 0)"); + } + + DEBUG_printf(" Calling init_slot()"); + check_esp_err(sdmmc_host_init_slot(self->host.slot, &slot_config)); + } + + DEBUG_printf(" Returning new card object: %p", self); + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t sd_deinit(mp_obj_t self_in) { + sdcard_card_obj_t *self = self_in; + + DEBUG_printf("De-init host\n"); + + if (self->flags & SDCARD_CARD_FLAGS_HOST_INIT_DONE) { + self->host.deinit(); + self->flags &= ~SDCARD_CARD_FLAGS_HOST_INIT_DONE; + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(sd_deinit_obj, sd_deinit); + +STATIC mp_obj_t sd_info(mp_obj_t self_in) { + sdcard_card_obj_t *self = self_in; + // We could potential return a great deal more SD card data but it + // is not clear that it is worth the extra code space to do + // so. For the most part people only care about the card size and + // block size. + + check_esp_err(sdcard_ensure_card_init((sdcard_card_obj_t *) self, false)); + + uint32_t log_block_nbr = self->card.csd.capacity; + uint32_t log_block_size = _SECTOR_SIZE(self); + + mp_obj_t tuple[2] = { + mp_obj_new_int_from_ull((uint64_t)log_block_nbr * (uint64_t)log_block_size), + mp_obj_new_int_from_uint(log_block_size), + }; + return mp_obj_new_tuple(2, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(sd_info_obj, sd_info); + +STATIC mp_obj_t machine_sdcard_readblocks(mp_obj_t self_in, mp_obj_t block_num, mp_obj_t buf) { + sdcard_card_obj_t *self = self_in; + mp_buffer_info_t bufinfo; + esp_err_t err; + + err = sdcard_ensure_card_init((sdcard_card_obj_t *) self, false); + if (err != ESP_OK) { + return false; + } + + mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_WRITE); + err = sdmmc_read_sectors(&(self->card), bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / _SECTOR_SIZE(self) ); + + return mp_obj_new_bool(err == ESP_OK); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(machine_sdcard_readblocks_obj, machine_sdcard_readblocks); + +STATIC mp_obj_t machine_sdcard_writeblocks(mp_obj_t self_in, mp_obj_t block_num, mp_obj_t buf) { + sdcard_card_obj_t *self = self_in; + mp_buffer_info_t bufinfo; + esp_err_t err; + + err = sdcard_ensure_card_init((sdcard_card_obj_t *) self, false); + if (err != ESP_OK) { + return false; + } + + mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ); + err = sdmmc_write_sectors(&(self->card), bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / _SECTOR_SIZE(self) ); + + return mp_obj_new_bool(err == ESP_OK); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(machine_sdcard_writeblocks_obj, machine_sdcard_writeblocks); + +STATIC mp_obj_t machine_sdcard_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t arg_in) { + sdcard_card_obj_t *self = self_in; + esp_err_t err = ESP_OK; + mp_int_t cmd = mp_obj_get_int(cmd_in); + + switch (cmd) { + case BP_IOCTL_INIT: + err = sdcard_ensure_card_init(self, false); + return MP_OBJ_NEW_SMALL_INT((err == ESP_OK) ? 0 : -1); + + case BP_IOCTL_DEINIT: + // Ensure that future attempts to look at info re-read the card + self->flags &= ~SDCARD_CARD_FLAGS_CARD_INIT_DONE; + return MP_OBJ_NEW_SMALL_INT(0); // success + + case BP_IOCTL_SYNC: + // nothing to do + return MP_OBJ_NEW_SMALL_INT(0); // success + + case BP_IOCTL_SEC_COUNT: + err = sdcard_ensure_card_init(self, false); + if (err != ESP_OK) + return MP_OBJ_NEW_SMALL_INT(-1); + return MP_OBJ_NEW_SMALL_INT(self->card.csd.capacity); + + case BP_IOCTL_SEC_SIZE: + err = sdcard_ensure_card_init(self, false); + if (err != ESP_OK) + return MP_OBJ_NEW_SMALL_INT(-1); + return MP_OBJ_NEW_SMALL_INT(_SECTOR_SIZE(self)); + + default: // unknown command + return MP_OBJ_NEW_SMALL_INT(-1); // error + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(machine_sdcard_ioctl_obj, machine_sdcard_ioctl); + +STATIC const mp_rom_map_elem_t machine_sdcard_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&sd_info_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&sd_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&sd_deinit_obj) }, + // block device protocol + { MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&machine_sdcard_readblocks_obj) }, + { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&machine_sdcard_writeblocks_obj) }, + { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&machine_sdcard_ioctl_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(machine_sdcard_locals_dict, machine_sdcard_locals_dict_table); + +const mp_obj_type_t machine_sdcard_type = { + { &mp_type_type }, + .name = MP_QSTR_SDCard, + .make_new = machine_sdcard_make_new, + .locals_dict = (mp_obj_dict_t*)&machine_sdcard_locals_dict, +}; + +#endif // MICROPY_HW_ENABLE_SDCARD diff --git a/ports/esp32/modmachine.c b/ports/esp32/modmachine.c index bc459ee5c2..fb864947d2 100644 --- a/ports/esp32/modmachine.c +++ b/ports/esp32/modmachine.c @@ -235,6 +235,9 @@ 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) }, + #if MICROPY_HW_ENABLE_SDCARD + { MP_ROM_QSTR(MP_QSTR_SDCard), MP_ROM_PTR(&machine_sdcard_type) }, + #endif // wake abilities { MP_ROM_QSTR(MP_QSTR_SLEEP), MP_ROM_INT(MACHINE_WAKE_SLEEP) }, diff --git a/ports/esp32/modmachine.h b/ports/esp32/modmachine.h index b65b427b4e..ca1776d8bf 100644 --- a/ports/esp32/modmachine.h +++ b/ports/esp32/modmachine.h @@ -19,6 +19,7 @@ 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; +extern const mp_obj_type_t machine_sdcard_type; void machine_pins_init(void); void machine_pins_deinit(void); diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 7b9b400250..bd19c6bfbd 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -141,6 +141,7 @@ #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_HW_ENABLE_SDCARD (1) #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) From 6077d1715013dac50b54d8321a7a0f51db34aa5c Mon Sep 17 00:00:00 2001 From: Nicko van Someren Date: Fri, 31 May 2019 01:04:32 -0600 Subject: [PATCH 0409/1788] docs/machine: Add initial docs for new machine.SDCard class. --- docs/library/machine.SD.rst | 4 +- docs/library/machine.SDCard.rst | 122 ++++++++++++++++++++++++++++++++ docs/library/machine.rst | 1 + 3 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 docs/library/machine.SDCard.rst diff --git a/docs/library/machine.SD.rst b/docs/library/machine.SD.rst index 9c58e73545..d985db231a 100644 --- a/docs/library/machine.SD.rst +++ b/docs/library/machine.SD.rst @@ -1,8 +1,8 @@ .. currentmodule:: machine .. _machine.SD: -class SD -- secure digital memory card -====================================== +class SD -- secure digital memory card (cc3200 port only) +========================================================= .. warning:: diff --git a/docs/library/machine.SDCard.rst b/docs/library/machine.SDCard.rst new file mode 100644 index 0000000000..34bb2e48bf --- /dev/null +++ b/docs/library/machine.SDCard.rst @@ -0,0 +1,122 @@ +.. currentmodule:: machine +.. _machine.SDCard: + +class SDCard -- secure digital memory card +========================================== + +SD cards are one of the most common small form factor removable storage media. +SD cards come in a variety of sizes and phsyical form factors. MMC cards are +similar removable storage devices while eMMC devices are electically similar +storage devices designed to be embedded into other systems. All three form +share a common protocol for communication with their host system and high-level +support looks the same for them all. As such in MicroPython they are implemented +in a single class called :class:`machine.SDCard` . + +Both SD and MMC interfaces support being accessed with a variety of bus widths. +When being accessed with a 1-bit wide interface they can be accessed using the +SPI protocol. Different MicroPython hardware platforms support different widths +and pin configurations but for most platforms there is a standard configuation +for any given hardware. In general constructing an `SDCard`` object with without +passing any parameters will initialise the interface to the default card slot +for the current hardware. The arguments listed below represent the common +arguments that might need to be set in order to use either a non-stanard slot +or a non-standard pin assignment. The exact subset of arguments suported will +vary from platform to platform. + +.. class:: SDCard(slot=1, width=1, cd=None, wp=None, sck=None, miso=None, mosi=None, cs=None) + + This class provides access to SD or MMC storage cards using either + a dedicated SD/MMC interface hardware or through an SPI channel. + The class implements the block protocol defined by :class:`uos.AbstractBlockDev`. + This allows the mounting of an SD card to be as simple as:: + + uos.mount(storage.SDCard(), "/sd") + + The constrcutor takes the following paramters: + + - *slot* selects which of the available interfaces to use. Leaving this + unset will select the default interface. + + - *width* selects the bus width for the SD/MMC interface. + + - *cd* can be used to specify a card-detect pin. + + - *wp* can be used to specify a write-protect pin. + + - *sck* can be used to specify an SPI clock pin. + + - *miso* can be used to specify an SPI miso pin. + + - *mosi* can be used to specify an SPI mosi pin. + + - *cs* can be used to specify an SPI chip select pin. + +Implementation-specific details +------------------------------- + +Different implementations of the ``SDCard`` class on different hardware support +varying subsets of the options above. + +PyBoard +``````` + +The standard PyBoard has just one slot. No arguments are necessary or supported. + +ESP32 +````` + +The ESP32 provides two channels of SD/MMC hardware and also supports +access to SD Cards through either of the two SPI ports that are +generally available to the user. As a result the *slot* argument can +take a value between 0 and 3, inclusive. Slots 0 and 1 use the +built-in SD/MMC hardware while slots 2 and 3 use the SPI ports. Slot 0 +supports 1, 4 or 8-bit wide access while slot 1 supports 1 or 4-bit +access; the SPI slots only support 1-bit access. + + .. note:: Slot 0 is used to communicate with on-board flash memory + on most ESP32 modules and so will be unavailable to the + user. + + .. note:: Most ESP32 modules that provide an SD card slot using the + dedicated hardware only wire up 1 data pin, so the default + value for *width* is 1. + +The pins used by the dedicated SD/MMC hardware are fixed. The pins +used by the SPI hardware can be reassigned. + + .. note:: If any of the SPI signals are remapped then all of the SPI + signals will pass through a GPIO multiplexer unit which + can limit the performance of high frequency signals. Since + the normal operating speed for SD cards is 40MHz this can + cause problems on some cards. + +The default (and preferred) pin assignment are as follows: + + ====== ====== ====== ====== ====== + Slot 0 1 2 3 + ------ ------ ------ ------ ------ + Signal Pin Pin Pin Pin + ====== ====== ====== ====== ====== + sck 6 14 18 14 + cmd 11 15 + cs 5 15 + miso 19 12 + mosi 23 13 + D0 7 2 + D1 8 4 + D2 9 12 + D3 10 13 + D4 16 + D5 17 + D6 5 + D7 18 + ====== ====== ====== ====== ====== + +cc3200 +`````` + +You can set the pins used for SPI access by passing a tuple as the +*pins* argument. + +*Note:* The current cc3200 SD card implementation names the this class +:class:`machine.SD` rather than :class:`machine.SDCard` . diff --git a/docs/library/machine.rst b/docs/library/machine.rst index a7b5957761..8cc5efe593 100644 --- a/docs/library/machine.rst +++ b/docs/library/machine.rst @@ -168,3 +168,4 @@ Classes machine.Timer.rst machine.WDT.rst machine.SD.rst + machine.SDCard.rst From 0a6c479187d0b50a92b65f639e377678bde8034e Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 29 May 2019 19:06:17 +1000 Subject: [PATCH 0410/1788] lib/cmsis: Upgrade to CMSIS 5.5.1. From https://github.com/ARM-software/CMSIS_5.git, tag 5.5.1 --- lib/cmsis/inc/cmsis_armcc.h | 247 +- lib/cmsis/inc/cmsis_armclang.h | 1420 ++++++++ ...{cmsis_armcc_V6.h => cmsis_armclang_ltm.h} | 970 +++--- lib/cmsis/inc/cmsis_compiler.h | 271 ++ lib/cmsis/inc/cmsis_gcc.h | 1162 +++++-- lib/cmsis/inc/cmsis_iccarm.h | 940 ++++++ lib/cmsis/inc/cmsis_version.h | 39 + lib/cmsis/inc/core_armv81mml.h | 2967 +++++++++++++++++ lib/cmsis/inc/core_armv8mbl.h | 1918 +++++++++++ lib/cmsis/inc/core_armv8mml.h | 2832 ++++++++++++++++ lib/cmsis/inc/core_cm0.h | 403 ++- lib/cmsis/inc/core_cm0plus.h | 428 ++- lib/cmsis/inc/core_cm1.h | 976 ++++++ lib/cmsis/inc/core_cm23.h | 1993 +++++++++++ lib/cmsis/inc/core_cm3.h | 519 ++- lib/cmsis/inc/core_cm33.h | 2907 ++++++++++++++++ lib/cmsis/inc/core_cm35p.h | 2907 ++++++++++++++++ lib/cmsis/inc/core_cm4.h | 560 ++-- lib/cmsis/inc/core_cm7.h | 719 ++-- lib/cmsis/inc/core_cmFunc.h | 87 - lib/cmsis/inc/core_cmInstr.h | 87 - lib/cmsis/inc/core_cmSimd.h | 96 - lib/cmsis/inc/core_sc000.h | 350 +- lib/cmsis/inc/core_sc300.h | 468 ++- lib/cmsis/inc/mpu_armv7.h | 272 ++ lib/cmsis/inc/mpu_armv8.h | 346 ++ lib/cmsis/inc/tz_context.h | 70 + 27 files changed, 23795 insertions(+), 2159 deletions(-) create mode 100644 lib/cmsis/inc/cmsis_armclang.h rename lib/cmsis/inc/{cmsis_armcc_V6.h => cmsis_armclang_ltm.h} (56%) create mode 100644 lib/cmsis/inc/cmsis_compiler.h create mode 100644 lib/cmsis/inc/cmsis_iccarm.h create mode 100644 lib/cmsis/inc/cmsis_version.h create mode 100644 lib/cmsis/inc/core_armv81mml.h create mode 100644 lib/cmsis/inc/core_armv8mbl.h create mode 100644 lib/cmsis/inc/core_armv8mml.h create mode 100644 lib/cmsis/inc/core_cm1.h create mode 100644 lib/cmsis/inc/core_cm23.h create mode 100644 lib/cmsis/inc/core_cm33.h create mode 100644 lib/cmsis/inc/core_cm35p.h delete mode 100644 lib/cmsis/inc/core_cmFunc.h delete mode 100644 lib/cmsis/inc/core_cmInstr.h delete mode 100644 lib/cmsis/inc/core_cmSimd.h create mode 100644 lib/cmsis/inc/mpu_armv7.h create mode 100644 lib/cmsis/inc/mpu_armv8.h create mode 100644 lib/cmsis/inc/tz_context.h diff --git a/lib/cmsis/inc/cmsis_armcc.h b/lib/cmsis/inc/cmsis_armcc.h index 74c49c67de..174d744033 100644 --- a/lib/cmsis/inc/cmsis_armcc.h +++ b/lib/cmsis/inc/cmsis_armcc.h @@ -1,43 +1,108 @@ /**************************************************************************//** * @file cmsis_armcc.h - * @brief CMSIS Cortex-M Core Function/Instruction Header File - * @version V4.30 - * @date 20. October 2015 + * @brief CMSIS compiler ARMCC (Arm Compiler 5) header file + * @version V5.0.5 + * @date 14. December 2018 ******************************************************************************/ -/* Copyright (c) 2009 - 2015 ARM LIMITED - - All rights reserved. - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 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. - - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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. - ---------------------------------------------------------------------------*/ - +/* + * Copyright (c) 2009-2018 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #ifndef __CMSIS_ARMCC_H #define __CMSIS_ARMCC_H #if defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 400677) - #error "Please use ARM Compiler Toolchain V4.0.677 or later!" + #error "Please use Arm Compiler Toolchain V4.0.677 or later!" +#endif + +/* CMSIS compiler control architecture macros */ +#if ((defined (__TARGET_ARCH_6_M ) && (__TARGET_ARCH_6_M == 1)) || \ + (defined (__TARGET_ARCH_6S_M ) && (__TARGET_ARCH_6S_M == 1)) ) + #define __ARM_ARCH_6M__ 1 +#endif + +#if (defined (__TARGET_ARCH_7_M ) && (__TARGET_ARCH_7_M == 1)) + #define __ARM_ARCH_7M__ 1 +#endif + +#if (defined (__TARGET_ARCH_7E_M) && (__TARGET_ARCH_7E_M == 1)) + #define __ARM_ARCH_7EM__ 1 +#endif + + /* __ARM_ARCH_8M_BASE__ not applicable */ + /* __ARM_ARCH_8M_MAIN__ not applicable */ + +/* CMSIS compiler control DSP macros */ +#if ((defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) ) + #define __ARM_FEATURE_DSP 1 +#endif + +/* CMSIS compiler specific defines */ +#ifndef __ASM + #define __ASM __asm +#endif +#ifndef __INLINE + #define __INLINE __inline +#endif +#ifndef __STATIC_INLINE + #define __STATIC_INLINE static __inline +#endif +#ifndef __STATIC_FORCEINLINE + #define __STATIC_FORCEINLINE static __forceinline +#endif +#ifndef __NO_RETURN + #define __NO_RETURN __declspec(noreturn) +#endif +#ifndef __USED + #define __USED __attribute__((used)) +#endif +#ifndef __WEAK + #define __WEAK __attribute__((weak)) +#endif +#ifndef __PACKED + #define __PACKED __attribute__((packed)) +#endif +#ifndef __PACKED_STRUCT + #define __PACKED_STRUCT __packed struct +#endif +#ifndef __PACKED_UNION + #define __PACKED_UNION __packed union +#endif +#ifndef __UNALIGNED_UINT32 /* deprecated */ + #define __UNALIGNED_UINT32(x) (*((__packed uint32_t *)(x))) +#endif +#ifndef __UNALIGNED_UINT16_WRITE + #define __UNALIGNED_UINT16_WRITE(addr, val) ((*((__packed uint16_t *)(addr))) = (val)) +#endif +#ifndef __UNALIGNED_UINT16_READ + #define __UNALIGNED_UINT16_READ(addr) (*((const __packed uint16_t *)(addr))) +#endif +#ifndef __UNALIGNED_UINT32_WRITE + #define __UNALIGNED_UINT32_WRITE(addr, val) ((*((__packed uint32_t *)(addr))) = (val)) +#endif +#ifndef __UNALIGNED_UINT32_READ + #define __UNALIGNED_UINT32_READ(addr) (*((const __packed uint32_t *)(addr))) +#endif +#ifndef __ALIGNED + #define __ALIGNED(x) __attribute__((aligned(x))) +#endif +#ifndef __RESTRICT + #define __RESTRICT __restrict #endif /* ########################### Core Function Access ########################### */ @@ -46,7 +111,19 @@ @{ */ +/** + \brief Enable IRQ Interrupts + \details Enables IRQ interrupts by clearing the I-bit in the CPSR. + Can only be executed in Privileged modes. + */ /* intrinsic void __enable_irq(); */ + + +/** + \brief Disable IRQ Interrupts + \details Disables IRQ interrupts by setting the I-bit in the CPSR. + Can only be executed in Privileged modes. + */ /* intrinsic void __disable_irq(); */ /** @@ -181,7 +258,8 @@ __STATIC_INLINE void __set_PRIMASK(uint32_t priMask) } -#if (__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U) +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) ) /** \brief Enable FIQ @@ -256,14 +334,13 @@ __STATIC_INLINE uint32_t __get_FAULTMASK(void) __STATIC_INLINE void __set_FAULTMASK(uint32_t faultMask) { register uint32_t __regFaultMask __ASM("faultmask"); - __regFaultMask = (faultMask & (uint32_t)1); + __regFaultMask = (faultMask & (uint32_t)1U); } -#endif /* (__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U) */ +#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) ) */ -#if (__CORTEX_M == 0x04U) || (__CORTEX_M == 0x07U) - /** \brief Get FPSCR \details Returns the current value of the Floating Point Status/Control register. @@ -271,7 +348,8 @@ __STATIC_INLINE void __set_FAULTMASK(uint32_t faultMask) */ __STATIC_INLINE uint32_t __get_FPSCR(void) { -#if (__FPU_PRESENT == 1U) && (__FPU_USED == 1U) +#if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ + (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) register uint32_t __regfpscr __ASM("fpscr"); return(__regfpscr); #else @@ -287,15 +365,15 @@ __STATIC_INLINE uint32_t __get_FPSCR(void) */ __STATIC_INLINE void __set_FPSCR(uint32_t fpscr) { -#if (__FPU_PRESENT == 1U) && (__FPU_USED == 1U) +#if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ + (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) register uint32_t __regfpscr __ASM("fpscr"); __regfpscr = (fpscr); +#else + (void)fpscr; #endif } -#endif /* (__CORTEX_M == 0x04U) || (__CORTEX_M == 0x07U) */ - - /*@} end of CMSIS_Core_RegAccFunctions */ @@ -369,9 +447,10 @@ __STATIC_INLINE void __set_FPSCR(uint32_t fpscr) __schedule_barrier();\ } while (0U) + /** \brief Reverse byte order (32 bit) - \details Reverses the byte order in integer value. + \details Reverses the byte order in unsigned integer value. For example, 0x12345678 becomes 0x78563412. \param [in] value Value to reverse \return Reversed value */ @@ -380,7 +459,7 @@ __STATIC_INLINE void __set_FPSCR(uint32_t fpscr) /** \brief Reverse byte order (16 bit) - \details Reverses the byte order in two unsigned short values. + \details Reverses the byte order within each halfword of a word. For example, 0x12345678 becomes 0x34127856. \param [in] value Value to reverse \return Reversed value */ @@ -392,14 +471,15 @@ __attribute__((section(".rev16_text"))) __STATIC_INLINE __ASM uint32_t __REV16(u } #endif + /** - \brief Reverse byte order in signed short value - \details Reverses the byte order in a signed short value with sign extension to integer. + \brief Reverse byte order (16 bit) + \details Reverses the byte order in a 16-bit value and returns the signed 16-bit result. For example, 0x0080 becomes 0x8000. \param [in] value Value to reverse \return Reversed value */ #ifndef __NO_EMBEDDED_ASM -__attribute__((section(".revsh_text"))) __STATIC_INLINE __ASM int32_t __REVSH(int32_t value) +__attribute__((section(".revsh_text"))) __STATIC_INLINE __ASM int16_t __REVSH(int16_t value) { revsh r0, r0 bx lr @@ -410,8 +490,8 @@ __attribute__((section(".revsh_text"))) __STATIC_INLINE __ASM int32_t __REVSH(in /** \brief Rotate Right in unsigned value (32 bit) \details Rotate Right (immediate) provides the value of the contents of a register rotated by a variable number of bits. - \param [in] value Value to rotate - \param [in] value Number of Bits to rotate + \param [in] op1 Value to rotate + \param [in] op2 Number of Bits to rotate \return Rotated value */ #define __ROR __ror @@ -433,23 +513,24 @@ __attribute__((section(".revsh_text"))) __STATIC_INLINE __ASM int32_t __REVSH(in \param [in] value Value to reverse \return Reversed value */ -#if (__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U) +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) ) #define __RBIT __rbit #else __attribute__((always_inline)) __STATIC_INLINE uint32_t __RBIT(uint32_t value) { uint32_t result; - int32_t s = 4 /*sizeof(v)*/ * 8 - 1; /* extra shift needed at end */ + uint32_t s = (4U /*sizeof(v)*/ * 8U) - 1U; /* extra shift needed at end */ result = value; /* r will be reversed bits of v; first get LSB of v */ - for (value >>= 1U; value; value >>= 1U) + for (value >>= 1U; value != 0U; value >>= 1U) { result <<= 1U; result |= value & 1U; s--; } result <<= s; /* shift when v's highest bits are zero */ - return(result); + return result; } #endif @@ -463,7 +544,8 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __RBIT(uint32_t value) #define __CLZ __clz -#if (__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U) +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) ) /** \brief LDR Exclusive (8 bit) @@ -645,7 +727,60 @@ __attribute__((section(".rrx_text"))) __STATIC_INLINE __ASM uint32_t __RRX(uint3 */ #define __STRT(value, ptr) __strt(value, ptr) -#endif /* (__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U) */ +#else /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) ) */ + +/** + \brief Signed Saturate + \details Saturates a signed value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (1..32) + \return Saturated value + */ +__attribute__((always_inline)) __STATIC_INLINE int32_t __SSAT(int32_t val, uint32_t sat) +{ + if ((sat >= 1U) && (sat <= 32U)) + { + const int32_t max = (int32_t)((1U << (sat - 1U)) - 1U); + const int32_t min = -1 - max ; + if (val > max) + { + return max; + } + else if (val < min) + { + return min; + } + } + return val; +} + +/** + \brief Unsigned Saturate + \details Saturates an unsigned value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (0..31) + \return Saturated value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __USAT(int32_t val, uint32_t sat) +{ + if (sat <= 31U) + { + const uint32_t max = ((1U << sat) - 1U); + if (val > (int32_t)max) + { + return max; + } + else if (val < 0) + { + return 0U; + } + } + return (uint32_t)val; +} + +#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) ) */ /*@}*/ /* end of group CMSIS_Core_InstructionInterface */ @@ -656,7 +791,7 @@ __attribute__((section(".rrx_text"))) __STATIC_INLINE __ASM uint32_t __RRX(uint3 @{ */ -#if (__CORTEX_M >= 0x04U) /* only for Cortex-M4 and above */ +#if ((defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) ) #define __SADD8 __sadd8 #define __QADD8 __qadd8 @@ -727,7 +862,7 @@ __attribute__((section(".rrx_text"))) __STATIC_INLINE __ASM uint32_t __RRX(uint3 #define __SMMLA(ARG1,ARG2,ARG3) ( (int32_t)((((int64_t)(ARG1) * (ARG2)) + \ ((int64_t)(ARG3) << 32U) ) >> 32U)) -#endif /* (__CORTEX_M >= 0x04) */ +#endif /* ((defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) ) */ /*@} end of group CMSIS_SIMD_intrinsics */ diff --git a/lib/cmsis/inc/cmsis_armclang.h b/lib/cmsis/inc/cmsis_armclang.h new file mode 100644 index 0000000000..6a8867d574 --- /dev/null +++ b/lib/cmsis/inc/cmsis_armclang.h @@ -0,0 +1,1420 @@ +/**************************************************************************//** + * @file cmsis_armclang.h + * @brief CMSIS compiler armclang (Arm Compiler 6) header file + * @version V5.1.0 + * @date 14. March 2019 + ******************************************************************************/ +/* + * Copyright (c) 2009-2019 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*lint -esym(9058, IRQn)*/ /* disable MISRA 2012 Rule 2.4 for IRQn */ + +#ifndef __CMSIS_ARMCLANG_H +#define __CMSIS_ARMCLANG_H + +#pragma clang system_header /* treat file as system include file */ + +#ifndef __ARM_COMPAT_H +#include /* Compatibility header for Arm Compiler 5 intrinsics */ +#endif + +/* CMSIS compiler specific defines */ +#ifndef __ASM + #define __ASM __asm +#endif +#ifndef __INLINE + #define __INLINE __inline +#endif +#ifndef __STATIC_INLINE + #define __STATIC_INLINE static __inline +#endif +#ifndef __STATIC_FORCEINLINE + #define __STATIC_FORCEINLINE __attribute__((always_inline)) static __inline +#endif +#ifndef __NO_RETURN + #define __NO_RETURN __attribute__((__noreturn__)) +#endif +#ifndef __USED + #define __USED __attribute__((used)) +#endif +#ifndef __WEAK + #define __WEAK __attribute__((weak)) +#endif +#ifndef __PACKED + #define __PACKED __attribute__((packed, aligned(1))) +#endif +#ifndef __PACKED_STRUCT + #define __PACKED_STRUCT struct __attribute__((packed, aligned(1))) +#endif +#ifndef __PACKED_UNION + #define __PACKED_UNION union __attribute__((packed, aligned(1))) +#endif +#ifndef __UNALIGNED_UINT32 /* deprecated */ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wpacked" +/*lint -esym(9058, T_UINT32)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT32 */ + struct __attribute__((packed)) T_UINT32 { uint32_t v; }; + #pragma clang diagnostic pop + #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) +#endif +#ifndef __UNALIGNED_UINT16_WRITE + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wpacked" +/*lint -esym(9058, T_UINT16_WRITE)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT16_WRITE */ + __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; + #pragma clang diagnostic pop + #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val)) +#endif +#ifndef __UNALIGNED_UINT16_READ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wpacked" +/*lint -esym(9058, T_UINT16_READ)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT16_READ */ + __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; + #pragma clang diagnostic pop + #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) +#endif +#ifndef __UNALIGNED_UINT32_WRITE + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wpacked" +/*lint -esym(9058, T_UINT32_WRITE)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT32_WRITE */ + __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; + #pragma clang diagnostic pop + #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) +#endif +#ifndef __UNALIGNED_UINT32_READ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wpacked" +/*lint -esym(9058, T_UINT32_READ)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT32_READ */ + __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; + #pragma clang diagnostic pop + #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) +#endif +#ifndef __ALIGNED + #define __ALIGNED(x) __attribute__((aligned(x))) +#endif +#ifndef __RESTRICT + #define __RESTRICT __restrict +#endif + + +/* ########################### Core Function Access ########################### */ +/** \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions + @{ + */ + +/** + \brief Enable IRQ Interrupts + \details Enables IRQ interrupts by clearing the I-bit in the CPSR. + Can only be executed in Privileged modes. + */ +/* intrinsic void __enable_irq(); see arm_compat.h */ + + +/** + \brief Disable IRQ Interrupts + \details Disables IRQ interrupts by setting the I-bit in the CPSR. + Can only be executed in Privileged modes. + */ +/* intrinsic void __disable_irq(); see arm_compat.h */ + + +/** + \brief Get Control Register + \details Returns the content of the Control Register. + \return Control Register value + */ +__STATIC_FORCEINLINE uint32_t __get_CONTROL(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, control" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Control Register (non-secure) + \details Returns the content of the non-secure Control Register when in secure mode. + \return non-secure Control Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_CONTROL_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, control_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Control Register + \details Writes the given value to the Control Register. + \param [in] control Control Register value to set + */ +__STATIC_FORCEINLINE void __set_CONTROL(uint32_t control) +{ + __ASM volatile ("MSR control, %0" : : "r" (control) : "memory"); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Control Register (non-secure) + \details Writes the given value to the non-secure Control Register when in secure state. + \param [in] control Control Register value to set + */ +__STATIC_FORCEINLINE void __TZ_set_CONTROL_NS(uint32_t control) +{ + __ASM volatile ("MSR control_ns, %0" : : "r" (control) : "memory"); +} +#endif + + +/** + \brief Get IPSR Register + \details Returns the content of the IPSR Register. + \return IPSR Register value + */ +__STATIC_FORCEINLINE uint32_t __get_IPSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, ipsr" : "=r" (result) ); + return(result); +} + + +/** + \brief Get APSR Register + \details Returns the content of the APSR Register. + \return APSR Register value + */ +__STATIC_FORCEINLINE uint32_t __get_APSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, apsr" : "=r" (result) ); + return(result); +} + + +/** + \brief Get xPSR Register + \details Returns the content of the xPSR Register. + \return xPSR Register value + */ +__STATIC_FORCEINLINE uint32_t __get_xPSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, xpsr" : "=r" (result) ); + return(result); +} + + +/** + \brief Get Process Stack Pointer + \details Returns the current value of the Process Stack Pointer (PSP). + \return PSP Register value + */ +__STATIC_FORCEINLINE uint32_t __get_PSP(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, psp" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Process Stack Pointer (non-secure) + \details Returns the current value of the non-secure Process Stack Pointer (PSP) when in secure state. + \return PSP Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_PSP_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, psp_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Process Stack Pointer + \details Assigns the given value to the Process Stack Pointer (PSP). + \param [in] topOfProcStack Process Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __set_PSP(uint32_t topOfProcStack) +{ + __ASM volatile ("MSR psp, %0" : : "r" (topOfProcStack) : ); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Process Stack Pointer (non-secure) + \details Assigns the given value to the non-secure Process Stack Pointer (PSP) when in secure state. + \param [in] topOfProcStack Process Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __TZ_set_PSP_NS(uint32_t topOfProcStack) +{ + __ASM volatile ("MSR psp_ns, %0" : : "r" (topOfProcStack) : ); +} +#endif + + +/** + \brief Get Main Stack Pointer + \details Returns the current value of the Main Stack Pointer (MSP). + \return MSP Register value + */ +__STATIC_FORCEINLINE uint32_t __get_MSP(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, msp" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Main Stack Pointer (non-secure) + \details Returns the current value of the non-secure Main Stack Pointer (MSP) when in secure state. + \return MSP Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_MSP_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, msp_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Main Stack Pointer + \details Assigns the given value to the Main Stack Pointer (MSP). + \param [in] topOfMainStack Main Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __set_MSP(uint32_t topOfMainStack) +{ + __ASM volatile ("MSR msp, %0" : : "r" (topOfMainStack) : ); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Main Stack Pointer (non-secure) + \details Assigns the given value to the non-secure Main Stack Pointer (MSP) when in secure state. + \param [in] topOfMainStack Main Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __TZ_set_MSP_NS(uint32_t topOfMainStack) +{ + __ASM volatile ("MSR msp_ns, %0" : : "r" (topOfMainStack) : ); +} +#endif + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Stack Pointer (non-secure) + \details Returns the current value of the non-secure Stack Pointer (SP) when in secure state. + \return SP Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_SP_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, sp_ns" : "=r" (result) ); + return(result); +} + + +/** + \brief Set Stack Pointer (non-secure) + \details Assigns the given value to the non-secure Stack Pointer (SP) when in secure state. + \param [in] topOfStack Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __TZ_set_SP_NS(uint32_t topOfStack) +{ + __ASM volatile ("MSR sp_ns, %0" : : "r" (topOfStack) : ); +} +#endif + + +/** + \brief Get Priority Mask + \details Returns the current state of the priority mask bit from the Priority Mask Register. + \return Priority Mask value + */ +__STATIC_FORCEINLINE uint32_t __get_PRIMASK(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, primask" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Priority Mask (non-secure) + \details Returns the current state of the non-secure priority mask bit from the Priority Mask Register when in secure state. + \return Priority Mask value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_PRIMASK_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, primask_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Priority Mask + \details Assigns the given value to the Priority Mask Register. + \param [in] priMask Priority Mask + */ +__STATIC_FORCEINLINE void __set_PRIMASK(uint32_t priMask) +{ + __ASM volatile ("MSR primask, %0" : : "r" (priMask) : "memory"); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Priority Mask (non-secure) + \details Assigns the given value to the non-secure Priority Mask Register when in secure state. + \param [in] priMask Priority Mask + */ +__STATIC_FORCEINLINE void __TZ_set_PRIMASK_NS(uint32_t priMask) +{ + __ASM volatile ("MSR primask_ns, %0" : : "r" (priMask) : "memory"); +} +#endif + + +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) +/** + \brief Enable FIQ + \details Enables FIQ interrupts by clearing the F-bit in the CPSR. + Can only be executed in Privileged modes. + */ +#define __enable_fault_irq __enable_fiq /* see arm_compat.h */ + + +/** + \brief Disable FIQ + \details Disables FIQ interrupts by setting the F-bit in the CPSR. + Can only be executed in Privileged modes. + */ +#define __disable_fault_irq __disable_fiq /* see arm_compat.h */ + + +/** + \brief Get Base Priority + \details Returns the current value of the Base Priority register. + \return Base Priority register value + */ +__STATIC_FORCEINLINE uint32_t __get_BASEPRI(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, basepri" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Base Priority (non-secure) + \details Returns the current value of the non-secure Base Priority register when in secure state. + \return Base Priority register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_BASEPRI_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, basepri_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Base Priority + \details Assigns the given value to the Base Priority register. + \param [in] basePri Base Priority value to set + */ +__STATIC_FORCEINLINE void __set_BASEPRI(uint32_t basePri) +{ + __ASM volatile ("MSR basepri, %0" : : "r" (basePri) : "memory"); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Base Priority (non-secure) + \details Assigns the given value to the non-secure Base Priority register when in secure state. + \param [in] basePri Base Priority value to set + */ +__STATIC_FORCEINLINE void __TZ_set_BASEPRI_NS(uint32_t basePri) +{ + __ASM volatile ("MSR basepri_ns, %0" : : "r" (basePri) : "memory"); +} +#endif + + +/** + \brief Set Base Priority with condition + \details Assigns the given value to the Base Priority register only if BASEPRI masking is disabled, + or the new value increases the BASEPRI priority level. + \param [in] basePri Base Priority value to set + */ +__STATIC_FORCEINLINE void __set_BASEPRI_MAX(uint32_t basePri) +{ + __ASM volatile ("MSR basepri_max, %0" : : "r" (basePri) : "memory"); +} + + +/** + \brief Get Fault Mask + \details Returns the current value of the Fault Mask register. + \return Fault Mask register value + */ +__STATIC_FORCEINLINE uint32_t __get_FAULTMASK(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, faultmask" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Fault Mask (non-secure) + \details Returns the current value of the non-secure Fault Mask register when in secure state. + \return Fault Mask register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_FAULTMASK_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, faultmask_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Fault Mask + \details Assigns the given value to the Fault Mask register. + \param [in] faultMask Fault Mask value to set + */ +__STATIC_FORCEINLINE void __set_FAULTMASK(uint32_t faultMask) +{ + __ASM volatile ("MSR faultmask, %0" : : "r" (faultMask) : "memory"); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Fault Mask (non-secure) + \details Assigns the given value to the non-secure Fault Mask register when in secure state. + \param [in] faultMask Fault Mask value to set + */ +__STATIC_FORCEINLINE void __TZ_set_FAULTMASK_NS(uint32_t faultMask) +{ + __ASM volatile ("MSR faultmask_ns, %0" : : "r" (faultMask) : "memory"); +} +#endif + +#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) */ + + +#if ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) + +/** + \brief Get Process Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always in non-secure + mode. + + \details Returns the current value of the Process Stack Pointer Limit (PSPLIM). + \return PSPLIM Register value + */ +__STATIC_FORCEINLINE uint32_t __get_PSPLIM(void) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; + __ASM volatile ("MRS %0, psplim" : "=r" (result) ); + return result; +#endif +} + +#if (defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Process Stack Pointer Limit (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always in non-secure + mode. + + \details Returns the current value of the non-secure Process Stack Pointer Limit (PSPLIM) when in secure state. + \return PSPLIM Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_PSPLIM_NS(void) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; + __ASM volatile ("MRS %0, psplim_ns" : "=r" (result) ); + return result; +#endif +} +#endif + + +/** + \brief Set Process Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored in non-secure + mode. + + \details Assigns the given value to the Process Stack Pointer Limit (PSPLIM). + \param [in] ProcStackPtrLimit Process Stack Pointer Limit value to set + */ +__STATIC_FORCEINLINE void __set_PSPLIM(uint32_t ProcStackPtrLimit) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + (void)ProcStackPtrLimit; +#else + __ASM volatile ("MSR psplim, %0" : : "r" (ProcStackPtrLimit)); +#endif +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Process Stack Pointer (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored in non-secure + mode. + + \details Assigns the given value to the non-secure Process Stack Pointer Limit (PSPLIM) when in secure state. + \param [in] ProcStackPtrLimit Process Stack Pointer Limit value to set + */ +__STATIC_FORCEINLINE void __TZ_set_PSPLIM_NS(uint32_t ProcStackPtrLimit) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + (void)ProcStackPtrLimit; +#else + __ASM volatile ("MSR psplim_ns, %0\n" : : "r" (ProcStackPtrLimit)); +#endif +} +#endif + + +/** + \brief Get Main Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always. + + \details Returns the current value of the Main Stack Pointer Limit (MSPLIM). + \return MSPLIM Register value + */ +__STATIC_FORCEINLINE uint32_t __get_MSPLIM(void) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; + __ASM volatile ("MRS %0, msplim" : "=r" (result) ); + return result; +#endif +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Main Stack Pointer Limit (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always. + + \details Returns the current value of the non-secure Main Stack Pointer Limit(MSPLIM) when in secure state. + \return MSPLIM Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_MSPLIM_NS(void) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; + __ASM volatile ("MRS %0, msplim_ns" : "=r" (result) ); + return result; +#endif +} +#endif + + +/** + \brief Set Main Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored. + + \details Assigns the given value to the Main Stack Pointer Limit (MSPLIM). + \param [in] MainStackPtrLimit Main Stack Pointer Limit value to set + */ +__STATIC_FORCEINLINE void __set_MSPLIM(uint32_t MainStackPtrLimit) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + (void)MainStackPtrLimit; +#else + __ASM volatile ("MSR msplim, %0" : : "r" (MainStackPtrLimit)); +#endif +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Main Stack Pointer Limit (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored. + + \details Assigns the given value to the non-secure Main Stack Pointer Limit (MSPLIM) when in secure state. + \param [in] MainStackPtrLimit Main Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __TZ_set_MSPLIM_NS(uint32_t MainStackPtrLimit) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + (void)MainStackPtrLimit; +#else + __ASM volatile ("MSR msplim_ns, %0" : : "r" (MainStackPtrLimit)); +#endif +} +#endif + +#endif /* ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) */ + +/** + \brief Get FPSCR + \details Returns the current value of the Floating Point Status/Control register. + \return Floating Point Status/Control register value + */ +#if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ + (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) +#define __get_FPSCR (uint32_t)__builtin_arm_get_fpscr +#else +#define __get_FPSCR() ((uint32_t)0U) +#endif + +/** + \brief Set FPSCR + \details Assigns the given value to the Floating Point Status/Control register. + \param [in] fpscr Floating Point Status/Control value to set + */ +#if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ + (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) +#define __set_FPSCR __builtin_arm_set_fpscr +#else +#define __set_FPSCR(x) ((void)(x)) +#endif + + +/*@} end of CMSIS_Core_RegAccFunctions */ + + +/* ########################## Core Instruction Access ######################### */ +/** \defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface + Access to dedicated instructions + @{ +*/ + +/* Define macros for porting to both thumb1 and thumb2. + * For thumb1, use low register (r0-r7), specified by constraint "l" + * Otherwise, use general registers, specified by constraint "r" */ +#if defined (__thumb__) && !defined (__thumb2__) +#define __CMSIS_GCC_OUT_REG(r) "=l" (r) +#define __CMSIS_GCC_RW_REG(r) "+l" (r) +#define __CMSIS_GCC_USE_REG(r) "l" (r) +#else +#define __CMSIS_GCC_OUT_REG(r) "=r" (r) +#define __CMSIS_GCC_RW_REG(r) "+r" (r) +#define __CMSIS_GCC_USE_REG(r) "r" (r) +#endif + +/** + \brief No Operation + \details No Operation does nothing. This instruction can be used for code alignment purposes. + */ +#define __NOP __builtin_arm_nop + +/** + \brief Wait For Interrupt + \details Wait For Interrupt is a hint instruction that suspends execution until one of a number of events occurs. + */ +#define __WFI __builtin_arm_wfi + + +/** + \brief Wait For Event + \details Wait For Event is a hint instruction that permits the processor to enter + a low-power state until one of a number of events occurs. + */ +#define __WFE __builtin_arm_wfe + + +/** + \brief Send Event + \details Send Event is a hint instruction. It causes an event to be signaled to the CPU. + */ +#define __SEV __builtin_arm_sev + + +/** + \brief Instruction Synchronization Barrier + \details Instruction Synchronization Barrier flushes the pipeline in the processor, + so that all instructions following the ISB are fetched from cache or memory, + after the instruction has been completed. + */ +#define __ISB() __builtin_arm_isb(0xF) + +/** + \brief Data Synchronization Barrier + \details Acts as a special kind of Data Memory Barrier. + It completes when all explicit memory accesses before this instruction complete. + */ +#define __DSB() __builtin_arm_dsb(0xF) + + +/** + \brief Data Memory Barrier + \details Ensures the apparent order of the explicit memory operations before + and after the instruction, without ensuring their completion. + */ +#define __DMB() __builtin_arm_dmb(0xF) + + +/** + \brief Reverse byte order (32 bit) + \details Reverses the byte order in unsigned integer value. For example, 0x12345678 becomes 0x78563412. + \param [in] value Value to reverse + \return Reversed value + */ +#define __REV(value) __builtin_bswap32(value) + + +/** + \brief Reverse byte order (16 bit) + \details Reverses the byte order within each halfword of a word. For example, 0x12345678 becomes 0x34127856. + \param [in] value Value to reverse + \return Reversed value + */ +#define __REV16(value) __ROR(__REV(value), 16) + + +/** + \brief Reverse byte order (16 bit) + \details Reverses the byte order in a 16-bit value and returns the signed 16-bit result. For example, 0x0080 becomes 0x8000. + \param [in] value Value to reverse + \return Reversed value + */ +#define __REVSH(value) (int16_t)__builtin_bswap16(value) + + +/** + \brief Rotate Right in unsigned value (32 bit) + \details Rotate Right (immediate) provides the value of the contents of a register rotated by a variable number of bits. + \param [in] op1 Value to rotate + \param [in] op2 Number of Bits to rotate + \return Rotated value + */ +__STATIC_FORCEINLINE uint32_t __ROR(uint32_t op1, uint32_t op2) +{ + op2 %= 32U; + if (op2 == 0U) + { + return op1; + } + return (op1 >> op2) | (op1 << (32U - op2)); +} + + +/** + \brief Breakpoint + \details Causes the processor to enter Debug state. + Debug tools can use this to investigate system state when the instruction at a particular address is reached. + \param [in] value is ignored by the processor. + If required, a debugger can use it to store additional information about the breakpoint. + */ +#define __BKPT(value) __ASM volatile ("bkpt "#value) + + +/** + \brief Reverse bit order of value + \details Reverses the bit order of the given value. + \param [in] value Value to reverse + \return Reversed value + */ +#define __RBIT __builtin_arm_rbit + +/** + \brief Count leading zeros + \details Counts the number of leading zeros of a data value. + \param [in] value Value to count the leading zeros + \return number of leading zeros in value + */ +__STATIC_FORCEINLINE uint8_t __CLZ(uint32_t value) +{ + /* Even though __builtin_clz produces a CLZ instruction on ARM, formally + __builtin_clz(0) is undefined behaviour, so handle this case specially. + This guarantees ARM-compatible results if happening to compile on a non-ARM + target, and ensures the compiler doesn't decide to activate any + optimisations using the logic "value was passed to __builtin_clz, so it + is non-zero". + ARM Compiler 6.10 and possibly earlier will optimise this test away, leaving a + single CLZ instruction. + */ + if (value == 0U) + { + return 32U; + } + return __builtin_clz(value); +} + + +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) +/** + \brief LDR Exclusive (8 bit) + \details Executes a exclusive LDR instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +#define __LDREXB (uint8_t)__builtin_arm_ldrex + + +/** + \brief LDR Exclusive (16 bit) + \details Executes a exclusive LDR instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +#define __LDREXH (uint16_t)__builtin_arm_ldrex + + +/** + \brief LDR Exclusive (32 bit) + \details Executes a exclusive LDR instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +#define __LDREXW (uint32_t)__builtin_arm_ldrex + + +/** + \brief STR Exclusive (8 bit) + \details Executes a exclusive STR instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STREXB (uint32_t)__builtin_arm_strex + + +/** + \brief STR Exclusive (16 bit) + \details Executes a exclusive STR instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STREXH (uint32_t)__builtin_arm_strex + + +/** + \brief STR Exclusive (32 bit) + \details Executes a exclusive STR instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STREXW (uint32_t)__builtin_arm_strex + + +/** + \brief Remove the exclusive lock + \details Removes the exclusive lock which is created by LDREX. + */ +#define __CLREX __builtin_arm_clrex + +#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) */ + + +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) + +/** + \brief Signed Saturate + \details Saturates a signed value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (1..32) + \return Saturated value + */ +#define __SSAT __builtin_arm_ssat + + +/** + \brief Unsigned Saturate + \details Saturates an unsigned value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (0..31) + \return Saturated value + */ +#define __USAT __builtin_arm_usat + + +/** + \brief Rotate Right with Extend (32 bit) + \details Moves each bit of a bitstring right by one bit. + The carry input is shifted in at the left end of the bitstring. + \param [in] value Value to rotate + \return Rotated value + */ +__STATIC_FORCEINLINE uint32_t __RRX(uint32_t value) +{ + uint32_t result; + + __ASM volatile ("rrx %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); + return(result); +} + + +/** + \brief LDRT Unprivileged (8 bit) + \details Executes a Unprivileged LDRT instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +__STATIC_FORCEINLINE uint8_t __LDRBT(volatile uint8_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldrbt %0, %1" : "=r" (result) : "Q" (*ptr) ); + return ((uint8_t) result); /* Add explicit type cast here */ +} + + +/** + \brief LDRT Unprivileged (16 bit) + \details Executes a Unprivileged LDRT instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +__STATIC_FORCEINLINE uint16_t __LDRHT(volatile uint16_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldrht %0, %1" : "=r" (result) : "Q" (*ptr) ); + return ((uint16_t) result); /* Add explicit type cast here */ +} + + +/** + \brief LDRT Unprivileged (32 bit) + \details Executes a Unprivileged LDRT instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +__STATIC_FORCEINLINE uint32_t __LDRT(volatile uint32_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldrt %0, %1" : "=r" (result) : "Q" (*ptr) ); + return(result); +} + + +/** + \brief STRT Unprivileged (8 bit) + \details Executes a Unprivileged STRT instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STRBT(uint8_t value, volatile uint8_t *ptr) +{ + __ASM volatile ("strbt %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); +} + + +/** + \brief STRT Unprivileged (16 bit) + \details Executes a Unprivileged STRT instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STRHT(uint16_t value, volatile uint16_t *ptr) +{ + __ASM volatile ("strht %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); +} + + +/** + \brief STRT Unprivileged (32 bit) + \details Executes a Unprivileged STRT instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STRT(uint32_t value, volatile uint32_t *ptr) +{ + __ASM volatile ("strt %1, %0" : "=Q" (*ptr) : "r" (value) ); +} + +#else /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) */ + +/** + \brief Signed Saturate + \details Saturates a signed value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (1..32) + \return Saturated value + */ +__STATIC_FORCEINLINE int32_t __SSAT(int32_t val, uint32_t sat) +{ + if ((sat >= 1U) && (sat <= 32U)) + { + const int32_t max = (int32_t)((1U << (sat - 1U)) - 1U); + const int32_t min = -1 - max ; + if (val > max) + { + return max; + } + else if (val < min) + { + return min; + } + } + return val; +} + +/** + \brief Unsigned Saturate + \details Saturates an unsigned value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (0..31) + \return Saturated value + */ +__STATIC_FORCEINLINE uint32_t __USAT(int32_t val, uint32_t sat) +{ + if (sat <= 31U) + { + const uint32_t max = ((1U << sat) - 1U); + if (val > (int32_t)max) + { + return max; + } + else if (val < 0) + { + return 0U; + } + } + return (uint32_t)val; +} + +#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) */ + + +#if ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) +/** + \brief Load-Acquire (8 bit) + \details Executes a LDAB instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +__STATIC_FORCEINLINE uint8_t __LDAB(volatile uint8_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldab %0, %1" : "=r" (result) : "Q" (*ptr) ); + return ((uint8_t) result); +} + + +/** + \brief Load-Acquire (16 bit) + \details Executes a LDAH instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +__STATIC_FORCEINLINE uint16_t __LDAH(volatile uint16_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldah %0, %1" : "=r" (result) : "Q" (*ptr) ); + return ((uint16_t) result); +} + + +/** + \brief Load-Acquire (32 bit) + \details Executes a LDA instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +__STATIC_FORCEINLINE uint32_t __LDA(volatile uint32_t *ptr) +{ + uint32_t result; + + __ASM volatile ("lda %0, %1" : "=r" (result) : "Q" (*ptr) ); + return(result); +} + + +/** + \brief Store-Release (8 bit) + \details Executes a STLB instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STLB(uint8_t value, volatile uint8_t *ptr) +{ + __ASM volatile ("stlb %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); +} + + +/** + \brief Store-Release (16 bit) + \details Executes a STLH instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STLH(uint16_t value, volatile uint16_t *ptr) +{ + __ASM volatile ("stlh %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); +} + + +/** + \brief Store-Release (32 bit) + \details Executes a STL instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STL(uint32_t value, volatile uint32_t *ptr) +{ + __ASM volatile ("stl %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); +} + + +/** + \brief Load-Acquire Exclusive (8 bit) + \details Executes a LDAB exclusive instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +#define __LDAEXB (uint8_t)__builtin_arm_ldaex + + +/** + \brief Load-Acquire Exclusive (16 bit) + \details Executes a LDAH exclusive instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +#define __LDAEXH (uint16_t)__builtin_arm_ldaex + + +/** + \brief Load-Acquire Exclusive (32 bit) + \details Executes a LDA exclusive instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +#define __LDAEX (uint32_t)__builtin_arm_ldaex + + +/** + \brief Store-Release Exclusive (8 bit) + \details Executes a STLB exclusive instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STLEXB (uint32_t)__builtin_arm_stlex + + +/** + \brief Store-Release Exclusive (16 bit) + \details Executes a STLH exclusive instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STLEXH (uint32_t)__builtin_arm_stlex + + +/** + \brief Store-Release Exclusive (32 bit) + \details Executes a STL exclusive instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STLEX (uint32_t)__builtin_arm_stlex + +#endif /* ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) */ + +/*@}*/ /* end of group CMSIS_Core_InstructionInterface */ + + +/* ################### Compiler specific Intrinsics ########################### */ +/** \defgroup CMSIS_SIMD_intrinsics CMSIS SIMD Intrinsics + Access to dedicated SIMD instructions + @{ +*/ + +#if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + +#define __SADD8 __builtin_arm_sadd8 +#define __QADD8 __builtin_arm_qadd8 +#define __SHADD8 __builtin_arm_shadd8 +#define __UADD8 __builtin_arm_uadd8 +#define __UQADD8 __builtin_arm_uqadd8 +#define __UHADD8 __builtin_arm_uhadd8 +#define __SSUB8 __builtin_arm_ssub8 +#define __QSUB8 __builtin_arm_qsub8 +#define __SHSUB8 __builtin_arm_shsub8 +#define __USUB8 __builtin_arm_usub8 +#define __UQSUB8 __builtin_arm_uqsub8 +#define __UHSUB8 __builtin_arm_uhsub8 +#define __SADD16 __builtin_arm_sadd16 +#define __QADD16 __builtin_arm_qadd16 +#define __SHADD16 __builtin_arm_shadd16 +#define __UADD16 __builtin_arm_uadd16 +#define __UQADD16 __builtin_arm_uqadd16 +#define __UHADD16 __builtin_arm_uhadd16 +#define __SSUB16 __builtin_arm_ssub16 +#define __QSUB16 __builtin_arm_qsub16 +#define __SHSUB16 __builtin_arm_shsub16 +#define __USUB16 __builtin_arm_usub16 +#define __UQSUB16 __builtin_arm_uqsub16 +#define __UHSUB16 __builtin_arm_uhsub16 +#define __SASX __builtin_arm_sasx +#define __QASX __builtin_arm_qasx +#define __SHASX __builtin_arm_shasx +#define __UASX __builtin_arm_uasx +#define __UQASX __builtin_arm_uqasx +#define __UHASX __builtin_arm_uhasx +#define __SSAX __builtin_arm_ssax +#define __QSAX __builtin_arm_qsax +#define __SHSAX __builtin_arm_shsax +#define __USAX __builtin_arm_usax +#define __UQSAX __builtin_arm_uqsax +#define __UHSAX __builtin_arm_uhsax +#define __USAD8 __builtin_arm_usad8 +#define __USADA8 __builtin_arm_usada8 +#define __SSAT16 __builtin_arm_ssat16 +#define __USAT16 __builtin_arm_usat16 +#define __UXTB16 __builtin_arm_uxtb16 +#define __UXTAB16 __builtin_arm_uxtab16 +#define __SXTB16 __builtin_arm_sxtb16 +#define __SXTAB16 __builtin_arm_sxtab16 +#define __SMUAD __builtin_arm_smuad +#define __SMUADX __builtin_arm_smuadx +#define __SMLAD __builtin_arm_smlad +#define __SMLADX __builtin_arm_smladx +#define __SMLALD __builtin_arm_smlald +#define __SMLALDX __builtin_arm_smlaldx +#define __SMUSD __builtin_arm_smusd +#define __SMUSDX __builtin_arm_smusdx +#define __SMLSD __builtin_arm_smlsd +#define __SMLSDX __builtin_arm_smlsdx +#define __SMLSLD __builtin_arm_smlsld +#define __SMLSLDX __builtin_arm_smlsldx +#define __SEL __builtin_arm_sel +#define __QADD __builtin_arm_qadd +#define __QSUB __builtin_arm_qsub + +#define __PKHBT(ARG1,ARG2,ARG3) ( ((((uint32_t)(ARG1)) ) & 0x0000FFFFUL) | \ + ((((uint32_t)(ARG2)) << (ARG3)) & 0xFFFF0000UL) ) + +#define __PKHTB(ARG1,ARG2,ARG3) ( ((((uint32_t)(ARG1)) ) & 0xFFFF0000UL) | \ + ((((uint32_t)(ARG2)) >> (ARG3)) & 0x0000FFFFUL) ) + +__STATIC_FORCEINLINE int32_t __SMMLA (int32_t op1, int32_t op2, int32_t op3) +{ + int32_t result; + + __ASM volatile ("smmla %0, %1, %2, %3" : "=r" (result): "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +#endif /* (__ARM_FEATURE_DSP == 1) */ +/*@} end of group CMSIS_SIMD_intrinsics */ + + +#endif /* __CMSIS_ARMCLANG_H */ diff --git a/lib/cmsis/inc/cmsis_armcc_V6.h b/lib/cmsis/inc/cmsis_armclang_ltm.h similarity index 56% rename from lib/cmsis/inc/cmsis_armcc_V6.h rename to lib/cmsis/inc/cmsis_armclang_ltm.h index cd13240ce3..e4002a3fc4 100644 --- a/lib/cmsis/inc/cmsis_armcc_V6.h +++ b/lib/cmsis/inc/cmsis_armclang_ltm.h @@ -1,39 +1,115 @@ /**************************************************************************//** - * @file cmsis_armcc_V6.h - * @brief CMSIS Cortex-M Core Function/Instruction Header File - * @version V4.30 - * @date 20. October 2015 + * @file cmsis_armclang_ltm.h + * @brief CMSIS compiler armclang (Arm Compiler 6) header file + * @version V1.0.1 + * @date 19. March 2019 ******************************************************************************/ -/* Copyright (c) 2009 - 2015 ARM LIMITED +/* + * Copyright (c) 2018-2019 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ - All rights reserved. - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 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. - - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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. - ---------------------------------------------------------------------------*/ +/*lint -esym(9058, IRQn)*/ /* disable MISRA 2012 Rule 2.4 for IRQn */ +#ifndef __CMSIS_ARMCLANG_H +#define __CMSIS_ARMCLANG_H -#ifndef __CMSIS_ARMCC_V6_H -#define __CMSIS_ARMCC_V6_H +#pragma clang system_header /* treat file as system include file */ + +#ifndef __ARM_COMPAT_H +#include /* Compatibility header for Arm Compiler 5 intrinsics */ +#endif + +/* CMSIS compiler specific defines */ +#ifndef __ASM + #define __ASM __asm +#endif +#ifndef __INLINE + #define __INLINE __inline +#endif +#ifndef __STATIC_INLINE + #define __STATIC_INLINE static __inline +#endif +#ifndef __STATIC_FORCEINLINE + #define __STATIC_FORCEINLINE __attribute__((always_inline)) static __inline +#endif +#ifndef __NO_RETURN + #define __NO_RETURN __attribute__((__noreturn__)) +#endif +#ifndef __USED + #define __USED __attribute__((used)) +#endif +#ifndef __WEAK + #define __WEAK __attribute__((weak)) +#endif +#ifndef __PACKED + #define __PACKED __attribute__((packed, aligned(1))) +#endif +#ifndef __PACKED_STRUCT + #define __PACKED_STRUCT struct __attribute__((packed, aligned(1))) +#endif +#ifndef __PACKED_UNION + #define __PACKED_UNION union __attribute__((packed, aligned(1))) +#endif +#ifndef __UNALIGNED_UINT32 /* deprecated */ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wpacked" +/*lint -esym(9058, T_UINT32)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT32 */ + struct __attribute__((packed)) T_UINT32 { uint32_t v; }; + #pragma clang diagnostic pop + #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) +#endif +#ifndef __UNALIGNED_UINT16_WRITE + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wpacked" +/*lint -esym(9058, T_UINT16_WRITE)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT16_WRITE */ + __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; + #pragma clang diagnostic pop + #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val)) +#endif +#ifndef __UNALIGNED_UINT16_READ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wpacked" +/*lint -esym(9058, T_UINT16_READ)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT16_READ */ + __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; + #pragma clang diagnostic pop + #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) +#endif +#ifndef __UNALIGNED_UINT32_WRITE + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wpacked" +/*lint -esym(9058, T_UINT32_WRITE)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT32_WRITE */ + __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; + #pragma clang diagnostic pop + #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) +#endif +#ifndef __UNALIGNED_UINT32_READ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wpacked" +/*lint -esym(9058, T_UINT32_READ)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT32_READ */ + __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; + #pragma clang diagnostic pop + #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) +#endif +#ifndef __ALIGNED + #define __ALIGNED(x) __attribute__((aligned(x))) +#endif +#ifndef __RESTRICT + #define __RESTRICT __restrict +#endif /* ########################### Core Function Access ########################### */ @@ -47,10 +123,7 @@ \details Enables IRQ interrupts by clearing the I-bit in the CPSR. Can only be executed in Privileged modes. */ -__attribute__((always_inline)) __STATIC_INLINE void __enable_irq(void) -{ - __ASM volatile ("cpsie i" : : : "memory"); -} +/* intrinsic void __enable_irq(); see arm_compat.h */ /** @@ -58,10 +131,7 @@ __attribute__((always_inline)) __STATIC_INLINE void __enable_irq(void) \details Disables IRQ interrupts by setting the I-bit in the CPSR. Can only be executed in Privileged modes. */ -__attribute__((always_inline)) __STATIC_INLINE void __disable_irq(void) -{ - __ASM volatile ("cpsid i" : : : "memory"); -} +/* intrinsic void __disable_irq(); see arm_compat.h */ /** @@ -69,7 +139,7 @@ __attribute__((always_inline)) __STATIC_INLINE void __disable_irq(void) \details Returns the content of the Control Register. \return Control Register value */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __get_CONTROL(void) +__STATIC_FORCEINLINE uint32_t __get_CONTROL(void) { uint32_t result; @@ -78,13 +148,13 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __get_CONTROL(void) } -#if (__ARM_FEATURE_CMSE == 3U) +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Get Control Register (non-secure) \details Returns the content of the non-secure Control Register when in secure mode. \return non-secure Control Register value */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_CONTROL_NS(void) +__STATIC_FORCEINLINE uint32_t __TZ_get_CONTROL_NS(void) { uint32_t result; @@ -99,19 +169,19 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_CONTROL_NS(void \details Writes the given value to the Control Register. \param [in] control Control Register value to set */ -__attribute__((always_inline)) __STATIC_INLINE void __set_CONTROL(uint32_t control) +__STATIC_FORCEINLINE void __set_CONTROL(uint32_t control) { __ASM volatile ("MSR control, %0" : : "r" (control) : "memory"); } -#if (__ARM_FEATURE_CMSE == 3U) +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Set Control Register (non-secure) \details Writes the given value to the non-secure Control Register when in secure state. \param [in] control Control Register value to set */ -__attribute__((always_inline)) __STATIC_INLINE void __TZ_set_CONTROL_NS(uint32_t control) +__STATIC_FORCEINLINE void __TZ_set_CONTROL_NS(uint32_t control) { __ASM volatile ("MSR control_ns, %0" : : "r" (control) : "memory"); } @@ -123,7 +193,7 @@ __attribute__((always_inline)) __STATIC_INLINE void __TZ_set_CONTROL_NS(uint32_t \details Returns the content of the IPSR Register. \return IPSR Register value */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __get_IPSR(void) +__STATIC_FORCEINLINE uint32_t __get_IPSR(void) { uint32_t result; @@ -132,28 +202,12 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __get_IPSR(void) } -#if (__ARM_FEATURE_CMSE == 3U) -/** - \brief Get IPSR Register (non-secure) - \details Returns the content of the non-secure IPSR Register when in secure state. - \return IPSR Register value - */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_IPSR_NS(void) -{ - uint32_t result; - - __ASM volatile ("MRS %0, ipsr_ns" : "=r" (result) ); - return(result); -} -#endif - - /** \brief Get APSR Register \details Returns the content of the APSR Register. \return APSR Register value */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __get_APSR(void) +__STATIC_FORCEINLINE uint32_t __get_APSR(void) { uint32_t result; @@ -162,28 +216,12 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __get_APSR(void) } -#if (__ARM_FEATURE_CMSE == 3U) -/** - \brief Get APSR Register (non-secure) - \details Returns the content of the non-secure APSR Register when in secure state. - \return APSR Register value - */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_APSR_NS(void) -{ - uint32_t result; - - __ASM volatile ("MRS %0, apsr_ns" : "=r" (result) ); - return(result); -} -#endif - - /** \brief Get xPSR Register \details Returns the content of the xPSR Register. \return xPSR Register value */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __get_xPSR(void) +__STATIC_FORCEINLINE uint32_t __get_xPSR(void) { uint32_t result; @@ -192,45 +230,29 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __get_xPSR(void) } -#if (__ARM_FEATURE_CMSE == 3U) -/** - \brief Get xPSR Register (non-secure) - \details Returns the content of the non-secure xPSR Register when in secure state. - \return xPSR Register value - */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_xPSR_NS(void) -{ - uint32_t result; - - __ASM volatile ("MRS %0, xpsr_ns" : "=r" (result) ); - return(result); -} -#endif - - /** \brief Get Process Stack Pointer \details Returns the current value of the Process Stack Pointer (PSP). \return PSP Register value */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __get_PSP(void) +__STATIC_FORCEINLINE uint32_t __get_PSP(void) { - register uint32_t result; + uint32_t result; __ASM volatile ("MRS %0, psp" : "=r" (result) ); return(result); } -#if (__ARM_FEATURE_CMSE == 3U) +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Get Process Stack Pointer (non-secure) \details Returns the current value of the non-secure Process Stack Pointer (PSP) when in secure state. \return PSP Register value */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_PSP_NS(void) +__STATIC_FORCEINLINE uint32_t __TZ_get_PSP_NS(void) { - register uint32_t result; + uint32_t result; __ASM volatile ("MRS %0, psp_ns" : "=r" (result) ); return(result); @@ -243,21 +265,21 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_PSP_NS(void) \details Assigns the given value to the Process Stack Pointer (PSP). \param [in] topOfProcStack Process Stack Pointer value to set */ -__attribute__((always_inline)) __STATIC_INLINE void __set_PSP(uint32_t topOfProcStack) +__STATIC_FORCEINLINE void __set_PSP(uint32_t topOfProcStack) { - __ASM volatile ("MSR psp, %0" : : "r" (topOfProcStack) : "sp"); + __ASM volatile ("MSR psp, %0" : : "r" (topOfProcStack) : ); } -#if (__ARM_FEATURE_CMSE == 3U) +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Set Process Stack Pointer (non-secure) \details Assigns the given value to the non-secure Process Stack Pointer (PSP) when in secure state. \param [in] topOfProcStack Process Stack Pointer value to set */ -__attribute__((always_inline)) __STATIC_INLINE void __TZ_set_PSP_NS(uint32_t topOfProcStack) +__STATIC_FORCEINLINE void __TZ_set_PSP_NS(uint32_t topOfProcStack) { - __ASM volatile ("MSR psp_ns, %0" : : "r" (topOfProcStack) : "sp"); + __ASM volatile ("MSR psp_ns, %0" : : "r" (topOfProcStack) : ); } #endif @@ -267,24 +289,24 @@ __attribute__((always_inline)) __STATIC_INLINE void __TZ_set_PSP_NS(uint32_t top \details Returns the current value of the Main Stack Pointer (MSP). \return MSP Register value */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __get_MSP(void) +__STATIC_FORCEINLINE uint32_t __get_MSP(void) { - register uint32_t result; + uint32_t result; __ASM volatile ("MRS %0, msp" : "=r" (result) ); return(result); } -#if (__ARM_FEATURE_CMSE == 3U) +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Get Main Stack Pointer (non-secure) \details Returns the current value of the non-secure Main Stack Pointer (MSP) when in secure state. \return MSP Register value */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_MSP_NS(void) +__STATIC_FORCEINLINE uint32_t __TZ_get_MSP_NS(void) { - register uint32_t result; + uint32_t result; __ASM volatile ("MRS %0, msp_ns" : "=r" (result) ); return(result); @@ -297,21 +319,48 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_MSP_NS(void) \details Assigns the given value to the Main Stack Pointer (MSP). \param [in] topOfMainStack Main Stack Pointer value to set */ -__attribute__((always_inline)) __STATIC_INLINE void __set_MSP(uint32_t topOfMainStack) +__STATIC_FORCEINLINE void __set_MSP(uint32_t topOfMainStack) { - __ASM volatile ("MSR msp, %0" : : "r" (topOfMainStack) : "sp"); + __ASM volatile ("MSR msp, %0" : : "r" (topOfMainStack) : ); } -#if (__ARM_FEATURE_CMSE == 3U) +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Set Main Stack Pointer (non-secure) \details Assigns the given value to the non-secure Main Stack Pointer (MSP) when in secure state. \param [in] topOfMainStack Main Stack Pointer value to set */ -__attribute__((always_inline)) __STATIC_INLINE void __TZ_set_MSP_NS(uint32_t topOfMainStack) +__STATIC_FORCEINLINE void __TZ_set_MSP_NS(uint32_t topOfMainStack) { - __ASM volatile ("MSR msp_ns, %0" : : "r" (topOfMainStack) : "sp"); + __ASM volatile ("MSR msp_ns, %0" : : "r" (topOfMainStack) : ); +} +#endif + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Stack Pointer (non-secure) + \details Returns the current value of the non-secure Stack Pointer (SP) when in secure state. + \return SP Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_SP_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, sp_ns" : "=r" (result) ); + return(result); +} + + +/** + \brief Set Stack Pointer (non-secure) + \details Assigns the given value to the non-secure Stack Pointer (SP) when in secure state. + \param [in] topOfStack Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __TZ_set_SP_NS(uint32_t topOfStack) +{ + __ASM volatile ("MSR sp_ns, %0" : : "r" (topOfStack) : ); } #endif @@ -321,7 +370,7 @@ __attribute__((always_inline)) __STATIC_INLINE void __TZ_set_MSP_NS(uint32_t top \details Returns the current state of the priority mask bit from the Priority Mask Register. \return Priority Mask value */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __get_PRIMASK(void) +__STATIC_FORCEINLINE uint32_t __get_PRIMASK(void) { uint32_t result; @@ -330,13 +379,13 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __get_PRIMASK(void) } -#if (__ARM_FEATURE_CMSE == 3U) +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Get Priority Mask (non-secure) \details Returns the current state of the non-secure priority mask bit from the Priority Mask Register when in secure state. \return Priority Mask value */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_PRIMASK_NS(void) +__STATIC_FORCEINLINE uint32_t __TZ_get_PRIMASK_NS(void) { uint32_t result; @@ -351,36 +400,34 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_PRIMASK_NS(void \details Assigns the given value to the Priority Mask Register. \param [in] priMask Priority Mask */ -__attribute__((always_inline)) __STATIC_INLINE void __set_PRIMASK(uint32_t priMask) +__STATIC_FORCEINLINE void __set_PRIMASK(uint32_t priMask) { __ASM volatile ("MSR primask, %0" : : "r" (priMask) : "memory"); } -#if (__ARM_FEATURE_CMSE == 3U) +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Set Priority Mask (non-secure) \details Assigns the given value to the non-secure Priority Mask Register when in secure state. \param [in] priMask Priority Mask */ -__attribute__((always_inline)) __STATIC_INLINE void __TZ_set_PRIMASK_NS(uint32_t priMask) +__STATIC_FORCEINLINE void __TZ_set_PRIMASK_NS(uint32_t priMask) { __ASM volatile ("MSR primask_ns, %0" : : "r" (priMask) : "memory"); } #endif -#if ((__ARM_ARCH_7M__ == 1U) || (__ARM_ARCH_7EM__ == 1U) || (__ARM_ARCH_8M__ == 1U)) /* ToDo: ARMCC_V6: check if this is ok for cortex >=3 */ - +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) /** \brief Enable FIQ \details Enables FIQ interrupts by clearing the F-bit in the CPSR. Can only be executed in Privileged modes. */ -__attribute__((always_inline)) __STATIC_INLINE void __enable_fault_irq(void) -{ - __ASM volatile ("cpsie f" : : : "memory"); -} +#define __enable_fault_irq __enable_fiq /* see arm_compat.h */ /** @@ -388,10 +435,7 @@ __attribute__((always_inline)) __STATIC_INLINE void __enable_fault_irq(void) \details Disables FIQ interrupts by setting the F-bit in the CPSR. Can only be executed in Privileged modes. */ -__attribute__((always_inline)) __STATIC_INLINE void __disable_fault_irq(void) -{ - __ASM volatile ("cpsid f" : : : "memory"); -} +#define __disable_fault_irq __disable_fiq /* see arm_compat.h */ /** @@ -399,7 +443,7 @@ __attribute__((always_inline)) __STATIC_INLINE void __disable_fault_irq(void) \details Returns the current value of the Base Priority register. \return Base Priority register value */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __get_BASEPRI(void) +__STATIC_FORCEINLINE uint32_t __get_BASEPRI(void) { uint32_t result; @@ -408,13 +452,13 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __get_BASEPRI(void) } -#if (__ARM_FEATURE_CMSE == 3U) +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Get Base Priority (non-secure) \details Returns the current value of the non-secure Base Priority register when in secure state. \return Base Priority register value */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_BASEPRI_NS(void) +__STATIC_FORCEINLINE uint32_t __TZ_get_BASEPRI_NS(void) { uint32_t result; @@ -429,21 +473,21 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_BASEPRI_NS(void \details Assigns the given value to the Base Priority register. \param [in] basePri Base Priority value to set */ -__attribute__((always_inline)) __STATIC_INLINE void __set_BASEPRI(uint32_t value) +__STATIC_FORCEINLINE void __set_BASEPRI(uint32_t basePri) { - __ASM volatile ("MSR basepri, %0" : : "r" (value) : "memory"); + __ASM volatile ("MSR basepri, %0" : : "r" (basePri) : "memory"); } -#if (__ARM_FEATURE_CMSE == 3U) +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Set Base Priority (non-secure) \details Assigns the given value to the non-secure Base Priority register when in secure state. \param [in] basePri Base Priority value to set */ -__attribute__((always_inline)) __STATIC_INLINE void __TZ_set_BASEPRI_NS(uint32_t value) +__STATIC_FORCEINLINE void __TZ_set_BASEPRI_NS(uint32_t basePri) { - __ASM volatile ("MSR basepri_ns, %0" : : "r" (value) : "memory"); + __ASM volatile ("MSR basepri_ns, %0" : : "r" (basePri) : "memory"); } #endif @@ -454,32 +498,18 @@ __attribute__((always_inline)) __STATIC_INLINE void __TZ_set_BASEPRI_NS(uint32_t or the new value increases the BASEPRI priority level. \param [in] basePri Base Priority value to set */ -__attribute__((always_inline)) __STATIC_INLINE void __set_BASEPRI_MAX(uint32_t value) +__STATIC_FORCEINLINE void __set_BASEPRI_MAX(uint32_t basePri) { - __ASM volatile ("MSR basepri_max, %0" : : "r" (value) : "memory"); + __ASM volatile ("MSR basepri_max, %0" : : "r" (basePri) : "memory"); } -#if (__ARM_FEATURE_CMSE == 3U) -/** - \brief Set Base Priority with condition (non_secure) - \details Assigns the given value to the non-secure Base Priority register when in secure state only if BASEPRI masking is disabled, - or the new value increases the BASEPRI priority level. - \param [in] basePri Base Priority value to set - */ -__attribute__((always_inline)) __STATIC_INLINE void __TZ_set_BASEPRI_MAX_NS(uint32_t value) -{ - __ASM volatile ("MSR basepri_max_ns, %0" : : "r" (value) : "memory"); -} -#endif - - /** \brief Get Fault Mask \details Returns the current value of the Fault Mask register. \return Fault Mask register value */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __get_FAULTMASK(void) +__STATIC_FORCEINLINE uint32_t __get_FAULTMASK(void) { uint32_t result; @@ -488,13 +518,13 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __get_FAULTMASK(void) } -#if (__ARM_FEATURE_CMSE == 3U) +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Get Fault Mask (non-secure) \details Returns the current value of the non-secure Fault Mask register when in secure state. \return Fault Mask register value */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_FAULTMASK_NS(void) +__STATIC_FORCEINLINE uint32_t __TZ_get_FAULTMASK_NS(void) { uint32_t result; @@ -509,222 +539,232 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_FAULTMASK_NS(vo \details Assigns the given value to the Fault Mask register. \param [in] faultMask Fault Mask value to set */ -__attribute__((always_inline)) __STATIC_INLINE void __set_FAULTMASK(uint32_t faultMask) +__STATIC_FORCEINLINE void __set_FAULTMASK(uint32_t faultMask) { __ASM volatile ("MSR faultmask, %0" : : "r" (faultMask) : "memory"); } -#if (__ARM_FEATURE_CMSE == 3U) +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Set Fault Mask (non-secure) \details Assigns the given value to the non-secure Fault Mask register when in secure state. \param [in] faultMask Fault Mask value to set */ -__attribute__((always_inline)) __STATIC_INLINE void __TZ_set_FAULTMASK_NS(uint32_t faultMask) +__STATIC_FORCEINLINE void __TZ_set_FAULTMASK_NS(uint32_t faultMask) { __ASM volatile ("MSR faultmask_ns, %0" : : "r" (faultMask) : "memory"); } #endif - -#endif /* ((__ARM_ARCH_7M__ == 1U) || (__ARM_ARCH_8M__ == 1U)) */ +#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) */ -#if (__ARM_ARCH_8M__ == 1U) +#if ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) /** \brief Get Process Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always in non-secure + mode. + \details Returns the current value of the Process Stack Pointer Limit (PSPLIM). \return PSPLIM Register value */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __get_PSPLIM(void) +__STATIC_FORCEINLINE uint32_t __get_PSPLIM(void) { - register uint32_t result; - +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; __ASM volatile ("MRS %0, psplim" : "=r" (result) ); - return(result); + return result; +#endif } - -#if (__ARM_FEATURE_CMSE == 3U) && (__ARM_ARCH_PROFILE == 'M') /* ToDo: ARMCC_V6: check predefined macro for mainline */ +#if (defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3)) /** \brief Get Process Stack Pointer Limit (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always in non-secure + mode. + \details Returns the current value of the non-secure Process Stack Pointer Limit (PSPLIM) when in secure state. \return PSPLIM Register value */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_PSPLIM_NS(void) +__STATIC_FORCEINLINE uint32_t __TZ_get_PSPLIM_NS(void) { - register uint32_t result; - +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; __ASM volatile ("MRS %0, psplim_ns" : "=r" (result) ); - return(result); + return result; +#endif } #endif /** \brief Set Process Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored in non-secure + mode. + \details Assigns the given value to the Process Stack Pointer Limit (PSPLIM). \param [in] ProcStackPtrLimit Process Stack Pointer Limit value to set */ -__attribute__((always_inline)) __STATIC_INLINE void __set_PSPLIM(uint32_t ProcStackPtrLimit) +__STATIC_FORCEINLINE void __set_PSPLIM(uint32_t ProcStackPtrLimit) { +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + (void)ProcStackPtrLimit; +#else __ASM volatile ("MSR psplim, %0" : : "r" (ProcStackPtrLimit)); +#endif } -#if (__ARM_FEATURE_CMSE == 3U) && (__ARM_ARCH_PROFILE == 'M') /* ToDo: ARMCC_V6: check predefined macro for mainline */ +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Set Process Stack Pointer (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored in non-secure + mode. + \details Assigns the given value to the non-secure Process Stack Pointer Limit (PSPLIM) when in secure state. \param [in] ProcStackPtrLimit Process Stack Pointer Limit value to set */ -__attribute__((always_inline)) __STATIC_INLINE void __TZ_set_PSPLIM_NS(uint32_t ProcStackPtrLimit) +__STATIC_FORCEINLINE void __TZ_set_PSPLIM_NS(uint32_t ProcStackPtrLimit) { +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + (void)ProcStackPtrLimit; +#else __ASM volatile ("MSR psplim_ns, %0\n" : : "r" (ProcStackPtrLimit)); +#endif } #endif /** \brief Get Main Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always. + \details Returns the current value of the Main Stack Pointer Limit (MSPLIM). \return MSPLIM Register value */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __get_MSPLIM(void) +__STATIC_FORCEINLINE uint32_t __get_MSPLIM(void) { - register uint32_t result; - +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; __ASM volatile ("MRS %0, msplim" : "=r" (result) ); - - return(result); + return result; +#endif } -#if (__ARM_FEATURE_CMSE == 3U) && (__ARM_ARCH_PROFILE == 'M') /* ToDo: ARMCC_V6: check predefined macro for mainline */ +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Get Main Stack Pointer Limit (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always. + \details Returns the current value of the non-secure Main Stack Pointer Limit(MSPLIM) when in secure state. \return MSPLIM Register value */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_MSPLIM_NS(void) +__STATIC_FORCEINLINE uint32_t __TZ_get_MSPLIM_NS(void) { - register uint32_t result; - +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; __ASM volatile ("MRS %0, msplim_ns" : "=r" (result) ); - return(result); + return result; +#endif } #endif /** \brief Set Main Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored. + \details Assigns the given value to the Main Stack Pointer Limit (MSPLIM). \param [in] MainStackPtrLimit Main Stack Pointer Limit value to set */ -__attribute__((always_inline)) __STATIC_INLINE void __set_MSPLIM(uint32_t MainStackPtrLimit) +__STATIC_FORCEINLINE void __set_MSPLIM(uint32_t MainStackPtrLimit) { +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + (void)MainStackPtrLimit; +#else __ASM volatile ("MSR msplim, %0" : : "r" (MainStackPtrLimit)); +#endif } -#if (__ARM_FEATURE_CMSE == 3U) && (__ARM_ARCH_PROFILE == 'M') /* ToDo: ARMCC_V6: check predefined macro for mainline */ +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Set Main Stack Pointer Limit (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored. + \details Assigns the given value to the non-secure Main Stack Pointer Limit (MSPLIM) when in secure state. \param [in] MainStackPtrLimit Main Stack Pointer value to set */ -__attribute__((always_inline)) __STATIC_INLINE void __TZ_set_MSPLIM_NS(uint32_t MainStackPtrLimit) +__STATIC_FORCEINLINE void __TZ_set_MSPLIM_NS(uint32_t MainStackPtrLimit) { +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + (void)MainStackPtrLimit; +#else __ASM volatile ("MSR msplim_ns, %0" : : "r" (MainStackPtrLimit)); +#endif } #endif -#endif /* (__ARM_ARCH_8M__ == 1U) */ - - -#if ((__ARM_ARCH_7EM__ == 1U) || (__ARM_ARCH_8M__ == 1U)) /* ToDo: ARMCC_V6: check if this is ok for cortex >=4 */ +#endif /* ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) */ /** \brief Get FPSCR - \details eturns the current value of the Floating Point Status/Control register. + \details Returns the current value of the Floating Point Status/Control register. \return Floating Point Status/Control register value */ -#define __get_FPSCR __builtin_arm_get_fpscr -#if 0 -__attribute__((always_inline)) __STATIC_INLINE uint32_t __get_FPSCR(void) -{ -#if (__FPU_PRESENT == 1U) && (__FPU_USED == 1U) - uint32_t result; - - __ASM volatile (""); /* Empty asm statement works as a scheduling barrier */ - __ASM volatile ("VMRS %0, fpscr" : "=r" (result) ); - __ASM volatile (""); - return(result); +#if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ + (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) +#define __get_FPSCR (uint32_t)__builtin_arm_get_fpscr #else - return(0); +#define __get_FPSCR() ((uint32_t)0U) #endif -} -#endif - -#if (__ARM_FEATURE_CMSE == 3U) -/** - \brief Get FPSCR (non-secure) - \details Returns the current value of the non-secure Floating Point Status/Control register when in secure state. - \return Floating Point Status/Control register value - */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_FPSCR_NS(void) -{ -#if (__FPU_PRESENT == 1U) && (__FPU_USED == 1U) - uint32_t result; - - __ASM volatile (""); /* Empty asm statement works as a scheduling barrier */ - __ASM volatile ("VMRS %0, fpscr_ns" : "=r" (result) ); - __ASM volatile (""); - return(result); -#else - return(0); -#endif -} -#endif - /** \brief Set FPSCR \details Assigns the given value to the Floating Point Status/Control register. \param [in] fpscr Floating Point Status/Control value to set */ +#if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ + (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) #define __set_FPSCR __builtin_arm_set_fpscr -#if 0 -__attribute__((always_inline)) __STATIC_INLINE void __set_FPSCR(uint32_t fpscr) -{ -#if (__FPU_PRESENT == 1U) && (__FPU_USED == 1U) - __ASM volatile (""); /* Empty asm statement works as a scheduling barrier */ - __ASM volatile ("VMSR fpscr, %0" : : "r" (fpscr) : "vfpcc"); - __ASM volatile (""); +#else +#define __set_FPSCR(x) ((void)(x)) #endif -} -#endif - -#if (__ARM_FEATURE_CMSE == 3U) -/** - \brief Set FPSCR (non-secure) - \details Assigns the given value to the non-secure Floating Point Status/Control register when in secure state. - \param [in] fpscr Floating Point Status/Control value to set - */ -__attribute__((always_inline)) __STATIC_INLINE void __TZ_set_FPSCR_NS(uint32_t fpscr) -{ -#if (__FPU_PRESENT == 1U) && (__FPU_USED == 1U) - __ASM volatile (""); /* Empty asm statement works as a scheduling barrier */ - __ASM volatile ("VMSR fpscr_ns, %0" : : "r" (fpscr) : "vfpcc"); - __ASM volatile (""); -#endif -} -#endif - -#endif /* ((__ARM_ARCH_7EM__ == 1U) || (__ARM_ARCH_8M__ == 1U)) */ - /*@} end of CMSIS_Core_RegAccFunctions */ @@ -781,14 +821,14 @@ __attribute__((always_inline)) __STATIC_INLINE void __TZ_set_FPSCR_NS(uint32_t f so that all instructions following the ISB are fetched from cache or memory, after the instruction has been completed. */ -#define __ISB() __builtin_arm_isb(0xF); +#define __ISB() __builtin_arm_isb(0xF) /** \brief Data Synchronization Barrier \details Acts as a special kind of Data Memory Barrier. It completes when all explicit memory accesses before this instruction complete. */ -#define __DSB() __builtin_arm_dsb(0xF); +#define __DSB() __builtin_arm_dsb(0xF) /** @@ -796,50 +836,34 @@ __attribute__((always_inline)) __STATIC_INLINE void __TZ_set_FPSCR_NS(uint32_t f \details Ensures the apparent order of the explicit memory operations before and after the instruction, without ensuring their completion. */ -#define __DMB() __builtin_arm_dmb(0xF); +#define __DMB() __builtin_arm_dmb(0xF) /** \brief Reverse byte order (32 bit) - \details Reverses the byte order in integer value. + \details Reverses the byte order in unsigned integer value. For example, 0x12345678 becomes 0x78563412. \param [in] value Value to reverse \return Reversed value */ -#define __REV __builtin_bswap32 +#define __REV(value) __builtin_bswap32(value) /** \brief Reverse byte order (16 bit) - \details Reverses the byte order in two unsigned short values. + \details Reverses the byte order within each halfword of a word. For example, 0x12345678 becomes 0x34127856. \param [in] value Value to reverse \return Reversed value */ -#define __REV16 __builtin_bswap16 /* ToDo: ARMCC_V6: check if __builtin_bswap16 could be used */ -#if 0 -__attribute__((always_inline)) __STATIC_INLINE uint32_t __REV16(uint32_t value) -{ - uint32_t result; - - __ASM volatile ("rev16 %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); - return(result); -} -#endif +#define __REV16(value) __ROR(__REV(value), 16) /** - \brief Reverse byte order in signed short value - \details Reverses the byte order in a signed short value with sign extension to integer. + \brief Reverse byte order (16 bit) + \details Reverses the byte order in a 16-bit value and returns the signed 16-bit result. For example, 0x0080 becomes 0x8000. \param [in] value Value to reverse \return Reversed value */ - /* ToDo: ARMCC_V6: check if __builtin_bswap16 could be used */ -__attribute__((always_inline)) __STATIC_INLINE int32_t __REVSH(int32_t value) -{ - int32_t result; - - __ASM volatile ("revsh %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); - return(result); -} +#define __REVSH(value) (int16_t)__builtin_bswap16(value) /** @@ -849,8 +873,13 @@ __attribute__((always_inline)) __STATIC_INLINE int32_t __REVSH(int32_t value) \param [in] op2 Number of Bits to rotate \return Rotated value */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __ROR(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __ROR(uint32_t op1, uint32_t op2) { + op2 %= 32U; + if (op2 == 0U) + { + return op1; + } return (op1 >> op2) | (op1 << (32U - op2)); } @@ -858,11 +887,11 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __ROR(uint32_t op1, uint /** \brief Breakpoint \details Causes the processor to enter Debug state. - Debug tools can use this to investigate system state when the instruction at a particular address is reached. - \param [in] value is ignored by the processor. - If required, a debugger can use it to store additional information about the breakpoint. + Debug tools can use this to investigate system state when the instruction at a particular address is reached. + \param [in] value is ignored by the processor. + If required, a debugger can use it to store additional information about the breakpoint. */ -#define __BKPT(value) __ASM volatile ("bkpt "#value) +#define __BKPT(value) __ASM volatile ("bkpt "#value) /** @@ -871,28 +900,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __ROR(uint32_t op1, uint \param [in] value Value to reverse \return Reversed value */ - /* ToDo: ARMCC_V6: check if __builtin_arm_rbit is supported */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __RBIT(uint32_t value) -{ - uint32_t result; - -#if ((__ARM_ARCH_7M__ == 1U) || (__ARM_ARCH_7EM__ == 1U) || (__ARM_ARCH_8M__ == 1U)) /* ToDo: ARMCC_V6: check if this is ok for cortex >=3 */ - __ASM volatile ("rbit %0, %1" : "=r" (result) : "r" (value) ); -#else - int32_t s = 4 /*sizeof(v)*/ * 8 - 1; /* extra shift needed at end */ - - result = value; /* r will be reversed bits of v; first get LSB of v */ - for (value >>= 1U; value; value >>= 1U) - { - result <<= 1U; - result |= value & 1U; - s--; - } - result <<= s; /* shift when v's highest bits are zero */ -#endif - return(result); -} - +#define __RBIT __builtin_arm_rbit /** \brief Count leading zeros @@ -900,11 +908,29 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __RBIT(uint32_t value) \param [in] value Value to count the leading zeros \return number of leading zeros in value */ -#define __CLZ __builtin_clz +__STATIC_FORCEINLINE uint8_t __CLZ(uint32_t value) +{ + /* Even though __builtin_clz produces a CLZ instruction on ARM, formally + __builtin_clz(0) is undefined behaviour, so handle this case specially. + This guarantees ARM-compatible results if happening to compile on a non-ARM + target, and ensures the compiler doesn't decide to activate any + optimisations using the logic "value was passed to __builtin_clz, so it + is non-zero". + ARM Compiler 6.10 and possibly earlier will optimise this test away, leaving a + single CLZ instruction. + */ + if (value == 0U) + { + return 32U; + } + return __builtin_clz(value); +} -#if ((__ARM_ARCH_7M__ == 1U) || (__ARM_ARCH_7EM__ == 1U) || (__ARM_ARCH_8M__ == 1U)) /* ToDo: ARMCC_V6: check if this is ok for cortex >=3 */ - +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) /** \brief LDR Exclusive (8 bit) \details Executes a exclusive LDR instruction for 8 bit value. @@ -971,6 +997,15 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __RBIT(uint32_t value) */ #define __CLREX __builtin_arm_clrex +#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) */ + + +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) /** \brief Signed Saturate @@ -979,13 +1014,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __RBIT(uint32_t value) \param [in] sat Bit position to saturate to (1..32) \return Saturated value */ -/*#define __SSAT __builtin_arm_ssat*/ -#define __SSAT(ARG1,ARG2) \ -({ \ - int32_t __RES, __ARG1 = (ARG1); \ - __ASM ("ssat %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \ - __RES; \ - }) +#define __SSAT __builtin_arm_ssat /** @@ -996,14 +1025,6 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __RBIT(uint32_t value) \return Saturated value */ #define __USAT __builtin_arm_usat -#if 0 -#define __USAT(ARG1,ARG2) \ -({ \ - uint32_t __RES, __ARG1 = (ARG1); \ - __ASM ("usat %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \ - __RES; \ - }) -#endif /** @@ -1013,7 +1034,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __RBIT(uint32_t value) \param [in] value Value to rotate \return Rotated value */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __RRX(uint32_t value) +__STATIC_FORCEINLINE uint32_t __RRX(uint32_t value) { uint32_t result; @@ -1028,12 +1049,12 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __RRX(uint32_t value) \param [in] ptr Pointer to data \return value of type uint8_t at (*ptr) */ -__attribute__((always_inline)) __STATIC_INLINE uint8_t __LDRBT(volatile uint8_t *ptr) +__STATIC_FORCEINLINE uint8_t __LDRBT(volatile uint8_t *ptr) { - uint32_t result; + uint32_t result; - __ASM volatile ("ldrbt %0, %1" : "=r" (result) : "Q" (*ptr) ); - return ((uint8_t) result); /* Add explicit type cast here */ + __ASM volatile ("ldrbt %0, %1" : "=r" (result) : "Q" (*ptr) ); + return ((uint8_t) result); /* Add explicit type cast here */ } @@ -1043,12 +1064,12 @@ __attribute__((always_inline)) __STATIC_INLINE uint8_t __LDRBT(volatile uint8_t \param [in] ptr Pointer to data \return value of type uint16_t at (*ptr) */ -__attribute__((always_inline)) __STATIC_INLINE uint16_t __LDRHT(volatile uint16_t *ptr) +__STATIC_FORCEINLINE uint16_t __LDRHT(volatile uint16_t *ptr) { - uint32_t result; + uint32_t result; - __ASM volatile ("ldrht %0, %1" : "=r" (result) : "Q" (*ptr) ); - return ((uint16_t) result); /* Add explicit type cast here */ + __ASM volatile ("ldrht %0, %1" : "=r" (result) : "Q" (*ptr) ); + return ((uint16_t) result); /* Add explicit type cast here */ } @@ -1058,12 +1079,12 @@ __attribute__((always_inline)) __STATIC_INLINE uint16_t __LDRHT(volatile uint16_ \param [in] ptr Pointer to data \return value of type uint32_t at (*ptr) */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __LDRT(volatile uint32_t *ptr) +__STATIC_FORCEINLINE uint32_t __LDRT(volatile uint32_t *ptr) { - uint32_t result; + uint32_t result; - __ASM volatile ("ldrt %0, %1" : "=r" (result) : "Q" (*ptr) ); - return(result); + __ASM volatile ("ldrt %0, %1" : "=r" (result) : "Q" (*ptr) ); + return(result); } @@ -1073,9 +1094,9 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __LDRT(volatile uint32_t \param [in] value Value to store \param [in] ptr Pointer to location */ -__attribute__((always_inline)) __STATIC_INLINE void __STRBT(uint8_t value, volatile uint8_t *ptr) +__STATIC_FORCEINLINE void __STRBT(uint8_t value, volatile uint8_t *ptr) { - __ASM volatile ("strbt %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); + __ASM volatile ("strbt %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); } @@ -1085,9 +1106,9 @@ __attribute__((always_inline)) __STATIC_INLINE void __STRBT(uint8_t value, volat \param [in] value Value to store \param [in] ptr Pointer to location */ -__attribute__((always_inline)) __STATIC_INLINE void __STRHT(uint16_t value, volatile uint16_t *ptr) +__STATIC_FORCEINLINE void __STRHT(uint16_t value, volatile uint16_t *ptr) { - __ASM volatile ("strht %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); + __ASM volatile ("strht %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); } @@ -1097,28 +1118,83 @@ __attribute__((always_inline)) __STATIC_INLINE void __STRHT(uint16_t value, vola \param [in] value Value to store \param [in] ptr Pointer to location */ -__attribute__((always_inline)) __STATIC_INLINE void __STRT(uint32_t value, volatile uint32_t *ptr) +__STATIC_FORCEINLINE void __STRT(uint32_t value, volatile uint32_t *ptr) { - __ASM volatile ("strt %1, %0" : "=Q" (*ptr) : "r" (value) ); + __ASM volatile ("strt %1, %0" : "=Q" (*ptr) : "r" (value) ); } -#endif /* ((__ARM_ARCH_7M__ == 1U) || (__ARM_ARCH_7EM__ == 1U) || (__ARM_ARCH_8M__ == 1U)) */ +#else /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) */ + +/** + \brief Signed Saturate + \details Saturates a signed value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (1..32) + \return Saturated value + */ +__STATIC_FORCEINLINE int32_t __SSAT(int32_t val, uint32_t sat) +{ + if ((sat >= 1U) && (sat <= 32U)) + { + const int32_t max = (int32_t)((1U << (sat - 1U)) - 1U); + const int32_t min = -1 - max ; + if (val > max) + { + return max; + } + else if (val < min) + { + return min; + } + } + return val; +} + +/** + \brief Unsigned Saturate + \details Saturates an unsigned value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (0..31) + \return Saturated value + */ +__STATIC_FORCEINLINE uint32_t __USAT(int32_t val, uint32_t sat) +{ + if (sat <= 31U) + { + const uint32_t max = ((1U << sat) - 1U); + if (val > (int32_t)max) + { + return max; + } + else if (val < 0) + { + return 0U; + } + } + return (uint32_t)val; +} + +#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) */ -#if (__ARM_ARCH_8M__ == 1U) - +#if ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) /** \brief Load-Acquire (8 bit) \details Executes a LDAB instruction for 8 bit value. \param [in] ptr Pointer to data \return value of type uint8_t at (*ptr) */ -__attribute__((always_inline)) __STATIC_INLINE uint8_t __LDAB(volatile uint8_t *ptr) +__STATIC_FORCEINLINE uint8_t __LDAB(volatile uint8_t *ptr) { - uint32_t result; + uint32_t result; - __ASM volatile ("ldab %0, %1" : "=r" (result) : "Q" (*ptr) ); - return ((uint8_t) result); + __ASM volatile ("ldab %0, %1" : "=r" (result) : "Q" (*ptr) ); + return ((uint8_t) result); } @@ -1128,12 +1204,12 @@ __attribute__((always_inline)) __STATIC_INLINE uint8_t __LDAB(volatile uint8_t * \param [in] ptr Pointer to data \return value of type uint16_t at (*ptr) */ -__attribute__((always_inline)) __STATIC_INLINE uint16_t __LDAH(volatile uint16_t *ptr) +__STATIC_FORCEINLINE uint16_t __LDAH(volatile uint16_t *ptr) { - uint32_t result; + uint32_t result; - __ASM volatile ("ldah %0, %1" : "=r" (result) : "Q" (*ptr) ); - return ((uint16_t) result); + __ASM volatile ("ldah %0, %1" : "=r" (result) : "Q" (*ptr) ); + return ((uint16_t) result); } @@ -1143,12 +1219,12 @@ __attribute__((always_inline)) __STATIC_INLINE uint16_t __LDAH(volatile uint16_t \param [in] ptr Pointer to data \return value of type uint32_t at (*ptr) */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __LDA(volatile uint32_t *ptr) +__STATIC_FORCEINLINE uint32_t __LDA(volatile uint32_t *ptr) { - uint32_t result; + uint32_t result; - __ASM volatile ("lda %0, %1" : "=r" (result) : "Q" (*ptr) ); - return(result); + __ASM volatile ("lda %0, %1" : "=r" (result) : "Q" (*ptr) ); + return(result); } @@ -1158,9 +1234,9 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __LDA(volatile uint32_t \param [in] value Value to store \param [in] ptr Pointer to location */ -__attribute__((always_inline)) __STATIC_INLINE void __STLB(uint8_t value, volatile uint8_t *ptr) +__STATIC_FORCEINLINE void __STLB(uint8_t value, volatile uint8_t *ptr) { - __ASM volatile ("stlb %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); + __ASM volatile ("stlb %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); } @@ -1170,9 +1246,9 @@ __attribute__((always_inline)) __STATIC_INLINE void __STLB(uint8_t value, volati \param [in] value Value to store \param [in] ptr Pointer to location */ -__attribute__((always_inline)) __STATIC_INLINE void __STLH(uint16_t value, volatile uint16_t *ptr) +__STATIC_FORCEINLINE void __STLH(uint16_t value, volatile uint16_t *ptr) { - __ASM volatile ("stlh %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); + __ASM volatile ("stlh %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); } @@ -1182,9 +1258,9 @@ __attribute__((always_inline)) __STATIC_INLINE void __STLH(uint16_t value, volat \param [in] value Value to store \param [in] ptr Pointer to location */ -__attribute__((always_inline)) __STATIC_INLINE void __STL(uint32_t value, volatile uint32_t *ptr) +__STATIC_FORCEINLINE void __STL(uint32_t value, volatile uint32_t *ptr) { - __ASM volatile ("stl %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); + __ASM volatile ("stl %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); } @@ -1247,7 +1323,8 @@ __attribute__((always_inline)) __STATIC_INLINE void __STL(uint32_t value, volati */ #define __STLEX (uint32_t)__builtin_arm_stlex -#endif /* (__ARM_ARCH_8M__ == 1U) */ +#endif /* ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) */ /*@}*/ /* end of group CMSIS_Core_InstructionInterface */ @@ -1258,9 +1335,9 @@ __attribute__((always_inline)) __STATIC_INLINE void __STL(uint32_t value, volati @{ */ -#if (__ARM_FEATURE_DSP == 1U) /* ToDo: ARMCC_V6: This should be ARCH >= ARMv7-M + SIMD */ +#if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) -__attribute__((always_inline)) __STATIC_INLINE uint32_t __SADD8(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SADD8(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1268,7 +1345,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __SADD8(uint32_t op1, ui return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __QADD8(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __QADD8(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1276,7 +1353,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __QADD8(uint32_t op1, ui return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __SHADD8(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SHADD8(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1284,7 +1361,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __SHADD8(uint32_t op1, u return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __UADD8(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UADD8(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1292,7 +1369,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __UADD8(uint32_t op1, ui return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __UQADD8(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UQADD8(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1300,7 +1377,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __UQADD8(uint32_t op1, u return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __UHADD8(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UHADD8(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1309,7 +1386,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __UHADD8(uint32_t op1, u } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __SSUB8(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SSUB8(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1317,7 +1394,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __SSUB8(uint32_t op1, ui return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __QSUB8(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __QSUB8(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1325,7 +1402,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __QSUB8(uint32_t op1, ui return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __SHSUB8(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SHSUB8(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1333,7 +1410,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __SHSUB8(uint32_t op1, u return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __USUB8(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __USUB8(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1341,7 +1418,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __USUB8(uint32_t op1, ui return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __UQSUB8(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UQSUB8(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1349,7 +1426,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __UQSUB8(uint32_t op1, u return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __UHSUB8(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UHSUB8(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1358,7 +1435,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __UHSUB8(uint32_t op1, u } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __SADD16(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SADD16(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1366,7 +1443,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __SADD16(uint32_t op1, u return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __QADD16(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __QADD16(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1374,7 +1451,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __QADD16(uint32_t op1, u return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __SHADD16(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SHADD16(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1382,7 +1459,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __SHADD16(uint32_t op1, return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __UADD16(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UADD16(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1390,7 +1467,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __UADD16(uint32_t op1, u return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __UQADD16(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UQADD16(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1398,7 +1475,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __UQADD16(uint32_t op1, return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __UHADD16(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UHADD16(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1406,7 +1483,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __UHADD16(uint32_t op1, return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __SSUB16(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SSUB16(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1414,7 +1491,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __SSUB16(uint32_t op1, u return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __QSUB16(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __QSUB16(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1422,7 +1499,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __QSUB16(uint32_t op1, u return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __SHSUB16(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SHSUB16(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1430,7 +1507,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __SHSUB16(uint32_t op1, return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __USUB16(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __USUB16(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1438,7 +1515,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __USUB16(uint32_t op1, u return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __UQSUB16(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UQSUB16(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1446,7 +1523,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __UQSUB16(uint32_t op1, return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __UHSUB16(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UHSUB16(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1454,7 +1531,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __UHSUB16(uint32_t op1, return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __SASX(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SASX(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1462,7 +1539,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __SASX(uint32_t op1, uin return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __QASX(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __QASX(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1470,7 +1547,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __QASX(uint32_t op1, uin return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __SHASX(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SHASX(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1478,7 +1555,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __SHASX(uint32_t op1, ui return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __UASX(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UASX(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1486,7 +1563,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __UASX(uint32_t op1, uin return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __UQASX(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UQASX(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1494,7 +1571,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __UQASX(uint32_t op1, ui return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __UHASX(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UHASX(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1502,7 +1579,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __UHASX(uint32_t op1, ui return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __SSAX(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SSAX(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1510,7 +1587,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __SSAX(uint32_t op1, uin return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __QSAX(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __QSAX(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1518,7 +1595,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __QSAX(uint32_t op1, uin return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __SHSAX(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SHSAX(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1526,7 +1603,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __SHSAX(uint32_t op1, ui return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __USAX(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __USAX(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1534,7 +1611,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __USAX(uint32_t op1, uin return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __UQSAX(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UQSAX(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1542,7 +1619,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __UQSAX(uint32_t op1, ui return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __UHSAX(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UHSAX(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1550,7 +1627,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __UHSAX(uint32_t op1, ui return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __USAD8(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __USAD8(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1558,7 +1635,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __USAD8(uint32_t op1, ui return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __USADA8(uint32_t op1, uint32_t op2, uint32_t op3) +__STATIC_FORCEINLINE uint32_t __USADA8(uint32_t op1, uint32_t op2, uint32_t op3) { uint32_t result; @@ -1568,7 +1645,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __USADA8(uint32_t op1, u #define __SSAT16(ARG1,ARG2) \ ({ \ - uint32_t __RES, __ARG1 = (ARG1); \ + int32_t __RES, __ARG1 = (ARG1); \ __ASM ("ssat16 %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \ __RES; \ }) @@ -1580,7 +1657,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __USADA8(uint32_t op1, u __RES; \ }) -__attribute__((always_inline)) __STATIC_INLINE uint32_t __UXTB16(uint32_t op1) +__STATIC_FORCEINLINE uint32_t __UXTB16(uint32_t op1) { uint32_t result; @@ -1588,7 +1665,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __UXTB16(uint32_t op1) return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __UXTAB16(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UXTAB16(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1596,7 +1673,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __UXTAB16(uint32_t op1, return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __SXTB16(uint32_t op1) +__STATIC_FORCEINLINE uint32_t __SXTB16(uint32_t op1) { uint32_t result; @@ -1604,7 +1681,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __SXTB16(uint32_t op1) return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __SXTAB16(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SXTAB16(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1612,7 +1689,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __SXTAB16(uint32_t op1, return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __SMUAD (uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SMUAD (uint32_t op1, uint32_t op2) { uint32_t result; @@ -1620,7 +1697,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __SMUAD (uint32_t op1, return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __SMUADX (uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SMUADX (uint32_t op1, uint32_t op2) { uint32_t result; @@ -1628,7 +1705,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __SMUADX (uint32_t op1, return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __SMLAD (uint32_t op1, uint32_t op2, uint32_t op3) +__STATIC_FORCEINLINE uint32_t __SMLAD (uint32_t op1, uint32_t op2, uint32_t op3) { uint32_t result; @@ -1636,7 +1713,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __SMLAD (uint32_t op1, u return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __SMLADX (uint32_t op1, uint32_t op2, uint32_t op3) +__STATIC_FORCEINLINE uint32_t __SMLADX (uint32_t op1, uint32_t op2, uint32_t op3) { uint32_t result; @@ -1644,7 +1721,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __SMLADX (uint32_t op1, return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint64_t __SMLALD (uint32_t op1, uint32_t op2, uint64_t acc) +__STATIC_FORCEINLINE uint64_t __SMLALD (uint32_t op1, uint32_t op2, uint64_t acc) { union llreg_u{ uint32_t w32[2]; @@ -1661,7 +1738,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint64_t __SMLALD (uint32_t op1, return(llr.w64); } -__attribute__((always_inline)) __STATIC_INLINE uint64_t __SMLALDX (uint32_t op1, uint32_t op2, uint64_t acc) +__STATIC_FORCEINLINE uint64_t __SMLALDX (uint32_t op1, uint32_t op2, uint64_t acc) { union llreg_u{ uint32_t w32[2]; @@ -1678,7 +1755,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint64_t __SMLALDX (uint32_t op1, return(llr.w64); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __SMUSD (uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SMUSD (uint32_t op1, uint32_t op2) { uint32_t result; @@ -1686,7 +1763,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __SMUSD (uint32_t op1, return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __SMUSDX (uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SMUSDX (uint32_t op1, uint32_t op2) { uint32_t result; @@ -1694,7 +1771,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __SMUSDX (uint32_t op1, return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __SMLSD (uint32_t op1, uint32_t op2, uint32_t op3) +__STATIC_FORCEINLINE uint32_t __SMLSD (uint32_t op1, uint32_t op2, uint32_t op3) { uint32_t result; @@ -1702,7 +1779,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __SMLSD (uint32_t op1, u return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __SMLSDX (uint32_t op1, uint32_t op2, uint32_t op3) +__STATIC_FORCEINLINE uint32_t __SMLSDX (uint32_t op1, uint32_t op2, uint32_t op3) { uint32_t result; @@ -1710,7 +1787,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __SMLSDX (uint32_t op1, return(result); } -__attribute__((always_inline)) __STATIC_INLINE uint64_t __SMLSLD (uint32_t op1, uint32_t op2, uint64_t acc) +__STATIC_FORCEINLINE uint64_t __SMLSLD (uint32_t op1, uint32_t op2, uint64_t acc) { union llreg_u{ uint32_t w32[2]; @@ -1727,7 +1804,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint64_t __SMLSLD (uint32_t op1, return(llr.w64); } -__attribute__((always_inline)) __STATIC_INLINE uint64_t __SMLSLDX (uint32_t op1, uint32_t op2, uint64_t acc) +__STATIC_FORCEINLINE uint64_t __SMLSLDX (uint32_t op1, uint32_t op2, uint64_t acc) { union llreg_u{ uint32_t w32[2]; @@ -1744,7 +1821,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint64_t __SMLSLDX (uint32_t op1, return(llr.w64); } -__attribute__((always_inline)) __STATIC_INLINE uint32_t __SEL (uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SEL (uint32_t op1, uint32_t op2) { uint32_t result; @@ -1752,7 +1829,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __SEL (uint32_t op1, ui return(result); } -__attribute__((always_inline)) __STATIC_INLINE int32_t __QADD( int32_t op1, int32_t op2) +__STATIC_FORCEINLINE int32_t __QADD( int32_t op1, int32_t op2) { int32_t result; @@ -1760,7 +1837,7 @@ __attribute__((always_inline)) __STATIC_INLINE int32_t __QADD( int32_t op1, in return(result); } -__attribute__((always_inline)) __STATIC_INLINE int32_t __QSUB( int32_t op1, int32_t op2) +__STATIC_FORCEINLINE int32_t __QSUB( int32_t op1, int32_t op2) { int32_t result; @@ -1768,33 +1845,22 @@ __attribute__((always_inline)) __STATIC_INLINE int32_t __QSUB( int32_t op1, in return(result); } -#define __PKHBT(ARG1,ARG2,ARG3) \ -({ \ - uint32_t __RES, __ARG1 = (ARG1), __ARG2 = (ARG2); \ - __ASM ("pkhbt %0, %1, %2, lsl %3" : "=r" (__RES) : "r" (__ARG1), "r" (__ARG2), "I" (ARG3) ); \ - __RES; \ - }) +#define __PKHBT(ARG1,ARG2,ARG3) ( ((((uint32_t)(ARG1)) ) & 0x0000FFFFUL) | \ + ((((uint32_t)(ARG2)) << (ARG3)) & 0xFFFF0000UL) ) -#define __PKHTB(ARG1,ARG2,ARG3) \ -({ \ - uint32_t __RES, __ARG1 = (ARG1), __ARG2 = (ARG2); \ - if (ARG3 == 0) \ - __ASM ("pkhtb %0, %1, %2" : "=r" (__RES) : "r" (__ARG1), "r" (__ARG2) ); \ - else \ - __ASM ("pkhtb %0, %1, %2, asr %3" : "=r" (__RES) : "r" (__ARG1), "r" (__ARG2), "I" (ARG3) ); \ - __RES; \ - }) +#define __PKHTB(ARG1,ARG2,ARG3) ( ((((uint32_t)(ARG1)) ) & 0xFFFF0000UL) | \ + ((((uint32_t)(ARG2)) >> (ARG3)) & 0x0000FFFFUL) ) -__attribute__((always_inline)) __STATIC_INLINE uint32_t __SMMLA (int32_t op1, int32_t op2, int32_t op3) +__STATIC_FORCEINLINE int32_t __SMMLA (int32_t op1, int32_t op2, int32_t op3) { - int32_t result; + int32_t result; - __ASM volatile ("smmla %0, %1, %2, %3" : "=r" (result): "r" (op1), "r" (op2), "r" (op3) ); - return(result); + __ASM volatile ("smmla %0, %1, %2, %3" : "=r" (result): "r" (op1), "r" (op2), "r" (op3) ); + return(result); } -#endif /* (__ARM_FEATURE_DSP == 1U) */ +#endif /* (__ARM_FEATURE_DSP == 1) */ /*@} end of group CMSIS_SIMD_intrinsics */ -#endif /* __CMSIS_ARMCC_V6_H */ +#endif /* __CMSIS_ARMCLANG_H */ diff --git a/lib/cmsis/inc/cmsis_compiler.h b/lib/cmsis/inc/cmsis_compiler.h new file mode 100644 index 0000000000..fdb1a971c6 --- /dev/null +++ b/lib/cmsis/inc/cmsis_compiler.h @@ -0,0 +1,271 @@ +/**************************************************************************//** + * @file cmsis_compiler.h + * @brief CMSIS compiler generic header file + * @version V5.1.0 + * @date 09. October 2018 + ******************************************************************************/ +/* + * Copyright (c) 2009-2018 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __CMSIS_COMPILER_H +#define __CMSIS_COMPILER_H + +#include + +/* + * Arm Compiler 4/5 + */ +#if defined ( __CC_ARM ) + #include "cmsis_armcc.h" + + +/* + * Arm Compiler 6.6 LTM (armclang) + */ +#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) && (__ARMCC_VERSION < 6100100) + #include "cmsis_armclang_ltm.h" + + /* + * Arm Compiler above 6.10.1 (armclang) + */ +#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6100100) + #include "cmsis_armclang.h" + + +/* + * GNU Compiler + */ +#elif defined ( __GNUC__ ) + #include "cmsis_gcc.h" + + +/* + * IAR Compiler + */ +#elif defined ( __ICCARM__ ) + #include + + +/* + * TI Arm Compiler + */ +#elif defined ( __TI_ARM__ ) + #include + + #ifndef __ASM + #define __ASM __asm + #endif + #ifndef __INLINE + #define __INLINE inline + #endif + #ifndef __STATIC_INLINE + #define __STATIC_INLINE static inline + #endif + #ifndef __STATIC_FORCEINLINE + #define __STATIC_FORCEINLINE __STATIC_INLINE + #endif + #ifndef __NO_RETURN + #define __NO_RETURN __attribute__((noreturn)) + #endif + #ifndef __USED + #define __USED __attribute__((used)) + #endif + #ifndef __WEAK + #define __WEAK __attribute__((weak)) + #endif + #ifndef __PACKED + #define __PACKED __attribute__((packed)) + #endif + #ifndef __PACKED_STRUCT + #define __PACKED_STRUCT struct __attribute__((packed)) + #endif + #ifndef __PACKED_UNION + #define __PACKED_UNION union __attribute__((packed)) + #endif + #ifndef __UNALIGNED_UINT32 /* deprecated */ + struct __attribute__((packed)) T_UINT32 { uint32_t v; }; + #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) + #endif + #ifndef __UNALIGNED_UINT16_WRITE + __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; + #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void*)(addr))->v) = (val)) + #endif + #ifndef __UNALIGNED_UINT16_READ + __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; + #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) + #endif + #ifndef __UNALIGNED_UINT32_WRITE + __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; + #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) + #endif + #ifndef __UNALIGNED_UINT32_READ + __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; + #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) + #endif + #ifndef __ALIGNED + #define __ALIGNED(x) __attribute__((aligned(x))) + #endif + #ifndef __RESTRICT + #define __RESTRICT __restrict + #endif + + +/* + * TASKING Compiler + */ +#elif defined ( __TASKING__ ) + /* + * The CMSIS functions have been implemented as intrinsics in the compiler. + * Please use "carm -?i" to get an up to date list of all intrinsics, + * Including the CMSIS ones. + */ + + #ifndef __ASM + #define __ASM __asm + #endif + #ifndef __INLINE + #define __INLINE inline + #endif + #ifndef __STATIC_INLINE + #define __STATIC_INLINE static inline + #endif + #ifndef __STATIC_FORCEINLINE + #define __STATIC_FORCEINLINE __STATIC_INLINE + #endif + #ifndef __NO_RETURN + #define __NO_RETURN __attribute__((noreturn)) + #endif + #ifndef __USED + #define __USED __attribute__((used)) + #endif + #ifndef __WEAK + #define __WEAK __attribute__((weak)) + #endif + #ifndef __PACKED + #define __PACKED __packed__ + #endif + #ifndef __PACKED_STRUCT + #define __PACKED_STRUCT struct __packed__ + #endif + #ifndef __PACKED_UNION + #define __PACKED_UNION union __packed__ + #endif + #ifndef __UNALIGNED_UINT32 /* deprecated */ + struct __packed__ T_UINT32 { uint32_t v; }; + #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) + #endif + #ifndef __UNALIGNED_UINT16_WRITE + __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; + #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val)) + #endif + #ifndef __UNALIGNED_UINT16_READ + __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; + #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) + #endif + #ifndef __UNALIGNED_UINT32_WRITE + __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; + #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) + #endif + #ifndef __UNALIGNED_UINT32_READ + __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; + #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) + #endif + #ifndef __ALIGNED + #define __ALIGNED(x) __align(x) + #endif + #ifndef __RESTRICT + #warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored. + #define __RESTRICT + #endif + + +/* + * COSMIC Compiler + */ +#elif defined ( __CSMC__ ) + #include + + #ifndef __ASM + #define __ASM _asm + #endif + #ifndef __INLINE + #define __INLINE inline + #endif + #ifndef __STATIC_INLINE + #define __STATIC_INLINE static inline + #endif + #ifndef __STATIC_FORCEINLINE + #define __STATIC_FORCEINLINE __STATIC_INLINE + #endif + #ifndef __NO_RETURN + // NO RETURN is automatically detected hence no warning here + #define __NO_RETURN + #endif + #ifndef __USED + #warning No compiler specific solution for __USED. __USED is ignored. + #define __USED + #endif + #ifndef __WEAK + #define __WEAK __weak + #endif + #ifndef __PACKED + #define __PACKED @packed + #endif + #ifndef __PACKED_STRUCT + #define __PACKED_STRUCT @packed struct + #endif + #ifndef __PACKED_UNION + #define __PACKED_UNION @packed union + #endif + #ifndef __UNALIGNED_UINT32 /* deprecated */ + @packed struct T_UINT32 { uint32_t v; }; + #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) + #endif + #ifndef __UNALIGNED_UINT16_WRITE + __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; + #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val)) + #endif + #ifndef __UNALIGNED_UINT16_READ + __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; + #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) + #endif + #ifndef __UNALIGNED_UINT32_WRITE + __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; + #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) + #endif + #ifndef __UNALIGNED_UINT32_READ + __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; + #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) + #endif + #ifndef __ALIGNED + #warning No compiler specific solution for __ALIGNED. __ALIGNED is ignored. + #define __ALIGNED(x) + #endif + #ifndef __RESTRICT + #warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored. + #define __RESTRICT + #endif + + +#else + #error Unknown compiler. +#endif + + +#endif /* __CMSIS_COMPILER_H */ + diff --git a/lib/cmsis/inc/cmsis_gcc.h b/lib/cmsis/inc/cmsis_gcc.h index bb89fbba9e..d86b0a2d5a 100644 --- a/lib/cmsis/inc/cmsis_gcc.h +++ b/lib/cmsis/inc/cmsis_gcc.h @@ -1,46 +1,117 @@ /**************************************************************************//** * @file cmsis_gcc.h - * @brief CMSIS Cortex-M Core Function/Instruction Header File - * @version V4.30 - * @date 20. October 2015 + * @brief CMSIS compiler GCC header file + * @version V5.1.0 + * @date 20. December 2018 ******************************************************************************/ -/* Copyright (c) 2009 - 2015 ARM LIMITED - - All rights reserved. - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 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. - - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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. - ---------------------------------------------------------------------------*/ - +/* + * Copyright (c) 2009-2018 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #ifndef __CMSIS_GCC_H #define __CMSIS_GCC_H /* ignore some GCC warnings */ -#if defined ( __GNUC__ ) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-conversion" #pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic ignored "-Wunused-parameter" + +/* Fallback for __has_builtin */ +#ifndef __has_builtin + #define __has_builtin(x) (0) +#endif + +/* CMSIS compiler specific defines */ +#ifndef __ASM + #define __ASM __asm +#endif +#ifndef __INLINE + #define __INLINE inline +#endif +#ifndef __STATIC_INLINE + #define __STATIC_INLINE static inline +#endif +#ifndef __STATIC_FORCEINLINE + #define __STATIC_FORCEINLINE __attribute__((always_inline)) static inline +#endif +#ifndef __NO_RETURN + #define __NO_RETURN __attribute__((__noreturn__)) +#endif +#ifndef __USED + #define __USED __attribute__((used)) +#endif +#ifndef __WEAK + #define __WEAK __attribute__((weak)) +#endif +#ifndef __PACKED + #define __PACKED __attribute__((packed, aligned(1))) +#endif +#ifndef __PACKED_STRUCT + #define __PACKED_STRUCT struct __attribute__((packed, aligned(1))) +#endif +#ifndef __PACKED_UNION + #define __PACKED_UNION union __attribute__((packed, aligned(1))) +#endif +#ifndef __UNALIGNED_UINT32 /* deprecated */ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wpacked" + #pragma GCC diagnostic ignored "-Wattributes" + struct __attribute__((packed)) T_UINT32 { uint32_t v; }; + #pragma GCC diagnostic pop + #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) +#endif +#ifndef __UNALIGNED_UINT16_WRITE + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wpacked" + #pragma GCC diagnostic ignored "-Wattributes" + __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; + #pragma GCC diagnostic pop + #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val)) +#endif +#ifndef __UNALIGNED_UINT16_READ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wpacked" + #pragma GCC diagnostic ignored "-Wattributes" + __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; + #pragma GCC diagnostic pop + #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) +#endif +#ifndef __UNALIGNED_UINT32_WRITE + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wpacked" + #pragma GCC diagnostic ignored "-Wattributes" + __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; + #pragma GCC diagnostic pop + #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) +#endif +#ifndef __UNALIGNED_UINT32_READ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wpacked" + #pragma GCC diagnostic ignored "-Wattributes" + __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; + #pragma GCC diagnostic pop + #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) +#endif +#ifndef __ALIGNED + #define __ALIGNED(x) __attribute__((aligned(x))) +#endif +#ifndef __RESTRICT + #define __RESTRICT __restrict #endif @@ -55,7 +126,7 @@ \details Enables IRQ interrupts by clearing the I-bit in the CPSR. Can only be executed in Privileged modes. */ -__attribute__( ( always_inline ) ) __STATIC_INLINE void __enable_irq(void) +__STATIC_FORCEINLINE void __enable_irq(void) { __ASM volatile ("cpsie i" : : : "memory"); } @@ -64,9 +135,9 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE void __enable_irq(void) /** \brief Disable IRQ Interrupts \details Disables IRQ interrupts by setting the I-bit in the CPSR. - Can only be executed in Privileged modes. + Can only be executed in Privileged modes. */ -__attribute__( ( always_inline ) ) __STATIC_INLINE void __disable_irq(void) +__STATIC_FORCEINLINE void __disable_irq(void) { __ASM volatile ("cpsid i" : : : "memory"); } @@ -77,7 +148,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE void __disable_irq(void) \details Returns the content of the Control Register. \return Control Register value */ -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_CONTROL(void) +__STATIC_FORCEINLINE uint32_t __get_CONTROL(void) { uint32_t result; @@ -86,23 +157,52 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_CONTROL(void) } +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Control Register (non-secure) + \details Returns the content of the non-secure Control Register when in secure mode. + \return non-secure Control Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_CONTROL_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, control_ns" : "=r" (result) ); + return(result); +} +#endif + + /** \brief Set Control Register \details Writes the given value to the Control Register. \param [in] control Control Register value to set */ -__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_CONTROL(uint32_t control) +__STATIC_FORCEINLINE void __set_CONTROL(uint32_t control) { __ASM volatile ("MSR control, %0" : : "r" (control) : "memory"); } +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Control Register (non-secure) + \details Writes the given value to the non-secure Control Register when in secure state. + \param [in] control Control Register value to set + */ +__STATIC_FORCEINLINE void __TZ_set_CONTROL_NS(uint32_t control) +{ + __ASM volatile ("MSR control_ns, %0" : : "r" (control) : "memory"); +} +#endif + + /** \brief Get IPSR Register \details Returns the content of the IPSR Register. \return IPSR Register value */ -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_IPSR(void) +__STATIC_FORCEINLINE uint32_t __get_IPSR(void) { uint32_t result; @@ -116,7 +216,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_IPSR(void) \details Returns the content of the APSR Register. \return APSR Register value */ -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_APSR(void) +__STATIC_FORCEINLINE uint32_t __get_APSR(void) { uint32_t result; @@ -128,10 +228,9 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_APSR(void) /** \brief Get xPSR Register \details Returns the content of the xPSR Register. - - \return xPSR Register value + \return xPSR Register value */ -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_xPSR(void) +__STATIC_FORCEINLINE uint32_t __get_xPSR(void) { uint32_t result; @@ -145,85 +244,199 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_xPSR(void) \details Returns the current value of the Process Stack Pointer (PSP). \return PSP Register value */ -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_PSP(void) +__STATIC_FORCEINLINE uint32_t __get_PSP(void) { - register uint32_t result; + uint32_t result; - __ASM volatile ("MRS %0, psp\n" : "=r" (result) ); + __ASM volatile ("MRS %0, psp" : "=r" (result) ); return(result); } +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Process Stack Pointer (non-secure) + \details Returns the current value of the non-secure Process Stack Pointer (PSP) when in secure state. + \return PSP Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_PSP_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, psp_ns" : "=r" (result) ); + return(result); +} +#endif + + /** \brief Set Process Stack Pointer \details Assigns the given value to the Process Stack Pointer (PSP). \param [in] topOfProcStack Process Stack Pointer value to set */ -__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_PSP(uint32_t topOfProcStack) +__STATIC_FORCEINLINE void __set_PSP(uint32_t topOfProcStack) { - __ASM volatile ("MSR psp, %0\n" : : "r" (topOfProcStack) : "sp"); + __ASM volatile ("MSR psp, %0" : : "r" (topOfProcStack) : ); } +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Process Stack Pointer (non-secure) + \details Assigns the given value to the non-secure Process Stack Pointer (PSP) when in secure state. + \param [in] topOfProcStack Process Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __TZ_set_PSP_NS(uint32_t topOfProcStack) +{ + __ASM volatile ("MSR psp_ns, %0" : : "r" (topOfProcStack) : ); +} +#endif + + /** \brief Get Main Stack Pointer \details Returns the current value of the Main Stack Pointer (MSP). \return MSP Register value */ -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_MSP(void) +__STATIC_FORCEINLINE uint32_t __get_MSP(void) { - register uint32_t result; + uint32_t result; - __ASM volatile ("MRS %0, msp\n" : "=r" (result) ); + __ASM volatile ("MRS %0, msp" : "=r" (result) ); return(result); } +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Main Stack Pointer (non-secure) + \details Returns the current value of the non-secure Main Stack Pointer (MSP) when in secure state. + \return MSP Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_MSP_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, msp_ns" : "=r" (result) ); + return(result); +} +#endif + + /** \brief Set Main Stack Pointer \details Assigns the given value to the Main Stack Pointer (MSP). - - \param [in] topOfMainStack Main Stack Pointer value to set + \param [in] topOfMainStack Main Stack Pointer value to set */ -__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_MSP(uint32_t topOfMainStack) +__STATIC_FORCEINLINE void __set_MSP(uint32_t topOfMainStack) { - __ASM volatile ("MSR msp, %0\n" : : "r" (topOfMainStack) : "sp"); + __ASM volatile ("MSR msp, %0" : : "r" (topOfMainStack) : ); } +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Main Stack Pointer (non-secure) + \details Assigns the given value to the non-secure Main Stack Pointer (MSP) when in secure state. + \param [in] topOfMainStack Main Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __TZ_set_MSP_NS(uint32_t topOfMainStack) +{ + __ASM volatile ("MSR msp_ns, %0" : : "r" (topOfMainStack) : ); +} +#endif + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Stack Pointer (non-secure) + \details Returns the current value of the non-secure Stack Pointer (SP) when in secure state. + \return SP Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_SP_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, sp_ns" : "=r" (result) ); + return(result); +} + + +/** + \brief Set Stack Pointer (non-secure) + \details Assigns the given value to the non-secure Stack Pointer (SP) when in secure state. + \param [in] topOfStack Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __TZ_set_SP_NS(uint32_t topOfStack) +{ + __ASM volatile ("MSR sp_ns, %0" : : "r" (topOfStack) : ); +} +#endif + + /** \brief Get Priority Mask \details Returns the current state of the priority mask bit from the Priority Mask Register. \return Priority Mask value */ -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_PRIMASK(void) +__STATIC_FORCEINLINE uint32_t __get_PRIMASK(void) { uint32_t result; - __ASM volatile ("MRS %0, primask" : "=r" (result) ); + __ASM volatile ("MRS %0, primask" : "=r" (result) :: "memory"); return(result); } +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Priority Mask (non-secure) + \details Returns the current state of the non-secure priority mask bit from the Priority Mask Register when in secure state. + \return Priority Mask value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_PRIMASK_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, primask_ns" : "=r" (result) :: "memory"); + return(result); +} +#endif + + /** \brief Set Priority Mask \details Assigns the given value to the Priority Mask Register. \param [in] priMask Priority Mask */ -__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_PRIMASK(uint32_t priMask) +__STATIC_FORCEINLINE void __set_PRIMASK(uint32_t priMask) { __ASM volatile ("MSR primask, %0" : : "r" (priMask) : "memory"); } -#if (__CORTEX_M >= 0x03U) +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Priority Mask (non-secure) + \details Assigns the given value to the non-secure Priority Mask Register when in secure state. + \param [in] priMask Priority Mask + */ +__STATIC_FORCEINLINE void __TZ_set_PRIMASK_NS(uint32_t priMask) +{ + __ASM volatile ("MSR primask_ns, %0" : : "r" (priMask) : "memory"); +} +#endif + +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) /** \brief Enable FIQ \details Enables FIQ interrupts by clearing the F-bit in the CPSR. Can only be executed in Privileged modes. */ -__attribute__( ( always_inline ) ) __STATIC_INLINE void __enable_fault_irq(void) +__STATIC_FORCEINLINE void __enable_fault_irq(void) { __ASM volatile ("cpsie f" : : : "memory"); } @@ -234,7 +447,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE void __enable_fault_irq(void) \details Disables FIQ interrupts by setting the F-bit in the CPSR. Can only be executed in Privileged modes. */ -__attribute__( ( always_inline ) ) __STATIC_INLINE void __disable_fault_irq(void) +__STATIC_FORCEINLINE void __disable_fault_irq(void) { __ASM volatile ("cpsid f" : : : "memory"); } @@ -245,7 +458,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE void __disable_fault_irq(void \details Returns the current value of the Base Priority register. \return Base Priority register value */ -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_BASEPRI(void) +__STATIC_FORCEINLINE uint32_t __get_BASEPRI(void) { uint32_t result; @@ -254,26 +467,55 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_BASEPRI(void) } +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Base Priority (non-secure) + \details Returns the current value of the non-secure Base Priority register when in secure state. + \return Base Priority register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_BASEPRI_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, basepri_ns" : "=r" (result) ); + return(result); +} +#endif + + /** \brief Set Base Priority \details Assigns the given value to the Base Priority register. \param [in] basePri Base Priority value to set */ -__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_BASEPRI(uint32_t value) +__STATIC_FORCEINLINE void __set_BASEPRI(uint32_t basePri) { - __ASM volatile ("MSR basepri, %0" : : "r" (value) : "memory"); + __ASM volatile ("MSR basepri, %0" : : "r" (basePri) : "memory"); } +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Base Priority (non-secure) + \details Assigns the given value to the non-secure Base Priority register when in secure state. + \param [in] basePri Base Priority value to set + */ +__STATIC_FORCEINLINE void __TZ_set_BASEPRI_NS(uint32_t basePri) +{ + __ASM volatile ("MSR basepri_ns, %0" : : "r" (basePri) : "memory"); +} +#endif + + /** \brief Set Base Priority with condition \details Assigns the given value to the Base Priority register only if BASEPRI masking is disabled, or the new value increases the BASEPRI priority level. \param [in] basePri Base Priority value to set */ -__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_BASEPRI_MAX(uint32_t value) +__STATIC_FORCEINLINE void __set_BASEPRI_MAX(uint32_t basePri) { - __ASM volatile ("MSR basepri_max, %0" : : "r" (value) : "memory"); + __ASM volatile ("MSR basepri_max, %0" : : "r" (basePri) : "memory"); } @@ -282,7 +524,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE void __set_BASEPRI_MAX(uint32 \details Returns the current value of the Fault Mask register. \return Fault Mask register value */ -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_FAULTMASK(void) +__STATIC_FORCEINLINE uint32_t __get_FAULTMASK(void) { uint32_t result; @@ -291,38 +533,253 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_FAULTMASK(void } +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Fault Mask (non-secure) + \details Returns the current value of the non-secure Fault Mask register when in secure state. + \return Fault Mask register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_FAULTMASK_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, faultmask_ns" : "=r" (result) ); + return(result); +} +#endif + + /** \brief Set Fault Mask \details Assigns the given value to the Fault Mask register. \param [in] faultMask Fault Mask value to set */ -__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_FAULTMASK(uint32_t faultMask) +__STATIC_FORCEINLINE void __set_FAULTMASK(uint32_t faultMask) { __ASM volatile ("MSR faultmask, %0" : : "r" (faultMask) : "memory"); } -#endif /* (__CORTEX_M >= 0x03U) */ + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Fault Mask (non-secure) + \details Assigns the given value to the non-secure Fault Mask register when in secure state. + \param [in] faultMask Fault Mask value to set + */ +__STATIC_FORCEINLINE void __TZ_set_FAULTMASK_NS(uint32_t faultMask) +{ + __ASM volatile ("MSR faultmask_ns, %0" : : "r" (faultMask) : "memory"); +} +#endif + +#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) */ -#if (__CORTEX_M == 0x04U) || (__CORTEX_M == 0x07U) +#if ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) + +/** + \brief Get Process Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always in non-secure + mode. + + \details Returns the current value of the Process Stack Pointer Limit (PSPLIM). + \return PSPLIM Register value + */ +__STATIC_FORCEINLINE uint32_t __get_PSPLIM(void) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; + __ASM volatile ("MRS %0, psplim" : "=r" (result) ); + return result; +#endif +} + +#if (defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Process Stack Pointer Limit (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always. + + \details Returns the current value of the non-secure Process Stack Pointer Limit (PSPLIM) when in secure state. + \return PSPLIM Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_PSPLIM_NS(void) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; + __ASM volatile ("MRS %0, psplim_ns" : "=r" (result) ); + return result; +#endif +} +#endif + + +/** + \brief Set Process Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored in non-secure + mode. + + \details Assigns the given value to the Process Stack Pointer Limit (PSPLIM). + \param [in] ProcStackPtrLimit Process Stack Pointer Limit value to set + */ +__STATIC_FORCEINLINE void __set_PSPLIM(uint32_t ProcStackPtrLimit) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + (void)ProcStackPtrLimit; +#else + __ASM volatile ("MSR psplim, %0" : : "r" (ProcStackPtrLimit)); +#endif +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Process Stack Pointer (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored. + + \details Assigns the given value to the non-secure Process Stack Pointer Limit (PSPLIM) when in secure state. + \param [in] ProcStackPtrLimit Process Stack Pointer Limit value to set + */ +__STATIC_FORCEINLINE void __TZ_set_PSPLIM_NS(uint32_t ProcStackPtrLimit) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + (void)ProcStackPtrLimit; +#else + __ASM volatile ("MSR psplim_ns, %0\n" : : "r" (ProcStackPtrLimit)); +#endif +} +#endif + + +/** + \brief Get Main Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always in non-secure + mode. + + \details Returns the current value of the Main Stack Pointer Limit (MSPLIM). + \return MSPLIM Register value + */ +__STATIC_FORCEINLINE uint32_t __get_MSPLIM(void) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; + __ASM volatile ("MRS %0, msplim" : "=r" (result) ); + return result; +#endif +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Main Stack Pointer Limit (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always. + + \details Returns the current value of the non-secure Main Stack Pointer Limit(MSPLIM) when in secure state. + \return MSPLIM Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_MSPLIM_NS(void) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; + __ASM volatile ("MRS %0, msplim_ns" : "=r" (result) ); + return result; +#endif +} +#endif + + +/** + \brief Set Main Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored in non-secure + mode. + + \details Assigns the given value to the Main Stack Pointer Limit (MSPLIM). + \param [in] MainStackPtrLimit Main Stack Pointer Limit value to set + */ +__STATIC_FORCEINLINE void __set_MSPLIM(uint32_t MainStackPtrLimit) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + (void)MainStackPtrLimit; +#else + __ASM volatile ("MSR msplim, %0" : : "r" (MainStackPtrLimit)); +#endif +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Main Stack Pointer Limit (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored. + + \details Assigns the given value to the non-secure Main Stack Pointer Limit (MSPLIM) when in secure state. + \param [in] MainStackPtrLimit Main Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __TZ_set_MSPLIM_NS(uint32_t MainStackPtrLimit) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + (void)MainStackPtrLimit; +#else + __ASM volatile ("MSR msplim_ns, %0" : : "r" (MainStackPtrLimit)); +#endif +} +#endif + +#endif /* ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) */ + /** \brief Get FPSCR \details Returns the current value of the Floating Point Status/Control register. \return Floating Point Status/Control register value */ -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_FPSCR(void) +__STATIC_FORCEINLINE uint32_t __get_FPSCR(void) { -#if (__FPU_PRESENT == 1U) && (__FPU_USED == 1U) +#if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ + (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) +#if __has_builtin(__builtin_arm_get_fpscr) +// Re-enable using built-in when GCC has been fixed +// || (__GNUC__ > 7) || (__GNUC__ == 7 && __GNUC_MINOR__ >= 2) + /* see https://gcc.gnu.org/ml/gcc-patches/2017-04/msg00443.html */ + return __builtin_arm_get_fpscr(); +#else uint32_t result; - /* Empty asm statement works as a scheduling barrier */ - __ASM volatile (""); __ASM volatile ("VMRS %0, fpscr" : "=r" (result) ); - __ASM volatile (""); return(result); +#endif #else - return(0); + return(0U); #endif } @@ -332,19 +789,23 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_FPSCR(void) \details Assigns the given value to the Floating Point Status/Control register. \param [in] fpscr Floating Point Status/Control value to set */ -__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_FPSCR(uint32_t fpscr) +__STATIC_FORCEINLINE void __set_FPSCR(uint32_t fpscr) { -#if (__FPU_PRESENT == 1U) && (__FPU_USED == 1U) - /* Empty asm statement works as a scheduling barrier */ - __ASM volatile (""); - __ASM volatile ("VMSR fpscr, %0" : : "r" (fpscr) : "vfpcc"); - __ASM volatile (""); +#if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ + (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) +#if __has_builtin(__builtin_arm_set_fpscr) +// Re-enable using built-in when GCC has been fixed +// || (__GNUC__ > 7) || (__GNUC__ == 7 && __GNUC_MINOR__ >= 2) + /* see https://gcc.gnu.org/ml/gcc-patches/2017-04/msg00443.html */ + __builtin_arm_set_fpscr(fpscr); +#else + __ASM volatile ("VMSR fpscr, %0" : : "r" (fpscr) : "vfpcc", "memory"); +#endif +#else + (void)fpscr; #endif } -#endif /* (__CORTEX_M == 0x04U) || (__CORTEX_M == 0x07U) */ - - /*@} end of CMSIS_Core_RegAccFunctions */ @@ -360,9 +821,11 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE void __set_FPSCR(uint32_t fps * Otherwise, use general registers, specified by constraint "r" */ #if defined (__thumb__) && !defined (__thumb2__) #define __CMSIS_GCC_OUT_REG(r) "=l" (r) +#define __CMSIS_GCC_RW_REG(r) "+l" (r) #define __CMSIS_GCC_USE_REG(r) "l" (r) #else #define __CMSIS_GCC_OUT_REG(r) "=r" (r) +#define __CMSIS_GCC_RW_REG(r) "+r" (r) #define __CMSIS_GCC_USE_REG(r) "r" (r) #endif @@ -370,41 +833,28 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE void __set_FPSCR(uint32_t fps \brief No Operation \details No Operation does nothing. This instruction can be used for code alignment purposes. */ -__attribute__((always_inline)) __STATIC_INLINE void __NOP(void) -{ - __ASM volatile ("nop"); -} - +#define __NOP() __ASM volatile ("nop") /** \brief Wait For Interrupt \details Wait For Interrupt is a hint instruction that suspends execution until one of a number of events occurs. */ -__attribute__((always_inline)) __STATIC_INLINE void __WFI(void) -{ - __ASM volatile ("wfi"); -} +#define __WFI() __ASM volatile ("wfi") /** \brief Wait For Event \details Wait For Event is a hint instruction that permits the processor to enter - a low-power state until one of a number of events occurs. + a low-power state until one of a number of events occurs. */ -__attribute__((always_inline)) __STATIC_INLINE void __WFE(void) -{ - __ASM volatile ("wfe"); -} +#define __WFE() __ASM volatile ("wfe") /** \brief Send Event \details Send Event is a hint instruction. It causes an event to be signaled to the CPU. */ -__attribute__((always_inline)) __STATIC_INLINE void __SEV(void) -{ - __ASM volatile ("sev"); -} +#define __SEV() __ASM volatile ("sev") /** @@ -413,7 +863,7 @@ __attribute__((always_inline)) __STATIC_INLINE void __SEV(void) so that all instructions following the ISB are fetched from cache or memory, after the instruction has been completed. */ -__attribute__((always_inline)) __STATIC_INLINE void __ISB(void) +__STATIC_FORCEINLINE void __ISB(void) { __ASM volatile ("isb 0xF":::"memory"); } @@ -424,7 +874,7 @@ __attribute__((always_inline)) __STATIC_INLINE void __ISB(void) \details Acts as a special kind of Data Memory Barrier. It completes when all explicit memory accesses before this instruction complete. */ -__attribute__((always_inline)) __STATIC_INLINE void __DSB(void) +__STATIC_FORCEINLINE void __DSB(void) { __ASM volatile ("dsb 0xF":::"memory"); } @@ -435,7 +885,7 @@ __attribute__((always_inline)) __STATIC_INLINE void __DSB(void) \details Ensures the apparent order of the explicit memory operations before and after the instruction, without ensuring their completion. */ -__attribute__((always_inline)) __STATIC_INLINE void __DMB(void) +__STATIC_FORCEINLINE void __DMB(void) { __ASM volatile ("dmb 0xF":::"memory"); } @@ -443,11 +893,11 @@ __attribute__((always_inline)) __STATIC_INLINE void __DMB(void) /** \brief Reverse byte order (32 bit) - \details Reverses the byte order in integer value. + \details Reverses the byte order in unsigned integer value. For example, 0x12345678 becomes 0x78563412. \param [in] value Value to reverse \return Reversed value */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __REV(uint32_t value) +__STATIC_FORCEINLINE uint32_t __REV(uint32_t value) { #if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) return __builtin_bswap32(value); @@ -455,41 +905,41 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __REV(uint32_t value) uint32_t result; __ASM volatile ("rev %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); - return(result); + return result; #endif } /** \brief Reverse byte order (16 bit) - \details Reverses the byte order in two unsigned short values. + \details Reverses the byte order within each halfword of a word. For example, 0x12345678 becomes 0x34127856. \param [in] value Value to reverse \return Reversed value */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __REV16(uint32_t value) +__STATIC_FORCEINLINE uint32_t __REV16(uint32_t value) { uint32_t result; __ASM volatile ("rev16 %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); - return(result); + return result; } /** - \brief Reverse byte order in signed short value - \details Reverses the byte order in a signed short value with sign extension to integer. + \brief Reverse byte order (16 bit) + \details Reverses the byte order in a 16-bit value and returns the signed 16-bit result. For example, 0x0080 becomes 0x8000. \param [in] value Value to reverse \return Reversed value */ -__attribute__((always_inline)) __STATIC_INLINE int32_t __REVSH(int32_t value) +__STATIC_FORCEINLINE int16_t __REVSH(int16_t value) { #if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) - return (short)__builtin_bswap16(value); + return (int16_t)__builtin_bswap16(value); #else - int32_t result; + int16_t result; __ASM volatile ("revsh %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); - return(result); + return result; #endif } @@ -497,12 +947,17 @@ __attribute__((always_inline)) __STATIC_INLINE int32_t __REVSH(int32_t value) /** \brief Rotate Right in unsigned value (32 bit) \details Rotate Right (immediate) provides the value of the contents of a register rotated by a variable number of bits. - \param [in] value Value to rotate - \param [in] value Number of Bits to rotate + \param [in] op1 Value to rotate + \param [in] op2 Number of Bits to rotate \return Rotated value */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __ROR(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __ROR(uint32_t op1, uint32_t op2) { + op2 %= 32U; + if (op2 == 0U) + { + return op1; + } return (op1 >> op2) | (op1 << (32U - op2)); } @@ -523,17 +978,19 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __ROR(uint32_t op1, uint \param [in] value Value to reverse \return Reversed value */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __RBIT(uint32_t value) +__STATIC_FORCEINLINE uint32_t __RBIT(uint32_t value) { uint32_t result; -#if (__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U) +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) __ASM volatile ("rbit %0, %1" : "=r" (result) : "r" (value) ); #else - int32_t s = 4 /*sizeof(v)*/ * 8 - 1; /* extra shift needed at end */ + uint32_t s = (4U /*sizeof(v)*/ * 8U) - 1U; /* extra shift needed at end */ result = value; /* r will be reversed bits of v; first get LSB of v */ - for (value >>= 1U; value; value >>= 1U) + for (value >>= 1U; value != 0U; value >>= 1U) { result <<= 1U; result |= value & 1U; @@ -541,7 +998,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __RBIT(uint32_t value) } result <<= s; /* shift when v's highest bits are zero */ #endif - return(result); + return result; } @@ -551,18 +1008,36 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __RBIT(uint32_t value) \param [in] value Value to count the leading zeros \return number of leading zeros in value */ -#define __CLZ __builtin_clz +__STATIC_FORCEINLINE uint8_t __CLZ(uint32_t value) +{ + /* Even though __builtin_clz produces a CLZ instruction on ARM, formally + __builtin_clz(0) is undefined behaviour, so handle this case specially. + This guarantees ARM-compatible results if happening to compile on a non-ARM + target, and ensures the compiler doesn't decide to activate any + optimisations using the logic "value was passed to __builtin_clz, so it + is non-zero". + ARM GCC 7.3 and possibly earlier will optimise this test away, leaving a + single CLZ instruction. + */ + if (value == 0U) + { + return 32U; + } + return __builtin_clz(value); +} -#if (__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U) - +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) /** \brief LDR Exclusive (8 bit) \details Executes a exclusive LDR instruction for 8 bit value. \param [in] ptr Pointer to data \return value of type uint8_t at (*ptr) */ -__attribute__((always_inline)) __STATIC_INLINE uint8_t __LDREXB(volatile uint8_t *addr) +__STATIC_FORCEINLINE uint8_t __LDREXB(volatile uint8_t *addr) { uint32_t result; @@ -584,7 +1059,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint8_t __LDREXB(volatile uint8_t \param [in] ptr Pointer to data \return value of type uint16_t at (*ptr) */ -__attribute__((always_inline)) __STATIC_INLINE uint16_t __LDREXH(volatile uint16_t *addr) +__STATIC_FORCEINLINE uint16_t __LDREXH(volatile uint16_t *addr) { uint32_t result; @@ -606,7 +1081,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint16_t __LDREXH(volatile uint16 \param [in] ptr Pointer to data \return value of type uint32_t at (*ptr) */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __LDREXW(volatile uint32_t *addr) +__STATIC_FORCEINLINE uint32_t __LDREXW(volatile uint32_t *addr) { uint32_t result; @@ -623,7 +1098,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __LDREXW(volatile uint32 \return 0 Function succeeded \return 1 Function failed */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __STREXB(uint8_t value, volatile uint8_t *addr) +__STATIC_FORCEINLINE uint32_t __STREXB(uint8_t value, volatile uint8_t *addr) { uint32_t result; @@ -640,7 +1115,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __STREXB(uint8_t value, \return 0 Function succeeded \return 1 Function failed */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __STREXH(uint16_t value, volatile uint16_t *addr) +__STATIC_FORCEINLINE uint32_t __STREXH(uint16_t value, volatile uint16_t *addr) { uint32_t result; @@ -657,7 +1132,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __STREXH(uint16_t value, \return 0 Function succeeded \return 1 Function failed */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __STREXW(uint32_t value, volatile uint32_t *addr) +__STATIC_FORCEINLINE uint32_t __STREXW(uint32_t value, volatile uint32_t *addr) { uint32_t result; @@ -670,22 +1145,31 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __STREXW(uint32_t value, \brief Remove the exclusive lock \details Removes the exclusive lock which is created by LDREX. */ -__attribute__((always_inline)) __STATIC_INLINE void __CLREX(void) +__STATIC_FORCEINLINE void __CLREX(void) { __ASM volatile ("clrex" ::: "memory"); } +#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) */ + +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) /** \brief Signed Saturate \details Saturates a signed value. - \param [in] value Value to be saturated - \param [in] sat Bit position to saturate to (1..32) + \param [in] ARG1 Value to be saturated + \param [in] ARG2 Bit position to saturate to (1..32) \return Saturated value */ #define __SSAT(ARG1,ARG2) \ +__extension__ \ ({ \ - uint32_t __RES, __ARG1 = (ARG1); \ + int32_t __RES, __ARG1 = (ARG1); \ __ASM ("ssat %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \ __RES; \ }) @@ -694,11 +1178,12 @@ __attribute__((always_inline)) __STATIC_INLINE void __CLREX(void) /** \brief Unsigned Saturate \details Saturates an unsigned value. - \param [in] value Value to be saturated - \param [in] sat Bit position to saturate to (0..31) + \param [in] ARG1 Value to be saturated + \param [in] ARG2 Bit position to saturate to (0..31) \return Saturated value */ #define __USAT(ARG1,ARG2) \ + __extension__ \ ({ \ uint32_t __RES, __ARG1 = (ARG1); \ __ASM ("usat %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \ @@ -713,7 +1198,7 @@ __attribute__((always_inline)) __STATIC_INLINE void __CLREX(void) \param [in] value Value to rotate \return Rotated value */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __RRX(uint32_t value) +__STATIC_FORCEINLINE uint32_t __RRX(uint32_t value) { uint32_t result; @@ -728,17 +1213,17 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __RRX(uint32_t value) \param [in] ptr Pointer to data \return value of type uint8_t at (*ptr) */ -__attribute__((always_inline)) __STATIC_INLINE uint8_t __LDRBT(volatile uint8_t *addr) +__STATIC_FORCEINLINE uint8_t __LDRBT(volatile uint8_t *ptr) { uint32_t result; #if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) - __ASM volatile ("ldrbt %0, %1" : "=r" (result) : "Q" (*addr) ); + __ASM volatile ("ldrbt %0, %1" : "=r" (result) : "Q" (*ptr) ); #else /* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not accepted by assembler. So has to use following less efficient pattern. */ - __ASM volatile ("ldrbt %0, [%1]" : "=r" (result) : "r" (addr) : "memory" ); + __ASM volatile ("ldrbt %0, [%1]" : "=r" (result) : "r" (ptr) : "memory" ); #endif return ((uint8_t) result); /* Add explicit type cast here */ } @@ -750,17 +1235,17 @@ __attribute__((always_inline)) __STATIC_INLINE uint8_t __LDRBT(volatile uint8_t \param [in] ptr Pointer to data \return value of type uint16_t at (*ptr) */ -__attribute__((always_inline)) __STATIC_INLINE uint16_t __LDRHT(volatile uint16_t *addr) +__STATIC_FORCEINLINE uint16_t __LDRHT(volatile uint16_t *ptr) { uint32_t result; #if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) - __ASM volatile ("ldrht %0, %1" : "=r" (result) : "Q" (*addr) ); + __ASM volatile ("ldrht %0, %1" : "=r" (result) : "Q" (*ptr) ); #else /* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not accepted by assembler. So has to use following less efficient pattern. */ - __ASM volatile ("ldrht %0, [%1]" : "=r" (result) : "r" (addr) : "memory" ); + __ASM volatile ("ldrht %0, [%1]" : "=r" (result) : "r" (ptr) : "memory" ); #endif return ((uint16_t) result); /* Add explicit type cast here */ } @@ -772,11 +1257,11 @@ __attribute__((always_inline)) __STATIC_INLINE uint16_t __LDRHT(volatile uint16_ \param [in] ptr Pointer to data \return value of type uint32_t at (*ptr) */ -__attribute__((always_inline)) __STATIC_INLINE uint32_t __LDRT(volatile uint32_t *addr) +__STATIC_FORCEINLINE uint32_t __LDRT(volatile uint32_t *ptr) { uint32_t result; - __ASM volatile ("ldrt %0, %1" : "=r" (result) : "Q" (*addr) ); + __ASM volatile ("ldrt %0, %1" : "=r" (result) : "Q" (*ptr) ); return(result); } @@ -787,9 +1272,9 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __LDRT(volatile uint32_t \param [in] value Value to store \param [in] ptr Pointer to location */ -__attribute__((always_inline)) __STATIC_INLINE void __STRBT(uint8_t value, volatile uint8_t *addr) +__STATIC_FORCEINLINE void __STRBT(uint8_t value, volatile uint8_t *ptr) { - __ASM volatile ("strbt %1, %0" : "=Q" (*addr) : "r" ((uint32_t)value) ); + __ASM volatile ("strbt %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); } @@ -799,9 +1284,9 @@ __attribute__((always_inline)) __STATIC_INLINE void __STRBT(uint8_t value, volat \param [in] value Value to store \param [in] ptr Pointer to location */ -__attribute__((always_inline)) __STATIC_INLINE void __STRHT(uint16_t value, volatile uint16_t *addr) +__STATIC_FORCEINLINE void __STRHT(uint16_t value, volatile uint16_t *ptr) { - __ASM volatile ("strht %1, %0" : "=Q" (*addr) : "r" ((uint32_t)value) ); + __ASM volatile ("strht %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); } @@ -811,12 +1296,249 @@ __attribute__((always_inline)) __STATIC_INLINE void __STRHT(uint16_t value, vola \param [in] value Value to store \param [in] ptr Pointer to location */ -__attribute__((always_inline)) __STATIC_INLINE void __STRT(uint32_t value, volatile uint32_t *addr) +__STATIC_FORCEINLINE void __STRT(uint32_t value, volatile uint32_t *ptr) { - __ASM volatile ("strt %1, %0" : "=Q" (*addr) : "r" (value) ); + __ASM volatile ("strt %1, %0" : "=Q" (*ptr) : "r" (value) ); } -#endif /* (__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U) */ +#else /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) */ + +/** + \brief Signed Saturate + \details Saturates a signed value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (1..32) + \return Saturated value + */ +__STATIC_FORCEINLINE int32_t __SSAT(int32_t val, uint32_t sat) +{ + if ((sat >= 1U) && (sat <= 32U)) + { + const int32_t max = (int32_t)((1U << (sat - 1U)) - 1U); + const int32_t min = -1 - max ; + if (val > max) + { + return max; + } + else if (val < min) + { + return min; + } + } + return val; +} + +/** + \brief Unsigned Saturate + \details Saturates an unsigned value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (0..31) + \return Saturated value + */ +__STATIC_FORCEINLINE uint32_t __USAT(int32_t val, uint32_t sat) +{ + if (sat <= 31U) + { + const uint32_t max = ((1U << sat) - 1U); + if (val > (int32_t)max) + { + return max; + } + else if (val < 0) + { + return 0U; + } + } + return (uint32_t)val; +} + +#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) */ + + +#if ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) +/** + \brief Load-Acquire (8 bit) + \details Executes a LDAB instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +__STATIC_FORCEINLINE uint8_t __LDAB(volatile uint8_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldab %0, %1" : "=r" (result) : "Q" (*ptr) ); + return ((uint8_t) result); +} + + +/** + \brief Load-Acquire (16 bit) + \details Executes a LDAH instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +__STATIC_FORCEINLINE uint16_t __LDAH(volatile uint16_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldah %0, %1" : "=r" (result) : "Q" (*ptr) ); + return ((uint16_t) result); +} + + +/** + \brief Load-Acquire (32 bit) + \details Executes a LDA instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +__STATIC_FORCEINLINE uint32_t __LDA(volatile uint32_t *ptr) +{ + uint32_t result; + + __ASM volatile ("lda %0, %1" : "=r" (result) : "Q" (*ptr) ); + return(result); +} + + +/** + \brief Store-Release (8 bit) + \details Executes a STLB instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STLB(uint8_t value, volatile uint8_t *ptr) +{ + __ASM volatile ("stlb %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); +} + + +/** + \brief Store-Release (16 bit) + \details Executes a STLH instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STLH(uint16_t value, volatile uint16_t *ptr) +{ + __ASM volatile ("stlh %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); +} + + +/** + \brief Store-Release (32 bit) + \details Executes a STL instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STL(uint32_t value, volatile uint32_t *ptr) +{ + __ASM volatile ("stl %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); +} + + +/** + \brief Load-Acquire Exclusive (8 bit) + \details Executes a LDAB exclusive instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +__STATIC_FORCEINLINE uint8_t __LDAEXB(volatile uint8_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldaexb %0, %1" : "=r" (result) : "Q" (*ptr) ); + return ((uint8_t) result); +} + + +/** + \brief Load-Acquire Exclusive (16 bit) + \details Executes a LDAH exclusive instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +__STATIC_FORCEINLINE uint16_t __LDAEXH(volatile uint16_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldaexh %0, %1" : "=r" (result) : "Q" (*ptr) ); + return ((uint16_t) result); +} + + +/** + \brief Load-Acquire Exclusive (32 bit) + \details Executes a LDA exclusive instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +__STATIC_FORCEINLINE uint32_t __LDAEX(volatile uint32_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldaex %0, %1" : "=r" (result) : "Q" (*ptr) ); + return(result); +} + + +/** + \brief Store-Release Exclusive (8 bit) + \details Executes a STLB exclusive instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +__STATIC_FORCEINLINE uint32_t __STLEXB(uint8_t value, volatile uint8_t *ptr) +{ + uint32_t result; + + __ASM volatile ("stlexb %0, %2, %1" : "=&r" (result), "=Q" (*ptr) : "r" ((uint32_t)value) ); + return(result); +} + + +/** + \brief Store-Release Exclusive (16 bit) + \details Executes a STLH exclusive instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +__STATIC_FORCEINLINE uint32_t __STLEXH(uint16_t value, volatile uint16_t *ptr) +{ + uint32_t result; + + __ASM volatile ("stlexh %0, %2, %1" : "=&r" (result), "=Q" (*ptr) : "r" ((uint32_t)value) ); + return(result); +} + + +/** + \brief Store-Release Exclusive (32 bit) + \details Executes a STL exclusive instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +__STATIC_FORCEINLINE uint32_t __STLEX(uint32_t value, volatile uint32_t *ptr) +{ + uint32_t result; + + __ASM volatile ("stlex %0, %2, %1" : "=&r" (result), "=Q" (*ptr) : "r" ((uint32_t)value) ); + return(result); +} + +#endif /* ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) */ /*@}*/ /* end of group CMSIS_Core_InstructionInterface */ @@ -827,9 +1549,9 @@ __attribute__((always_inline)) __STATIC_INLINE void __STRT(uint32_t value, volat @{ */ -#if (__CORTEX_M >= 0x04U) /* only for Cortex-M4 and above */ +#if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SADD8(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SADD8(uint32_t op1, uint32_t op2) { uint32_t result; @@ -837,7 +1559,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SADD8(uint32_t op1 return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __QADD8(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __QADD8(uint32_t op1, uint32_t op2) { uint32_t result; @@ -845,7 +1567,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __QADD8(uint32_t op1 return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SHADD8(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SHADD8(uint32_t op1, uint32_t op2) { uint32_t result; @@ -853,7 +1575,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SHADD8(uint32_t op return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UADD8(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UADD8(uint32_t op1, uint32_t op2) { uint32_t result; @@ -861,7 +1583,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UADD8(uint32_t op1 return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UQADD8(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UQADD8(uint32_t op1, uint32_t op2) { uint32_t result; @@ -869,7 +1591,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UQADD8(uint32_t op return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UHADD8(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UHADD8(uint32_t op1, uint32_t op2) { uint32_t result; @@ -878,7 +1600,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UHADD8(uint32_t op } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SSUB8(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SSUB8(uint32_t op1, uint32_t op2) { uint32_t result; @@ -886,7 +1608,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SSUB8(uint32_t op1 return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __QSUB8(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __QSUB8(uint32_t op1, uint32_t op2) { uint32_t result; @@ -894,7 +1616,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __QSUB8(uint32_t op1 return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SHSUB8(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SHSUB8(uint32_t op1, uint32_t op2) { uint32_t result; @@ -902,7 +1624,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SHSUB8(uint32_t op return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __USUB8(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __USUB8(uint32_t op1, uint32_t op2) { uint32_t result; @@ -910,7 +1632,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __USUB8(uint32_t op1 return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UQSUB8(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UQSUB8(uint32_t op1, uint32_t op2) { uint32_t result; @@ -918,7 +1640,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UQSUB8(uint32_t op return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UHSUB8(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UHSUB8(uint32_t op1, uint32_t op2) { uint32_t result; @@ -927,7 +1649,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UHSUB8(uint32_t op } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SADD16(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SADD16(uint32_t op1, uint32_t op2) { uint32_t result; @@ -935,7 +1657,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SADD16(uint32_t op return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __QADD16(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __QADD16(uint32_t op1, uint32_t op2) { uint32_t result; @@ -943,7 +1665,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __QADD16(uint32_t op return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SHADD16(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SHADD16(uint32_t op1, uint32_t op2) { uint32_t result; @@ -951,7 +1673,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SHADD16(uint32_t o return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UADD16(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UADD16(uint32_t op1, uint32_t op2) { uint32_t result; @@ -959,7 +1681,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UADD16(uint32_t op return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UQADD16(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UQADD16(uint32_t op1, uint32_t op2) { uint32_t result; @@ -967,7 +1689,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UQADD16(uint32_t o return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UHADD16(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UHADD16(uint32_t op1, uint32_t op2) { uint32_t result; @@ -975,7 +1697,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UHADD16(uint32_t o return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SSUB16(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SSUB16(uint32_t op1, uint32_t op2) { uint32_t result; @@ -983,7 +1705,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SSUB16(uint32_t op return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __QSUB16(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __QSUB16(uint32_t op1, uint32_t op2) { uint32_t result; @@ -991,7 +1713,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __QSUB16(uint32_t op return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SHSUB16(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SHSUB16(uint32_t op1, uint32_t op2) { uint32_t result; @@ -999,7 +1721,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SHSUB16(uint32_t o return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __USUB16(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __USUB16(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1007,7 +1729,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __USUB16(uint32_t op return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UQSUB16(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UQSUB16(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1015,7 +1737,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UQSUB16(uint32_t o return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UHSUB16(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UHSUB16(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1023,7 +1745,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UHSUB16(uint32_t o return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SASX(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SASX(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1031,7 +1753,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SASX(uint32_t op1, return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __QASX(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __QASX(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1039,7 +1761,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __QASX(uint32_t op1, return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SHASX(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SHASX(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1047,7 +1769,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SHASX(uint32_t op1 return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UASX(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UASX(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1055,7 +1777,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UASX(uint32_t op1, return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UQASX(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UQASX(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1063,7 +1785,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UQASX(uint32_t op1 return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UHASX(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UHASX(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1071,7 +1793,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UHASX(uint32_t op1 return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SSAX(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SSAX(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1079,7 +1801,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SSAX(uint32_t op1, return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __QSAX(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __QSAX(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1087,7 +1809,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __QSAX(uint32_t op1, return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SHSAX(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SHSAX(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1095,7 +1817,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SHSAX(uint32_t op1 return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __USAX(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __USAX(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1103,7 +1825,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __USAX(uint32_t op1, return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UQSAX(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UQSAX(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1111,7 +1833,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UQSAX(uint32_t op1 return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UHSAX(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UHSAX(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1119,7 +1841,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UHSAX(uint32_t op1 return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __USAD8(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __USAD8(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1127,7 +1849,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __USAD8(uint32_t op1 return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __USADA8(uint32_t op1, uint32_t op2, uint32_t op3) +__STATIC_FORCEINLINE uint32_t __USADA8(uint32_t op1, uint32_t op2, uint32_t op3) { uint32_t result; @@ -1149,7 +1871,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __USADA8(uint32_t op __RES; \ }) -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UXTB16(uint32_t op1) +__STATIC_FORCEINLINE uint32_t __UXTB16(uint32_t op1) { uint32_t result; @@ -1157,7 +1879,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UXTB16(uint32_t op return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UXTAB16(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __UXTAB16(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1165,7 +1887,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UXTAB16(uint32_t o return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SXTB16(uint32_t op1) +__STATIC_FORCEINLINE uint32_t __SXTB16(uint32_t op1) { uint32_t result; @@ -1173,7 +1895,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SXTB16(uint32_t op return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SXTAB16(uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SXTAB16(uint32_t op1, uint32_t op2) { uint32_t result; @@ -1181,7 +1903,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SXTAB16(uint32_t o return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMUAD (uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SMUAD (uint32_t op1, uint32_t op2) { uint32_t result; @@ -1189,7 +1911,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMUAD (uint32_t o return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMUADX (uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SMUADX (uint32_t op1, uint32_t op2) { uint32_t result; @@ -1197,7 +1919,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMUADX (uint32_t o return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMLAD (uint32_t op1, uint32_t op2, uint32_t op3) +__STATIC_FORCEINLINE uint32_t __SMLAD (uint32_t op1, uint32_t op2, uint32_t op3) { uint32_t result; @@ -1205,7 +1927,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMLAD (uint32_t op return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMLADX (uint32_t op1, uint32_t op2, uint32_t op3) +__STATIC_FORCEINLINE uint32_t __SMLADX (uint32_t op1, uint32_t op2, uint32_t op3) { uint32_t result; @@ -1213,7 +1935,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMLADX (uint32_t o return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint64_t __SMLALD (uint32_t op1, uint32_t op2, uint64_t acc) +__STATIC_FORCEINLINE uint64_t __SMLALD (uint32_t op1, uint32_t op2, uint64_t acc) { union llreg_u{ uint32_t w32[2]; @@ -1230,7 +1952,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint64_t __SMLALD (uint32_t o return(llr.w64); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint64_t __SMLALDX (uint32_t op1, uint32_t op2, uint64_t acc) +__STATIC_FORCEINLINE uint64_t __SMLALDX (uint32_t op1, uint32_t op2, uint64_t acc) { union llreg_u{ uint32_t w32[2]; @@ -1247,7 +1969,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint64_t __SMLALDX (uint32_t return(llr.w64); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMUSD (uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SMUSD (uint32_t op1, uint32_t op2) { uint32_t result; @@ -1255,7 +1977,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMUSD (uint32_t o return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMUSDX (uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SMUSDX (uint32_t op1, uint32_t op2) { uint32_t result; @@ -1263,7 +1985,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMUSDX (uint32_t o return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMLSD (uint32_t op1, uint32_t op2, uint32_t op3) +__STATIC_FORCEINLINE uint32_t __SMLSD (uint32_t op1, uint32_t op2, uint32_t op3) { uint32_t result; @@ -1271,7 +1993,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMLSD (uint32_t op return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMLSDX (uint32_t op1, uint32_t op2, uint32_t op3) +__STATIC_FORCEINLINE uint32_t __SMLSDX (uint32_t op1, uint32_t op2, uint32_t op3) { uint32_t result; @@ -1279,7 +2001,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMLSDX (uint32_t o return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint64_t __SMLSLD (uint32_t op1, uint32_t op2, uint64_t acc) +__STATIC_FORCEINLINE uint64_t __SMLSLD (uint32_t op1, uint32_t op2, uint64_t acc) { union llreg_u{ uint32_t w32[2]; @@ -1296,7 +2018,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint64_t __SMLSLD (uint32_t o return(llr.w64); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint64_t __SMLSLDX (uint32_t op1, uint32_t op2, uint64_t acc) +__STATIC_FORCEINLINE uint64_t __SMLSLDX (uint32_t op1, uint32_t op2, uint64_t acc) { union llreg_u{ uint32_t w32[2]; @@ -1313,7 +2035,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint64_t __SMLSLDX (uint32_t return(llr.w64); } -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SEL (uint32_t op1, uint32_t op2) +__STATIC_FORCEINLINE uint32_t __SEL (uint32_t op1, uint32_t op2) { uint32_t result; @@ -1321,7 +2043,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SEL (uint32_t op1 return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE int32_t __QADD( int32_t op1, int32_t op2) +__STATIC_FORCEINLINE int32_t __QADD( int32_t op1, int32_t op2) { int32_t result; @@ -1329,7 +2051,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE int32_t __QADD( int32_t op1, return(result); } -__attribute__( ( always_inline ) ) __STATIC_INLINE int32_t __QSUB( int32_t op1, int32_t op2) +__STATIC_FORCEINLINE int32_t __QSUB( int32_t op1, int32_t op2) { int32_t result; @@ -1337,6 +2059,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE int32_t __QSUB( int32_t op1, return(result); } +#if 0 #define __PKHBT(ARG1,ARG2,ARG3) \ ({ \ uint32_t __RES, __ARG1 = (ARG1), __ARG2 = (ARG2); \ @@ -1353,8 +2076,15 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE int32_t __QSUB( int32_t op1, __ASM ("pkhtb %0, %1, %2, asr %3" : "=r" (__RES) : "r" (__ARG1), "r" (__ARG2), "I" (ARG3) ); \ __RES; \ }) +#endif -__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMMLA (int32_t op1, int32_t op2, int32_t op3) +#define __PKHBT(ARG1,ARG2,ARG3) ( ((((uint32_t)(ARG1)) ) & 0x0000FFFFUL) | \ + ((((uint32_t)(ARG2)) << (ARG3)) & 0xFFFF0000UL) ) + +#define __PKHTB(ARG1,ARG2,ARG3) ( ((((uint32_t)(ARG1)) ) & 0xFFFF0000UL) | \ + ((((uint32_t)(ARG2)) >> (ARG3)) & 0x0000FFFFUL) ) + +__STATIC_FORCEINLINE int32_t __SMMLA (int32_t op1, int32_t op2, int32_t op3) { int32_t result; @@ -1362,12 +2092,10 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMMLA (int32_t op1 return(result); } -#endif /* (__CORTEX_M >= 0x04) */ +#endif /* (__ARM_FEATURE_DSP == 1) */ /*@} end of group CMSIS_SIMD_intrinsics */ -#if defined ( __GNUC__ ) #pragma GCC diagnostic pop -#endif #endif /* __CMSIS_GCC_H */ diff --git a/lib/cmsis/inc/cmsis_iccarm.h b/lib/cmsis/inc/cmsis_iccarm.h new file mode 100644 index 0000000000..20b50ce380 --- /dev/null +++ b/lib/cmsis/inc/cmsis_iccarm.h @@ -0,0 +1,940 @@ +/**************************************************************************//** + * @file cmsis_iccarm.h + * @brief CMSIS compiler ICCARM (IAR Compiler for Arm) header file + * @version V5.0.8 + * @date 04. September 2018 + ******************************************************************************/ + +//------------------------------------------------------------------------------ +// +// Copyright (c) 2017-2018 IAR Systems +// +// Licensed under the Apache License, Version 2.0 (the "License") +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//------------------------------------------------------------------------------ + + +#ifndef __CMSIS_ICCARM_H__ +#define __CMSIS_ICCARM_H__ + +#ifndef __ICCARM__ + #error This file should only be compiled by ICCARM +#endif + +#pragma system_include + +#define __IAR_FT _Pragma("inline=forced") __intrinsic + +#if (__VER__ >= 8000000) + #define __ICCARM_V8 1 +#else + #define __ICCARM_V8 0 +#endif + +#ifndef __ALIGNED + #if __ICCARM_V8 + #define __ALIGNED(x) __attribute__((aligned(x))) + #elif (__VER__ >= 7080000) + /* Needs IAR language extensions */ + #define __ALIGNED(x) __attribute__((aligned(x))) + #else + #warning No compiler specific solution for __ALIGNED.__ALIGNED is ignored. + #define __ALIGNED(x) + #endif +#endif + + +/* Define compiler macros for CPU architecture, used in CMSIS 5. + */ +#if __ARM_ARCH_6M__ || __ARM_ARCH_7M__ || __ARM_ARCH_7EM__ || __ARM_ARCH_8M_BASE__ || __ARM_ARCH_8M_MAIN__ +/* Macros already defined */ +#else + #if defined(__ARM8M_MAINLINE__) || defined(__ARM8EM_MAINLINE__) + #define __ARM_ARCH_8M_MAIN__ 1 + #elif defined(__ARM8M_BASELINE__) + #define __ARM_ARCH_8M_BASE__ 1 + #elif defined(__ARM_ARCH_PROFILE) && __ARM_ARCH_PROFILE == 'M' + #if __ARM_ARCH == 6 + #define __ARM_ARCH_6M__ 1 + #elif __ARM_ARCH == 7 + #if __ARM_FEATURE_DSP + #define __ARM_ARCH_7EM__ 1 + #else + #define __ARM_ARCH_7M__ 1 + #endif + #endif /* __ARM_ARCH */ + #endif /* __ARM_ARCH_PROFILE == 'M' */ +#endif + +/* Alternativ core deduction for older ICCARM's */ +#if !defined(__ARM_ARCH_6M__) && !defined(__ARM_ARCH_7M__) && !defined(__ARM_ARCH_7EM__) && \ + !defined(__ARM_ARCH_8M_BASE__) && !defined(__ARM_ARCH_8M_MAIN__) + #if defined(__ARM6M__) && (__CORE__ == __ARM6M__) + #define __ARM_ARCH_6M__ 1 + #elif defined(__ARM7M__) && (__CORE__ == __ARM7M__) + #define __ARM_ARCH_7M__ 1 + #elif defined(__ARM7EM__) && (__CORE__ == __ARM7EM__) + #define __ARM_ARCH_7EM__ 1 + #elif defined(__ARM8M_BASELINE__) && (__CORE == __ARM8M_BASELINE__) + #define __ARM_ARCH_8M_BASE__ 1 + #elif defined(__ARM8M_MAINLINE__) && (__CORE == __ARM8M_MAINLINE__) + #define __ARM_ARCH_8M_MAIN__ 1 + #elif defined(__ARM8EM_MAINLINE__) && (__CORE == __ARM8EM_MAINLINE__) + #define __ARM_ARCH_8M_MAIN__ 1 + #else + #error "Unknown target." + #endif +#endif + + + +#if defined(__ARM_ARCH_6M__) && __ARM_ARCH_6M__==1 + #define __IAR_M0_FAMILY 1 +#elif defined(__ARM_ARCH_8M_BASE__) && __ARM_ARCH_8M_BASE__==1 + #define __IAR_M0_FAMILY 1 +#else + #define __IAR_M0_FAMILY 0 +#endif + + +#ifndef __ASM + #define __ASM __asm +#endif + +#ifndef __INLINE + #define __INLINE inline +#endif + +#ifndef __NO_RETURN + #if __ICCARM_V8 + #define __NO_RETURN __attribute__((__noreturn__)) + #else + #define __NO_RETURN _Pragma("object_attribute=__noreturn") + #endif +#endif + +#ifndef __PACKED + #if __ICCARM_V8 + #define __PACKED __attribute__((packed, aligned(1))) + #else + /* Needs IAR language extensions */ + #define __PACKED __packed + #endif +#endif + +#ifndef __PACKED_STRUCT + #if __ICCARM_V8 + #define __PACKED_STRUCT struct __attribute__((packed, aligned(1))) + #else + /* Needs IAR language extensions */ + #define __PACKED_STRUCT __packed struct + #endif +#endif + +#ifndef __PACKED_UNION + #if __ICCARM_V8 + #define __PACKED_UNION union __attribute__((packed, aligned(1))) + #else + /* Needs IAR language extensions */ + #define __PACKED_UNION __packed union + #endif +#endif + +#ifndef __RESTRICT + #if __ICCARM_V8 + #define __RESTRICT __restrict + #else + /* Needs IAR language extensions */ + #define __RESTRICT restrict + #endif +#endif + +#ifndef __STATIC_INLINE + #define __STATIC_INLINE static inline +#endif + +#ifndef __FORCEINLINE + #define __FORCEINLINE _Pragma("inline=forced") +#endif + +#ifndef __STATIC_FORCEINLINE + #define __STATIC_FORCEINLINE __FORCEINLINE __STATIC_INLINE +#endif + +#ifndef __UNALIGNED_UINT16_READ +#pragma language=save +#pragma language=extended +__IAR_FT uint16_t __iar_uint16_read(void const *ptr) +{ + return *(__packed uint16_t*)(ptr); +} +#pragma language=restore +#define __UNALIGNED_UINT16_READ(PTR) __iar_uint16_read(PTR) +#endif + + +#ifndef __UNALIGNED_UINT16_WRITE +#pragma language=save +#pragma language=extended +__IAR_FT void __iar_uint16_write(void const *ptr, uint16_t val) +{ + *(__packed uint16_t*)(ptr) = val;; +} +#pragma language=restore +#define __UNALIGNED_UINT16_WRITE(PTR,VAL) __iar_uint16_write(PTR,VAL) +#endif + +#ifndef __UNALIGNED_UINT32_READ +#pragma language=save +#pragma language=extended +__IAR_FT uint32_t __iar_uint32_read(void const *ptr) +{ + return *(__packed uint32_t*)(ptr); +} +#pragma language=restore +#define __UNALIGNED_UINT32_READ(PTR) __iar_uint32_read(PTR) +#endif + +#ifndef __UNALIGNED_UINT32_WRITE +#pragma language=save +#pragma language=extended +__IAR_FT void __iar_uint32_write(void const *ptr, uint32_t val) +{ + *(__packed uint32_t*)(ptr) = val;; +} +#pragma language=restore +#define __UNALIGNED_UINT32_WRITE(PTR,VAL) __iar_uint32_write(PTR,VAL) +#endif + +#ifndef __UNALIGNED_UINT32 /* deprecated */ +#pragma language=save +#pragma language=extended +__packed struct __iar_u32 { uint32_t v; }; +#pragma language=restore +#define __UNALIGNED_UINT32(PTR) (((struct __iar_u32 *)(PTR))->v) +#endif + +#ifndef __USED + #if __ICCARM_V8 + #define __USED __attribute__((used)) + #else + #define __USED _Pragma("__root") + #endif +#endif + +#ifndef __WEAK + #if __ICCARM_V8 + #define __WEAK __attribute__((weak)) + #else + #define __WEAK _Pragma("__weak") + #endif +#endif + + +#ifndef __ICCARM_INTRINSICS_VERSION__ + #define __ICCARM_INTRINSICS_VERSION__ 0 +#endif + +#if __ICCARM_INTRINSICS_VERSION__ == 2 + + #if defined(__CLZ) + #undef __CLZ + #endif + #if defined(__REVSH) + #undef __REVSH + #endif + #if defined(__RBIT) + #undef __RBIT + #endif + #if defined(__SSAT) + #undef __SSAT + #endif + #if defined(__USAT) + #undef __USAT + #endif + + #include "iccarm_builtin.h" + + #define __disable_fault_irq __iar_builtin_disable_fiq + #define __disable_irq __iar_builtin_disable_interrupt + #define __enable_fault_irq __iar_builtin_enable_fiq + #define __enable_irq __iar_builtin_enable_interrupt + #define __arm_rsr __iar_builtin_rsr + #define __arm_wsr __iar_builtin_wsr + + + #define __get_APSR() (__arm_rsr("APSR")) + #define __get_BASEPRI() (__arm_rsr("BASEPRI")) + #define __get_CONTROL() (__arm_rsr("CONTROL")) + #define __get_FAULTMASK() (__arm_rsr("FAULTMASK")) + + #if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ + (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) + #define __get_FPSCR() (__arm_rsr("FPSCR")) + #define __set_FPSCR(VALUE) (__arm_wsr("FPSCR", (VALUE))) + #else + #define __get_FPSCR() ( 0 ) + #define __set_FPSCR(VALUE) ((void)VALUE) + #endif + + #define __get_IPSR() (__arm_rsr("IPSR")) + #define __get_MSP() (__arm_rsr("MSP")) + #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + #define __get_MSPLIM() (0U) + #else + #define __get_MSPLIM() (__arm_rsr("MSPLIM")) + #endif + #define __get_PRIMASK() (__arm_rsr("PRIMASK")) + #define __get_PSP() (__arm_rsr("PSP")) + + #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + #define __get_PSPLIM() (0U) + #else + #define __get_PSPLIM() (__arm_rsr("PSPLIM")) + #endif + + #define __get_xPSR() (__arm_rsr("xPSR")) + + #define __set_BASEPRI(VALUE) (__arm_wsr("BASEPRI", (VALUE))) + #define __set_BASEPRI_MAX(VALUE) (__arm_wsr("BASEPRI_MAX", (VALUE))) + #define __set_CONTROL(VALUE) (__arm_wsr("CONTROL", (VALUE))) + #define __set_FAULTMASK(VALUE) (__arm_wsr("FAULTMASK", (VALUE))) + #define __set_MSP(VALUE) (__arm_wsr("MSP", (VALUE))) + + #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + #define __set_MSPLIM(VALUE) ((void)(VALUE)) + #else + #define __set_MSPLIM(VALUE) (__arm_wsr("MSPLIM", (VALUE))) + #endif + #define __set_PRIMASK(VALUE) (__arm_wsr("PRIMASK", (VALUE))) + #define __set_PSP(VALUE) (__arm_wsr("PSP", (VALUE))) + #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + #define __set_PSPLIM(VALUE) ((void)(VALUE)) + #else + #define __set_PSPLIM(VALUE) (__arm_wsr("PSPLIM", (VALUE))) + #endif + + #define __TZ_get_CONTROL_NS() (__arm_rsr("CONTROL_NS")) + #define __TZ_set_CONTROL_NS(VALUE) (__arm_wsr("CONTROL_NS", (VALUE))) + #define __TZ_get_PSP_NS() (__arm_rsr("PSP_NS")) + #define __TZ_set_PSP_NS(VALUE) (__arm_wsr("PSP_NS", (VALUE))) + #define __TZ_get_MSP_NS() (__arm_rsr("MSP_NS")) + #define __TZ_set_MSP_NS(VALUE) (__arm_wsr("MSP_NS", (VALUE))) + #define __TZ_get_SP_NS() (__arm_rsr("SP_NS")) + #define __TZ_set_SP_NS(VALUE) (__arm_wsr("SP_NS", (VALUE))) + #define __TZ_get_PRIMASK_NS() (__arm_rsr("PRIMASK_NS")) + #define __TZ_set_PRIMASK_NS(VALUE) (__arm_wsr("PRIMASK_NS", (VALUE))) + #define __TZ_get_BASEPRI_NS() (__arm_rsr("BASEPRI_NS")) + #define __TZ_set_BASEPRI_NS(VALUE) (__arm_wsr("BASEPRI_NS", (VALUE))) + #define __TZ_get_FAULTMASK_NS() (__arm_rsr("FAULTMASK_NS")) + #define __TZ_set_FAULTMASK_NS(VALUE)(__arm_wsr("FAULTMASK_NS", (VALUE))) + + #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + #define __TZ_get_PSPLIM_NS() (0U) + #define __TZ_set_PSPLIM_NS(VALUE) ((void)(VALUE)) + #else + #define __TZ_get_PSPLIM_NS() (__arm_rsr("PSPLIM_NS")) + #define __TZ_set_PSPLIM_NS(VALUE) (__arm_wsr("PSPLIM_NS", (VALUE))) + #endif + + #define __TZ_get_MSPLIM_NS() (__arm_rsr("MSPLIM_NS")) + #define __TZ_set_MSPLIM_NS(VALUE) (__arm_wsr("MSPLIM_NS", (VALUE))) + + #define __NOP __iar_builtin_no_operation + + #define __CLZ __iar_builtin_CLZ + #define __CLREX __iar_builtin_CLREX + + #define __DMB __iar_builtin_DMB + #define __DSB __iar_builtin_DSB + #define __ISB __iar_builtin_ISB + + #define __LDREXB __iar_builtin_LDREXB + #define __LDREXH __iar_builtin_LDREXH + #define __LDREXW __iar_builtin_LDREX + + #define __RBIT __iar_builtin_RBIT + #define __REV __iar_builtin_REV + #define __REV16 __iar_builtin_REV16 + + __IAR_FT int16_t __REVSH(int16_t val) + { + return (int16_t) __iar_builtin_REVSH(val); + } + + #define __ROR __iar_builtin_ROR + #define __RRX __iar_builtin_RRX + + #define __SEV __iar_builtin_SEV + + #if !__IAR_M0_FAMILY + #define __SSAT __iar_builtin_SSAT + #endif + + #define __STREXB __iar_builtin_STREXB + #define __STREXH __iar_builtin_STREXH + #define __STREXW __iar_builtin_STREX + + #if !__IAR_M0_FAMILY + #define __USAT __iar_builtin_USAT + #endif + + #define __WFE __iar_builtin_WFE + #define __WFI __iar_builtin_WFI + + #if __ARM_MEDIA__ + #define __SADD8 __iar_builtin_SADD8 + #define __QADD8 __iar_builtin_QADD8 + #define __SHADD8 __iar_builtin_SHADD8 + #define __UADD8 __iar_builtin_UADD8 + #define __UQADD8 __iar_builtin_UQADD8 + #define __UHADD8 __iar_builtin_UHADD8 + #define __SSUB8 __iar_builtin_SSUB8 + #define __QSUB8 __iar_builtin_QSUB8 + #define __SHSUB8 __iar_builtin_SHSUB8 + #define __USUB8 __iar_builtin_USUB8 + #define __UQSUB8 __iar_builtin_UQSUB8 + #define __UHSUB8 __iar_builtin_UHSUB8 + #define __SADD16 __iar_builtin_SADD16 + #define __QADD16 __iar_builtin_QADD16 + #define __SHADD16 __iar_builtin_SHADD16 + #define __UADD16 __iar_builtin_UADD16 + #define __UQADD16 __iar_builtin_UQADD16 + #define __UHADD16 __iar_builtin_UHADD16 + #define __SSUB16 __iar_builtin_SSUB16 + #define __QSUB16 __iar_builtin_QSUB16 + #define __SHSUB16 __iar_builtin_SHSUB16 + #define __USUB16 __iar_builtin_USUB16 + #define __UQSUB16 __iar_builtin_UQSUB16 + #define __UHSUB16 __iar_builtin_UHSUB16 + #define __SASX __iar_builtin_SASX + #define __QASX __iar_builtin_QASX + #define __SHASX __iar_builtin_SHASX + #define __UASX __iar_builtin_UASX + #define __UQASX __iar_builtin_UQASX + #define __UHASX __iar_builtin_UHASX + #define __SSAX __iar_builtin_SSAX + #define __QSAX __iar_builtin_QSAX + #define __SHSAX __iar_builtin_SHSAX + #define __USAX __iar_builtin_USAX + #define __UQSAX __iar_builtin_UQSAX + #define __UHSAX __iar_builtin_UHSAX + #define __USAD8 __iar_builtin_USAD8 + #define __USADA8 __iar_builtin_USADA8 + #define __SSAT16 __iar_builtin_SSAT16 + #define __USAT16 __iar_builtin_USAT16 + #define __UXTB16 __iar_builtin_UXTB16 + #define __UXTAB16 __iar_builtin_UXTAB16 + #define __SXTB16 __iar_builtin_SXTB16 + #define __SXTAB16 __iar_builtin_SXTAB16 + #define __SMUAD __iar_builtin_SMUAD + #define __SMUADX __iar_builtin_SMUADX + #define __SMMLA __iar_builtin_SMMLA + #define __SMLAD __iar_builtin_SMLAD + #define __SMLADX __iar_builtin_SMLADX + #define __SMLALD __iar_builtin_SMLALD + #define __SMLALDX __iar_builtin_SMLALDX + #define __SMUSD __iar_builtin_SMUSD + #define __SMUSDX __iar_builtin_SMUSDX + #define __SMLSD __iar_builtin_SMLSD + #define __SMLSDX __iar_builtin_SMLSDX + #define __SMLSLD __iar_builtin_SMLSLD + #define __SMLSLDX __iar_builtin_SMLSLDX + #define __SEL __iar_builtin_SEL + #define __QADD __iar_builtin_QADD + #define __QSUB __iar_builtin_QSUB + #define __PKHBT __iar_builtin_PKHBT + #define __PKHTB __iar_builtin_PKHTB + #endif + +#else /* __ICCARM_INTRINSICS_VERSION__ == 2 */ + + #if __IAR_M0_FAMILY + /* Avoid clash between intrinsics.h and arm_math.h when compiling for Cortex-M0. */ + #define __CLZ __cmsis_iar_clz_not_active + #define __SSAT __cmsis_iar_ssat_not_active + #define __USAT __cmsis_iar_usat_not_active + #define __RBIT __cmsis_iar_rbit_not_active + #define __get_APSR __cmsis_iar_get_APSR_not_active + #endif + + + #if (!((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ + (defined (__FPU_USED ) && (__FPU_USED == 1U)) )) + #define __get_FPSCR __cmsis_iar_get_FPSR_not_active + #define __set_FPSCR __cmsis_iar_set_FPSR_not_active + #endif + + #ifdef __INTRINSICS_INCLUDED + #error intrinsics.h is already included previously! + #endif + + #include + + #if __IAR_M0_FAMILY + /* Avoid clash between intrinsics.h and arm_math.h when compiling for Cortex-M0. */ + #undef __CLZ + #undef __SSAT + #undef __USAT + #undef __RBIT + #undef __get_APSR + + __STATIC_INLINE uint8_t __CLZ(uint32_t data) + { + if (data == 0U) { return 32U; } + + uint32_t count = 0U; + uint32_t mask = 0x80000000U; + + while ((data & mask) == 0U) + { + count += 1U; + mask = mask >> 1U; + } + return count; + } + + __STATIC_INLINE uint32_t __RBIT(uint32_t v) + { + uint8_t sc = 31U; + uint32_t r = v; + for (v >>= 1U; v; v >>= 1U) + { + r <<= 1U; + r |= v & 1U; + sc--; + } + return (r << sc); + } + + __STATIC_INLINE uint32_t __get_APSR(void) + { + uint32_t res; + __asm("MRS %0,APSR" : "=r" (res)); + return res; + } + + #endif + + #if (!((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ + (defined (__FPU_USED ) && (__FPU_USED == 1U)) )) + #undef __get_FPSCR + #undef __set_FPSCR + #define __get_FPSCR() (0) + #define __set_FPSCR(VALUE) ((void)VALUE) + #endif + + #pragma diag_suppress=Pe940 + #pragma diag_suppress=Pe177 + + #define __enable_irq __enable_interrupt + #define __disable_irq __disable_interrupt + #define __NOP __no_operation + + #define __get_xPSR __get_PSR + + #if (!defined(__ARM_ARCH_6M__) || __ARM_ARCH_6M__==0) + + __IAR_FT uint32_t __LDREXW(uint32_t volatile *ptr) + { + return __LDREX((unsigned long *)ptr); + } + + __IAR_FT uint32_t __STREXW(uint32_t value, uint32_t volatile *ptr) + { + return __STREX(value, (unsigned long *)ptr); + } + #endif + + + /* __CORTEX_M is defined in core_cm0.h, core_cm3.h and core_cm4.h. */ + #if (__CORTEX_M >= 0x03) + + __IAR_FT uint32_t __RRX(uint32_t value) + { + uint32_t result; + __ASM("RRX %0, %1" : "=r"(result) : "r" (value) : "cc"); + return(result); + } + + __IAR_FT void __set_BASEPRI_MAX(uint32_t value) + { + __asm volatile("MSR BASEPRI_MAX,%0"::"r" (value)); + } + + + #define __enable_fault_irq __enable_fiq + #define __disable_fault_irq __disable_fiq + + + #endif /* (__CORTEX_M >= 0x03) */ + + __IAR_FT uint32_t __ROR(uint32_t op1, uint32_t op2) + { + return (op1 >> op2) | (op1 << ((sizeof(op1)*8)-op2)); + } + + #if ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) + + __IAR_FT uint32_t __get_MSPLIM(void) + { + uint32_t res; + #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE ) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + res = 0U; + #else + __asm volatile("MRS %0,MSPLIM" : "=r" (res)); + #endif + return res; + } + + __IAR_FT void __set_MSPLIM(uint32_t value) + { + #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE ) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + (void)value; + #else + __asm volatile("MSR MSPLIM,%0" :: "r" (value)); + #endif + } + + __IAR_FT uint32_t __get_PSPLIM(void) + { + uint32_t res; + #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE ) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + res = 0U; + #else + __asm volatile("MRS %0,PSPLIM" : "=r" (res)); + #endif + return res; + } + + __IAR_FT void __set_PSPLIM(uint32_t value) + { + #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE ) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + (void)value; + #else + __asm volatile("MSR PSPLIM,%0" :: "r" (value)); + #endif + } + + __IAR_FT uint32_t __TZ_get_CONTROL_NS(void) + { + uint32_t res; + __asm volatile("MRS %0,CONTROL_NS" : "=r" (res)); + return res; + } + + __IAR_FT void __TZ_set_CONTROL_NS(uint32_t value) + { + __asm volatile("MSR CONTROL_NS,%0" :: "r" (value)); + } + + __IAR_FT uint32_t __TZ_get_PSP_NS(void) + { + uint32_t res; + __asm volatile("MRS %0,PSP_NS" : "=r" (res)); + return res; + } + + __IAR_FT void __TZ_set_PSP_NS(uint32_t value) + { + __asm volatile("MSR PSP_NS,%0" :: "r" (value)); + } + + __IAR_FT uint32_t __TZ_get_MSP_NS(void) + { + uint32_t res; + __asm volatile("MRS %0,MSP_NS" : "=r" (res)); + return res; + } + + __IAR_FT void __TZ_set_MSP_NS(uint32_t value) + { + __asm volatile("MSR MSP_NS,%0" :: "r" (value)); + } + + __IAR_FT uint32_t __TZ_get_SP_NS(void) + { + uint32_t res; + __asm volatile("MRS %0,SP_NS" : "=r" (res)); + return res; + } + __IAR_FT void __TZ_set_SP_NS(uint32_t value) + { + __asm volatile("MSR SP_NS,%0" :: "r" (value)); + } + + __IAR_FT uint32_t __TZ_get_PRIMASK_NS(void) + { + uint32_t res; + __asm volatile("MRS %0,PRIMASK_NS" : "=r" (res)); + return res; + } + + __IAR_FT void __TZ_set_PRIMASK_NS(uint32_t value) + { + __asm volatile("MSR PRIMASK_NS,%0" :: "r" (value)); + } + + __IAR_FT uint32_t __TZ_get_BASEPRI_NS(void) + { + uint32_t res; + __asm volatile("MRS %0,BASEPRI_NS" : "=r" (res)); + return res; + } + + __IAR_FT void __TZ_set_BASEPRI_NS(uint32_t value) + { + __asm volatile("MSR BASEPRI_NS,%0" :: "r" (value)); + } + + __IAR_FT uint32_t __TZ_get_FAULTMASK_NS(void) + { + uint32_t res; + __asm volatile("MRS %0,FAULTMASK_NS" : "=r" (res)); + return res; + } + + __IAR_FT void __TZ_set_FAULTMASK_NS(uint32_t value) + { + __asm volatile("MSR FAULTMASK_NS,%0" :: "r" (value)); + } + + __IAR_FT uint32_t __TZ_get_PSPLIM_NS(void) + { + uint32_t res; + #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE ) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + res = 0U; + #else + __asm volatile("MRS %0,PSPLIM_NS" : "=r" (res)); + #endif + return res; + } + + __IAR_FT void __TZ_set_PSPLIM_NS(uint32_t value) + { + #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE ) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + (void)value; + #else + __asm volatile("MSR PSPLIM_NS,%0" :: "r" (value)); + #endif + } + + __IAR_FT uint32_t __TZ_get_MSPLIM_NS(void) + { + uint32_t res; + __asm volatile("MRS %0,MSPLIM_NS" : "=r" (res)); + return res; + } + + __IAR_FT void __TZ_set_MSPLIM_NS(uint32_t value) + { + __asm volatile("MSR MSPLIM_NS,%0" :: "r" (value)); + } + + #endif /* __ARM_ARCH_8M_MAIN__ or __ARM_ARCH_8M_BASE__ */ + +#endif /* __ICCARM_INTRINSICS_VERSION__ == 2 */ + +#define __BKPT(value) __asm volatile ("BKPT %0" : : "i"(value)) + +#if __IAR_M0_FAMILY + __STATIC_INLINE int32_t __SSAT(int32_t val, uint32_t sat) + { + if ((sat >= 1U) && (sat <= 32U)) + { + const int32_t max = (int32_t)((1U << (sat - 1U)) - 1U); + const int32_t min = -1 - max ; + if (val > max) + { + return max; + } + else if (val < min) + { + return min; + } + } + return val; + } + + __STATIC_INLINE uint32_t __USAT(int32_t val, uint32_t sat) + { + if (sat <= 31U) + { + const uint32_t max = ((1U << sat) - 1U); + if (val > (int32_t)max) + { + return max; + } + else if (val < 0) + { + return 0U; + } + } + return (uint32_t)val; + } +#endif + +#if (__CORTEX_M >= 0x03) /* __CORTEX_M is defined in core_cm0.h, core_cm3.h and core_cm4.h. */ + + __IAR_FT uint8_t __LDRBT(volatile uint8_t *addr) + { + uint32_t res; + __ASM("LDRBT %0, [%1]" : "=r" (res) : "r" (addr) : "memory"); + return ((uint8_t)res); + } + + __IAR_FT uint16_t __LDRHT(volatile uint16_t *addr) + { + uint32_t res; + __ASM("LDRHT %0, [%1]" : "=r" (res) : "r" (addr) : "memory"); + return ((uint16_t)res); + } + + __IAR_FT uint32_t __LDRT(volatile uint32_t *addr) + { + uint32_t res; + __ASM("LDRT %0, [%1]" : "=r" (res) : "r" (addr) : "memory"); + return res; + } + + __IAR_FT void __STRBT(uint8_t value, volatile uint8_t *addr) + { + __ASM("STRBT %1, [%0]" : : "r" (addr), "r" ((uint32_t)value) : "memory"); + } + + __IAR_FT void __STRHT(uint16_t value, volatile uint16_t *addr) + { + __ASM("STRHT %1, [%0]" : : "r" (addr), "r" ((uint32_t)value) : "memory"); + } + + __IAR_FT void __STRT(uint32_t value, volatile uint32_t *addr) + { + __ASM("STRT %1, [%0]" : : "r" (addr), "r" (value) : "memory"); + } + +#endif /* (__CORTEX_M >= 0x03) */ + +#if ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) + + + __IAR_FT uint8_t __LDAB(volatile uint8_t *ptr) + { + uint32_t res; + __ASM volatile ("LDAB %0, [%1]" : "=r" (res) : "r" (ptr) : "memory"); + return ((uint8_t)res); + } + + __IAR_FT uint16_t __LDAH(volatile uint16_t *ptr) + { + uint32_t res; + __ASM volatile ("LDAH %0, [%1]" : "=r" (res) : "r" (ptr) : "memory"); + return ((uint16_t)res); + } + + __IAR_FT uint32_t __LDA(volatile uint32_t *ptr) + { + uint32_t res; + __ASM volatile ("LDA %0, [%1]" : "=r" (res) : "r" (ptr) : "memory"); + return res; + } + + __IAR_FT void __STLB(uint8_t value, volatile uint8_t *ptr) + { + __ASM volatile ("STLB %1, [%0]" :: "r" (ptr), "r" (value) : "memory"); + } + + __IAR_FT void __STLH(uint16_t value, volatile uint16_t *ptr) + { + __ASM volatile ("STLH %1, [%0]" :: "r" (ptr), "r" (value) : "memory"); + } + + __IAR_FT void __STL(uint32_t value, volatile uint32_t *ptr) + { + __ASM volatile ("STL %1, [%0]" :: "r" (ptr), "r" (value) : "memory"); + } + + __IAR_FT uint8_t __LDAEXB(volatile uint8_t *ptr) + { + uint32_t res; + __ASM volatile ("LDAEXB %0, [%1]" : "=r" (res) : "r" (ptr) : "memory"); + return ((uint8_t)res); + } + + __IAR_FT uint16_t __LDAEXH(volatile uint16_t *ptr) + { + uint32_t res; + __ASM volatile ("LDAEXH %0, [%1]" : "=r" (res) : "r" (ptr) : "memory"); + return ((uint16_t)res); + } + + __IAR_FT uint32_t __LDAEX(volatile uint32_t *ptr) + { + uint32_t res; + __ASM volatile ("LDAEX %0, [%1]" : "=r" (res) : "r" (ptr) : "memory"); + return res; + } + + __IAR_FT uint32_t __STLEXB(uint8_t value, volatile uint8_t *ptr) + { + uint32_t res; + __ASM volatile ("STLEXB %0, %2, [%1]" : "=r" (res) : "r" (ptr), "r" (value) : "memory"); + return res; + } + + __IAR_FT uint32_t __STLEXH(uint16_t value, volatile uint16_t *ptr) + { + uint32_t res; + __ASM volatile ("STLEXH %0, %2, [%1]" : "=r" (res) : "r" (ptr), "r" (value) : "memory"); + return res; + } + + __IAR_FT uint32_t __STLEX(uint32_t value, volatile uint32_t *ptr) + { + uint32_t res; + __ASM volatile ("STLEX %0, %2, [%1]" : "=r" (res) : "r" (ptr), "r" (value) : "memory"); + return res; + } + +#endif /* __ARM_ARCH_8M_MAIN__ or __ARM_ARCH_8M_BASE__ */ + +#undef __IAR_FT +#undef __IAR_M0_FAMILY +#undef __ICCARM_V8 + +#pragma diag_default=Pe940 +#pragma diag_default=Pe177 + +#endif /* __CMSIS_ICCARM_H__ */ diff --git a/lib/cmsis/inc/cmsis_version.h b/lib/cmsis/inc/cmsis_version.h new file mode 100644 index 0000000000..660f612aa3 --- /dev/null +++ b/lib/cmsis/inc/cmsis_version.h @@ -0,0 +1,39 @@ +/**************************************************************************//** + * @file cmsis_version.h + * @brief CMSIS Core(M) Version definitions + * @version V5.0.2 + * @date 19. April 2017 + ******************************************************************************/ +/* + * Copyright (c) 2009-2017 ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined (__clang__) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef __CMSIS_VERSION_H +#define __CMSIS_VERSION_H + +/* CMSIS Version definitions */ +#define __CM_CMSIS_VERSION_MAIN ( 5U) /*!< [31:16] CMSIS Core(M) main version */ +#define __CM_CMSIS_VERSION_SUB ( 1U) /*!< [15:0] CMSIS Core(M) sub version */ +#define __CM_CMSIS_VERSION ((__CM_CMSIS_VERSION_MAIN << 16U) | \ + __CM_CMSIS_VERSION_SUB ) /*!< CMSIS Core(M) version number */ +#endif diff --git a/lib/cmsis/inc/core_armv81mml.h b/lib/cmsis/inc/core_armv81mml.h new file mode 100644 index 0000000000..db6d9f2363 --- /dev/null +++ b/lib/cmsis/inc/core_armv81mml.h @@ -0,0 +1,2967 @@ +/**************************************************************************//** + * @file core_armv81mml.h + * @brief CMSIS Armv8.1-M Mainline Core Peripheral Access Layer Header File + * @version V1.0.0 + * @date 15. March 2019 + ******************************************************************************/ +/* + * Copyright (c) 2018-2019 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined (__clang__) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef __CORE_ARMV81MML_H_GENERIC +#define __CORE_ARMV81MML_H_GENERIC + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/** + \page CMSIS_MISRA_Exceptions MISRA-C:2004 Compliance Exceptions + CMSIS violates the following MISRA-C:2004 rules: + + \li Required Rule 8.5, object/function definition in header file.
+ Function definitions in header files are used to allow 'inlining'. + + \li Required Rule 18.4, declaration of union type or object of union type: '{...}'.
+ Unions are used for effective representation of core registers. + + \li Advisory Rule 19.7, Function-like macro defined.
+ Function-like macros are used to allow more efficient code. + */ + + +/******************************************************************************* + * CMSIS definitions + ******************************************************************************/ +/** + \ingroup Cortex_ARMV81MML + @{ + */ + +#include "cmsis_version.h" + +#define __ARM_ARCH_8M_MAIN__ 1 // patching for now +/* CMSIS ARMV81MML definitions */ +#define __ARMv81MML_CMSIS_VERSION_MAIN (__CM_CMSIS_VERSION_MAIN) /*!< \deprecated [31:16] CMSIS HAL main version */ +#define __ARMv81MML_CMSIS_VERSION_SUB (__CM_CMSIS_VERSION_SUB) /*!< \deprecated [15:0] CMSIS HAL sub version */ +#define __ARMv81MML_CMSIS_VERSION ((__ARMv81MML_CMSIS_VERSION_MAIN << 16U) | \ + __ARMv81MML_CMSIS_VERSION_SUB ) /*!< \deprecated CMSIS HAL version number */ + +#define __CORTEX_M (81U) /*!< Cortex-M Core */ + +/** __FPU_USED indicates whether an FPU is used or not. + For this, __FPU_PRESENT has to be checked prior to making use of FPU specific registers and functions. +*/ +#if defined ( __CC_ARM ) + #if defined __TARGET_FPU_VFP + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + + #if defined(__ARM_FEATURE_DSP) + #if defined(__DSP_PRESENT) && (__DSP_PRESENT == 1U) + #define __DSP_USED 1U + #else + #error "Compiler generates DSP (SIMD) instructions for a devices without DSP extensions (check __DSP_PRESENT)" + #define __DSP_USED 0U + #endif + #else + #define __DSP_USED 0U + #endif + +#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #if defined __ARM_FP + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #warning "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + + #if defined(__ARM_FEATURE_DSP) + #if defined(__DSP_PRESENT) && (__DSP_PRESENT == 1U) + #define __DSP_USED 1U + #else + #error "Compiler generates DSP (SIMD) instructions for a devices without DSP extensions (check __DSP_PRESENT)" + #define __DSP_USED 0U + #endif + #else + #define __DSP_USED 0U + #endif + +#elif defined ( __GNUC__ ) + #if defined (__VFP_FP__) && !defined(__SOFTFP__) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + + #if defined(__ARM_FEATURE_DSP) + #if defined(__DSP_PRESENT) && (__DSP_PRESENT == 1U) + #define __DSP_USED 1U + #else + #error "Compiler generates DSP (SIMD) instructions for a devices without DSP extensions (check __DSP_PRESENT)" + #define __DSP_USED 0U + #endif + #else + #define __DSP_USED 0U + #endif + +#elif defined ( __ICCARM__ ) + #if defined __ARMVFP__ + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + + #if defined(__ARM_FEATURE_DSP) + #if defined(__DSP_PRESENT) && (__DSP_PRESENT == 1U) + #define __DSP_USED 1U + #else + #error "Compiler generates DSP (SIMD) instructions for a devices without DSP extensions (check __DSP_PRESENT)" + #define __DSP_USED 0U + #endif + #else + #define __DSP_USED 0U + #endif + +#elif defined ( __TI_ARM__ ) + #if defined __TI_VFP_SUPPORT__ + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#elif defined ( __TASKING__ ) + #if defined __FPU_VFP__ + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#elif defined ( __CSMC__ ) + #if ( __CSMC__ & 0x400U) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#endif + +#include "cmsis_compiler.h" /* CMSIS compiler specific defines */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_ARMV81MML_H_GENERIC */ + +#ifndef __CMSIS_GENERIC + +#ifndef __CORE_ARMV81MML_H_DEPENDANT +#define __CORE_ARMV81MML_H_DEPENDANT + +#ifdef __cplusplus + extern "C" { +#endif + +/* check device defines and use defaults */ +#if defined __CHECK_DEVICE_DEFINES + #ifndef __ARMv81MML_REV + #define __ARMv81MML_REV 0x0000U + #warning "__ARMv81MML_REV not defined in device header file; using default!" + #endif + + #ifndef __FPU_PRESENT + #define __FPU_PRESENT 0U + #warning "__FPU_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __MPU_PRESENT + #define __MPU_PRESENT 0U + #warning "__MPU_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __SAUREGION_PRESENT + #define __SAUREGION_PRESENT 0U + #warning "__SAUREGION_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __DSP_PRESENT + #define __DSP_PRESENT 0U + #warning "__DSP_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __NVIC_PRIO_BITS + #define __NVIC_PRIO_BITS 3U + #warning "__NVIC_PRIO_BITS not defined in device header file; using default!" + #endif + + #ifndef __Vendor_SysTickConfig + #define __Vendor_SysTickConfig 0U + #warning "__Vendor_SysTickConfig not defined in device header file; using default!" + #endif +#endif + +/* IO definitions (access restrictions to peripheral registers) */ +/** + \defgroup CMSIS_glob_defs CMSIS Global Defines + + IO Type Qualifiers are used + \li to specify the access to peripheral variables. + \li for automatic generation of peripheral register debug information. +*/ +#ifdef __cplusplus + #define __I volatile /*!< Defines 'read only' permissions */ +#else + #define __I volatile const /*!< Defines 'read only' permissions */ +#endif +#define __O volatile /*!< Defines 'write only' permissions */ +#define __IO volatile /*!< Defines 'read / write' permissions */ + +/* following defines should be used for structure members */ +#define __IM volatile const /*! Defines 'read only' structure member permissions */ +#define __OM volatile /*! Defines 'write only' structure member permissions */ +#define __IOM volatile /*! Defines 'read / write' structure member permissions */ + +/*@} end of group ARMv81MML */ + + + +/******************************************************************************* + * Register Abstraction + Core Register contain: + - Core Register + - Core NVIC Register + - Core SCB Register + - Core SysTick Register + - Core Debug Register + - Core MPU Register + - Core SAU Register + - Core FPU Register + ******************************************************************************/ +/** + \defgroup CMSIS_core_register Defines and Type Definitions + \brief Type definitions and defines for Cortex-M processor based devices. +*/ + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CORE Status and Control Registers + \brief Core Register type definitions. + @{ + */ + +/** + \brief Union type to access the Application Program Status Register (APSR). + */ +typedef union +{ + struct + { + uint32_t _reserved0:16; /*!< bit: 0..15 Reserved */ + uint32_t GE:4; /*!< bit: 16..19 Greater than or Equal flags */ + uint32_t _reserved1:7; /*!< bit: 20..26 Reserved */ + uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} APSR_Type; + +/* APSR Register Definitions */ +#define APSR_N_Pos 31U /*!< APSR: N Position */ +#define APSR_N_Msk (1UL << APSR_N_Pos) /*!< APSR: N Mask */ + +#define APSR_Z_Pos 30U /*!< APSR: Z Position */ +#define APSR_Z_Msk (1UL << APSR_Z_Pos) /*!< APSR: Z Mask */ + +#define APSR_C_Pos 29U /*!< APSR: C Position */ +#define APSR_C_Msk (1UL << APSR_C_Pos) /*!< APSR: C Mask */ + +#define APSR_V_Pos 28U /*!< APSR: V Position */ +#define APSR_V_Msk (1UL << APSR_V_Pos) /*!< APSR: V Mask */ + +#define APSR_Q_Pos 27U /*!< APSR: Q Position */ +#define APSR_Q_Msk (1UL << APSR_Q_Pos) /*!< APSR: Q Mask */ + +#define APSR_GE_Pos 16U /*!< APSR: GE Position */ +#define APSR_GE_Msk (0xFUL << APSR_GE_Pos) /*!< APSR: GE Mask */ + + +/** + \brief Union type to access the Interrupt Program Status Register (IPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:23; /*!< bit: 9..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} IPSR_Type; + +/* IPSR Register Definitions */ +#define IPSR_ISR_Pos 0U /*!< IPSR: ISR Position */ +#define IPSR_ISR_Msk (0x1FFUL /*<< IPSR_ISR_Pos*/) /*!< IPSR: ISR Mask */ + + +/** + \brief Union type to access the Special-Purpose Program Status Registers (xPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:7; /*!< bit: 9..15 Reserved */ + uint32_t GE:4; /*!< bit: 16..19 Greater than or Equal flags */ + uint32_t _reserved1:4; /*!< bit: 20..23 Reserved */ + uint32_t T:1; /*!< bit: 24 Thumb bit (read 0) */ + uint32_t IT:2; /*!< bit: 25..26 saved IT state (read 0) */ + uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} xPSR_Type; + +/* xPSR Register Definitions */ +#define xPSR_N_Pos 31U /*!< xPSR: N Position */ +#define xPSR_N_Msk (1UL << xPSR_N_Pos) /*!< xPSR: N Mask */ + +#define xPSR_Z_Pos 30U /*!< xPSR: Z Position */ +#define xPSR_Z_Msk (1UL << xPSR_Z_Pos) /*!< xPSR: Z Mask */ + +#define xPSR_C_Pos 29U /*!< xPSR: C Position */ +#define xPSR_C_Msk (1UL << xPSR_C_Pos) /*!< xPSR: C Mask */ + +#define xPSR_V_Pos 28U /*!< xPSR: V Position */ +#define xPSR_V_Msk (1UL << xPSR_V_Pos) /*!< xPSR: V Mask */ + +#define xPSR_Q_Pos 27U /*!< xPSR: Q Position */ +#define xPSR_Q_Msk (1UL << xPSR_Q_Pos) /*!< xPSR: Q Mask */ + +#define xPSR_IT_Pos 25U /*!< xPSR: IT Position */ +#define xPSR_IT_Msk (3UL << xPSR_IT_Pos) /*!< xPSR: IT Mask */ + +#define xPSR_T_Pos 24U /*!< xPSR: T Position */ +#define xPSR_T_Msk (1UL << xPSR_T_Pos) /*!< xPSR: T Mask */ + +#define xPSR_GE_Pos 16U /*!< xPSR: GE Position */ +#define xPSR_GE_Msk (0xFUL << xPSR_GE_Pos) /*!< xPSR: GE Mask */ + +#define xPSR_ISR_Pos 0U /*!< xPSR: ISR Position */ +#define xPSR_ISR_Msk (0x1FFUL /*<< xPSR_ISR_Pos*/) /*!< xPSR: ISR Mask */ + + +/** + \brief Union type to access the Control Registers (CONTROL). + */ +typedef union +{ + struct + { + uint32_t nPRIV:1; /*!< bit: 0 Execution privilege in Thread mode */ + uint32_t SPSEL:1; /*!< bit: 1 Stack-pointer select */ + uint32_t FPCA:1; /*!< bit: 2 Floating-point context active */ + uint32_t SFPA:1; /*!< bit: 3 Secure floating-point active */ + uint32_t _reserved1:28; /*!< bit: 4..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} CONTROL_Type; + +/* CONTROL Register Definitions */ +#define CONTROL_SFPA_Pos 3U /*!< CONTROL: SFPA Position */ +#define CONTROL_SFPA_Msk (1UL << CONTROL_SFPA_Pos) /*!< CONTROL: SFPA Mask */ + +#define CONTROL_FPCA_Pos 2U /*!< CONTROL: FPCA Position */ +#define CONTROL_FPCA_Msk (1UL << CONTROL_FPCA_Pos) /*!< CONTROL: FPCA Mask */ + +#define CONTROL_SPSEL_Pos 1U /*!< CONTROL: SPSEL Position */ +#define CONTROL_SPSEL_Msk (1UL << CONTROL_SPSEL_Pos) /*!< CONTROL: SPSEL Mask */ + +#define CONTROL_nPRIV_Pos 0U /*!< CONTROL: nPRIV Position */ +#define CONTROL_nPRIV_Msk (1UL /*<< CONTROL_nPRIV_Pos*/) /*!< CONTROL: nPRIV Mask */ + +/*@} end of group CMSIS_CORE */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_NVIC Nested Vectored Interrupt Controller (NVIC) + \brief Type definitions for the NVIC Registers + @{ + */ + +/** + \brief Structure type to access the Nested Vectored Interrupt Controller (NVIC). + */ +typedef struct +{ + __IOM uint32_t ISER[16U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ + uint32_t RESERVED0[16U]; + __IOM uint32_t ICER[16U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ + uint32_t RSERVED1[16U]; + __IOM uint32_t ISPR[16U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ + uint32_t RESERVED2[16U]; + __IOM uint32_t ICPR[16U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ + uint32_t RESERVED3[16U]; + __IOM uint32_t IABR[16U]; /*!< Offset: 0x200 (R/W) Interrupt Active bit Register */ + uint32_t RESERVED4[16U]; + __IOM uint32_t ITNS[16U]; /*!< Offset: 0x280 (R/W) Interrupt Non-Secure State Register */ + uint32_t RESERVED5[16U]; + __IOM uint8_t IPR[496U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register (8Bit wide) */ + uint32_t RESERVED6[580U]; + __OM uint32_t STIR; /*!< Offset: 0xE00 ( /W) Software Trigger Interrupt Register */ +} NVIC_Type; + +/* Software Triggered Interrupt Register Definitions */ +#define NVIC_STIR_INTID_Pos 0U /*!< STIR: INTLINESNUM Position */ +#define NVIC_STIR_INTID_Msk (0x1FFUL /*<< NVIC_STIR_INTID_Pos*/) /*!< STIR: INTLINESNUM Mask */ + +/*@} end of group CMSIS_NVIC */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SCB System Control Block (SCB) + \brief Type definitions for the System Control Block Registers + @{ + */ + +/** + \brief Structure type to access the System Control Block (SCB). + */ +typedef struct +{ + __IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */ + __IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */ + __IOM uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */ + __IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */ + __IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */ + __IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */ + __IOM uint8_t SHPR[12U]; /*!< Offset: 0x018 (R/W) System Handlers Priority Registers (4-7, 8-11, 12-15) */ + __IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */ + __IOM uint32_t CFSR; /*!< Offset: 0x028 (R/W) Configurable Fault Status Register */ + __IOM uint32_t HFSR; /*!< Offset: 0x02C (R/W) HardFault Status Register */ + __IOM uint32_t DFSR; /*!< Offset: 0x030 (R/W) Debug Fault Status Register */ + __IOM uint32_t MMFAR; /*!< Offset: 0x034 (R/W) MemManage Fault Address Register */ + __IOM uint32_t BFAR; /*!< Offset: 0x038 (R/W) BusFault Address Register */ + __IOM uint32_t AFSR; /*!< Offset: 0x03C (R/W) Auxiliary Fault Status Register */ + __IM uint32_t ID_PFR[2U]; /*!< Offset: 0x040 (R/ ) Processor Feature Register */ + __IM uint32_t ID_DFR; /*!< Offset: 0x048 (R/ ) Debug Feature Register */ + __IM uint32_t ID_ADR; /*!< Offset: 0x04C (R/ ) Auxiliary Feature Register */ + __IM uint32_t ID_MMFR[4U]; /*!< Offset: 0x050 (R/ ) Memory Model Feature Register */ + __IM uint32_t ID_ISAR[6U]; /*!< Offset: 0x060 (R/ ) Instruction Set Attributes Register */ + __IM uint32_t CLIDR; /*!< Offset: 0x078 (R/ ) Cache Level ID register */ + __IM uint32_t CTR; /*!< Offset: 0x07C (R/ ) Cache Type register */ + __IM uint32_t CCSIDR; /*!< Offset: 0x080 (R/ ) Cache Size ID Register */ + __IOM uint32_t CSSELR; /*!< Offset: 0x084 (R/W) Cache Size Selection Register */ + __IOM uint32_t CPACR; /*!< Offset: 0x088 (R/W) Coprocessor Access Control Register */ + __IOM uint32_t NSACR; /*!< Offset: 0x08C (R/W) Non-Secure Access Control Register */ + uint32_t RESERVED3[92U]; + __OM uint32_t STIR; /*!< Offset: 0x200 ( /W) Software Triggered Interrupt Register */ + uint32_t RESERVED4[15U]; + __IM uint32_t MVFR0; /*!< Offset: 0x240 (R/ ) Media and VFP Feature Register 0 */ + __IM uint32_t MVFR1; /*!< Offset: 0x244 (R/ ) Media and VFP Feature Register 1 */ + __IM uint32_t MVFR2; /*!< Offset: 0x248 (R/ ) Media and VFP Feature Register 2 */ + uint32_t RESERVED5[1U]; + __OM uint32_t ICIALLU; /*!< Offset: 0x250 ( /W) I-Cache Invalidate All to PoU */ + uint32_t RESERVED6[1U]; + __OM uint32_t ICIMVAU; /*!< Offset: 0x258 ( /W) I-Cache Invalidate by MVA to PoU */ + __OM uint32_t DCIMVAC; /*!< Offset: 0x25C ( /W) D-Cache Invalidate by MVA to PoC */ + __OM uint32_t DCISW; /*!< Offset: 0x260 ( /W) D-Cache Invalidate by Set-way */ + __OM uint32_t DCCMVAU; /*!< Offset: 0x264 ( /W) D-Cache Clean by MVA to PoU */ + __OM uint32_t DCCMVAC; /*!< Offset: 0x268 ( /W) D-Cache Clean by MVA to PoC */ + __OM uint32_t DCCSW; /*!< Offset: 0x26C ( /W) D-Cache Clean by Set-way */ + __OM uint32_t DCCIMVAC; /*!< Offset: 0x270 ( /W) D-Cache Clean and Invalidate by MVA to PoC */ + __OM uint32_t DCCISW; /*!< Offset: 0x274 ( /W) D-Cache Clean and Invalidate by Set-way */ + uint32_t RESERVED7[6U]; + __IOM uint32_t ITCMCR; /*!< Offset: 0x290 (R/W) Instruction Tightly-Coupled Memory Control Register */ + __IOM uint32_t DTCMCR; /*!< Offset: 0x294 (R/W) Data Tightly-Coupled Memory Control Registers */ + __IOM uint32_t AHBPCR; /*!< Offset: 0x298 (R/W) AHBP Control Register */ + __IOM uint32_t CACR; /*!< Offset: 0x29C (R/W) L1 Cache Control Register */ + __IOM uint32_t AHBSCR; /*!< Offset: 0x2A0 (R/W) AHB Slave Control Register */ + uint32_t RESERVED8[1U]; + __IOM uint32_t ABFSR; /*!< Offset: 0x2A8 (R/W) Auxiliary Bus Fault Status Register */ +} SCB_Type; + +/* SCB CPUID Register Definitions */ +#define SCB_CPUID_IMPLEMENTER_Pos 24U /*!< SCB CPUID: IMPLEMENTER Position */ +#define SCB_CPUID_IMPLEMENTER_Msk (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos) /*!< SCB CPUID: IMPLEMENTER Mask */ + +#define SCB_CPUID_VARIANT_Pos 20U /*!< SCB CPUID: VARIANT Position */ +#define SCB_CPUID_VARIANT_Msk (0xFUL << SCB_CPUID_VARIANT_Pos) /*!< SCB CPUID: VARIANT Mask */ + +#define SCB_CPUID_ARCHITECTURE_Pos 16U /*!< SCB CPUID: ARCHITECTURE Position */ +#define SCB_CPUID_ARCHITECTURE_Msk (0xFUL << SCB_CPUID_ARCHITECTURE_Pos) /*!< SCB CPUID: ARCHITECTURE Mask */ + +#define SCB_CPUID_PARTNO_Pos 4U /*!< SCB CPUID: PARTNO Position */ +#define SCB_CPUID_PARTNO_Msk (0xFFFUL << SCB_CPUID_PARTNO_Pos) /*!< SCB CPUID: PARTNO Mask */ + +#define SCB_CPUID_REVISION_Pos 0U /*!< SCB CPUID: REVISION Position */ +#define SCB_CPUID_REVISION_Msk (0xFUL /*<< SCB_CPUID_REVISION_Pos*/) /*!< SCB CPUID: REVISION Mask */ + +/* SCB Interrupt Control State Register Definitions */ +#define SCB_ICSR_PENDNMISET_Pos 31U /*!< SCB ICSR: PENDNMISET Position */ +#define SCB_ICSR_PENDNMISET_Msk (1UL << SCB_ICSR_PENDNMISET_Pos) /*!< SCB ICSR: PENDNMISET Mask */ + +#define SCB_ICSR_NMIPENDSET_Pos SCB_ICSR_PENDNMISET_Pos /*!< SCB ICSR: NMIPENDSET Position, backward compatibility */ +#define SCB_ICSR_NMIPENDSET_Msk SCB_ICSR_PENDNMISET_Msk /*!< SCB ICSR: NMIPENDSET Mask, backward compatibility */ + +#define SCB_ICSR_PENDNMICLR_Pos 30U /*!< SCB ICSR: PENDNMICLR Position */ +#define SCB_ICSR_PENDNMICLR_Msk (1UL << SCB_ICSR_PENDNMICLR_Pos) /*!< SCB ICSR: PENDNMICLR Mask */ + +#define SCB_ICSR_PENDSVSET_Pos 28U /*!< SCB ICSR: PENDSVSET Position */ +#define SCB_ICSR_PENDSVSET_Msk (1UL << SCB_ICSR_PENDSVSET_Pos) /*!< SCB ICSR: PENDSVSET Mask */ + +#define SCB_ICSR_PENDSVCLR_Pos 27U /*!< SCB ICSR: PENDSVCLR Position */ +#define SCB_ICSR_PENDSVCLR_Msk (1UL << SCB_ICSR_PENDSVCLR_Pos) /*!< SCB ICSR: PENDSVCLR Mask */ + +#define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */ +#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */ + +#define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */ +#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */ + +#define SCB_ICSR_STTNS_Pos 24U /*!< SCB ICSR: STTNS Position (Security Extension) */ +#define SCB_ICSR_STTNS_Msk (1UL << SCB_ICSR_STTNS_Pos) /*!< SCB ICSR: STTNS Mask (Security Extension) */ + +#define SCB_ICSR_ISRPREEMPT_Pos 23U /*!< SCB ICSR: ISRPREEMPT Position */ +#define SCB_ICSR_ISRPREEMPT_Msk (1UL << SCB_ICSR_ISRPREEMPT_Pos) /*!< SCB ICSR: ISRPREEMPT Mask */ + +#define SCB_ICSR_ISRPENDING_Pos 22U /*!< SCB ICSR: ISRPENDING Position */ +#define SCB_ICSR_ISRPENDING_Msk (1UL << SCB_ICSR_ISRPENDING_Pos) /*!< SCB ICSR: ISRPENDING Mask */ + +#define SCB_ICSR_VECTPENDING_Pos 12U /*!< SCB ICSR: VECTPENDING Position */ +#define SCB_ICSR_VECTPENDING_Msk (0x1FFUL << SCB_ICSR_VECTPENDING_Pos) /*!< SCB ICSR: VECTPENDING Mask */ + +#define SCB_ICSR_RETTOBASE_Pos 11U /*!< SCB ICSR: RETTOBASE Position */ +#define SCB_ICSR_RETTOBASE_Msk (1UL << SCB_ICSR_RETTOBASE_Pos) /*!< SCB ICSR: RETTOBASE Mask */ + +#define SCB_ICSR_VECTACTIVE_Pos 0U /*!< SCB ICSR: VECTACTIVE Position */ +#define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL /*<< SCB_ICSR_VECTACTIVE_Pos*/) /*!< SCB ICSR: VECTACTIVE Mask */ + +/* SCB Vector Table Offset Register Definitions */ +#define SCB_VTOR_TBLOFF_Pos 7U /*!< SCB VTOR: TBLOFF Position */ +#define SCB_VTOR_TBLOFF_Msk (0x1FFFFFFUL << SCB_VTOR_TBLOFF_Pos) /*!< SCB VTOR: TBLOFF Mask */ + +/* SCB Application Interrupt and Reset Control Register Definitions */ +#define SCB_AIRCR_VECTKEY_Pos 16U /*!< SCB AIRCR: VECTKEY Position */ +#define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */ + +#define SCB_AIRCR_VECTKEYSTAT_Pos 16U /*!< SCB AIRCR: VECTKEYSTAT Position */ +#define SCB_AIRCR_VECTKEYSTAT_Msk (0xFFFFUL << SCB_AIRCR_VECTKEYSTAT_Pos) /*!< SCB AIRCR: VECTKEYSTAT Mask */ + +#define SCB_AIRCR_ENDIANESS_Pos 15U /*!< SCB AIRCR: ENDIANESS Position */ +#define SCB_AIRCR_ENDIANESS_Msk (1UL << SCB_AIRCR_ENDIANESS_Pos) /*!< SCB AIRCR: ENDIANESS Mask */ + +#define SCB_AIRCR_PRIS_Pos 14U /*!< SCB AIRCR: PRIS Position */ +#define SCB_AIRCR_PRIS_Msk (1UL << SCB_AIRCR_PRIS_Pos) /*!< SCB AIRCR: PRIS Mask */ + +#define SCB_AIRCR_BFHFNMINS_Pos 13U /*!< SCB AIRCR: BFHFNMINS Position */ +#define SCB_AIRCR_BFHFNMINS_Msk (1UL << SCB_AIRCR_BFHFNMINS_Pos) /*!< SCB AIRCR: BFHFNMINS Mask */ + +#define SCB_AIRCR_PRIGROUP_Pos 8U /*!< SCB AIRCR: PRIGROUP Position */ +#define SCB_AIRCR_PRIGROUP_Msk (7UL << SCB_AIRCR_PRIGROUP_Pos) /*!< SCB AIRCR: PRIGROUP Mask */ + +#define SCB_AIRCR_SYSRESETREQS_Pos 3U /*!< SCB AIRCR: SYSRESETREQS Position */ +#define SCB_AIRCR_SYSRESETREQS_Msk (1UL << SCB_AIRCR_SYSRESETREQS_Pos) /*!< SCB AIRCR: SYSRESETREQS Mask */ + +#define SCB_AIRCR_SYSRESETREQ_Pos 2U /*!< SCB AIRCR: SYSRESETREQ Position */ +#define SCB_AIRCR_SYSRESETREQ_Msk (1UL << SCB_AIRCR_SYSRESETREQ_Pos) /*!< SCB AIRCR: SYSRESETREQ Mask */ + +#define SCB_AIRCR_VECTCLRACTIVE_Pos 1U /*!< SCB AIRCR: VECTCLRACTIVE Position */ +#define SCB_AIRCR_VECTCLRACTIVE_Msk (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos) /*!< SCB AIRCR: VECTCLRACTIVE Mask */ + +/* SCB System Control Register Definitions */ +#define SCB_SCR_SEVONPEND_Pos 4U /*!< SCB SCR: SEVONPEND Position */ +#define SCB_SCR_SEVONPEND_Msk (1UL << SCB_SCR_SEVONPEND_Pos) /*!< SCB SCR: SEVONPEND Mask */ + +#define SCB_SCR_SLEEPDEEPS_Pos 3U /*!< SCB SCR: SLEEPDEEPS Position */ +#define SCB_SCR_SLEEPDEEPS_Msk (1UL << SCB_SCR_SLEEPDEEPS_Pos) /*!< SCB SCR: SLEEPDEEPS Mask */ + +#define SCB_SCR_SLEEPDEEP_Pos 2U /*!< SCB SCR: SLEEPDEEP Position */ +#define SCB_SCR_SLEEPDEEP_Msk (1UL << SCB_SCR_SLEEPDEEP_Pos) /*!< SCB SCR: SLEEPDEEP Mask */ + +#define SCB_SCR_SLEEPONEXIT_Pos 1U /*!< SCB SCR: SLEEPONEXIT Position */ +#define SCB_SCR_SLEEPONEXIT_Msk (1UL << SCB_SCR_SLEEPONEXIT_Pos) /*!< SCB SCR: SLEEPONEXIT Mask */ + +/* SCB Configuration Control Register Definitions */ +#define SCB_CCR_BP_Pos 18U /*!< SCB CCR: BP Position */ +#define SCB_CCR_BP_Msk (1UL << SCB_CCR_BP_Pos) /*!< SCB CCR: BP Mask */ + +#define SCB_CCR_IC_Pos 17U /*!< SCB CCR: IC Position */ +#define SCB_CCR_IC_Msk (1UL << SCB_CCR_IC_Pos) /*!< SCB CCR: IC Mask */ + +#define SCB_CCR_DC_Pos 16U /*!< SCB CCR: DC Position */ +#define SCB_CCR_DC_Msk (1UL << SCB_CCR_DC_Pos) /*!< SCB CCR: DC Mask */ + +#define SCB_CCR_STKOFHFNMIGN_Pos 10U /*!< SCB CCR: STKOFHFNMIGN Position */ +#define SCB_CCR_STKOFHFNMIGN_Msk (1UL << SCB_CCR_STKOFHFNMIGN_Pos) /*!< SCB CCR: STKOFHFNMIGN Mask */ + +#define SCB_CCR_BFHFNMIGN_Pos 8U /*!< SCB CCR: BFHFNMIGN Position */ +#define SCB_CCR_BFHFNMIGN_Msk (1UL << SCB_CCR_BFHFNMIGN_Pos) /*!< SCB CCR: BFHFNMIGN Mask */ + +#define SCB_CCR_DIV_0_TRP_Pos 4U /*!< SCB CCR: DIV_0_TRP Position */ +#define SCB_CCR_DIV_0_TRP_Msk (1UL << SCB_CCR_DIV_0_TRP_Pos) /*!< SCB CCR: DIV_0_TRP Mask */ + +#define SCB_CCR_UNALIGN_TRP_Pos 3U /*!< SCB CCR: UNALIGN_TRP Position */ +#define SCB_CCR_UNALIGN_TRP_Msk (1UL << SCB_CCR_UNALIGN_TRP_Pos) /*!< SCB CCR: UNALIGN_TRP Mask */ + +#define SCB_CCR_USERSETMPEND_Pos 1U /*!< SCB CCR: USERSETMPEND Position */ +#define SCB_CCR_USERSETMPEND_Msk (1UL << SCB_CCR_USERSETMPEND_Pos) /*!< SCB CCR: USERSETMPEND Mask */ + +/* SCB System Handler Control and State Register Definitions */ +#define SCB_SHCSR_HARDFAULTPENDED_Pos 21U /*!< SCB SHCSR: HARDFAULTPENDED Position */ +#define SCB_SHCSR_HARDFAULTPENDED_Msk (1UL << SCB_SHCSR_HARDFAULTPENDED_Pos) /*!< SCB SHCSR: HARDFAULTPENDED Mask */ + +#define SCB_SHCSR_SECUREFAULTPENDED_Pos 20U /*!< SCB SHCSR: SECUREFAULTPENDED Position */ +#define SCB_SHCSR_SECUREFAULTPENDED_Msk (1UL << SCB_SHCSR_SECUREFAULTPENDED_Pos) /*!< SCB SHCSR: SECUREFAULTPENDED Mask */ + +#define SCB_SHCSR_SECUREFAULTENA_Pos 19U /*!< SCB SHCSR: SECUREFAULTENA Position */ +#define SCB_SHCSR_SECUREFAULTENA_Msk (1UL << SCB_SHCSR_SECUREFAULTENA_Pos) /*!< SCB SHCSR: SECUREFAULTENA Mask */ + +#define SCB_SHCSR_USGFAULTENA_Pos 18U /*!< SCB SHCSR: USGFAULTENA Position */ +#define SCB_SHCSR_USGFAULTENA_Msk (1UL << SCB_SHCSR_USGFAULTENA_Pos) /*!< SCB SHCSR: USGFAULTENA Mask */ + +#define SCB_SHCSR_BUSFAULTENA_Pos 17U /*!< SCB SHCSR: BUSFAULTENA Position */ +#define SCB_SHCSR_BUSFAULTENA_Msk (1UL << SCB_SHCSR_BUSFAULTENA_Pos) /*!< SCB SHCSR: BUSFAULTENA Mask */ + +#define SCB_SHCSR_MEMFAULTENA_Pos 16U /*!< SCB SHCSR: MEMFAULTENA Position */ +#define SCB_SHCSR_MEMFAULTENA_Msk (1UL << SCB_SHCSR_MEMFAULTENA_Pos) /*!< SCB SHCSR: MEMFAULTENA Mask */ + +#define SCB_SHCSR_SVCALLPENDED_Pos 15U /*!< SCB SHCSR: SVCALLPENDED Position */ +#define SCB_SHCSR_SVCALLPENDED_Msk (1UL << SCB_SHCSR_SVCALLPENDED_Pos) /*!< SCB SHCSR: SVCALLPENDED Mask */ + +#define SCB_SHCSR_BUSFAULTPENDED_Pos 14U /*!< SCB SHCSR: BUSFAULTPENDED Position */ +#define SCB_SHCSR_BUSFAULTPENDED_Msk (1UL << SCB_SHCSR_BUSFAULTPENDED_Pos) /*!< SCB SHCSR: BUSFAULTPENDED Mask */ + +#define SCB_SHCSR_MEMFAULTPENDED_Pos 13U /*!< SCB SHCSR: MEMFAULTPENDED Position */ +#define SCB_SHCSR_MEMFAULTPENDED_Msk (1UL << SCB_SHCSR_MEMFAULTPENDED_Pos) /*!< SCB SHCSR: MEMFAULTPENDED Mask */ + +#define SCB_SHCSR_USGFAULTPENDED_Pos 12U /*!< SCB SHCSR: USGFAULTPENDED Position */ +#define SCB_SHCSR_USGFAULTPENDED_Msk (1UL << SCB_SHCSR_USGFAULTPENDED_Pos) /*!< SCB SHCSR: USGFAULTPENDED Mask */ + +#define SCB_SHCSR_SYSTICKACT_Pos 11U /*!< SCB SHCSR: SYSTICKACT Position */ +#define SCB_SHCSR_SYSTICKACT_Msk (1UL << SCB_SHCSR_SYSTICKACT_Pos) /*!< SCB SHCSR: SYSTICKACT Mask */ + +#define SCB_SHCSR_PENDSVACT_Pos 10U /*!< SCB SHCSR: PENDSVACT Position */ +#define SCB_SHCSR_PENDSVACT_Msk (1UL << SCB_SHCSR_PENDSVACT_Pos) /*!< SCB SHCSR: PENDSVACT Mask */ + +#define SCB_SHCSR_MONITORACT_Pos 8U /*!< SCB SHCSR: MONITORACT Position */ +#define SCB_SHCSR_MONITORACT_Msk (1UL << SCB_SHCSR_MONITORACT_Pos) /*!< SCB SHCSR: MONITORACT Mask */ + +#define SCB_SHCSR_SVCALLACT_Pos 7U /*!< SCB SHCSR: SVCALLACT Position */ +#define SCB_SHCSR_SVCALLACT_Msk (1UL << SCB_SHCSR_SVCALLACT_Pos) /*!< SCB SHCSR: SVCALLACT Mask */ + +#define SCB_SHCSR_NMIACT_Pos 5U /*!< SCB SHCSR: NMIACT Position */ +#define SCB_SHCSR_NMIACT_Msk (1UL << SCB_SHCSR_NMIACT_Pos) /*!< SCB SHCSR: NMIACT Mask */ + +#define SCB_SHCSR_SECUREFAULTACT_Pos 4U /*!< SCB SHCSR: SECUREFAULTACT Position */ +#define SCB_SHCSR_SECUREFAULTACT_Msk (1UL << SCB_SHCSR_SECUREFAULTACT_Pos) /*!< SCB SHCSR: SECUREFAULTACT Mask */ + +#define SCB_SHCSR_USGFAULTACT_Pos 3U /*!< SCB SHCSR: USGFAULTACT Position */ +#define SCB_SHCSR_USGFAULTACT_Msk (1UL << SCB_SHCSR_USGFAULTACT_Pos) /*!< SCB SHCSR: USGFAULTACT Mask */ + +#define SCB_SHCSR_HARDFAULTACT_Pos 2U /*!< SCB SHCSR: HARDFAULTACT Position */ +#define SCB_SHCSR_HARDFAULTACT_Msk (1UL << SCB_SHCSR_HARDFAULTACT_Pos) /*!< SCB SHCSR: HARDFAULTACT Mask */ + +#define SCB_SHCSR_BUSFAULTACT_Pos 1U /*!< SCB SHCSR: BUSFAULTACT Position */ +#define SCB_SHCSR_BUSFAULTACT_Msk (1UL << SCB_SHCSR_BUSFAULTACT_Pos) /*!< SCB SHCSR: BUSFAULTACT Mask */ + +#define SCB_SHCSR_MEMFAULTACT_Pos 0U /*!< SCB SHCSR: MEMFAULTACT Position */ +#define SCB_SHCSR_MEMFAULTACT_Msk (1UL /*<< SCB_SHCSR_MEMFAULTACT_Pos*/) /*!< SCB SHCSR: MEMFAULTACT Mask */ + +/* SCB Configurable Fault Status Register Definitions */ +#define SCB_CFSR_USGFAULTSR_Pos 16U /*!< SCB CFSR: Usage Fault Status Register Position */ +#define SCB_CFSR_USGFAULTSR_Msk (0xFFFFUL << SCB_CFSR_USGFAULTSR_Pos) /*!< SCB CFSR: Usage Fault Status Register Mask */ + +#define SCB_CFSR_BUSFAULTSR_Pos 8U /*!< SCB CFSR: Bus Fault Status Register Position */ +#define SCB_CFSR_BUSFAULTSR_Msk (0xFFUL << SCB_CFSR_BUSFAULTSR_Pos) /*!< SCB CFSR: Bus Fault Status Register Mask */ + +#define SCB_CFSR_MEMFAULTSR_Pos 0U /*!< SCB CFSR: Memory Manage Fault Status Register Position */ +#define SCB_CFSR_MEMFAULTSR_Msk (0xFFUL /*<< SCB_CFSR_MEMFAULTSR_Pos*/) /*!< SCB CFSR: Memory Manage Fault Status Register Mask */ + +/* MemManage Fault Status Register (part of SCB Configurable Fault Status Register) */ +#define SCB_CFSR_MMARVALID_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 7U) /*!< SCB CFSR (MMFSR): MMARVALID Position */ +#define SCB_CFSR_MMARVALID_Msk (1UL << SCB_CFSR_MMARVALID_Pos) /*!< SCB CFSR (MMFSR): MMARVALID Mask */ + +#define SCB_CFSR_MLSPERR_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 5U) /*!< SCB CFSR (MMFSR): MLSPERR Position */ +#define SCB_CFSR_MLSPERR_Msk (1UL << SCB_CFSR_MLSPERR_Pos) /*!< SCB CFSR (MMFSR): MLSPERR Mask */ + +#define SCB_CFSR_MSTKERR_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 4U) /*!< SCB CFSR (MMFSR): MSTKERR Position */ +#define SCB_CFSR_MSTKERR_Msk (1UL << SCB_CFSR_MSTKERR_Pos) /*!< SCB CFSR (MMFSR): MSTKERR Mask */ + +#define SCB_CFSR_MUNSTKERR_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 3U) /*!< SCB CFSR (MMFSR): MUNSTKERR Position */ +#define SCB_CFSR_MUNSTKERR_Msk (1UL << SCB_CFSR_MUNSTKERR_Pos) /*!< SCB CFSR (MMFSR): MUNSTKERR Mask */ + +#define SCB_CFSR_DACCVIOL_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 1U) /*!< SCB CFSR (MMFSR): DACCVIOL Position */ +#define SCB_CFSR_DACCVIOL_Msk (1UL << SCB_CFSR_DACCVIOL_Pos) /*!< SCB CFSR (MMFSR): DACCVIOL Mask */ + +#define SCB_CFSR_IACCVIOL_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 0U) /*!< SCB CFSR (MMFSR): IACCVIOL Position */ +#define SCB_CFSR_IACCVIOL_Msk (1UL /*<< SCB_CFSR_IACCVIOL_Pos*/) /*!< SCB CFSR (MMFSR): IACCVIOL Mask */ + +/* BusFault Status Register (part of SCB Configurable Fault Status Register) */ +#define SCB_CFSR_BFARVALID_Pos (SCB_CFSR_BUSFAULTSR_Pos + 7U) /*!< SCB CFSR (BFSR): BFARVALID Position */ +#define SCB_CFSR_BFARVALID_Msk (1UL << SCB_CFSR_BFARVALID_Pos) /*!< SCB CFSR (BFSR): BFARVALID Mask */ + +#define SCB_CFSR_LSPERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 5U) /*!< SCB CFSR (BFSR): LSPERR Position */ +#define SCB_CFSR_LSPERR_Msk (1UL << SCB_CFSR_LSPERR_Pos) /*!< SCB CFSR (BFSR): LSPERR Mask */ + +#define SCB_CFSR_STKERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 4U) /*!< SCB CFSR (BFSR): STKERR Position */ +#define SCB_CFSR_STKERR_Msk (1UL << SCB_CFSR_STKERR_Pos) /*!< SCB CFSR (BFSR): STKERR Mask */ + +#define SCB_CFSR_UNSTKERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 3U) /*!< SCB CFSR (BFSR): UNSTKERR Position */ +#define SCB_CFSR_UNSTKERR_Msk (1UL << SCB_CFSR_UNSTKERR_Pos) /*!< SCB CFSR (BFSR): UNSTKERR Mask */ + +#define SCB_CFSR_IMPRECISERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 2U) /*!< SCB CFSR (BFSR): IMPRECISERR Position */ +#define SCB_CFSR_IMPRECISERR_Msk (1UL << SCB_CFSR_IMPRECISERR_Pos) /*!< SCB CFSR (BFSR): IMPRECISERR Mask */ + +#define SCB_CFSR_PRECISERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 1U) /*!< SCB CFSR (BFSR): PRECISERR Position */ +#define SCB_CFSR_PRECISERR_Msk (1UL << SCB_CFSR_PRECISERR_Pos) /*!< SCB CFSR (BFSR): PRECISERR Mask */ + +#define SCB_CFSR_IBUSERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 0U) /*!< SCB CFSR (BFSR): IBUSERR Position */ +#define SCB_CFSR_IBUSERR_Msk (1UL << SCB_CFSR_IBUSERR_Pos) /*!< SCB CFSR (BFSR): IBUSERR Mask */ + +/* UsageFault Status Register (part of SCB Configurable Fault Status Register) */ +#define SCB_CFSR_DIVBYZERO_Pos (SCB_CFSR_USGFAULTSR_Pos + 9U) /*!< SCB CFSR (UFSR): DIVBYZERO Position */ +#define SCB_CFSR_DIVBYZERO_Msk (1UL << SCB_CFSR_DIVBYZERO_Pos) /*!< SCB CFSR (UFSR): DIVBYZERO Mask */ + +#define SCB_CFSR_UNALIGNED_Pos (SCB_CFSR_USGFAULTSR_Pos + 8U) /*!< SCB CFSR (UFSR): UNALIGNED Position */ +#define SCB_CFSR_UNALIGNED_Msk (1UL << SCB_CFSR_UNALIGNED_Pos) /*!< SCB CFSR (UFSR): UNALIGNED Mask */ + +#define SCB_CFSR_STKOF_Pos (SCB_CFSR_USGFAULTSR_Pos + 4U) /*!< SCB CFSR (UFSR): STKOF Position */ +#define SCB_CFSR_STKOF_Msk (1UL << SCB_CFSR_STKOF_Pos) /*!< SCB CFSR (UFSR): STKOF Mask */ + +#define SCB_CFSR_NOCP_Pos (SCB_CFSR_USGFAULTSR_Pos + 3U) /*!< SCB CFSR (UFSR): NOCP Position */ +#define SCB_CFSR_NOCP_Msk (1UL << SCB_CFSR_NOCP_Pos) /*!< SCB CFSR (UFSR): NOCP Mask */ + +#define SCB_CFSR_INVPC_Pos (SCB_CFSR_USGFAULTSR_Pos + 2U) /*!< SCB CFSR (UFSR): INVPC Position */ +#define SCB_CFSR_INVPC_Msk (1UL << SCB_CFSR_INVPC_Pos) /*!< SCB CFSR (UFSR): INVPC Mask */ + +#define SCB_CFSR_INVSTATE_Pos (SCB_CFSR_USGFAULTSR_Pos + 1U) /*!< SCB CFSR (UFSR): INVSTATE Position */ +#define SCB_CFSR_INVSTATE_Msk (1UL << SCB_CFSR_INVSTATE_Pos) /*!< SCB CFSR (UFSR): INVSTATE Mask */ + +#define SCB_CFSR_UNDEFINSTR_Pos (SCB_CFSR_USGFAULTSR_Pos + 0U) /*!< SCB CFSR (UFSR): UNDEFINSTR Position */ +#define SCB_CFSR_UNDEFINSTR_Msk (1UL << SCB_CFSR_UNDEFINSTR_Pos) /*!< SCB CFSR (UFSR): UNDEFINSTR Mask */ + +/* SCB Hard Fault Status Register Definitions */ +#define SCB_HFSR_DEBUGEVT_Pos 31U /*!< SCB HFSR: DEBUGEVT Position */ +#define SCB_HFSR_DEBUGEVT_Msk (1UL << SCB_HFSR_DEBUGEVT_Pos) /*!< SCB HFSR: DEBUGEVT Mask */ + +#define SCB_HFSR_FORCED_Pos 30U /*!< SCB HFSR: FORCED Position */ +#define SCB_HFSR_FORCED_Msk (1UL << SCB_HFSR_FORCED_Pos) /*!< SCB HFSR: FORCED Mask */ + +#define SCB_HFSR_VECTTBL_Pos 1U /*!< SCB HFSR: VECTTBL Position */ +#define SCB_HFSR_VECTTBL_Msk (1UL << SCB_HFSR_VECTTBL_Pos) /*!< SCB HFSR: VECTTBL Mask */ + +/* SCB Debug Fault Status Register Definitions */ +#define SCB_DFSR_EXTERNAL_Pos 4U /*!< SCB DFSR: EXTERNAL Position */ +#define SCB_DFSR_EXTERNAL_Msk (1UL << SCB_DFSR_EXTERNAL_Pos) /*!< SCB DFSR: EXTERNAL Mask */ + +#define SCB_DFSR_VCATCH_Pos 3U /*!< SCB DFSR: VCATCH Position */ +#define SCB_DFSR_VCATCH_Msk (1UL << SCB_DFSR_VCATCH_Pos) /*!< SCB DFSR: VCATCH Mask */ + +#define SCB_DFSR_DWTTRAP_Pos 2U /*!< SCB DFSR: DWTTRAP Position */ +#define SCB_DFSR_DWTTRAP_Msk (1UL << SCB_DFSR_DWTTRAP_Pos) /*!< SCB DFSR: DWTTRAP Mask */ + +#define SCB_DFSR_BKPT_Pos 1U /*!< SCB DFSR: BKPT Position */ +#define SCB_DFSR_BKPT_Msk (1UL << SCB_DFSR_BKPT_Pos) /*!< SCB DFSR: BKPT Mask */ + +#define SCB_DFSR_HALTED_Pos 0U /*!< SCB DFSR: HALTED Position */ +#define SCB_DFSR_HALTED_Msk (1UL /*<< SCB_DFSR_HALTED_Pos*/) /*!< SCB DFSR: HALTED Mask */ + +/* SCB Non-Secure Access Control Register Definitions */ +#define SCB_NSACR_CP11_Pos 11U /*!< SCB NSACR: CP11 Position */ +#define SCB_NSACR_CP11_Msk (1UL << SCB_NSACR_CP11_Pos) /*!< SCB NSACR: CP11 Mask */ + +#define SCB_NSACR_CP10_Pos 10U /*!< SCB NSACR: CP10 Position */ +#define SCB_NSACR_CP10_Msk (1UL << SCB_NSACR_CP10_Pos) /*!< SCB NSACR: CP10 Mask */ + +#define SCB_NSACR_CPn_Pos 0U /*!< SCB NSACR: CPn Position */ +#define SCB_NSACR_CPn_Msk (1UL /*<< SCB_NSACR_CPn_Pos*/) /*!< SCB NSACR: CPn Mask */ + +/* SCB Cache Level ID Register Definitions */ +#define SCB_CLIDR_LOUU_Pos 27U /*!< SCB CLIDR: LoUU Position */ +#define SCB_CLIDR_LOUU_Msk (7UL << SCB_CLIDR_LOUU_Pos) /*!< SCB CLIDR: LoUU Mask */ + +#define SCB_CLIDR_LOC_Pos 24U /*!< SCB CLIDR: LoC Position */ +#define SCB_CLIDR_LOC_Msk (7UL << SCB_CLIDR_LOC_Pos) /*!< SCB CLIDR: LoC Mask */ + +/* SCB Cache Type Register Definitions */ +#define SCB_CTR_FORMAT_Pos 29U /*!< SCB CTR: Format Position */ +#define SCB_CTR_FORMAT_Msk (7UL << SCB_CTR_FORMAT_Pos) /*!< SCB CTR: Format Mask */ + +#define SCB_CTR_CWG_Pos 24U /*!< SCB CTR: CWG Position */ +#define SCB_CTR_CWG_Msk (0xFUL << SCB_CTR_CWG_Pos) /*!< SCB CTR: CWG Mask */ + +#define SCB_CTR_ERG_Pos 20U /*!< SCB CTR: ERG Position */ +#define SCB_CTR_ERG_Msk (0xFUL << SCB_CTR_ERG_Pos) /*!< SCB CTR: ERG Mask */ + +#define SCB_CTR_DMINLINE_Pos 16U /*!< SCB CTR: DminLine Position */ +#define SCB_CTR_DMINLINE_Msk (0xFUL << SCB_CTR_DMINLINE_Pos) /*!< SCB CTR: DminLine Mask */ + +#define SCB_CTR_IMINLINE_Pos 0U /*!< SCB CTR: ImInLine Position */ +#define SCB_CTR_IMINLINE_Msk (0xFUL /*<< SCB_CTR_IMINLINE_Pos*/) /*!< SCB CTR: ImInLine Mask */ + +/* SCB Cache Size ID Register Definitions */ +#define SCB_CCSIDR_WT_Pos 31U /*!< SCB CCSIDR: WT Position */ +#define SCB_CCSIDR_WT_Msk (1UL << SCB_CCSIDR_WT_Pos) /*!< SCB CCSIDR: WT Mask */ + +#define SCB_CCSIDR_WB_Pos 30U /*!< SCB CCSIDR: WB Position */ +#define SCB_CCSIDR_WB_Msk (1UL << SCB_CCSIDR_WB_Pos) /*!< SCB CCSIDR: WB Mask */ + +#define SCB_CCSIDR_RA_Pos 29U /*!< SCB CCSIDR: RA Position */ +#define SCB_CCSIDR_RA_Msk (1UL << SCB_CCSIDR_RA_Pos) /*!< SCB CCSIDR: RA Mask */ + +#define SCB_CCSIDR_WA_Pos 28U /*!< SCB CCSIDR: WA Position */ +#define SCB_CCSIDR_WA_Msk (1UL << SCB_CCSIDR_WA_Pos) /*!< SCB CCSIDR: WA Mask */ + +#define SCB_CCSIDR_NUMSETS_Pos 13U /*!< SCB CCSIDR: NumSets Position */ +#define SCB_CCSIDR_NUMSETS_Msk (0x7FFFUL << SCB_CCSIDR_NUMSETS_Pos) /*!< SCB CCSIDR: NumSets Mask */ + +#define SCB_CCSIDR_ASSOCIATIVITY_Pos 3U /*!< SCB CCSIDR: Associativity Position */ +#define SCB_CCSIDR_ASSOCIATIVITY_Msk (0x3FFUL << SCB_CCSIDR_ASSOCIATIVITY_Pos) /*!< SCB CCSIDR: Associativity Mask */ + +#define SCB_CCSIDR_LINESIZE_Pos 0U /*!< SCB CCSIDR: LineSize Position */ +#define SCB_CCSIDR_LINESIZE_Msk (7UL /*<< SCB_CCSIDR_LINESIZE_Pos*/) /*!< SCB CCSIDR: LineSize Mask */ + +/* SCB Cache Size Selection Register Definitions */ +#define SCB_CSSELR_LEVEL_Pos 1U /*!< SCB CSSELR: Level Position */ +#define SCB_CSSELR_LEVEL_Msk (7UL << SCB_CSSELR_LEVEL_Pos) /*!< SCB CSSELR: Level Mask */ + +#define SCB_CSSELR_IND_Pos 0U /*!< SCB CSSELR: InD Position */ +#define SCB_CSSELR_IND_Msk (1UL /*<< SCB_CSSELR_IND_Pos*/) /*!< SCB CSSELR: InD Mask */ + +/* SCB Software Triggered Interrupt Register Definitions */ +#define SCB_STIR_INTID_Pos 0U /*!< SCB STIR: INTID Position */ +#define SCB_STIR_INTID_Msk (0x1FFUL /*<< SCB_STIR_INTID_Pos*/) /*!< SCB STIR: INTID Mask */ + +/* SCB D-Cache Invalidate by Set-way Register Definitions */ +#define SCB_DCISW_WAY_Pos 30U /*!< SCB DCISW: Way Position */ +#define SCB_DCISW_WAY_Msk (3UL << SCB_DCISW_WAY_Pos) /*!< SCB DCISW: Way Mask */ + +#define SCB_DCISW_SET_Pos 5U /*!< SCB DCISW: Set Position */ +#define SCB_DCISW_SET_Msk (0x1FFUL << SCB_DCISW_SET_Pos) /*!< SCB DCISW: Set Mask */ + +/* SCB D-Cache Clean by Set-way Register Definitions */ +#define SCB_DCCSW_WAY_Pos 30U /*!< SCB DCCSW: Way Position */ +#define SCB_DCCSW_WAY_Msk (3UL << SCB_DCCSW_WAY_Pos) /*!< SCB DCCSW: Way Mask */ + +#define SCB_DCCSW_SET_Pos 5U /*!< SCB DCCSW: Set Position */ +#define SCB_DCCSW_SET_Msk (0x1FFUL << SCB_DCCSW_SET_Pos) /*!< SCB DCCSW: Set Mask */ + +/* SCB D-Cache Clean and Invalidate by Set-way Register Definitions */ +#define SCB_DCCISW_WAY_Pos 30U /*!< SCB DCCISW: Way Position */ +#define SCB_DCCISW_WAY_Msk (3UL << SCB_DCCISW_WAY_Pos) /*!< SCB DCCISW: Way Mask */ + +#define SCB_DCCISW_SET_Pos 5U /*!< SCB DCCISW: Set Position */ +#define SCB_DCCISW_SET_Msk (0x1FFUL << SCB_DCCISW_SET_Pos) /*!< SCB DCCISW: Set Mask */ + +/* Instruction Tightly-Coupled Memory Control Register Definitions */ +#define SCB_ITCMCR_SZ_Pos 3U /*!< SCB ITCMCR: SZ Position */ +#define SCB_ITCMCR_SZ_Msk (0xFUL << SCB_ITCMCR_SZ_Pos) /*!< SCB ITCMCR: SZ Mask */ + +#define SCB_ITCMCR_RETEN_Pos 2U /*!< SCB ITCMCR: RETEN Position */ +#define SCB_ITCMCR_RETEN_Msk (1UL << SCB_ITCMCR_RETEN_Pos) /*!< SCB ITCMCR: RETEN Mask */ + +#define SCB_ITCMCR_RMW_Pos 1U /*!< SCB ITCMCR: RMW Position */ +#define SCB_ITCMCR_RMW_Msk (1UL << SCB_ITCMCR_RMW_Pos) /*!< SCB ITCMCR: RMW Mask */ + +#define SCB_ITCMCR_EN_Pos 0U /*!< SCB ITCMCR: EN Position */ +#define SCB_ITCMCR_EN_Msk (1UL /*<< SCB_ITCMCR_EN_Pos*/) /*!< SCB ITCMCR: EN Mask */ + +/* Data Tightly-Coupled Memory Control Register Definitions */ +#define SCB_DTCMCR_SZ_Pos 3U /*!< SCB DTCMCR: SZ Position */ +#define SCB_DTCMCR_SZ_Msk (0xFUL << SCB_DTCMCR_SZ_Pos) /*!< SCB DTCMCR: SZ Mask */ + +#define SCB_DTCMCR_RETEN_Pos 2U /*!< SCB DTCMCR: RETEN Position */ +#define SCB_DTCMCR_RETEN_Msk (1UL << SCB_DTCMCR_RETEN_Pos) /*!< SCB DTCMCR: RETEN Mask */ + +#define SCB_DTCMCR_RMW_Pos 1U /*!< SCB DTCMCR: RMW Position */ +#define SCB_DTCMCR_RMW_Msk (1UL << SCB_DTCMCR_RMW_Pos) /*!< SCB DTCMCR: RMW Mask */ + +#define SCB_DTCMCR_EN_Pos 0U /*!< SCB DTCMCR: EN Position */ +#define SCB_DTCMCR_EN_Msk (1UL /*<< SCB_DTCMCR_EN_Pos*/) /*!< SCB DTCMCR: EN Mask */ + +/* AHBP Control Register Definitions */ +#define SCB_AHBPCR_SZ_Pos 1U /*!< SCB AHBPCR: SZ Position */ +#define SCB_AHBPCR_SZ_Msk (7UL << SCB_AHBPCR_SZ_Pos) /*!< SCB AHBPCR: SZ Mask */ + +#define SCB_AHBPCR_EN_Pos 0U /*!< SCB AHBPCR: EN Position */ +#define SCB_AHBPCR_EN_Msk (1UL /*<< SCB_AHBPCR_EN_Pos*/) /*!< SCB AHBPCR: EN Mask */ + +/* L1 Cache Control Register Definitions */ +#define SCB_CACR_FORCEWT_Pos 2U /*!< SCB CACR: FORCEWT Position */ +#define SCB_CACR_FORCEWT_Msk (1UL << SCB_CACR_FORCEWT_Pos) /*!< SCB CACR: FORCEWT Mask */ + +#define SCB_CACR_ECCEN_Pos 1U /*!< SCB CACR: ECCEN Position */ +#define SCB_CACR_ECCEN_Msk (1UL << SCB_CACR_ECCEN_Pos) /*!< SCB CACR: ECCEN Mask */ + +#define SCB_CACR_SIWT_Pos 0U /*!< SCB CACR: SIWT Position */ +#define SCB_CACR_SIWT_Msk (1UL /*<< SCB_CACR_SIWT_Pos*/) /*!< SCB CACR: SIWT Mask */ + +/* AHBS Control Register Definitions */ +#define SCB_AHBSCR_INITCOUNT_Pos 11U /*!< SCB AHBSCR: INITCOUNT Position */ +#define SCB_AHBSCR_INITCOUNT_Msk (0x1FUL << SCB_AHBPCR_INITCOUNT_Pos) /*!< SCB AHBSCR: INITCOUNT Mask */ + +#define SCB_AHBSCR_TPRI_Pos 2U /*!< SCB AHBSCR: TPRI Position */ +#define SCB_AHBSCR_TPRI_Msk (0x1FFUL << SCB_AHBPCR_TPRI_Pos) /*!< SCB AHBSCR: TPRI Mask */ + +#define SCB_AHBSCR_CTL_Pos 0U /*!< SCB AHBSCR: CTL Position*/ +#define SCB_AHBSCR_CTL_Msk (3UL /*<< SCB_AHBPCR_CTL_Pos*/) /*!< SCB AHBSCR: CTL Mask */ + +/* Auxiliary Bus Fault Status Register Definitions */ +#define SCB_ABFSR_AXIMTYPE_Pos 8U /*!< SCB ABFSR: AXIMTYPE Position*/ +#define SCB_ABFSR_AXIMTYPE_Msk (3UL << SCB_ABFSR_AXIMTYPE_Pos) /*!< SCB ABFSR: AXIMTYPE Mask */ + +#define SCB_ABFSR_EPPB_Pos 4U /*!< SCB ABFSR: EPPB Position*/ +#define SCB_ABFSR_EPPB_Msk (1UL << SCB_ABFSR_EPPB_Pos) /*!< SCB ABFSR: EPPB Mask */ + +#define SCB_ABFSR_AXIM_Pos 3U /*!< SCB ABFSR: AXIM Position*/ +#define SCB_ABFSR_AXIM_Msk (1UL << SCB_ABFSR_AXIM_Pos) /*!< SCB ABFSR: AXIM Mask */ + +#define SCB_ABFSR_AHBP_Pos 2U /*!< SCB ABFSR: AHBP Position*/ +#define SCB_ABFSR_AHBP_Msk (1UL << SCB_ABFSR_AHBP_Pos) /*!< SCB ABFSR: AHBP Mask */ + +#define SCB_ABFSR_DTCM_Pos 1U /*!< SCB ABFSR: DTCM Position*/ +#define SCB_ABFSR_DTCM_Msk (1UL << SCB_ABFSR_DTCM_Pos) /*!< SCB ABFSR: DTCM Mask */ + +#define SCB_ABFSR_ITCM_Pos 0U /*!< SCB ABFSR: ITCM Position*/ +#define SCB_ABFSR_ITCM_Msk (1UL /*<< SCB_ABFSR_ITCM_Pos*/) /*!< SCB ABFSR: ITCM Mask */ + +/*@} end of group CMSIS_SCB */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SCnSCB System Controls not in SCB (SCnSCB) + \brief Type definitions for the System Control and ID Register not in the SCB + @{ + */ + +/** + \brief Structure type to access the System Control and ID Register not in the SCB. + */ +typedef struct +{ + uint32_t RESERVED0[1U]; + __IM uint32_t ICTR; /*!< Offset: 0x004 (R/ ) Interrupt Controller Type Register */ + __IOM uint32_t ACTLR; /*!< Offset: 0x008 (R/W) Auxiliary Control Register */ + __IOM uint32_t CPPWR; /*!< Offset: 0x00C (R/W) Coprocessor Power Control Register */ +} SCnSCB_Type; + +/* Interrupt Controller Type Register Definitions */ +#define SCnSCB_ICTR_INTLINESNUM_Pos 0U /*!< ICTR: INTLINESNUM Position */ +#define SCnSCB_ICTR_INTLINESNUM_Msk (0xFUL /*<< SCnSCB_ICTR_INTLINESNUM_Pos*/) /*!< ICTR: INTLINESNUM Mask */ + +/*@} end of group CMSIS_SCnotSCB */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SysTick System Tick Timer (SysTick) + \brief Type definitions for the System Timer Registers. + @{ + */ + +/** + \brief Structure type to access the System Timer (SysTick). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */ + __IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */ + __IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */ + __IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */ +} SysTick_Type; + +/* SysTick Control / Status Register Definitions */ +#define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */ +#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */ + +#define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */ +#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */ + +#define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */ +#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */ + +#define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */ +#define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */ + +/* SysTick Reload Register Definitions */ +#define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */ +#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */ + +/* SysTick Current Register Definitions */ +#define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */ +#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */ + +/* SysTick Calibration Register Definitions */ +#define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */ +#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */ + +#define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */ +#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */ + +#define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */ +#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */ + +/*@} end of group CMSIS_SysTick */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_ITM Instrumentation Trace Macrocell (ITM) + \brief Type definitions for the Instrumentation Trace Macrocell (ITM) + @{ + */ + +/** + \brief Structure type to access the Instrumentation Trace Macrocell Register (ITM). + */ +typedef struct +{ + __OM union + { + __OM uint8_t u8; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 8-bit */ + __OM uint16_t u16; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 16-bit */ + __OM uint32_t u32; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 32-bit */ + } PORT [32U]; /*!< Offset: 0x000 ( /W) ITM Stimulus Port Registers */ + uint32_t RESERVED0[864U]; + __IOM uint32_t TER; /*!< Offset: 0xE00 (R/W) ITM Trace Enable Register */ + uint32_t RESERVED1[15U]; + __IOM uint32_t TPR; /*!< Offset: 0xE40 (R/W) ITM Trace Privilege Register */ + uint32_t RESERVED2[15U]; + __IOM uint32_t TCR; /*!< Offset: 0xE80 (R/W) ITM Trace Control Register */ + uint32_t RESERVED3[29U]; + __OM uint32_t IWR; /*!< Offset: 0xEF8 ( /W) ITM Integration Write Register */ + __IM uint32_t IRR; /*!< Offset: 0xEFC (R/ ) ITM Integration Read Register */ + __IOM uint32_t IMCR; /*!< Offset: 0xF00 (R/W) ITM Integration Mode Control Register */ + uint32_t RESERVED4[43U]; + __OM uint32_t LAR; /*!< Offset: 0xFB0 ( /W) ITM Lock Access Register */ + __IM uint32_t LSR; /*!< Offset: 0xFB4 (R/ ) ITM Lock Status Register */ + uint32_t RESERVED5[1U]; + __IM uint32_t DEVARCH; /*!< Offset: 0xFBC (R/ ) ITM Device Architecture Register */ + uint32_t RESERVED6[4U]; + __IM uint32_t PID4; /*!< Offset: 0xFD0 (R/ ) ITM Peripheral Identification Register #4 */ + __IM uint32_t PID5; /*!< Offset: 0xFD4 (R/ ) ITM Peripheral Identification Register #5 */ + __IM uint32_t PID6; /*!< Offset: 0xFD8 (R/ ) ITM Peripheral Identification Register #6 */ + __IM uint32_t PID7; /*!< Offset: 0xFDC (R/ ) ITM Peripheral Identification Register #7 */ + __IM uint32_t PID0; /*!< Offset: 0xFE0 (R/ ) ITM Peripheral Identification Register #0 */ + __IM uint32_t PID1; /*!< Offset: 0xFE4 (R/ ) ITM Peripheral Identification Register #1 */ + __IM uint32_t PID2; /*!< Offset: 0xFE8 (R/ ) ITM Peripheral Identification Register #2 */ + __IM uint32_t PID3; /*!< Offset: 0xFEC (R/ ) ITM Peripheral Identification Register #3 */ + __IM uint32_t CID0; /*!< Offset: 0xFF0 (R/ ) ITM Component Identification Register #0 */ + __IM uint32_t CID1; /*!< Offset: 0xFF4 (R/ ) ITM Component Identification Register #1 */ + __IM uint32_t CID2; /*!< Offset: 0xFF8 (R/ ) ITM Component Identification Register #2 */ + __IM uint32_t CID3; /*!< Offset: 0xFFC (R/ ) ITM Component Identification Register #3 */ +} ITM_Type; + +/* ITM Stimulus Port Register Definitions */ +#define ITM_STIM_DISABLED_Pos 1U /*!< ITM STIM: DISABLED Position */ +#define ITM_STIM_DISABLED_Msk (0x1UL << ITM_STIM_DISABLED_Pos) /*!< ITM STIM: DISABLED Mask */ + +#define ITM_STIM_FIFOREADY_Pos 0U /*!< ITM STIM: FIFOREADY Position */ +#define ITM_STIM_FIFOREADY_Msk (0x1UL /*<< ITM_STIM_FIFOREADY_Pos*/) /*!< ITM STIM: FIFOREADY Mask */ + +/* ITM Trace Privilege Register Definitions */ +#define ITM_TPR_PRIVMASK_Pos 0U /*!< ITM TPR: PRIVMASK Position */ +#define ITM_TPR_PRIVMASK_Msk (0xFUL /*<< ITM_TPR_PRIVMASK_Pos*/) /*!< ITM TPR: PRIVMASK Mask */ + +/* ITM Trace Control Register Definitions */ +#define ITM_TCR_BUSY_Pos 23U /*!< ITM TCR: BUSY Position */ +#define ITM_TCR_BUSY_Msk (1UL << ITM_TCR_BUSY_Pos) /*!< ITM TCR: BUSY Mask */ + +#define ITM_TCR_TRACEBUSID_Pos 16U /*!< ITM TCR: ATBID Position */ +#define ITM_TCR_TRACEBUSID_Msk (0x7FUL << ITM_TCR_TRACEBUSID_Pos) /*!< ITM TCR: ATBID Mask */ + +#define ITM_TCR_GTSFREQ_Pos 10U /*!< ITM TCR: Global timestamp frequency Position */ +#define ITM_TCR_GTSFREQ_Msk (3UL << ITM_TCR_GTSFREQ_Pos) /*!< ITM TCR: Global timestamp frequency Mask */ + +#define ITM_TCR_TSPRESCALE_Pos 8U /*!< ITM TCR: TSPRESCALE Position */ +#define ITM_TCR_TSPRESCALE_Msk (3UL << ITM_TCR_TSPRESCALE_Pos) /*!< ITM TCR: TSPRESCALE Mask */ + +#define ITM_TCR_STALLENA_Pos 5U /*!< ITM TCR: STALLENA Position */ +#define ITM_TCR_STALLENA_Msk (1UL << ITM_TCR_STALLENA_Pos) /*!< ITM TCR: STALLENA Mask */ + +#define ITM_TCR_SWOENA_Pos 4U /*!< ITM TCR: SWOENA Position */ +#define ITM_TCR_SWOENA_Msk (1UL << ITM_TCR_SWOENA_Pos) /*!< ITM TCR: SWOENA Mask */ + +#define ITM_TCR_DWTENA_Pos 3U /*!< ITM TCR: DWTENA Position */ +#define ITM_TCR_DWTENA_Msk (1UL << ITM_TCR_DWTENA_Pos) /*!< ITM TCR: DWTENA Mask */ + +#define ITM_TCR_SYNCENA_Pos 2U /*!< ITM TCR: SYNCENA Position */ +#define ITM_TCR_SYNCENA_Msk (1UL << ITM_TCR_SYNCENA_Pos) /*!< ITM TCR: SYNCENA Mask */ + +#define ITM_TCR_TSENA_Pos 1U /*!< ITM TCR: TSENA Position */ +#define ITM_TCR_TSENA_Msk (1UL << ITM_TCR_TSENA_Pos) /*!< ITM TCR: TSENA Mask */ + +#define ITM_TCR_ITMENA_Pos 0U /*!< ITM TCR: ITM Enable bit Position */ +#define ITM_TCR_ITMENA_Msk (1UL /*<< ITM_TCR_ITMENA_Pos*/) /*!< ITM TCR: ITM Enable bit Mask */ + +/* ITM Integration Write Register Definitions */ +#define ITM_IWR_ATVALIDM_Pos 0U /*!< ITM IWR: ATVALIDM Position */ +#define ITM_IWR_ATVALIDM_Msk (1UL /*<< ITM_IWR_ATVALIDM_Pos*/) /*!< ITM IWR: ATVALIDM Mask */ + +/* ITM Integration Read Register Definitions */ +#define ITM_IRR_ATREADYM_Pos 0U /*!< ITM IRR: ATREADYM Position */ +#define ITM_IRR_ATREADYM_Msk (1UL /*<< ITM_IRR_ATREADYM_Pos*/) /*!< ITM IRR: ATREADYM Mask */ + +/* ITM Integration Mode Control Register Definitions */ +#define ITM_IMCR_INTEGRATION_Pos 0U /*!< ITM IMCR: INTEGRATION Position */ +#define ITM_IMCR_INTEGRATION_Msk (1UL /*<< ITM_IMCR_INTEGRATION_Pos*/) /*!< ITM IMCR: INTEGRATION Mask */ + +/* ITM Lock Status Register Definitions */ +#define ITM_LSR_ByteAcc_Pos 2U /*!< ITM LSR: ByteAcc Position */ +#define ITM_LSR_ByteAcc_Msk (1UL << ITM_LSR_ByteAcc_Pos) /*!< ITM LSR: ByteAcc Mask */ + +#define ITM_LSR_Access_Pos 1U /*!< ITM LSR: Access Position */ +#define ITM_LSR_Access_Msk (1UL << ITM_LSR_Access_Pos) /*!< ITM LSR: Access Mask */ + +#define ITM_LSR_Present_Pos 0U /*!< ITM LSR: Present Position */ +#define ITM_LSR_Present_Msk (1UL /*<< ITM_LSR_Present_Pos*/) /*!< ITM LSR: Present Mask */ + +/*@}*/ /* end of group CMSIS_ITM */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_DWT Data Watchpoint and Trace (DWT) + \brief Type definitions for the Data Watchpoint and Trace (DWT) + @{ + */ + +/** + \brief Structure type to access the Data Watchpoint and Trace Register (DWT). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) Control Register */ + __IOM uint32_t CYCCNT; /*!< Offset: 0x004 (R/W) Cycle Count Register */ + __IOM uint32_t CPICNT; /*!< Offset: 0x008 (R/W) CPI Count Register */ + __IOM uint32_t EXCCNT; /*!< Offset: 0x00C (R/W) Exception Overhead Count Register */ + __IOM uint32_t SLEEPCNT; /*!< Offset: 0x010 (R/W) Sleep Count Register */ + __IOM uint32_t LSUCNT; /*!< Offset: 0x014 (R/W) LSU Count Register */ + __IOM uint32_t FOLDCNT; /*!< Offset: 0x018 (R/W) Folded-instruction Count Register */ + __IM uint32_t PCSR; /*!< Offset: 0x01C (R/ ) Program Counter Sample Register */ + __IOM uint32_t COMP0; /*!< Offset: 0x020 (R/W) Comparator Register 0 */ + uint32_t RESERVED1[1U]; + __IOM uint32_t FUNCTION0; /*!< Offset: 0x028 (R/W) Function Register 0 */ + uint32_t RESERVED2[1U]; + __IOM uint32_t COMP1; /*!< Offset: 0x030 (R/W) Comparator Register 1 */ + uint32_t RESERVED3[1U]; + __IOM uint32_t FUNCTION1; /*!< Offset: 0x038 (R/W) Function Register 1 */ + uint32_t RESERVED4[1U]; + __IOM uint32_t COMP2; /*!< Offset: 0x040 (R/W) Comparator Register 2 */ + uint32_t RESERVED5[1U]; + __IOM uint32_t FUNCTION2; /*!< Offset: 0x048 (R/W) Function Register 2 */ + uint32_t RESERVED6[1U]; + __IOM uint32_t COMP3; /*!< Offset: 0x050 (R/W) Comparator Register 3 */ + uint32_t RESERVED7[1U]; + __IOM uint32_t FUNCTION3; /*!< Offset: 0x058 (R/W) Function Register 3 */ + uint32_t RESERVED8[1U]; + __IOM uint32_t COMP4; /*!< Offset: 0x060 (R/W) Comparator Register 4 */ + uint32_t RESERVED9[1U]; + __IOM uint32_t FUNCTION4; /*!< Offset: 0x068 (R/W) Function Register 4 */ + uint32_t RESERVED10[1U]; + __IOM uint32_t COMP5; /*!< Offset: 0x070 (R/W) Comparator Register 5 */ + uint32_t RESERVED11[1U]; + __IOM uint32_t FUNCTION5; /*!< Offset: 0x078 (R/W) Function Register 5 */ + uint32_t RESERVED12[1U]; + __IOM uint32_t COMP6; /*!< Offset: 0x080 (R/W) Comparator Register 6 */ + uint32_t RESERVED13[1U]; + __IOM uint32_t FUNCTION6; /*!< Offset: 0x088 (R/W) Function Register 6 */ + uint32_t RESERVED14[1U]; + __IOM uint32_t COMP7; /*!< Offset: 0x090 (R/W) Comparator Register 7 */ + uint32_t RESERVED15[1U]; + __IOM uint32_t FUNCTION7; /*!< Offset: 0x098 (R/W) Function Register 7 */ + uint32_t RESERVED16[1U]; + __IOM uint32_t COMP8; /*!< Offset: 0x0A0 (R/W) Comparator Register 8 */ + uint32_t RESERVED17[1U]; + __IOM uint32_t FUNCTION8; /*!< Offset: 0x0A8 (R/W) Function Register 8 */ + uint32_t RESERVED18[1U]; + __IOM uint32_t COMP9; /*!< Offset: 0x0B0 (R/W) Comparator Register 9 */ + uint32_t RESERVED19[1U]; + __IOM uint32_t FUNCTION9; /*!< Offset: 0x0B8 (R/W) Function Register 9 */ + uint32_t RESERVED20[1U]; + __IOM uint32_t COMP10; /*!< Offset: 0x0C0 (R/W) Comparator Register 10 */ + uint32_t RESERVED21[1U]; + __IOM uint32_t FUNCTION10; /*!< Offset: 0x0C8 (R/W) Function Register 10 */ + uint32_t RESERVED22[1U]; + __IOM uint32_t COMP11; /*!< Offset: 0x0D0 (R/W) Comparator Register 11 */ + uint32_t RESERVED23[1U]; + __IOM uint32_t FUNCTION11; /*!< Offset: 0x0D8 (R/W) Function Register 11 */ + uint32_t RESERVED24[1U]; + __IOM uint32_t COMP12; /*!< Offset: 0x0E0 (R/W) Comparator Register 12 */ + uint32_t RESERVED25[1U]; + __IOM uint32_t FUNCTION12; /*!< Offset: 0x0E8 (R/W) Function Register 12 */ + uint32_t RESERVED26[1U]; + __IOM uint32_t COMP13; /*!< Offset: 0x0F0 (R/W) Comparator Register 13 */ + uint32_t RESERVED27[1U]; + __IOM uint32_t FUNCTION13; /*!< Offset: 0x0F8 (R/W) Function Register 13 */ + uint32_t RESERVED28[1U]; + __IOM uint32_t COMP14; /*!< Offset: 0x100 (R/W) Comparator Register 14 */ + uint32_t RESERVED29[1U]; + __IOM uint32_t FUNCTION14; /*!< Offset: 0x108 (R/W) Function Register 14 */ + uint32_t RESERVED30[1U]; + __IOM uint32_t COMP15; /*!< Offset: 0x110 (R/W) Comparator Register 15 */ + uint32_t RESERVED31[1U]; + __IOM uint32_t FUNCTION15; /*!< Offset: 0x118 (R/W) Function Register 15 */ + uint32_t RESERVED32[934U]; + __IM uint32_t LSR; /*!< Offset: 0xFB4 (R ) Lock Status Register */ + uint32_t RESERVED33[1U]; + __IM uint32_t DEVARCH; /*!< Offset: 0xFBC (R/ ) Device Architecture Register */ +} DWT_Type; + +/* DWT Control Register Definitions */ +#define DWT_CTRL_NUMCOMP_Pos 28U /*!< DWT CTRL: NUMCOMP Position */ +#define DWT_CTRL_NUMCOMP_Msk (0xFUL << DWT_CTRL_NUMCOMP_Pos) /*!< DWT CTRL: NUMCOMP Mask */ + +#define DWT_CTRL_NOTRCPKT_Pos 27U /*!< DWT CTRL: NOTRCPKT Position */ +#define DWT_CTRL_NOTRCPKT_Msk (0x1UL << DWT_CTRL_NOTRCPKT_Pos) /*!< DWT CTRL: NOTRCPKT Mask */ + +#define DWT_CTRL_NOEXTTRIG_Pos 26U /*!< DWT CTRL: NOEXTTRIG Position */ +#define DWT_CTRL_NOEXTTRIG_Msk (0x1UL << DWT_CTRL_NOEXTTRIG_Pos) /*!< DWT CTRL: NOEXTTRIG Mask */ + +#define DWT_CTRL_NOCYCCNT_Pos 25U /*!< DWT CTRL: NOCYCCNT Position */ +#define DWT_CTRL_NOCYCCNT_Msk (0x1UL << DWT_CTRL_NOCYCCNT_Pos) /*!< DWT CTRL: NOCYCCNT Mask */ + +#define DWT_CTRL_NOPRFCNT_Pos 24U /*!< DWT CTRL: NOPRFCNT Position */ +#define DWT_CTRL_NOPRFCNT_Msk (0x1UL << DWT_CTRL_NOPRFCNT_Pos) /*!< DWT CTRL: NOPRFCNT Mask */ + +#define DWT_CTRL_CYCDISS_Pos 23U /*!< DWT CTRL: CYCDISS Position */ +#define DWT_CTRL_CYCDISS_Msk (0x1UL << DWT_CTRL_CYCDISS_Pos) /*!< DWT CTRL: CYCDISS Mask */ + +#define DWT_CTRL_CYCEVTENA_Pos 22U /*!< DWT CTRL: CYCEVTENA Position */ +#define DWT_CTRL_CYCEVTENA_Msk (0x1UL << DWT_CTRL_CYCEVTENA_Pos) /*!< DWT CTRL: CYCEVTENA Mask */ + +#define DWT_CTRL_FOLDEVTENA_Pos 21U /*!< DWT CTRL: FOLDEVTENA Position */ +#define DWT_CTRL_FOLDEVTENA_Msk (0x1UL << DWT_CTRL_FOLDEVTENA_Pos) /*!< DWT CTRL: FOLDEVTENA Mask */ + +#define DWT_CTRL_LSUEVTENA_Pos 20U /*!< DWT CTRL: LSUEVTENA Position */ +#define DWT_CTRL_LSUEVTENA_Msk (0x1UL << DWT_CTRL_LSUEVTENA_Pos) /*!< DWT CTRL: LSUEVTENA Mask */ + +#define DWT_CTRL_SLEEPEVTENA_Pos 19U /*!< DWT CTRL: SLEEPEVTENA Position */ +#define DWT_CTRL_SLEEPEVTENA_Msk (0x1UL << DWT_CTRL_SLEEPEVTENA_Pos) /*!< DWT CTRL: SLEEPEVTENA Mask */ + +#define DWT_CTRL_EXCEVTENA_Pos 18U /*!< DWT CTRL: EXCEVTENA Position */ +#define DWT_CTRL_EXCEVTENA_Msk (0x1UL << DWT_CTRL_EXCEVTENA_Pos) /*!< DWT CTRL: EXCEVTENA Mask */ + +#define DWT_CTRL_CPIEVTENA_Pos 17U /*!< DWT CTRL: CPIEVTENA Position */ +#define DWT_CTRL_CPIEVTENA_Msk (0x1UL << DWT_CTRL_CPIEVTENA_Pos) /*!< DWT CTRL: CPIEVTENA Mask */ + +#define DWT_CTRL_EXCTRCENA_Pos 16U /*!< DWT CTRL: EXCTRCENA Position */ +#define DWT_CTRL_EXCTRCENA_Msk (0x1UL << DWT_CTRL_EXCTRCENA_Pos) /*!< DWT CTRL: EXCTRCENA Mask */ + +#define DWT_CTRL_PCSAMPLENA_Pos 12U /*!< DWT CTRL: PCSAMPLENA Position */ +#define DWT_CTRL_PCSAMPLENA_Msk (0x1UL << DWT_CTRL_PCSAMPLENA_Pos) /*!< DWT CTRL: PCSAMPLENA Mask */ + +#define DWT_CTRL_SYNCTAP_Pos 10U /*!< DWT CTRL: SYNCTAP Position */ +#define DWT_CTRL_SYNCTAP_Msk (0x3UL << DWT_CTRL_SYNCTAP_Pos) /*!< DWT CTRL: SYNCTAP Mask */ + +#define DWT_CTRL_CYCTAP_Pos 9U /*!< DWT CTRL: CYCTAP Position */ +#define DWT_CTRL_CYCTAP_Msk (0x1UL << DWT_CTRL_CYCTAP_Pos) /*!< DWT CTRL: CYCTAP Mask */ + +#define DWT_CTRL_POSTINIT_Pos 5U /*!< DWT CTRL: POSTINIT Position */ +#define DWT_CTRL_POSTINIT_Msk (0xFUL << DWT_CTRL_POSTINIT_Pos) /*!< DWT CTRL: POSTINIT Mask */ + +#define DWT_CTRL_POSTPRESET_Pos 1U /*!< DWT CTRL: POSTPRESET Position */ +#define DWT_CTRL_POSTPRESET_Msk (0xFUL << DWT_CTRL_POSTPRESET_Pos) /*!< DWT CTRL: POSTPRESET Mask */ + +#define DWT_CTRL_CYCCNTENA_Pos 0U /*!< DWT CTRL: CYCCNTENA Position */ +#define DWT_CTRL_CYCCNTENA_Msk (0x1UL /*<< DWT_CTRL_CYCCNTENA_Pos*/) /*!< DWT CTRL: CYCCNTENA Mask */ + +/* DWT CPI Count Register Definitions */ +#define DWT_CPICNT_CPICNT_Pos 0U /*!< DWT CPICNT: CPICNT Position */ +#define DWT_CPICNT_CPICNT_Msk (0xFFUL /*<< DWT_CPICNT_CPICNT_Pos*/) /*!< DWT CPICNT: CPICNT Mask */ + +/* DWT Exception Overhead Count Register Definitions */ +#define DWT_EXCCNT_EXCCNT_Pos 0U /*!< DWT EXCCNT: EXCCNT Position */ +#define DWT_EXCCNT_EXCCNT_Msk (0xFFUL /*<< DWT_EXCCNT_EXCCNT_Pos*/) /*!< DWT EXCCNT: EXCCNT Mask */ + +/* DWT Sleep Count Register Definitions */ +#define DWT_SLEEPCNT_SLEEPCNT_Pos 0U /*!< DWT SLEEPCNT: SLEEPCNT Position */ +#define DWT_SLEEPCNT_SLEEPCNT_Msk (0xFFUL /*<< DWT_SLEEPCNT_SLEEPCNT_Pos*/) /*!< DWT SLEEPCNT: SLEEPCNT Mask */ + +/* DWT LSU Count Register Definitions */ +#define DWT_LSUCNT_LSUCNT_Pos 0U /*!< DWT LSUCNT: LSUCNT Position */ +#define DWT_LSUCNT_LSUCNT_Msk (0xFFUL /*<< DWT_LSUCNT_LSUCNT_Pos*/) /*!< DWT LSUCNT: LSUCNT Mask */ + +/* DWT Folded-instruction Count Register Definitions */ +#define DWT_FOLDCNT_FOLDCNT_Pos 0U /*!< DWT FOLDCNT: FOLDCNT Position */ +#define DWT_FOLDCNT_FOLDCNT_Msk (0xFFUL /*<< DWT_FOLDCNT_FOLDCNT_Pos*/) /*!< DWT FOLDCNT: FOLDCNT Mask */ + +/* DWT Comparator Function Register Definitions */ +#define DWT_FUNCTION_ID_Pos 27U /*!< DWT FUNCTION: ID Position */ +#define DWT_FUNCTION_ID_Msk (0x1FUL << DWT_FUNCTION_ID_Pos) /*!< DWT FUNCTION: ID Mask */ + +#define DWT_FUNCTION_MATCHED_Pos 24U /*!< DWT FUNCTION: MATCHED Position */ +#define DWT_FUNCTION_MATCHED_Msk (0x1UL << DWT_FUNCTION_MATCHED_Pos) /*!< DWT FUNCTION: MATCHED Mask */ + +#define DWT_FUNCTION_DATAVSIZE_Pos 10U /*!< DWT FUNCTION: DATAVSIZE Position */ +#define DWT_FUNCTION_DATAVSIZE_Msk (0x3UL << DWT_FUNCTION_DATAVSIZE_Pos) /*!< DWT FUNCTION: DATAVSIZE Mask */ + +#define DWT_FUNCTION_ACTION_Pos 4U /*!< DWT FUNCTION: ACTION Position */ +#define DWT_FUNCTION_ACTION_Msk (0x1UL << DWT_FUNCTION_ACTION_Pos) /*!< DWT FUNCTION: ACTION Mask */ + +#define DWT_FUNCTION_MATCH_Pos 0U /*!< DWT FUNCTION: MATCH Position */ +#define DWT_FUNCTION_MATCH_Msk (0xFUL /*<< DWT_FUNCTION_MATCH_Pos*/) /*!< DWT FUNCTION: MATCH Mask */ + +/*@}*/ /* end of group CMSIS_DWT */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_TPI Trace Port Interface (TPI) + \brief Type definitions for the Trace Port Interface (TPI) + @{ + */ + +/** + \brief Structure type to access the Trace Port Interface Register (TPI). + */ +typedef struct +{ + __IM uint32_t SSPSR; /*!< Offset: 0x000 (R/ ) Supported Parallel Port Sizes Register */ + __IOM uint32_t CSPSR; /*!< Offset: 0x004 (R/W) Current Parallel Port Sizes Register */ + uint32_t RESERVED0[2U]; + __IOM uint32_t ACPR; /*!< Offset: 0x010 (R/W) Asynchronous Clock Prescaler Register */ + uint32_t RESERVED1[55U]; + __IOM uint32_t SPPR; /*!< Offset: 0x0F0 (R/W) Selected Pin Protocol Register */ + uint32_t RESERVED2[131U]; + __IM uint32_t FFSR; /*!< Offset: 0x300 (R/ ) Formatter and Flush Status Register */ + __IOM uint32_t FFCR; /*!< Offset: 0x304 (R/W) Formatter and Flush Control Register */ + __IM uint32_t FSCR; /*!< Offset: 0x308 (R/ ) Formatter Synchronization Counter Register */ + uint32_t RESERVED3[759U]; + __IM uint32_t TRIGGER; /*!< Offset: 0xEE8 (R/ ) TRIGGER */ + __IM uint32_t FIFO0; /*!< Offset: 0xEEC (R/ ) Integration ETM Data */ + __IM uint32_t ITATBCTR2; /*!< Offset: 0xEF0 (R/ ) ITATBCTR2 */ + uint32_t RESERVED4[1U]; + __IM uint32_t ITATBCTR0; /*!< Offset: 0xEF8 (R/ ) ITATBCTR0 */ + __IM uint32_t FIFO1; /*!< Offset: 0xEFC (R/ ) Integration ITM Data */ + __IOM uint32_t ITCTRL; /*!< Offset: 0xF00 (R/W) Integration Mode Control */ + uint32_t RESERVED5[39U]; + __IOM uint32_t CLAIMSET; /*!< Offset: 0xFA0 (R/W) Claim tag set */ + __IOM uint32_t CLAIMCLR; /*!< Offset: 0xFA4 (R/W) Claim tag clear */ + uint32_t RESERVED7[8U]; + __IM uint32_t DEVID; /*!< Offset: 0xFC8 (R/ ) TPIU_DEVID */ + __IM uint32_t DEVTYPE; /*!< Offset: 0xFCC (R/ ) TPIU_DEVTYPE */ +} TPI_Type; + +/* TPI Asynchronous Clock Prescaler Register Definitions */ +#define TPI_ACPR_PRESCALER_Pos 0U /*!< TPI ACPR: PRESCALER Position */ +#define TPI_ACPR_PRESCALER_Msk (0x1FFFUL /*<< TPI_ACPR_PRESCALER_Pos*/) /*!< TPI ACPR: PRESCALER Mask */ + +/* TPI Selected Pin Protocol Register Definitions */ +#define TPI_SPPR_TXMODE_Pos 0U /*!< TPI SPPR: TXMODE Position */ +#define TPI_SPPR_TXMODE_Msk (0x3UL /*<< TPI_SPPR_TXMODE_Pos*/) /*!< TPI SPPR: TXMODE Mask */ + +/* TPI Formatter and Flush Status Register Definitions */ +#define TPI_FFSR_FtNonStop_Pos 3U /*!< TPI FFSR: FtNonStop Position */ +#define TPI_FFSR_FtNonStop_Msk (0x1UL << TPI_FFSR_FtNonStop_Pos) /*!< TPI FFSR: FtNonStop Mask */ + +#define TPI_FFSR_TCPresent_Pos 2U /*!< TPI FFSR: TCPresent Position */ +#define TPI_FFSR_TCPresent_Msk (0x1UL << TPI_FFSR_TCPresent_Pos) /*!< TPI FFSR: TCPresent Mask */ + +#define TPI_FFSR_FtStopped_Pos 1U /*!< TPI FFSR: FtStopped Position */ +#define TPI_FFSR_FtStopped_Msk (0x1UL << TPI_FFSR_FtStopped_Pos) /*!< TPI FFSR: FtStopped Mask */ + +#define TPI_FFSR_FlInProg_Pos 0U /*!< TPI FFSR: FlInProg Position */ +#define TPI_FFSR_FlInProg_Msk (0x1UL /*<< TPI_FFSR_FlInProg_Pos*/) /*!< TPI FFSR: FlInProg Mask */ + +/* TPI Formatter and Flush Control Register Definitions */ +#define TPI_FFCR_TrigIn_Pos 8U /*!< TPI FFCR: TrigIn Position */ +#define TPI_FFCR_TrigIn_Msk (0x1UL << TPI_FFCR_TrigIn_Pos) /*!< TPI FFCR: TrigIn Mask */ + +#define TPI_FFCR_EnFCont_Pos 1U /*!< TPI FFCR: EnFCont Position */ +#define TPI_FFCR_EnFCont_Msk (0x1UL << TPI_FFCR_EnFCont_Pos) /*!< TPI FFCR: EnFCont Mask */ + +/* TPI TRIGGER Register Definitions */ +#define TPI_TRIGGER_TRIGGER_Pos 0U /*!< TPI TRIGGER: TRIGGER Position */ +#define TPI_TRIGGER_TRIGGER_Msk (0x1UL /*<< TPI_TRIGGER_TRIGGER_Pos*/) /*!< TPI TRIGGER: TRIGGER Mask */ + +/* TPI Integration ETM Data Register Definitions (FIFO0) */ +#define TPI_FIFO0_ITM_ATVALID_Pos 29U /*!< TPI FIFO0: ITM_ATVALID Position */ +#define TPI_FIFO0_ITM_ATVALID_Msk (0x3UL << TPI_FIFO0_ITM_ATVALID_Pos) /*!< TPI FIFO0: ITM_ATVALID Mask */ + +#define TPI_FIFO0_ITM_bytecount_Pos 27U /*!< TPI FIFO0: ITM_bytecount Position */ +#define TPI_FIFO0_ITM_bytecount_Msk (0x3UL << TPI_FIFO0_ITM_bytecount_Pos) /*!< TPI FIFO0: ITM_bytecount Mask */ + +#define TPI_FIFO0_ETM_ATVALID_Pos 26U /*!< TPI FIFO0: ETM_ATVALID Position */ +#define TPI_FIFO0_ETM_ATVALID_Msk (0x3UL << TPI_FIFO0_ETM_ATVALID_Pos) /*!< TPI FIFO0: ETM_ATVALID Mask */ + +#define TPI_FIFO0_ETM_bytecount_Pos 24U /*!< TPI FIFO0: ETM_bytecount Position */ +#define TPI_FIFO0_ETM_bytecount_Msk (0x3UL << TPI_FIFO0_ETM_bytecount_Pos) /*!< TPI FIFO0: ETM_bytecount Mask */ + +#define TPI_FIFO0_ETM2_Pos 16U /*!< TPI FIFO0: ETM2 Position */ +#define TPI_FIFO0_ETM2_Msk (0xFFUL << TPI_FIFO0_ETM2_Pos) /*!< TPI FIFO0: ETM2 Mask */ + +#define TPI_FIFO0_ETM1_Pos 8U /*!< TPI FIFO0: ETM1 Position */ +#define TPI_FIFO0_ETM1_Msk (0xFFUL << TPI_FIFO0_ETM1_Pos) /*!< TPI FIFO0: ETM1 Mask */ + +#define TPI_FIFO0_ETM0_Pos 0U /*!< TPI FIFO0: ETM0 Position */ +#define TPI_FIFO0_ETM0_Msk (0xFFUL /*<< TPI_FIFO0_ETM0_Pos*/) /*!< TPI FIFO0: ETM0 Mask */ + +/* TPI ITATBCTR2 Register Definitions */ +#define TPI_ITATBCTR2_ATREADY_Pos 0U /*!< TPI ITATBCTR2: ATREADY Position */ +#define TPI_ITATBCTR2_ATREADY_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY_Pos*/) /*!< TPI ITATBCTR2: ATREADY Mask */ + +/* TPI Integration ITM Data Register Definitions (FIFO1) */ +#define TPI_FIFO1_ITM_ATVALID_Pos 29U /*!< TPI FIFO1: ITM_ATVALID Position */ +#define TPI_FIFO1_ITM_ATVALID_Msk (0x3UL << TPI_FIFO1_ITM_ATVALID_Pos) /*!< TPI FIFO1: ITM_ATVALID Mask */ + +#define TPI_FIFO1_ITM_bytecount_Pos 27U /*!< TPI FIFO1: ITM_bytecount Position */ +#define TPI_FIFO1_ITM_bytecount_Msk (0x3UL << TPI_FIFO1_ITM_bytecount_Pos) /*!< TPI FIFO1: ITM_bytecount Mask */ + +#define TPI_FIFO1_ETM_ATVALID_Pos 26U /*!< TPI FIFO1: ETM_ATVALID Position */ +#define TPI_FIFO1_ETM_ATVALID_Msk (0x3UL << TPI_FIFO1_ETM_ATVALID_Pos) /*!< TPI FIFO1: ETM_ATVALID Mask */ + +#define TPI_FIFO1_ETM_bytecount_Pos 24U /*!< TPI FIFO1: ETM_bytecount Position */ +#define TPI_FIFO1_ETM_bytecount_Msk (0x3UL << TPI_FIFO1_ETM_bytecount_Pos) /*!< TPI FIFO1: ETM_bytecount Mask */ + +#define TPI_FIFO1_ITM2_Pos 16U /*!< TPI FIFO1: ITM2 Position */ +#define TPI_FIFO1_ITM2_Msk (0xFFUL << TPI_FIFO1_ITM2_Pos) /*!< TPI FIFO1: ITM2 Mask */ + +#define TPI_FIFO1_ITM1_Pos 8U /*!< TPI FIFO1: ITM1 Position */ +#define TPI_FIFO1_ITM1_Msk (0xFFUL << TPI_FIFO1_ITM1_Pos) /*!< TPI FIFO1: ITM1 Mask */ + +#define TPI_FIFO1_ITM0_Pos 0U /*!< TPI FIFO1: ITM0 Position */ +#define TPI_FIFO1_ITM0_Msk (0xFFUL /*<< TPI_FIFO1_ITM0_Pos*/) /*!< TPI FIFO1: ITM0 Mask */ + +/* TPI ITATBCTR0 Register Definitions */ +#define TPI_ITATBCTR0_ATREADY_Pos 0U /*!< TPI ITATBCTR0: ATREADY Position */ +#define TPI_ITATBCTR0_ATREADY_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY_Pos*/) /*!< TPI ITATBCTR0: ATREADY Mask */ + +/* TPI Integration Mode Control Register Definitions */ +#define TPI_ITCTRL_Mode_Pos 0U /*!< TPI ITCTRL: Mode Position */ +#define TPI_ITCTRL_Mode_Msk (0x1UL /*<< TPI_ITCTRL_Mode_Pos*/) /*!< TPI ITCTRL: Mode Mask */ + +/* TPI DEVID Register Definitions */ +#define TPI_DEVID_NRZVALID_Pos 11U /*!< TPI DEVID: NRZVALID Position */ +#define TPI_DEVID_NRZVALID_Msk (0x1UL << TPI_DEVID_NRZVALID_Pos) /*!< TPI DEVID: NRZVALID Mask */ + +#define TPI_DEVID_MANCVALID_Pos 10U /*!< TPI DEVID: MANCVALID Position */ +#define TPI_DEVID_MANCVALID_Msk (0x1UL << TPI_DEVID_MANCVALID_Pos) /*!< TPI DEVID: MANCVALID Mask */ + +#define TPI_DEVID_PTINVALID_Pos 9U /*!< TPI DEVID: PTINVALID Position */ +#define TPI_DEVID_PTINVALID_Msk (0x1UL << TPI_DEVID_PTINVALID_Pos) /*!< TPI DEVID: PTINVALID Mask */ + +#define TPI_DEVID_MinBufSz_Pos 6U /*!< TPI DEVID: MinBufSz Position */ +#define TPI_DEVID_MinBufSz_Msk (0x7UL << TPI_DEVID_MinBufSz_Pos) /*!< TPI DEVID: MinBufSz Mask */ + +#define TPI_DEVID_AsynClkIn_Pos 5U /*!< TPI DEVID: AsynClkIn Position */ +#define TPI_DEVID_AsynClkIn_Msk (0x1UL << TPI_DEVID_AsynClkIn_Pos) /*!< TPI DEVID: AsynClkIn Mask */ + +#define TPI_DEVID_NrTraceInput_Pos 0U /*!< TPI DEVID: NrTraceInput Position */ +#define TPI_DEVID_NrTraceInput_Msk (0x1FUL /*<< TPI_DEVID_NrTraceInput_Pos*/) /*!< TPI DEVID: NrTraceInput Mask */ + +/* TPI DEVTYPE Register Definitions */ +#define TPI_DEVTYPE_MajorType_Pos 4U /*!< TPI DEVTYPE: MajorType Position */ +#define TPI_DEVTYPE_MajorType_Msk (0xFUL << TPI_DEVTYPE_MajorType_Pos) /*!< TPI DEVTYPE: MajorType Mask */ + +#define TPI_DEVTYPE_SubType_Pos 0U /*!< TPI DEVTYPE: SubType Position */ +#define TPI_DEVTYPE_SubType_Msk (0xFUL /*<< TPI_DEVTYPE_SubType_Pos*/) /*!< TPI DEVTYPE: SubType Mask */ + +/*@}*/ /* end of group CMSIS_TPI */ + + +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_MPU Memory Protection Unit (MPU) + \brief Type definitions for the Memory Protection Unit (MPU) + @{ + */ + +/** + \brief Structure type to access the Memory Protection Unit (MPU). + */ +typedef struct +{ + __IM uint32_t TYPE; /*!< Offset: 0x000 (R/ ) MPU Type Register */ + __IOM uint32_t CTRL; /*!< Offset: 0x004 (R/W) MPU Control Register */ + __IOM uint32_t RNR; /*!< Offset: 0x008 (R/W) MPU Region Number Register */ + __IOM uint32_t RBAR; /*!< Offset: 0x00C (R/W) MPU Region Base Address Register */ + __IOM uint32_t RLAR; /*!< Offset: 0x010 (R/W) MPU Region Limit Address Register */ + __IOM uint32_t RBAR_A1; /*!< Offset: 0x014 (R/W) MPU Region Base Address Register Alias 1 */ + __IOM uint32_t RLAR_A1; /*!< Offset: 0x018 (R/W) MPU Region Limit Address Register Alias 1 */ + __IOM uint32_t RBAR_A2; /*!< Offset: 0x01C (R/W) MPU Region Base Address Register Alias 2 */ + __IOM uint32_t RLAR_A2; /*!< Offset: 0x020 (R/W) MPU Region Limit Address Register Alias 2 */ + __IOM uint32_t RBAR_A3; /*!< Offset: 0x024 (R/W) MPU Region Base Address Register Alias 3 */ + __IOM uint32_t RLAR_A3; /*!< Offset: 0x028 (R/W) MPU Region Limit Address Register Alias 3 */ + uint32_t RESERVED0[1]; + union { + __IOM uint32_t MAIR[2]; + struct { + __IOM uint32_t MAIR0; /*!< Offset: 0x030 (R/W) MPU Memory Attribute Indirection Register 0 */ + __IOM uint32_t MAIR1; /*!< Offset: 0x034 (R/W) MPU Memory Attribute Indirection Register 1 */ + }; + }; +} MPU_Type; + +#define MPU_TYPE_RALIASES 4U + +/* MPU Type Register Definitions */ +#define MPU_TYPE_IREGION_Pos 16U /*!< MPU TYPE: IREGION Position */ +#define MPU_TYPE_IREGION_Msk (0xFFUL << MPU_TYPE_IREGION_Pos) /*!< MPU TYPE: IREGION Mask */ + +#define MPU_TYPE_DREGION_Pos 8U /*!< MPU TYPE: DREGION Position */ +#define MPU_TYPE_DREGION_Msk (0xFFUL << MPU_TYPE_DREGION_Pos) /*!< MPU TYPE: DREGION Mask */ + +#define MPU_TYPE_SEPARATE_Pos 0U /*!< MPU TYPE: SEPARATE Position */ +#define MPU_TYPE_SEPARATE_Msk (1UL /*<< MPU_TYPE_SEPARATE_Pos*/) /*!< MPU TYPE: SEPARATE Mask */ + +/* MPU Control Register Definitions */ +#define MPU_CTRL_PRIVDEFENA_Pos 2U /*!< MPU CTRL: PRIVDEFENA Position */ +#define MPU_CTRL_PRIVDEFENA_Msk (1UL << MPU_CTRL_PRIVDEFENA_Pos) /*!< MPU CTRL: PRIVDEFENA Mask */ + +#define MPU_CTRL_HFNMIENA_Pos 1U /*!< MPU CTRL: HFNMIENA Position */ +#define MPU_CTRL_HFNMIENA_Msk (1UL << MPU_CTRL_HFNMIENA_Pos) /*!< MPU CTRL: HFNMIENA Mask */ + +#define MPU_CTRL_ENABLE_Pos 0U /*!< MPU CTRL: ENABLE Position */ +#define MPU_CTRL_ENABLE_Msk (1UL /*<< MPU_CTRL_ENABLE_Pos*/) /*!< MPU CTRL: ENABLE Mask */ + +/* MPU Region Number Register Definitions */ +#define MPU_RNR_REGION_Pos 0U /*!< MPU RNR: REGION Position */ +#define MPU_RNR_REGION_Msk (0xFFUL /*<< MPU_RNR_REGION_Pos*/) /*!< MPU RNR: REGION Mask */ + +/* MPU Region Base Address Register Definitions */ +#define MPU_RBAR_ADDR_Pos 5U /*!< MPU RBAR: ADDR Position */ +#define MPU_RBAR_ADDR_Msk (0x7FFFFFFUL << MPU_RBAR_ADDR_Pos) /*!< MPU RBAR: ADDR Mask */ + +#define MPU_RBAR_SH_Pos 3U /*!< MPU RBAR: SH Position */ +#define MPU_RBAR_SH_Msk (0x3UL << MPU_RBAR_SH_Pos) /*!< MPU RBAR: SH Mask */ + +#define MPU_RBAR_AP_Pos 1U /*!< MPU RBAR: AP Position */ +#define MPU_RBAR_AP_Msk (0x3UL << MPU_RBAR_AP_Pos) /*!< MPU RBAR: AP Mask */ + +#define MPU_RBAR_XN_Pos 0U /*!< MPU RBAR: XN Position */ +#define MPU_RBAR_XN_Msk (01UL /*<< MPU_RBAR_XN_Pos*/) /*!< MPU RBAR: XN Mask */ + +/* MPU Region Limit Address Register Definitions */ +#define MPU_RLAR_LIMIT_Pos 5U /*!< MPU RLAR: LIMIT Position */ +#define MPU_RLAR_LIMIT_Msk (0x7FFFFFFUL << MPU_RLAR_LIMIT_Pos) /*!< MPU RLAR: LIMIT Mask */ + +#define MPU_RLAR_PXN_Pos 4U /*!< MPU RLAR: PXN Position */ +#define MPU_RLAR_PXN_Msk (0x1UL << MPU_RLAR_PXN_Pos) /*!< MPU RLAR: PXN Mask */ + +#define MPU_RLAR_AttrIndx_Pos 1U /*!< MPU RLAR: AttrIndx Position */ +#define MPU_RLAR_AttrIndx_Msk (0x7UL << MPU_RLAR_AttrIndx_Pos) /*!< MPU RLAR: AttrIndx Mask */ + +#define MPU_RLAR_EN_Pos 0U /*!< MPU RLAR: Region enable bit Position */ +#define MPU_RLAR_EN_Msk (1UL /*<< MPU_RLAR_EN_Pos*/) /*!< MPU RLAR: Region enable bit Disable Mask */ + +/* MPU Memory Attribute Indirection Register 0 Definitions */ +#define MPU_MAIR0_Attr3_Pos 24U /*!< MPU MAIR0: Attr3 Position */ +#define MPU_MAIR0_Attr3_Msk (0xFFUL << MPU_MAIR0_Attr3_Pos) /*!< MPU MAIR0: Attr3 Mask */ + +#define MPU_MAIR0_Attr2_Pos 16U /*!< MPU MAIR0: Attr2 Position */ +#define MPU_MAIR0_Attr2_Msk (0xFFUL << MPU_MAIR0_Attr2_Pos) /*!< MPU MAIR0: Attr2 Mask */ + +#define MPU_MAIR0_Attr1_Pos 8U /*!< MPU MAIR0: Attr1 Position */ +#define MPU_MAIR0_Attr1_Msk (0xFFUL << MPU_MAIR0_Attr1_Pos) /*!< MPU MAIR0: Attr1 Mask */ + +#define MPU_MAIR0_Attr0_Pos 0U /*!< MPU MAIR0: Attr0 Position */ +#define MPU_MAIR0_Attr0_Msk (0xFFUL /*<< MPU_MAIR0_Attr0_Pos*/) /*!< MPU MAIR0: Attr0 Mask */ + +/* MPU Memory Attribute Indirection Register 1 Definitions */ +#define MPU_MAIR1_Attr7_Pos 24U /*!< MPU MAIR1: Attr7 Position */ +#define MPU_MAIR1_Attr7_Msk (0xFFUL << MPU_MAIR1_Attr7_Pos) /*!< MPU MAIR1: Attr7 Mask */ + +#define MPU_MAIR1_Attr6_Pos 16U /*!< MPU MAIR1: Attr6 Position */ +#define MPU_MAIR1_Attr6_Msk (0xFFUL << MPU_MAIR1_Attr6_Pos) /*!< MPU MAIR1: Attr6 Mask */ + +#define MPU_MAIR1_Attr5_Pos 8U /*!< MPU MAIR1: Attr5 Position */ +#define MPU_MAIR1_Attr5_Msk (0xFFUL << MPU_MAIR1_Attr5_Pos) /*!< MPU MAIR1: Attr5 Mask */ + +#define MPU_MAIR1_Attr4_Pos 0U /*!< MPU MAIR1: Attr4 Position */ +#define MPU_MAIR1_Attr4_Msk (0xFFUL /*<< MPU_MAIR1_Attr4_Pos*/) /*!< MPU MAIR1: Attr4 Mask */ + +/*@} end of group CMSIS_MPU */ +#endif + + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SAU Security Attribution Unit (SAU) + \brief Type definitions for the Security Attribution Unit (SAU) + @{ + */ + +/** + \brief Structure type to access the Security Attribution Unit (SAU). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SAU Control Register */ + __IM uint32_t TYPE; /*!< Offset: 0x004 (R/ ) SAU Type Register */ +#if defined (__SAUREGION_PRESENT) && (__SAUREGION_PRESENT == 1U) + __IOM uint32_t RNR; /*!< Offset: 0x008 (R/W) SAU Region Number Register */ + __IOM uint32_t RBAR; /*!< Offset: 0x00C (R/W) SAU Region Base Address Register */ + __IOM uint32_t RLAR; /*!< Offset: 0x010 (R/W) SAU Region Limit Address Register */ +#else + uint32_t RESERVED0[3]; +#endif + __IOM uint32_t SFSR; /*!< Offset: 0x014 (R/W) Secure Fault Status Register */ + __IOM uint32_t SFAR; /*!< Offset: 0x018 (R/W) Secure Fault Address Register */ +} SAU_Type; + +/* SAU Control Register Definitions */ +#define SAU_CTRL_ALLNS_Pos 1U /*!< SAU CTRL: ALLNS Position */ +#define SAU_CTRL_ALLNS_Msk (1UL << SAU_CTRL_ALLNS_Pos) /*!< SAU CTRL: ALLNS Mask */ + +#define SAU_CTRL_ENABLE_Pos 0U /*!< SAU CTRL: ENABLE Position */ +#define SAU_CTRL_ENABLE_Msk (1UL /*<< SAU_CTRL_ENABLE_Pos*/) /*!< SAU CTRL: ENABLE Mask */ + +/* SAU Type Register Definitions */ +#define SAU_TYPE_SREGION_Pos 0U /*!< SAU TYPE: SREGION Position */ +#define SAU_TYPE_SREGION_Msk (0xFFUL /*<< SAU_TYPE_SREGION_Pos*/) /*!< SAU TYPE: SREGION Mask */ + +#if defined (__SAUREGION_PRESENT) && (__SAUREGION_PRESENT == 1U) +/* SAU Region Number Register Definitions */ +#define SAU_RNR_REGION_Pos 0U /*!< SAU RNR: REGION Position */ +#define SAU_RNR_REGION_Msk (0xFFUL /*<< SAU_RNR_REGION_Pos*/) /*!< SAU RNR: REGION Mask */ + +/* SAU Region Base Address Register Definitions */ +#define SAU_RBAR_BADDR_Pos 5U /*!< SAU RBAR: BADDR Position */ +#define SAU_RBAR_BADDR_Msk (0x7FFFFFFUL << SAU_RBAR_BADDR_Pos) /*!< SAU RBAR: BADDR Mask */ + +/* SAU Region Limit Address Register Definitions */ +#define SAU_RLAR_LADDR_Pos 5U /*!< SAU RLAR: LADDR Position */ +#define SAU_RLAR_LADDR_Msk (0x7FFFFFFUL << SAU_RLAR_LADDR_Pos) /*!< SAU RLAR: LADDR Mask */ + +#define SAU_RLAR_NSC_Pos 1U /*!< SAU RLAR: NSC Position */ +#define SAU_RLAR_NSC_Msk (1UL << SAU_RLAR_NSC_Pos) /*!< SAU RLAR: NSC Mask */ + +#define SAU_RLAR_ENABLE_Pos 0U /*!< SAU RLAR: ENABLE Position */ +#define SAU_RLAR_ENABLE_Msk (1UL /*<< SAU_RLAR_ENABLE_Pos*/) /*!< SAU RLAR: ENABLE Mask */ + +#endif /* defined (__SAUREGION_PRESENT) && (__SAUREGION_PRESENT == 1U) */ + +/* Secure Fault Status Register Definitions */ +#define SAU_SFSR_LSERR_Pos 7U /*!< SAU SFSR: LSERR Position */ +#define SAU_SFSR_LSERR_Msk (1UL << SAU_SFSR_LSERR_Pos) /*!< SAU SFSR: LSERR Mask */ + +#define SAU_SFSR_SFARVALID_Pos 6U /*!< SAU SFSR: SFARVALID Position */ +#define SAU_SFSR_SFARVALID_Msk (1UL << SAU_SFSR_SFARVALID_Pos) /*!< SAU SFSR: SFARVALID Mask */ + +#define SAU_SFSR_LSPERR_Pos 5U /*!< SAU SFSR: LSPERR Position */ +#define SAU_SFSR_LSPERR_Msk (1UL << SAU_SFSR_LSPERR_Pos) /*!< SAU SFSR: LSPERR Mask */ + +#define SAU_SFSR_INVTRAN_Pos 4U /*!< SAU SFSR: INVTRAN Position */ +#define SAU_SFSR_INVTRAN_Msk (1UL << SAU_SFSR_INVTRAN_Pos) /*!< SAU SFSR: INVTRAN Mask */ + +#define SAU_SFSR_AUVIOL_Pos 3U /*!< SAU SFSR: AUVIOL Position */ +#define SAU_SFSR_AUVIOL_Msk (1UL << SAU_SFSR_AUVIOL_Pos) /*!< SAU SFSR: AUVIOL Mask */ + +#define SAU_SFSR_INVER_Pos 2U /*!< SAU SFSR: INVER Position */ +#define SAU_SFSR_INVER_Msk (1UL << SAU_SFSR_INVER_Pos) /*!< SAU SFSR: INVER Mask */ + +#define SAU_SFSR_INVIS_Pos 1U /*!< SAU SFSR: INVIS Position */ +#define SAU_SFSR_INVIS_Msk (1UL << SAU_SFSR_INVIS_Pos) /*!< SAU SFSR: INVIS Mask */ + +#define SAU_SFSR_INVEP_Pos 0U /*!< SAU SFSR: INVEP Position */ +#define SAU_SFSR_INVEP_Msk (1UL /*<< SAU_SFSR_INVEP_Pos*/) /*!< SAU SFSR: INVEP Mask */ + +/*@} end of group CMSIS_SAU */ +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_FPU Floating Point Unit (FPU) + \brief Type definitions for the Floating Point Unit (FPU) + @{ + */ + +/** + \brief Structure type to access the Floating Point Unit (FPU). + */ +typedef struct +{ + uint32_t RESERVED0[1U]; + __IOM uint32_t FPCCR; /*!< Offset: 0x004 (R/W) Floating-Point Context Control Register */ + __IOM uint32_t FPCAR; /*!< Offset: 0x008 (R/W) Floating-Point Context Address Register */ + __IOM uint32_t FPDSCR; /*!< Offset: 0x00C (R/W) Floating-Point Default Status Control Register */ + __IM uint32_t MVFR0; /*!< Offset: 0x010 (R/ ) Media and FP Feature Register 0 */ + __IM uint32_t MVFR1; /*!< Offset: 0x014 (R/ ) Media and FP Feature Register 1 */ +} FPU_Type; + +/* Floating-Point Context Control Register Definitions */ +#define FPU_FPCCR_ASPEN_Pos 31U /*!< FPCCR: ASPEN bit Position */ +#define FPU_FPCCR_ASPEN_Msk (1UL << FPU_FPCCR_ASPEN_Pos) /*!< FPCCR: ASPEN bit Mask */ + +#define FPU_FPCCR_LSPEN_Pos 30U /*!< FPCCR: LSPEN Position */ +#define FPU_FPCCR_LSPEN_Msk (1UL << FPU_FPCCR_LSPEN_Pos) /*!< FPCCR: LSPEN bit Mask */ + +#define FPU_FPCCR_LSPENS_Pos 29U /*!< FPCCR: LSPENS Position */ +#define FPU_FPCCR_LSPENS_Msk (1UL << FPU_FPCCR_LSPENS_Pos) /*!< FPCCR: LSPENS bit Mask */ + +#define FPU_FPCCR_CLRONRET_Pos 28U /*!< FPCCR: CLRONRET Position */ +#define FPU_FPCCR_CLRONRET_Msk (1UL << FPU_FPCCR_CLRONRET_Pos) /*!< FPCCR: CLRONRET bit Mask */ + +#define FPU_FPCCR_CLRONRETS_Pos 27U /*!< FPCCR: CLRONRETS Position */ +#define FPU_FPCCR_CLRONRETS_Msk (1UL << FPU_FPCCR_CLRONRETS_Pos) /*!< FPCCR: CLRONRETS bit Mask */ + +#define FPU_FPCCR_TS_Pos 26U /*!< FPCCR: TS Position */ +#define FPU_FPCCR_TS_Msk (1UL << FPU_FPCCR_TS_Pos) /*!< FPCCR: TS bit Mask */ + +#define FPU_FPCCR_UFRDY_Pos 10U /*!< FPCCR: UFRDY Position */ +#define FPU_FPCCR_UFRDY_Msk (1UL << FPU_FPCCR_UFRDY_Pos) /*!< FPCCR: UFRDY bit Mask */ + +#define FPU_FPCCR_SPLIMVIOL_Pos 9U /*!< FPCCR: SPLIMVIOL Position */ +#define FPU_FPCCR_SPLIMVIOL_Msk (1UL << FPU_FPCCR_SPLIMVIOL_Pos) /*!< FPCCR: SPLIMVIOL bit Mask */ + +#define FPU_FPCCR_MONRDY_Pos 8U /*!< FPCCR: MONRDY Position */ +#define FPU_FPCCR_MONRDY_Msk (1UL << FPU_FPCCR_MONRDY_Pos) /*!< FPCCR: MONRDY bit Mask */ + +#define FPU_FPCCR_SFRDY_Pos 7U /*!< FPCCR: SFRDY Position */ +#define FPU_FPCCR_SFRDY_Msk (1UL << FPU_FPCCR_SFRDY_Pos) /*!< FPCCR: SFRDY bit Mask */ + +#define FPU_FPCCR_BFRDY_Pos 6U /*!< FPCCR: BFRDY Position */ +#define FPU_FPCCR_BFRDY_Msk (1UL << FPU_FPCCR_BFRDY_Pos) /*!< FPCCR: BFRDY bit Mask */ + +#define FPU_FPCCR_MMRDY_Pos 5U /*!< FPCCR: MMRDY Position */ +#define FPU_FPCCR_MMRDY_Msk (1UL << FPU_FPCCR_MMRDY_Pos) /*!< FPCCR: MMRDY bit Mask */ + +#define FPU_FPCCR_HFRDY_Pos 4U /*!< FPCCR: HFRDY Position */ +#define FPU_FPCCR_HFRDY_Msk (1UL << FPU_FPCCR_HFRDY_Pos) /*!< FPCCR: HFRDY bit Mask */ + +#define FPU_FPCCR_THREAD_Pos 3U /*!< FPCCR: processor mode bit Position */ +#define FPU_FPCCR_THREAD_Msk (1UL << FPU_FPCCR_THREAD_Pos) /*!< FPCCR: processor mode active bit Mask */ + +#define FPU_FPCCR_S_Pos 2U /*!< FPCCR: Security status of the FP context bit Position */ +#define FPU_FPCCR_S_Msk (1UL << FPU_FPCCR_S_Pos) /*!< FPCCR: Security status of the FP context bit Mask */ + +#define FPU_FPCCR_USER_Pos 1U /*!< FPCCR: privilege level bit Position */ +#define FPU_FPCCR_USER_Msk (1UL << FPU_FPCCR_USER_Pos) /*!< FPCCR: privilege level bit Mask */ + +#define FPU_FPCCR_LSPACT_Pos 0U /*!< FPCCR: Lazy state preservation active bit Position */ +#define FPU_FPCCR_LSPACT_Msk (1UL /*<< FPU_FPCCR_LSPACT_Pos*/) /*!< FPCCR: Lazy state preservation active bit Mask */ + +/* Floating-Point Context Address Register Definitions */ +#define FPU_FPCAR_ADDRESS_Pos 3U /*!< FPCAR: ADDRESS bit Position */ +#define FPU_FPCAR_ADDRESS_Msk (0x1FFFFFFFUL << FPU_FPCAR_ADDRESS_Pos) /*!< FPCAR: ADDRESS bit Mask */ + +/* Floating-Point Default Status Control Register Definitions */ +#define FPU_FPDSCR_AHP_Pos 26U /*!< FPDSCR: AHP bit Position */ +#define FPU_FPDSCR_AHP_Msk (1UL << FPU_FPDSCR_AHP_Pos) /*!< FPDSCR: AHP bit Mask */ + +#define FPU_FPDSCR_DN_Pos 25U /*!< FPDSCR: DN bit Position */ +#define FPU_FPDSCR_DN_Msk (1UL << FPU_FPDSCR_DN_Pos) /*!< FPDSCR: DN bit Mask */ + +#define FPU_FPDSCR_FZ_Pos 24U /*!< FPDSCR: FZ bit Position */ +#define FPU_FPDSCR_FZ_Msk (1UL << FPU_FPDSCR_FZ_Pos) /*!< FPDSCR: FZ bit Mask */ + +#define FPU_FPDSCR_RMode_Pos 22U /*!< FPDSCR: RMode bit Position */ +#define FPU_FPDSCR_RMode_Msk (3UL << FPU_FPDSCR_RMode_Pos) /*!< FPDSCR: RMode bit Mask */ + +/* Media and FP Feature Register 0 Definitions */ +#define FPU_MVFR0_FP_rounding_modes_Pos 28U /*!< MVFR0: FP rounding modes bits Position */ +#define FPU_MVFR0_FP_rounding_modes_Msk (0xFUL << FPU_MVFR0_FP_rounding_modes_Pos) /*!< MVFR0: FP rounding modes bits Mask */ + +#define FPU_MVFR0_Short_vectors_Pos 24U /*!< MVFR0: Short vectors bits Position */ +#define FPU_MVFR0_Short_vectors_Msk (0xFUL << FPU_MVFR0_Short_vectors_Pos) /*!< MVFR0: Short vectors bits Mask */ + +#define FPU_MVFR0_Square_root_Pos 20U /*!< MVFR0: Square root bits Position */ +#define FPU_MVFR0_Square_root_Msk (0xFUL << FPU_MVFR0_Square_root_Pos) /*!< MVFR0: Square root bits Mask */ + +#define FPU_MVFR0_Divide_Pos 16U /*!< MVFR0: Divide bits Position */ +#define FPU_MVFR0_Divide_Msk (0xFUL << FPU_MVFR0_Divide_Pos) /*!< MVFR0: Divide bits Mask */ + +#define FPU_MVFR0_FP_excep_trapping_Pos 12U /*!< MVFR0: FP exception trapping bits Position */ +#define FPU_MVFR0_FP_excep_trapping_Msk (0xFUL << FPU_MVFR0_FP_excep_trapping_Pos) /*!< MVFR0: FP exception trapping bits Mask */ + +#define FPU_MVFR0_Double_precision_Pos 8U /*!< MVFR0: Double-precision bits Position */ +#define FPU_MVFR0_Double_precision_Msk (0xFUL << FPU_MVFR0_Double_precision_Pos) /*!< MVFR0: Double-precision bits Mask */ + +#define FPU_MVFR0_Single_precision_Pos 4U /*!< MVFR0: Single-precision bits Position */ +#define FPU_MVFR0_Single_precision_Msk (0xFUL << FPU_MVFR0_Single_precision_Pos) /*!< MVFR0: Single-precision bits Mask */ + +#define FPU_MVFR0_A_SIMD_registers_Pos 0U /*!< MVFR0: A_SIMD registers bits Position */ +#define FPU_MVFR0_A_SIMD_registers_Msk (0xFUL /*<< FPU_MVFR0_A_SIMD_registers_Pos*/) /*!< MVFR0: A_SIMD registers bits Mask */ + +/* Media and FP Feature Register 1 Definitions */ +#define FPU_MVFR1_FP_fused_MAC_Pos 28U /*!< MVFR1: FP fused MAC bits Position */ +#define FPU_MVFR1_FP_fused_MAC_Msk (0xFUL << FPU_MVFR1_FP_fused_MAC_Pos) /*!< MVFR1: FP fused MAC bits Mask */ + +#define FPU_MVFR1_FP_HPFP_Pos 24U /*!< MVFR1: FP HPFP bits Position */ +#define FPU_MVFR1_FP_HPFP_Msk (0xFUL << FPU_MVFR1_FP_HPFP_Pos) /*!< MVFR1: FP HPFP bits Mask */ + +#define FPU_MVFR1_D_NaN_mode_Pos 4U /*!< MVFR1: D_NaN mode bits Position */ +#define FPU_MVFR1_D_NaN_mode_Msk (0xFUL << FPU_MVFR1_D_NaN_mode_Pos) /*!< MVFR1: D_NaN mode bits Mask */ + +#define FPU_MVFR1_FtZ_mode_Pos 0U /*!< MVFR1: FtZ mode bits Position */ +#define FPU_MVFR1_FtZ_mode_Msk (0xFUL /*<< FPU_MVFR1_FtZ_mode_Pos*/) /*!< MVFR1: FtZ mode bits Mask */ + +/*@} end of group CMSIS_FPU */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CoreDebug Core Debug Registers (CoreDebug) + \brief Type definitions for the Core Debug Registers + @{ + */ + +/** + \brief Structure type to access the Core Debug Register (CoreDebug). + */ +typedef struct +{ + __IOM uint32_t DHCSR; /*!< Offset: 0x000 (R/W) Debug Halting Control and Status Register */ + __OM uint32_t DCRSR; /*!< Offset: 0x004 ( /W) Debug Core Register Selector Register */ + __IOM uint32_t DCRDR; /*!< Offset: 0x008 (R/W) Debug Core Register Data Register */ + __IOM uint32_t DEMCR; /*!< Offset: 0x00C (R/W) Debug Exception and Monitor Control Register */ + uint32_t RESERVED4[1U]; + __IOM uint32_t DAUTHCTRL; /*!< Offset: 0x014 (R/W) Debug Authentication Control Register */ + __IOM uint32_t DSCSR; /*!< Offset: 0x018 (R/W) Debug Security Control and Status Register */ +} CoreDebug_Type; + +/* Debug Halting Control and Status Register Definitions */ +#define CoreDebug_DHCSR_DBGKEY_Pos 16U /*!< CoreDebug DHCSR: DBGKEY Position */ +#define CoreDebug_DHCSR_DBGKEY_Msk (0xFFFFUL << CoreDebug_DHCSR_DBGKEY_Pos) /*!< CoreDebug DHCSR: DBGKEY Mask */ + +#define CoreDebug_DHCSR_S_RESTART_ST_Pos 26U /*!< CoreDebug DHCSR: S_RESTART_ST Position */ +#define CoreDebug_DHCSR_S_RESTART_ST_Msk (1UL << CoreDebug_DHCSR_S_RESTART_ST_Pos) /*!< CoreDebug DHCSR: S_RESTART_ST Mask */ + +#define CoreDebug_DHCSR_S_RESET_ST_Pos 25U /*!< CoreDebug DHCSR: S_RESET_ST Position */ +#define CoreDebug_DHCSR_S_RESET_ST_Msk (1UL << CoreDebug_DHCSR_S_RESET_ST_Pos) /*!< CoreDebug DHCSR: S_RESET_ST Mask */ + +#define CoreDebug_DHCSR_S_RETIRE_ST_Pos 24U /*!< CoreDebug DHCSR: S_RETIRE_ST Position */ +#define CoreDebug_DHCSR_S_RETIRE_ST_Msk (1UL << CoreDebug_DHCSR_S_RETIRE_ST_Pos) /*!< CoreDebug DHCSR: S_RETIRE_ST Mask */ + +#define CoreDebug_DHCSR_S_LOCKUP_Pos 19U /*!< CoreDebug DHCSR: S_LOCKUP Position */ +#define CoreDebug_DHCSR_S_LOCKUP_Msk (1UL << CoreDebug_DHCSR_S_LOCKUP_Pos) /*!< CoreDebug DHCSR: S_LOCKUP Mask */ + +#define CoreDebug_DHCSR_S_SLEEP_Pos 18U /*!< CoreDebug DHCSR: S_SLEEP Position */ +#define CoreDebug_DHCSR_S_SLEEP_Msk (1UL << CoreDebug_DHCSR_S_SLEEP_Pos) /*!< CoreDebug DHCSR: S_SLEEP Mask */ + +#define CoreDebug_DHCSR_S_HALT_Pos 17U /*!< CoreDebug DHCSR: S_HALT Position */ +#define CoreDebug_DHCSR_S_HALT_Msk (1UL << CoreDebug_DHCSR_S_HALT_Pos) /*!< CoreDebug DHCSR: S_HALT Mask */ + +#define CoreDebug_DHCSR_S_REGRDY_Pos 16U /*!< CoreDebug DHCSR: S_REGRDY Position */ +#define CoreDebug_DHCSR_S_REGRDY_Msk (1UL << CoreDebug_DHCSR_S_REGRDY_Pos) /*!< CoreDebug DHCSR: S_REGRDY Mask */ + +#define CoreDebug_DHCSR_C_SNAPSTALL_Pos 5U /*!< CoreDebug DHCSR: C_SNAPSTALL Position */ +#define CoreDebug_DHCSR_C_SNAPSTALL_Msk (1UL << CoreDebug_DHCSR_C_SNAPSTALL_Pos) /*!< CoreDebug DHCSR: C_SNAPSTALL Mask */ + +#define CoreDebug_DHCSR_C_MASKINTS_Pos 3U /*!< CoreDebug DHCSR: C_MASKINTS Position */ +#define CoreDebug_DHCSR_C_MASKINTS_Msk (1UL << CoreDebug_DHCSR_C_MASKINTS_Pos) /*!< CoreDebug DHCSR: C_MASKINTS Mask */ + +#define CoreDebug_DHCSR_C_STEP_Pos 2U /*!< CoreDebug DHCSR: C_STEP Position */ +#define CoreDebug_DHCSR_C_STEP_Msk (1UL << CoreDebug_DHCSR_C_STEP_Pos) /*!< CoreDebug DHCSR: C_STEP Mask */ + +#define CoreDebug_DHCSR_C_HALT_Pos 1U /*!< CoreDebug DHCSR: C_HALT Position */ +#define CoreDebug_DHCSR_C_HALT_Msk (1UL << CoreDebug_DHCSR_C_HALT_Pos) /*!< CoreDebug DHCSR: C_HALT Mask */ + +#define CoreDebug_DHCSR_C_DEBUGEN_Pos 0U /*!< CoreDebug DHCSR: C_DEBUGEN Position */ +#define CoreDebug_DHCSR_C_DEBUGEN_Msk (1UL /*<< CoreDebug_DHCSR_C_DEBUGEN_Pos*/) /*!< CoreDebug DHCSR: C_DEBUGEN Mask */ + +/* Debug Core Register Selector Register Definitions */ +#define CoreDebug_DCRSR_REGWnR_Pos 16U /*!< CoreDebug DCRSR: REGWnR Position */ +#define CoreDebug_DCRSR_REGWnR_Msk (1UL << CoreDebug_DCRSR_REGWnR_Pos) /*!< CoreDebug DCRSR: REGWnR Mask */ + +#define CoreDebug_DCRSR_REGSEL_Pos 0U /*!< CoreDebug DCRSR: REGSEL Position */ +#define CoreDebug_DCRSR_REGSEL_Msk (0x1FUL /*<< CoreDebug_DCRSR_REGSEL_Pos*/) /*!< CoreDebug DCRSR: REGSEL Mask */ + +/* Debug Exception and Monitor Control Register Definitions */ +#define CoreDebug_DEMCR_TRCENA_Pos 24U /*!< CoreDebug DEMCR: TRCENA Position */ +#define CoreDebug_DEMCR_TRCENA_Msk (1UL << CoreDebug_DEMCR_TRCENA_Pos) /*!< CoreDebug DEMCR: TRCENA Mask */ + +#define CoreDebug_DEMCR_MON_REQ_Pos 19U /*!< CoreDebug DEMCR: MON_REQ Position */ +#define CoreDebug_DEMCR_MON_REQ_Msk (1UL << CoreDebug_DEMCR_MON_REQ_Pos) /*!< CoreDebug DEMCR: MON_REQ Mask */ + +#define CoreDebug_DEMCR_MON_STEP_Pos 18U /*!< CoreDebug DEMCR: MON_STEP Position */ +#define CoreDebug_DEMCR_MON_STEP_Msk (1UL << CoreDebug_DEMCR_MON_STEP_Pos) /*!< CoreDebug DEMCR: MON_STEP Mask */ + +#define CoreDebug_DEMCR_MON_PEND_Pos 17U /*!< CoreDebug DEMCR: MON_PEND Position */ +#define CoreDebug_DEMCR_MON_PEND_Msk (1UL << CoreDebug_DEMCR_MON_PEND_Pos) /*!< CoreDebug DEMCR: MON_PEND Mask */ + +#define CoreDebug_DEMCR_MON_EN_Pos 16U /*!< CoreDebug DEMCR: MON_EN Position */ +#define CoreDebug_DEMCR_MON_EN_Msk (1UL << CoreDebug_DEMCR_MON_EN_Pos) /*!< CoreDebug DEMCR: MON_EN Mask */ + +#define CoreDebug_DEMCR_VC_HARDERR_Pos 10U /*!< CoreDebug DEMCR: VC_HARDERR Position */ +#define CoreDebug_DEMCR_VC_HARDERR_Msk (1UL << CoreDebug_DEMCR_VC_HARDERR_Pos) /*!< CoreDebug DEMCR: VC_HARDERR Mask */ + +#define CoreDebug_DEMCR_VC_INTERR_Pos 9U /*!< CoreDebug DEMCR: VC_INTERR Position */ +#define CoreDebug_DEMCR_VC_INTERR_Msk (1UL << CoreDebug_DEMCR_VC_INTERR_Pos) /*!< CoreDebug DEMCR: VC_INTERR Mask */ + +#define CoreDebug_DEMCR_VC_BUSERR_Pos 8U /*!< CoreDebug DEMCR: VC_BUSERR Position */ +#define CoreDebug_DEMCR_VC_BUSERR_Msk (1UL << CoreDebug_DEMCR_VC_BUSERR_Pos) /*!< CoreDebug DEMCR: VC_BUSERR Mask */ + +#define CoreDebug_DEMCR_VC_STATERR_Pos 7U /*!< CoreDebug DEMCR: VC_STATERR Position */ +#define CoreDebug_DEMCR_VC_STATERR_Msk (1UL << CoreDebug_DEMCR_VC_STATERR_Pos) /*!< CoreDebug DEMCR: VC_STATERR Mask */ + +#define CoreDebug_DEMCR_VC_CHKERR_Pos 6U /*!< CoreDebug DEMCR: VC_CHKERR Position */ +#define CoreDebug_DEMCR_VC_CHKERR_Msk (1UL << CoreDebug_DEMCR_VC_CHKERR_Pos) /*!< CoreDebug DEMCR: VC_CHKERR Mask */ + +#define CoreDebug_DEMCR_VC_NOCPERR_Pos 5U /*!< CoreDebug DEMCR: VC_NOCPERR Position */ +#define CoreDebug_DEMCR_VC_NOCPERR_Msk (1UL << CoreDebug_DEMCR_VC_NOCPERR_Pos) /*!< CoreDebug DEMCR: VC_NOCPERR Mask */ + +#define CoreDebug_DEMCR_VC_MMERR_Pos 4U /*!< CoreDebug DEMCR: VC_MMERR Position */ +#define CoreDebug_DEMCR_VC_MMERR_Msk (1UL << CoreDebug_DEMCR_VC_MMERR_Pos) /*!< CoreDebug DEMCR: VC_MMERR Mask */ + +#define CoreDebug_DEMCR_VC_CORERESET_Pos 0U /*!< CoreDebug DEMCR: VC_CORERESET Position */ +#define CoreDebug_DEMCR_VC_CORERESET_Msk (1UL /*<< CoreDebug_DEMCR_VC_CORERESET_Pos*/) /*!< CoreDebug DEMCR: VC_CORERESET Mask */ + +/* Debug Authentication Control Register Definitions */ +#define CoreDebug_DAUTHCTRL_INTSPNIDEN_Pos 3U /*!< CoreDebug DAUTHCTRL: INTSPNIDEN, Position */ +#define CoreDebug_DAUTHCTRL_INTSPNIDEN_Msk (1UL << CoreDebug_DAUTHCTRL_INTSPNIDEN_Pos) /*!< CoreDebug DAUTHCTRL: INTSPNIDEN, Mask */ + +#define CoreDebug_DAUTHCTRL_SPNIDENSEL_Pos 2U /*!< CoreDebug DAUTHCTRL: SPNIDENSEL Position */ +#define CoreDebug_DAUTHCTRL_SPNIDENSEL_Msk (1UL << CoreDebug_DAUTHCTRL_SPNIDENSEL_Pos) /*!< CoreDebug DAUTHCTRL: SPNIDENSEL Mask */ + +#define CoreDebug_DAUTHCTRL_INTSPIDEN_Pos 1U /*!< CoreDebug DAUTHCTRL: INTSPIDEN Position */ +#define CoreDebug_DAUTHCTRL_INTSPIDEN_Msk (1UL << CoreDebug_DAUTHCTRL_INTSPIDEN_Pos) /*!< CoreDebug DAUTHCTRL: INTSPIDEN Mask */ + +#define CoreDebug_DAUTHCTRL_SPIDENSEL_Pos 0U /*!< CoreDebug DAUTHCTRL: SPIDENSEL Position */ +#define CoreDebug_DAUTHCTRL_SPIDENSEL_Msk (1UL /*<< CoreDebug_DAUTHCTRL_SPIDENSEL_Pos*/) /*!< CoreDebug DAUTHCTRL: SPIDENSEL Mask */ + +/* Debug Security Control and Status Register Definitions */ +#define CoreDebug_DSCSR_CDS_Pos 16U /*!< CoreDebug DSCSR: CDS Position */ +#define CoreDebug_DSCSR_CDS_Msk (1UL << CoreDebug_DSCSR_CDS_Pos) /*!< CoreDebug DSCSR: CDS Mask */ + +#define CoreDebug_DSCSR_SBRSEL_Pos 1U /*!< CoreDebug DSCSR: SBRSEL Position */ +#define CoreDebug_DSCSR_SBRSEL_Msk (1UL << CoreDebug_DSCSR_SBRSEL_Pos) /*!< CoreDebug DSCSR: SBRSEL Mask */ + +#define CoreDebug_DSCSR_SBRSELEN_Pos 0U /*!< CoreDebug DSCSR: SBRSELEN Position */ +#define CoreDebug_DSCSR_SBRSELEN_Msk (1UL /*<< CoreDebug_DSCSR_SBRSELEN_Pos*/) /*!< CoreDebug DSCSR: SBRSELEN Mask */ + +/*@} end of group CMSIS_CoreDebug */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_bitfield Core register bit field macros + \brief Macros for use with bit field definitions (xxx_Pos, xxx_Msk). + @{ + */ + +/** + \brief Mask and shift a bit field value for use in a register bit range. + \param[in] field Name of the register bit field. + \param[in] value Value of the bit field. This parameter is interpreted as an uint32_t type. + \return Masked and shifted value. +*/ +#define _VAL2FLD(field, value) (((uint32_t)(value) << field ## _Pos) & field ## _Msk) + +/** + \brief Mask and shift a register value to extract a bit filed value. + \param[in] field Name of the register bit field. + \param[in] value Value of register. This parameter is interpreted as an uint32_t type. + \return Masked and shifted bit field value. +*/ +#define _FLD2VAL(field, value) (((uint32_t)(value) & field ## _Msk) >> field ## _Pos) + +/*@} end of group CMSIS_core_bitfield */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_base Core Definitions + \brief Definitions for base addresses, unions, and structures. + @{ + */ + +/* Memory mapping of Core Hardware */ + #define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ + #define ITM_BASE (0xE0000000UL) /*!< ITM Base Address */ + #define DWT_BASE (0xE0001000UL) /*!< DWT Base Address */ + #define TPI_BASE (0xE0040000UL) /*!< TPI Base Address */ + #define CoreDebug_BASE (0xE000EDF0UL) /*!< Core Debug Base Address */ + #define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */ + #define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */ + #define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */ + + #define SCnSCB ((SCnSCB_Type *) SCS_BASE ) /*!< System control Register not in SCB */ + #define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */ + #define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */ + #define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */ + #define ITM ((ITM_Type *) ITM_BASE ) /*!< ITM configuration struct */ + #define DWT ((DWT_Type *) DWT_BASE ) /*!< DWT configuration struct */ + #define TPI ((TPI_Type *) TPI_BASE ) /*!< TPI configuration struct */ + #define CoreDebug ((CoreDebug_Type *) CoreDebug_BASE ) /*!< Core Debug configuration struct */ + + #if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + #define MPU_BASE (SCS_BASE + 0x0D90UL) /*!< Memory Protection Unit */ + #define MPU ((MPU_Type *) MPU_BASE ) /*!< Memory Protection Unit */ + #endif + + #if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + #define SAU_BASE (SCS_BASE + 0x0DD0UL) /*!< Security Attribution Unit */ + #define SAU ((SAU_Type *) SAU_BASE ) /*!< Security Attribution Unit */ + #endif + + #define FPU_BASE (SCS_BASE + 0x0F30UL) /*!< Floating Point Unit */ + #define FPU ((FPU_Type *) FPU_BASE ) /*!< Floating Point Unit */ + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + #define SCS_BASE_NS (0xE002E000UL) /*!< System Control Space Base Address (non-secure address space) */ + #define CoreDebug_BASE_NS (0xE002EDF0UL) /*!< Core Debug Base Address (non-secure address space) */ + #define SysTick_BASE_NS (SCS_BASE_NS + 0x0010UL) /*!< SysTick Base Address (non-secure address space) */ + #define NVIC_BASE_NS (SCS_BASE_NS + 0x0100UL) /*!< NVIC Base Address (non-secure address space) */ + #define SCB_BASE_NS (SCS_BASE_NS + 0x0D00UL) /*!< System Control Block Base Address (non-secure address space) */ + + #define SCnSCB_NS ((SCnSCB_Type *) SCS_BASE_NS ) /*!< System control Register not in SCB(non-secure address space) */ + #define SCB_NS ((SCB_Type *) SCB_BASE_NS ) /*!< SCB configuration struct (non-secure address space) */ + #define SysTick_NS ((SysTick_Type *) SysTick_BASE_NS ) /*!< SysTick configuration struct (non-secure address space) */ + #define NVIC_NS ((NVIC_Type *) NVIC_BASE_NS ) /*!< NVIC configuration struct (non-secure address space) */ + #define CoreDebug_NS ((CoreDebug_Type *) CoreDebug_BASE_NS) /*!< Core Debug configuration struct (non-secure address space) */ + + #if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + #define MPU_BASE_NS (SCS_BASE_NS + 0x0D90UL) /*!< Memory Protection Unit (non-secure address space) */ + #define MPU_NS ((MPU_Type *) MPU_BASE_NS ) /*!< Memory Protection Unit (non-secure address space) */ + #endif + + #define FPU_BASE_NS (SCS_BASE_NS + 0x0F30UL) /*!< Floating Point Unit (non-secure address space) */ + #define FPU_NS ((FPU_Type *) FPU_BASE_NS ) /*!< Floating Point Unit (non-secure address space) */ + +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ +/*@} */ + + + +/******************************************************************************* + * Hardware Abstraction Layer + Core Function Interface contains: + - Core NVIC Functions + - Core SysTick Functions + - Core Debug Functions + - Core Register Access Functions + ******************************************************************************/ +/** + \defgroup CMSIS_Core_FunctionInterface Functions and Instructions Reference +*/ + + + +/* ########################## NVIC functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_NVICFunctions NVIC Functions + \brief Functions that manage interrupts and exceptions via the NVIC. + @{ + */ + +#ifdef CMSIS_NVIC_VIRTUAL + #ifndef CMSIS_NVIC_VIRTUAL_HEADER_FILE + #define CMSIS_NVIC_VIRTUAL_HEADER_FILE "cmsis_nvic_virtual.h" + #endif + #include CMSIS_NVIC_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetPriorityGrouping __NVIC_SetPriorityGrouping + #define NVIC_GetPriorityGrouping __NVIC_GetPriorityGrouping + #define NVIC_EnableIRQ __NVIC_EnableIRQ + #define NVIC_GetEnableIRQ __NVIC_GetEnableIRQ + #define NVIC_DisableIRQ __NVIC_DisableIRQ + #define NVIC_GetPendingIRQ __NVIC_GetPendingIRQ + #define NVIC_SetPendingIRQ __NVIC_SetPendingIRQ + #define NVIC_ClearPendingIRQ __NVIC_ClearPendingIRQ + #define NVIC_GetActive __NVIC_GetActive + #define NVIC_SetPriority __NVIC_SetPriority + #define NVIC_GetPriority __NVIC_GetPriority + #define NVIC_SystemReset __NVIC_SystemReset +#endif /* CMSIS_NVIC_VIRTUAL */ + +#ifdef CMSIS_VECTAB_VIRTUAL + #ifndef CMSIS_VECTAB_VIRTUAL_HEADER_FILE + #define CMSIS_VECTAB_VIRTUAL_HEADER_FILE "cmsis_vectab_virtual.h" + #endif + #include CMSIS_VECTAB_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetVector __NVIC_SetVector + #define NVIC_GetVector __NVIC_GetVector +#endif /* (CMSIS_VECTAB_VIRTUAL) */ + +#define NVIC_USER_IRQ_OFFSET 16 + + + +/** + \brief Set Priority Grouping + \details Sets the priority grouping field using the required unlock sequence. + The parameter PriorityGroup is assigned to the field SCB->AIRCR [10:8] PRIGROUP field. + Only values from 0..7 are used. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. + \param [in] PriorityGroup Priority grouping field. + */ +__STATIC_INLINE void __NVIC_SetPriorityGrouping(uint32_t PriorityGroup) +{ + uint32_t reg_value; + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + + reg_value = SCB->AIRCR; /* read old register configuration */ + reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk)); /* clear bits to change */ + reg_value = (reg_value | + ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + (PriorityGroupTmp << 8U) ); /* Insert write key and priorty group */ + SCB->AIRCR = reg_value; +} + + +/** + \brief Get Priority Grouping + \details Reads the priority grouping field from the NVIC Interrupt Controller. + \return Priority grouping field (SCB->AIRCR [10:8] PRIGROUP field). + */ +__STATIC_INLINE uint32_t __NVIC_GetPriorityGrouping(void) +{ + return ((uint32_t)((SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) >> SCB_AIRCR_PRIGROUP_Pos)); +} + + +/** + \brief Enable Interrupt + \details Enables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Interrupt Enable status + \details Returns a device specific interrupt enable status from the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt is not enabled. + \return 1 Interrupt is enabled. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t __NVIC_GetEnableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Disable Interrupt + \details Disables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_DisableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + __DSB(); + __ISB(); + } +} + + +/** + \brief Get Pending Interrupt + \details Reads the NVIC pending register and returns the pending bit for the specified device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt status is not pending. + \return 1 Interrupt status is pending. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t __NVIC_GetPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Set Pending Interrupt + \details Sets the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_SetPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Clear Pending Interrupt + \details Clears the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_ClearPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Active Interrupt + \details Reads the active register in the NVIC and returns the active bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt status is not active. + \return 1 Interrupt status is active. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t __NVIC_GetActive(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->IABR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +/** + \brief Get Interrupt Target State + \details Reads the interrupt target field in the NVIC and returns the interrupt target bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 if interrupt is assigned to Secure + \return 1 if interrupt is assigned to Non Secure + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t NVIC_GetTargetState(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Set Interrupt Target State + \details Sets the interrupt target field in the NVIC and returns the interrupt target bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 if interrupt is assigned to Secure + 1 if interrupt is assigned to Non Secure + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t NVIC_SetTargetState(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] |= ((uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL))); + return((uint32_t)(((NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Clear Interrupt Target State + \details Clears the interrupt target field in the NVIC and returns the interrupt target bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 if interrupt is assigned to Secure + 1 if interrupt is assigned to Non Secure + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t NVIC_ClearTargetState(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] &= ~((uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL))); + return((uint32_t)(((NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ + + +/** + \brief Set Interrupt Priority + \details Sets the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \param [in] priority Priority to set. + \note The priority cannot be set for every processor exception. + */ +__STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->IPR[((uint32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + } + else + { + SCB->SHPR[(((uint32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + } +} + + +/** + \brief Get Interrupt Priority + \details Reads the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Interrupt Priority. + Value is aligned automatically to the implemented priority bits of the microcontroller. + */ +__STATIC_INLINE uint32_t __NVIC_GetPriority(IRQn_Type IRQn) +{ + + if ((int32_t)(IRQn) >= 0) + { + return(((uint32_t)NVIC->IPR[((uint32_t)IRQn)] >> (8U - __NVIC_PRIO_BITS))); + } + else + { + return(((uint32_t)SCB->SHPR[(((uint32_t)IRQn) & 0xFUL)-4UL] >> (8U - __NVIC_PRIO_BITS))); + } +} + + +/** + \brief Encode Priority + \details Encodes the priority for an interrupt with the given priority group, + preemptive priority value, and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. + \param [in] PriorityGroup Used priority group. + \param [in] PreemptPriority Preemptive priority value (starting from 0). + \param [in] SubPriority Subpriority value (starting from 0). + \return Encoded priority. Value can be used in the function \ref NVIC_SetPriority(). + */ +__STATIC_INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + return ( + ((PreemptPriority & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL)) << SubPriorityBits) | + ((SubPriority & (uint32_t)((1UL << (SubPriorityBits )) - 1UL))) + ); +} + + +/** + \brief Decode Priority + \details Decodes an interrupt priority value with a given priority group to + preemptive priority value and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS) the smallest possible priority group is set. + \param [in] Priority Priority value, which can be retrieved with the function \ref NVIC_GetPriority(). + \param [in] PriorityGroup Used priority group. + \param [out] pPreemptPriority Preemptive priority value (starting from 0). + \param [out] pSubPriority Subpriority value (starting from 0). + */ +__STATIC_INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGroup, uint32_t* const pPreemptPriority, uint32_t* const pSubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + *pPreemptPriority = (Priority >> SubPriorityBits) & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL); + *pSubPriority = (Priority ) & (uint32_t)((1UL << (SubPriorityBits )) - 1UL); +} + + +/** + \brief Set Interrupt Vector + \details Sets an interrupt vector in SRAM based interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + VTOR must been relocated to SRAM before. + \param [in] IRQn Interrupt number + \param [in] vector Address of interrupt handler function + */ +__STATIC_INLINE void __NVIC_SetVector(IRQn_Type IRQn, uint32_t vector) +{ + uint32_t *vectors = (uint32_t *)SCB->VTOR; + vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET] = vector; +} + + +/** + \brief Get Interrupt Vector + \details Reads an interrupt vector from interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Address of interrupt handler function + */ +__STATIC_INLINE uint32_t __NVIC_GetVector(IRQn_Type IRQn) +{ + uint32_t *vectors = (uint32_t *)SCB->VTOR; + return vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET]; +} + + +/** + \brief System Reset + \details Initiates a system reset request to reset the MCU. + */ +__NO_RETURN __STATIC_INLINE void __NVIC_SystemReset(void) +{ + __DSB(); /* Ensure all outstanding memory accesses included + buffered write are completed before reset */ + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + SCB_AIRCR_SYSRESETREQ_Msk ); /* Keep priority group unchanged */ + __DSB(); /* Ensure completion of memory access */ + + for(;;) /* wait until reset */ + { + __NOP(); + } +} + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +/** + \brief Set Priority Grouping (non-secure) + \details Sets the non-secure priority grouping field when in secure state using the required unlock sequence. + The parameter PriorityGroup is assigned to the field SCB->AIRCR [10:8] PRIGROUP field. + Only values from 0..7 are used. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. + \param [in] PriorityGroup Priority grouping field. + */ +__STATIC_INLINE void TZ_NVIC_SetPriorityGrouping_NS(uint32_t PriorityGroup) +{ + uint32_t reg_value; + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + + reg_value = SCB_NS->AIRCR; /* read old register configuration */ + reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk)); /* clear bits to change */ + reg_value = (reg_value | + ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + (PriorityGroupTmp << 8U) ); /* Insert write key and priorty group */ + SCB_NS->AIRCR = reg_value; +} + + +/** + \brief Get Priority Grouping (non-secure) + \details Reads the priority grouping field from the non-secure NVIC when in secure state. + \return Priority grouping field (SCB->AIRCR [10:8] PRIGROUP field). + */ +__STATIC_INLINE uint32_t TZ_NVIC_GetPriorityGrouping_NS(void) +{ + return ((uint32_t)((SCB_NS->AIRCR & SCB_AIRCR_PRIGROUP_Msk) >> SCB_AIRCR_PRIGROUP_Pos)); +} + + +/** + \brief Enable Interrupt (non-secure) + \details Enables a device specific interrupt in the non-secure NVIC interrupt controller when in secure state. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void TZ_NVIC_EnableIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Interrupt Enable status (non-secure) + \details Returns a device specific interrupt enable status from the non-secure NVIC interrupt controller when in secure state. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt is not enabled. + \return 1 Interrupt is enabled. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t TZ_NVIC_GetEnableIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC_NS->ISER[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Disable Interrupt (non-secure) + \details Disables a device specific interrupt in the non-secure NVIC interrupt controller when in secure state. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void TZ_NVIC_DisableIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->ICER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Pending Interrupt (non-secure) + \details Reads the NVIC pending register in the non-secure NVIC when in secure state and returns the pending bit for the specified device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt status is not pending. + \return 1 Interrupt status is pending. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t TZ_NVIC_GetPendingIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC_NS->ISPR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Set Pending Interrupt (non-secure) + \details Sets the pending bit of a device specific interrupt in the non-secure NVIC pending register when in secure state. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void TZ_NVIC_SetPendingIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->ISPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Clear Pending Interrupt (non-secure) + \details Clears the pending bit of a device specific interrupt in the non-secure NVIC pending register when in secure state. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void TZ_NVIC_ClearPendingIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->ICPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Active Interrupt (non-secure) + \details Reads the active register in non-secure NVIC when in secure state and returns the active bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt status is not active. + \return 1 Interrupt status is active. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t TZ_NVIC_GetActive_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC_NS->IABR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Set Interrupt Priority (non-secure) + \details Sets the priority of a non-secure device specific interrupt or a non-secure processor exception when in secure state. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \param [in] priority Priority to set. + \note The priority cannot be set for every non-secure processor exception. + */ +__STATIC_INLINE void TZ_NVIC_SetPriority_NS(IRQn_Type IRQn, uint32_t priority) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->IPR[((uint32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + } + else + { + SCB_NS->SHPR[(((uint32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + } +} + + +/** + \brief Get Interrupt Priority (non-secure) + \details Reads the priority of a non-secure device specific interrupt or a non-secure processor exception when in secure state. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Interrupt Priority. Value is aligned automatically to the implemented priority bits of the microcontroller. + */ +__STATIC_INLINE uint32_t TZ_NVIC_GetPriority_NS(IRQn_Type IRQn) +{ + + if ((int32_t)(IRQn) >= 0) + { + return(((uint32_t)NVIC_NS->IPR[((uint32_t)IRQn)] >> (8U - __NVIC_PRIO_BITS))); + } + else + { + return(((uint32_t)SCB_NS->SHPR[(((uint32_t)IRQn) & 0xFUL)-4UL] >> (8U - __NVIC_PRIO_BITS))); + } +} +#endif /* defined (__ARM_FEATURE_CMSE) &&(__ARM_FEATURE_CMSE == 3U) */ + +/*@} end of CMSIS_Core_NVICFunctions */ + +/* ########################## MPU functions #################################### */ + +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + +#include "mpu_armv8.h" + +#endif + +/* ########################## FPU functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_FpuFunctions FPU Functions + \brief Function that provides FPU type. + @{ + */ + +/** + \brief get FPU type + \details returns the FPU type + \returns + - \b 0: No FPU + - \b 1: Single precision FPU + - \b 2: Double + Single precision FPU + */ +__STATIC_INLINE uint32_t SCB_GetFPUType(void) +{ + uint32_t mvfr0; + + mvfr0 = FPU->MVFR0; + if ((mvfr0 & (FPU_MVFR0_Single_precision_Msk | FPU_MVFR0_Double_precision_Msk)) == 0x220U) + { + return 2U; /* Double + Single precision FPU */ + } + else if ((mvfr0 & (FPU_MVFR0_Single_precision_Msk | FPU_MVFR0_Double_precision_Msk)) == 0x020U) + { + return 1U; /* Single precision FPU */ + } + else + { + return 0U; /* No FPU */ + } +} + + +/*@} end of CMSIS_Core_FpuFunctions */ + + + +/* ########################## SAU functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_SAUFunctions SAU Functions + \brief Functions that configure the SAU. + @{ + */ + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + +/** + \brief Enable SAU + \details Enables the Security Attribution Unit (SAU). + */ +__STATIC_INLINE void TZ_SAU_Enable(void) +{ + SAU->CTRL |= (SAU_CTRL_ENABLE_Msk); +} + + + +/** + \brief Disable SAU + \details Disables the Security Attribution Unit (SAU). + */ +__STATIC_INLINE void TZ_SAU_Disable(void) +{ + SAU->CTRL &= ~(SAU_CTRL_ENABLE_Msk); +} + +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ + +/*@} end of CMSIS_Core_SAUFunctions */ + + + + +/* ################################## SysTick function ############################################ */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_SysTickFunctions SysTick Functions + \brief Functions that configure the System. + @{ + */ + +#if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U) + +/** + \brief System Tick Configuration + \details Initializes the System Timer and its interrupt, and starts the System Tick Timer. + Counter is in free running mode to generate periodic interrupts. + \param [in] ticks Number of ticks between two interrupts. + \return 0 Function succeeded. + \return 1 Function failed. + \note When the variable __Vendor_SysTickConfig is set to 1, then the + function SysTick_Config is not included. In this case, the file device.h + must contain a vendor-specific implementation of this function. + */ +__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) +{ + if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) + { + return (1UL); /* Reload value impossible */ + } + + SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ + NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ + SysTick->VAL = 0UL; /* Load the SysTick Counter Value */ + SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + SysTick_CTRL_TICKINT_Msk | + SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ + return (0UL); /* Function successful */ +} + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +/** + \brief System Tick Configuration (non-secure) + \details Initializes the non-secure System Timer and its interrupt when in secure state, and starts the System Tick Timer. + Counter is in free running mode to generate periodic interrupts. + \param [in] ticks Number of ticks between two interrupts. + \return 0 Function succeeded. + \return 1 Function failed. + \note When the variable __Vendor_SysTickConfig is set to 1, then the + function TZ_SysTick_Config_NS is not included. In this case, the file device.h + must contain a vendor-specific implementation of this function. + + */ +__STATIC_INLINE uint32_t TZ_SysTick_Config_NS(uint32_t ticks) +{ + if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) + { + return (1UL); /* Reload value impossible */ + } + + SysTick_NS->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ + TZ_NVIC_SetPriority_NS (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ + SysTick_NS->VAL = 0UL; /* Load the SysTick Counter Value */ + SysTick_NS->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + SysTick_CTRL_TICKINT_Msk | + SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ + return (0UL); /* Function successful */ +} +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ + +#endif + +/*@} end of CMSIS_Core_SysTickFunctions */ + + + +/* ##################################### Debug In/Output function ########################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_core_DebugFunctions ITM Functions + \brief Functions that access the ITM debug interface. + @{ + */ + +extern volatile int32_t ITM_RxBuffer; /*!< External variable to receive characters. */ +#define ITM_RXBUFFER_EMPTY ((int32_t)0x5AA55AA5U) /*!< Value identifying \ref ITM_RxBuffer is ready for next character. */ + + +/** + \brief ITM Send Character + \details Transmits a character via the ITM channel 0, and + \li Just returns when no debugger is connected that has booked the output. + \li Is blocking when a debugger is connected, but the previous character sent has not been transmitted. + \param [in] ch Character to transmit. + \returns Character to transmit. + */ +__STATIC_INLINE uint32_t ITM_SendChar (uint32_t ch) +{ + if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && /* ITM enabled */ + ((ITM->TER & 1UL ) != 0UL) ) /* ITM Port #0 enabled */ + { + while (ITM->PORT[0U].u32 == 0UL) + { + __NOP(); + } + ITM->PORT[0U].u8 = (uint8_t)ch; + } + return (ch); +} + + +/** + \brief ITM Receive Character + \details Inputs a character via the external variable \ref ITM_RxBuffer. + \return Received character. + \return -1 No character pending. + */ +__STATIC_INLINE int32_t ITM_ReceiveChar (void) +{ + int32_t ch = -1; /* no character available */ + + if (ITM_RxBuffer != ITM_RXBUFFER_EMPTY) + { + ch = ITM_RxBuffer; + ITM_RxBuffer = ITM_RXBUFFER_EMPTY; /* ready for next character */ + } + + return (ch); +} + + +/** + \brief ITM Check Character + \details Checks whether a character is pending for reading in the variable \ref ITM_RxBuffer. + \return 0 No character available. + \return 1 Character available. + */ +__STATIC_INLINE int32_t ITM_CheckChar (void) +{ + + if (ITM_RxBuffer == ITM_RXBUFFER_EMPTY) + { + return (0); /* no character available */ + } + else + { + return (1); /* character available */ + } +} + +/*@} end of CMSIS_core_DebugFunctions */ + + + + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_ARMV81MML_H_DEPENDANT */ + +#endif /* __CMSIS_GENERIC */ diff --git a/lib/cmsis/inc/core_armv8mbl.h b/lib/cmsis/inc/core_armv8mbl.h new file mode 100644 index 0000000000..57d9f663fd --- /dev/null +++ b/lib/cmsis/inc/core_armv8mbl.h @@ -0,0 +1,1918 @@ +/**************************************************************************//** + * @file core_armv8mbl.h + * @brief CMSIS Armv8-M Baseline Core Peripheral Access Layer Header File + * @version V5.0.8 + * @date 12. November 2018 + ******************************************************************************/ +/* + * Copyright (c) 2009-2018 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined (__clang__) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef __CORE_ARMV8MBL_H_GENERIC +#define __CORE_ARMV8MBL_H_GENERIC + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/** + \page CMSIS_MISRA_Exceptions MISRA-C:2004 Compliance Exceptions + CMSIS violates the following MISRA-C:2004 rules: + + \li Required Rule 8.5, object/function definition in header file.
+ Function definitions in header files are used to allow 'inlining'. + + \li Required Rule 18.4, declaration of union type or object of union type: '{...}'.
+ Unions are used for effective representation of core registers. + + \li Advisory Rule 19.7, Function-like macro defined.
+ Function-like macros are used to allow more efficient code. + */ + + +/******************************************************************************* + * CMSIS definitions + ******************************************************************************/ +/** + \ingroup Cortex_ARMv8MBL + @{ + */ + +#include "cmsis_version.h" + +/* CMSIS definitions */ +#define __ARMv8MBL_CMSIS_VERSION_MAIN (__CM_CMSIS_VERSION_MAIN) /*!< \deprecated [31:16] CMSIS HAL main version */ +#define __ARMv8MBL_CMSIS_VERSION_SUB (__CM_CMSIS_VERSION_SUB) /*!< \deprecated [15:0] CMSIS HAL sub version */ +#define __ARMv8MBL_CMSIS_VERSION ((__ARMv8MBL_CMSIS_VERSION_MAIN << 16U) | \ + __ARMv8MBL_CMSIS_VERSION_SUB ) /*!< \deprecated CMSIS HAL version number */ + +#define __CORTEX_M ( 2U) /*!< Cortex-M Core */ + +/** __FPU_USED indicates whether an FPU is used or not. + This core does not support an FPU at all +*/ +#define __FPU_USED 0U + +#if defined ( __CC_ARM ) + #if defined __TARGET_FPU_VFP + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #if defined __ARM_FP + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __GNUC__ ) + #if defined (__VFP_FP__) && !defined(__SOFTFP__) + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __ICCARM__ ) + #if defined __ARMVFP__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __TI_ARM__ ) + #if defined __TI_VFP_SUPPORT__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __TASKING__ ) + #if defined __FPU_VFP__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __CSMC__ ) + #if ( __CSMC__ & 0x400U) + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#endif + +#include "cmsis_compiler.h" /* CMSIS compiler specific defines */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_ARMV8MBL_H_GENERIC */ + +#ifndef __CMSIS_GENERIC + +#ifndef __CORE_ARMV8MBL_H_DEPENDANT +#define __CORE_ARMV8MBL_H_DEPENDANT + +#ifdef __cplusplus + extern "C" { +#endif + +/* check device defines and use defaults */ +#if defined __CHECK_DEVICE_DEFINES + #ifndef __ARMv8MBL_REV + #define __ARMv8MBL_REV 0x0000U + #warning "__ARMv8MBL_REV not defined in device header file; using default!" + #endif + + #ifndef __FPU_PRESENT + #define __FPU_PRESENT 0U + #warning "__FPU_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __MPU_PRESENT + #define __MPU_PRESENT 0U + #warning "__MPU_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __SAUREGION_PRESENT + #define __SAUREGION_PRESENT 0U + #warning "__SAUREGION_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __VTOR_PRESENT + #define __VTOR_PRESENT 0U + #warning "__VTOR_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __NVIC_PRIO_BITS + #define __NVIC_PRIO_BITS 2U + #warning "__NVIC_PRIO_BITS not defined in device header file; using default!" + #endif + + #ifndef __Vendor_SysTickConfig + #define __Vendor_SysTickConfig 0U + #warning "__Vendor_SysTickConfig not defined in device header file; using default!" + #endif + + #ifndef __ETM_PRESENT + #define __ETM_PRESENT 0U + #warning "__ETM_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __MTB_PRESENT + #define __MTB_PRESENT 0U + #warning "__MTB_PRESENT not defined in device header file; using default!" + #endif + +#endif + +/* IO definitions (access restrictions to peripheral registers) */ +/** + \defgroup CMSIS_glob_defs CMSIS Global Defines + + IO Type Qualifiers are used + \li to specify the access to peripheral variables. + \li for automatic generation of peripheral register debug information. +*/ +#ifdef __cplusplus + #define __I volatile /*!< Defines 'read only' permissions */ +#else + #define __I volatile const /*!< Defines 'read only' permissions */ +#endif +#define __O volatile /*!< Defines 'write only' permissions */ +#define __IO volatile /*!< Defines 'read / write' permissions */ + +/* following defines should be used for structure members */ +#define __IM volatile const /*! Defines 'read only' structure member permissions */ +#define __OM volatile /*! Defines 'write only' structure member permissions */ +#define __IOM volatile /*! Defines 'read / write' structure member permissions */ + +/*@} end of group ARMv8MBL */ + + + +/******************************************************************************* + * Register Abstraction + Core Register contain: + - Core Register + - Core NVIC Register + - Core SCB Register + - Core SysTick Register + - Core Debug Register + - Core MPU Register + - Core SAU Register + ******************************************************************************/ +/** + \defgroup CMSIS_core_register Defines and Type Definitions + \brief Type definitions and defines for Cortex-M processor based devices. +*/ + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CORE Status and Control Registers + \brief Core Register type definitions. + @{ + */ + +/** + \brief Union type to access the Application Program Status Register (APSR). + */ +typedef union +{ + struct + { + uint32_t _reserved0:28; /*!< bit: 0..27 Reserved */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} APSR_Type; + +/* APSR Register Definitions */ +#define APSR_N_Pos 31U /*!< APSR: N Position */ +#define APSR_N_Msk (1UL << APSR_N_Pos) /*!< APSR: N Mask */ + +#define APSR_Z_Pos 30U /*!< APSR: Z Position */ +#define APSR_Z_Msk (1UL << APSR_Z_Pos) /*!< APSR: Z Mask */ + +#define APSR_C_Pos 29U /*!< APSR: C Position */ +#define APSR_C_Msk (1UL << APSR_C_Pos) /*!< APSR: C Mask */ + +#define APSR_V_Pos 28U /*!< APSR: V Position */ +#define APSR_V_Msk (1UL << APSR_V_Pos) /*!< APSR: V Mask */ + + +/** + \brief Union type to access the Interrupt Program Status Register (IPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:23; /*!< bit: 9..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} IPSR_Type; + +/* IPSR Register Definitions */ +#define IPSR_ISR_Pos 0U /*!< IPSR: ISR Position */ +#define IPSR_ISR_Msk (0x1FFUL /*<< IPSR_ISR_Pos*/) /*!< IPSR: ISR Mask */ + + +/** + \brief Union type to access the Special-Purpose Program Status Registers (xPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:15; /*!< bit: 9..23 Reserved */ + uint32_t T:1; /*!< bit: 24 Thumb bit (read 0) */ + uint32_t _reserved1:3; /*!< bit: 25..27 Reserved */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} xPSR_Type; + +/* xPSR Register Definitions */ +#define xPSR_N_Pos 31U /*!< xPSR: N Position */ +#define xPSR_N_Msk (1UL << xPSR_N_Pos) /*!< xPSR: N Mask */ + +#define xPSR_Z_Pos 30U /*!< xPSR: Z Position */ +#define xPSR_Z_Msk (1UL << xPSR_Z_Pos) /*!< xPSR: Z Mask */ + +#define xPSR_C_Pos 29U /*!< xPSR: C Position */ +#define xPSR_C_Msk (1UL << xPSR_C_Pos) /*!< xPSR: C Mask */ + +#define xPSR_V_Pos 28U /*!< xPSR: V Position */ +#define xPSR_V_Msk (1UL << xPSR_V_Pos) /*!< xPSR: V Mask */ + +#define xPSR_T_Pos 24U /*!< xPSR: T Position */ +#define xPSR_T_Msk (1UL << xPSR_T_Pos) /*!< xPSR: T Mask */ + +#define xPSR_ISR_Pos 0U /*!< xPSR: ISR Position */ +#define xPSR_ISR_Msk (0x1FFUL /*<< xPSR_ISR_Pos*/) /*!< xPSR: ISR Mask */ + + +/** + \brief Union type to access the Control Registers (CONTROL). + */ +typedef union +{ + struct + { + uint32_t nPRIV:1; /*!< bit: 0 Execution privilege in Thread mode */ + uint32_t SPSEL:1; /*!< bit: 1 Stack-pointer select */ + uint32_t _reserved1:30; /*!< bit: 2..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} CONTROL_Type; + +/* CONTROL Register Definitions */ +#define CONTROL_SPSEL_Pos 1U /*!< CONTROL: SPSEL Position */ +#define CONTROL_SPSEL_Msk (1UL << CONTROL_SPSEL_Pos) /*!< CONTROL: SPSEL Mask */ + +#define CONTROL_nPRIV_Pos 0U /*!< CONTROL: nPRIV Position */ +#define CONTROL_nPRIV_Msk (1UL /*<< CONTROL_nPRIV_Pos*/) /*!< CONTROL: nPRIV Mask */ + +/*@} end of group CMSIS_CORE */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_NVIC Nested Vectored Interrupt Controller (NVIC) + \brief Type definitions for the NVIC Registers + @{ + */ + +/** + \brief Structure type to access the Nested Vectored Interrupt Controller (NVIC). + */ +typedef struct +{ + __IOM uint32_t ISER[16U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ + uint32_t RESERVED0[16U]; + __IOM uint32_t ICER[16U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ + uint32_t RSERVED1[16U]; + __IOM uint32_t ISPR[16U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ + uint32_t RESERVED2[16U]; + __IOM uint32_t ICPR[16U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ + uint32_t RESERVED3[16U]; + __IOM uint32_t IABR[16U]; /*!< Offset: 0x200 (R/W) Interrupt Active bit Register */ + uint32_t RESERVED4[16U]; + __IOM uint32_t ITNS[16U]; /*!< Offset: 0x280 (R/W) Interrupt Non-Secure State Register */ + uint32_t RESERVED5[16U]; + __IOM uint32_t IPR[124U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register */ +} NVIC_Type; + +/*@} end of group CMSIS_NVIC */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SCB System Control Block (SCB) + \brief Type definitions for the System Control Block Registers + @{ + */ + +/** + \brief Structure type to access the System Control Block (SCB). + */ +typedef struct +{ + __IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */ + __IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */ +#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U) + __IOM uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */ +#else + uint32_t RESERVED0; +#endif + __IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */ + __IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */ + __IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */ + uint32_t RESERVED1; + __IOM uint32_t SHPR[2U]; /*!< Offset: 0x01C (R/W) System Handlers Priority Registers. [0] is RESERVED */ + __IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */ +} SCB_Type; + +/* SCB CPUID Register Definitions */ +#define SCB_CPUID_IMPLEMENTER_Pos 24U /*!< SCB CPUID: IMPLEMENTER Position */ +#define SCB_CPUID_IMPLEMENTER_Msk (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos) /*!< SCB CPUID: IMPLEMENTER Mask */ + +#define SCB_CPUID_VARIANT_Pos 20U /*!< SCB CPUID: VARIANT Position */ +#define SCB_CPUID_VARIANT_Msk (0xFUL << SCB_CPUID_VARIANT_Pos) /*!< SCB CPUID: VARIANT Mask */ + +#define SCB_CPUID_ARCHITECTURE_Pos 16U /*!< SCB CPUID: ARCHITECTURE Position */ +#define SCB_CPUID_ARCHITECTURE_Msk (0xFUL << SCB_CPUID_ARCHITECTURE_Pos) /*!< SCB CPUID: ARCHITECTURE Mask */ + +#define SCB_CPUID_PARTNO_Pos 4U /*!< SCB CPUID: PARTNO Position */ +#define SCB_CPUID_PARTNO_Msk (0xFFFUL << SCB_CPUID_PARTNO_Pos) /*!< SCB CPUID: PARTNO Mask */ + +#define SCB_CPUID_REVISION_Pos 0U /*!< SCB CPUID: REVISION Position */ +#define SCB_CPUID_REVISION_Msk (0xFUL /*<< SCB_CPUID_REVISION_Pos*/) /*!< SCB CPUID: REVISION Mask */ + +/* SCB Interrupt Control State Register Definitions */ +#define SCB_ICSR_PENDNMISET_Pos 31U /*!< SCB ICSR: PENDNMISET Position */ +#define SCB_ICSR_PENDNMISET_Msk (1UL << SCB_ICSR_PENDNMISET_Pos) /*!< SCB ICSR: PENDNMISET Mask */ + +#define SCB_ICSR_NMIPENDSET_Pos SCB_ICSR_PENDNMISET_Pos /*!< SCB ICSR: NMIPENDSET Position, backward compatibility */ +#define SCB_ICSR_NMIPENDSET_Msk SCB_ICSR_PENDNMISET_Msk /*!< SCB ICSR: NMIPENDSET Mask, backward compatibility */ + +#define SCB_ICSR_PENDNMICLR_Pos 30U /*!< SCB ICSR: PENDNMICLR Position */ +#define SCB_ICSR_PENDNMICLR_Msk (1UL << SCB_ICSR_PENDNMICLR_Pos) /*!< SCB ICSR: PENDNMICLR Mask */ + +#define SCB_ICSR_PENDSVSET_Pos 28U /*!< SCB ICSR: PENDSVSET Position */ +#define SCB_ICSR_PENDSVSET_Msk (1UL << SCB_ICSR_PENDSVSET_Pos) /*!< SCB ICSR: PENDSVSET Mask */ + +#define SCB_ICSR_PENDSVCLR_Pos 27U /*!< SCB ICSR: PENDSVCLR Position */ +#define SCB_ICSR_PENDSVCLR_Msk (1UL << SCB_ICSR_PENDSVCLR_Pos) /*!< SCB ICSR: PENDSVCLR Mask */ + +#define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */ +#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */ + +#define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */ +#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */ + +#define SCB_ICSR_STTNS_Pos 24U /*!< SCB ICSR: STTNS Position (Security Extension) */ +#define SCB_ICSR_STTNS_Msk (1UL << SCB_ICSR_STTNS_Pos) /*!< SCB ICSR: STTNS Mask (Security Extension) */ + +#define SCB_ICSR_ISRPREEMPT_Pos 23U /*!< SCB ICSR: ISRPREEMPT Position */ +#define SCB_ICSR_ISRPREEMPT_Msk (1UL << SCB_ICSR_ISRPREEMPT_Pos) /*!< SCB ICSR: ISRPREEMPT Mask */ + +#define SCB_ICSR_ISRPENDING_Pos 22U /*!< SCB ICSR: ISRPENDING Position */ +#define SCB_ICSR_ISRPENDING_Msk (1UL << SCB_ICSR_ISRPENDING_Pos) /*!< SCB ICSR: ISRPENDING Mask */ + +#define SCB_ICSR_VECTPENDING_Pos 12U /*!< SCB ICSR: VECTPENDING Position */ +#define SCB_ICSR_VECTPENDING_Msk (0x1FFUL << SCB_ICSR_VECTPENDING_Pos) /*!< SCB ICSR: VECTPENDING Mask */ + +#define SCB_ICSR_RETTOBASE_Pos 11U /*!< SCB ICSR: RETTOBASE Position */ +#define SCB_ICSR_RETTOBASE_Msk (1UL << SCB_ICSR_RETTOBASE_Pos) /*!< SCB ICSR: RETTOBASE Mask */ + +#define SCB_ICSR_VECTACTIVE_Pos 0U /*!< SCB ICSR: VECTACTIVE Position */ +#define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL /*<< SCB_ICSR_VECTACTIVE_Pos*/) /*!< SCB ICSR: VECTACTIVE Mask */ + +#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U) +/* SCB Vector Table Offset Register Definitions */ +#define SCB_VTOR_TBLOFF_Pos 7U /*!< SCB VTOR: TBLOFF Position */ +#define SCB_VTOR_TBLOFF_Msk (0x1FFFFFFUL << SCB_VTOR_TBLOFF_Pos) /*!< SCB VTOR: TBLOFF Mask */ +#endif + +/* SCB Application Interrupt and Reset Control Register Definitions */ +#define SCB_AIRCR_VECTKEY_Pos 16U /*!< SCB AIRCR: VECTKEY Position */ +#define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */ + +#define SCB_AIRCR_VECTKEYSTAT_Pos 16U /*!< SCB AIRCR: VECTKEYSTAT Position */ +#define SCB_AIRCR_VECTKEYSTAT_Msk (0xFFFFUL << SCB_AIRCR_VECTKEYSTAT_Pos) /*!< SCB AIRCR: VECTKEYSTAT Mask */ + +#define SCB_AIRCR_ENDIANESS_Pos 15U /*!< SCB AIRCR: ENDIANESS Position */ +#define SCB_AIRCR_ENDIANESS_Msk (1UL << SCB_AIRCR_ENDIANESS_Pos) /*!< SCB AIRCR: ENDIANESS Mask */ + +#define SCB_AIRCR_PRIS_Pos 14U /*!< SCB AIRCR: PRIS Position */ +#define SCB_AIRCR_PRIS_Msk (1UL << SCB_AIRCR_PRIS_Pos) /*!< SCB AIRCR: PRIS Mask */ + +#define SCB_AIRCR_BFHFNMINS_Pos 13U /*!< SCB AIRCR: BFHFNMINS Position */ +#define SCB_AIRCR_BFHFNMINS_Msk (1UL << SCB_AIRCR_BFHFNMINS_Pos) /*!< SCB AIRCR: BFHFNMINS Mask */ + +#define SCB_AIRCR_SYSRESETREQS_Pos 3U /*!< SCB AIRCR: SYSRESETREQS Position */ +#define SCB_AIRCR_SYSRESETREQS_Msk (1UL << SCB_AIRCR_SYSRESETREQS_Pos) /*!< SCB AIRCR: SYSRESETREQS Mask */ + +#define SCB_AIRCR_SYSRESETREQ_Pos 2U /*!< SCB AIRCR: SYSRESETREQ Position */ +#define SCB_AIRCR_SYSRESETREQ_Msk (1UL << SCB_AIRCR_SYSRESETREQ_Pos) /*!< SCB AIRCR: SYSRESETREQ Mask */ + +#define SCB_AIRCR_VECTCLRACTIVE_Pos 1U /*!< SCB AIRCR: VECTCLRACTIVE Position */ +#define SCB_AIRCR_VECTCLRACTIVE_Msk (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos) /*!< SCB AIRCR: VECTCLRACTIVE Mask */ + +/* SCB System Control Register Definitions */ +#define SCB_SCR_SEVONPEND_Pos 4U /*!< SCB SCR: SEVONPEND Position */ +#define SCB_SCR_SEVONPEND_Msk (1UL << SCB_SCR_SEVONPEND_Pos) /*!< SCB SCR: SEVONPEND Mask */ + +#define SCB_SCR_SLEEPDEEPS_Pos 3U /*!< SCB SCR: SLEEPDEEPS Position */ +#define SCB_SCR_SLEEPDEEPS_Msk (1UL << SCB_SCR_SLEEPDEEPS_Pos) /*!< SCB SCR: SLEEPDEEPS Mask */ + +#define SCB_SCR_SLEEPDEEP_Pos 2U /*!< SCB SCR: SLEEPDEEP Position */ +#define SCB_SCR_SLEEPDEEP_Msk (1UL << SCB_SCR_SLEEPDEEP_Pos) /*!< SCB SCR: SLEEPDEEP Mask */ + +#define SCB_SCR_SLEEPONEXIT_Pos 1U /*!< SCB SCR: SLEEPONEXIT Position */ +#define SCB_SCR_SLEEPONEXIT_Msk (1UL << SCB_SCR_SLEEPONEXIT_Pos) /*!< SCB SCR: SLEEPONEXIT Mask */ + +/* SCB Configuration Control Register Definitions */ +#define SCB_CCR_BP_Pos 18U /*!< SCB CCR: BP Position */ +#define SCB_CCR_BP_Msk (1UL << SCB_CCR_BP_Pos) /*!< SCB CCR: BP Mask */ + +#define SCB_CCR_IC_Pos 17U /*!< SCB CCR: IC Position */ +#define SCB_CCR_IC_Msk (1UL << SCB_CCR_IC_Pos) /*!< SCB CCR: IC Mask */ + +#define SCB_CCR_DC_Pos 16U /*!< SCB CCR: DC Position */ +#define SCB_CCR_DC_Msk (1UL << SCB_CCR_DC_Pos) /*!< SCB CCR: DC Mask */ + +#define SCB_CCR_STKOFHFNMIGN_Pos 10U /*!< SCB CCR: STKOFHFNMIGN Position */ +#define SCB_CCR_STKOFHFNMIGN_Msk (1UL << SCB_CCR_STKOFHFNMIGN_Pos) /*!< SCB CCR: STKOFHFNMIGN Mask */ + +#define SCB_CCR_BFHFNMIGN_Pos 8U /*!< SCB CCR: BFHFNMIGN Position */ +#define SCB_CCR_BFHFNMIGN_Msk (1UL << SCB_CCR_BFHFNMIGN_Pos) /*!< SCB CCR: BFHFNMIGN Mask */ + +#define SCB_CCR_DIV_0_TRP_Pos 4U /*!< SCB CCR: DIV_0_TRP Position */ +#define SCB_CCR_DIV_0_TRP_Msk (1UL << SCB_CCR_DIV_0_TRP_Pos) /*!< SCB CCR: DIV_0_TRP Mask */ + +#define SCB_CCR_UNALIGN_TRP_Pos 3U /*!< SCB CCR: UNALIGN_TRP Position */ +#define SCB_CCR_UNALIGN_TRP_Msk (1UL << SCB_CCR_UNALIGN_TRP_Pos) /*!< SCB CCR: UNALIGN_TRP Mask */ + +#define SCB_CCR_USERSETMPEND_Pos 1U /*!< SCB CCR: USERSETMPEND Position */ +#define SCB_CCR_USERSETMPEND_Msk (1UL << SCB_CCR_USERSETMPEND_Pos) /*!< SCB CCR: USERSETMPEND Mask */ + +/* SCB System Handler Control and State Register Definitions */ +#define SCB_SHCSR_HARDFAULTPENDED_Pos 21U /*!< SCB SHCSR: HARDFAULTPENDED Position */ +#define SCB_SHCSR_HARDFAULTPENDED_Msk (1UL << SCB_SHCSR_HARDFAULTPENDED_Pos) /*!< SCB SHCSR: HARDFAULTPENDED Mask */ + +#define SCB_SHCSR_SVCALLPENDED_Pos 15U /*!< SCB SHCSR: SVCALLPENDED Position */ +#define SCB_SHCSR_SVCALLPENDED_Msk (1UL << SCB_SHCSR_SVCALLPENDED_Pos) /*!< SCB SHCSR: SVCALLPENDED Mask */ + +#define SCB_SHCSR_SYSTICKACT_Pos 11U /*!< SCB SHCSR: SYSTICKACT Position */ +#define SCB_SHCSR_SYSTICKACT_Msk (1UL << SCB_SHCSR_SYSTICKACT_Pos) /*!< SCB SHCSR: SYSTICKACT Mask */ + +#define SCB_SHCSR_PENDSVACT_Pos 10U /*!< SCB SHCSR: PENDSVACT Position */ +#define SCB_SHCSR_PENDSVACT_Msk (1UL << SCB_SHCSR_PENDSVACT_Pos) /*!< SCB SHCSR: PENDSVACT Mask */ + +#define SCB_SHCSR_SVCALLACT_Pos 7U /*!< SCB SHCSR: SVCALLACT Position */ +#define SCB_SHCSR_SVCALLACT_Msk (1UL << SCB_SHCSR_SVCALLACT_Pos) /*!< SCB SHCSR: SVCALLACT Mask */ + +#define SCB_SHCSR_NMIACT_Pos 5U /*!< SCB SHCSR: NMIACT Position */ +#define SCB_SHCSR_NMIACT_Msk (1UL << SCB_SHCSR_NMIACT_Pos) /*!< SCB SHCSR: NMIACT Mask */ + +#define SCB_SHCSR_HARDFAULTACT_Pos 2U /*!< SCB SHCSR: HARDFAULTACT Position */ +#define SCB_SHCSR_HARDFAULTACT_Msk (1UL << SCB_SHCSR_HARDFAULTACT_Pos) /*!< SCB SHCSR: HARDFAULTACT Mask */ + +/*@} end of group CMSIS_SCB */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SysTick System Tick Timer (SysTick) + \brief Type definitions for the System Timer Registers. + @{ + */ + +/** + \brief Structure type to access the System Timer (SysTick). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */ + __IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */ + __IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */ + __IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */ +} SysTick_Type; + +/* SysTick Control / Status Register Definitions */ +#define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */ +#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */ + +#define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */ +#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */ + +#define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */ +#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */ + +#define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */ +#define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */ + +/* SysTick Reload Register Definitions */ +#define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */ +#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */ + +/* SysTick Current Register Definitions */ +#define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */ +#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */ + +/* SysTick Calibration Register Definitions */ +#define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */ +#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */ + +#define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */ +#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */ + +#define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */ +#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */ + +/*@} end of group CMSIS_SysTick */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_DWT Data Watchpoint and Trace (DWT) + \brief Type definitions for the Data Watchpoint and Trace (DWT) + @{ + */ + +/** + \brief Structure type to access the Data Watchpoint and Trace Register (DWT). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) Control Register */ + uint32_t RESERVED0[6U]; + __IM uint32_t PCSR; /*!< Offset: 0x01C (R/ ) Program Counter Sample Register */ + __IOM uint32_t COMP0; /*!< Offset: 0x020 (R/W) Comparator Register 0 */ + uint32_t RESERVED1[1U]; + __IOM uint32_t FUNCTION0; /*!< Offset: 0x028 (R/W) Function Register 0 */ + uint32_t RESERVED2[1U]; + __IOM uint32_t COMP1; /*!< Offset: 0x030 (R/W) Comparator Register 1 */ + uint32_t RESERVED3[1U]; + __IOM uint32_t FUNCTION1; /*!< Offset: 0x038 (R/W) Function Register 1 */ + uint32_t RESERVED4[1U]; + __IOM uint32_t COMP2; /*!< Offset: 0x040 (R/W) Comparator Register 2 */ + uint32_t RESERVED5[1U]; + __IOM uint32_t FUNCTION2; /*!< Offset: 0x048 (R/W) Function Register 2 */ + uint32_t RESERVED6[1U]; + __IOM uint32_t COMP3; /*!< Offset: 0x050 (R/W) Comparator Register 3 */ + uint32_t RESERVED7[1U]; + __IOM uint32_t FUNCTION3; /*!< Offset: 0x058 (R/W) Function Register 3 */ + uint32_t RESERVED8[1U]; + __IOM uint32_t COMP4; /*!< Offset: 0x060 (R/W) Comparator Register 4 */ + uint32_t RESERVED9[1U]; + __IOM uint32_t FUNCTION4; /*!< Offset: 0x068 (R/W) Function Register 4 */ + uint32_t RESERVED10[1U]; + __IOM uint32_t COMP5; /*!< Offset: 0x070 (R/W) Comparator Register 5 */ + uint32_t RESERVED11[1U]; + __IOM uint32_t FUNCTION5; /*!< Offset: 0x078 (R/W) Function Register 5 */ + uint32_t RESERVED12[1U]; + __IOM uint32_t COMP6; /*!< Offset: 0x080 (R/W) Comparator Register 6 */ + uint32_t RESERVED13[1U]; + __IOM uint32_t FUNCTION6; /*!< Offset: 0x088 (R/W) Function Register 6 */ + uint32_t RESERVED14[1U]; + __IOM uint32_t COMP7; /*!< Offset: 0x090 (R/W) Comparator Register 7 */ + uint32_t RESERVED15[1U]; + __IOM uint32_t FUNCTION7; /*!< Offset: 0x098 (R/W) Function Register 7 */ + uint32_t RESERVED16[1U]; + __IOM uint32_t COMP8; /*!< Offset: 0x0A0 (R/W) Comparator Register 8 */ + uint32_t RESERVED17[1U]; + __IOM uint32_t FUNCTION8; /*!< Offset: 0x0A8 (R/W) Function Register 8 */ + uint32_t RESERVED18[1U]; + __IOM uint32_t COMP9; /*!< Offset: 0x0B0 (R/W) Comparator Register 9 */ + uint32_t RESERVED19[1U]; + __IOM uint32_t FUNCTION9; /*!< Offset: 0x0B8 (R/W) Function Register 9 */ + uint32_t RESERVED20[1U]; + __IOM uint32_t COMP10; /*!< Offset: 0x0C0 (R/W) Comparator Register 10 */ + uint32_t RESERVED21[1U]; + __IOM uint32_t FUNCTION10; /*!< Offset: 0x0C8 (R/W) Function Register 10 */ + uint32_t RESERVED22[1U]; + __IOM uint32_t COMP11; /*!< Offset: 0x0D0 (R/W) Comparator Register 11 */ + uint32_t RESERVED23[1U]; + __IOM uint32_t FUNCTION11; /*!< Offset: 0x0D8 (R/W) Function Register 11 */ + uint32_t RESERVED24[1U]; + __IOM uint32_t COMP12; /*!< Offset: 0x0E0 (R/W) Comparator Register 12 */ + uint32_t RESERVED25[1U]; + __IOM uint32_t FUNCTION12; /*!< Offset: 0x0E8 (R/W) Function Register 12 */ + uint32_t RESERVED26[1U]; + __IOM uint32_t COMP13; /*!< Offset: 0x0F0 (R/W) Comparator Register 13 */ + uint32_t RESERVED27[1U]; + __IOM uint32_t FUNCTION13; /*!< Offset: 0x0F8 (R/W) Function Register 13 */ + uint32_t RESERVED28[1U]; + __IOM uint32_t COMP14; /*!< Offset: 0x100 (R/W) Comparator Register 14 */ + uint32_t RESERVED29[1U]; + __IOM uint32_t FUNCTION14; /*!< Offset: 0x108 (R/W) Function Register 14 */ + uint32_t RESERVED30[1U]; + __IOM uint32_t COMP15; /*!< Offset: 0x110 (R/W) Comparator Register 15 */ + uint32_t RESERVED31[1U]; + __IOM uint32_t FUNCTION15; /*!< Offset: 0x118 (R/W) Function Register 15 */ +} DWT_Type; + +/* DWT Control Register Definitions */ +#define DWT_CTRL_NUMCOMP_Pos 28U /*!< DWT CTRL: NUMCOMP Position */ +#define DWT_CTRL_NUMCOMP_Msk (0xFUL << DWT_CTRL_NUMCOMP_Pos) /*!< DWT CTRL: NUMCOMP Mask */ + +#define DWT_CTRL_NOTRCPKT_Pos 27U /*!< DWT CTRL: NOTRCPKT Position */ +#define DWT_CTRL_NOTRCPKT_Msk (0x1UL << DWT_CTRL_NOTRCPKT_Pos) /*!< DWT CTRL: NOTRCPKT Mask */ + +#define DWT_CTRL_NOEXTTRIG_Pos 26U /*!< DWT CTRL: NOEXTTRIG Position */ +#define DWT_CTRL_NOEXTTRIG_Msk (0x1UL << DWT_CTRL_NOEXTTRIG_Pos) /*!< DWT CTRL: NOEXTTRIG Mask */ + +#define DWT_CTRL_NOCYCCNT_Pos 25U /*!< DWT CTRL: NOCYCCNT Position */ +#define DWT_CTRL_NOCYCCNT_Msk (0x1UL << DWT_CTRL_NOCYCCNT_Pos) /*!< DWT CTRL: NOCYCCNT Mask */ + +#define DWT_CTRL_NOPRFCNT_Pos 24U /*!< DWT CTRL: NOPRFCNT Position */ +#define DWT_CTRL_NOPRFCNT_Msk (0x1UL << DWT_CTRL_NOPRFCNT_Pos) /*!< DWT CTRL: NOPRFCNT Mask */ + +/* DWT Comparator Function Register Definitions */ +#define DWT_FUNCTION_ID_Pos 27U /*!< DWT FUNCTION: ID Position */ +#define DWT_FUNCTION_ID_Msk (0x1FUL << DWT_FUNCTION_ID_Pos) /*!< DWT FUNCTION: ID Mask */ + +#define DWT_FUNCTION_MATCHED_Pos 24U /*!< DWT FUNCTION: MATCHED Position */ +#define DWT_FUNCTION_MATCHED_Msk (0x1UL << DWT_FUNCTION_MATCHED_Pos) /*!< DWT FUNCTION: MATCHED Mask */ + +#define DWT_FUNCTION_DATAVSIZE_Pos 10U /*!< DWT FUNCTION: DATAVSIZE Position */ +#define DWT_FUNCTION_DATAVSIZE_Msk (0x3UL << DWT_FUNCTION_DATAVSIZE_Pos) /*!< DWT FUNCTION: DATAVSIZE Mask */ + +#define DWT_FUNCTION_ACTION_Pos 4U /*!< DWT FUNCTION: ACTION Position */ +#define DWT_FUNCTION_ACTION_Msk (0x3UL << DWT_FUNCTION_ACTION_Pos) /*!< DWT FUNCTION: ACTION Mask */ + +#define DWT_FUNCTION_MATCH_Pos 0U /*!< DWT FUNCTION: MATCH Position */ +#define DWT_FUNCTION_MATCH_Msk (0xFUL /*<< DWT_FUNCTION_MATCH_Pos*/) /*!< DWT FUNCTION: MATCH Mask */ + +/*@}*/ /* end of group CMSIS_DWT */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_TPI Trace Port Interface (TPI) + \brief Type definitions for the Trace Port Interface (TPI) + @{ + */ + +/** + \brief Structure type to access the Trace Port Interface Register (TPI). + */ +typedef struct +{ + __IM uint32_t SSPSR; /*!< Offset: 0x000 (R/ ) Supported Parallel Port Sizes Register */ + __IOM uint32_t CSPSR; /*!< Offset: 0x004 (R/W) Current Parallel Port Sizes Register */ + uint32_t RESERVED0[2U]; + __IOM uint32_t ACPR; /*!< Offset: 0x010 (R/W) Asynchronous Clock Prescaler Register */ + uint32_t RESERVED1[55U]; + __IOM uint32_t SPPR; /*!< Offset: 0x0F0 (R/W) Selected Pin Protocol Register */ + uint32_t RESERVED2[131U]; + __IM uint32_t FFSR; /*!< Offset: 0x300 (R/ ) Formatter and Flush Status Register */ + __IOM uint32_t FFCR; /*!< Offset: 0x304 (R/W) Formatter and Flush Control Register */ + __IOM uint32_t PSCR; /*!< Offset: 0x308 (R/W) Periodic Synchronization Control Register */ + uint32_t RESERVED3[809U]; + __OM uint32_t LAR; /*!< Offset: 0xFB0 ( /W) Software Lock Access Register */ + __IM uint32_t LSR; /*!< Offset: 0xFB4 (R/ ) Software Lock Status Register */ + uint32_t RESERVED4[4U]; + __IM uint32_t TYPE; /*!< Offset: 0xFC8 (R/ ) Device Identifier Register */ + __IM uint32_t DEVTYPE; /*!< Offset: 0xFCC (R/ ) Device Type Register */ +} TPI_Type; + +/* TPI Asynchronous Clock Prescaler Register Definitions */ +#define TPI_ACPR_SWOSCALER_Pos 0U /*!< TPI ACPR: SWOSCALER Position */ +#define TPI_ACPR_SWOSCALER_Msk (0xFFFFUL /*<< TPI_ACPR_SWOSCALER_Pos*/) /*!< TPI ACPR: SWOSCALER Mask */ + +/* TPI Selected Pin Protocol Register Definitions */ +#define TPI_SPPR_TXMODE_Pos 0U /*!< TPI SPPR: TXMODE Position */ +#define TPI_SPPR_TXMODE_Msk (0x3UL /*<< TPI_SPPR_TXMODE_Pos*/) /*!< TPI SPPR: TXMODE Mask */ + +/* TPI Formatter and Flush Status Register Definitions */ +#define TPI_FFSR_FtNonStop_Pos 3U /*!< TPI FFSR: FtNonStop Position */ +#define TPI_FFSR_FtNonStop_Msk (0x1UL << TPI_FFSR_FtNonStop_Pos) /*!< TPI FFSR: FtNonStop Mask */ + +#define TPI_FFSR_TCPresent_Pos 2U /*!< TPI FFSR: TCPresent Position */ +#define TPI_FFSR_TCPresent_Msk (0x1UL << TPI_FFSR_TCPresent_Pos) /*!< TPI FFSR: TCPresent Mask */ + +#define TPI_FFSR_FtStopped_Pos 1U /*!< TPI FFSR: FtStopped Position */ +#define TPI_FFSR_FtStopped_Msk (0x1UL << TPI_FFSR_FtStopped_Pos) /*!< TPI FFSR: FtStopped Mask */ + +#define TPI_FFSR_FlInProg_Pos 0U /*!< TPI FFSR: FlInProg Position */ +#define TPI_FFSR_FlInProg_Msk (0x1UL /*<< TPI_FFSR_FlInProg_Pos*/) /*!< TPI FFSR: FlInProg Mask */ + +/* TPI Formatter and Flush Control Register Definitions */ +#define TPI_FFCR_TrigIn_Pos 8U /*!< TPI FFCR: TrigIn Position */ +#define TPI_FFCR_TrigIn_Msk (0x1UL << TPI_FFCR_TrigIn_Pos) /*!< TPI FFCR: TrigIn Mask */ + +#define TPI_FFCR_FOnMan_Pos 6U /*!< TPI FFCR: FOnMan Position */ +#define TPI_FFCR_FOnMan_Msk (0x1UL << TPI_FFCR_FOnMan_Pos) /*!< TPI FFCR: FOnMan Mask */ + +#define TPI_FFCR_EnFCont_Pos 1U /*!< TPI FFCR: EnFCont Position */ +#define TPI_FFCR_EnFCont_Msk (0x1UL << TPI_FFCR_EnFCont_Pos) /*!< TPI FFCR: EnFCont Mask */ + +/* TPI Periodic Synchronization Control Register Definitions */ +#define TPI_PSCR_PSCount_Pos 0U /*!< TPI PSCR: PSCount Position */ +#define TPI_PSCR_PSCount_Msk (0x1FUL /*<< TPI_PSCR_PSCount_Pos*/) /*!< TPI PSCR: TPSCount Mask */ + +/* TPI Software Lock Status Register Definitions */ +#define TPI_LSR_nTT_Pos 1U /*!< TPI LSR: Not thirty-two bit. Position */ +#define TPI_LSR_nTT_Msk (0x1UL << TPI_LSR_nTT_Pos) /*!< TPI LSR: Not thirty-two bit. Mask */ + +#define TPI_LSR_SLK_Pos 1U /*!< TPI LSR: Software Lock status Position */ +#define TPI_LSR_SLK_Msk (0x1UL << TPI_LSR_SLK_Pos) /*!< TPI LSR: Software Lock status Mask */ + +#define TPI_LSR_SLI_Pos 0U /*!< TPI LSR: Software Lock implemented Position */ +#define TPI_LSR_SLI_Msk (0x1UL /*<< TPI_LSR_SLI_Pos*/) /*!< TPI LSR: Software Lock implemented Mask */ + +/* TPI DEVID Register Definitions */ +#define TPI_DEVID_NRZVALID_Pos 11U /*!< TPI DEVID: NRZVALID Position */ +#define TPI_DEVID_NRZVALID_Msk (0x1UL << TPI_DEVID_NRZVALID_Pos) /*!< TPI DEVID: NRZVALID Mask */ + +#define TPI_DEVID_MANCVALID_Pos 10U /*!< TPI DEVID: MANCVALID Position */ +#define TPI_DEVID_MANCVALID_Msk (0x1UL << TPI_DEVID_MANCVALID_Pos) /*!< TPI DEVID: MANCVALID Mask */ + +#define TPI_DEVID_PTINVALID_Pos 9U /*!< TPI DEVID: PTINVALID Position */ +#define TPI_DEVID_PTINVALID_Msk (0x1UL << TPI_DEVID_PTINVALID_Pos) /*!< TPI DEVID: PTINVALID Mask */ + +#define TPI_DEVID_FIFOSZ_Pos 6U /*!< TPI DEVID: FIFO depth Position */ +#define TPI_DEVID_FIFOSZ_Msk (0x7UL << TPI_DEVID_FIFOSZ_Pos) /*!< TPI DEVID: FIFO depth Mask */ + +/* TPI DEVTYPE Register Definitions */ +#define TPI_DEVTYPE_SubType_Pos 4U /*!< TPI DEVTYPE: SubType Position */ +#define TPI_DEVTYPE_SubType_Msk (0xFUL /*<< TPI_DEVTYPE_SubType_Pos*/) /*!< TPI DEVTYPE: SubType Mask */ + +#define TPI_DEVTYPE_MajorType_Pos 0U /*!< TPI DEVTYPE: MajorType Position */ +#define TPI_DEVTYPE_MajorType_Msk (0xFUL << TPI_DEVTYPE_MajorType_Pos) /*!< TPI DEVTYPE: MajorType Mask */ + +/*@}*/ /* end of group CMSIS_TPI */ + + +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_MPU Memory Protection Unit (MPU) + \brief Type definitions for the Memory Protection Unit (MPU) + @{ + */ + +/** + \brief Structure type to access the Memory Protection Unit (MPU). + */ +typedef struct +{ + __IM uint32_t TYPE; /*!< Offset: 0x000 (R/ ) MPU Type Register */ + __IOM uint32_t CTRL; /*!< Offset: 0x004 (R/W) MPU Control Register */ + __IOM uint32_t RNR; /*!< Offset: 0x008 (R/W) MPU Region Number Register */ + __IOM uint32_t RBAR; /*!< Offset: 0x00C (R/W) MPU Region Base Address Register */ + __IOM uint32_t RLAR; /*!< Offset: 0x010 (R/W) MPU Region Limit Address Register */ + uint32_t RESERVED0[7U]; + union { + __IOM uint32_t MAIR[2]; + struct { + __IOM uint32_t MAIR0; /*!< Offset: 0x030 (R/W) MPU Memory Attribute Indirection Register 0 */ + __IOM uint32_t MAIR1; /*!< Offset: 0x034 (R/W) MPU Memory Attribute Indirection Register 1 */ + }; + }; +} MPU_Type; + +#define MPU_TYPE_RALIASES 1U + +/* MPU Type Register Definitions */ +#define MPU_TYPE_IREGION_Pos 16U /*!< MPU TYPE: IREGION Position */ +#define MPU_TYPE_IREGION_Msk (0xFFUL << MPU_TYPE_IREGION_Pos) /*!< MPU TYPE: IREGION Mask */ + +#define MPU_TYPE_DREGION_Pos 8U /*!< MPU TYPE: DREGION Position */ +#define MPU_TYPE_DREGION_Msk (0xFFUL << MPU_TYPE_DREGION_Pos) /*!< MPU TYPE: DREGION Mask */ + +#define MPU_TYPE_SEPARATE_Pos 0U /*!< MPU TYPE: SEPARATE Position */ +#define MPU_TYPE_SEPARATE_Msk (1UL /*<< MPU_TYPE_SEPARATE_Pos*/) /*!< MPU TYPE: SEPARATE Mask */ + +/* MPU Control Register Definitions */ +#define MPU_CTRL_PRIVDEFENA_Pos 2U /*!< MPU CTRL: PRIVDEFENA Position */ +#define MPU_CTRL_PRIVDEFENA_Msk (1UL << MPU_CTRL_PRIVDEFENA_Pos) /*!< MPU CTRL: PRIVDEFENA Mask */ + +#define MPU_CTRL_HFNMIENA_Pos 1U /*!< MPU CTRL: HFNMIENA Position */ +#define MPU_CTRL_HFNMIENA_Msk (1UL << MPU_CTRL_HFNMIENA_Pos) /*!< MPU CTRL: HFNMIENA Mask */ + +#define MPU_CTRL_ENABLE_Pos 0U /*!< MPU CTRL: ENABLE Position */ +#define MPU_CTRL_ENABLE_Msk (1UL /*<< MPU_CTRL_ENABLE_Pos*/) /*!< MPU CTRL: ENABLE Mask */ + +/* MPU Region Number Register Definitions */ +#define MPU_RNR_REGION_Pos 0U /*!< MPU RNR: REGION Position */ +#define MPU_RNR_REGION_Msk (0xFFUL /*<< MPU_RNR_REGION_Pos*/) /*!< MPU RNR: REGION Mask */ + +/* MPU Region Base Address Register Definitions */ +#define MPU_RBAR_BASE_Pos 5U /*!< MPU RBAR: BASE Position */ +#define MPU_RBAR_BASE_Msk (0x7FFFFFFUL << MPU_RBAR_BASE_Pos) /*!< MPU RBAR: BASE Mask */ + +#define MPU_RBAR_SH_Pos 3U /*!< MPU RBAR: SH Position */ +#define MPU_RBAR_SH_Msk (0x3UL << MPU_RBAR_SH_Pos) /*!< MPU RBAR: SH Mask */ + +#define MPU_RBAR_AP_Pos 1U /*!< MPU RBAR: AP Position */ +#define MPU_RBAR_AP_Msk (0x3UL << MPU_RBAR_AP_Pos) /*!< MPU RBAR: AP Mask */ + +#define MPU_RBAR_XN_Pos 0U /*!< MPU RBAR: XN Position */ +#define MPU_RBAR_XN_Msk (01UL /*<< MPU_RBAR_XN_Pos*/) /*!< MPU RBAR: XN Mask */ + +/* MPU Region Limit Address Register Definitions */ +#define MPU_RLAR_LIMIT_Pos 5U /*!< MPU RLAR: LIMIT Position */ +#define MPU_RLAR_LIMIT_Msk (0x7FFFFFFUL << MPU_RLAR_LIMIT_Pos) /*!< MPU RLAR: LIMIT Mask */ + +#define MPU_RLAR_AttrIndx_Pos 1U /*!< MPU RLAR: AttrIndx Position */ +#define MPU_RLAR_AttrIndx_Msk (0x7UL << MPU_RLAR_AttrIndx_Pos) /*!< MPU RLAR: AttrIndx Mask */ + +#define MPU_RLAR_EN_Pos 0U /*!< MPU RLAR: EN Position */ +#define MPU_RLAR_EN_Msk (1UL /*<< MPU_RLAR_EN_Pos*/) /*!< MPU RLAR: EN Mask */ + +/* MPU Memory Attribute Indirection Register 0 Definitions */ +#define MPU_MAIR0_Attr3_Pos 24U /*!< MPU MAIR0: Attr3 Position */ +#define MPU_MAIR0_Attr3_Msk (0xFFUL << MPU_MAIR0_Attr3_Pos) /*!< MPU MAIR0: Attr3 Mask */ + +#define MPU_MAIR0_Attr2_Pos 16U /*!< MPU MAIR0: Attr2 Position */ +#define MPU_MAIR0_Attr2_Msk (0xFFUL << MPU_MAIR0_Attr2_Pos) /*!< MPU MAIR0: Attr2 Mask */ + +#define MPU_MAIR0_Attr1_Pos 8U /*!< MPU MAIR0: Attr1 Position */ +#define MPU_MAIR0_Attr1_Msk (0xFFUL << MPU_MAIR0_Attr1_Pos) /*!< MPU MAIR0: Attr1 Mask */ + +#define MPU_MAIR0_Attr0_Pos 0U /*!< MPU MAIR0: Attr0 Position */ +#define MPU_MAIR0_Attr0_Msk (0xFFUL /*<< MPU_MAIR0_Attr0_Pos*/) /*!< MPU MAIR0: Attr0 Mask */ + +/* MPU Memory Attribute Indirection Register 1 Definitions */ +#define MPU_MAIR1_Attr7_Pos 24U /*!< MPU MAIR1: Attr7 Position */ +#define MPU_MAIR1_Attr7_Msk (0xFFUL << MPU_MAIR1_Attr7_Pos) /*!< MPU MAIR1: Attr7 Mask */ + +#define MPU_MAIR1_Attr6_Pos 16U /*!< MPU MAIR1: Attr6 Position */ +#define MPU_MAIR1_Attr6_Msk (0xFFUL << MPU_MAIR1_Attr6_Pos) /*!< MPU MAIR1: Attr6 Mask */ + +#define MPU_MAIR1_Attr5_Pos 8U /*!< MPU MAIR1: Attr5 Position */ +#define MPU_MAIR1_Attr5_Msk (0xFFUL << MPU_MAIR1_Attr5_Pos) /*!< MPU MAIR1: Attr5 Mask */ + +#define MPU_MAIR1_Attr4_Pos 0U /*!< MPU MAIR1: Attr4 Position */ +#define MPU_MAIR1_Attr4_Msk (0xFFUL /*<< MPU_MAIR1_Attr4_Pos*/) /*!< MPU MAIR1: Attr4 Mask */ + +/*@} end of group CMSIS_MPU */ +#endif + + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SAU Security Attribution Unit (SAU) + \brief Type definitions for the Security Attribution Unit (SAU) + @{ + */ + +/** + \brief Structure type to access the Security Attribution Unit (SAU). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SAU Control Register */ + __IM uint32_t TYPE; /*!< Offset: 0x004 (R/ ) SAU Type Register */ +#if defined (__SAUREGION_PRESENT) && (__SAUREGION_PRESENT == 1U) + __IOM uint32_t RNR; /*!< Offset: 0x008 (R/W) SAU Region Number Register */ + __IOM uint32_t RBAR; /*!< Offset: 0x00C (R/W) SAU Region Base Address Register */ + __IOM uint32_t RLAR; /*!< Offset: 0x010 (R/W) SAU Region Limit Address Register */ +#endif +} SAU_Type; + +/* SAU Control Register Definitions */ +#define SAU_CTRL_ALLNS_Pos 1U /*!< SAU CTRL: ALLNS Position */ +#define SAU_CTRL_ALLNS_Msk (1UL << SAU_CTRL_ALLNS_Pos) /*!< SAU CTRL: ALLNS Mask */ + +#define SAU_CTRL_ENABLE_Pos 0U /*!< SAU CTRL: ENABLE Position */ +#define SAU_CTRL_ENABLE_Msk (1UL /*<< SAU_CTRL_ENABLE_Pos*/) /*!< SAU CTRL: ENABLE Mask */ + +/* SAU Type Register Definitions */ +#define SAU_TYPE_SREGION_Pos 0U /*!< SAU TYPE: SREGION Position */ +#define SAU_TYPE_SREGION_Msk (0xFFUL /*<< SAU_TYPE_SREGION_Pos*/) /*!< SAU TYPE: SREGION Mask */ + +#if defined (__SAUREGION_PRESENT) && (__SAUREGION_PRESENT == 1U) +/* SAU Region Number Register Definitions */ +#define SAU_RNR_REGION_Pos 0U /*!< SAU RNR: REGION Position */ +#define SAU_RNR_REGION_Msk (0xFFUL /*<< SAU_RNR_REGION_Pos*/) /*!< SAU RNR: REGION Mask */ + +/* SAU Region Base Address Register Definitions */ +#define SAU_RBAR_BADDR_Pos 5U /*!< SAU RBAR: BADDR Position */ +#define SAU_RBAR_BADDR_Msk (0x7FFFFFFUL << SAU_RBAR_BADDR_Pos) /*!< SAU RBAR: BADDR Mask */ + +/* SAU Region Limit Address Register Definitions */ +#define SAU_RLAR_LADDR_Pos 5U /*!< SAU RLAR: LADDR Position */ +#define SAU_RLAR_LADDR_Msk (0x7FFFFFFUL << SAU_RLAR_LADDR_Pos) /*!< SAU RLAR: LADDR Mask */ + +#define SAU_RLAR_NSC_Pos 1U /*!< SAU RLAR: NSC Position */ +#define SAU_RLAR_NSC_Msk (1UL << SAU_RLAR_NSC_Pos) /*!< SAU RLAR: NSC Mask */ + +#define SAU_RLAR_ENABLE_Pos 0U /*!< SAU RLAR: ENABLE Position */ +#define SAU_RLAR_ENABLE_Msk (1UL /*<< SAU_RLAR_ENABLE_Pos*/) /*!< SAU RLAR: ENABLE Mask */ + +#endif /* defined (__SAUREGION_PRESENT) && (__SAUREGION_PRESENT == 1U) */ + +/*@} end of group CMSIS_SAU */ +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CoreDebug Core Debug Registers (CoreDebug) + \brief Type definitions for the Core Debug Registers + @{ + */ + +/** + \brief Structure type to access the Core Debug Register (CoreDebug). + */ +typedef struct +{ + __IOM uint32_t DHCSR; /*!< Offset: 0x000 (R/W) Debug Halting Control and Status Register */ + __OM uint32_t DCRSR; /*!< Offset: 0x004 ( /W) Debug Core Register Selector Register */ + __IOM uint32_t DCRDR; /*!< Offset: 0x008 (R/W) Debug Core Register Data Register */ + __IOM uint32_t DEMCR; /*!< Offset: 0x00C (R/W) Debug Exception and Monitor Control Register */ + uint32_t RESERVED4[1U]; + __IOM uint32_t DAUTHCTRL; /*!< Offset: 0x014 (R/W) Debug Authentication Control Register */ + __IOM uint32_t DSCSR; /*!< Offset: 0x018 (R/W) Debug Security Control and Status Register */ +} CoreDebug_Type; + +/* Debug Halting Control and Status Register Definitions */ +#define CoreDebug_DHCSR_DBGKEY_Pos 16U /*!< CoreDebug DHCSR: DBGKEY Position */ +#define CoreDebug_DHCSR_DBGKEY_Msk (0xFFFFUL << CoreDebug_DHCSR_DBGKEY_Pos) /*!< CoreDebug DHCSR: DBGKEY Mask */ + +#define CoreDebug_DHCSR_S_RESTART_ST_Pos 26U /*!< CoreDebug DHCSR: S_RESTART_ST Position */ +#define CoreDebug_DHCSR_S_RESTART_ST_Msk (1UL << CoreDebug_DHCSR_S_RESTART_ST_Pos) /*!< CoreDebug DHCSR: S_RESTART_ST Mask */ + +#define CoreDebug_DHCSR_S_RESET_ST_Pos 25U /*!< CoreDebug DHCSR: S_RESET_ST Position */ +#define CoreDebug_DHCSR_S_RESET_ST_Msk (1UL << CoreDebug_DHCSR_S_RESET_ST_Pos) /*!< CoreDebug DHCSR: S_RESET_ST Mask */ + +#define CoreDebug_DHCSR_S_RETIRE_ST_Pos 24U /*!< CoreDebug DHCSR: S_RETIRE_ST Position */ +#define CoreDebug_DHCSR_S_RETIRE_ST_Msk (1UL << CoreDebug_DHCSR_S_RETIRE_ST_Pos) /*!< CoreDebug DHCSR: S_RETIRE_ST Mask */ + +#define CoreDebug_DHCSR_S_LOCKUP_Pos 19U /*!< CoreDebug DHCSR: S_LOCKUP Position */ +#define CoreDebug_DHCSR_S_LOCKUP_Msk (1UL << CoreDebug_DHCSR_S_LOCKUP_Pos) /*!< CoreDebug DHCSR: S_LOCKUP Mask */ + +#define CoreDebug_DHCSR_S_SLEEP_Pos 18U /*!< CoreDebug DHCSR: S_SLEEP Position */ +#define CoreDebug_DHCSR_S_SLEEP_Msk (1UL << CoreDebug_DHCSR_S_SLEEP_Pos) /*!< CoreDebug DHCSR: S_SLEEP Mask */ + +#define CoreDebug_DHCSR_S_HALT_Pos 17U /*!< CoreDebug DHCSR: S_HALT Position */ +#define CoreDebug_DHCSR_S_HALT_Msk (1UL << CoreDebug_DHCSR_S_HALT_Pos) /*!< CoreDebug DHCSR: S_HALT Mask */ + +#define CoreDebug_DHCSR_S_REGRDY_Pos 16U /*!< CoreDebug DHCSR: S_REGRDY Position */ +#define CoreDebug_DHCSR_S_REGRDY_Msk (1UL << CoreDebug_DHCSR_S_REGRDY_Pos) /*!< CoreDebug DHCSR: S_REGRDY Mask */ + +#define CoreDebug_DHCSR_C_MASKINTS_Pos 3U /*!< CoreDebug DHCSR: C_MASKINTS Position */ +#define CoreDebug_DHCSR_C_MASKINTS_Msk (1UL << CoreDebug_DHCSR_C_MASKINTS_Pos) /*!< CoreDebug DHCSR: C_MASKINTS Mask */ + +#define CoreDebug_DHCSR_C_STEP_Pos 2U /*!< CoreDebug DHCSR: C_STEP Position */ +#define CoreDebug_DHCSR_C_STEP_Msk (1UL << CoreDebug_DHCSR_C_STEP_Pos) /*!< CoreDebug DHCSR: C_STEP Mask */ + +#define CoreDebug_DHCSR_C_HALT_Pos 1U /*!< CoreDebug DHCSR: C_HALT Position */ +#define CoreDebug_DHCSR_C_HALT_Msk (1UL << CoreDebug_DHCSR_C_HALT_Pos) /*!< CoreDebug DHCSR: C_HALT Mask */ + +#define CoreDebug_DHCSR_C_DEBUGEN_Pos 0U /*!< CoreDebug DHCSR: C_DEBUGEN Position */ +#define CoreDebug_DHCSR_C_DEBUGEN_Msk (1UL /*<< CoreDebug_DHCSR_C_DEBUGEN_Pos*/) /*!< CoreDebug DHCSR: C_DEBUGEN Mask */ + +/* Debug Core Register Selector Register Definitions */ +#define CoreDebug_DCRSR_REGWnR_Pos 16U /*!< CoreDebug DCRSR: REGWnR Position */ +#define CoreDebug_DCRSR_REGWnR_Msk (1UL << CoreDebug_DCRSR_REGWnR_Pos) /*!< CoreDebug DCRSR: REGWnR Mask */ + +#define CoreDebug_DCRSR_REGSEL_Pos 0U /*!< CoreDebug DCRSR: REGSEL Position */ +#define CoreDebug_DCRSR_REGSEL_Msk (0x1FUL /*<< CoreDebug_DCRSR_REGSEL_Pos*/) /*!< CoreDebug DCRSR: REGSEL Mask */ + +/* Debug Exception and Monitor Control Register */ +#define CoreDebug_DEMCR_DWTENA_Pos 24U /*!< CoreDebug DEMCR: DWTENA Position */ +#define CoreDebug_DEMCR_DWTENA_Msk (1UL << CoreDebug_DEMCR_DWTENA_Pos) /*!< CoreDebug DEMCR: DWTENA Mask */ + +#define CoreDebug_DEMCR_VC_HARDERR_Pos 10U /*!< CoreDebug DEMCR: VC_HARDERR Position */ +#define CoreDebug_DEMCR_VC_HARDERR_Msk (1UL << CoreDebug_DEMCR_VC_HARDERR_Pos) /*!< CoreDebug DEMCR: VC_HARDERR Mask */ + +#define CoreDebug_DEMCR_VC_CORERESET_Pos 0U /*!< CoreDebug DEMCR: VC_CORERESET Position */ +#define CoreDebug_DEMCR_VC_CORERESET_Msk (1UL /*<< CoreDebug_DEMCR_VC_CORERESET_Pos*/) /*!< CoreDebug DEMCR: VC_CORERESET Mask */ + +/* Debug Authentication Control Register Definitions */ +#define CoreDebug_DAUTHCTRL_INTSPNIDEN_Pos 3U /*!< CoreDebug DAUTHCTRL: INTSPNIDEN, Position */ +#define CoreDebug_DAUTHCTRL_INTSPNIDEN_Msk (1UL << CoreDebug_DAUTHCTRL_INTSPNIDEN_Pos) /*!< CoreDebug DAUTHCTRL: INTSPNIDEN, Mask */ + +#define CoreDebug_DAUTHCTRL_SPNIDENSEL_Pos 2U /*!< CoreDebug DAUTHCTRL: SPNIDENSEL Position */ +#define CoreDebug_DAUTHCTRL_SPNIDENSEL_Msk (1UL << CoreDebug_DAUTHCTRL_SPNIDENSEL_Pos) /*!< CoreDebug DAUTHCTRL: SPNIDENSEL Mask */ + +#define CoreDebug_DAUTHCTRL_INTSPIDEN_Pos 1U /*!< CoreDebug DAUTHCTRL: INTSPIDEN Position */ +#define CoreDebug_DAUTHCTRL_INTSPIDEN_Msk (1UL << CoreDebug_DAUTHCTRL_INTSPIDEN_Pos) /*!< CoreDebug DAUTHCTRL: INTSPIDEN Mask */ + +#define CoreDebug_DAUTHCTRL_SPIDENSEL_Pos 0U /*!< CoreDebug DAUTHCTRL: SPIDENSEL Position */ +#define CoreDebug_DAUTHCTRL_SPIDENSEL_Msk (1UL /*<< CoreDebug_DAUTHCTRL_SPIDENSEL_Pos*/) /*!< CoreDebug DAUTHCTRL: SPIDENSEL Mask */ + +/* Debug Security Control and Status Register Definitions */ +#define CoreDebug_DSCSR_CDS_Pos 16U /*!< CoreDebug DSCSR: CDS Position */ +#define CoreDebug_DSCSR_CDS_Msk (1UL << CoreDebug_DSCSR_CDS_Pos) /*!< CoreDebug DSCSR: CDS Mask */ + +#define CoreDebug_DSCSR_SBRSEL_Pos 1U /*!< CoreDebug DSCSR: SBRSEL Position */ +#define CoreDebug_DSCSR_SBRSEL_Msk (1UL << CoreDebug_DSCSR_SBRSEL_Pos) /*!< CoreDebug DSCSR: SBRSEL Mask */ + +#define CoreDebug_DSCSR_SBRSELEN_Pos 0U /*!< CoreDebug DSCSR: SBRSELEN Position */ +#define CoreDebug_DSCSR_SBRSELEN_Msk (1UL /*<< CoreDebug_DSCSR_SBRSELEN_Pos*/) /*!< CoreDebug DSCSR: SBRSELEN Mask */ + +/*@} end of group CMSIS_CoreDebug */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_bitfield Core register bit field macros + \brief Macros for use with bit field definitions (xxx_Pos, xxx_Msk). + @{ + */ + +/** + \brief Mask and shift a bit field value for use in a register bit range. + \param[in] field Name of the register bit field. + \param[in] value Value of the bit field. This parameter is interpreted as an uint32_t type. + \return Masked and shifted value. +*/ +#define _VAL2FLD(field, value) (((uint32_t)(value) << field ## _Pos) & field ## _Msk) + +/** + \brief Mask and shift a register value to extract a bit filed value. + \param[in] field Name of the register bit field. + \param[in] value Value of register. This parameter is interpreted as an uint32_t type. + \return Masked and shifted bit field value. +*/ +#define _FLD2VAL(field, value) (((uint32_t)(value) & field ## _Msk) >> field ## _Pos) + +/*@} end of group CMSIS_core_bitfield */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_base Core Definitions + \brief Definitions for base addresses, unions, and structures. + @{ + */ + +/* Memory mapping of Core Hardware */ + #define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ + #define DWT_BASE (0xE0001000UL) /*!< DWT Base Address */ + #define TPI_BASE (0xE0040000UL) /*!< TPI Base Address */ + #define CoreDebug_BASE (0xE000EDF0UL) /*!< Core Debug Base Address */ + #define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */ + #define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */ + #define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */ + + + #define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */ + #define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */ + #define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */ + #define DWT ((DWT_Type *) DWT_BASE ) /*!< DWT configuration struct */ + #define TPI ((TPI_Type *) TPI_BASE ) /*!< TPI configuration struct */ + #define CoreDebug ((CoreDebug_Type *) CoreDebug_BASE ) /*!< Core Debug configuration struct */ + + #if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + #define MPU_BASE (SCS_BASE + 0x0D90UL) /*!< Memory Protection Unit */ + #define MPU ((MPU_Type *) MPU_BASE ) /*!< Memory Protection Unit */ + #endif + + #if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + #define SAU_BASE (SCS_BASE + 0x0DD0UL) /*!< Security Attribution Unit */ + #define SAU ((SAU_Type *) SAU_BASE ) /*!< Security Attribution Unit */ + #endif + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + #define SCS_BASE_NS (0xE002E000UL) /*!< System Control Space Base Address (non-secure address space) */ + #define CoreDebug_BASE_NS (0xE002EDF0UL) /*!< Core Debug Base Address (non-secure address space) */ + #define SysTick_BASE_NS (SCS_BASE_NS + 0x0010UL) /*!< SysTick Base Address (non-secure address space) */ + #define NVIC_BASE_NS (SCS_BASE_NS + 0x0100UL) /*!< NVIC Base Address (non-secure address space) */ + #define SCB_BASE_NS (SCS_BASE_NS + 0x0D00UL) /*!< System Control Block Base Address (non-secure address space) */ + + #define SCB_NS ((SCB_Type *) SCB_BASE_NS ) /*!< SCB configuration struct (non-secure address space) */ + #define SysTick_NS ((SysTick_Type *) SysTick_BASE_NS ) /*!< SysTick configuration struct (non-secure address space) */ + #define NVIC_NS ((NVIC_Type *) NVIC_BASE_NS ) /*!< NVIC configuration struct (non-secure address space) */ + #define CoreDebug_NS ((CoreDebug_Type *) CoreDebug_BASE_NS) /*!< Core Debug configuration struct (non-secure address space) */ + + #if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + #define MPU_BASE_NS (SCS_BASE_NS + 0x0D90UL) /*!< Memory Protection Unit (non-secure address space) */ + #define MPU_NS ((MPU_Type *) MPU_BASE_NS ) /*!< Memory Protection Unit (non-secure address space) */ + #endif + +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ +/*@} */ + + + +/******************************************************************************* + * Hardware Abstraction Layer + Core Function Interface contains: + - Core NVIC Functions + - Core SysTick Functions + - Core Register Access Functions + ******************************************************************************/ +/** + \defgroup CMSIS_Core_FunctionInterface Functions and Instructions Reference +*/ + + + +/* ########################## NVIC functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_NVICFunctions NVIC Functions + \brief Functions that manage interrupts and exceptions via the NVIC. + @{ + */ + +#ifdef CMSIS_NVIC_VIRTUAL + #ifndef CMSIS_NVIC_VIRTUAL_HEADER_FILE + #define CMSIS_NVIC_VIRTUAL_HEADER_FILE "cmsis_nvic_virtual.h" + #endif + #include CMSIS_NVIC_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetPriorityGrouping __NVIC_SetPriorityGrouping + #define NVIC_GetPriorityGrouping __NVIC_GetPriorityGrouping + #define NVIC_EnableIRQ __NVIC_EnableIRQ + #define NVIC_GetEnableIRQ __NVIC_GetEnableIRQ + #define NVIC_DisableIRQ __NVIC_DisableIRQ + #define NVIC_GetPendingIRQ __NVIC_GetPendingIRQ + #define NVIC_SetPendingIRQ __NVIC_SetPendingIRQ + #define NVIC_ClearPendingIRQ __NVIC_ClearPendingIRQ + #define NVIC_GetActive __NVIC_GetActive + #define NVIC_SetPriority __NVIC_SetPriority + #define NVIC_GetPriority __NVIC_GetPriority + #define NVIC_SystemReset __NVIC_SystemReset +#endif /* CMSIS_NVIC_VIRTUAL */ + +#ifdef CMSIS_VECTAB_VIRTUAL + #ifndef CMSIS_VECTAB_VIRTUAL_HEADER_FILE + #define CMSIS_VECTAB_VIRTUAL_HEADER_FILE "cmsis_vectab_virtual.h" + #endif + #include CMSIS_VECTAB_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetVector __NVIC_SetVector + #define NVIC_GetVector __NVIC_GetVector +#endif /* (CMSIS_VECTAB_VIRTUAL) */ + +#define NVIC_USER_IRQ_OFFSET 16 + + +/* Special LR values for Secure/Non-Secure call handling and exception handling */ + +/* Function Return Payload (from ARMv8-M Architecture Reference Manual) LR value on entry from Secure BLXNS */ +#define FNC_RETURN (0xFEFFFFFFUL) /* bit [0] ignored when processing a branch */ + +/* The following EXC_RETURN mask values are used to evaluate the LR on exception entry */ +#define EXC_RETURN_PREFIX (0xFF000000UL) /* bits [31:24] set to indicate an EXC_RETURN value */ +#define EXC_RETURN_S (0x00000040UL) /* bit [6] stack used to push registers: 0=Non-secure 1=Secure */ +#define EXC_RETURN_DCRS (0x00000020UL) /* bit [5] stacking rules for called registers: 0=skipped 1=saved */ +#define EXC_RETURN_FTYPE (0x00000010UL) /* bit [4] allocate stack for floating-point context: 0=done 1=skipped */ +#define EXC_RETURN_MODE (0x00000008UL) /* bit [3] processor mode for return: 0=Handler mode 1=Thread mode */ +#define EXC_RETURN_SPSEL (0x00000004UL) /* bit [2] stack pointer used to restore context: 0=MSP 1=PSP */ +#define EXC_RETURN_ES (0x00000001UL) /* bit [0] security state exception was taken to: 0=Non-secure 1=Secure */ + +/* Integrity Signature (from ARMv8-M Architecture Reference Manual) for exception context stacking */ +#if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) /* Value for processors with floating-point extension: */ +#define EXC_INTEGRITY_SIGNATURE (0xFEFA125AUL) /* bit [0] SFTC must match LR bit[4] EXC_RETURN_FTYPE */ +#else +#define EXC_INTEGRITY_SIGNATURE (0xFEFA125BUL) /* Value for processors without floating-point extension */ +#endif + + +/* Interrupt Priorities are WORD accessible only under Armv6-M */ +/* The following MACROS handle generation of the register offset and byte masks */ +#define _BIT_SHIFT(IRQn) ( ((((uint32_t)(int32_t)(IRQn)) ) & 0x03UL) * 8UL) +#define _SHP_IDX(IRQn) ( (((((uint32_t)(int32_t)(IRQn)) & 0x0FUL)-8UL) >> 2UL) ) +#define _IP_IDX(IRQn) ( (((uint32_t)(int32_t)(IRQn)) >> 2UL) ) + +#define __NVIC_SetPriorityGrouping(X) (void)(X) +#define __NVIC_GetPriorityGrouping() (0U) + +/** + \brief Enable Interrupt + \details Enables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Interrupt Enable status + \details Returns a device specific interrupt enable status from the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt is not enabled. + \return 1 Interrupt is enabled. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t __NVIC_GetEnableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Disable Interrupt + \details Disables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_DisableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + __DSB(); + __ISB(); + } +} + + +/** + \brief Get Pending Interrupt + \details Reads the NVIC pending register and returns the pending bit for the specified device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt status is not pending. + \return 1 Interrupt status is pending. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t __NVIC_GetPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Set Pending Interrupt + \details Sets the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_SetPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Clear Pending Interrupt + \details Clears the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_ClearPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Active Interrupt + \details Reads the active register in the NVIC and returns the active bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt status is not active. + \return 1 Interrupt status is active. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t __NVIC_GetActive(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->IABR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +/** + \brief Get Interrupt Target State + \details Reads the interrupt target field in the NVIC and returns the interrupt target bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 if interrupt is assigned to Secure + \return 1 if interrupt is assigned to Non Secure + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t NVIC_GetTargetState(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Set Interrupt Target State + \details Sets the interrupt target field in the NVIC and returns the interrupt target bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 if interrupt is assigned to Secure + 1 if interrupt is assigned to Non Secure + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t NVIC_SetTargetState(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] |= ((uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL))); + return((uint32_t)(((NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Clear Interrupt Target State + \details Clears the interrupt target field in the NVIC and returns the interrupt target bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 if interrupt is assigned to Secure + 1 if interrupt is assigned to Non Secure + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t NVIC_ClearTargetState(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] &= ~((uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL))); + return((uint32_t)(((NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ + + +/** + \brief Set Interrupt Priority + \details Sets the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \param [in] priority Priority to set. + \note The priority cannot be set for every processor exception. + */ +__STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->IPR[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IPR[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); + } + else + { + SCB->SHPR[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHPR[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); + } +} + + +/** + \brief Get Interrupt Priority + \details Reads the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Interrupt Priority. + Value is aligned automatically to the implemented priority bits of the microcontroller. + */ +__STATIC_INLINE uint32_t __NVIC_GetPriority(IRQn_Type IRQn) +{ + + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->IPR[ _IP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); + } + else + { + return((uint32_t)(((SCB->SHPR[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); + } +} + + +/** + \brief Encode Priority + \details Encodes the priority for an interrupt with the given priority group, + preemptive priority value, and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. + \param [in] PriorityGroup Used priority group. + \param [in] PreemptPriority Preemptive priority value (starting from 0). + \param [in] SubPriority Subpriority value (starting from 0). + \return Encoded priority. Value can be used in the function \ref NVIC_SetPriority(). + */ +__STATIC_INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + return ( + ((PreemptPriority & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL)) << SubPriorityBits) | + ((SubPriority & (uint32_t)((1UL << (SubPriorityBits )) - 1UL))) + ); +} + + +/** + \brief Decode Priority + \details Decodes an interrupt priority value with a given priority group to + preemptive priority value and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS) the smallest possible priority group is set. + \param [in] Priority Priority value, which can be retrieved with the function \ref NVIC_GetPriority(). + \param [in] PriorityGroup Used priority group. + \param [out] pPreemptPriority Preemptive priority value (starting from 0). + \param [out] pSubPriority Subpriority value (starting from 0). + */ +__STATIC_INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGroup, uint32_t* const pPreemptPriority, uint32_t* const pSubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + *pPreemptPriority = (Priority >> SubPriorityBits) & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL); + *pSubPriority = (Priority ) & (uint32_t)((1UL << (SubPriorityBits )) - 1UL); +} + + +/** + \brief Set Interrupt Vector + \details Sets an interrupt vector in SRAM based interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + VTOR must been relocated to SRAM before. + If VTOR is not present address 0 must be mapped to SRAM. + \param [in] IRQn Interrupt number + \param [in] vector Address of interrupt handler function + */ +__STATIC_INLINE void __NVIC_SetVector(IRQn_Type IRQn, uint32_t vector) +{ +#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U) + uint32_t *vectors = (uint32_t *)SCB->VTOR; +#else + uint32_t *vectors = (uint32_t *)0x0U; +#endif + vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET] = vector; +} + + +/** + \brief Get Interrupt Vector + \details Reads an interrupt vector from interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Address of interrupt handler function + */ +__STATIC_INLINE uint32_t __NVIC_GetVector(IRQn_Type IRQn) +{ +#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U) + uint32_t *vectors = (uint32_t *)SCB->VTOR; +#else + uint32_t *vectors = (uint32_t *)0x0U; +#endif + return vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET]; +} + + +/** + \brief System Reset + \details Initiates a system reset request to reset the MCU. + */ +__NO_RETURN __STATIC_INLINE void __NVIC_SystemReset(void) +{ + __DSB(); /* Ensure all outstanding memory accesses included + buffered write are completed before reset */ + SCB->AIRCR = ((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + SCB_AIRCR_SYSRESETREQ_Msk); + __DSB(); /* Ensure completion of memory access */ + + for(;;) /* wait until reset */ + { + __NOP(); + } +} + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +/** + \brief Enable Interrupt (non-secure) + \details Enables a device specific interrupt in the non-secure NVIC interrupt controller when in secure state. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void TZ_NVIC_EnableIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Interrupt Enable status (non-secure) + \details Returns a device specific interrupt enable status from the non-secure NVIC interrupt controller when in secure state. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt is not enabled. + \return 1 Interrupt is enabled. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t TZ_NVIC_GetEnableIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC_NS->ISER[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Disable Interrupt (non-secure) + \details Disables a device specific interrupt in the non-secure NVIC interrupt controller when in secure state. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void TZ_NVIC_DisableIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->ICER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Pending Interrupt (non-secure) + \details Reads the NVIC pending register in the non-secure NVIC when in secure state and returns the pending bit for the specified device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt status is not pending. + \return 1 Interrupt status is pending. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t TZ_NVIC_GetPendingIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC_NS->ISPR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Set Pending Interrupt (non-secure) + \details Sets the pending bit of a device specific interrupt in the non-secure NVIC pending register when in secure state. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void TZ_NVIC_SetPendingIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->ISPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Clear Pending Interrupt (non-secure) + \details Clears the pending bit of a device specific interrupt in the non-secure NVIC pending register when in secure state. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void TZ_NVIC_ClearPendingIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->ICPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Active Interrupt (non-secure) + \details Reads the active register in non-secure NVIC when in secure state and returns the active bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt status is not active. + \return 1 Interrupt status is active. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t TZ_NVIC_GetActive_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC_NS->IABR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Set Interrupt Priority (non-secure) + \details Sets the priority of a non-secure device specific interrupt or a non-secure processor exception when in secure state. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \param [in] priority Priority to set. + \note The priority cannot be set for every non-secure processor exception. + */ +__STATIC_INLINE void TZ_NVIC_SetPriority_NS(IRQn_Type IRQn, uint32_t priority) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->IPR[_IP_IDX(IRQn)] = ((uint32_t)(NVIC_NS->IPR[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); + } + else + { + SCB_NS->SHPR[_SHP_IDX(IRQn)] = ((uint32_t)(SCB_NS->SHPR[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); + } +} + + +/** + \brief Get Interrupt Priority (non-secure) + \details Reads the priority of a non-secure device specific interrupt or a non-secure processor exception when in secure state. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Interrupt Priority. Value is aligned automatically to the implemented priority bits of the microcontroller. + */ +__STATIC_INLINE uint32_t TZ_NVIC_GetPriority_NS(IRQn_Type IRQn) +{ + + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC_NS->IPR[ _IP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); + } + else + { + return((uint32_t)(((SCB_NS->SHPR[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); + } +} +#endif /* defined (__ARM_FEATURE_CMSE) &&(__ARM_FEATURE_CMSE == 3U) */ + +/*@} end of CMSIS_Core_NVICFunctions */ + +/* ########################## MPU functions #################################### */ + +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + +#include "mpu_armv8.h" + +#endif + +/* ########################## FPU functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_FpuFunctions FPU Functions + \brief Function that provides FPU type. + @{ + */ + +/** + \brief get FPU type + \details returns the FPU type + \returns + - \b 0: No FPU + - \b 1: Single precision FPU + - \b 2: Double + Single precision FPU + */ +__STATIC_INLINE uint32_t SCB_GetFPUType(void) +{ + return 0U; /* No FPU */ +} + + +/*@} end of CMSIS_Core_FpuFunctions */ + + + +/* ########################## SAU functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_SAUFunctions SAU Functions + \brief Functions that configure the SAU. + @{ + */ + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + +/** + \brief Enable SAU + \details Enables the Security Attribution Unit (SAU). + */ +__STATIC_INLINE void TZ_SAU_Enable(void) +{ + SAU->CTRL |= (SAU_CTRL_ENABLE_Msk); +} + + + +/** + \brief Disable SAU + \details Disables the Security Attribution Unit (SAU). + */ +__STATIC_INLINE void TZ_SAU_Disable(void) +{ + SAU->CTRL &= ~(SAU_CTRL_ENABLE_Msk); +} + +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ + +/*@} end of CMSIS_Core_SAUFunctions */ + + + + +/* ################################## SysTick function ############################################ */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_SysTickFunctions SysTick Functions + \brief Functions that configure the System. + @{ + */ + +#if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U) + +/** + \brief System Tick Configuration + \details Initializes the System Timer and its interrupt, and starts the System Tick Timer. + Counter is in free running mode to generate periodic interrupts. + \param [in] ticks Number of ticks between two interrupts. + \return 0 Function succeeded. + \return 1 Function failed. + \note When the variable __Vendor_SysTickConfig is set to 1, then the + function SysTick_Config is not included. In this case, the file device.h + must contain a vendor-specific implementation of this function. + */ +__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) +{ + if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) + { + return (1UL); /* Reload value impossible */ + } + + SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ + NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ + SysTick->VAL = 0UL; /* Load the SysTick Counter Value */ + SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + SysTick_CTRL_TICKINT_Msk | + SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ + return (0UL); /* Function successful */ +} + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +/** + \brief System Tick Configuration (non-secure) + \details Initializes the non-secure System Timer and its interrupt when in secure state, and starts the System Tick Timer. + Counter is in free running mode to generate periodic interrupts. + \param [in] ticks Number of ticks between two interrupts. + \return 0 Function succeeded. + \return 1 Function failed. + \note When the variable __Vendor_SysTickConfig is set to 1, then the + function TZ_SysTick_Config_NS is not included. In this case, the file device.h + must contain a vendor-specific implementation of this function. + + */ +__STATIC_INLINE uint32_t TZ_SysTick_Config_NS(uint32_t ticks) +{ + if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) + { + return (1UL); /* Reload value impossible */ + } + + SysTick_NS->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ + TZ_NVIC_SetPriority_NS (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ + SysTick_NS->VAL = 0UL; /* Load the SysTick Counter Value */ + SysTick_NS->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + SysTick_CTRL_TICKINT_Msk | + SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ + return (0UL); /* Function successful */ +} +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ + +#endif + +/*@} end of CMSIS_Core_SysTickFunctions */ + + + + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_ARMV8MBL_H_DEPENDANT */ + +#endif /* __CMSIS_GENERIC */ diff --git a/lib/cmsis/inc/core_armv8mml.h b/lib/cmsis/inc/core_armv8mml.h new file mode 100644 index 0000000000..30aab58722 --- /dev/null +++ b/lib/cmsis/inc/core_armv8mml.h @@ -0,0 +1,2832 @@ +/**************************************************************************//** + * @file core_armv8mml.h + * @brief CMSIS Armv8-M Mainline Core Peripheral Access Layer Header File + * @version V5.1.0 + * @date 12. September 2018 + ******************************************************************************/ +/* + * Copyright (c) 2009-2018 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined (__clang__) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef __CORE_ARMV8MML_H_GENERIC +#define __CORE_ARMV8MML_H_GENERIC + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/** + \page CMSIS_MISRA_Exceptions MISRA-C:2004 Compliance Exceptions + CMSIS violates the following MISRA-C:2004 rules: + + \li Required Rule 8.5, object/function definition in header file.
+ Function definitions in header files are used to allow 'inlining'. + + \li Required Rule 18.4, declaration of union type or object of union type: '{...}'.
+ Unions are used for effective representation of core registers. + + \li Advisory Rule 19.7, Function-like macro defined.
+ Function-like macros are used to allow more efficient code. + */ + + +/******************************************************************************* + * CMSIS definitions + ******************************************************************************/ +/** + \ingroup Cortex_ARMv8MML + @{ + */ + +#include "cmsis_version.h" + +/* CMSIS Armv8MML definitions */ +#define __ARMv8MML_CMSIS_VERSION_MAIN (__CM_CMSIS_VERSION_MAIN) /*!< \deprecated [31:16] CMSIS HAL main version */ +#define __ARMv8MML_CMSIS_VERSION_SUB (__CM_CMSIS_VERSION_SUB) /*!< \deprecated [15:0] CMSIS HAL sub version */ +#define __ARMv8MML_CMSIS_VERSION ((__ARMv8MML_CMSIS_VERSION_MAIN << 16U) | \ + __ARMv8MML_CMSIS_VERSION_SUB ) /*!< \deprecated CMSIS HAL version number */ + +#define __CORTEX_M (81U) /*!< Cortex-M Core */ + +/** __FPU_USED indicates whether an FPU is used or not. + For this, __FPU_PRESENT has to be checked prior to making use of FPU specific registers and functions. +*/ +#if defined ( __CC_ARM ) + #if defined __TARGET_FPU_VFP + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + + #if defined(__ARM_FEATURE_DSP) + #if defined(__DSP_PRESENT) && (__DSP_PRESENT == 1U) + #define __DSP_USED 1U + #else + #error "Compiler generates DSP (SIMD) instructions for a devices without DSP extensions (check __DSP_PRESENT)" + #define __DSP_USED 0U + #endif + #else + #define __DSP_USED 0U + #endif + +#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #if defined __ARM_FP + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #warning "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + + #if defined(__ARM_FEATURE_DSP) + #if defined(__DSP_PRESENT) && (__DSP_PRESENT == 1U) + #define __DSP_USED 1U + #else + #error "Compiler generates DSP (SIMD) instructions for a devices without DSP extensions (check __DSP_PRESENT)" + #define __DSP_USED 0U + #endif + #else + #define __DSP_USED 0U + #endif + +#elif defined ( __GNUC__ ) + #if defined (__VFP_FP__) && !defined(__SOFTFP__) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + + #if defined(__ARM_FEATURE_DSP) + #if defined(__DSP_PRESENT) && (__DSP_PRESENT == 1U) + #define __DSP_USED 1U + #else + #error "Compiler generates DSP (SIMD) instructions for a devices without DSP extensions (check __DSP_PRESENT)" + #define __DSP_USED 0U + #endif + #else + #define __DSP_USED 0U + #endif + +#elif defined ( __ICCARM__ ) + #if defined __ARMVFP__ + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + + #if defined(__ARM_FEATURE_DSP) + #if defined(__DSP_PRESENT) && (__DSP_PRESENT == 1U) + #define __DSP_USED 1U + #else + #error "Compiler generates DSP (SIMD) instructions for a devices without DSP extensions (check __DSP_PRESENT)" + #define __DSP_USED 0U + #endif + #else + #define __DSP_USED 0U + #endif + +#elif defined ( __TI_ARM__ ) + #if defined __TI_VFP_SUPPORT__ + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#elif defined ( __TASKING__ ) + #if defined __FPU_VFP__ + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#elif defined ( __CSMC__ ) + #if ( __CSMC__ & 0x400U) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#endif + +#include "cmsis_compiler.h" /* CMSIS compiler specific defines */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_ARMV8MML_H_GENERIC */ + +#ifndef __CMSIS_GENERIC + +#ifndef __CORE_ARMV8MML_H_DEPENDANT +#define __CORE_ARMV8MML_H_DEPENDANT + +#ifdef __cplusplus + extern "C" { +#endif + +/* check device defines and use defaults */ +#if defined __CHECK_DEVICE_DEFINES + #ifndef __ARMv8MML_REV + #define __ARMv8MML_REV 0x0000U + #warning "__ARMv8MML_REV not defined in device header file; using default!" + #endif + + #ifndef __FPU_PRESENT + #define __FPU_PRESENT 0U + #warning "__FPU_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __MPU_PRESENT + #define __MPU_PRESENT 0U + #warning "__MPU_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __SAUREGION_PRESENT + #define __SAUREGION_PRESENT 0U + #warning "__SAUREGION_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __DSP_PRESENT + #define __DSP_PRESENT 0U + #warning "__DSP_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __NVIC_PRIO_BITS + #define __NVIC_PRIO_BITS 3U + #warning "__NVIC_PRIO_BITS not defined in device header file; using default!" + #endif + + #ifndef __Vendor_SysTickConfig + #define __Vendor_SysTickConfig 0U + #warning "__Vendor_SysTickConfig not defined in device header file; using default!" + #endif +#endif + +/* IO definitions (access restrictions to peripheral registers) */ +/** + \defgroup CMSIS_glob_defs CMSIS Global Defines + + IO Type Qualifiers are used + \li to specify the access to peripheral variables. + \li for automatic generation of peripheral register debug information. +*/ +#ifdef __cplusplus + #define __I volatile /*!< Defines 'read only' permissions */ +#else + #define __I volatile const /*!< Defines 'read only' permissions */ +#endif +#define __O volatile /*!< Defines 'write only' permissions */ +#define __IO volatile /*!< Defines 'read / write' permissions */ + +/* following defines should be used for structure members */ +#define __IM volatile const /*! Defines 'read only' structure member permissions */ +#define __OM volatile /*! Defines 'write only' structure member permissions */ +#define __IOM volatile /*! Defines 'read / write' structure member permissions */ + +/*@} end of group ARMv8MML */ + + + +/******************************************************************************* + * Register Abstraction + Core Register contain: + - Core Register + - Core NVIC Register + - Core SCB Register + - Core SysTick Register + - Core Debug Register + - Core MPU Register + - Core SAU Register + - Core FPU Register + ******************************************************************************/ +/** + \defgroup CMSIS_core_register Defines and Type Definitions + \brief Type definitions and defines for Cortex-M processor based devices. +*/ + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CORE Status and Control Registers + \brief Core Register type definitions. + @{ + */ + +/** + \brief Union type to access the Application Program Status Register (APSR). + */ +typedef union +{ + struct + { + uint32_t _reserved0:16; /*!< bit: 0..15 Reserved */ + uint32_t GE:4; /*!< bit: 16..19 Greater than or Equal flags */ + uint32_t _reserved1:7; /*!< bit: 20..26 Reserved */ + uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} APSR_Type; + +/* APSR Register Definitions */ +#define APSR_N_Pos 31U /*!< APSR: N Position */ +#define APSR_N_Msk (1UL << APSR_N_Pos) /*!< APSR: N Mask */ + +#define APSR_Z_Pos 30U /*!< APSR: Z Position */ +#define APSR_Z_Msk (1UL << APSR_Z_Pos) /*!< APSR: Z Mask */ + +#define APSR_C_Pos 29U /*!< APSR: C Position */ +#define APSR_C_Msk (1UL << APSR_C_Pos) /*!< APSR: C Mask */ + +#define APSR_V_Pos 28U /*!< APSR: V Position */ +#define APSR_V_Msk (1UL << APSR_V_Pos) /*!< APSR: V Mask */ + +#define APSR_Q_Pos 27U /*!< APSR: Q Position */ +#define APSR_Q_Msk (1UL << APSR_Q_Pos) /*!< APSR: Q Mask */ + +#define APSR_GE_Pos 16U /*!< APSR: GE Position */ +#define APSR_GE_Msk (0xFUL << APSR_GE_Pos) /*!< APSR: GE Mask */ + + +/** + \brief Union type to access the Interrupt Program Status Register (IPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:23; /*!< bit: 9..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} IPSR_Type; + +/* IPSR Register Definitions */ +#define IPSR_ISR_Pos 0U /*!< IPSR: ISR Position */ +#define IPSR_ISR_Msk (0x1FFUL /*<< IPSR_ISR_Pos*/) /*!< IPSR: ISR Mask */ + + +/** + \brief Union type to access the Special-Purpose Program Status Registers (xPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:7; /*!< bit: 9..15 Reserved */ + uint32_t GE:4; /*!< bit: 16..19 Greater than or Equal flags */ + uint32_t _reserved1:4; /*!< bit: 20..23 Reserved */ + uint32_t T:1; /*!< bit: 24 Thumb bit (read 0) */ + uint32_t IT:2; /*!< bit: 25..26 saved IT state (read 0) */ + uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} xPSR_Type; + +/* xPSR Register Definitions */ +#define xPSR_N_Pos 31U /*!< xPSR: N Position */ +#define xPSR_N_Msk (1UL << xPSR_N_Pos) /*!< xPSR: N Mask */ + +#define xPSR_Z_Pos 30U /*!< xPSR: Z Position */ +#define xPSR_Z_Msk (1UL << xPSR_Z_Pos) /*!< xPSR: Z Mask */ + +#define xPSR_C_Pos 29U /*!< xPSR: C Position */ +#define xPSR_C_Msk (1UL << xPSR_C_Pos) /*!< xPSR: C Mask */ + +#define xPSR_V_Pos 28U /*!< xPSR: V Position */ +#define xPSR_V_Msk (1UL << xPSR_V_Pos) /*!< xPSR: V Mask */ + +#define xPSR_Q_Pos 27U /*!< xPSR: Q Position */ +#define xPSR_Q_Msk (1UL << xPSR_Q_Pos) /*!< xPSR: Q Mask */ + +#define xPSR_IT_Pos 25U /*!< xPSR: IT Position */ +#define xPSR_IT_Msk (3UL << xPSR_IT_Pos) /*!< xPSR: IT Mask */ + +#define xPSR_T_Pos 24U /*!< xPSR: T Position */ +#define xPSR_T_Msk (1UL << xPSR_T_Pos) /*!< xPSR: T Mask */ + +#define xPSR_GE_Pos 16U /*!< xPSR: GE Position */ +#define xPSR_GE_Msk (0xFUL << xPSR_GE_Pos) /*!< xPSR: GE Mask */ + +#define xPSR_ISR_Pos 0U /*!< xPSR: ISR Position */ +#define xPSR_ISR_Msk (0x1FFUL /*<< xPSR_ISR_Pos*/) /*!< xPSR: ISR Mask */ + + +/** + \brief Union type to access the Control Registers (CONTROL). + */ +typedef union +{ + struct + { + uint32_t nPRIV:1; /*!< bit: 0 Execution privilege in Thread mode */ + uint32_t SPSEL:1; /*!< bit: 1 Stack-pointer select */ + uint32_t FPCA:1; /*!< bit: 2 Floating-point context active */ + uint32_t SFPA:1; /*!< bit: 3 Secure floating-point active */ + uint32_t _reserved1:28; /*!< bit: 4..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} CONTROL_Type; + +/* CONTROL Register Definitions */ +#define CONTROL_SFPA_Pos 3U /*!< CONTROL: SFPA Position */ +#define CONTROL_SFPA_Msk (1UL << CONTROL_SFPA_Pos) /*!< CONTROL: SFPA Mask */ + +#define CONTROL_FPCA_Pos 2U /*!< CONTROL: FPCA Position */ +#define CONTROL_FPCA_Msk (1UL << CONTROL_FPCA_Pos) /*!< CONTROL: FPCA Mask */ + +#define CONTROL_SPSEL_Pos 1U /*!< CONTROL: SPSEL Position */ +#define CONTROL_SPSEL_Msk (1UL << CONTROL_SPSEL_Pos) /*!< CONTROL: SPSEL Mask */ + +#define CONTROL_nPRIV_Pos 0U /*!< CONTROL: nPRIV Position */ +#define CONTROL_nPRIV_Msk (1UL /*<< CONTROL_nPRIV_Pos*/) /*!< CONTROL: nPRIV Mask */ + +/*@} end of group CMSIS_CORE */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_NVIC Nested Vectored Interrupt Controller (NVIC) + \brief Type definitions for the NVIC Registers + @{ + */ + +/** + \brief Structure type to access the Nested Vectored Interrupt Controller (NVIC). + */ +typedef struct +{ + __IOM uint32_t ISER[16U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ + uint32_t RESERVED0[16U]; + __IOM uint32_t ICER[16U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ + uint32_t RSERVED1[16U]; + __IOM uint32_t ISPR[16U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ + uint32_t RESERVED2[16U]; + __IOM uint32_t ICPR[16U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ + uint32_t RESERVED3[16U]; + __IOM uint32_t IABR[16U]; /*!< Offset: 0x200 (R/W) Interrupt Active bit Register */ + uint32_t RESERVED4[16U]; + __IOM uint32_t ITNS[16U]; /*!< Offset: 0x280 (R/W) Interrupt Non-Secure State Register */ + uint32_t RESERVED5[16U]; + __IOM uint8_t IPR[496U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register (8Bit wide) */ + uint32_t RESERVED6[580U]; + __OM uint32_t STIR; /*!< Offset: 0xE00 ( /W) Software Trigger Interrupt Register */ +} NVIC_Type; + +/* Software Triggered Interrupt Register Definitions */ +#define NVIC_STIR_INTID_Pos 0U /*!< STIR: INTLINESNUM Position */ +#define NVIC_STIR_INTID_Msk (0x1FFUL /*<< NVIC_STIR_INTID_Pos*/) /*!< STIR: INTLINESNUM Mask */ + +/*@} end of group CMSIS_NVIC */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SCB System Control Block (SCB) + \brief Type definitions for the System Control Block Registers + @{ + */ + +/** + \brief Structure type to access the System Control Block (SCB). + */ +typedef struct +{ + __IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */ + __IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */ + __IOM uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */ + __IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */ + __IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */ + __IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */ + __IOM uint8_t SHPR[12U]; /*!< Offset: 0x018 (R/W) System Handlers Priority Registers (4-7, 8-11, 12-15) */ + __IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */ + __IOM uint32_t CFSR; /*!< Offset: 0x028 (R/W) Configurable Fault Status Register */ + __IOM uint32_t HFSR; /*!< Offset: 0x02C (R/W) HardFault Status Register */ + __IOM uint32_t DFSR; /*!< Offset: 0x030 (R/W) Debug Fault Status Register */ + __IOM uint32_t MMFAR; /*!< Offset: 0x034 (R/W) MemManage Fault Address Register */ + __IOM uint32_t BFAR; /*!< Offset: 0x038 (R/W) BusFault Address Register */ + __IOM uint32_t AFSR; /*!< Offset: 0x03C (R/W) Auxiliary Fault Status Register */ + __IM uint32_t ID_PFR[2U]; /*!< Offset: 0x040 (R/ ) Processor Feature Register */ + __IM uint32_t ID_DFR; /*!< Offset: 0x048 (R/ ) Debug Feature Register */ + __IM uint32_t ID_ADR; /*!< Offset: 0x04C (R/ ) Auxiliary Feature Register */ + __IM uint32_t ID_MMFR[4U]; /*!< Offset: 0x050 (R/ ) Memory Model Feature Register */ + __IM uint32_t ID_ISAR[6U]; /*!< Offset: 0x060 (R/ ) Instruction Set Attributes Register */ + __IM uint32_t CLIDR; /*!< Offset: 0x078 (R/ ) Cache Level ID register */ + __IM uint32_t CTR; /*!< Offset: 0x07C (R/ ) Cache Type register */ + __IM uint32_t CCSIDR; /*!< Offset: 0x080 (R/ ) Cache Size ID Register */ + __IOM uint32_t CSSELR; /*!< Offset: 0x084 (R/W) Cache Size Selection Register */ + __IOM uint32_t CPACR; /*!< Offset: 0x088 (R/W) Coprocessor Access Control Register */ + __IOM uint32_t NSACR; /*!< Offset: 0x08C (R/W) Non-Secure Access Control Register */ + uint32_t RESERVED3[92U]; + __OM uint32_t STIR; /*!< Offset: 0x200 ( /W) Software Triggered Interrupt Register */ + uint32_t RESERVED4[15U]; + __IM uint32_t MVFR0; /*!< Offset: 0x240 (R/ ) Media and VFP Feature Register 0 */ + __IM uint32_t MVFR1; /*!< Offset: 0x244 (R/ ) Media and VFP Feature Register 1 */ + __IM uint32_t MVFR2; /*!< Offset: 0x248 (R/ ) Media and VFP Feature Register 2 */ + uint32_t RESERVED5[1U]; + __OM uint32_t ICIALLU; /*!< Offset: 0x250 ( /W) I-Cache Invalidate All to PoU */ + uint32_t RESERVED6[1U]; + __OM uint32_t ICIMVAU; /*!< Offset: 0x258 ( /W) I-Cache Invalidate by MVA to PoU */ + __OM uint32_t DCIMVAC; /*!< Offset: 0x25C ( /W) D-Cache Invalidate by MVA to PoC */ + __OM uint32_t DCISW; /*!< Offset: 0x260 ( /W) D-Cache Invalidate by Set-way */ + __OM uint32_t DCCMVAU; /*!< Offset: 0x264 ( /W) D-Cache Clean by MVA to PoU */ + __OM uint32_t DCCMVAC; /*!< Offset: 0x268 ( /W) D-Cache Clean by MVA to PoC */ + __OM uint32_t DCCSW; /*!< Offset: 0x26C ( /W) D-Cache Clean by Set-way */ + __OM uint32_t DCCIMVAC; /*!< Offset: 0x270 ( /W) D-Cache Clean and Invalidate by MVA to PoC */ + __OM uint32_t DCCISW; /*!< Offset: 0x274 ( /W) D-Cache Clean and Invalidate by Set-way */ +} SCB_Type; + +/* SCB CPUID Register Definitions */ +#define SCB_CPUID_IMPLEMENTER_Pos 24U /*!< SCB CPUID: IMPLEMENTER Position */ +#define SCB_CPUID_IMPLEMENTER_Msk (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos) /*!< SCB CPUID: IMPLEMENTER Mask */ + +#define SCB_CPUID_VARIANT_Pos 20U /*!< SCB CPUID: VARIANT Position */ +#define SCB_CPUID_VARIANT_Msk (0xFUL << SCB_CPUID_VARIANT_Pos) /*!< SCB CPUID: VARIANT Mask */ + +#define SCB_CPUID_ARCHITECTURE_Pos 16U /*!< SCB CPUID: ARCHITECTURE Position */ +#define SCB_CPUID_ARCHITECTURE_Msk (0xFUL << SCB_CPUID_ARCHITECTURE_Pos) /*!< SCB CPUID: ARCHITECTURE Mask */ + +#define SCB_CPUID_PARTNO_Pos 4U /*!< SCB CPUID: PARTNO Position */ +#define SCB_CPUID_PARTNO_Msk (0xFFFUL << SCB_CPUID_PARTNO_Pos) /*!< SCB CPUID: PARTNO Mask */ + +#define SCB_CPUID_REVISION_Pos 0U /*!< SCB CPUID: REVISION Position */ +#define SCB_CPUID_REVISION_Msk (0xFUL /*<< SCB_CPUID_REVISION_Pos*/) /*!< SCB CPUID: REVISION Mask */ + +/* SCB Interrupt Control State Register Definitions */ +#define SCB_ICSR_PENDNMISET_Pos 31U /*!< SCB ICSR: PENDNMISET Position */ +#define SCB_ICSR_PENDNMISET_Msk (1UL << SCB_ICSR_PENDNMISET_Pos) /*!< SCB ICSR: PENDNMISET Mask */ + +#define SCB_ICSR_NMIPENDSET_Pos SCB_ICSR_PENDNMISET_Pos /*!< SCB ICSR: NMIPENDSET Position, backward compatibility */ +#define SCB_ICSR_NMIPENDSET_Msk SCB_ICSR_PENDNMISET_Msk /*!< SCB ICSR: NMIPENDSET Mask, backward compatibility */ + +#define SCB_ICSR_PENDNMICLR_Pos 30U /*!< SCB ICSR: PENDNMICLR Position */ +#define SCB_ICSR_PENDNMICLR_Msk (1UL << SCB_ICSR_PENDNMICLR_Pos) /*!< SCB ICSR: PENDNMICLR Mask */ + +#define SCB_ICSR_PENDSVSET_Pos 28U /*!< SCB ICSR: PENDSVSET Position */ +#define SCB_ICSR_PENDSVSET_Msk (1UL << SCB_ICSR_PENDSVSET_Pos) /*!< SCB ICSR: PENDSVSET Mask */ + +#define SCB_ICSR_PENDSVCLR_Pos 27U /*!< SCB ICSR: PENDSVCLR Position */ +#define SCB_ICSR_PENDSVCLR_Msk (1UL << SCB_ICSR_PENDSVCLR_Pos) /*!< SCB ICSR: PENDSVCLR Mask */ + +#define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */ +#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */ + +#define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */ +#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */ + +#define SCB_ICSR_STTNS_Pos 24U /*!< SCB ICSR: STTNS Position (Security Extension) */ +#define SCB_ICSR_STTNS_Msk (1UL << SCB_ICSR_STTNS_Pos) /*!< SCB ICSR: STTNS Mask (Security Extension) */ + +#define SCB_ICSR_ISRPREEMPT_Pos 23U /*!< SCB ICSR: ISRPREEMPT Position */ +#define SCB_ICSR_ISRPREEMPT_Msk (1UL << SCB_ICSR_ISRPREEMPT_Pos) /*!< SCB ICSR: ISRPREEMPT Mask */ + +#define SCB_ICSR_ISRPENDING_Pos 22U /*!< SCB ICSR: ISRPENDING Position */ +#define SCB_ICSR_ISRPENDING_Msk (1UL << SCB_ICSR_ISRPENDING_Pos) /*!< SCB ICSR: ISRPENDING Mask */ + +#define SCB_ICSR_VECTPENDING_Pos 12U /*!< SCB ICSR: VECTPENDING Position */ +#define SCB_ICSR_VECTPENDING_Msk (0x1FFUL << SCB_ICSR_VECTPENDING_Pos) /*!< SCB ICSR: VECTPENDING Mask */ + +#define SCB_ICSR_RETTOBASE_Pos 11U /*!< SCB ICSR: RETTOBASE Position */ +#define SCB_ICSR_RETTOBASE_Msk (1UL << SCB_ICSR_RETTOBASE_Pos) /*!< SCB ICSR: RETTOBASE Mask */ + +#define SCB_ICSR_VECTACTIVE_Pos 0U /*!< SCB ICSR: VECTACTIVE Position */ +#define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL /*<< SCB_ICSR_VECTACTIVE_Pos*/) /*!< SCB ICSR: VECTACTIVE Mask */ + +/* SCB Vector Table Offset Register Definitions */ +#define SCB_VTOR_TBLOFF_Pos 7U /*!< SCB VTOR: TBLOFF Position */ +#define SCB_VTOR_TBLOFF_Msk (0x1FFFFFFUL << SCB_VTOR_TBLOFF_Pos) /*!< SCB VTOR: TBLOFF Mask */ + +/* SCB Application Interrupt and Reset Control Register Definitions */ +#define SCB_AIRCR_VECTKEY_Pos 16U /*!< SCB AIRCR: VECTKEY Position */ +#define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */ + +#define SCB_AIRCR_VECTKEYSTAT_Pos 16U /*!< SCB AIRCR: VECTKEYSTAT Position */ +#define SCB_AIRCR_VECTKEYSTAT_Msk (0xFFFFUL << SCB_AIRCR_VECTKEYSTAT_Pos) /*!< SCB AIRCR: VECTKEYSTAT Mask */ + +#define SCB_AIRCR_ENDIANESS_Pos 15U /*!< SCB AIRCR: ENDIANESS Position */ +#define SCB_AIRCR_ENDIANESS_Msk (1UL << SCB_AIRCR_ENDIANESS_Pos) /*!< SCB AIRCR: ENDIANESS Mask */ + +#define SCB_AIRCR_PRIS_Pos 14U /*!< SCB AIRCR: PRIS Position */ +#define SCB_AIRCR_PRIS_Msk (1UL << SCB_AIRCR_PRIS_Pos) /*!< SCB AIRCR: PRIS Mask */ + +#define SCB_AIRCR_BFHFNMINS_Pos 13U /*!< SCB AIRCR: BFHFNMINS Position */ +#define SCB_AIRCR_BFHFNMINS_Msk (1UL << SCB_AIRCR_BFHFNMINS_Pos) /*!< SCB AIRCR: BFHFNMINS Mask */ + +#define SCB_AIRCR_PRIGROUP_Pos 8U /*!< SCB AIRCR: PRIGROUP Position */ +#define SCB_AIRCR_PRIGROUP_Msk (7UL << SCB_AIRCR_PRIGROUP_Pos) /*!< SCB AIRCR: PRIGROUP Mask */ + +#define SCB_AIRCR_SYSRESETREQS_Pos 3U /*!< SCB AIRCR: SYSRESETREQS Position */ +#define SCB_AIRCR_SYSRESETREQS_Msk (1UL << SCB_AIRCR_SYSRESETREQS_Pos) /*!< SCB AIRCR: SYSRESETREQS Mask */ + +#define SCB_AIRCR_SYSRESETREQ_Pos 2U /*!< SCB AIRCR: SYSRESETREQ Position */ +#define SCB_AIRCR_SYSRESETREQ_Msk (1UL << SCB_AIRCR_SYSRESETREQ_Pos) /*!< SCB AIRCR: SYSRESETREQ Mask */ + +#define SCB_AIRCR_VECTCLRACTIVE_Pos 1U /*!< SCB AIRCR: VECTCLRACTIVE Position */ +#define SCB_AIRCR_VECTCLRACTIVE_Msk (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos) /*!< SCB AIRCR: VECTCLRACTIVE Mask */ + +/* SCB System Control Register Definitions */ +#define SCB_SCR_SEVONPEND_Pos 4U /*!< SCB SCR: SEVONPEND Position */ +#define SCB_SCR_SEVONPEND_Msk (1UL << SCB_SCR_SEVONPEND_Pos) /*!< SCB SCR: SEVONPEND Mask */ + +#define SCB_SCR_SLEEPDEEPS_Pos 3U /*!< SCB SCR: SLEEPDEEPS Position */ +#define SCB_SCR_SLEEPDEEPS_Msk (1UL << SCB_SCR_SLEEPDEEPS_Pos) /*!< SCB SCR: SLEEPDEEPS Mask */ + +#define SCB_SCR_SLEEPDEEP_Pos 2U /*!< SCB SCR: SLEEPDEEP Position */ +#define SCB_SCR_SLEEPDEEP_Msk (1UL << SCB_SCR_SLEEPDEEP_Pos) /*!< SCB SCR: SLEEPDEEP Mask */ + +#define SCB_SCR_SLEEPONEXIT_Pos 1U /*!< SCB SCR: SLEEPONEXIT Position */ +#define SCB_SCR_SLEEPONEXIT_Msk (1UL << SCB_SCR_SLEEPONEXIT_Pos) /*!< SCB SCR: SLEEPONEXIT Mask */ + +/* SCB Configuration Control Register Definitions */ +#define SCB_CCR_BP_Pos 18U /*!< SCB CCR: BP Position */ +#define SCB_CCR_BP_Msk (1UL << SCB_CCR_BP_Pos) /*!< SCB CCR: BP Mask */ + +#define SCB_CCR_IC_Pos 17U /*!< SCB CCR: IC Position */ +#define SCB_CCR_IC_Msk (1UL << SCB_CCR_IC_Pos) /*!< SCB CCR: IC Mask */ + +#define SCB_CCR_DC_Pos 16U /*!< SCB CCR: DC Position */ +#define SCB_CCR_DC_Msk (1UL << SCB_CCR_DC_Pos) /*!< SCB CCR: DC Mask */ + +#define SCB_CCR_STKOFHFNMIGN_Pos 10U /*!< SCB CCR: STKOFHFNMIGN Position */ +#define SCB_CCR_STKOFHFNMIGN_Msk (1UL << SCB_CCR_STKOFHFNMIGN_Pos) /*!< SCB CCR: STKOFHFNMIGN Mask */ + +#define SCB_CCR_BFHFNMIGN_Pos 8U /*!< SCB CCR: BFHFNMIGN Position */ +#define SCB_CCR_BFHFNMIGN_Msk (1UL << SCB_CCR_BFHFNMIGN_Pos) /*!< SCB CCR: BFHFNMIGN Mask */ + +#define SCB_CCR_DIV_0_TRP_Pos 4U /*!< SCB CCR: DIV_0_TRP Position */ +#define SCB_CCR_DIV_0_TRP_Msk (1UL << SCB_CCR_DIV_0_TRP_Pos) /*!< SCB CCR: DIV_0_TRP Mask */ + +#define SCB_CCR_UNALIGN_TRP_Pos 3U /*!< SCB CCR: UNALIGN_TRP Position */ +#define SCB_CCR_UNALIGN_TRP_Msk (1UL << SCB_CCR_UNALIGN_TRP_Pos) /*!< SCB CCR: UNALIGN_TRP Mask */ + +#define SCB_CCR_USERSETMPEND_Pos 1U /*!< SCB CCR: USERSETMPEND Position */ +#define SCB_CCR_USERSETMPEND_Msk (1UL << SCB_CCR_USERSETMPEND_Pos) /*!< SCB CCR: USERSETMPEND Mask */ + +/* SCB System Handler Control and State Register Definitions */ +#define SCB_SHCSR_HARDFAULTPENDED_Pos 21U /*!< SCB SHCSR: HARDFAULTPENDED Position */ +#define SCB_SHCSR_HARDFAULTPENDED_Msk (1UL << SCB_SHCSR_HARDFAULTPENDED_Pos) /*!< SCB SHCSR: HARDFAULTPENDED Mask */ + +#define SCB_SHCSR_SECUREFAULTPENDED_Pos 20U /*!< SCB SHCSR: SECUREFAULTPENDED Position */ +#define SCB_SHCSR_SECUREFAULTPENDED_Msk (1UL << SCB_SHCSR_SECUREFAULTPENDED_Pos) /*!< SCB SHCSR: SECUREFAULTPENDED Mask */ + +#define SCB_SHCSR_SECUREFAULTENA_Pos 19U /*!< SCB SHCSR: SECUREFAULTENA Position */ +#define SCB_SHCSR_SECUREFAULTENA_Msk (1UL << SCB_SHCSR_SECUREFAULTENA_Pos) /*!< SCB SHCSR: SECUREFAULTENA Mask */ + +#define SCB_SHCSR_USGFAULTENA_Pos 18U /*!< SCB SHCSR: USGFAULTENA Position */ +#define SCB_SHCSR_USGFAULTENA_Msk (1UL << SCB_SHCSR_USGFAULTENA_Pos) /*!< SCB SHCSR: USGFAULTENA Mask */ + +#define SCB_SHCSR_BUSFAULTENA_Pos 17U /*!< SCB SHCSR: BUSFAULTENA Position */ +#define SCB_SHCSR_BUSFAULTENA_Msk (1UL << SCB_SHCSR_BUSFAULTENA_Pos) /*!< SCB SHCSR: BUSFAULTENA Mask */ + +#define SCB_SHCSR_MEMFAULTENA_Pos 16U /*!< SCB SHCSR: MEMFAULTENA Position */ +#define SCB_SHCSR_MEMFAULTENA_Msk (1UL << SCB_SHCSR_MEMFAULTENA_Pos) /*!< SCB SHCSR: MEMFAULTENA Mask */ + +#define SCB_SHCSR_SVCALLPENDED_Pos 15U /*!< SCB SHCSR: SVCALLPENDED Position */ +#define SCB_SHCSR_SVCALLPENDED_Msk (1UL << SCB_SHCSR_SVCALLPENDED_Pos) /*!< SCB SHCSR: SVCALLPENDED Mask */ + +#define SCB_SHCSR_BUSFAULTPENDED_Pos 14U /*!< SCB SHCSR: BUSFAULTPENDED Position */ +#define SCB_SHCSR_BUSFAULTPENDED_Msk (1UL << SCB_SHCSR_BUSFAULTPENDED_Pos) /*!< SCB SHCSR: BUSFAULTPENDED Mask */ + +#define SCB_SHCSR_MEMFAULTPENDED_Pos 13U /*!< SCB SHCSR: MEMFAULTPENDED Position */ +#define SCB_SHCSR_MEMFAULTPENDED_Msk (1UL << SCB_SHCSR_MEMFAULTPENDED_Pos) /*!< SCB SHCSR: MEMFAULTPENDED Mask */ + +#define SCB_SHCSR_USGFAULTPENDED_Pos 12U /*!< SCB SHCSR: USGFAULTPENDED Position */ +#define SCB_SHCSR_USGFAULTPENDED_Msk (1UL << SCB_SHCSR_USGFAULTPENDED_Pos) /*!< SCB SHCSR: USGFAULTPENDED Mask */ + +#define SCB_SHCSR_SYSTICKACT_Pos 11U /*!< SCB SHCSR: SYSTICKACT Position */ +#define SCB_SHCSR_SYSTICKACT_Msk (1UL << SCB_SHCSR_SYSTICKACT_Pos) /*!< SCB SHCSR: SYSTICKACT Mask */ + +#define SCB_SHCSR_PENDSVACT_Pos 10U /*!< SCB SHCSR: PENDSVACT Position */ +#define SCB_SHCSR_PENDSVACT_Msk (1UL << SCB_SHCSR_PENDSVACT_Pos) /*!< SCB SHCSR: PENDSVACT Mask */ + +#define SCB_SHCSR_MONITORACT_Pos 8U /*!< SCB SHCSR: MONITORACT Position */ +#define SCB_SHCSR_MONITORACT_Msk (1UL << SCB_SHCSR_MONITORACT_Pos) /*!< SCB SHCSR: MONITORACT Mask */ + +#define SCB_SHCSR_SVCALLACT_Pos 7U /*!< SCB SHCSR: SVCALLACT Position */ +#define SCB_SHCSR_SVCALLACT_Msk (1UL << SCB_SHCSR_SVCALLACT_Pos) /*!< SCB SHCSR: SVCALLACT Mask */ + +#define SCB_SHCSR_NMIACT_Pos 5U /*!< SCB SHCSR: NMIACT Position */ +#define SCB_SHCSR_NMIACT_Msk (1UL << SCB_SHCSR_NMIACT_Pos) /*!< SCB SHCSR: NMIACT Mask */ + +#define SCB_SHCSR_SECUREFAULTACT_Pos 4U /*!< SCB SHCSR: SECUREFAULTACT Position */ +#define SCB_SHCSR_SECUREFAULTACT_Msk (1UL << SCB_SHCSR_SECUREFAULTACT_Pos) /*!< SCB SHCSR: SECUREFAULTACT Mask */ + +#define SCB_SHCSR_USGFAULTACT_Pos 3U /*!< SCB SHCSR: USGFAULTACT Position */ +#define SCB_SHCSR_USGFAULTACT_Msk (1UL << SCB_SHCSR_USGFAULTACT_Pos) /*!< SCB SHCSR: USGFAULTACT Mask */ + +#define SCB_SHCSR_HARDFAULTACT_Pos 2U /*!< SCB SHCSR: HARDFAULTACT Position */ +#define SCB_SHCSR_HARDFAULTACT_Msk (1UL << SCB_SHCSR_HARDFAULTACT_Pos) /*!< SCB SHCSR: HARDFAULTACT Mask */ + +#define SCB_SHCSR_BUSFAULTACT_Pos 1U /*!< SCB SHCSR: BUSFAULTACT Position */ +#define SCB_SHCSR_BUSFAULTACT_Msk (1UL << SCB_SHCSR_BUSFAULTACT_Pos) /*!< SCB SHCSR: BUSFAULTACT Mask */ + +#define SCB_SHCSR_MEMFAULTACT_Pos 0U /*!< SCB SHCSR: MEMFAULTACT Position */ +#define SCB_SHCSR_MEMFAULTACT_Msk (1UL /*<< SCB_SHCSR_MEMFAULTACT_Pos*/) /*!< SCB SHCSR: MEMFAULTACT Mask */ + +/* SCB Configurable Fault Status Register Definitions */ +#define SCB_CFSR_USGFAULTSR_Pos 16U /*!< SCB CFSR: Usage Fault Status Register Position */ +#define SCB_CFSR_USGFAULTSR_Msk (0xFFFFUL << SCB_CFSR_USGFAULTSR_Pos) /*!< SCB CFSR: Usage Fault Status Register Mask */ + +#define SCB_CFSR_BUSFAULTSR_Pos 8U /*!< SCB CFSR: Bus Fault Status Register Position */ +#define SCB_CFSR_BUSFAULTSR_Msk (0xFFUL << SCB_CFSR_BUSFAULTSR_Pos) /*!< SCB CFSR: Bus Fault Status Register Mask */ + +#define SCB_CFSR_MEMFAULTSR_Pos 0U /*!< SCB CFSR: Memory Manage Fault Status Register Position */ +#define SCB_CFSR_MEMFAULTSR_Msk (0xFFUL /*<< SCB_CFSR_MEMFAULTSR_Pos*/) /*!< SCB CFSR: Memory Manage Fault Status Register Mask */ + +/* MemManage Fault Status Register (part of SCB Configurable Fault Status Register) */ +#define SCB_CFSR_MMARVALID_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 7U) /*!< SCB CFSR (MMFSR): MMARVALID Position */ +#define SCB_CFSR_MMARVALID_Msk (1UL << SCB_CFSR_MMARVALID_Pos) /*!< SCB CFSR (MMFSR): MMARVALID Mask */ + +#define SCB_CFSR_MLSPERR_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 5U) /*!< SCB CFSR (MMFSR): MLSPERR Position */ +#define SCB_CFSR_MLSPERR_Msk (1UL << SCB_CFSR_MLSPERR_Pos) /*!< SCB CFSR (MMFSR): MLSPERR Mask */ + +#define SCB_CFSR_MSTKERR_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 4U) /*!< SCB CFSR (MMFSR): MSTKERR Position */ +#define SCB_CFSR_MSTKERR_Msk (1UL << SCB_CFSR_MSTKERR_Pos) /*!< SCB CFSR (MMFSR): MSTKERR Mask */ + +#define SCB_CFSR_MUNSTKERR_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 3U) /*!< SCB CFSR (MMFSR): MUNSTKERR Position */ +#define SCB_CFSR_MUNSTKERR_Msk (1UL << SCB_CFSR_MUNSTKERR_Pos) /*!< SCB CFSR (MMFSR): MUNSTKERR Mask */ + +#define SCB_CFSR_DACCVIOL_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 1U) /*!< SCB CFSR (MMFSR): DACCVIOL Position */ +#define SCB_CFSR_DACCVIOL_Msk (1UL << SCB_CFSR_DACCVIOL_Pos) /*!< SCB CFSR (MMFSR): DACCVIOL Mask */ + +#define SCB_CFSR_IACCVIOL_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 0U) /*!< SCB CFSR (MMFSR): IACCVIOL Position */ +#define SCB_CFSR_IACCVIOL_Msk (1UL /*<< SCB_CFSR_IACCVIOL_Pos*/) /*!< SCB CFSR (MMFSR): IACCVIOL Mask */ + +/* BusFault Status Register (part of SCB Configurable Fault Status Register) */ +#define SCB_CFSR_BFARVALID_Pos (SCB_CFSR_BUSFAULTSR_Pos + 7U) /*!< SCB CFSR (BFSR): BFARVALID Position */ +#define SCB_CFSR_BFARVALID_Msk (1UL << SCB_CFSR_BFARVALID_Pos) /*!< SCB CFSR (BFSR): BFARVALID Mask */ + +#define SCB_CFSR_LSPERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 5U) /*!< SCB CFSR (BFSR): LSPERR Position */ +#define SCB_CFSR_LSPERR_Msk (1UL << SCB_CFSR_LSPERR_Pos) /*!< SCB CFSR (BFSR): LSPERR Mask */ + +#define SCB_CFSR_STKERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 4U) /*!< SCB CFSR (BFSR): STKERR Position */ +#define SCB_CFSR_STKERR_Msk (1UL << SCB_CFSR_STKERR_Pos) /*!< SCB CFSR (BFSR): STKERR Mask */ + +#define SCB_CFSR_UNSTKERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 3U) /*!< SCB CFSR (BFSR): UNSTKERR Position */ +#define SCB_CFSR_UNSTKERR_Msk (1UL << SCB_CFSR_UNSTKERR_Pos) /*!< SCB CFSR (BFSR): UNSTKERR Mask */ + +#define SCB_CFSR_IMPRECISERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 2U) /*!< SCB CFSR (BFSR): IMPRECISERR Position */ +#define SCB_CFSR_IMPRECISERR_Msk (1UL << SCB_CFSR_IMPRECISERR_Pos) /*!< SCB CFSR (BFSR): IMPRECISERR Mask */ + +#define SCB_CFSR_PRECISERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 1U) /*!< SCB CFSR (BFSR): PRECISERR Position */ +#define SCB_CFSR_PRECISERR_Msk (1UL << SCB_CFSR_PRECISERR_Pos) /*!< SCB CFSR (BFSR): PRECISERR Mask */ + +#define SCB_CFSR_IBUSERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 0U) /*!< SCB CFSR (BFSR): IBUSERR Position */ +#define SCB_CFSR_IBUSERR_Msk (1UL << SCB_CFSR_IBUSERR_Pos) /*!< SCB CFSR (BFSR): IBUSERR Mask */ + +/* UsageFault Status Register (part of SCB Configurable Fault Status Register) */ +#define SCB_CFSR_DIVBYZERO_Pos (SCB_CFSR_USGFAULTSR_Pos + 9U) /*!< SCB CFSR (UFSR): DIVBYZERO Position */ +#define SCB_CFSR_DIVBYZERO_Msk (1UL << SCB_CFSR_DIVBYZERO_Pos) /*!< SCB CFSR (UFSR): DIVBYZERO Mask */ + +#define SCB_CFSR_UNALIGNED_Pos (SCB_CFSR_USGFAULTSR_Pos + 8U) /*!< SCB CFSR (UFSR): UNALIGNED Position */ +#define SCB_CFSR_UNALIGNED_Msk (1UL << SCB_CFSR_UNALIGNED_Pos) /*!< SCB CFSR (UFSR): UNALIGNED Mask */ + +#define SCB_CFSR_STKOF_Pos (SCB_CFSR_USGFAULTSR_Pos + 4U) /*!< SCB CFSR (UFSR): STKOF Position */ +#define SCB_CFSR_STKOF_Msk (1UL << SCB_CFSR_STKOF_Pos) /*!< SCB CFSR (UFSR): STKOF Mask */ + +#define SCB_CFSR_NOCP_Pos (SCB_CFSR_USGFAULTSR_Pos + 3U) /*!< SCB CFSR (UFSR): NOCP Position */ +#define SCB_CFSR_NOCP_Msk (1UL << SCB_CFSR_NOCP_Pos) /*!< SCB CFSR (UFSR): NOCP Mask */ + +#define SCB_CFSR_INVPC_Pos (SCB_CFSR_USGFAULTSR_Pos + 2U) /*!< SCB CFSR (UFSR): INVPC Position */ +#define SCB_CFSR_INVPC_Msk (1UL << SCB_CFSR_INVPC_Pos) /*!< SCB CFSR (UFSR): INVPC Mask */ + +#define SCB_CFSR_INVSTATE_Pos (SCB_CFSR_USGFAULTSR_Pos + 1U) /*!< SCB CFSR (UFSR): INVSTATE Position */ +#define SCB_CFSR_INVSTATE_Msk (1UL << SCB_CFSR_INVSTATE_Pos) /*!< SCB CFSR (UFSR): INVSTATE Mask */ + +#define SCB_CFSR_UNDEFINSTR_Pos (SCB_CFSR_USGFAULTSR_Pos + 0U) /*!< SCB CFSR (UFSR): UNDEFINSTR Position */ +#define SCB_CFSR_UNDEFINSTR_Msk (1UL << SCB_CFSR_UNDEFINSTR_Pos) /*!< SCB CFSR (UFSR): UNDEFINSTR Mask */ + +/* SCB Hard Fault Status Register Definitions */ +#define SCB_HFSR_DEBUGEVT_Pos 31U /*!< SCB HFSR: DEBUGEVT Position */ +#define SCB_HFSR_DEBUGEVT_Msk (1UL << SCB_HFSR_DEBUGEVT_Pos) /*!< SCB HFSR: DEBUGEVT Mask */ + +#define SCB_HFSR_FORCED_Pos 30U /*!< SCB HFSR: FORCED Position */ +#define SCB_HFSR_FORCED_Msk (1UL << SCB_HFSR_FORCED_Pos) /*!< SCB HFSR: FORCED Mask */ + +#define SCB_HFSR_VECTTBL_Pos 1U /*!< SCB HFSR: VECTTBL Position */ +#define SCB_HFSR_VECTTBL_Msk (1UL << SCB_HFSR_VECTTBL_Pos) /*!< SCB HFSR: VECTTBL Mask */ + +/* SCB Debug Fault Status Register Definitions */ +#define SCB_DFSR_EXTERNAL_Pos 4U /*!< SCB DFSR: EXTERNAL Position */ +#define SCB_DFSR_EXTERNAL_Msk (1UL << SCB_DFSR_EXTERNAL_Pos) /*!< SCB DFSR: EXTERNAL Mask */ + +#define SCB_DFSR_VCATCH_Pos 3U /*!< SCB DFSR: VCATCH Position */ +#define SCB_DFSR_VCATCH_Msk (1UL << SCB_DFSR_VCATCH_Pos) /*!< SCB DFSR: VCATCH Mask */ + +#define SCB_DFSR_DWTTRAP_Pos 2U /*!< SCB DFSR: DWTTRAP Position */ +#define SCB_DFSR_DWTTRAP_Msk (1UL << SCB_DFSR_DWTTRAP_Pos) /*!< SCB DFSR: DWTTRAP Mask */ + +#define SCB_DFSR_BKPT_Pos 1U /*!< SCB DFSR: BKPT Position */ +#define SCB_DFSR_BKPT_Msk (1UL << SCB_DFSR_BKPT_Pos) /*!< SCB DFSR: BKPT Mask */ + +#define SCB_DFSR_HALTED_Pos 0U /*!< SCB DFSR: HALTED Position */ +#define SCB_DFSR_HALTED_Msk (1UL /*<< SCB_DFSR_HALTED_Pos*/) /*!< SCB DFSR: HALTED Mask */ + +/* SCB Non-Secure Access Control Register Definitions */ +#define SCB_NSACR_CP11_Pos 11U /*!< SCB NSACR: CP11 Position */ +#define SCB_NSACR_CP11_Msk (1UL << SCB_NSACR_CP11_Pos) /*!< SCB NSACR: CP11 Mask */ + +#define SCB_NSACR_CP10_Pos 10U /*!< SCB NSACR: CP10 Position */ +#define SCB_NSACR_CP10_Msk (1UL << SCB_NSACR_CP10_Pos) /*!< SCB NSACR: CP10 Mask */ + +#define SCB_NSACR_CPn_Pos 0U /*!< SCB NSACR: CPn Position */ +#define SCB_NSACR_CPn_Msk (1UL /*<< SCB_NSACR_CPn_Pos*/) /*!< SCB NSACR: CPn Mask */ + +/* SCB Cache Level ID Register Definitions */ +#define SCB_CLIDR_LOUU_Pos 27U /*!< SCB CLIDR: LoUU Position */ +#define SCB_CLIDR_LOUU_Msk (7UL << SCB_CLIDR_LOUU_Pos) /*!< SCB CLIDR: LoUU Mask */ + +#define SCB_CLIDR_LOC_Pos 24U /*!< SCB CLIDR: LoC Position */ +#define SCB_CLIDR_LOC_Msk (7UL << SCB_CLIDR_LOC_Pos) /*!< SCB CLIDR: LoC Mask */ + +/* SCB Cache Type Register Definitions */ +#define SCB_CTR_FORMAT_Pos 29U /*!< SCB CTR: Format Position */ +#define SCB_CTR_FORMAT_Msk (7UL << SCB_CTR_FORMAT_Pos) /*!< SCB CTR: Format Mask */ + +#define SCB_CTR_CWG_Pos 24U /*!< SCB CTR: CWG Position */ +#define SCB_CTR_CWG_Msk (0xFUL << SCB_CTR_CWG_Pos) /*!< SCB CTR: CWG Mask */ + +#define SCB_CTR_ERG_Pos 20U /*!< SCB CTR: ERG Position */ +#define SCB_CTR_ERG_Msk (0xFUL << SCB_CTR_ERG_Pos) /*!< SCB CTR: ERG Mask */ + +#define SCB_CTR_DMINLINE_Pos 16U /*!< SCB CTR: DminLine Position */ +#define SCB_CTR_DMINLINE_Msk (0xFUL << SCB_CTR_DMINLINE_Pos) /*!< SCB CTR: DminLine Mask */ + +#define SCB_CTR_IMINLINE_Pos 0U /*!< SCB CTR: ImInLine Position */ +#define SCB_CTR_IMINLINE_Msk (0xFUL /*<< SCB_CTR_IMINLINE_Pos*/) /*!< SCB CTR: ImInLine Mask */ + +/* SCB Cache Size ID Register Definitions */ +#define SCB_CCSIDR_WT_Pos 31U /*!< SCB CCSIDR: WT Position */ +#define SCB_CCSIDR_WT_Msk (1UL << SCB_CCSIDR_WT_Pos) /*!< SCB CCSIDR: WT Mask */ + +#define SCB_CCSIDR_WB_Pos 30U /*!< SCB CCSIDR: WB Position */ +#define SCB_CCSIDR_WB_Msk (1UL << SCB_CCSIDR_WB_Pos) /*!< SCB CCSIDR: WB Mask */ + +#define SCB_CCSIDR_RA_Pos 29U /*!< SCB CCSIDR: RA Position */ +#define SCB_CCSIDR_RA_Msk (1UL << SCB_CCSIDR_RA_Pos) /*!< SCB CCSIDR: RA Mask */ + +#define SCB_CCSIDR_WA_Pos 28U /*!< SCB CCSIDR: WA Position */ +#define SCB_CCSIDR_WA_Msk (1UL << SCB_CCSIDR_WA_Pos) /*!< SCB CCSIDR: WA Mask */ + +#define SCB_CCSIDR_NUMSETS_Pos 13U /*!< SCB CCSIDR: NumSets Position */ +#define SCB_CCSIDR_NUMSETS_Msk (0x7FFFUL << SCB_CCSIDR_NUMSETS_Pos) /*!< SCB CCSIDR: NumSets Mask */ + +#define SCB_CCSIDR_ASSOCIATIVITY_Pos 3U /*!< SCB CCSIDR: Associativity Position */ +#define SCB_CCSIDR_ASSOCIATIVITY_Msk (0x3FFUL << SCB_CCSIDR_ASSOCIATIVITY_Pos) /*!< SCB CCSIDR: Associativity Mask */ + +#define SCB_CCSIDR_LINESIZE_Pos 0U /*!< SCB CCSIDR: LineSize Position */ +#define SCB_CCSIDR_LINESIZE_Msk (7UL /*<< SCB_CCSIDR_LINESIZE_Pos*/) /*!< SCB CCSIDR: LineSize Mask */ + +/* SCB Cache Size Selection Register Definitions */ +#define SCB_CSSELR_LEVEL_Pos 1U /*!< SCB CSSELR: Level Position */ +#define SCB_CSSELR_LEVEL_Msk (7UL << SCB_CSSELR_LEVEL_Pos) /*!< SCB CSSELR: Level Mask */ + +#define SCB_CSSELR_IND_Pos 0U /*!< SCB CSSELR: InD Position */ +#define SCB_CSSELR_IND_Msk (1UL /*<< SCB_CSSELR_IND_Pos*/) /*!< SCB CSSELR: InD Mask */ + +/* SCB Software Triggered Interrupt Register Definitions */ +#define SCB_STIR_INTID_Pos 0U /*!< SCB STIR: INTID Position */ +#define SCB_STIR_INTID_Msk (0x1FFUL /*<< SCB_STIR_INTID_Pos*/) /*!< SCB STIR: INTID Mask */ + +/* SCB D-Cache Invalidate by Set-way Register Definitions */ +#define SCB_DCISW_WAY_Pos 30U /*!< SCB DCISW: Way Position */ +#define SCB_DCISW_WAY_Msk (3UL << SCB_DCISW_WAY_Pos) /*!< SCB DCISW: Way Mask */ + +#define SCB_DCISW_SET_Pos 5U /*!< SCB DCISW: Set Position */ +#define SCB_DCISW_SET_Msk (0x1FFUL << SCB_DCISW_SET_Pos) /*!< SCB DCISW: Set Mask */ + +/* SCB D-Cache Clean by Set-way Register Definitions */ +#define SCB_DCCSW_WAY_Pos 30U /*!< SCB DCCSW: Way Position */ +#define SCB_DCCSW_WAY_Msk (3UL << SCB_DCCSW_WAY_Pos) /*!< SCB DCCSW: Way Mask */ + +#define SCB_DCCSW_SET_Pos 5U /*!< SCB DCCSW: Set Position */ +#define SCB_DCCSW_SET_Msk (0x1FFUL << SCB_DCCSW_SET_Pos) /*!< SCB DCCSW: Set Mask */ + +/* SCB D-Cache Clean and Invalidate by Set-way Register Definitions */ +#define SCB_DCCISW_WAY_Pos 30U /*!< SCB DCCISW: Way Position */ +#define SCB_DCCISW_WAY_Msk (3UL << SCB_DCCISW_WAY_Pos) /*!< SCB DCCISW: Way Mask */ + +#define SCB_DCCISW_SET_Pos 5U /*!< SCB DCCISW: Set Position */ +#define SCB_DCCISW_SET_Msk (0x1FFUL << SCB_DCCISW_SET_Pos) /*!< SCB DCCISW: Set Mask */ + +/*@} end of group CMSIS_SCB */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SCnSCB System Controls not in SCB (SCnSCB) + \brief Type definitions for the System Control and ID Register not in the SCB + @{ + */ + +/** + \brief Structure type to access the System Control and ID Register not in the SCB. + */ +typedef struct +{ + uint32_t RESERVED0[1U]; + __IM uint32_t ICTR; /*!< Offset: 0x004 (R/ ) Interrupt Controller Type Register */ + __IOM uint32_t ACTLR; /*!< Offset: 0x008 (R/W) Auxiliary Control Register */ + __IOM uint32_t CPPWR; /*!< Offset: 0x00C (R/W) Coprocessor Power Control Register */ +} SCnSCB_Type; + +/* Interrupt Controller Type Register Definitions */ +#define SCnSCB_ICTR_INTLINESNUM_Pos 0U /*!< ICTR: INTLINESNUM Position */ +#define SCnSCB_ICTR_INTLINESNUM_Msk (0xFUL /*<< SCnSCB_ICTR_INTLINESNUM_Pos*/) /*!< ICTR: INTLINESNUM Mask */ + +/*@} end of group CMSIS_SCnotSCB */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SysTick System Tick Timer (SysTick) + \brief Type definitions for the System Timer Registers. + @{ + */ + +/** + \brief Structure type to access the System Timer (SysTick). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */ + __IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */ + __IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */ + __IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */ +} SysTick_Type; + +/* SysTick Control / Status Register Definitions */ +#define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */ +#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */ + +#define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */ +#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */ + +#define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */ +#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */ + +#define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */ +#define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */ + +/* SysTick Reload Register Definitions */ +#define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */ +#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */ + +/* SysTick Current Register Definitions */ +#define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */ +#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */ + +/* SysTick Calibration Register Definitions */ +#define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */ +#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */ + +#define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */ +#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */ + +#define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */ +#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */ + +/*@} end of group CMSIS_SysTick */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_ITM Instrumentation Trace Macrocell (ITM) + \brief Type definitions for the Instrumentation Trace Macrocell (ITM) + @{ + */ + +/** + \brief Structure type to access the Instrumentation Trace Macrocell Register (ITM). + */ +typedef struct +{ + __OM union + { + __OM uint8_t u8; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 8-bit */ + __OM uint16_t u16; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 16-bit */ + __OM uint32_t u32; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 32-bit */ + } PORT [32U]; /*!< Offset: 0x000 ( /W) ITM Stimulus Port Registers */ + uint32_t RESERVED0[864U]; + __IOM uint32_t TER; /*!< Offset: 0xE00 (R/W) ITM Trace Enable Register */ + uint32_t RESERVED1[15U]; + __IOM uint32_t TPR; /*!< Offset: 0xE40 (R/W) ITM Trace Privilege Register */ + uint32_t RESERVED2[15U]; + __IOM uint32_t TCR; /*!< Offset: 0xE80 (R/W) ITM Trace Control Register */ + uint32_t RESERVED3[32U]; + uint32_t RESERVED4[43U]; + __OM uint32_t LAR; /*!< Offset: 0xFB0 ( /W) ITM Lock Access Register */ + __IM uint32_t LSR; /*!< Offset: 0xFB4 (R/ ) ITM Lock Status Register */ + uint32_t RESERVED5[1U]; + __IM uint32_t DEVARCH; /*!< Offset: 0xFBC (R/ ) ITM Device Architecture Register */ + uint32_t RESERVED6[4U]; + __IM uint32_t PID4; /*!< Offset: 0xFD0 (R/ ) ITM Peripheral Identification Register #4 */ + __IM uint32_t PID5; /*!< Offset: 0xFD4 (R/ ) ITM Peripheral Identification Register #5 */ + __IM uint32_t PID6; /*!< Offset: 0xFD8 (R/ ) ITM Peripheral Identification Register #6 */ + __IM uint32_t PID7; /*!< Offset: 0xFDC (R/ ) ITM Peripheral Identification Register #7 */ + __IM uint32_t PID0; /*!< Offset: 0xFE0 (R/ ) ITM Peripheral Identification Register #0 */ + __IM uint32_t PID1; /*!< Offset: 0xFE4 (R/ ) ITM Peripheral Identification Register #1 */ + __IM uint32_t PID2; /*!< Offset: 0xFE8 (R/ ) ITM Peripheral Identification Register #2 */ + __IM uint32_t PID3; /*!< Offset: 0xFEC (R/ ) ITM Peripheral Identification Register #3 */ + __IM uint32_t CID0; /*!< Offset: 0xFF0 (R/ ) ITM Component Identification Register #0 */ + __IM uint32_t CID1; /*!< Offset: 0xFF4 (R/ ) ITM Component Identification Register #1 */ + __IM uint32_t CID2; /*!< Offset: 0xFF8 (R/ ) ITM Component Identification Register #2 */ + __IM uint32_t CID3; /*!< Offset: 0xFFC (R/ ) ITM Component Identification Register #3 */ +} ITM_Type; + +/* ITM Stimulus Port Register Definitions */ +#define ITM_STIM_DISABLED_Pos 1U /*!< ITM STIM: DISABLED Position */ +#define ITM_STIM_DISABLED_Msk (0x1UL << ITM_STIM_DISABLED_Pos) /*!< ITM STIM: DISABLED Mask */ + +#define ITM_STIM_FIFOREADY_Pos 0U /*!< ITM STIM: FIFOREADY Position */ +#define ITM_STIM_FIFOREADY_Msk (0x1UL /*<< ITM_STIM_FIFOREADY_Pos*/) /*!< ITM STIM: FIFOREADY Mask */ + +/* ITM Trace Privilege Register Definitions */ +#define ITM_TPR_PRIVMASK_Pos 0U /*!< ITM TPR: PRIVMASK Position */ +#define ITM_TPR_PRIVMASK_Msk (0xFUL /*<< ITM_TPR_PRIVMASK_Pos*/) /*!< ITM TPR: PRIVMASK Mask */ + +/* ITM Trace Control Register Definitions */ +#define ITM_TCR_BUSY_Pos 23U /*!< ITM TCR: BUSY Position */ +#define ITM_TCR_BUSY_Msk (1UL << ITM_TCR_BUSY_Pos) /*!< ITM TCR: BUSY Mask */ + +#define ITM_TCR_TRACEBUSID_Pos 16U /*!< ITM TCR: ATBID Position */ +#define ITM_TCR_TRACEBUSID_Msk (0x7FUL << ITM_TCR_TRACEBUSID_Pos) /*!< ITM TCR: ATBID Mask */ + +#define ITM_TCR_GTSFREQ_Pos 10U /*!< ITM TCR: Global timestamp frequency Position */ +#define ITM_TCR_GTSFREQ_Msk (3UL << ITM_TCR_GTSFREQ_Pos) /*!< ITM TCR: Global timestamp frequency Mask */ + +#define ITM_TCR_TSPRESCALE_Pos 8U /*!< ITM TCR: TSPRESCALE Position */ +#define ITM_TCR_TSPRESCALE_Msk (3UL << ITM_TCR_TSPRESCALE_Pos) /*!< ITM TCR: TSPRESCALE Mask */ + +#define ITM_TCR_STALLENA_Pos 5U /*!< ITM TCR: STALLENA Position */ +#define ITM_TCR_STALLENA_Msk (1UL << ITM_TCR_STALLENA_Pos) /*!< ITM TCR: STALLENA Mask */ + +#define ITM_TCR_SWOENA_Pos 4U /*!< ITM TCR: SWOENA Position */ +#define ITM_TCR_SWOENA_Msk (1UL << ITM_TCR_SWOENA_Pos) /*!< ITM TCR: SWOENA Mask */ + +#define ITM_TCR_DWTENA_Pos 3U /*!< ITM TCR: DWTENA Position */ +#define ITM_TCR_DWTENA_Msk (1UL << ITM_TCR_DWTENA_Pos) /*!< ITM TCR: DWTENA Mask */ + +#define ITM_TCR_SYNCENA_Pos 2U /*!< ITM TCR: SYNCENA Position */ +#define ITM_TCR_SYNCENA_Msk (1UL << ITM_TCR_SYNCENA_Pos) /*!< ITM TCR: SYNCENA Mask */ + +#define ITM_TCR_TSENA_Pos 1U /*!< ITM TCR: TSENA Position */ +#define ITM_TCR_TSENA_Msk (1UL << ITM_TCR_TSENA_Pos) /*!< ITM TCR: TSENA Mask */ + +#define ITM_TCR_ITMENA_Pos 0U /*!< ITM TCR: ITM Enable bit Position */ +#define ITM_TCR_ITMENA_Msk (1UL /*<< ITM_TCR_ITMENA_Pos*/) /*!< ITM TCR: ITM Enable bit Mask */ + +/* ITM Lock Status Register Definitions */ +#define ITM_LSR_ByteAcc_Pos 2U /*!< ITM LSR: ByteAcc Position */ +#define ITM_LSR_ByteAcc_Msk (1UL << ITM_LSR_ByteAcc_Pos) /*!< ITM LSR: ByteAcc Mask */ + +#define ITM_LSR_Access_Pos 1U /*!< ITM LSR: Access Position */ +#define ITM_LSR_Access_Msk (1UL << ITM_LSR_Access_Pos) /*!< ITM LSR: Access Mask */ + +#define ITM_LSR_Present_Pos 0U /*!< ITM LSR: Present Position */ +#define ITM_LSR_Present_Msk (1UL /*<< ITM_LSR_Present_Pos*/) /*!< ITM LSR: Present Mask */ + +/*@}*/ /* end of group CMSIS_ITM */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_DWT Data Watchpoint and Trace (DWT) + \brief Type definitions for the Data Watchpoint and Trace (DWT) + @{ + */ + +/** + \brief Structure type to access the Data Watchpoint and Trace Register (DWT). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) Control Register */ + __IOM uint32_t CYCCNT; /*!< Offset: 0x004 (R/W) Cycle Count Register */ + __IOM uint32_t CPICNT; /*!< Offset: 0x008 (R/W) CPI Count Register */ + __IOM uint32_t EXCCNT; /*!< Offset: 0x00C (R/W) Exception Overhead Count Register */ + __IOM uint32_t SLEEPCNT; /*!< Offset: 0x010 (R/W) Sleep Count Register */ + __IOM uint32_t LSUCNT; /*!< Offset: 0x014 (R/W) LSU Count Register */ + __IOM uint32_t FOLDCNT; /*!< Offset: 0x018 (R/W) Folded-instruction Count Register */ + __IM uint32_t PCSR; /*!< Offset: 0x01C (R/ ) Program Counter Sample Register */ + __IOM uint32_t COMP0; /*!< Offset: 0x020 (R/W) Comparator Register 0 */ + uint32_t RESERVED1[1U]; + __IOM uint32_t FUNCTION0; /*!< Offset: 0x028 (R/W) Function Register 0 */ + uint32_t RESERVED2[1U]; + __IOM uint32_t COMP1; /*!< Offset: 0x030 (R/W) Comparator Register 1 */ + uint32_t RESERVED3[1U]; + __IOM uint32_t FUNCTION1; /*!< Offset: 0x038 (R/W) Function Register 1 */ + uint32_t RESERVED4[1U]; + __IOM uint32_t COMP2; /*!< Offset: 0x040 (R/W) Comparator Register 2 */ + uint32_t RESERVED5[1U]; + __IOM uint32_t FUNCTION2; /*!< Offset: 0x048 (R/W) Function Register 2 */ + uint32_t RESERVED6[1U]; + __IOM uint32_t COMP3; /*!< Offset: 0x050 (R/W) Comparator Register 3 */ + uint32_t RESERVED7[1U]; + __IOM uint32_t FUNCTION3; /*!< Offset: 0x058 (R/W) Function Register 3 */ + uint32_t RESERVED8[1U]; + __IOM uint32_t COMP4; /*!< Offset: 0x060 (R/W) Comparator Register 4 */ + uint32_t RESERVED9[1U]; + __IOM uint32_t FUNCTION4; /*!< Offset: 0x068 (R/W) Function Register 4 */ + uint32_t RESERVED10[1U]; + __IOM uint32_t COMP5; /*!< Offset: 0x070 (R/W) Comparator Register 5 */ + uint32_t RESERVED11[1U]; + __IOM uint32_t FUNCTION5; /*!< Offset: 0x078 (R/W) Function Register 5 */ + uint32_t RESERVED12[1U]; + __IOM uint32_t COMP6; /*!< Offset: 0x080 (R/W) Comparator Register 6 */ + uint32_t RESERVED13[1U]; + __IOM uint32_t FUNCTION6; /*!< Offset: 0x088 (R/W) Function Register 6 */ + uint32_t RESERVED14[1U]; + __IOM uint32_t COMP7; /*!< Offset: 0x090 (R/W) Comparator Register 7 */ + uint32_t RESERVED15[1U]; + __IOM uint32_t FUNCTION7; /*!< Offset: 0x098 (R/W) Function Register 7 */ + uint32_t RESERVED16[1U]; + __IOM uint32_t COMP8; /*!< Offset: 0x0A0 (R/W) Comparator Register 8 */ + uint32_t RESERVED17[1U]; + __IOM uint32_t FUNCTION8; /*!< Offset: 0x0A8 (R/W) Function Register 8 */ + uint32_t RESERVED18[1U]; + __IOM uint32_t COMP9; /*!< Offset: 0x0B0 (R/W) Comparator Register 9 */ + uint32_t RESERVED19[1U]; + __IOM uint32_t FUNCTION9; /*!< Offset: 0x0B8 (R/W) Function Register 9 */ + uint32_t RESERVED20[1U]; + __IOM uint32_t COMP10; /*!< Offset: 0x0C0 (R/W) Comparator Register 10 */ + uint32_t RESERVED21[1U]; + __IOM uint32_t FUNCTION10; /*!< Offset: 0x0C8 (R/W) Function Register 10 */ + uint32_t RESERVED22[1U]; + __IOM uint32_t COMP11; /*!< Offset: 0x0D0 (R/W) Comparator Register 11 */ + uint32_t RESERVED23[1U]; + __IOM uint32_t FUNCTION11; /*!< Offset: 0x0D8 (R/W) Function Register 11 */ + uint32_t RESERVED24[1U]; + __IOM uint32_t COMP12; /*!< Offset: 0x0E0 (R/W) Comparator Register 12 */ + uint32_t RESERVED25[1U]; + __IOM uint32_t FUNCTION12; /*!< Offset: 0x0E8 (R/W) Function Register 12 */ + uint32_t RESERVED26[1U]; + __IOM uint32_t COMP13; /*!< Offset: 0x0F0 (R/W) Comparator Register 13 */ + uint32_t RESERVED27[1U]; + __IOM uint32_t FUNCTION13; /*!< Offset: 0x0F8 (R/W) Function Register 13 */ + uint32_t RESERVED28[1U]; + __IOM uint32_t COMP14; /*!< Offset: 0x100 (R/W) Comparator Register 14 */ + uint32_t RESERVED29[1U]; + __IOM uint32_t FUNCTION14; /*!< Offset: 0x108 (R/W) Function Register 14 */ + uint32_t RESERVED30[1U]; + __IOM uint32_t COMP15; /*!< Offset: 0x110 (R/W) Comparator Register 15 */ + uint32_t RESERVED31[1U]; + __IOM uint32_t FUNCTION15; /*!< Offset: 0x118 (R/W) Function Register 15 */ + uint32_t RESERVED32[934U]; + __IM uint32_t LSR; /*!< Offset: 0xFB4 (R ) Lock Status Register */ + uint32_t RESERVED33[1U]; + __IM uint32_t DEVARCH; /*!< Offset: 0xFBC (R/ ) Device Architecture Register */ +} DWT_Type; + +/* DWT Control Register Definitions */ +#define DWT_CTRL_NUMCOMP_Pos 28U /*!< DWT CTRL: NUMCOMP Position */ +#define DWT_CTRL_NUMCOMP_Msk (0xFUL << DWT_CTRL_NUMCOMP_Pos) /*!< DWT CTRL: NUMCOMP Mask */ + +#define DWT_CTRL_NOTRCPKT_Pos 27U /*!< DWT CTRL: NOTRCPKT Position */ +#define DWT_CTRL_NOTRCPKT_Msk (0x1UL << DWT_CTRL_NOTRCPKT_Pos) /*!< DWT CTRL: NOTRCPKT Mask */ + +#define DWT_CTRL_NOEXTTRIG_Pos 26U /*!< DWT CTRL: NOEXTTRIG Position */ +#define DWT_CTRL_NOEXTTRIG_Msk (0x1UL << DWT_CTRL_NOEXTTRIG_Pos) /*!< DWT CTRL: NOEXTTRIG Mask */ + +#define DWT_CTRL_NOCYCCNT_Pos 25U /*!< DWT CTRL: NOCYCCNT Position */ +#define DWT_CTRL_NOCYCCNT_Msk (0x1UL << DWT_CTRL_NOCYCCNT_Pos) /*!< DWT CTRL: NOCYCCNT Mask */ + +#define DWT_CTRL_NOPRFCNT_Pos 24U /*!< DWT CTRL: NOPRFCNT Position */ +#define DWT_CTRL_NOPRFCNT_Msk (0x1UL << DWT_CTRL_NOPRFCNT_Pos) /*!< DWT CTRL: NOPRFCNT Mask */ + +#define DWT_CTRL_CYCDISS_Pos 23U /*!< DWT CTRL: CYCDISS Position */ +#define DWT_CTRL_CYCDISS_Msk (0x1UL << DWT_CTRL_CYCDISS_Pos) /*!< DWT CTRL: CYCDISS Mask */ + +#define DWT_CTRL_CYCEVTENA_Pos 22U /*!< DWT CTRL: CYCEVTENA Position */ +#define DWT_CTRL_CYCEVTENA_Msk (0x1UL << DWT_CTRL_CYCEVTENA_Pos) /*!< DWT CTRL: CYCEVTENA Mask */ + +#define DWT_CTRL_FOLDEVTENA_Pos 21U /*!< DWT CTRL: FOLDEVTENA Position */ +#define DWT_CTRL_FOLDEVTENA_Msk (0x1UL << DWT_CTRL_FOLDEVTENA_Pos) /*!< DWT CTRL: FOLDEVTENA Mask */ + +#define DWT_CTRL_LSUEVTENA_Pos 20U /*!< DWT CTRL: LSUEVTENA Position */ +#define DWT_CTRL_LSUEVTENA_Msk (0x1UL << DWT_CTRL_LSUEVTENA_Pos) /*!< DWT CTRL: LSUEVTENA Mask */ + +#define DWT_CTRL_SLEEPEVTENA_Pos 19U /*!< DWT CTRL: SLEEPEVTENA Position */ +#define DWT_CTRL_SLEEPEVTENA_Msk (0x1UL << DWT_CTRL_SLEEPEVTENA_Pos) /*!< DWT CTRL: SLEEPEVTENA Mask */ + +#define DWT_CTRL_EXCEVTENA_Pos 18U /*!< DWT CTRL: EXCEVTENA Position */ +#define DWT_CTRL_EXCEVTENA_Msk (0x1UL << DWT_CTRL_EXCEVTENA_Pos) /*!< DWT CTRL: EXCEVTENA Mask */ + +#define DWT_CTRL_CPIEVTENA_Pos 17U /*!< DWT CTRL: CPIEVTENA Position */ +#define DWT_CTRL_CPIEVTENA_Msk (0x1UL << DWT_CTRL_CPIEVTENA_Pos) /*!< DWT CTRL: CPIEVTENA Mask */ + +#define DWT_CTRL_EXCTRCENA_Pos 16U /*!< DWT CTRL: EXCTRCENA Position */ +#define DWT_CTRL_EXCTRCENA_Msk (0x1UL << DWT_CTRL_EXCTRCENA_Pos) /*!< DWT CTRL: EXCTRCENA Mask */ + +#define DWT_CTRL_PCSAMPLENA_Pos 12U /*!< DWT CTRL: PCSAMPLENA Position */ +#define DWT_CTRL_PCSAMPLENA_Msk (0x1UL << DWT_CTRL_PCSAMPLENA_Pos) /*!< DWT CTRL: PCSAMPLENA Mask */ + +#define DWT_CTRL_SYNCTAP_Pos 10U /*!< DWT CTRL: SYNCTAP Position */ +#define DWT_CTRL_SYNCTAP_Msk (0x3UL << DWT_CTRL_SYNCTAP_Pos) /*!< DWT CTRL: SYNCTAP Mask */ + +#define DWT_CTRL_CYCTAP_Pos 9U /*!< DWT CTRL: CYCTAP Position */ +#define DWT_CTRL_CYCTAP_Msk (0x1UL << DWT_CTRL_CYCTAP_Pos) /*!< DWT CTRL: CYCTAP Mask */ + +#define DWT_CTRL_POSTINIT_Pos 5U /*!< DWT CTRL: POSTINIT Position */ +#define DWT_CTRL_POSTINIT_Msk (0xFUL << DWT_CTRL_POSTINIT_Pos) /*!< DWT CTRL: POSTINIT Mask */ + +#define DWT_CTRL_POSTPRESET_Pos 1U /*!< DWT CTRL: POSTPRESET Position */ +#define DWT_CTRL_POSTPRESET_Msk (0xFUL << DWT_CTRL_POSTPRESET_Pos) /*!< DWT CTRL: POSTPRESET Mask */ + +#define DWT_CTRL_CYCCNTENA_Pos 0U /*!< DWT CTRL: CYCCNTENA Position */ +#define DWT_CTRL_CYCCNTENA_Msk (0x1UL /*<< DWT_CTRL_CYCCNTENA_Pos*/) /*!< DWT CTRL: CYCCNTENA Mask */ + +/* DWT CPI Count Register Definitions */ +#define DWT_CPICNT_CPICNT_Pos 0U /*!< DWT CPICNT: CPICNT Position */ +#define DWT_CPICNT_CPICNT_Msk (0xFFUL /*<< DWT_CPICNT_CPICNT_Pos*/) /*!< DWT CPICNT: CPICNT Mask */ + +/* DWT Exception Overhead Count Register Definitions */ +#define DWT_EXCCNT_EXCCNT_Pos 0U /*!< DWT EXCCNT: EXCCNT Position */ +#define DWT_EXCCNT_EXCCNT_Msk (0xFFUL /*<< DWT_EXCCNT_EXCCNT_Pos*/) /*!< DWT EXCCNT: EXCCNT Mask */ + +/* DWT Sleep Count Register Definitions */ +#define DWT_SLEEPCNT_SLEEPCNT_Pos 0U /*!< DWT SLEEPCNT: SLEEPCNT Position */ +#define DWT_SLEEPCNT_SLEEPCNT_Msk (0xFFUL /*<< DWT_SLEEPCNT_SLEEPCNT_Pos*/) /*!< DWT SLEEPCNT: SLEEPCNT Mask */ + +/* DWT LSU Count Register Definitions */ +#define DWT_LSUCNT_LSUCNT_Pos 0U /*!< DWT LSUCNT: LSUCNT Position */ +#define DWT_LSUCNT_LSUCNT_Msk (0xFFUL /*<< DWT_LSUCNT_LSUCNT_Pos*/) /*!< DWT LSUCNT: LSUCNT Mask */ + +/* DWT Folded-instruction Count Register Definitions */ +#define DWT_FOLDCNT_FOLDCNT_Pos 0U /*!< DWT FOLDCNT: FOLDCNT Position */ +#define DWT_FOLDCNT_FOLDCNT_Msk (0xFFUL /*<< DWT_FOLDCNT_FOLDCNT_Pos*/) /*!< DWT FOLDCNT: FOLDCNT Mask */ + +/* DWT Comparator Function Register Definitions */ +#define DWT_FUNCTION_ID_Pos 27U /*!< DWT FUNCTION: ID Position */ +#define DWT_FUNCTION_ID_Msk (0x1FUL << DWT_FUNCTION_ID_Pos) /*!< DWT FUNCTION: ID Mask */ + +#define DWT_FUNCTION_MATCHED_Pos 24U /*!< DWT FUNCTION: MATCHED Position */ +#define DWT_FUNCTION_MATCHED_Msk (0x1UL << DWT_FUNCTION_MATCHED_Pos) /*!< DWT FUNCTION: MATCHED Mask */ + +#define DWT_FUNCTION_DATAVSIZE_Pos 10U /*!< DWT FUNCTION: DATAVSIZE Position */ +#define DWT_FUNCTION_DATAVSIZE_Msk (0x3UL << DWT_FUNCTION_DATAVSIZE_Pos) /*!< DWT FUNCTION: DATAVSIZE Mask */ + +#define DWT_FUNCTION_ACTION_Pos 4U /*!< DWT FUNCTION: ACTION Position */ +#define DWT_FUNCTION_ACTION_Msk (0x1UL << DWT_FUNCTION_ACTION_Pos) /*!< DWT FUNCTION: ACTION Mask */ + +#define DWT_FUNCTION_MATCH_Pos 0U /*!< DWT FUNCTION: MATCH Position */ +#define DWT_FUNCTION_MATCH_Msk (0xFUL /*<< DWT_FUNCTION_MATCH_Pos*/) /*!< DWT FUNCTION: MATCH Mask */ + +/*@}*/ /* end of group CMSIS_DWT */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_TPI Trace Port Interface (TPI) + \brief Type definitions for the Trace Port Interface (TPI) + @{ + */ + +/** + \brief Structure type to access the Trace Port Interface Register (TPI). + */ +typedef struct +{ + __IM uint32_t SSPSR; /*!< Offset: 0x000 (R/ ) Supported Parallel Port Sizes Register */ + __IOM uint32_t CSPSR; /*!< Offset: 0x004 (R/W) Current Parallel Port Sizes Register */ + uint32_t RESERVED0[2U]; + __IOM uint32_t ACPR; /*!< Offset: 0x010 (R/W) Asynchronous Clock Prescaler Register */ + uint32_t RESERVED1[55U]; + __IOM uint32_t SPPR; /*!< Offset: 0x0F0 (R/W) Selected Pin Protocol Register */ + uint32_t RESERVED2[131U]; + __IM uint32_t FFSR; /*!< Offset: 0x300 (R/ ) Formatter and Flush Status Register */ + __IOM uint32_t FFCR; /*!< Offset: 0x304 (R/W) Formatter and Flush Control Register */ + __IOM uint32_t PSCR; /*!< Offset: 0x308 (R/W) Periodic Synchronization Control Register */ + uint32_t RESERVED3[809U]; + __OM uint32_t LAR; /*!< Offset: 0xFB0 ( /W) Software Lock Access Register */ + __IM uint32_t LSR; /*!< Offset: 0xFB4 (R/ ) Software Lock Status Register */ + uint32_t RESERVED4[4U]; + __IM uint32_t TYPE; /*!< Offset: 0xFC8 (R/ ) Device Identifier Register */ + __IM uint32_t DEVTYPE; /*!< Offset: 0xFCC (R/ ) Device Type Register */ +} TPI_Type; + +/* TPI Asynchronous Clock Prescaler Register Definitions */ +#define TPI_ACPR_SWOSCALER_Pos 0U /*!< TPI ACPR: SWOSCALER Position */ +#define TPI_ACPR_SWOSCALER_Msk (0xFFFFUL /*<< TPI_ACPR_SWOSCALER_Pos*/) /*!< TPI ACPR: SWOSCALER Mask */ + +/* TPI Selected Pin Protocol Register Definitions */ +#define TPI_SPPR_TXMODE_Pos 0U /*!< TPI SPPR: TXMODE Position */ +#define TPI_SPPR_TXMODE_Msk (0x3UL /*<< TPI_SPPR_TXMODE_Pos*/) /*!< TPI SPPR: TXMODE Mask */ + +/* TPI Formatter and Flush Status Register Definitions */ +#define TPI_FFSR_FtNonStop_Pos 3U /*!< TPI FFSR: FtNonStop Position */ +#define TPI_FFSR_FtNonStop_Msk (0x1UL << TPI_FFSR_FtNonStop_Pos) /*!< TPI FFSR: FtNonStop Mask */ + +#define TPI_FFSR_TCPresent_Pos 2U /*!< TPI FFSR: TCPresent Position */ +#define TPI_FFSR_TCPresent_Msk (0x1UL << TPI_FFSR_TCPresent_Pos) /*!< TPI FFSR: TCPresent Mask */ + +#define TPI_FFSR_FtStopped_Pos 1U /*!< TPI FFSR: FtStopped Position */ +#define TPI_FFSR_FtStopped_Msk (0x1UL << TPI_FFSR_FtStopped_Pos) /*!< TPI FFSR: FtStopped Mask */ + +#define TPI_FFSR_FlInProg_Pos 0U /*!< TPI FFSR: FlInProg Position */ +#define TPI_FFSR_FlInProg_Msk (0x1UL /*<< TPI_FFSR_FlInProg_Pos*/) /*!< TPI FFSR: FlInProg Mask */ + +/* TPI Formatter and Flush Control Register Definitions */ +#define TPI_FFCR_TrigIn_Pos 8U /*!< TPI FFCR: TrigIn Position */ +#define TPI_FFCR_TrigIn_Msk (0x1UL << TPI_FFCR_TrigIn_Pos) /*!< TPI FFCR: TrigIn Mask */ + +#define TPI_FFCR_FOnMan_Pos 6U /*!< TPI FFCR: FOnMan Position */ +#define TPI_FFCR_FOnMan_Msk (0x1UL << TPI_FFCR_FOnMan_Pos) /*!< TPI FFCR: FOnMan Mask */ + +#define TPI_FFCR_EnFCont_Pos 1U /*!< TPI FFCR: EnFCont Position */ +#define TPI_FFCR_EnFCont_Msk (0x1UL << TPI_FFCR_EnFCont_Pos) /*!< TPI FFCR: EnFCont Mask */ + +/* TPI Periodic Synchronization Control Register Definitions */ +#define TPI_PSCR_PSCount_Pos 0U /*!< TPI PSCR: PSCount Position */ +#define TPI_PSCR_PSCount_Msk (0x1FUL /*<< TPI_PSCR_PSCount_Pos*/) /*!< TPI PSCR: TPSCount Mask */ + +/* TPI Software Lock Status Register Definitions */ +#define TPI_LSR_nTT_Pos 1U /*!< TPI LSR: Not thirty-two bit. Position */ +#define TPI_LSR_nTT_Msk (0x1UL << TPI_LSR_nTT_Pos) /*!< TPI LSR: Not thirty-two bit. Mask */ + +#define TPI_LSR_SLK_Pos 1U /*!< TPI LSR: Software Lock status Position */ +#define TPI_LSR_SLK_Msk (0x1UL << TPI_LSR_SLK_Pos) /*!< TPI LSR: Software Lock status Mask */ + +#define TPI_LSR_SLI_Pos 0U /*!< TPI LSR: Software Lock implemented Position */ +#define TPI_LSR_SLI_Msk (0x1UL /*<< TPI_LSR_SLI_Pos*/) /*!< TPI LSR: Software Lock implemented Mask */ + +/* TPI DEVID Register Definitions */ +#define TPI_DEVID_NRZVALID_Pos 11U /*!< TPI DEVID: NRZVALID Position */ +#define TPI_DEVID_NRZVALID_Msk (0x1UL << TPI_DEVID_NRZVALID_Pos) /*!< TPI DEVID: NRZVALID Mask */ + +#define TPI_DEVID_MANCVALID_Pos 10U /*!< TPI DEVID: MANCVALID Position */ +#define TPI_DEVID_MANCVALID_Msk (0x1UL << TPI_DEVID_MANCVALID_Pos) /*!< TPI DEVID: MANCVALID Mask */ + +#define TPI_DEVID_PTINVALID_Pos 9U /*!< TPI DEVID: PTINVALID Position */ +#define TPI_DEVID_PTINVALID_Msk (0x1UL << TPI_DEVID_PTINVALID_Pos) /*!< TPI DEVID: PTINVALID Mask */ + +#define TPI_DEVID_FIFOSZ_Pos 6U /*!< TPI DEVID: FIFO depth Position */ +#define TPI_DEVID_FIFOSZ_Msk (0x7UL << TPI_DEVID_FIFOSZ_Pos) /*!< TPI DEVID: FIFO depth Mask */ + +/* TPI DEVTYPE Register Definitions */ +#define TPI_DEVTYPE_SubType_Pos 4U /*!< TPI DEVTYPE: SubType Position */ +#define TPI_DEVTYPE_SubType_Msk (0xFUL /*<< TPI_DEVTYPE_SubType_Pos*/) /*!< TPI DEVTYPE: SubType Mask */ + +#define TPI_DEVTYPE_MajorType_Pos 0U /*!< TPI DEVTYPE: MajorType Position */ +#define TPI_DEVTYPE_MajorType_Msk (0xFUL << TPI_DEVTYPE_MajorType_Pos) /*!< TPI DEVTYPE: MajorType Mask */ + +/*@}*/ /* end of group CMSIS_TPI */ + + +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_MPU Memory Protection Unit (MPU) + \brief Type definitions for the Memory Protection Unit (MPU) + @{ + */ + +/** + \brief Structure type to access the Memory Protection Unit (MPU). + */ +typedef struct +{ + __IM uint32_t TYPE; /*!< Offset: 0x000 (R/ ) MPU Type Register */ + __IOM uint32_t CTRL; /*!< Offset: 0x004 (R/W) MPU Control Register */ + __IOM uint32_t RNR; /*!< Offset: 0x008 (R/W) MPU Region Number Register */ + __IOM uint32_t RBAR; /*!< Offset: 0x00C (R/W) MPU Region Base Address Register */ + __IOM uint32_t RLAR; /*!< Offset: 0x010 (R/W) MPU Region Limit Address Register */ + __IOM uint32_t RBAR_A1; /*!< Offset: 0x014 (R/W) MPU Region Base Address Register Alias 1 */ + __IOM uint32_t RLAR_A1; /*!< Offset: 0x018 (R/W) MPU Region Limit Address Register Alias 1 */ + __IOM uint32_t RBAR_A2; /*!< Offset: 0x01C (R/W) MPU Region Base Address Register Alias 2 */ + __IOM uint32_t RLAR_A2; /*!< Offset: 0x020 (R/W) MPU Region Limit Address Register Alias 2 */ + __IOM uint32_t RBAR_A3; /*!< Offset: 0x024 (R/W) MPU Region Base Address Register Alias 3 */ + __IOM uint32_t RLAR_A3; /*!< Offset: 0x028 (R/W) MPU Region Limit Address Register Alias 3 */ + uint32_t RESERVED0[1]; + union { + __IOM uint32_t MAIR[2]; + struct { + __IOM uint32_t MAIR0; /*!< Offset: 0x030 (R/W) MPU Memory Attribute Indirection Register 0 */ + __IOM uint32_t MAIR1; /*!< Offset: 0x034 (R/W) MPU Memory Attribute Indirection Register 1 */ + }; + }; +} MPU_Type; + +#define MPU_TYPE_RALIASES 4U + +/* MPU Type Register Definitions */ +#define MPU_TYPE_IREGION_Pos 16U /*!< MPU TYPE: IREGION Position */ +#define MPU_TYPE_IREGION_Msk (0xFFUL << MPU_TYPE_IREGION_Pos) /*!< MPU TYPE: IREGION Mask */ + +#define MPU_TYPE_DREGION_Pos 8U /*!< MPU TYPE: DREGION Position */ +#define MPU_TYPE_DREGION_Msk (0xFFUL << MPU_TYPE_DREGION_Pos) /*!< MPU TYPE: DREGION Mask */ + +#define MPU_TYPE_SEPARATE_Pos 0U /*!< MPU TYPE: SEPARATE Position */ +#define MPU_TYPE_SEPARATE_Msk (1UL /*<< MPU_TYPE_SEPARATE_Pos*/) /*!< MPU TYPE: SEPARATE Mask */ + +/* MPU Control Register Definitions */ +#define MPU_CTRL_PRIVDEFENA_Pos 2U /*!< MPU CTRL: PRIVDEFENA Position */ +#define MPU_CTRL_PRIVDEFENA_Msk (1UL << MPU_CTRL_PRIVDEFENA_Pos) /*!< MPU CTRL: PRIVDEFENA Mask */ + +#define MPU_CTRL_HFNMIENA_Pos 1U /*!< MPU CTRL: HFNMIENA Position */ +#define MPU_CTRL_HFNMIENA_Msk (1UL << MPU_CTRL_HFNMIENA_Pos) /*!< MPU CTRL: HFNMIENA Mask */ + +#define MPU_CTRL_ENABLE_Pos 0U /*!< MPU CTRL: ENABLE Position */ +#define MPU_CTRL_ENABLE_Msk (1UL /*<< MPU_CTRL_ENABLE_Pos*/) /*!< MPU CTRL: ENABLE Mask */ + +/* MPU Region Number Register Definitions */ +#define MPU_RNR_REGION_Pos 0U /*!< MPU RNR: REGION Position */ +#define MPU_RNR_REGION_Msk (0xFFUL /*<< MPU_RNR_REGION_Pos*/) /*!< MPU RNR: REGION Mask */ + +/* MPU Region Base Address Register Definitions */ +#define MPU_RBAR_BASE_Pos 5U /*!< MPU RBAR: BASE Position */ +#define MPU_RBAR_BASE_Msk (0x7FFFFFFUL << MPU_RBAR_BASE_Pos) /*!< MPU RBAR: BASE Mask */ + +#define MPU_RBAR_SH_Pos 3U /*!< MPU RBAR: SH Position */ +#define MPU_RBAR_SH_Msk (0x3UL << MPU_RBAR_SH_Pos) /*!< MPU RBAR: SH Mask */ + +#define MPU_RBAR_AP_Pos 1U /*!< MPU RBAR: AP Position */ +#define MPU_RBAR_AP_Msk (0x3UL << MPU_RBAR_AP_Pos) /*!< MPU RBAR: AP Mask */ + +#define MPU_RBAR_XN_Pos 0U /*!< MPU RBAR: XN Position */ +#define MPU_RBAR_XN_Msk (01UL /*<< MPU_RBAR_XN_Pos*/) /*!< MPU RBAR: XN Mask */ + +/* MPU Region Limit Address Register Definitions */ +#define MPU_RLAR_LIMIT_Pos 5U /*!< MPU RLAR: LIMIT Position */ +#define MPU_RLAR_LIMIT_Msk (0x7FFFFFFUL << MPU_RLAR_LIMIT_Pos) /*!< MPU RLAR: LIMIT Mask */ + +#define MPU_RLAR_AttrIndx_Pos 1U /*!< MPU RLAR: AttrIndx Position */ +#define MPU_RLAR_AttrIndx_Msk (0x7UL << MPU_RLAR_AttrIndx_Pos) /*!< MPU RLAR: AttrIndx Mask */ + +#define MPU_RLAR_EN_Pos 0U /*!< MPU RLAR: Region enable bit Position */ +#define MPU_RLAR_EN_Msk (1UL /*<< MPU_RLAR_EN_Pos*/) /*!< MPU RLAR: Region enable bit Disable Mask */ + +/* MPU Memory Attribute Indirection Register 0 Definitions */ +#define MPU_MAIR0_Attr3_Pos 24U /*!< MPU MAIR0: Attr3 Position */ +#define MPU_MAIR0_Attr3_Msk (0xFFUL << MPU_MAIR0_Attr3_Pos) /*!< MPU MAIR0: Attr3 Mask */ + +#define MPU_MAIR0_Attr2_Pos 16U /*!< MPU MAIR0: Attr2 Position */ +#define MPU_MAIR0_Attr2_Msk (0xFFUL << MPU_MAIR0_Attr2_Pos) /*!< MPU MAIR0: Attr2 Mask */ + +#define MPU_MAIR0_Attr1_Pos 8U /*!< MPU MAIR0: Attr1 Position */ +#define MPU_MAIR0_Attr1_Msk (0xFFUL << MPU_MAIR0_Attr1_Pos) /*!< MPU MAIR0: Attr1 Mask */ + +#define MPU_MAIR0_Attr0_Pos 0U /*!< MPU MAIR0: Attr0 Position */ +#define MPU_MAIR0_Attr0_Msk (0xFFUL /*<< MPU_MAIR0_Attr0_Pos*/) /*!< MPU MAIR0: Attr0 Mask */ + +/* MPU Memory Attribute Indirection Register 1 Definitions */ +#define MPU_MAIR1_Attr7_Pos 24U /*!< MPU MAIR1: Attr7 Position */ +#define MPU_MAIR1_Attr7_Msk (0xFFUL << MPU_MAIR1_Attr7_Pos) /*!< MPU MAIR1: Attr7 Mask */ + +#define MPU_MAIR1_Attr6_Pos 16U /*!< MPU MAIR1: Attr6 Position */ +#define MPU_MAIR1_Attr6_Msk (0xFFUL << MPU_MAIR1_Attr6_Pos) /*!< MPU MAIR1: Attr6 Mask */ + +#define MPU_MAIR1_Attr5_Pos 8U /*!< MPU MAIR1: Attr5 Position */ +#define MPU_MAIR1_Attr5_Msk (0xFFUL << MPU_MAIR1_Attr5_Pos) /*!< MPU MAIR1: Attr5 Mask */ + +#define MPU_MAIR1_Attr4_Pos 0U /*!< MPU MAIR1: Attr4 Position */ +#define MPU_MAIR1_Attr4_Msk (0xFFUL /*<< MPU_MAIR1_Attr4_Pos*/) /*!< MPU MAIR1: Attr4 Mask */ + +/*@} end of group CMSIS_MPU */ +#endif + + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SAU Security Attribution Unit (SAU) + \brief Type definitions for the Security Attribution Unit (SAU) + @{ + */ + +/** + \brief Structure type to access the Security Attribution Unit (SAU). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SAU Control Register */ + __IM uint32_t TYPE; /*!< Offset: 0x004 (R/ ) SAU Type Register */ +#if defined (__SAUREGION_PRESENT) && (__SAUREGION_PRESENT == 1U) + __IOM uint32_t RNR; /*!< Offset: 0x008 (R/W) SAU Region Number Register */ + __IOM uint32_t RBAR; /*!< Offset: 0x00C (R/W) SAU Region Base Address Register */ + __IOM uint32_t RLAR; /*!< Offset: 0x010 (R/W) SAU Region Limit Address Register */ +#else + uint32_t RESERVED0[3]; +#endif + __IOM uint32_t SFSR; /*!< Offset: 0x014 (R/W) Secure Fault Status Register */ + __IOM uint32_t SFAR; /*!< Offset: 0x018 (R/W) Secure Fault Address Register */ +} SAU_Type; + +/* SAU Control Register Definitions */ +#define SAU_CTRL_ALLNS_Pos 1U /*!< SAU CTRL: ALLNS Position */ +#define SAU_CTRL_ALLNS_Msk (1UL << SAU_CTRL_ALLNS_Pos) /*!< SAU CTRL: ALLNS Mask */ + +#define SAU_CTRL_ENABLE_Pos 0U /*!< SAU CTRL: ENABLE Position */ +#define SAU_CTRL_ENABLE_Msk (1UL /*<< SAU_CTRL_ENABLE_Pos*/) /*!< SAU CTRL: ENABLE Mask */ + +/* SAU Type Register Definitions */ +#define SAU_TYPE_SREGION_Pos 0U /*!< SAU TYPE: SREGION Position */ +#define SAU_TYPE_SREGION_Msk (0xFFUL /*<< SAU_TYPE_SREGION_Pos*/) /*!< SAU TYPE: SREGION Mask */ + +#if defined (__SAUREGION_PRESENT) && (__SAUREGION_PRESENT == 1U) +/* SAU Region Number Register Definitions */ +#define SAU_RNR_REGION_Pos 0U /*!< SAU RNR: REGION Position */ +#define SAU_RNR_REGION_Msk (0xFFUL /*<< SAU_RNR_REGION_Pos*/) /*!< SAU RNR: REGION Mask */ + +/* SAU Region Base Address Register Definitions */ +#define SAU_RBAR_BADDR_Pos 5U /*!< SAU RBAR: BADDR Position */ +#define SAU_RBAR_BADDR_Msk (0x7FFFFFFUL << SAU_RBAR_BADDR_Pos) /*!< SAU RBAR: BADDR Mask */ + +/* SAU Region Limit Address Register Definitions */ +#define SAU_RLAR_LADDR_Pos 5U /*!< SAU RLAR: LADDR Position */ +#define SAU_RLAR_LADDR_Msk (0x7FFFFFFUL << SAU_RLAR_LADDR_Pos) /*!< SAU RLAR: LADDR Mask */ + +#define SAU_RLAR_NSC_Pos 1U /*!< SAU RLAR: NSC Position */ +#define SAU_RLAR_NSC_Msk (1UL << SAU_RLAR_NSC_Pos) /*!< SAU RLAR: NSC Mask */ + +#define SAU_RLAR_ENABLE_Pos 0U /*!< SAU RLAR: ENABLE Position */ +#define SAU_RLAR_ENABLE_Msk (1UL /*<< SAU_RLAR_ENABLE_Pos*/) /*!< SAU RLAR: ENABLE Mask */ + +#endif /* defined (__SAUREGION_PRESENT) && (__SAUREGION_PRESENT == 1U) */ + +/* Secure Fault Status Register Definitions */ +#define SAU_SFSR_LSERR_Pos 7U /*!< SAU SFSR: LSERR Position */ +#define SAU_SFSR_LSERR_Msk (1UL << SAU_SFSR_LSERR_Pos) /*!< SAU SFSR: LSERR Mask */ + +#define SAU_SFSR_SFARVALID_Pos 6U /*!< SAU SFSR: SFARVALID Position */ +#define SAU_SFSR_SFARVALID_Msk (1UL << SAU_SFSR_SFARVALID_Pos) /*!< SAU SFSR: SFARVALID Mask */ + +#define SAU_SFSR_LSPERR_Pos 5U /*!< SAU SFSR: LSPERR Position */ +#define SAU_SFSR_LSPERR_Msk (1UL << SAU_SFSR_LSPERR_Pos) /*!< SAU SFSR: LSPERR Mask */ + +#define SAU_SFSR_INVTRAN_Pos 4U /*!< SAU SFSR: INVTRAN Position */ +#define SAU_SFSR_INVTRAN_Msk (1UL << SAU_SFSR_INVTRAN_Pos) /*!< SAU SFSR: INVTRAN Mask */ + +#define SAU_SFSR_AUVIOL_Pos 3U /*!< SAU SFSR: AUVIOL Position */ +#define SAU_SFSR_AUVIOL_Msk (1UL << SAU_SFSR_AUVIOL_Pos) /*!< SAU SFSR: AUVIOL Mask */ + +#define SAU_SFSR_INVER_Pos 2U /*!< SAU SFSR: INVER Position */ +#define SAU_SFSR_INVER_Msk (1UL << SAU_SFSR_INVER_Pos) /*!< SAU SFSR: INVER Mask */ + +#define SAU_SFSR_INVIS_Pos 1U /*!< SAU SFSR: INVIS Position */ +#define SAU_SFSR_INVIS_Msk (1UL << SAU_SFSR_INVIS_Pos) /*!< SAU SFSR: INVIS Mask */ + +#define SAU_SFSR_INVEP_Pos 0U /*!< SAU SFSR: INVEP Position */ +#define SAU_SFSR_INVEP_Msk (1UL /*<< SAU_SFSR_INVEP_Pos*/) /*!< SAU SFSR: INVEP Mask */ + +/*@} end of group CMSIS_SAU */ +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_FPU Floating Point Unit (FPU) + \brief Type definitions for the Floating Point Unit (FPU) + @{ + */ + +/** + \brief Structure type to access the Floating Point Unit (FPU). + */ +typedef struct +{ + uint32_t RESERVED0[1U]; + __IOM uint32_t FPCCR; /*!< Offset: 0x004 (R/W) Floating-Point Context Control Register */ + __IOM uint32_t FPCAR; /*!< Offset: 0x008 (R/W) Floating-Point Context Address Register */ + __IOM uint32_t FPDSCR; /*!< Offset: 0x00C (R/W) Floating-Point Default Status Control Register */ + __IM uint32_t MVFR0; /*!< Offset: 0x010 (R/ ) Media and FP Feature Register 0 */ + __IM uint32_t MVFR1; /*!< Offset: 0x014 (R/ ) Media and FP Feature Register 1 */ +} FPU_Type; + +/* Floating-Point Context Control Register Definitions */ +#define FPU_FPCCR_ASPEN_Pos 31U /*!< FPCCR: ASPEN bit Position */ +#define FPU_FPCCR_ASPEN_Msk (1UL << FPU_FPCCR_ASPEN_Pos) /*!< FPCCR: ASPEN bit Mask */ + +#define FPU_FPCCR_LSPEN_Pos 30U /*!< FPCCR: LSPEN Position */ +#define FPU_FPCCR_LSPEN_Msk (1UL << FPU_FPCCR_LSPEN_Pos) /*!< FPCCR: LSPEN bit Mask */ + +#define FPU_FPCCR_LSPENS_Pos 29U /*!< FPCCR: LSPENS Position */ +#define FPU_FPCCR_LSPENS_Msk (1UL << FPU_FPCCR_LSPENS_Pos) /*!< FPCCR: LSPENS bit Mask */ + +#define FPU_FPCCR_CLRONRET_Pos 28U /*!< FPCCR: CLRONRET Position */ +#define FPU_FPCCR_CLRONRET_Msk (1UL << FPU_FPCCR_CLRONRET_Pos) /*!< FPCCR: CLRONRET bit Mask */ + +#define FPU_FPCCR_CLRONRETS_Pos 27U /*!< FPCCR: CLRONRETS Position */ +#define FPU_FPCCR_CLRONRETS_Msk (1UL << FPU_FPCCR_CLRONRETS_Pos) /*!< FPCCR: CLRONRETS bit Mask */ + +#define FPU_FPCCR_TS_Pos 26U /*!< FPCCR: TS Position */ +#define FPU_FPCCR_TS_Msk (1UL << FPU_FPCCR_TS_Pos) /*!< FPCCR: TS bit Mask */ + +#define FPU_FPCCR_UFRDY_Pos 10U /*!< FPCCR: UFRDY Position */ +#define FPU_FPCCR_UFRDY_Msk (1UL << FPU_FPCCR_UFRDY_Pos) /*!< FPCCR: UFRDY bit Mask */ + +#define FPU_FPCCR_SPLIMVIOL_Pos 9U /*!< FPCCR: SPLIMVIOL Position */ +#define FPU_FPCCR_SPLIMVIOL_Msk (1UL << FPU_FPCCR_SPLIMVIOL_Pos) /*!< FPCCR: SPLIMVIOL bit Mask */ + +#define FPU_FPCCR_MONRDY_Pos 8U /*!< FPCCR: MONRDY Position */ +#define FPU_FPCCR_MONRDY_Msk (1UL << FPU_FPCCR_MONRDY_Pos) /*!< FPCCR: MONRDY bit Mask */ + +#define FPU_FPCCR_SFRDY_Pos 7U /*!< FPCCR: SFRDY Position */ +#define FPU_FPCCR_SFRDY_Msk (1UL << FPU_FPCCR_SFRDY_Pos) /*!< FPCCR: SFRDY bit Mask */ + +#define FPU_FPCCR_BFRDY_Pos 6U /*!< FPCCR: BFRDY Position */ +#define FPU_FPCCR_BFRDY_Msk (1UL << FPU_FPCCR_BFRDY_Pos) /*!< FPCCR: BFRDY bit Mask */ + +#define FPU_FPCCR_MMRDY_Pos 5U /*!< FPCCR: MMRDY Position */ +#define FPU_FPCCR_MMRDY_Msk (1UL << FPU_FPCCR_MMRDY_Pos) /*!< FPCCR: MMRDY bit Mask */ + +#define FPU_FPCCR_HFRDY_Pos 4U /*!< FPCCR: HFRDY Position */ +#define FPU_FPCCR_HFRDY_Msk (1UL << FPU_FPCCR_HFRDY_Pos) /*!< FPCCR: HFRDY bit Mask */ + +#define FPU_FPCCR_THREAD_Pos 3U /*!< FPCCR: processor mode bit Position */ +#define FPU_FPCCR_THREAD_Msk (1UL << FPU_FPCCR_THREAD_Pos) /*!< FPCCR: processor mode active bit Mask */ + +#define FPU_FPCCR_S_Pos 2U /*!< FPCCR: Security status of the FP context bit Position */ +#define FPU_FPCCR_S_Msk (1UL << FPU_FPCCR_S_Pos) /*!< FPCCR: Security status of the FP context bit Mask */ + +#define FPU_FPCCR_USER_Pos 1U /*!< FPCCR: privilege level bit Position */ +#define FPU_FPCCR_USER_Msk (1UL << FPU_FPCCR_USER_Pos) /*!< FPCCR: privilege level bit Mask */ + +#define FPU_FPCCR_LSPACT_Pos 0U /*!< FPCCR: Lazy state preservation active bit Position */ +#define FPU_FPCCR_LSPACT_Msk (1UL /*<< FPU_FPCCR_LSPACT_Pos*/) /*!< FPCCR: Lazy state preservation active bit Mask */ + +/* Floating-Point Context Address Register Definitions */ +#define FPU_FPCAR_ADDRESS_Pos 3U /*!< FPCAR: ADDRESS bit Position */ +#define FPU_FPCAR_ADDRESS_Msk (0x1FFFFFFFUL << FPU_FPCAR_ADDRESS_Pos) /*!< FPCAR: ADDRESS bit Mask */ + +/* Floating-Point Default Status Control Register Definitions */ +#define FPU_FPDSCR_AHP_Pos 26U /*!< FPDSCR: AHP bit Position */ +#define FPU_FPDSCR_AHP_Msk (1UL << FPU_FPDSCR_AHP_Pos) /*!< FPDSCR: AHP bit Mask */ + +#define FPU_FPDSCR_DN_Pos 25U /*!< FPDSCR: DN bit Position */ +#define FPU_FPDSCR_DN_Msk (1UL << FPU_FPDSCR_DN_Pos) /*!< FPDSCR: DN bit Mask */ + +#define FPU_FPDSCR_FZ_Pos 24U /*!< FPDSCR: FZ bit Position */ +#define FPU_FPDSCR_FZ_Msk (1UL << FPU_FPDSCR_FZ_Pos) /*!< FPDSCR: FZ bit Mask */ + +#define FPU_FPDSCR_RMode_Pos 22U /*!< FPDSCR: RMode bit Position */ +#define FPU_FPDSCR_RMode_Msk (3UL << FPU_FPDSCR_RMode_Pos) /*!< FPDSCR: RMode bit Mask */ + +/* Media and FP Feature Register 0 Definitions */ +#define FPU_MVFR0_FP_rounding_modes_Pos 28U /*!< MVFR0: FP rounding modes bits Position */ +#define FPU_MVFR0_FP_rounding_modes_Msk (0xFUL << FPU_MVFR0_FP_rounding_modes_Pos) /*!< MVFR0: FP rounding modes bits Mask */ + +#define FPU_MVFR0_Short_vectors_Pos 24U /*!< MVFR0: Short vectors bits Position */ +#define FPU_MVFR0_Short_vectors_Msk (0xFUL << FPU_MVFR0_Short_vectors_Pos) /*!< MVFR0: Short vectors bits Mask */ + +#define FPU_MVFR0_Square_root_Pos 20U /*!< MVFR0: Square root bits Position */ +#define FPU_MVFR0_Square_root_Msk (0xFUL << FPU_MVFR0_Square_root_Pos) /*!< MVFR0: Square root bits Mask */ + +#define FPU_MVFR0_Divide_Pos 16U /*!< MVFR0: Divide bits Position */ +#define FPU_MVFR0_Divide_Msk (0xFUL << FPU_MVFR0_Divide_Pos) /*!< MVFR0: Divide bits Mask */ + +#define FPU_MVFR0_FP_excep_trapping_Pos 12U /*!< MVFR0: FP exception trapping bits Position */ +#define FPU_MVFR0_FP_excep_trapping_Msk (0xFUL << FPU_MVFR0_FP_excep_trapping_Pos) /*!< MVFR0: FP exception trapping bits Mask */ + +#define FPU_MVFR0_Double_precision_Pos 8U /*!< MVFR0: Double-precision bits Position */ +#define FPU_MVFR0_Double_precision_Msk (0xFUL << FPU_MVFR0_Double_precision_Pos) /*!< MVFR0: Double-precision bits Mask */ + +#define FPU_MVFR0_Single_precision_Pos 4U /*!< MVFR0: Single-precision bits Position */ +#define FPU_MVFR0_Single_precision_Msk (0xFUL << FPU_MVFR0_Single_precision_Pos) /*!< MVFR0: Single-precision bits Mask */ + +#define FPU_MVFR0_A_SIMD_registers_Pos 0U /*!< MVFR0: A_SIMD registers bits Position */ +#define FPU_MVFR0_A_SIMD_registers_Msk (0xFUL /*<< FPU_MVFR0_A_SIMD_registers_Pos*/) /*!< MVFR0: A_SIMD registers bits Mask */ + +/* Media and FP Feature Register 1 Definitions */ +#define FPU_MVFR1_FP_fused_MAC_Pos 28U /*!< MVFR1: FP fused MAC bits Position */ +#define FPU_MVFR1_FP_fused_MAC_Msk (0xFUL << FPU_MVFR1_FP_fused_MAC_Pos) /*!< MVFR1: FP fused MAC bits Mask */ + +#define FPU_MVFR1_FP_HPFP_Pos 24U /*!< MVFR1: FP HPFP bits Position */ +#define FPU_MVFR1_FP_HPFP_Msk (0xFUL << FPU_MVFR1_FP_HPFP_Pos) /*!< MVFR1: FP HPFP bits Mask */ + +#define FPU_MVFR1_D_NaN_mode_Pos 4U /*!< MVFR1: D_NaN mode bits Position */ +#define FPU_MVFR1_D_NaN_mode_Msk (0xFUL << FPU_MVFR1_D_NaN_mode_Pos) /*!< MVFR1: D_NaN mode bits Mask */ + +#define FPU_MVFR1_FtZ_mode_Pos 0U /*!< MVFR1: FtZ mode bits Position */ +#define FPU_MVFR1_FtZ_mode_Msk (0xFUL /*<< FPU_MVFR1_FtZ_mode_Pos*/) /*!< MVFR1: FtZ mode bits Mask */ + +/*@} end of group CMSIS_FPU */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CoreDebug Core Debug Registers (CoreDebug) + \brief Type definitions for the Core Debug Registers + @{ + */ + +/** + \brief Structure type to access the Core Debug Register (CoreDebug). + */ +typedef struct +{ + __IOM uint32_t DHCSR; /*!< Offset: 0x000 (R/W) Debug Halting Control and Status Register */ + __OM uint32_t DCRSR; /*!< Offset: 0x004 ( /W) Debug Core Register Selector Register */ + __IOM uint32_t DCRDR; /*!< Offset: 0x008 (R/W) Debug Core Register Data Register */ + __IOM uint32_t DEMCR; /*!< Offset: 0x00C (R/W) Debug Exception and Monitor Control Register */ + uint32_t RESERVED4[1U]; + __IOM uint32_t DAUTHCTRL; /*!< Offset: 0x014 (R/W) Debug Authentication Control Register */ + __IOM uint32_t DSCSR; /*!< Offset: 0x018 (R/W) Debug Security Control and Status Register */ +} CoreDebug_Type; + +/* Debug Halting Control and Status Register Definitions */ +#define CoreDebug_DHCSR_DBGKEY_Pos 16U /*!< CoreDebug DHCSR: DBGKEY Position */ +#define CoreDebug_DHCSR_DBGKEY_Msk (0xFFFFUL << CoreDebug_DHCSR_DBGKEY_Pos) /*!< CoreDebug DHCSR: DBGKEY Mask */ + +#define CoreDebug_DHCSR_S_RESTART_ST_Pos 26U /*!< CoreDebug DHCSR: S_RESTART_ST Position */ +#define CoreDebug_DHCSR_S_RESTART_ST_Msk (1UL << CoreDebug_DHCSR_S_RESTART_ST_Pos) /*!< CoreDebug DHCSR: S_RESTART_ST Mask */ + +#define CoreDebug_DHCSR_S_RESET_ST_Pos 25U /*!< CoreDebug DHCSR: S_RESET_ST Position */ +#define CoreDebug_DHCSR_S_RESET_ST_Msk (1UL << CoreDebug_DHCSR_S_RESET_ST_Pos) /*!< CoreDebug DHCSR: S_RESET_ST Mask */ + +#define CoreDebug_DHCSR_S_RETIRE_ST_Pos 24U /*!< CoreDebug DHCSR: S_RETIRE_ST Position */ +#define CoreDebug_DHCSR_S_RETIRE_ST_Msk (1UL << CoreDebug_DHCSR_S_RETIRE_ST_Pos) /*!< CoreDebug DHCSR: S_RETIRE_ST Mask */ + +#define CoreDebug_DHCSR_S_LOCKUP_Pos 19U /*!< CoreDebug DHCSR: S_LOCKUP Position */ +#define CoreDebug_DHCSR_S_LOCKUP_Msk (1UL << CoreDebug_DHCSR_S_LOCKUP_Pos) /*!< CoreDebug DHCSR: S_LOCKUP Mask */ + +#define CoreDebug_DHCSR_S_SLEEP_Pos 18U /*!< CoreDebug DHCSR: S_SLEEP Position */ +#define CoreDebug_DHCSR_S_SLEEP_Msk (1UL << CoreDebug_DHCSR_S_SLEEP_Pos) /*!< CoreDebug DHCSR: S_SLEEP Mask */ + +#define CoreDebug_DHCSR_S_HALT_Pos 17U /*!< CoreDebug DHCSR: S_HALT Position */ +#define CoreDebug_DHCSR_S_HALT_Msk (1UL << CoreDebug_DHCSR_S_HALT_Pos) /*!< CoreDebug DHCSR: S_HALT Mask */ + +#define CoreDebug_DHCSR_S_REGRDY_Pos 16U /*!< CoreDebug DHCSR: S_REGRDY Position */ +#define CoreDebug_DHCSR_S_REGRDY_Msk (1UL << CoreDebug_DHCSR_S_REGRDY_Pos) /*!< CoreDebug DHCSR: S_REGRDY Mask */ + +#define CoreDebug_DHCSR_C_SNAPSTALL_Pos 5U /*!< CoreDebug DHCSR: C_SNAPSTALL Position */ +#define CoreDebug_DHCSR_C_SNAPSTALL_Msk (1UL << CoreDebug_DHCSR_C_SNAPSTALL_Pos) /*!< CoreDebug DHCSR: C_SNAPSTALL Mask */ + +#define CoreDebug_DHCSR_C_MASKINTS_Pos 3U /*!< CoreDebug DHCSR: C_MASKINTS Position */ +#define CoreDebug_DHCSR_C_MASKINTS_Msk (1UL << CoreDebug_DHCSR_C_MASKINTS_Pos) /*!< CoreDebug DHCSR: C_MASKINTS Mask */ + +#define CoreDebug_DHCSR_C_STEP_Pos 2U /*!< CoreDebug DHCSR: C_STEP Position */ +#define CoreDebug_DHCSR_C_STEP_Msk (1UL << CoreDebug_DHCSR_C_STEP_Pos) /*!< CoreDebug DHCSR: C_STEP Mask */ + +#define CoreDebug_DHCSR_C_HALT_Pos 1U /*!< CoreDebug DHCSR: C_HALT Position */ +#define CoreDebug_DHCSR_C_HALT_Msk (1UL << CoreDebug_DHCSR_C_HALT_Pos) /*!< CoreDebug DHCSR: C_HALT Mask */ + +#define CoreDebug_DHCSR_C_DEBUGEN_Pos 0U /*!< CoreDebug DHCSR: C_DEBUGEN Position */ +#define CoreDebug_DHCSR_C_DEBUGEN_Msk (1UL /*<< CoreDebug_DHCSR_C_DEBUGEN_Pos*/) /*!< CoreDebug DHCSR: C_DEBUGEN Mask */ + +/* Debug Core Register Selector Register Definitions */ +#define CoreDebug_DCRSR_REGWnR_Pos 16U /*!< CoreDebug DCRSR: REGWnR Position */ +#define CoreDebug_DCRSR_REGWnR_Msk (1UL << CoreDebug_DCRSR_REGWnR_Pos) /*!< CoreDebug DCRSR: REGWnR Mask */ + +#define CoreDebug_DCRSR_REGSEL_Pos 0U /*!< CoreDebug DCRSR: REGSEL Position */ +#define CoreDebug_DCRSR_REGSEL_Msk (0x1FUL /*<< CoreDebug_DCRSR_REGSEL_Pos*/) /*!< CoreDebug DCRSR: REGSEL Mask */ + +/* Debug Exception and Monitor Control Register Definitions */ +#define CoreDebug_DEMCR_TRCENA_Pos 24U /*!< CoreDebug DEMCR: TRCENA Position */ +#define CoreDebug_DEMCR_TRCENA_Msk (1UL << CoreDebug_DEMCR_TRCENA_Pos) /*!< CoreDebug DEMCR: TRCENA Mask */ + +#define CoreDebug_DEMCR_MON_REQ_Pos 19U /*!< CoreDebug DEMCR: MON_REQ Position */ +#define CoreDebug_DEMCR_MON_REQ_Msk (1UL << CoreDebug_DEMCR_MON_REQ_Pos) /*!< CoreDebug DEMCR: MON_REQ Mask */ + +#define CoreDebug_DEMCR_MON_STEP_Pos 18U /*!< CoreDebug DEMCR: MON_STEP Position */ +#define CoreDebug_DEMCR_MON_STEP_Msk (1UL << CoreDebug_DEMCR_MON_STEP_Pos) /*!< CoreDebug DEMCR: MON_STEP Mask */ + +#define CoreDebug_DEMCR_MON_PEND_Pos 17U /*!< CoreDebug DEMCR: MON_PEND Position */ +#define CoreDebug_DEMCR_MON_PEND_Msk (1UL << CoreDebug_DEMCR_MON_PEND_Pos) /*!< CoreDebug DEMCR: MON_PEND Mask */ + +#define CoreDebug_DEMCR_MON_EN_Pos 16U /*!< CoreDebug DEMCR: MON_EN Position */ +#define CoreDebug_DEMCR_MON_EN_Msk (1UL << CoreDebug_DEMCR_MON_EN_Pos) /*!< CoreDebug DEMCR: MON_EN Mask */ + +#define CoreDebug_DEMCR_VC_HARDERR_Pos 10U /*!< CoreDebug DEMCR: VC_HARDERR Position */ +#define CoreDebug_DEMCR_VC_HARDERR_Msk (1UL << CoreDebug_DEMCR_VC_HARDERR_Pos) /*!< CoreDebug DEMCR: VC_HARDERR Mask */ + +#define CoreDebug_DEMCR_VC_INTERR_Pos 9U /*!< CoreDebug DEMCR: VC_INTERR Position */ +#define CoreDebug_DEMCR_VC_INTERR_Msk (1UL << CoreDebug_DEMCR_VC_INTERR_Pos) /*!< CoreDebug DEMCR: VC_INTERR Mask */ + +#define CoreDebug_DEMCR_VC_BUSERR_Pos 8U /*!< CoreDebug DEMCR: VC_BUSERR Position */ +#define CoreDebug_DEMCR_VC_BUSERR_Msk (1UL << CoreDebug_DEMCR_VC_BUSERR_Pos) /*!< CoreDebug DEMCR: VC_BUSERR Mask */ + +#define CoreDebug_DEMCR_VC_STATERR_Pos 7U /*!< CoreDebug DEMCR: VC_STATERR Position */ +#define CoreDebug_DEMCR_VC_STATERR_Msk (1UL << CoreDebug_DEMCR_VC_STATERR_Pos) /*!< CoreDebug DEMCR: VC_STATERR Mask */ + +#define CoreDebug_DEMCR_VC_CHKERR_Pos 6U /*!< CoreDebug DEMCR: VC_CHKERR Position */ +#define CoreDebug_DEMCR_VC_CHKERR_Msk (1UL << CoreDebug_DEMCR_VC_CHKERR_Pos) /*!< CoreDebug DEMCR: VC_CHKERR Mask */ + +#define CoreDebug_DEMCR_VC_NOCPERR_Pos 5U /*!< CoreDebug DEMCR: VC_NOCPERR Position */ +#define CoreDebug_DEMCR_VC_NOCPERR_Msk (1UL << CoreDebug_DEMCR_VC_NOCPERR_Pos) /*!< CoreDebug DEMCR: VC_NOCPERR Mask */ + +#define CoreDebug_DEMCR_VC_MMERR_Pos 4U /*!< CoreDebug DEMCR: VC_MMERR Position */ +#define CoreDebug_DEMCR_VC_MMERR_Msk (1UL << CoreDebug_DEMCR_VC_MMERR_Pos) /*!< CoreDebug DEMCR: VC_MMERR Mask */ + +#define CoreDebug_DEMCR_VC_CORERESET_Pos 0U /*!< CoreDebug DEMCR: VC_CORERESET Position */ +#define CoreDebug_DEMCR_VC_CORERESET_Msk (1UL /*<< CoreDebug_DEMCR_VC_CORERESET_Pos*/) /*!< CoreDebug DEMCR: VC_CORERESET Mask */ + +/* Debug Authentication Control Register Definitions */ +#define CoreDebug_DAUTHCTRL_INTSPNIDEN_Pos 3U /*!< CoreDebug DAUTHCTRL: INTSPNIDEN, Position */ +#define CoreDebug_DAUTHCTRL_INTSPNIDEN_Msk (1UL << CoreDebug_DAUTHCTRL_INTSPNIDEN_Pos) /*!< CoreDebug DAUTHCTRL: INTSPNIDEN, Mask */ + +#define CoreDebug_DAUTHCTRL_SPNIDENSEL_Pos 2U /*!< CoreDebug DAUTHCTRL: SPNIDENSEL Position */ +#define CoreDebug_DAUTHCTRL_SPNIDENSEL_Msk (1UL << CoreDebug_DAUTHCTRL_SPNIDENSEL_Pos) /*!< CoreDebug DAUTHCTRL: SPNIDENSEL Mask */ + +#define CoreDebug_DAUTHCTRL_INTSPIDEN_Pos 1U /*!< CoreDebug DAUTHCTRL: INTSPIDEN Position */ +#define CoreDebug_DAUTHCTRL_INTSPIDEN_Msk (1UL << CoreDebug_DAUTHCTRL_INTSPIDEN_Pos) /*!< CoreDebug DAUTHCTRL: INTSPIDEN Mask */ + +#define CoreDebug_DAUTHCTRL_SPIDENSEL_Pos 0U /*!< CoreDebug DAUTHCTRL: SPIDENSEL Position */ +#define CoreDebug_DAUTHCTRL_SPIDENSEL_Msk (1UL /*<< CoreDebug_DAUTHCTRL_SPIDENSEL_Pos*/) /*!< CoreDebug DAUTHCTRL: SPIDENSEL Mask */ + +/* Debug Security Control and Status Register Definitions */ +#define CoreDebug_DSCSR_CDS_Pos 16U /*!< CoreDebug DSCSR: CDS Position */ +#define CoreDebug_DSCSR_CDS_Msk (1UL << CoreDebug_DSCSR_CDS_Pos) /*!< CoreDebug DSCSR: CDS Mask */ + +#define CoreDebug_DSCSR_SBRSEL_Pos 1U /*!< CoreDebug DSCSR: SBRSEL Position */ +#define CoreDebug_DSCSR_SBRSEL_Msk (1UL << CoreDebug_DSCSR_SBRSEL_Pos) /*!< CoreDebug DSCSR: SBRSEL Mask */ + +#define CoreDebug_DSCSR_SBRSELEN_Pos 0U /*!< CoreDebug DSCSR: SBRSELEN Position */ +#define CoreDebug_DSCSR_SBRSELEN_Msk (1UL /*<< CoreDebug_DSCSR_SBRSELEN_Pos*/) /*!< CoreDebug DSCSR: SBRSELEN Mask */ + +/*@} end of group CMSIS_CoreDebug */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_bitfield Core register bit field macros + \brief Macros for use with bit field definitions (xxx_Pos, xxx_Msk). + @{ + */ + +/** + \brief Mask and shift a bit field value for use in a register bit range. + \param[in] field Name of the register bit field. + \param[in] value Value of the bit field. This parameter is interpreted as an uint32_t type. + \return Masked and shifted value. +*/ +#define _VAL2FLD(field, value) (((uint32_t)(value) << field ## _Pos) & field ## _Msk) + +/** + \brief Mask and shift a register value to extract a bit filed value. + \param[in] field Name of the register bit field. + \param[in] value Value of register. This parameter is interpreted as an uint32_t type. + \return Masked and shifted bit field value. +*/ +#define _FLD2VAL(field, value) (((uint32_t)(value) & field ## _Msk) >> field ## _Pos) + +/*@} end of group CMSIS_core_bitfield */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_base Core Definitions + \brief Definitions for base addresses, unions, and structures. + @{ + */ + +/* Memory mapping of Core Hardware */ + #define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ + #define ITM_BASE (0xE0000000UL) /*!< ITM Base Address */ + #define DWT_BASE (0xE0001000UL) /*!< DWT Base Address */ + #define TPI_BASE (0xE0040000UL) /*!< TPI Base Address */ + #define CoreDebug_BASE (0xE000EDF0UL) /*!< Core Debug Base Address */ + #define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */ + #define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */ + #define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */ + + #define SCnSCB ((SCnSCB_Type *) SCS_BASE ) /*!< System control Register not in SCB */ + #define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */ + #define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */ + #define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */ + #define ITM ((ITM_Type *) ITM_BASE ) /*!< ITM configuration struct */ + #define DWT ((DWT_Type *) DWT_BASE ) /*!< DWT configuration struct */ + #define TPI ((TPI_Type *) TPI_BASE ) /*!< TPI configuration struct */ + #define CoreDebug ((CoreDebug_Type *) CoreDebug_BASE ) /*!< Core Debug configuration struct */ + + #if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + #define MPU_BASE (SCS_BASE + 0x0D90UL) /*!< Memory Protection Unit */ + #define MPU ((MPU_Type *) MPU_BASE ) /*!< Memory Protection Unit */ + #endif + + #if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + #define SAU_BASE (SCS_BASE + 0x0DD0UL) /*!< Security Attribution Unit */ + #define SAU ((SAU_Type *) SAU_BASE ) /*!< Security Attribution Unit */ + #endif + + #define FPU_BASE (SCS_BASE + 0x0F30UL) /*!< Floating Point Unit */ + #define FPU ((FPU_Type *) FPU_BASE ) /*!< Floating Point Unit */ + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + #define SCS_BASE_NS (0xE002E000UL) /*!< System Control Space Base Address (non-secure address space) */ + #define CoreDebug_BASE_NS (0xE002EDF0UL) /*!< Core Debug Base Address (non-secure address space) */ + #define SysTick_BASE_NS (SCS_BASE_NS + 0x0010UL) /*!< SysTick Base Address (non-secure address space) */ + #define NVIC_BASE_NS (SCS_BASE_NS + 0x0100UL) /*!< NVIC Base Address (non-secure address space) */ + #define SCB_BASE_NS (SCS_BASE_NS + 0x0D00UL) /*!< System Control Block Base Address (non-secure address space) */ + + #define SCnSCB_NS ((SCnSCB_Type *) SCS_BASE_NS ) /*!< System control Register not in SCB(non-secure address space) */ + #define SCB_NS ((SCB_Type *) SCB_BASE_NS ) /*!< SCB configuration struct (non-secure address space) */ + #define SysTick_NS ((SysTick_Type *) SysTick_BASE_NS ) /*!< SysTick configuration struct (non-secure address space) */ + #define NVIC_NS ((NVIC_Type *) NVIC_BASE_NS ) /*!< NVIC configuration struct (non-secure address space) */ + #define CoreDebug_NS ((CoreDebug_Type *) CoreDebug_BASE_NS) /*!< Core Debug configuration struct (non-secure address space) */ + + #if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + #define MPU_BASE_NS (SCS_BASE_NS + 0x0D90UL) /*!< Memory Protection Unit (non-secure address space) */ + #define MPU_NS ((MPU_Type *) MPU_BASE_NS ) /*!< Memory Protection Unit (non-secure address space) */ + #endif + + #define FPU_BASE_NS (SCS_BASE_NS + 0x0F30UL) /*!< Floating Point Unit (non-secure address space) */ + #define FPU_NS ((FPU_Type *) FPU_BASE_NS ) /*!< Floating Point Unit (non-secure address space) */ + +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ +/*@} */ + + + +/******************************************************************************* + * Hardware Abstraction Layer + Core Function Interface contains: + - Core NVIC Functions + - Core SysTick Functions + - Core Debug Functions + - Core Register Access Functions + ******************************************************************************/ +/** + \defgroup CMSIS_Core_FunctionInterface Functions and Instructions Reference +*/ + + + +/* ########################## NVIC functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_NVICFunctions NVIC Functions + \brief Functions that manage interrupts and exceptions via the NVIC. + @{ + */ + +#ifdef CMSIS_NVIC_VIRTUAL + #ifndef CMSIS_NVIC_VIRTUAL_HEADER_FILE + #define CMSIS_NVIC_VIRTUAL_HEADER_FILE "cmsis_nvic_virtual.h" + #endif + #include CMSIS_NVIC_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetPriorityGrouping __NVIC_SetPriorityGrouping + #define NVIC_GetPriorityGrouping __NVIC_GetPriorityGrouping + #define NVIC_EnableIRQ __NVIC_EnableIRQ + #define NVIC_GetEnableIRQ __NVIC_GetEnableIRQ + #define NVIC_DisableIRQ __NVIC_DisableIRQ + #define NVIC_GetPendingIRQ __NVIC_GetPendingIRQ + #define NVIC_SetPendingIRQ __NVIC_SetPendingIRQ + #define NVIC_ClearPendingIRQ __NVIC_ClearPendingIRQ + #define NVIC_GetActive __NVIC_GetActive + #define NVIC_SetPriority __NVIC_SetPriority + #define NVIC_GetPriority __NVIC_GetPriority + #define NVIC_SystemReset __NVIC_SystemReset +#endif /* CMSIS_NVIC_VIRTUAL */ + +#ifdef CMSIS_VECTAB_VIRTUAL + #ifndef CMSIS_VECTAB_VIRTUAL_HEADER_FILE + #define CMSIS_VECTAB_VIRTUAL_HEADER_FILE "cmsis_vectab_virtual.h" + #endif + #include CMSIS_VECTAB_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetVector __NVIC_SetVector + #define NVIC_GetVector __NVIC_GetVector +#endif /* (CMSIS_VECTAB_VIRTUAL) */ + +#define NVIC_USER_IRQ_OFFSET 16 + + +/* Special LR values for Secure/Non-Secure call handling and exception handling */ + +/* Function Return Payload (from ARMv8-M Architecture Reference Manual) LR value on entry from Secure BLXNS */ +#define FNC_RETURN (0xFEFFFFFFUL) /* bit [0] ignored when processing a branch */ + +/* The following EXC_RETURN mask values are used to evaluate the LR on exception entry */ +#define EXC_RETURN_PREFIX (0xFF000000UL) /* bits [31:24] set to indicate an EXC_RETURN value */ +#define EXC_RETURN_S (0x00000040UL) /* bit [6] stack used to push registers: 0=Non-secure 1=Secure */ +#define EXC_RETURN_DCRS (0x00000020UL) /* bit [5] stacking rules for called registers: 0=skipped 1=saved */ +#define EXC_RETURN_FTYPE (0x00000010UL) /* bit [4] allocate stack for floating-point context: 0=done 1=skipped */ +#define EXC_RETURN_MODE (0x00000008UL) /* bit [3] processor mode for return: 0=Handler mode 1=Thread mode */ +#define EXC_RETURN_SPSEL (0x00000004UL) /* bit [2] stack pointer used to restore context: 0=MSP 1=PSP */ +#define EXC_RETURN_ES (0x00000001UL) /* bit [0] security state exception was taken to: 0=Non-secure 1=Secure */ + +/* Integrity Signature (from ARMv8-M Architecture Reference Manual) for exception context stacking */ +#if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) /* Value for processors with floating-point extension: */ +#define EXC_INTEGRITY_SIGNATURE (0xFEFA125AUL) /* bit [0] SFTC must match LR bit[4] EXC_RETURN_FTYPE */ +#else +#define EXC_INTEGRITY_SIGNATURE (0xFEFA125BUL) /* Value for processors without floating-point extension */ +#endif + + +/** + \brief Set Priority Grouping + \details Sets the priority grouping field using the required unlock sequence. + The parameter PriorityGroup is assigned to the field SCB->AIRCR [10:8] PRIGROUP field. + Only values from 0..7 are used. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. + \param [in] PriorityGroup Priority grouping field. + */ +__STATIC_INLINE void __NVIC_SetPriorityGrouping(uint32_t PriorityGroup) +{ + uint32_t reg_value; + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + + reg_value = SCB->AIRCR; /* read old register configuration */ + reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk)); /* clear bits to change */ + reg_value = (reg_value | + ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + (PriorityGroupTmp << SCB_AIRCR_PRIGROUP_Pos) ); /* Insert write key and priority group */ + SCB->AIRCR = reg_value; +} + + +/** + \brief Get Priority Grouping + \details Reads the priority grouping field from the NVIC Interrupt Controller. + \return Priority grouping field (SCB->AIRCR [10:8] PRIGROUP field). + */ +__STATIC_INLINE uint32_t __NVIC_GetPriorityGrouping(void) +{ + return ((uint32_t)((SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) >> SCB_AIRCR_PRIGROUP_Pos)); +} + + +/** + \brief Enable Interrupt + \details Enables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Interrupt Enable status + \details Returns a device specific interrupt enable status from the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt is not enabled. + \return 1 Interrupt is enabled. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t __NVIC_GetEnableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Disable Interrupt + \details Disables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_DisableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + __DSB(); + __ISB(); + } +} + + +/** + \brief Get Pending Interrupt + \details Reads the NVIC pending register and returns the pending bit for the specified device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt status is not pending. + \return 1 Interrupt status is pending. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t __NVIC_GetPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Set Pending Interrupt + \details Sets the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_SetPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Clear Pending Interrupt + \details Clears the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_ClearPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Active Interrupt + \details Reads the active register in the NVIC and returns the active bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt status is not active. + \return 1 Interrupt status is active. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t __NVIC_GetActive(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->IABR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +/** + \brief Get Interrupt Target State + \details Reads the interrupt target field in the NVIC and returns the interrupt target bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 if interrupt is assigned to Secure + \return 1 if interrupt is assigned to Non Secure + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t NVIC_GetTargetState(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Set Interrupt Target State + \details Sets the interrupt target field in the NVIC and returns the interrupt target bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 if interrupt is assigned to Secure + 1 if interrupt is assigned to Non Secure + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t NVIC_SetTargetState(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] |= ((uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL))); + return((uint32_t)(((NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Clear Interrupt Target State + \details Clears the interrupt target field in the NVIC and returns the interrupt target bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 if interrupt is assigned to Secure + 1 if interrupt is assigned to Non Secure + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t NVIC_ClearTargetState(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] &= ~((uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL))); + return((uint32_t)(((NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ + + +/** + \brief Set Interrupt Priority + \details Sets the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \param [in] priority Priority to set. + \note The priority cannot be set for every processor exception. + */ +__STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->IPR[((uint32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + } + else + { + SCB->SHPR[(((uint32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + } +} + + +/** + \brief Get Interrupt Priority + \details Reads the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Interrupt Priority. + Value is aligned automatically to the implemented priority bits of the microcontroller. + */ +__STATIC_INLINE uint32_t __NVIC_GetPriority(IRQn_Type IRQn) +{ + + if ((int32_t)(IRQn) >= 0) + { + return(((uint32_t)NVIC->IPR[((uint32_t)IRQn)] >> (8U - __NVIC_PRIO_BITS))); + } + else + { + return(((uint32_t)SCB->SHPR[(((uint32_t)IRQn) & 0xFUL)-4UL] >> (8U - __NVIC_PRIO_BITS))); + } +} + + +/** + \brief Encode Priority + \details Encodes the priority for an interrupt with the given priority group, + preemptive priority value, and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. + \param [in] PriorityGroup Used priority group. + \param [in] PreemptPriority Preemptive priority value (starting from 0). + \param [in] SubPriority Subpriority value (starting from 0). + \return Encoded priority. Value can be used in the function \ref NVIC_SetPriority(). + */ +__STATIC_INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + return ( + ((PreemptPriority & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL)) << SubPriorityBits) | + ((SubPriority & (uint32_t)((1UL << (SubPriorityBits )) - 1UL))) + ); +} + + +/** + \brief Decode Priority + \details Decodes an interrupt priority value with a given priority group to + preemptive priority value and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS) the smallest possible priority group is set. + \param [in] Priority Priority value, which can be retrieved with the function \ref NVIC_GetPriority(). + \param [in] PriorityGroup Used priority group. + \param [out] pPreemptPriority Preemptive priority value (starting from 0). + \param [out] pSubPriority Subpriority value (starting from 0). + */ +__STATIC_INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGroup, uint32_t* const pPreemptPriority, uint32_t* const pSubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + *pPreemptPriority = (Priority >> SubPriorityBits) & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL); + *pSubPriority = (Priority ) & (uint32_t)((1UL << (SubPriorityBits )) - 1UL); +} + + +/** + \brief Set Interrupt Vector + \details Sets an interrupt vector in SRAM based interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + VTOR must been relocated to SRAM before. + \param [in] IRQn Interrupt number + \param [in] vector Address of interrupt handler function + */ +__STATIC_INLINE void __NVIC_SetVector(IRQn_Type IRQn, uint32_t vector) +{ + uint32_t *vectors = (uint32_t *)SCB->VTOR; + vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET] = vector; +} + + +/** + \brief Get Interrupt Vector + \details Reads an interrupt vector from interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Address of interrupt handler function + */ +__STATIC_INLINE uint32_t __NVIC_GetVector(IRQn_Type IRQn) +{ + uint32_t *vectors = (uint32_t *)SCB->VTOR; + return vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET]; +} + + +/** + \brief System Reset + \details Initiates a system reset request to reset the MCU. + */ +__NO_RETURN __STATIC_INLINE void __NVIC_SystemReset(void) +{ + __DSB(); /* Ensure all outstanding memory accesses included + buffered write are completed before reset */ + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + SCB_AIRCR_SYSRESETREQ_Msk ); /* Keep priority group unchanged */ + __DSB(); /* Ensure completion of memory access */ + + for(;;) /* wait until reset */ + { + __NOP(); + } +} + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +/** + \brief Set Priority Grouping (non-secure) + \details Sets the non-secure priority grouping field when in secure state using the required unlock sequence. + The parameter PriorityGroup is assigned to the field SCB->AIRCR [10:8] PRIGROUP field. + Only values from 0..7 are used. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. + \param [in] PriorityGroup Priority grouping field. + */ +__STATIC_INLINE void TZ_NVIC_SetPriorityGrouping_NS(uint32_t PriorityGroup) +{ + uint32_t reg_value; + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + + reg_value = SCB_NS->AIRCR; /* read old register configuration */ + reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk)); /* clear bits to change */ + reg_value = (reg_value | + ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + (PriorityGroupTmp << SCB_AIRCR_PRIGROUP_Pos) ); /* Insert write key and priority group */ + SCB_NS->AIRCR = reg_value; +} + + +/** + \brief Get Priority Grouping (non-secure) + \details Reads the priority grouping field from the non-secure NVIC when in secure state. + \return Priority grouping field (SCB->AIRCR [10:8] PRIGROUP field). + */ +__STATIC_INLINE uint32_t TZ_NVIC_GetPriorityGrouping_NS(void) +{ + return ((uint32_t)((SCB_NS->AIRCR & SCB_AIRCR_PRIGROUP_Msk) >> SCB_AIRCR_PRIGROUP_Pos)); +} + + +/** + \brief Enable Interrupt (non-secure) + \details Enables a device specific interrupt in the non-secure NVIC interrupt controller when in secure state. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void TZ_NVIC_EnableIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Interrupt Enable status (non-secure) + \details Returns a device specific interrupt enable status from the non-secure NVIC interrupt controller when in secure state. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt is not enabled. + \return 1 Interrupt is enabled. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t TZ_NVIC_GetEnableIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC_NS->ISER[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Disable Interrupt (non-secure) + \details Disables a device specific interrupt in the non-secure NVIC interrupt controller when in secure state. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void TZ_NVIC_DisableIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->ICER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Pending Interrupt (non-secure) + \details Reads the NVIC pending register in the non-secure NVIC when in secure state and returns the pending bit for the specified device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt status is not pending. + \return 1 Interrupt status is pending. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t TZ_NVIC_GetPendingIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC_NS->ISPR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Set Pending Interrupt (non-secure) + \details Sets the pending bit of a device specific interrupt in the non-secure NVIC pending register when in secure state. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void TZ_NVIC_SetPendingIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->ISPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Clear Pending Interrupt (non-secure) + \details Clears the pending bit of a device specific interrupt in the non-secure NVIC pending register when in secure state. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void TZ_NVIC_ClearPendingIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->ICPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Active Interrupt (non-secure) + \details Reads the active register in non-secure NVIC when in secure state and returns the active bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt status is not active. + \return 1 Interrupt status is active. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t TZ_NVIC_GetActive_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC_NS->IABR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Set Interrupt Priority (non-secure) + \details Sets the priority of a non-secure device specific interrupt or a non-secure processor exception when in secure state. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \param [in] priority Priority to set. + \note The priority cannot be set for every non-secure processor exception. + */ +__STATIC_INLINE void TZ_NVIC_SetPriority_NS(IRQn_Type IRQn, uint32_t priority) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->IPR[((uint32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + } + else + { + SCB_NS->SHPR[(((uint32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + } +} + + +/** + \brief Get Interrupt Priority (non-secure) + \details Reads the priority of a non-secure device specific interrupt or a non-secure processor exception when in secure state. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Interrupt Priority. Value is aligned automatically to the implemented priority bits of the microcontroller. + */ +__STATIC_INLINE uint32_t TZ_NVIC_GetPriority_NS(IRQn_Type IRQn) +{ + + if ((int32_t)(IRQn) >= 0) + { + return(((uint32_t)NVIC_NS->IPR[((uint32_t)IRQn)] >> (8U - __NVIC_PRIO_BITS))); + } + else + { + return(((uint32_t)SCB_NS->SHPR[(((uint32_t)IRQn) & 0xFUL)-4UL] >> (8U - __NVIC_PRIO_BITS))); + } +} +#endif /* defined (__ARM_FEATURE_CMSE) &&(__ARM_FEATURE_CMSE == 3U) */ + +/*@} end of CMSIS_Core_NVICFunctions */ + +/* ########################## MPU functions #################################### */ + +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + +#include "mpu_armv8.h" + +#endif + +/* ########################## FPU functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_FpuFunctions FPU Functions + \brief Function that provides FPU type. + @{ + */ + +/** + \brief get FPU type + \details returns the FPU type + \returns + - \b 0: No FPU + - \b 1: Single precision FPU + - \b 2: Double + Single precision FPU + */ +__STATIC_INLINE uint32_t SCB_GetFPUType(void) +{ + uint32_t mvfr0; + + mvfr0 = FPU->MVFR0; + if ((mvfr0 & (FPU_MVFR0_Single_precision_Msk | FPU_MVFR0_Double_precision_Msk)) == 0x220U) + { + return 2U; /* Double + Single precision FPU */ + } + else if ((mvfr0 & (FPU_MVFR0_Single_precision_Msk | FPU_MVFR0_Double_precision_Msk)) == 0x020U) + { + return 1U; /* Single precision FPU */ + } + else + { + return 0U; /* No FPU */ + } +} + + +/*@} end of CMSIS_Core_FpuFunctions */ + + + +/* ########################## SAU functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_SAUFunctions SAU Functions + \brief Functions that configure the SAU. + @{ + */ + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + +/** + \brief Enable SAU + \details Enables the Security Attribution Unit (SAU). + */ +__STATIC_INLINE void TZ_SAU_Enable(void) +{ + SAU->CTRL |= (SAU_CTRL_ENABLE_Msk); +} + + + +/** + \brief Disable SAU + \details Disables the Security Attribution Unit (SAU). + */ +__STATIC_INLINE void TZ_SAU_Disable(void) +{ + SAU->CTRL &= ~(SAU_CTRL_ENABLE_Msk); +} + +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ + +/*@} end of CMSIS_Core_SAUFunctions */ + + + + +/* ################################## SysTick function ############################################ */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_SysTickFunctions SysTick Functions + \brief Functions that configure the System. + @{ + */ + +#if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U) + +/** + \brief System Tick Configuration + \details Initializes the System Timer and its interrupt, and starts the System Tick Timer. + Counter is in free running mode to generate periodic interrupts. + \param [in] ticks Number of ticks between two interrupts. + \return 0 Function succeeded. + \return 1 Function failed. + \note When the variable __Vendor_SysTickConfig is set to 1, then the + function SysTick_Config is not included. In this case, the file device.h + must contain a vendor-specific implementation of this function. + */ +__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) +{ + if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) + { + return (1UL); /* Reload value impossible */ + } + + SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ + NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ + SysTick->VAL = 0UL; /* Load the SysTick Counter Value */ + SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + SysTick_CTRL_TICKINT_Msk | + SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ + return (0UL); /* Function successful */ +} + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +/** + \brief System Tick Configuration (non-secure) + \details Initializes the non-secure System Timer and its interrupt when in secure state, and starts the System Tick Timer. + Counter is in free running mode to generate periodic interrupts. + \param [in] ticks Number of ticks between two interrupts. + \return 0 Function succeeded. + \return 1 Function failed. + \note When the variable __Vendor_SysTickConfig is set to 1, then the + function TZ_SysTick_Config_NS is not included. In this case, the file device.h + must contain a vendor-specific implementation of this function. + + */ +__STATIC_INLINE uint32_t TZ_SysTick_Config_NS(uint32_t ticks) +{ + if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) + { + return (1UL); /* Reload value impossible */ + } + + SysTick_NS->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ + TZ_NVIC_SetPriority_NS (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ + SysTick_NS->VAL = 0UL; /* Load the SysTick Counter Value */ + SysTick_NS->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + SysTick_CTRL_TICKINT_Msk | + SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ + return (0UL); /* Function successful */ +} +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ + +#endif + +/*@} end of CMSIS_Core_SysTickFunctions */ + + + +/* ##################################### Debug In/Output function ########################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_core_DebugFunctions ITM Functions + \brief Functions that access the ITM debug interface. + @{ + */ + +extern volatile int32_t ITM_RxBuffer; /*!< External variable to receive characters. */ +#define ITM_RXBUFFER_EMPTY ((int32_t)0x5AA55AA5U) /*!< Value identifying \ref ITM_RxBuffer is ready for next character. */ + + +/** + \brief ITM Send Character + \details Transmits a character via the ITM channel 0, and + \li Just returns when no debugger is connected that has booked the output. + \li Is blocking when a debugger is connected, but the previous character sent has not been transmitted. + \param [in] ch Character to transmit. + \returns Character to transmit. + */ +__STATIC_INLINE uint32_t ITM_SendChar (uint32_t ch) +{ + if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && /* ITM enabled */ + ((ITM->TER & 1UL ) != 0UL) ) /* ITM Port #0 enabled */ + { + while (ITM->PORT[0U].u32 == 0UL) + { + __NOP(); + } + ITM->PORT[0U].u8 = (uint8_t)ch; + } + return (ch); +} + + +/** + \brief ITM Receive Character + \details Inputs a character via the external variable \ref ITM_RxBuffer. + \return Received character. + \return -1 No character pending. + */ +__STATIC_INLINE int32_t ITM_ReceiveChar (void) +{ + int32_t ch = -1; /* no character available */ + + if (ITM_RxBuffer != ITM_RXBUFFER_EMPTY) + { + ch = ITM_RxBuffer; + ITM_RxBuffer = ITM_RXBUFFER_EMPTY; /* ready for next character */ + } + + return (ch); +} + + +/** + \brief ITM Check Character + \details Checks whether a character is pending for reading in the variable \ref ITM_RxBuffer. + \return 0 No character available. + \return 1 Character available. + */ +__STATIC_INLINE int32_t ITM_CheckChar (void) +{ + + if (ITM_RxBuffer == ITM_RXBUFFER_EMPTY) + { + return (0); /* no character available */ + } + else + { + return (1); /* character available */ + } +} + +/*@} end of CMSIS_core_DebugFunctions */ + + + + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_ARMV8MML_H_DEPENDANT */ + +#endif /* __CMSIS_GENERIC */ diff --git a/lib/cmsis/inc/core_cm0.h b/lib/cmsis/inc/core_cm0.h index 711dad5517..fcf27578cc 100644 --- a/lib/cmsis/inc/core_cm0.h +++ b/lib/cmsis/inc/core_cm0.h @@ -1,40 +1,30 @@ /**************************************************************************//** * @file core_cm0.h * @brief CMSIS Cortex-M0 Core Peripheral Access Layer Header File - * @version V4.30 - * @date 20. October 2015 + * @version V5.0.6 + * @date 13. March 2019 ******************************************************************************/ -/* Copyright (c) 2009 - 2015 ARM LIMITED - - All rights reserved. - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 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. - - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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. - ---------------------------------------------------------------------------*/ - +/* + * Copyright (c) 2009-2019 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #if defined ( __ICCARM__ ) - #pragma system_include /* treat file as system include file for MISRA check */ -#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined (__clang__) #pragma clang system_header /* treat file as system include file */ #endif @@ -70,53 +60,15 @@ @{ */ +#include "cmsis_version.h" + /* CMSIS CM0 definitions */ -#define __CM0_CMSIS_VERSION_MAIN (0x04U) /*!< [31:16] CMSIS HAL main version */ -#define __CM0_CMSIS_VERSION_SUB (0x1EU) /*!< [15:0] CMSIS HAL sub version */ +#define __CM0_CMSIS_VERSION_MAIN (__CM_CMSIS_VERSION_MAIN) /*!< \deprecated [31:16] CMSIS HAL main version */ +#define __CM0_CMSIS_VERSION_SUB (__CM_CMSIS_VERSION_SUB) /*!< \deprecated [15:0] CMSIS HAL sub version */ #define __CM0_CMSIS_VERSION ((__CM0_CMSIS_VERSION_MAIN << 16U) | \ - __CM0_CMSIS_VERSION_SUB ) /*!< CMSIS HAL version number */ + __CM0_CMSIS_VERSION_SUB ) /*!< \deprecated CMSIS HAL version number */ -#define __CORTEX_M (0x00U) /*!< Cortex-M Core */ - - -#if defined ( __CC_ARM ) - #define __ASM __asm /*!< asm keyword for ARM Compiler */ - #define __INLINE __inline /*!< inline keyword for ARM Compiler */ - #define __STATIC_INLINE static __inline - -#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) - #define __ASM __asm /*!< asm keyword for ARM Compiler */ - #define __INLINE __inline /*!< inline keyword for ARM Compiler */ - #define __STATIC_INLINE static __inline - -#elif defined ( __GNUC__ ) - #define __ASM __asm /*!< asm keyword for GNU Compiler */ - #define __INLINE inline /*!< inline keyword for GNU Compiler */ - #define __STATIC_INLINE static inline - -#elif defined ( __ICCARM__ ) - #define __ASM __asm /*!< asm keyword for IAR Compiler */ - #define __INLINE inline /*!< inline keyword for IAR Compiler. Only available in High optimization mode! */ - #define __STATIC_INLINE static inline - -#elif defined ( __TMS470__ ) - #define __ASM __asm /*!< asm keyword for TI CCS Compiler */ - #define __STATIC_INLINE static inline - -#elif defined ( __TASKING__ ) - #define __ASM __asm /*!< asm keyword for TASKING Compiler */ - #define __INLINE inline /*!< inline keyword for TASKING Compiler */ - #define __STATIC_INLINE static inline - -#elif defined ( __CSMC__ ) - #define __packed - #define __ASM _asm /*!< asm keyword for COSMIC Compiler */ - #define __INLINE inline /*!< inline keyword for COSMIC Compiler. Use -pc99 on compile line */ - #define __STATIC_INLINE static inline - -#else - #error Unknown compiler -#endif +#define __CORTEX_M (0U) /*!< Cortex-M Core */ /** __FPU_USED indicates whether an FPU is used or not. This core does not support an FPU at all @@ -128,8 +80,8 @@ #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif -#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) - #if defined __ARM_PCS_VFP +#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #if defined __ARM_FP #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif @@ -143,7 +95,7 @@ #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif -#elif defined ( __TMS470__ ) +#elif defined ( __TI_ARM__ ) #if defined __TI_VFP_SUPPORT__ #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif @@ -160,8 +112,8 @@ #endif -#include "core_cmInstr.h" /* Core Instruction Access */ -#include "core_cmFunc.h" /* Core Function Access */ +#include "cmsis_compiler.h" /* CMSIS compiler specific defines */ + #ifdef __cplusplus } @@ -364,7 +316,7 @@ typedef struct __IOM uint32_t ISER[1U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ uint32_t RESERVED0[31U]; __IOM uint32_t ICER[1U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ - uint32_t RSERVED1[31U]; + uint32_t RESERVED1[31U]; __IOM uint32_t ISPR[1U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ uint32_t RESERVED2[31U]; __IOM uint32_t ICPR[1U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ @@ -555,18 +507,18 @@ typedef struct /** \brief Mask and shift a bit field value for use in a register bit range. \param[in] field Name of the register bit field. - \param[in] value Value of the bit field. + \param[in] value Value of the bit field. This parameter is interpreted as an uint32_t type. \return Masked and shifted value. */ -#define _VAL2FLD(field, value) ((value << field ## _Pos) & field ## _Msk) +#define _VAL2FLD(field, value) (((uint32_t)(value) << field ## _Pos) & field ## _Msk) /** \brief Mask and shift a register value to extract a bit filed value. \param[in] field Name of the register bit field. - \param[in] value Value of register. + \param[in] value Value of register. This parameter is interpreted as an uint32_t type. \return Masked and shifted bit field value. */ -#define _FLD2VAL(field, value) ((value & field ## _Msk) >> field ## _Pos) +#define _FLD2VAL(field, value) (((uint32_t)(value) & field ## _Msk) >> field ## _Pos) /*@} end of group CMSIS_core_bitfield */ @@ -578,7 +530,7 @@ typedef struct @{ */ -/* Memory mapping of Cortex-M0 Hardware */ +/* Memory mapping of Core Hardware */ #define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ #define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */ #define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */ @@ -614,87 +566,177 @@ typedef struct @{ */ -/* Interrupt Priorities are WORD accessible only under ARMv6M */ +#ifdef CMSIS_NVIC_VIRTUAL + #ifndef CMSIS_NVIC_VIRTUAL_HEADER_FILE + #define CMSIS_NVIC_VIRTUAL_HEADER_FILE "cmsis_nvic_virtual.h" + #endif + #include CMSIS_NVIC_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetPriorityGrouping __NVIC_SetPriorityGrouping + #define NVIC_GetPriorityGrouping __NVIC_GetPriorityGrouping + #define NVIC_EnableIRQ __NVIC_EnableIRQ + #define NVIC_GetEnableIRQ __NVIC_GetEnableIRQ + #define NVIC_DisableIRQ __NVIC_DisableIRQ + #define NVIC_GetPendingIRQ __NVIC_GetPendingIRQ + #define NVIC_SetPendingIRQ __NVIC_SetPendingIRQ + #define NVIC_ClearPendingIRQ __NVIC_ClearPendingIRQ +/*#define NVIC_GetActive __NVIC_GetActive not available for Cortex-M0 */ + #define NVIC_SetPriority __NVIC_SetPriority + #define NVIC_GetPriority __NVIC_GetPriority + #define NVIC_SystemReset __NVIC_SystemReset +#endif /* CMSIS_NVIC_VIRTUAL */ + +#ifdef CMSIS_VECTAB_VIRTUAL + #ifndef CMSIS_VECTAB_VIRTUAL_HEADER_FILE + #define CMSIS_VECTAB_VIRTUAL_HEADER_FILE "cmsis_vectab_virtual.h" + #endif + #include CMSIS_VECTAB_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetVector __NVIC_SetVector + #define NVIC_GetVector __NVIC_GetVector +#endif /* (CMSIS_VECTAB_VIRTUAL) */ + +#define NVIC_USER_IRQ_OFFSET 16 + + +/* The following EXC_RETURN values are saved the LR on exception entry */ +#define EXC_RETURN_HANDLER (0xFFFFFFF1UL) /* return to Handler mode, uses MSP after return */ +#define EXC_RETURN_THREAD_MSP (0xFFFFFFF9UL) /* return to Thread mode, uses MSP after return */ +#define EXC_RETURN_THREAD_PSP (0xFFFFFFFDUL) /* return to Thread mode, uses PSP after return */ + + +/* Interrupt Priorities are WORD accessible only under Armv6-M */ /* The following MACROS handle generation of the register offset and byte masks */ #define _BIT_SHIFT(IRQn) ( ((((uint32_t)(int32_t)(IRQn)) ) & 0x03UL) * 8UL) #define _SHP_IDX(IRQn) ( (((((uint32_t)(int32_t)(IRQn)) & 0x0FUL)-8UL) >> 2UL) ) #define _IP_IDX(IRQn) ( (((uint32_t)(int32_t)(IRQn)) >> 2UL) ) +#define __NVIC_SetPriorityGrouping(X) (void)(X) +#define __NVIC_GetPriorityGrouping() (0U) /** - \brief Enable External Interrupt - \details Enables a device-specific interrupt in the NVIC interrupt controller. - \param [in] IRQn External interrupt number. Value cannot be negative. + \brief Enable Interrupt + \details Enables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. */ -__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn) +__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn) { - NVIC->ISER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISER[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } } /** - \brief Disable External Interrupt - \details Disables a device-specific interrupt in the NVIC interrupt controller. - \param [in] IRQn External interrupt number. Value cannot be negative. + \brief Get Interrupt Enable status + \details Returns a device specific interrupt enable status from the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt is not enabled. + \return 1 Interrupt is enabled. + \note IRQn must not be negative. */ -__STATIC_INLINE void NVIC_DisableIRQ(IRQn_Type IRQn) +__STATIC_INLINE uint32_t __NVIC_GetEnableIRQ(IRQn_Type IRQn) { - NVIC->ICER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISER[0U] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Disable Interrupt + \details Disables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_DisableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICER[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + __DSB(); + __ISB(); + } } /** \brief Get Pending Interrupt - \details Reads the pending register in the NVIC and returns the pending bit for the specified interrupt. - \param [in] IRQn Interrupt number. + \details Reads the NVIC pending register and returns the pending bit for the specified device specific interrupt. + \param [in] IRQn Device specific interrupt number. \return 0 Interrupt status is not pending. \return 1 Interrupt status is pending. + \note IRQn must not be negative. */ -__STATIC_INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn) +__STATIC_INLINE uint32_t __NVIC_GetPendingIRQ(IRQn_Type IRQn) { - return((uint32_t)(((NVIC->ISPR[0U] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISPR[0U] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } } /** \brief Set Pending Interrupt - \details Sets the pending bit of an external interrupt. - \param [in] IRQn Interrupt number. Value cannot be negative. + \details Sets the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. */ -__STATIC_INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn) +__STATIC_INLINE void __NVIC_SetPendingIRQ(IRQn_Type IRQn) { - NVIC->ISPR[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISPR[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } } /** \brief Clear Pending Interrupt - \details Clears the pending bit of an external interrupt. - \param [in] IRQn External interrupt number. Value cannot be negative. + \details Clears the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. */ -__STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn) +__STATIC_INLINE void __NVIC_ClearPendingIRQ(IRQn_Type IRQn) { - NVIC->ICPR[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICPR[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } } /** \brief Set Interrupt Priority - \details Sets the priority of an interrupt. - \note The priority cannot be set for every core interrupt. + \details Sets the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. \param [in] IRQn Interrupt number. \param [in] priority Priority to set. + \note The priority cannot be set for every processor exception. */ -__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +__STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) { - if ((int32_t)(IRQn) < 0) + if ((int32_t)(IRQn) >= 0) { - SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); } else { - NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); } } @@ -702,24 +744,108 @@ __STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) /** \brief Get Interrupt Priority - \details Reads the priority of an interrupt. - The interrupt number can be positive to specify an external (device specific) interrupt, - or negative to specify an internal (core) interrupt. + \details Reads the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. \param [in] IRQn Interrupt number. \return Interrupt Priority. Value is aligned automatically to the implemented priority bits of the microcontroller. */ -__STATIC_INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn) +__STATIC_INLINE uint32_t __NVIC_GetPriority(IRQn_Type IRQn) { - if ((int32_t)(IRQn) < 0) - { - return((uint32_t)(((SCB->SHP[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); - } - else + if ((int32_t)(IRQn) >= 0) { return((uint32_t)(((NVIC->IP[ _IP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); } + else + { + return((uint32_t)(((SCB->SHP[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); + } +} + + +/** + \brief Encode Priority + \details Encodes the priority for an interrupt with the given priority group, + preemptive priority value, and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. + \param [in] PriorityGroup Used priority group. + \param [in] PreemptPriority Preemptive priority value (starting from 0). + \param [in] SubPriority Subpriority value (starting from 0). + \return Encoded priority. Value can be used in the function \ref NVIC_SetPriority(). + */ +__STATIC_INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + return ( + ((PreemptPriority & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL)) << SubPriorityBits) | + ((SubPriority & (uint32_t)((1UL << (SubPriorityBits )) - 1UL))) + ); +} + + +/** + \brief Decode Priority + \details Decodes an interrupt priority value with a given priority group to + preemptive priority value and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS) the smallest possible priority group is set. + \param [in] Priority Priority value, which can be retrieved with the function \ref NVIC_GetPriority(). + \param [in] PriorityGroup Used priority group. + \param [out] pPreemptPriority Preemptive priority value (starting from 0). + \param [out] pSubPriority Subpriority value (starting from 0). + */ +__STATIC_INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGroup, uint32_t* const pPreemptPriority, uint32_t* const pSubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + *pPreemptPriority = (Priority >> SubPriorityBits) & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL); + *pSubPriority = (Priority ) & (uint32_t)((1UL << (SubPriorityBits )) - 1UL); +} + + + +/** + \brief Set Interrupt Vector + \details Sets an interrupt vector in SRAM based interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + Address 0 must be mapped to SRAM. + \param [in] IRQn Interrupt number + \param [in] vector Address of interrupt handler function + */ +__STATIC_INLINE void __NVIC_SetVector(IRQn_Type IRQn, uint32_t vector) +{ + uint32_t vectors = 0x0U; + (* (int *) (vectors + ((int32_t)IRQn + NVIC_USER_IRQ_OFFSET) * 4)) = vector; +} + + +/** + \brief Get Interrupt Vector + \details Reads an interrupt vector from interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Address of interrupt handler function + */ +__STATIC_INLINE uint32_t __NVIC_GetVector(IRQn_Type IRQn) +{ + uint32_t vectors = 0x0U; + return (uint32_t)(* (int *) (vectors + ((int32_t)IRQn + NVIC_USER_IRQ_OFFSET) * 4)); } @@ -727,7 +853,7 @@ __STATIC_INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn) \brief System Reset \details Initiates a system reset request to reset the MCU. */ -__STATIC_INLINE void NVIC_SystemReset(void) +__NO_RETURN __STATIC_INLINE void __NVIC_SystemReset(void) { __DSB(); /* Ensure all outstanding memory accesses included buffered write are completed before reset */ @@ -744,6 +870,31 @@ __STATIC_INLINE void NVIC_SystemReset(void) /*@} end of CMSIS_Core_NVICFunctions */ +/* ########################## FPU functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_FpuFunctions FPU Functions + \brief Function that provides FPU type. + @{ + */ + +/** + \brief get FPU type + \details returns the FPU type + \returns + - \b 0: No FPU + - \b 1: Single precision FPU + - \b 2: Double + Single precision FPU + */ +__STATIC_INLINE uint32_t SCB_GetFPUType(void) +{ + return 0U; /* No FPU */ +} + + +/*@} end of CMSIS_Core_FpuFunctions */ + + /* ################################## SysTick function ############################################ */ /** @@ -753,7 +904,7 @@ __STATIC_INLINE void NVIC_SystemReset(void) @{ */ -#if (__Vendor_SysTickConfig == 0U) +#if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U) /** \brief System Tick Configuration diff --git a/lib/cmsis/inc/core_cm0plus.h b/lib/cmsis/inc/core_cm0plus.h index b04aa39053..65ea443095 100644 --- a/lib/cmsis/inc/core_cm0plus.h +++ b/lib/cmsis/inc/core_cm0plus.h @@ -1,40 +1,30 @@ /**************************************************************************//** * @file core_cm0plus.h * @brief CMSIS Cortex-M0+ Core Peripheral Access Layer Header File - * @version V4.30 - * @date 20. October 2015 + * @version V5.0.7 + * @date 13. March 2019 ******************************************************************************/ -/* Copyright (c) 2009 - 2015 ARM LIMITED - - All rights reserved. - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 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. - - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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. - ---------------------------------------------------------------------------*/ - +/* + * Copyright (c) 2009-2018 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #if defined ( __ICCARM__ ) - #pragma system_include /* treat file as system include file for MISRA check */ -#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined (__clang__) #pragma clang system_header /* treat file as system include file */ #endif @@ -70,53 +60,15 @@ @{ */ +#include "cmsis_version.h" + /* CMSIS CM0+ definitions */ -#define __CM0PLUS_CMSIS_VERSION_MAIN (0x04U) /*!< [31:16] CMSIS HAL main version */ -#define __CM0PLUS_CMSIS_VERSION_SUB (0x1EU) /*!< [15:0] CMSIS HAL sub version */ +#define __CM0PLUS_CMSIS_VERSION_MAIN (__CM_CMSIS_VERSION_MAIN) /*!< \deprecated [31:16] CMSIS HAL main version */ +#define __CM0PLUS_CMSIS_VERSION_SUB (__CM_CMSIS_VERSION_SUB) /*!< \deprecated [15:0] CMSIS HAL sub version */ #define __CM0PLUS_CMSIS_VERSION ((__CM0PLUS_CMSIS_VERSION_MAIN << 16U) | \ - __CM0PLUS_CMSIS_VERSION_SUB ) /*!< CMSIS HAL version number */ + __CM0PLUS_CMSIS_VERSION_SUB ) /*!< \deprecated CMSIS HAL version number */ -#define __CORTEX_M (0x00U) /*!< Cortex-M Core */ - - -#if defined ( __CC_ARM ) - #define __ASM __asm /*!< asm keyword for ARM Compiler */ - #define __INLINE __inline /*!< inline keyword for ARM Compiler */ - #define __STATIC_INLINE static __inline - -#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) - #define __ASM __asm /*!< asm keyword for ARM Compiler */ - #define __INLINE __inline /*!< inline keyword for ARM Compiler */ - #define __STATIC_INLINE static __inline - -#elif defined ( __GNUC__ ) - #define __ASM __asm /*!< asm keyword for GNU Compiler */ - #define __INLINE inline /*!< inline keyword for GNU Compiler */ - #define __STATIC_INLINE static inline - -#elif defined ( __ICCARM__ ) - #define __ASM __asm /*!< asm keyword for IAR Compiler */ - #define __INLINE inline /*!< inline keyword for IAR Compiler. Only available in High optimization mode! */ - #define __STATIC_INLINE static inline - -#elif defined ( __TMS470__ ) - #define __ASM __asm /*!< asm keyword for TI CCS Compiler */ - #define __STATIC_INLINE static inline - -#elif defined ( __TASKING__ ) - #define __ASM __asm /*!< asm keyword for TASKING Compiler */ - #define __INLINE inline /*!< inline keyword for TASKING Compiler */ - #define __STATIC_INLINE static inline - -#elif defined ( __CSMC__ ) - #define __packed - #define __ASM _asm /*!< asm keyword for COSMIC Compiler */ - #define __INLINE inline /*!< inline keyword for COSMIC Compiler. Use -pc99 on compile line */ - #define __STATIC_INLINE static inline - -#else - #error Unknown compiler -#endif +#define __CORTEX_M (0U) /*!< Cortex-M Core */ /** __FPU_USED indicates whether an FPU is used or not. This core does not support an FPU at all @@ -128,8 +80,8 @@ #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif -#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) - #if defined __ARM_PCS_VFP +#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #if defined __ARM_FP #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif @@ -143,7 +95,7 @@ #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif -#elif defined ( __TMS470__ ) +#elif defined ( __TI_ARM__ ) #if defined __TI_VFP_SUPPORT__ #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif @@ -160,8 +112,8 @@ #endif -#include "core_cmInstr.h" /* Core Instruction Access */ -#include "core_cmFunc.h" /* Core Function Access */ +#include "cmsis_compiler.h" /* CMSIS compiler specific defines */ + #ifdef __cplusplus } @@ -378,7 +330,7 @@ typedef struct __IOM uint32_t ISER[1U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ uint32_t RESERVED0[31U]; __IOM uint32_t ICER[1U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ - uint32_t RSERVED1[31U]; + uint32_t RESERVED1[31U]; __IOM uint32_t ISPR[1U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ uint32_t RESERVED2[31U]; __IOM uint32_t ICPR[1U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ @@ -404,7 +356,7 @@ typedef struct { __IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */ __IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */ -#if (__VTOR_PRESENT == 1U) +#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U) __IOM uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */ #else uint32_t RESERVED0; @@ -461,7 +413,7 @@ typedef struct #define SCB_ICSR_VECTACTIVE_Pos 0U /*!< SCB ICSR: VECTACTIVE Position */ #define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL /*<< SCB_ICSR_VECTACTIVE_Pos*/) /*!< SCB ICSR: VECTACTIVE Mask */ -#if (__VTOR_PRESENT == 1U) +#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U) /* SCB Interrupt Control State Register Definitions */ #define SCB_VTOR_TBLOFF_Pos 8U /*!< SCB VTOR: TBLOFF Position */ #define SCB_VTOR_TBLOFF_Msk (0xFFFFFFUL << SCB_VTOR_TBLOFF_Pos) /*!< SCB VTOR: TBLOFF Mask */ @@ -558,7 +510,7 @@ typedef struct /*@} end of group CMSIS_SysTick */ -#if (__MPU_PRESENT == 1U) +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) /** \ingroup CMSIS_core_register \defgroup CMSIS_MPU Memory Protection Unit (MPU) @@ -578,6 +530,8 @@ typedef struct __IOM uint32_t RASR; /*!< Offset: 0x010 (R/W) MPU Region Attribute and Size Register */ } MPU_Type; +#define MPU_TYPE_RALIASES 1U + /* MPU Type Register Definitions */ #define MPU_TYPE_IREGION_Pos 16U /*!< MPU TYPE: IREGION Position */ #define MPU_TYPE_IREGION_Msk (0xFFUL << MPU_TYPE_IREGION_Pos) /*!< MPU TYPE: IREGION Mask */ @@ -667,18 +621,18 @@ typedef struct /** \brief Mask and shift a bit field value for use in a register bit range. \param[in] field Name of the register bit field. - \param[in] value Value of the bit field. + \param[in] value Value of the bit field. This parameter is interpreted as an uint32_t type. \return Masked and shifted value. */ -#define _VAL2FLD(field, value) ((value << field ## _Pos) & field ## _Msk) +#define _VAL2FLD(field, value) (((uint32_t)(value) << field ## _Pos) & field ## _Msk) /** \brief Mask and shift a register value to extract a bit filed value. \param[in] field Name of the register bit field. - \param[in] value Value of register. + \param[in] value Value of register. This parameter is interpreted as an uint32_t type. \return Masked and shifted bit field value. */ -#define _FLD2VAL(field, value) ((value & field ## _Msk) >> field ## _Pos) +#define _FLD2VAL(field, value) (((uint32_t)(value) & field ## _Msk) >> field ## _Pos) /*@} end of group CMSIS_core_bitfield */ @@ -690,7 +644,7 @@ typedef struct @{ */ -/* Memory mapping of Cortex-M0+ Hardware */ +/* Memory mapping of Core Hardware */ #define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ #define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */ #define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */ @@ -700,7 +654,7 @@ typedef struct #define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */ #define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */ -#if (__MPU_PRESENT == 1U) +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) #define MPU_BASE (SCS_BASE + 0x0D90UL) /*!< Memory Protection Unit */ #define MPU ((MPU_Type *) MPU_BASE ) /*!< Memory Protection Unit */ #endif @@ -730,87 +684,177 @@ typedef struct @{ */ -/* Interrupt Priorities are WORD accessible only under ARMv6M */ +#ifdef CMSIS_NVIC_VIRTUAL + #ifndef CMSIS_NVIC_VIRTUAL_HEADER_FILE + #define CMSIS_NVIC_VIRTUAL_HEADER_FILE "cmsis_nvic_virtual.h" + #endif + #include CMSIS_NVIC_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetPriorityGrouping __NVIC_SetPriorityGrouping + #define NVIC_GetPriorityGrouping __NVIC_GetPriorityGrouping + #define NVIC_EnableIRQ __NVIC_EnableIRQ + #define NVIC_GetEnableIRQ __NVIC_GetEnableIRQ + #define NVIC_DisableIRQ __NVIC_DisableIRQ + #define NVIC_GetPendingIRQ __NVIC_GetPendingIRQ + #define NVIC_SetPendingIRQ __NVIC_SetPendingIRQ + #define NVIC_ClearPendingIRQ __NVIC_ClearPendingIRQ +/*#define NVIC_GetActive __NVIC_GetActive not available for Cortex-M0+ */ + #define NVIC_SetPriority __NVIC_SetPriority + #define NVIC_GetPriority __NVIC_GetPriority + #define NVIC_SystemReset __NVIC_SystemReset +#endif /* CMSIS_NVIC_VIRTUAL */ + +#ifdef CMSIS_VECTAB_VIRTUAL + #ifndef CMSIS_VECTAB_VIRTUAL_HEADER_FILE + #define CMSIS_VECTAB_VIRTUAL_HEADER_FILE "cmsis_vectab_virtual.h" + #endif + #include CMSIS_VECTAB_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetVector __NVIC_SetVector + #define NVIC_GetVector __NVIC_GetVector +#endif /* (CMSIS_VECTAB_VIRTUAL) */ + +#define NVIC_USER_IRQ_OFFSET 16 + + +/* The following EXC_RETURN values are saved the LR on exception entry */ +#define EXC_RETURN_HANDLER (0xFFFFFFF1UL) /* return to Handler mode, uses MSP after return */ +#define EXC_RETURN_THREAD_MSP (0xFFFFFFF9UL) /* return to Thread mode, uses MSP after return */ +#define EXC_RETURN_THREAD_PSP (0xFFFFFFFDUL) /* return to Thread mode, uses PSP after return */ + + +/* Interrupt Priorities are WORD accessible only under Armv6-M */ /* The following MACROS handle generation of the register offset and byte masks */ #define _BIT_SHIFT(IRQn) ( ((((uint32_t)(int32_t)(IRQn)) ) & 0x03UL) * 8UL) #define _SHP_IDX(IRQn) ( (((((uint32_t)(int32_t)(IRQn)) & 0x0FUL)-8UL) >> 2UL) ) #define _IP_IDX(IRQn) ( (((uint32_t)(int32_t)(IRQn)) >> 2UL) ) +#define __NVIC_SetPriorityGrouping(X) (void)(X) +#define __NVIC_GetPriorityGrouping() (0U) /** - \brief Enable External Interrupt - \details Enables a device-specific interrupt in the NVIC interrupt controller. - \param [in] IRQn External interrupt number. Value cannot be negative. + \brief Enable Interrupt + \details Enables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. */ -__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn) +__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn) { - NVIC->ISER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISER[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } } /** - \brief Disable External Interrupt - \details Disables a device-specific interrupt in the NVIC interrupt controller. - \param [in] IRQn External interrupt number. Value cannot be negative. + \brief Get Interrupt Enable status + \details Returns a device specific interrupt enable status from the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt is not enabled. + \return 1 Interrupt is enabled. + \note IRQn must not be negative. */ -__STATIC_INLINE void NVIC_DisableIRQ(IRQn_Type IRQn) +__STATIC_INLINE uint32_t __NVIC_GetEnableIRQ(IRQn_Type IRQn) { - NVIC->ICER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISER[0U] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Disable Interrupt + \details Disables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_DisableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICER[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + __DSB(); + __ISB(); + } } /** \brief Get Pending Interrupt - \details Reads the pending register in the NVIC and returns the pending bit for the specified interrupt. - \param [in] IRQn Interrupt number. + \details Reads the NVIC pending register and returns the pending bit for the specified device specific interrupt. + \param [in] IRQn Device specific interrupt number. \return 0 Interrupt status is not pending. \return 1 Interrupt status is pending. + \note IRQn must not be negative. */ -__STATIC_INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn) +__STATIC_INLINE uint32_t __NVIC_GetPendingIRQ(IRQn_Type IRQn) { - return((uint32_t)(((NVIC->ISPR[0U] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISPR[0U] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } } /** \brief Set Pending Interrupt - \details Sets the pending bit of an external interrupt. - \param [in] IRQn Interrupt number. Value cannot be negative. + \details Sets the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. */ -__STATIC_INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn) +__STATIC_INLINE void __NVIC_SetPendingIRQ(IRQn_Type IRQn) { - NVIC->ISPR[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISPR[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } } /** \brief Clear Pending Interrupt - \details Clears the pending bit of an external interrupt. - \param [in] IRQn External interrupt number. Value cannot be negative. + \details Clears the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. */ -__STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn) +__STATIC_INLINE void __NVIC_ClearPendingIRQ(IRQn_Type IRQn) { - NVIC->ICPR[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICPR[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } } /** \brief Set Interrupt Priority - \details Sets the priority of an interrupt. - \note The priority cannot be set for every core interrupt. + \details Sets the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. \param [in] IRQn Interrupt number. \param [in] priority Priority to set. + \note The priority cannot be set for every processor exception. */ -__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +__STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) { - if ((int32_t)(IRQn) < 0) + if ((int32_t)(IRQn) >= 0) { - SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); } else { - NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); } } @@ -818,24 +862,116 @@ __STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) /** \brief Get Interrupt Priority - \details Reads the priority of an interrupt. - The interrupt number can be positive to specify an external (device specific) interrupt, - or negative to specify an internal (core) interrupt. + \details Reads the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. \param [in] IRQn Interrupt number. \return Interrupt Priority. Value is aligned automatically to the implemented priority bits of the microcontroller. */ -__STATIC_INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn) +__STATIC_INLINE uint32_t __NVIC_GetPriority(IRQn_Type IRQn) { - if ((int32_t)(IRQn) < 0) - { - return((uint32_t)(((SCB->SHP[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); - } - else + if ((int32_t)(IRQn) >= 0) { return((uint32_t)(((NVIC->IP[ _IP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); } + else + { + return((uint32_t)(((SCB->SHP[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); + } +} + + +/** + \brief Encode Priority + \details Encodes the priority for an interrupt with the given priority group, + preemptive priority value, and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. + \param [in] PriorityGroup Used priority group. + \param [in] PreemptPriority Preemptive priority value (starting from 0). + \param [in] SubPriority Subpriority value (starting from 0). + \return Encoded priority. Value can be used in the function \ref NVIC_SetPriority(). + */ +__STATIC_INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + return ( + ((PreemptPriority & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL)) << SubPriorityBits) | + ((SubPriority & (uint32_t)((1UL << (SubPriorityBits )) - 1UL))) + ); +} + + +/** + \brief Decode Priority + \details Decodes an interrupt priority value with a given priority group to + preemptive priority value and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS) the smallest possible priority group is set. + \param [in] Priority Priority value, which can be retrieved with the function \ref NVIC_GetPriority(). + \param [in] PriorityGroup Used priority group. + \param [out] pPreemptPriority Preemptive priority value (starting from 0). + \param [out] pSubPriority Subpriority value (starting from 0). + */ +__STATIC_INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGroup, uint32_t* const pPreemptPriority, uint32_t* const pSubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + *pPreemptPriority = (Priority >> SubPriorityBits) & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL); + *pSubPriority = (Priority ) & (uint32_t)((1UL << (SubPriorityBits )) - 1UL); +} + + +/** + \brief Set Interrupt Vector + \details Sets an interrupt vector in SRAM based interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + VTOR must been relocated to SRAM before. + If VTOR is not present address 0 must be mapped to SRAM. + \param [in] IRQn Interrupt number + \param [in] vector Address of interrupt handler function + */ +__STATIC_INLINE void __NVIC_SetVector(IRQn_Type IRQn, uint32_t vector) +{ +#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U) + uint32_t vectors = SCB->VTOR; +#else + uint32_t vectors = 0x0U; +#endif + (* (int *) (vectors + ((int32_t)IRQn + NVIC_USER_IRQ_OFFSET) * 4)) = vector; +} + + +/** + \brief Get Interrupt Vector + \details Reads an interrupt vector from interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Address of interrupt handler function + */ +__STATIC_INLINE uint32_t __NVIC_GetVector(IRQn_Type IRQn) +{ +#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U) + uint32_t vectors = SCB->VTOR; +#else + uint32_t vectors = 0x0U; +#endif + return (uint32_t)(* (int *) (vectors + ((int32_t)IRQn + NVIC_USER_IRQ_OFFSET) * 4)); } @@ -843,7 +979,7 @@ __STATIC_INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn) \brief System Reset \details Initiates a system reset request to reset the MCU. */ -__STATIC_INLINE void NVIC_SystemReset(void) +__NO_RETURN __STATIC_INLINE void __NVIC_SystemReset(void) { __DSB(); /* Ensure all outstanding memory accesses included buffered write are completed before reset */ @@ -859,6 +995,38 @@ __STATIC_INLINE void NVIC_SystemReset(void) /*@} end of CMSIS_Core_NVICFunctions */ +/* ########################## MPU functions #################################### */ + +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + +#include "mpu_armv7.h" + +#endif + +/* ########################## FPU functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_FpuFunctions FPU Functions + \brief Function that provides FPU type. + @{ + */ + +/** + \brief get FPU type + \details returns the FPU type + \returns + - \b 0: No FPU + - \b 1: Single precision FPU + - \b 2: Double + Single precision FPU + */ +__STATIC_INLINE uint32_t SCB_GetFPUType(void) +{ + return 0U; /* No FPU */ +} + + +/*@} end of CMSIS_Core_FpuFunctions */ + /* ################################## SysTick function ############################################ */ @@ -869,7 +1037,7 @@ __STATIC_INLINE void NVIC_SystemReset(void) @{ */ -#if (__Vendor_SysTickConfig == 0U) +#if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U) /** \brief System Tick Configuration diff --git a/lib/cmsis/inc/core_cm1.h b/lib/cmsis/inc/core_cm1.h new file mode 100644 index 0000000000..72c515cb09 --- /dev/null +++ b/lib/cmsis/inc/core_cm1.h @@ -0,0 +1,976 @@ +/**************************************************************************//** + * @file core_cm1.h + * @brief CMSIS Cortex-M1 Core Peripheral Access Layer Header File + * @version V1.0.1 + * @date 12. November 2018 + ******************************************************************************/ +/* + * Copyright (c) 2009-2018 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined (__clang__) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef __CORE_CM1_H_GENERIC +#define __CORE_CM1_H_GENERIC + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/** + \page CMSIS_MISRA_Exceptions MISRA-C:2004 Compliance Exceptions + CMSIS violates the following MISRA-C:2004 rules: + + \li Required Rule 8.5, object/function definition in header file.
+ Function definitions in header files are used to allow 'inlining'. + + \li Required Rule 18.4, declaration of union type or object of union type: '{...}'.
+ Unions are used for effective representation of core registers. + + \li Advisory Rule 19.7, Function-like macro defined.
+ Function-like macros are used to allow more efficient code. + */ + + +/******************************************************************************* + * CMSIS definitions + ******************************************************************************/ +/** + \ingroup Cortex_M1 + @{ + */ + +#include "cmsis_version.h" + +/* CMSIS CM1 definitions */ +#define __CM1_CMSIS_VERSION_MAIN (__CM_CMSIS_VERSION_MAIN) /*!< \deprecated [31:16] CMSIS HAL main version */ +#define __CM1_CMSIS_VERSION_SUB (__CM_CMSIS_VERSION_SUB) /*!< \deprecated [15:0] CMSIS HAL sub version */ +#define __CM1_CMSIS_VERSION ((__CM1_CMSIS_VERSION_MAIN << 16U) | \ + __CM1_CMSIS_VERSION_SUB ) /*!< \deprecated CMSIS HAL version number */ + +#define __CORTEX_M (1U) /*!< Cortex-M Core */ + +/** __FPU_USED indicates whether an FPU is used or not. + This core does not support an FPU at all +*/ +#define __FPU_USED 0U + +#if defined ( __CC_ARM ) + #if defined __TARGET_FPU_VFP + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #if defined __ARM_FP + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __GNUC__ ) + #if defined (__VFP_FP__) && !defined(__SOFTFP__) + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __ICCARM__ ) + #if defined __ARMVFP__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __TI_ARM__ ) + #if defined __TI_VFP_SUPPORT__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __TASKING__ ) + #if defined __FPU_VFP__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __CSMC__ ) + #if ( __CSMC__ & 0x400U) + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#endif + +#include "cmsis_compiler.h" /* CMSIS compiler specific defines */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_CM1_H_GENERIC */ + +#ifndef __CMSIS_GENERIC + +#ifndef __CORE_CM1_H_DEPENDANT +#define __CORE_CM1_H_DEPENDANT + +#ifdef __cplusplus + extern "C" { +#endif + +/* check device defines and use defaults */ +#if defined __CHECK_DEVICE_DEFINES + #ifndef __CM1_REV + #define __CM1_REV 0x0100U + #warning "__CM1_REV not defined in device header file; using default!" + #endif + + #ifndef __NVIC_PRIO_BITS + #define __NVIC_PRIO_BITS 2U + #warning "__NVIC_PRIO_BITS not defined in device header file; using default!" + #endif + + #ifndef __Vendor_SysTickConfig + #define __Vendor_SysTickConfig 0U + #warning "__Vendor_SysTickConfig not defined in device header file; using default!" + #endif +#endif + +/* IO definitions (access restrictions to peripheral registers) */ +/** + \defgroup CMSIS_glob_defs CMSIS Global Defines + + IO Type Qualifiers are used + \li to specify the access to peripheral variables. + \li for automatic generation of peripheral register debug information. +*/ +#ifdef __cplusplus + #define __I volatile /*!< Defines 'read only' permissions */ +#else + #define __I volatile const /*!< Defines 'read only' permissions */ +#endif +#define __O volatile /*!< Defines 'write only' permissions */ +#define __IO volatile /*!< Defines 'read / write' permissions */ + +/* following defines should be used for structure members */ +#define __IM volatile const /*! Defines 'read only' structure member permissions */ +#define __OM volatile /*! Defines 'write only' structure member permissions */ +#define __IOM volatile /*! Defines 'read / write' structure member permissions */ + +/*@} end of group Cortex_M1 */ + + + +/******************************************************************************* + * Register Abstraction + Core Register contain: + - Core Register + - Core NVIC Register + - Core SCB Register + - Core SysTick Register + ******************************************************************************/ +/** + \defgroup CMSIS_core_register Defines and Type Definitions + \brief Type definitions and defines for Cortex-M processor based devices. +*/ + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CORE Status and Control Registers + \brief Core Register type definitions. + @{ + */ + +/** + \brief Union type to access the Application Program Status Register (APSR). + */ +typedef union +{ + struct + { + uint32_t _reserved0:28; /*!< bit: 0..27 Reserved */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} APSR_Type; + +/* APSR Register Definitions */ +#define APSR_N_Pos 31U /*!< APSR: N Position */ +#define APSR_N_Msk (1UL << APSR_N_Pos) /*!< APSR: N Mask */ + +#define APSR_Z_Pos 30U /*!< APSR: Z Position */ +#define APSR_Z_Msk (1UL << APSR_Z_Pos) /*!< APSR: Z Mask */ + +#define APSR_C_Pos 29U /*!< APSR: C Position */ +#define APSR_C_Msk (1UL << APSR_C_Pos) /*!< APSR: C Mask */ + +#define APSR_V_Pos 28U /*!< APSR: V Position */ +#define APSR_V_Msk (1UL << APSR_V_Pos) /*!< APSR: V Mask */ + + +/** + \brief Union type to access the Interrupt Program Status Register (IPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:23; /*!< bit: 9..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} IPSR_Type; + +/* IPSR Register Definitions */ +#define IPSR_ISR_Pos 0U /*!< IPSR: ISR Position */ +#define IPSR_ISR_Msk (0x1FFUL /*<< IPSR_ISR_Pos*/) /*!< IPSR: ISR Mask */ + + +/** + \brief Union type to access the Special-Purpose Program Status Registers (xPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:15; /*!< bit: 9..23 Reserved */ + uint32_t T:1; /*!< bit: 24 Thumb bit (read 0) */ + uint32_t _reserved1:3; /*!< bit: 25..27 Reserved */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} xPSR_Type; + +/* xPSR Register Definitions */ +#define xPSR_N_Pos 31U /*!< xPSR: N Position */ +#define xPSR_N_Msk (1UL << xPSR_N_Pos) /*!< xPSR: N Mask */ + +#define xPSR_Z_Pos 30U /*!< xPSR: Z Position */ +#define xPSR_Z_Msk (1UL << xPSR_Z_Pos) /*!< xPSR: Z Mask */ + +#define xPSR_C_Pos 29U /*!< xPSR: C Position */ +#define xPSR_C_Msk (1UL << xPSR_C_Pos) /*!< xPSR: C Mask */ + +#define xPSR_V_Pos 28U /*!< xPSR: V Position */ +#define xPSR_V_Msk (1UL << xPSR_V_Pos) /*!< xPSR: V Mask */ + +#define xPSR_T_Pos 24U /*!< xPSR: T Position */ +#define xPSR_T_Msk (1UL << xPSR_T_Pos) /*!< xPSR: T Mask */ + +#define xPSR_ISR_Pos 0U /*!< xPSR: ISR Position */ +#define xPSR_ISR_Msk (0x1FFUL /*<< xPSR_ISR_Pos*/) /*!< xPSR: ISR Mask */ + + +/** + \brief Union type to access the Control Registers (CONTROL). + */ +typedef union +{ + struct + { + uint32_t _reserved0:1; /*!< bit: 0 Reserved */ + uint32_t SPSEL:1; /*!< bit: 1 Stack to be used */ + uint32_t _reserved1:30; /*!< bit: 2..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} CONTROL_Type; + +/* CONTROL Register Definitions */ +#define CONTROL_SPSEL_Pos 1U /*!< CONTROL: SPSEL Position */ +#define CONTROL_SPSEL_Msk (1UL << CONTROL_SPSEL_Pos) /*!< CONTROL: SPSEL Mask */ + +/*@} end of group CMSIS_CORE */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_NVIC Nested Vectored Interrupt Controller (NVIC) + \brief Type definitions for the NVIC Registers + @{ + */ + +/** + \brief Structure type to access the Nested Vectored Interrupt Controller (NVIC). + */ +typedef struct +{ + __IOM uint32_t ISER[1U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ + uint32_t RESERVED0[31U]; + __IOM uint32_t ICER[1U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ + uint32_t RSERVED1[31U]; + __IOM uint32_t ISPR[1U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ + uint32_t RESERVED2[31U]; + __IOM uint32_t ICPR[1U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ + uint32_t RESERVED3[31U]; + uint32_t RESERVED4[64U]; + __IOM uint32_t IP[8U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register */ +} NVIC_Type; + +/*@} end of group CMSIS_NVIC */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SCB System Control Block (SCB) + \brief Type definitions for the System Control Block Registers + @{ + */ + +/** + \brief Structure type to access the System Control Block (SCB). + */ +typedef struct +{ + __IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */ + __IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */ + uint32_t RESERVED0; + __IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */ + __IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */ + __IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */ + uint32_t RESERVED1; + __IOM uint32_t SHP[2U]; /*!< Offset: 0x01C (R/W) System Handlers Priority Registers. [0] is RESERVED */ + __IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */ +} SCB_Type; + +/* SCB CPUID Register Definitions */ +#define SCB_CPUID_IMPLEMENTER_Pos 24U /*!< SCB CPUID: IMPLEMENTER Position */ +#define SCB_CPUID_IMPLEMENTER_Msk (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos) /*!< SCB CPUID: IMPLEMENTER Mask */ + +#define SCB_CPUID_VARIANT_Pos 20U /*!< SCB CPUID: VARIANT Position */ +#define SCB_CPUID_VARIANT_Msk (0xFUL << SCB_CPUID_VARIANT_Pos) /*!< SCB CPUID: VARIANT Mask */ + +#define SCB_CPUID_ARCHITECTURE_Pos 16U /*!< SCB CPUID: ARCHITECTURE Position */ +#define SCB_CPUID_ARCHITECTURE_Msk (0xFUL << SCB_CPUID_ARCHITECTURE_Pos) /*!< SCB CPUID: ARCHITECTURE Mask */ + +#define SCB_CPUID_PARTNO_Pos 4U /*!< SCB CPUID: PARTNO Position */ +#define SCB_CPUID_PARTNO_Msk (0xFFFUL << SCB_CPUID_PARTNO_Pos) /*!< SCB CPUID: PARTNO Mask */ + +#define SCB_CPUID_REVISION_Pos 0U /*!< SCB CPUID: REVISION Position */ +#define SCB_CPUID_REVISION_Msk (0xFUL /*<< SCB_CPUID_REVISION_Pos*/) /*!< SCB CPUID: REVISION Mask */ + +/* SCB Interrupt Control State Register Definitions */ +#define SCB_ICSR_NMIPENDSET_Pos 31U /*!< SCB ICSR: NMIPENDSET Position */ +#define SCB_ICSR_NMIPENDSET_Msk (1UL << SCB_ICSR_NMIPENDSET_Pos) /*!< SCB ICSR: NMIPENDSET Mask */ + +#define SCB_ICSR_PENDSVSET_Pos 28U /*!< SCB ICSR: PENDSVSET Position */ +#define SCB_ICSR_PENDSVSET_Msk (1UL << SCB_ICSR_PENDSVSET_Pos) /*!< SCB ICSR: PENDSVSET Mask */ + +#define SCB_ICSR_PENDSVCLR_Pos 27U /*!< SCB ICSR: PENDSVCLR Position */ +#define SCB_ICSR_PENDSVCLR_Msk (1UL << SCB_ICSR_PENDSVCLR_Pos) /*!< SCB ICSR: PENDSVCLR Mask */ + +#define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */ +#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */ + +#define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */ +#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */ + +#define SCB_ICSR_ISRPREEMPT_Pos 23U /*!< SCB ICSR: ISRPREEMPT Position */ +#define SCB_ICSR_ISRPREEMPT_Msk (1UL << SCB_ICSR_ISRPREEMPT_Pos) /*!< SCB ICSR: ISRPREEMPT Mask */ + +#define SCB_ICSR_ISRPENDING_Pos 22U /*!< SCB ICSR: ISRPENDING Position */ +#define SCB_ICSR_ISRPENDING_Msk (1UL << SCB_ICSR_ISRPENDING_Pos) /*!< SCB ICSR: ISRPENDING Mask */ + +#define SCB_ICSR_VECTPENDING_Pos 12U /*!< SCB ICSR: VECTPENDING Position */ +#define SCB_ICSR_VECTPENDING_Msk (0x1FFUL << SCB_ICSR_VECTPENDING_Pos) /*!< SCB ICSR: VECTPENDING Mask */ + +#define SCB_ICSR_VECTACTIVE_Pos 0U /*!< SCB ICSR: VECTACTIVE Position */ +#define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL /*<< SCB_ICSR_VECTACTIVE_Pos*/) /*!< SCB ICSR: VECTACTIVE Mask */ + +/* SCB Application Interrupt and Reset Control Register Definitions */ +#define SCB_AIRCR_VECTKEY_Pos 16U /*!< SCB AIRCR: VECTKEY Position */ +#define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */ + +#define SCB_AIRCR_VECTKEYSTAT_Pos 16U /*!< SCB AIRCR: VECTKEYSTAT Position */ +#define SCB_AIRCR_VECTKEYSTAT_Msk (0xFFFFUL << SCB_AIRCR_VECTKEYSTAT_Pos) /*!< SCB AIRCR: VECTKEYSTAT Mask */ + +#define SCB_AIRCR_ENDIANESS_Pos 15U /*!< SCB AIRCR: ENDIANESS Position */ +#define SCB_AIRCR_ENDIANESS_Msk (1UL << SCB_AIRCR_ENDIANESS_Pos) /*!< SCB AIRCR: ENDIANESS Mask */ + +#define SCB_AIRCR_SYSRESETREQ_Pos 2U /*!< SCB AIRCR: SYSRESETREQ Position */ +#define SCB_AIRCR_SYSRESETREQ_Msk (1UL << SCB_AIRCR_SYSRESETREQ_Pos) /*!< SCB AIRCR: SYSRESETREQ Mask */ + +#define SCB_AIRCR_VECTCLRACTIVE_Pos 1U /*!< SCB AIRCR: VECTCLRACTIVE Position */ +#define SCB_AIRCR_VECTCLRACTIVE_Msk (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos) /*!< SCB AIRCR: VECTCLRACTIVE Mask */ + +/* SCB System Control Register Definitions */ +#define SCB_SCR_SEVONPEND_Pos 4U /*!< SCB SCR: SEVONPEND Position */ +#define SCB_SCR_SEVONPEND_Msk (1UL << SCB_SCR_SEVONPEND_Pos) /*!< SCB SCR: SEVONPEND Mask */ + +#define SCB_SCR_SLEEPDEEP_Pos 2U /*!< SCB SCR: SLEEPDEEP Position */ +#define SCB_SCR_SLEEPDEEP_Msk (1UL << SCB_SCR_SLEEPDEEP_Pos) /*!< SCB SCR: SLEEPDEEP Mask */ + +#define SCB_SCR_SLEEPONEXIT_Pos 1U /*!< SCB SCR: SLEEPONEXIT Position */ +#define SCB_SCR_SLEEPONEXIT_Msk (1UL << SCB_SCR_SLEEPONEXIT_Pos) /*!< SCB SCR: SLEEPONEXIT Mask */ + +/* SCB Configuration Control Register Definitions */ +#define SCB_CCR_STKALIGN_Pos 9U /*!< SCB CCR: STKALIGN Position */ +#define SCB_CCR_STKALIGN_Msk (1UL << SCB_CCR_STKALIGN_Pos) /*!< SCB CCR: STKALIGN Mask */ + +#define SCB_CCR_UNALIGN_TRP_Pos 3U /*!< SCB CCR: UNALIGN_TRP Position */ +#define SCB_CCR_UNALIGN_TRP_Msk (1UL << SCB_CCR_UNALIGN_TRP_Pos) /*!< SCB CCR: UNALIGN_TRP Mask */ + +/* SCB System Handler Control and State Register Definitions */ +#define SCB_SHCSR_SVCALLPENDED_Pos 15U /*!< SCB SHCSR: SVCALLPENDED Position */ +#define SCB_SHCSR_SVCALLPENDED_Msk (1UL << SCB_SHCSR_SVCALLPENDED_Pos) /*!< SCB SHCSR: SVCALLPENDED Mask */ + +/*@} end of group CMSIS_SCB */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SCnSCB System Controls not in SCB (SCnSCB) + \brief Type definitions for the System Control and ID Register not in the SCB + @{ + */ + +/** + \brief Structure type to access the System Control and ID Register not in the SCB. + */ +typedef struct +{ + uint32_t RESERVED0[2U]; + __IOM uint32_t ACTLR; /*!< Offset: 0x008 (R/W) Auxiliary Control Register */ +} SCnSCB_Type; + +/* Auxiliary Control Register Definitions */ +#define SCnSCB_ACTLR_ITCMUAEN_Pos 4U /*!< ACTLR: Instruction TCM Upper Alias Enable Position */ +#define SCnSCB_ACTLR_ITCMUAEN_Msk (1UL << SCnSCB_ACTLR_ITCMUAEN_Pos) /*!< ACTLR: Instruction TCM Upper Alias Enable Mask */ + +#define SCnSCB_ACTLR_ITCMLAEN_Pos 3U /*!< ACTLR: Instruction TCM Lower Alias Enable Position */ +#define SCnSCB_ACTLR_ITCMLAEN_Msk (1UL << SCnSCB_ACTLR_ITCMLAEN_Pos) /*!< ACTLR: Instruction TCM Lower Alias Enable Mask */ + +/*@} end of group CMSIS_SCnotSCB */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SysTick System Tick Timer (SysTick) + \brief Type definitions for the System Timer Registers. + @{ + */ + +/** + \brief Structure type to access the System Timer (SysTick). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */ + __IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */ + __IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */ + __IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */ +} SysTick_Type; + +/* SysTick Control / Status Register Definitions */ +#define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */ +#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */ + +#define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */ +#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */ + +#define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */ +#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */ + +#define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */ +#define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */ + +/* SysTick Reload Register Definitions */ +#define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */ +#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */ + +/* SysTick Current Register Definitions */ +#define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */ +#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */ + +/* SysTick Calibration Register Definitions */ +#define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */ +#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */ + +#define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */ +#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */ + +#define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */ +#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */ + +/*@} end of group CMSIS_SysTick */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CoreDebug Core Debug Registers (CoreDebug) + \brief Cortex-M1 Core Debug Registers (DCB registers, SHCSR, and DFSR) are only accessible over DAP and not via processor. + Therefore they are not covered by the Cortex-M1 header file. + @{ + */ +/*@} end of group CMSIS_CoreDebug */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_bitfield Core register bit field macros + \brief Macros for use with bit field definitions (xxx_Pos, xxx_Msk). + @{ + */ + +/** + \brief Mask and shift a bit field value for use in a register bit range. + \param[in] field Name of the register bit field. + \param[in] value Value of the bit field. This parameter is interpreted as an uint32_t type. + \return Masked and shifted value. +*/ +#define _VAL2FLD(field, value) (((uint32_t)(value) << field ## _Pos) & field ## _Msk) + +/** + \brief Mask and shift a register value to extract a bit filed value. + \param[in] field Name of the register bit field. + \param[in] value Value of register. This parameter is interpreted as an uint32_t type. + \return Masked and shifted bit field value. +*/ +#define _FLD2VAL(field, value) (((uint32_t)(value) & field ## _Msk) >> field ## _Pos) + +/*@} end of group CMSIS_core_bitfield */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_base Core Definitions + \brief Definitions for base addresses, unions, and structures. + @{ + */ + +/* Memory mapping of Core Hardware */ +#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ +#define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */ +#define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */ +#define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */ + +#define SCnSCB ((SCnSCB_Type *) SCS_BASE ) /*!< System control Register not in SCB */ +#define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */ +#define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */ +#define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */ + + +/*@} */ + + + +/******************************************************************************* + * Hardware Abstraction Layer + Core Function Interface contains: + - Core NVIC Functions + - Core SysTick Functions + - Core Register Access Functions + ******************************************************************************/ +/** + \defgroup CMSIS_Core_FunctionInterface Functions and Instructions Reference +*/ + + + +/* ########################## NVIC functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_NVICFunctions NVIC Functions + \brief Functions that manage interrupts and exceptions via the NVIC. + @{ + */ + +#ifdef CMSIS_NVIC_VIRTUAL + #ifndef CMSIS_NVIC_VIRTUAL_HEADER_FILE + #define CMSIS_NVIC_VIRTUAL_HEADER_FILE "cmsis_nvic_virtual.h" + #endif + #include CMSIS_NVIC_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetPriorityGrouping __NVIC_SetPriorityGrouping + #define NVIC_GetPriorityGrouping __NVIC_GetPriorityGrouping + #define NVIC_EnableIRQ __NVIC_EnableIRQ + #define NVIC_GetEnableIRQ __NVIC_GetEnableIRQ + #define NVIC_DisableIRQ __NVIC_DisableIRQ + #define NVIC_GetPendingIRQ __NVIC_GetPendingIRQ + #define NVIC_SetPendingIRQ __NVIC_SetPendingIRQ + #define NVIC_ClearPendingIRQ __NVIC_ClearPendingIRQ +/*#define NVIC_GetActive __NVIC_GetActive not available for Cortex-M1 */ + #define NVIC_SetPriority __NVIC_SetPriority + #define NVIC_GetPriority __NVIC_GetPriority + #define NVIC_SystemReset __NVIC_SystemReset +#endif /* CMSIS_NVIC_VIRTUAL */ + +#ifdef CMSIS_VECTAB_VIRTUAL + #ifndef CMSIS_VECTAB_VIRTUAL_HEADER_FILE + #define CMSIS_VECTAB_VIRTUAL_HEADER_FILE "cmsis_vectab_virtual.h" + #endif + #include CMSIS_VECTAB_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetVector __NVIC_SetVector + #define NVIC_GetVector __NVIC_GetVector +#endif /* (CMSIS_VECTAB_VIRTUAL) */ + +#define NVIC_USER_IRQ_OFFSET 16 + + +/* The following EXC_RETURN values are saved the LR on exception entry */ +#define EXC_RETURN_HANDLER (0xFFFFFFF1UL) /* return to Handler mode, uses MSP after return */ +#define EXC_RETURN_THREAD_MSP (0xFFFFFFF9UL) /* return to Thread mode, uses MSP after return */ +#define EXC_RETURN_THREAD_PSP (0xFFFFFFFDUL) /* return to Thread mode, uses PSP after return */ + + +/* Interrupt Priorities are WORD accessible only under Armv6-M */ +/* The following MACROS handle generation of the register offset and byte masks */ +#define _BIT_SHIFT(IRQn) ( ((((uint32_t)(int32_t)(IRQn)) ) & 0x03UL) * 8UL) +#define _SHP_IDX(IRQn) ( (((((uint32_t)(int32_t)(IRQn)) & 0x0FUL)-8UL) >> 2UL) ) +#define _IP_IDX(IRQn) ( (((uint32_t)(int32_t)(IRQn)) >> 2UL) ) + +#define __NVIC_SetPriorityGrouping(X) (void)(X) +#define __NVIC_GetPriorityGrouping() (0U) + +/** + \brief Enable Interrupt + \details Enables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISER[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Interrupt Enable status + \details Returns a device specific interrupt enable status from the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt is not enabled. + \return 1 Interrupt is enabled. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t __NVIC_GetEnableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISER[0U] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Disable Interrupt + \details Disables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_DisableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICER[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + __DSB(); + __ISB(); + } +} + + +/** + \brief Get Pending Interrupt + \details Reads the NVIC pending register and returns the pending bit for the specified device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt status is not pending. + \return 1 Interrupt status is pending. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t __NVIC_GetPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISPR[0U] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Set Pending Interrupt + \details Sets the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_SetPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISPR[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Clear Pending Interrupt + \details Clears the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_ClearPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICPR[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Set Interrupt Priority + \details Sets the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \param [in] priority Priority to set. + \note The priority cannot be set for every processor exception. + */ +__STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); + } + else + { + SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); + } +} + + +/** + \brief Get Interrupt Priority + \details Reads the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Interrupt Priority. + Value is aligned automatically to the implemented priority bits of the microcontroller. + */ +__STATIC_INLINE uint32_t __NVIC_GetPriority(IRQn_Type IRQn) +{ + + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->IP[ _IP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); + } + else + { + return((uint32_t)(((SCB->SHP[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); + } +} + + +/** + \brief Encode Priority + \details Encodes the priority for an interrupt with the given priority group, + preemptive priority value, and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. + \param [in] PriorityGroup Used priority group. + \param [in] PreemptPriority Preemptive priority value (starting from 0). + \param [in] SubPriority Subpriority value (starting from 0). + \return Encoded priority. Value can be used in the function \ref NVIC_SetPriority(). + */ +__STATIC_INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + return ( + ((PreemptPriority & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL)) << SubPriorityBits) | + ((SubPriority & (uint32_t)((1UL << (SubPriorityBits )) - 1UL))) + ); +} + + +/** + \brief Decode Priority + \details Decodes an interrupt priority value with a given priority group to + preemptive priority value and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS) the smallest possible priority group is set. + \param [in] Priority Priority value, which can be retrieved with the function \ref NVIC_GetPriority(). + \param [in] PriorityGroup Used priority group. + \param [out] pPreemptPriority Preemptive priority value (starting from 0). + \param [out] pSubPriority Subpriority value (starting from 0). + */ +__STATIC_INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGroup, uint32_t* const pPreemptPriority, uint32_t* const pSubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + *pPreemptPriority = (Priority >> SubPriorityBits) & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL); + *pSubPriority = (Priority ) & (uint32_t)((1UL << (SubPriorityBits )) - 1UL); +} + + + +/** + \brief Set Interrupt Vector + \details Sets an interrupt vector in SRAM based interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + Address 0 must be mapped to SRAM. + \param [in] IRQn Interrupt number + \param [in] vector Address of interrupt handler function + */ +__STATIC_INLINE void __NVIC_SetVector(IRQn_Type IRQn, uint32_t vector) +{ + uint32_t *vectors = (uint32_t *)0x0U; + vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET] = vector; +} + + +/** + \brief Get Interrupt Vector + \details Reads an interrupt vector from interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Address of interrupt handler function + */ +__STATIC_INLINE uint32_t __NVIC_GetVector(IRQn_Type IRQn) +{ + uint32_t *vectors = (uint32_t *)0x0U; + return vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET]; +} + + +/** + \brief System Reset + \details Initiates a system reset request to reset the MCU. + */ +__NO_RETURN __STATIC_INLINE void __NVIC_SystemReset(void) +{ + __DSB(); /* Ensure all outstanding memory accesses included + buffered write are completed before reset */ + SCB->AIRCR = ((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + SCB_AIRCR_SYSRESETREQ_Msk); + __DSB(); /* Ensure completion of memory access */ + + for(;;) /* wait until reset */ + { + __NOP(); + } +} + +/*@} end of CMSIS_Core_NVICFunctions */ + + +/* ########################## FPU functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_FpuFunctions FPU Functions + \brief Function that provides FPU type. + @{ + */ + +/** + \brief get FPU type + \details returns the FPU type + \returns + - \b 0: No FPU + - \b 1: Single precision FPU + - \b 2: Double + Single precision FPU + */ +__STATIC_INLINE uint32_t SCB_GetFPUType(void) +{ + return 0U; /* No FPU */ +} + + +/*@} end of CMSIS_Core_FpuFunctions */ + + + +/* ################################## SysTick function ############################################ */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_SysTickFunctions SysTick Functions + \brief Functions that configure the System. + @{ + */ + +#if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U) + +/** + \brief System Tick Configuration + \details Initializes the System Timer and its interrupt, and starts the System Tick Timer. + Counter is in free running mode to generate periodic interrupts. + \param [in] ticks Number of ticks between two interrupts. + \return 0 Function succeeded. + \return 1 Function failed. + \note When the variable __Vendor_SysTickConfig is set to 1, then the + function SysTick_Config is not included. In this case, the file device.h + must contain a vendor-specific implementation of this function. + */ +__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) +{ + if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) + { + return (1UL); /* Reload value impossible */ + } + + SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ + NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ + SysTick->VAL = 0UL; /* Load the SysTick Counter Value */ + SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + SysTick_CTRL_TICKINT_Msk | + SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ + return (0UL); /* Function successful */ +} + +#endif + +/*@} end of CMSIS_Core_SysTickFunctions */ + + + + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_CM1_H_DEPENDANT */ + +#endif /* __CMSIS_GENERIC */ diff --git a/lib/cmsis/inc/core_cm23.h b/lib/cmsis/inc/core_cm23.h new file mode 100644 index 0000000000..26fe163a0e --- /dev/null +++ b/lib/cmsis/inc/core_cm23.h @@ -0,0 +1,1993 @@ +/**************************************************************************//** + * @file core_cm23.h + * @brief CMSIS Cortex-M23 Core Peripheral Access Layer Header File + * @version V5.0.8 + * @date 12. November 2018 + ******************************************************************************/ +/* + * Copyright (c) 2009-2018 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined (__clang__) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef __CORE_CM23_H_GENERIC +#define __CORE_CM23_H_GENERIC + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/** + \page CMSIS_MISRA_Exceptions MISRA-C:2004 Compliance Exceptions + CMSIS violates the following MISRA-C:2004 rules: + + \li Required Rule 8.5, object/function definition in header file.
+ Function definitions in header files are used to allow 'inlining'. + + \li Required Rule 18.4, declaration of union type or object of union type: '{...}'.
+ Unions are used for effective representation of core registers. + + \li Advisory Rule 19.7, Function-like macro defined.
+ Function-like macros are used to allow more efficient code. + */ + + +/******************************************************************************* + * CMSIS definitions + ******************************************************************************/ +/** + \ingroup Cortex_M23 + @{ + */ + +#include "cmsis_version.h" + +/* CMSIS definitions */ +#define __CM23_CMSIS_VERSION_MAIN (__CM_CMSIS_VERSION_MAIN) /*!< \deprecated [31:16] CMSIS HAL main version */ +#define __CM23_CMSIS_VERSION_SUB (__CM_CMSIS_VERSION_SUB) /*!< \deprecated [15:0] CMSIS HAL sub version */ +#define __CM23_CMSIS_VERSION ((__CM23_CMSIS_VERSION_MAIN << 16U) | \ + __CM23_CMSIS_VERSION_SUB ) /*!< \deprecated CMSIS HAL version number */ + +#define __CORTEX_M (23U) /*!< Cortex-M Core */ + +/** __FPU_USED indicates whether an FPU is used or not. + This core does not support an FPU at all +*/ +#define __FPU_USED 0U + +#if defined ( __CC_ARM ) + #if defined __TARGET_FPU_VFP + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #if defined __ARM_FP + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __GNUC__ ) + #if defined (__VFP_FP__) && !defined(__SOFTFP__) + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __ICCARM__ ) + #if defined __ARMVFP__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __TI_ARM__ ) + #if defined __TI_VFP_SUPPORT__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __TASKING__ ) + #if defined __FPU_VFP__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __CSMC__ ) + #if ( __CSMC__ & 0x400U) + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#endif + +#include "cmsis_compiler.h" /* CMSIS compiler specific defines */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_CM23_H_GENERIC */ + +#ifndef __CMSIS_GENERIC + +#ifndef __CORE_CM23_H_DEPENDANT +#define __CORE_CM23_H_DEPENDANT + +#ifdef __cplusplus + extern "C" { +#endif + +/* check device defines and use defaults */ +#if defined __CHECK_DEVICE_DEFINES + #ifndef __CM23_REV + #define __CM23_REV 0x0000U + #warning "__CM23_REV not defined in device header file; using default!" + #endif + + #ifndef __FPU_PRESENT + #define __FPU_PRESENT 0U + #warning "__FPU_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __MPU_PRESENT + #define __MPU_PRESENT 0U + #warning "__MPU_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __SAUREGION_PRESENT + #define __SAUREGION_PRESENT 0U + #warning "__SAUREGION_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __VTOR_PRESENT + #define __VTOR_PRESENT 0U + #warning "__VTOR_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __NVIC_PRIO_BITS + #define __NVIC_PRIO_BITS 2U + #warning "__NVIC_PRIO_BITS not defined in device header file; using default!" + #endif + + #ifndef __Vendor_SysTickConfig + #define __Vendor_SysTickConfig 0U + #warning "__Vendor_SysTickConfig not defined in device header file; using default!" + #endif + + #ifndef __ETM_PRESENT + #define __ETM_PRESENT 0U + #warning "__ETM_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __MTB_PRESENT + #define __MTB_PRESENT 0U + #warning "__MTB_PRESENT not defined in device header file; using default!" + #endif + +#endif + +/* IO definitions (access restrictions to peripheral registers) */ +/** + \defgroup CMSIS_glob_defs CMSIS Global Defines + + IO Type Qualifiers are used + \li to specify the access to peripheral variables. + \li for automatic generation of peripheral register debug information. +*/ +#ifdef __cplusplus + #define __I volatile /*!< Defines 'read only' permissions */ +#else + #define __I volatile const /*!< Defines 'read only' permissions */ +#endif +#define __O volatile /*!< Defines 'write only' permissions */ +#define __IO volatile /*!< Defines 'read / write' permissions */ + +/* following defines should be used for structure members */ +#define __IM volatile const /*! Defines 'read only' structure member permissions */ +#define __OM volatile /*! Defines 'write only' structure member permissions */ +#define __IOM volatile /*! Defines 'read / write' structure member permissions */ + +/*@} end of group Cortex_M23 */ + + + +/******************************************************************************* + * Register Abstraction + Core Register contain: + - Core Register + - Core NVIC Register + - Core SCB Register + - Core SysTick Register + - Core Debug Register + - Core MPU Register + - Core SAU Register + ******************************************************************************/ +/** + \defgroup CMSIS_core_register Defines and Type Definitions + \brief Type definitions and defines for Cortex-M processor based devices. +*/ + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CORE Status and Control Registers + \brief Core Register type definitions. + @{ + */ + +/** + \brief Union type to access the Application Program Status Register (APSR). + */ +typedef union +{ + struct + { + uint32_t _reserved0:28; /*!< bit: 0..27 Reserved */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} APSR_Type; + +/* APSR Register Definitions */ +#define APSR_N_Pos 31U /*!< APSR: N Position */ +#define APSR_N_Msk (1UL << APSR_N_Pos) /*!< APSR: N Mask */ + +#define APSR_Z_Pos 30U /*!< APSR: Z Position */ +#define APSR_Z_Msk (1UL << APSR_Z_Pos) /*!< APSR: Z Mask */ + +#define APSR_C_Pos 29U /*!< APSR: C Position */ +#define APSR_C_Msk (1UL << APSR_C_Pos) /*!< APSR: C Mask */ + +#define APSR_V_Pos 28U /*!< APSR: V Position */ +#define APSR_V_Msk (1UL << APSR_V_Pos) /*!< APSR: V Mask */ + + +/** + \brief Union type to access the Interrupt Program Status Register (IPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:23; /*!< bit: 9..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} IPSR_Type; + +/* IPSR Register Definitions */ +#define IPSR_ISR_Pos 0U /*!< IPSR: ISR Position */ +#define IPSR_ISR_Msk (0x1FFUL /*<< IPSR_ISR_Pos*/) /*!< IPSR: ISR Mask */ + + +/** + \brief Union type to access the Special-Purpose Program Status Registers (xPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:15; /*!< bit: 9..23 Reserved */ + uint32_t T:1; /*!< bit: 24 Thumb bit (read 0) */ + uint32_t _reserved1:3; /*!< bit: 25..27 Reserved */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} xPSR_Type; + +/* xPSR Register Definitions */ +#define xPSR_N_Pos 31U /*!< xPSR: N Position */ +#define xPSR_N_Msk (1UL << xPSR_N_Pos) /*!< xPSR: N Mask */ + +#define xPSR_Z_Pos 30U /*!< xPSR: Z Position */ +#define xPSR_Z_Msk (1UL << xPSR_Z_Pos) /*!< xPSR: Z Mask */ + +#define xPSR_C_Pos 29U /*!< xPSR: C Position */ +#define xPSR_C_Msk (1UL << xPSR_C_Pos) /*!< xPSR: C Mask */ + +#define xPSR_V_Pos 28U /*!< xPSR: V Position */ +#define xPSR_V_Msk (1UL << xPSR_V_Pos) /*!< xPSR: V Mask */ + +#define xPSR_T_Pos 24U /*!< xPSR: T Position */ +#define xPSR_T_Msk (1UL << xPSR_T_Pos) /*!< xPSR: T Mask */ + +#define xPSR_ISR_Pos 0U /*!< xPSR: ISR Position */ +#define xPSR_ISR_Msk (0x1FFUL /*<< xPSR_ISR_Pos*/) /*!< xPSR: ISR Mask */ + + +/** + \brief Union type to access the Control Registers (CONTROL). + */ +typedef union +{ + struct + { + uint32_t nPRIV:1; /*!< bit: 0 Execution privilege in Thread mode */ + uint32_t SPSEL:1; /*!< bit: 1 Stack-pointer select */ + uint32_t _reserved1:30; /*!< bit: 2..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} CONTROL_Type; + +/* CONTROL Register Definitions */ +#define CONTROL_SPSEL_Pos 1U /*!< CONTROL: SPSEL Position */ +#define CONTROL_SPSEL_Msk (1UL << CONTROL_SPSEL_Pos) /*!< CONTROL: SPSEL Mask */ + +#define CONTROL_nPRIV_Pos 0U /*!< CONTROL: nPRIV Position */ +#define CONTROL_nPRIV_Msk (1UL /*<< CONTROL_nPRIV_Pos*/) /*!< CONTROL: nPRIV Mask */ + +/*@} end of group CMSIS_CORE */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_NVIC Nested Vectored Interrupt Controller (NVIC) + \brief Type definitions for the NVIC Registers + @{ + */ + +/** + \brief Structure type to access the Nested Vectored Interrupt Controller (NVIC). + */ +typedef struct +{ + __IOM uint32_t ISER[16U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ + uint32_t RESERVED0[16U]; + __IOM uint32_t ICER[16U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ + uint32_t RSERVED1[16U]; + __IOM uint32_t ISPR[16U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ + uint32_t RESERVED2[16U]; + __IOM uint32_t ICPR[16U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ + uint32_t RESERVED3[16U]; + __IOM uint32_t IABR[16U]; /*!< Offset: 0x200 (R/W) Interrupt Active bit Register */ + uint32_t RESERVED4[16U]; + __IOM uint32_t ITNS[16U]; /*!< Offset: 0x280 (R/W) Interrupt Non-Secure State Register */ + uint32_t RESERVED5[16U]; + __IOM uint32_t IPR[124U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register */ +} NVIC_Type; + +/*@} end of group CMSIS_NVIC */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SCB System Control Block (SCB) + \brief Type definitions for the System Control Block Registers + @{ + */ + +/** + \brief Structure type to access the System Control Block (SCB). + */ +typedef struct +{ + __IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */ + __IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */ +#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U) + __IOM uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */ +#else + uint32_t RESERVED0; +#endif + __IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */ + __IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */ + __IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */ + uint32_t RESERVED1; + __IOM uint32_t SHPR[2U]; /*!< Offset: 0x01C (R/W) System Handlers Priority Registers. [0] is RESERVED */ + __IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */ +} SCB_Type; + +/* SCB CPUID Register Definitions */ +#define SCB_CPUID_IMPLEMENTER_Pos 24U /*!< SCB CPUID: IMPLEMENTER Position */ +#define SCB_CPUID_IMPLEMENTER_Msk (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos) /*!< SCB CPUID: IMPLEMENTER Mask */ + +#define SCB_CPUID_VARIANT_Pos 20U /*!< SCB CPUID: VARIANT Position */ +#define SCB_CPUID_VARIANT_Msk (0xFUL << SCB_CPUID_VARIANT_Pos) /*!< SCB CPUID: VARIANT Mask */ + +#define SCB_CPUID_ARCHITECTURE_Pos 16U /*!< SCB CPUID: ARCHITECTURE Position */ +#define SCB_CPUID_ARCHITECTURE_Msk (0xFUL << SCB_CPUID_ARCHITECTURE_Pos) /*!< SCB CPUID: ARCHITECTURE Mask */ + +#define SCB_CPUID_PARTNO_Pos 4U /*!< SCB CPUID: PARTNO Position */ +#define SCB_CPUID_PARTNO_Msk (0xFFFUL << SCB_CPUID_PARTNO_Pos) /*!< SCB CPUID: PARTNO Mask */ + +#define SCB_CPUID_REVISION_Pos 0U /*!< SCB CPUID: REVISION Position */ +#define SCB_CPUID_REVISION_Msk (0xFUL /*<< SCB_CPUID_REVISION_Pos*/) /*!< SCB CPUID: REVISION Mask */ + +/* SCB Interrupt Control State Register Definitions */ +#define SCB_ICSR_PENDNMISET_Pos 31U /*!< SCB ICSR: PENDNMISET Position */ +#define SCB_ICSR_PENDNMISET_Msk (1UL << SCB_ICSR_PENDNMISET_Pos) /*!< SCB ICSR: PENDNMISET Mask */ + +#define SCB_ICSR_NMIPENDSET_Pos SCB_ICSR_PENDNMISET_Pos /*!< SCB ICSR: NMIPENDSET Position, backward compatibility */ +#define SCB_ICSR_NMIPENDSET_Msk SCB_ICSR_PENDNMISET_Msk /*!< SCB ICSR: NMIPENDSET Mask, backward compatibility */ + +#define SCB_ICSR_PENDNMICLR_Pos 30U /*!< SCB ICSR: PENDNMICLR Position */ +#define SCB_ICSR_PENDNMICLR_Msk (1UL << SCB_ICSR_PENDNMICLR_Pos) /*!< SCB ICSR: PENDNMICLR Mask */ + +#define SCB_ICSR_PENDSVSET_Pos 28U /*!< SCB ICSR: PENDSVSET Position */ +#define SCB_ICSR_PENDSVSET_Msk (1UL << SCB_ICSR_PENDSVSET_Pos) /*!< SCB ICSR: PENDSVSET Mask */ + +#define SCB_ICSR_PENDSVCLR_Pos 27U /*!< SCB ICSR: PENDSVCLR Position */ +#define SCB_ICSR_PENDSVCLR_Msk (1UL << SCB_ICSR_PENDSVCLR_Pos) /*!< SCB ICSR: PENDSVCLR Mask */ + +#define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */ +#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */ + +#define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */ +#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */ + +#define SCB_ICSR_STTNS_Pos 24U /*!< SCB ICSR: STTNS Position (Security Extension) */ +#define SCB_ICSR_STTNS_Msk (1UL << SCB_ICSR_STTNS_Pos) /*!< SCB ICSR: STTNS Mask (Security Extension) */ + +#define SCB_ICSR_ISRPREEMPT_Pos 23U /*!< SCB ICSR: ISRPREEMPT Position */ +#define SCB_ICSR_ISRPREEMPT_Msk (1UL << SCB_ICSR_ISRPREEMPT_Pos) /*!< SCB ICSR: ISRPREEMPT Mask */ + +#define SCB_ICSR_ISRPENDING_Pos 22U /*!< SCB ICSR: ISRPENDING Position */ +#define SCB_ICSR_ISRPENDING_Msk (1UL << SCB_ICSR_ISRPENDING_Pos) /*!< SCB ICSR: ISRPENDING Mask */ + +#define SCB_ICSR_VECTPENDING_Pos 12U /*!< SCB ICSR: VECTPENDING Position */ +#define SCB_ICSR_VECTPENDING_Msk (0x1FFUL << SCB_ICSR_VECTPENDING_Pos) /*!< SCB ICSR: VECTPENDING Mask */ + +#define SCB_ICSR_RETTOBASE_Pos 11U /*!< SCB ICSR: RETTOBASE Position */ +#define SCB_ICSR_RETTOBASE_Msk (1UL << SCB_ICSR_RETTOBASE_Pos) /*!< SCB ICSR: RETTOBASE Mask */ + +#define SCB_ICSR_VECTACTIVE_Pos 0U /*!< SCB ICSR: VECTACTIVE Position */ +#define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL /*<< SCB_ICSR_VECTACTIVE_Pos*/) /*!< SCB ICSR: VECTACTIVE Mask */ + +#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U) +/* SCB Vector Table Offset Register Definitions */ +#define SCB_VTOR_TBLOFF_Pos 7U /*!< SCB VTOR: TBLOFF Position */ +#define SCB_VTOR_TBLOFF_Msk (0x1FFFFFFUL << SCB_VTOR_TBLOFF_Pos) /*!< SCB VTOR: TBLOFF Mask */ +#endif + +/* SCB Application Interrupt and Reset Control Register Definitions */ +#define SCB_AIRCR_VECTKEY_Pos 16U /*!< SCB AIRCR: VECTKEY Position */ +#define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */ + +#define SCB_AIRCR_VECTKEYSTAT_Pos 16U /*!< SCB AIRCR: VECTKEYSTAT Position */ +#define SCB_AIRCR_VECTKEYSTAT_Msk (0xFFFFUL << SCB_AIRCR_VECTKEYSTAT_Pos) /*!< SCB AIRCR: VECTKEYSTAT Mask */ + +#define SCB_AIRCR_ENDIANESS_Pos 15U /*!< SCB AIRCR: ENDIANESS Position */ +#define SCB_AIRCR_ENDIANESS_Msk (1UL << SCB_AIRCR_ENDIANESS_Pos) /*!< SCB AIRCR: ENDIANESS Mask */ + +#define SCB_AIRCR_PRIS_Pos 14U /*!< SCB AIRCR: PRIS Position */ +#define SCB_AIRCR_PRIS_Msk (1UL << SCB_AIRCR_PRIS_Pos) /*!< SCB AIRCR: PRIS Mask */ + +#define SCB_AIRCR_BFHFNMINS_Pos 13U /*!< SCB AIRCR: BFHFNMINS Position */ +#define SCB_AIRCR_BFHFNMINS_Msk (1UL << SCB_AIRCR_BFHFNMINS_Pos) /*!< SCB AIRCR: BFHFNMINS Mask */ + +#define SCB_AIRCR_SYSRESETREQS_Pos 3U /*!< SCB AIRCR: SYSRESETREQS Position */ +#define SCB_AIRCR_SYSRESETREQS_Msk (1UL << SCB_AIRCR_SYSRESETREQS_Pos) /*!< SCB AIRCR: SYSRESETREQS Mask */ + +#define SCB_AIRCR_SYSRESETREQ_Pos 2U /*!< SCB AIRCR: SYSRESETREQ Position */ +#define SCB_AIRCR_SYSRESETREQ_Msk (1UL << SCB_AIRCR_SYSRESETREQ_Pos) /*!< SCB AIRCR: SYSRESETREQ Mask */ + +#define SCB_AIRCR_VECTCLRACTIVE_Pos 1U /*!< SCB AIRCR: VECTCLRACTIVE Position */ +#define SCB_AIRCR_VECTCLRACTIVE_Msk (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos) /*!< SCB AIRCR: VECTCLRACTIVE Mask */ + +/* SCB System Control Register Definitions */ +#define SCB_SCR_SEVONPEND_Pos 4U /*!< SCB SCR: SEVONPEND Position */ +#define SCB_SCR_SEVONPEND_Msk (1UL << SCB_SCR_SEVONPEND_Pos) /*!< SCB SCR: SEVONPEND Mask */ + +#define SCB_SCR_SLEEPDEEPS_Pos 3U /*!< SCB SCR: SLEEPDEEPS Position */ +#define SCB_SCR_SLEEPDEEPS_Msk (1UL << SCB_SCR_SLEEPDEEPS_Pos) /*!< SCB SCR: SLEEPDEEPS Mask */ + +#define SCB_SCR_SLEEPDEEP_Pos 2U /*!< SCB SCR: SLEEPDEEP Position */ +#define SCB_SCR_SLEEPDEEP_Msk (1UL << SCB_SCR_SLEEPDEEP_Pos) /*!< SCB SCR: SLEEPDEEP Mask */ + +#define SCB_SCR_SLEEPONEXIT_Pos 1U /*!< SCB SCR: SLEEPONEXIT Position */ +#define SCB_SCR_SLEEPONEXIT_Msk (1UL << SCB_SCR_SLEEPONEXIT_Pos) /*!< SCB SCR: SLEEPONEXIT Mask */ + +/* SCB Configuration Control Register Definitions */ +#define SCB_CCR_BP_Pos 18U /*!< SCB CCR: BP Position */ +#define SCB_CCR_BP_Msk (1UL << SCB_CCR_BP_Pos) /*!< SCB CCR: BP Mask */ + +#define SCB_CCR_IC_Pos 17U /*!< SCB CCR: IC Position */ +#define SCB_CCR_IC_Msk (1UL << SCB_CCR_IC_Pos) /*!< SCB CCR: IC Mask */ + +#define SCB_CCR_DC_Pos 16U /*!< SCB CCR: DC Position */ +#define SCB_CCR_DC_Msk (1UL << SCB_CCR_DC_Pos) /*!< SCB CCR: DC Mask */ + +#define SCB_CCR_STKOFHFNMIGN_Pos 10U /*!< SCB CCR: STKOFHFNMIGN Position */ +#define SCB_CCR_STKOFHFNMIGN_Msk (1UL << SCB_CCR_STKOFHFNMIGN_Pos) /*!< SCB CCR: STKOFHFNMIGN Mask */ + +#define SCB_CCR_BFHFNMIGN_Pos 8U /*!< SCB CCR: BFHFNMIGN Position */ +#define SCB_CCR_BFHFNMIGN_Msk (1UL << SCB_CCR_BFHFNMIGN_Pos) /*!< SCB CCR: BFHFNMIGN Mask */ + +#define SCB_CCR_DIV_0_TRP_Pos 4U /*!< SCB CCR: DIV_0_TRP Position */ +#define SCB_CCR_DIV_0_TRP_Msk (1UL << SCB_CCR_DIV_0_TRP_Pos) /*!< SCB CCR: DIV_0_TRP Mask */ + +#define SCB_CCR_UNALIGN_TRP_Pos 3U /*!< SCB CCR: UNALIGN_TRP Position */ +#define SCB_CCR_UNALIGN_TRP_Msk (1UL << SCB_CCR_UNALIGN_TRP_Pos) /*!< SCB CCR: UNALIGN_TRP Mask */ + +#define SCB_CCR_USERSETMPEND_Pos 1U /*!< SCB CCR: USERSETMPEND Position */ +#define SCB_CCR_USERSETMPEND_Msk (1UL << SCB_CCR_USERSETMPEND_Pos) /*!< SCB CCR: USERSETMPEND Mask */ + +/* SCB System Handler Control and State Register Definitions */ +#define SCB_SHCSR_HARDFAULTPENDED_Pos 21U /*!< SCB SHCSR: HARDFAULTPENDED Position */ +#define SCB_SHCSR_HARDFAULTPENDED_Msk (1UL << SCB_SHCSR_HARDFAULTPENDED_Pos) /*!< SCB SHCSR: HARDFAULTPENDED Mask */ + +#define SCB_SHCSR_SVCALLPENDED_Pos 15U /*!< SCB SHCSR: SVCALLPENDED Position */ +#define SCB_SHCSR_SVCALLPENDED_Msk (1UL << SCB_SHCSR_SVCALLPENDED_Pos) /*!< SCB SHCSR: SVCALLPENDED Mask */ + +#define SCB_SHCSR_SYSTICKACT_Pos 11U /*!< SCB SHCSR: SYSTICKACT Position */ +#define SCB_SHCSR_SYSTICKACT_Msk (1UL << SCB_SHCSR_SYSTICKACT_Pos) /*!< SCB SHCSR: SYSTICKACT Mask */ + +#define SCB_SHCSR_PENDSVACT_Pos 10U /*!< SCB SHCSR: PENDSVACT Position */ +#define SCB_SHCSR_PENDSVACT_Msk (1UL << SCB_SHCSR_PENDSVACT_Pos) /*!< SCB SHCSR: PENDSVACT Mask */ + +#define SCB_SHCSR_SVCALLACT_Pos 7U /*!< SCB SHCSR: SVCALLACT Position */ +#define SCB_SHCSR_SVCALLACT_Msk (1UL << SCB_SHCSR_SVCALLACT_Pos) /*!< SCB SHCSR: SVCALLACT Mask */ + +#define SCB_SHCSR_NMIACT_Pos 5U /*!< SCB SHCSR: NMIACT Position */ +#define SCB_SHCSR_NMIACT_Msk (1UL << SCB_SHCSR_NMIACT_Pos) /*!< SCB SHCSR: NMIACT Mask */ + +#define SCB_SHCSR_HARDFAULTACT_Pos 2U /*!< SCB SHCSR: HARDFAULTACT Position */ +#define SCB_SHCSR_HARDFAULTACT_Msk (1UL << SCB_SHCSR_HARDFAULTACT_Pos) /*!< SCB SHCSR: HARDFAULTACT Mask */ + +/*@} end of group CMSIS_SCB */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SysTick System Tick Timer (SysTick) + \brief Type definitions for the System Timer Registers. + @{ + */ + +/** + \brief Structure type to access the System Timer (SysTick). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */ + __IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */ + __IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */ + __IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */ +} SysTick_Type; + +/* SysTick Control / Status Register Definitions */ +#define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */ +#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */ + +#define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */ +#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */ + +#define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */ +#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */ + +#define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */ +#define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */ + +/* SysTick Reload Register Definitions */ +#define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */ +#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */ + +/* SysTick Current Register Definitions */ +#define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */ +#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */ + +/* SysTick Calibration Register Definitions */ +#define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */ +#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */ + +#define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */ +#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */ + +#define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */ +#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */ + +/*@} end of group CMSIS_SysTick */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_DWT Data Watchpoint and Trace (DWT) + \brief Type definitions for the Data Watchpoint and Trace (DWT) + @{ + */ + +/** + \brief Structure type to access the Data Watchpoint and Trace Register (DWT). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) Control Register */ + uint32_t RESERVED0[6U]; + __IM uint32_t PCSR; /*!< Offset: 0x01C (R/ ) Program Counter Sample Register */ + __IOM uint32_t COMP0; /*!< Offset: 0x020 (R/W) Comparator Register 0 */ + uint32_t RESERVED1[1U]; + __IOM uint32_t FUNCTION0; /*!< Offset: 0x028 (R/W) Function Register 0 */ + uint32_t RESERVED2[1U]; + __IOM uint32_t COMP1; /*!< Offset: 0x030 (R/W) Comparator Register 1 */ + uint32_t RESERVED3[1U]; + __IOM uint32_t FUNCTION1; /*!< Offset: 0x038 (R/W) Function Register 1 */ + uint32_t RESERVED4[1U]; + __IOM uint32_t COMP2; /*!< Offset: 0x040 (R/W) Comparator Register 2 */ + uint32_t RESERVED5[1U]; + __IOM uint32_t FUNCTION2; /*!< Offset: 0x048 (R/W) Function Register 2 */ + uint32_t RESERVED6[1U]; + __IOM uint32_t COMP3; /*!< Offset: 0x050 (R/W) Comparator Register 3 */ + uint32_t RESERVED7[1U]; + __IOM uint32_t FUNCTION3; /*!< Offset: 0x058 (R/W) Function Register 3 */ + uint32_t RESERVED8[1U]; + __IOM uint32_t COMP4; /*!< Offset: 0x060 (R/W) Comparator Register 4 */ + uint32_t RESERVED9[1U]; + __IOM uint32_t FUNCTION4; /*!< Offset: 0x068 (R/W) Function Register 4 */ + uint32_t RESERVED10[1U]; + __IOM uint32_t COMP5; /*!< Offset: 0x070 (R/W) Comparator Register 5 */ + uint32_t RESERVED11[1U]; + __IOM uint32_t FUNCTION5; /*!< Offset: 0x078 (R/W) Function Register 5 */ + uint32_t RESERVED12[1U]; + __IOM uint32_t COMP6; /*!< Offset: 0x080 (R/W) Comparator Register 6 */ + uint32_t RESERVED13[1U]; + __IOM uint32_t FUNCTION6; /*!< Offset: 0x088 (R/W) Function Register 6 */ + uint32_t RESERVED14[1U]; + __IOM uint32_t COMP7; /*!< Offset: 0x090 (R/W) Comparator Register 7 */ + uint32_t RESERVED15[1U]; + __IOM uint32_t FUNCTION7; /*!< Offset: 0x098 (R/W) Function Register 7 */ + uint32_t RESERVED16[1U]; + __IOM uint32_t COMP8; /*!< Offset: 0x0A0 (R/W) Comparator Register 8 */ + uint32_t RESERVED17[1U]; + __IOM uint32_t FUNCTION8; /*!< Offset: 0x0A8 (R/W) Function Register 8 */ + uint32_t RESERVED18[1U]; + __IOM uint32_t COMP9; /*!< Offset: 0x0B0 (R/W) Comparator Register 9 */ + uint32_t RESERVED19[1U]; + __IOM uint32_t FUNCTION9; /*!< Offset: 0x0B8 (R/W) Function Register 9 */ + uint32_t RESERVED20[1U]; + __IOM uint32_t COMP10; /*!< Offset: 0x0C0 (R/W) Comparator Register 10 */ + uint32_t RESERVED21[1U]; + __IOM uint32_t FUNCTION10; /*!< Offset: 0x0C8 (R/W) Function Register 10 */ + uint32_t RESERVED22[1U]; + __IOM uint32_t COMP11; /*!< Offset: 0x0D0 (R/W) Comparator Register 11 */ + uint32_t RESERVED23[1U]; + __IOM uint32_t FUNCTION11; /*!< Offset: 0x0D8 (R/W) Function Register 11 */ + uint32_t RESERVED24[1U]; + __IOM uint32_t COMP12; /*!< Offset: 0x0E0 (R/W) Comparator Register 12 */ + uint32_t RESERVED25[1U]; + __IOM uint32_t FUNCTION12; /*!< Offset: 0x0E8 (R/W) Function Register 12 */ + uint32_t RESERVED26[1U]; + __IOM uint32_t COMP13; /*!< Offset: 0x0F0 (R/W) Comparator Register 13 */ + uint32_t RESERVED27[1U]; + __IOM uint32_t FUNCTION13; /*!< Offset: 0x0F8 (R/W) Function Register 13 */ + uint32_t RESERVED28[1U]; + __IOM uint32_t COMP14; /*!< Offset: 0x100 (R/W) Comparator Register 14 */ + uint32_t RESERVED29[1U]; + __IOM uint32_t FUNCTION14; /*!< Offset: 0x108 (R/W) Function Register 14 */ + uint32_t RESERVED30[1U]; + __IOM uint32_t COMP15; /*!< Offset: 0x110 (R/W) Comparator Register 15 */ + uint32_t RESERVED31[1U]; + __IOM uint32_t FUNCTION15; /*!< Offset: 0x118 (R/W) Function Register 15 */ +} DWT_Type; + +/* DWT Control Register Definitions */ +#define DWT_CTRL_NUMCOMP_Pos 28U /*!< DWT CTRL: NUMCOMP Position */ +#define DWT_CTRL_NUMCOMP_Msk (0xFUL << DWT_CTRL_NUMCOMP_Pos) /*!< DWT CTRL: NUMCOMP Mask */ + +#define DWT_CTRL_NOTRCPKT_Pos 27U /*!< DWT CTRL: NOTRCPKT Position */ +#define DWT_CTRL_NOTRCPKT_Msk (0x1UL << DWT_CTRL_NOTRCPKT_Pos) /*!< DWT CTRL: NOTRCPKT Mask */ + +#define DWT_CTRL_NOEXTTRIG_Pos 26U /*!< DWT CTRL: NOEXTTRIG Position */ +#define DWT_CTRL_NOEXTTRIG_Msk (0x1UL << DWT_CTRL_NOEXTTRIG_Pos) /*!< DWT CTRL: NOEXTTRIG Mask */ + +#define DWT_CTRL_NOCYCCNT_Pos 25U /*!< DWT CTRL: NOCYCCNT Position */ +#define DWT_CTRL_NOCYCCNT_Msk (0x1UL << DWT_CTRL_NOCYCCNT_Pos) /*!< DWT CTRL: NOCYCCNT Mask */ + +#define DWT_CTRL_NOPRFCNT_Pos 24U /*!< DWT CTRL: NOPRFCNT Position */ +#define DWT_CTRL_NOPRFCNT_Msk (0x1UL << DWT_CTRL_NOPRFCNT_Pos) /*!< DWT CTRL: NOPRFCNT Mask */ + +/* DWT Comparator Function Register Definitions */ +#define DWT_FUNCTION_ID_Pos 27U /*!< DWT FUNCTION: ID Position */ +#define DWT_FUNCTION_ID_Msk (0x1FUL << DWT_FUNCTION_ID_Pos) /*!< DWT FUNCTION: ID Mask */ + +#define DWT_FUNCTION_MATCHED_Pos 24U /*!< DWT FUNCTION: MATCHED Position */ +#define DWT_FUNCTION_MATCHED_Msk (0x1UL << DWT_FUNCTION_MATCHED_Pos) /*!< DWT FUNCTION: MATCHED Mask */ + +#define DWT_FUNCTION_DATAVSIZE_Pos 10U /*!< DWT FUNCTION: DATAVSIZE Position */ +#define DWT_FUNCTION_DATAVSIZE_Msk (0x3UL << DWT_FUNCTION_DATAVSIZE_Pos) /*!< DWT FUNCTION: DATAVSIZE Mask */ + +#define DWT_FUNCTION_ACTION_Pos 4U /*!< DWT FUNCTION: ACTION Position */ +#define DWT_FUNCTION_ACTION_Msk (0x3UL << DWT_FUNCTION_ACTION_Pos) /*!< DWT FUNCTION: ACTION Mask */ + +#define DWT_FUNCTION_MATCH_Pos 0U /*!< DWT FUNCTION: MATCH Position */ +#define DWT_FUNCTION_MATCH_Msk (0xFUL /*<< DWT_FUNCTION_MATCH_Pos*/) /*!< DWT FUNCTION: MATCH Mask */ + +/*@}*/ /* end of group CMSIS_DWT */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_TPI Trace Port Interface (TPI) + \brief Type definitions for the Trace Port Interface (TPI) + @{ + */ + +/** + \brief Structure type to access the Trace Port Interface Register (TPI). + */ +typedef struct +{ + __IM uint32_t SSPSR; /*!< Offset: 0x000 (R/ ) Supported Parallel Port Size Register */ + __IOM uint32_t CSPSR; /*!< Offset: 0x004 (R/W) Current Parallel Port Size Register */ + uint32_t RESERVED0[2U]; + __IOM uint32_t ACPR; /*!< Offset: 0x010 (R/W) Asynchronous Clock Prescaler Register */ + uint32_t RESERVED1[55U]; + __IOM uint32_t SPPR; /*!< Offset: 0x0F0 (R/W) Selected Pin Protocol Register */ + uint32_t RESERVED2[131U]; + __IM uint32_t FFSR; /*!< Offset: 0x300 (R/ ) Formatter and Flush Status Register */ + __IOM uint32_t FFCR; /*!< Offset: 0x304 (R/W) Formatter and Flush Control Register */ + __IOM uint32_t PSCR; /*!< Offset: 0x308 (R/W) Periodic Synchronization Control Register */ + uint32_t RESERVED3[759U]; + __IM uint32_t TRIGGER; /*!< Offset: 0xEE8 (R/ ) TRIGGER Register */ + __IM uint32_t ITFTTD0; /*!< Offset: 0xEEC (R/ ) Integration Test FIFO Test Data 0 Register */ + __IOM uint32_t ITATBCTR2; /*!< Offset: 0xEF0 (R/W) Integration Test ATB Control Register 2 */ + uint32_t RESERVED4[1U]; + __IM uint32_t ITATBCTR0; /*!< Offset: 0xEF8 (R/ ) Integration Test ATB Control Register 0 */ + __IM uint32_t ITFTTD1; /*!< Offset: 0xEFC (R/ ) Integration Test FIFO Test Data 1 Register */ + __IOM uint32_t ITCTRL; /*!< Offset: 0xF00 (R/W) Integration Mode Control */ + uint32_t RESERVED5[39U]; + __IOM uint32_t CLAIMSET; /*!< Offset: 0xFA0 (R/W) Claim tag set */ + __IOM uint32_t CLAIMCLR; /*!< Offset: 0xFA4 (R/W) Claim tag clear */ + uint32_t RESERVED7[8U]; + __IM uint32_t DEVID; /*!< Offset: 0xFC8 (R/ ) Device Configuration Register */ + __IM uint32_t DEVTYPE; /*!< Offset: 0xFCC (R/ ) Device Type Identifier Register */ +} TPI_Type; + +/* TPI Asynchronous Clock Prescaler Register Definitions */ +#define TPI_ACPR_PRESCALER_Pos 0U /*!< TPI ACPR: PRESCALER Position */ +#define TPI_ACPR_PRESCALER_Msk (0x1FFFUL /*<< TPI_ACPR_PRESCALER_Pos*/) /*!< TPI ACPR: PRESCALER Mask */ + +/* TPI Selected Pin Protocol Register Definitions */ +#define TPI_SPPR_TXMODE_Pos 0U /*!< TPI SPPR: TXMODE Position */ +#define TPI_SPPR_TXMODE_Msk (0x3UL /*<< TPI_SPPR_TXMODE_Pos*/) /*!< TPI SPPR: TXMODE Mask */ + +/* TPI Formatter and Flush Status Register Definitions */ +#define TPI_FFSR_FtNonStop_Pos 3U /*!< TPI FFSR: FtNonStop Position */ +#define TPI_FFSR_FtNonStop_Msk (0x1UL << TPI_FFSR_FtNonStop_Pos) /*!< TPI FFSR: FtNonStop Mask */ + +#define TPI_FFSR_TCPresent_Pos 2U /*!< TPI FFSR: TCPresent Position */ +#define TPI_FFSR_TCPresent_Msk (0x1UL << TPI_FFSR_TCPresent_Pos) /*!< TPI FFSR: TCPresent Mask */ + +#define TPI_FFSR_FtStopped_Pos 1U /*!< TPI FFSR: FtStopped Position */ +#define TPI_FFSR_FtStopped_Msk (0x1UL << TPI_FFSR_FtStopped_Pos) /*!< TPI FFSR: FtStopped Mask */ + +#define TPI_FFSR_FlInProg_Pos 0U /*!< TPI FFSR: FlInProg Position */ +#define TPI_FFSR_FlInProg_Msk (0x1UL /*<< TPI_FFSR_FlInProg_Pos*/) /*!< TPI FFSR: FlInProg Mask */ + +/* TPI Formatter and Flush Control Register Definitions */ +#define TPI_FFCR_TrigIn_Pos 8U /*!< TPI FFCR: TrigIn Position */ +#define TPI_FFCR_TrigIn_Msk (0x1UL << TPI_FFCR_TrigIn_Pos) /*!< TPI FFCR: TrigIn Mask */ + +#define TPI_FFCR_FOnMan_Pos 6U /*!< TPI FFCR: FOnMan Position */ +#define TPI_FFCR_FOnMan_Msk (0x1UL << TPI_FFCR_FOnMan_Pos) /*!< TPI FFCR: FOnMan Mask */ + +#define TPI_FFCR_EnFCont_Pos 1U /*!< TPI FFCR: EnFCont Position */ +#define TPI_FFCR_EnFCont_Msk (0x1UL << TPI_FFCR_EnFCont_Pos) /*!< TPI FFCR: EnFCont Mask */ + +/* TPI TRIGGER Register Definitions */ +#define TPI_TRIGGER_TRIGGER_Pos 0U /*!< TPI TRIGGER: TRIGGER Position */ +#define TPI_TRIGGER_TRIGGER_Msk (0x1UL /*<< TPI_TRIGGER_TRIGGER_Pos*/) /*!< TPI TRIGGER: TRIGGER Mask */ + +/* TPI Integration Test FIFO Test Data 0 Register Definitions */ +#define TPI_ITFTTD0_ATB_IF2_ATVALID_Pos 29U /*!< TPI ITFTTD0: ATB Interface 2 ATVALIDPosition */ +#define TPI_ITFTTD0_ATB_IF2_ATVALID_Msk (0x3UL << TPI_ITFTTD0_ATB_IF2_ATVALID_Pos) /*!< TPI ITFTTD0: ATB Interface 2 ATVALID Mask */ + +#define TPI_ITFTTD0_ATB_IF2_bytecount_Pos 27U /*!< TPI ITFTTD0: ATB Interface 2 byte count Position */ +#define TPI_ITFTTD0_ATB_IF2_bytecount_Msk (0x3UL << TPI_ITFTTD0_ATB_IF2_bytecount_Pos) /*!< TPI ITFTTD0: ATB Interface 2 byte count Mask */ + +#define TPI_ITFTTD0_ATB_IF1_ATVALID_Pos 26U /*!< TPI ITFTTD0: ATB Interface 1 ATVALID Position */ +#define TPI_ITFTTD0_ATB_IF1_ATVALID_Msk (0x3UL << TPI_ITFTTD0_ATB_IF1_ATVALID_Pos) /*!< TPI ITFTTD0: ATB Interface 1 ATVALID Mask */ + +#define TPI_ITFTTD0_ATB_IF1_bytecount_Pos 24U /*!< TPI ITFTTD0: ATB Interface 1 byte count Position */ +#define TPI_ITFTTD0_ATB_IF1_bytecount_Msk (0x3UL << TPI_ITFTTD0_ATB_IF1_bytecount_Pos) /*!< TPI ITFTTD0: ATB Interface 1 byte countt Mask */ + +#define TPI_ITFTTD0_ATB_IF1_data2_Pos 16U /*!< TPI ITFTTD0: ATB Interface 1 data2 Position */ +#define TPI_ITFTTD0_ATB_IF1_data2_Msk (0xFFUL << TPI_ITFTTD0_ATB_IF1_data1_Pos) /*!< TPI ITFTTD0: ATB Interface 1 data2 Mask */ + +#define TPI_ITFTTD0_ATB_IF1_data1_Pos 8U /*!< TPI ITFTTD0: ATB Interface 1 data1 Position */ +#define TPI_ITFTTD0_ATB_IF1_data1_Msk (0xFFUL << TPI_ITFTTD0_ATB_IF1_data1_Pos) /*!< TPI ITFTTD0: ATB Interface 1 data1 Mask */ + +#define TPI_ITFTTD0_ATB_IF1_data0_Pos 0U /*!< TPI ITFTTD0: ATB Interface 1 data0 Position */ +#define TPI_ITFTTD0_ATB_IF1_data0_Msk (0xFFUL /*<< TPI_ITFTTD0_ATB_IF1_data0_Pos*/) /*!< TPI ITFTTD0: ATB Interface 1 data0 Mask */ + +/* TPI Integration Test ATB Control Register 2 Register Definitions */ +#define TPI_ITATBCTR2_AFVALID2S_Pos 1U /*!< TPI ITATBCTR2: AFVALID2S Position */ +#define TPI_ITATBCTR2_AFVALID2S_Msk (0x1UL << TPI_ITATBCTR2_AFVALID2S_Pos) /*!< TPI ITATBCTR2: AFVALID2SS Mask */ + +#define TPI_ITATBCTR2_AFVALID1S_Pos 1U /*!< TPI ITATBCTR2: AFVALID1S Position */ +#define TPI_ITATBCTR2_AFVALID1S_Msk (0x1UL << TPI_ITATBCTR2_AFVALID1S_Pos) /*!< TPI ITATBCTR2: AFVALID1SS Mask */ + +#define TPI_ITATBCTR2_ATREADY2S_Pos 0U /*!< TPI ITATBCTR2: ATREADY2S Position */ +#define TPI_ITATBCTR2_ATREADY2S_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY2S_Pos*/) /*!< TPI ITATBCTR2: ATREADY2S Mask */ + +#define TPI_ITATBCTR2_ATREADY1S_Pos 0U /*!< TPI ITATBCTR2: ATREADY1S Position */ +#define TPI_ITATBCTR2_ATREADY1S_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY1S_Pos*/) /*!< TPI ITATBCTR2: ATREADY1S Mask */ + +/* TPI Integration Test FIFO Test Data 1 Register Definitions */ +#define TPI_ITFTTD1_ATB_IF2_ATVALID_Pos 29U /*!< TPI ITFTTD1: ATB Interface 2 ATVALID Position */ +#define TPI_ITFTTD1_ATB_IF2_ATVALID_Msk (0x3UL << TPI_ITFTTD1_ATB_IF2_ATVALID_Pos) /*!< TPI ITFTTD1: ATB Interface 2 ATVALID Mask */ + +#define TPI_ITFTTD1_ATB_IF2_bytecount_Pos 27U /*!< TPI ITFTTD1: ATB Interface 2 byte count Position */ +#define TPI_ITFTTD1_ATB_IF2_bytecount_Msk (0x3UL << TPI_ITFTTD1_ATB_IF2_bytecount_Pos) /*!< TPI ITFTTD1: ATB Interface 2 byte count Mask */ + +#define TPI_ITFTTD1_ATB_IF1_ATVALID_Pos 26U /*!< TPI ITFTTD1: ATB Interface 1 ATVALID Position */ +#define TPI_ITFTTD1_ATB_IF1_ATVALID_Msk (0x3UL << TPI_ITFTTD1_ATB_IF1_ATVALID_Pos) /*!< TPI ITFTTD1: ATB Interface 1 ATVALID Mask */ + +#define TPI_ITFTTD1_ATB_IF1_bytecount_Pos 24U /*!< TPI ITFTTD1: ATB Interface 1 byte count Position */ +#define TPI_ITFTTD1_ATB_IF1_bytecount_Msk (0x3UL << TPI_ITFTTD1_ATB_IF1_bytecount_Pos) /*!< TPI ITFTTD1: ATB Interface 1 byte countt Mask */ + +#define TPI_ITFTTD1_ATB_IF2_data2_Pos 16U /*!< TPI ITFTTD1: ATB Interface 2 data2 Position */ +#define TPI_ITFTTD1_ATB_IF2_data2_Msk (0xFFUL << TPI_ITFTTD1_ATB_IF2_data1_Pos) /*!< TPI ITFTTD1: ATB Interface 2 data2 Mask */ + +#define TPI_ITFTTD1_ATB_IF2_data1_Pos 8U /*!< TPI ITFTTD1: ATB Interface 2 data1 Position */ +#define TPI_ITFTTD1_ATB_IF2_data1_Msk (0xFFUL << TPI_ITFTTD1_ATB_IF2_data1_Pos) /*!< TPI ITFTTD1: ATB Interface 2 data1 Mask */ + +#define TPI_ITFTTD1_ATB_IF2_data0_Pos 0U /*!< TPI ITFTTD1: ATB Interface 2 data0 Position */ +#define TPI_ITFTTD1_ATB_IF2_data0_Msk (0xFFUL /*<< TPI_ITFTTD1_ATB_IF2_data0_Pos*/) /*!< TPI ITFTTD1: ATB Interface 2 data0 Mask */ + +/* TPI Integration Test ATB Control Register 0 Definitions */ +#define TPI_ITATBCTR0_AFVALID2S_Pos 1U /*!< TPI ITATBCTR0: AFVALID2S Position */ +#define TPI_ITATBCTR0_AFVALID2S_Msk (0x1UL << TPI_ITATBCTR0_AFVALID2S_Pos) /*!< TPI ITATBCTR0: AFVALID2SS Mask */ + +#define TPI_ITATBCTR0_AFVALID1S_Pos 1U /*!< TPI ITATBCTR0: AFVALID1S Position */ +#define TPI_ITATBCTR0_AFVALID1S_Msk (0x1UL << TPI_ITATBCTR0_AFVALID1S_Pos) /*!< TPI ITATBCTR0: AFVALID1SS Mask */ + +#define TPI_ITATBCTR0_ATREADY2S_Pos 0U /*!< TPI ITATBCTR0: ATREADY2S Position */ +#define TPI_ITATBCTR0_ATREADY2S_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY2S_Pos*/) /*!< TPI ITATBCTR0: ATREADY2S Mask */ + +#define TPI_ITATBCTR0_ATREADY1S_Pos 0U /*!< TPI ITATBCTR0: ATREADY1S Position */ +#define TPI_ITATBCTR0_ATREADY1S_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY1S_Pos*/) /*!< TPI ITATBCTR0: ATREADY1S Mask */ + +/* TPI Integration Mode Control Register Definitions */ +#define TPI_ITCTRL_Mode_Pos 0U /*!< TPI ITCTRL: Mode Position */ +#define TPI_ITCTRL_Mode_Msk (0x3UL /*<< TPI_ITCTRL_Mode_Pos*/) /*!< TPI ITCTRL: Mode Mask */ + +/* TPI DEVID Register Definitions */ +#define TPI_DEVID_NRZVALID_Pos 11U /*!< TPI DEVID: NRZVALID Position */ +#define TPI_DEVID_NRZVALID_Msk (0x1UL << TPI_DEVID_NRZVALID_Pos) /*!< TPI DEVID: NRZVALID Mask */ + +#define TPI_DEVID_MANCVALID_Pos 10U /*!< TPI DEVID: MANCVALID Position */ +#define TPI_DEVID_MANCVALID_Msk (0x1UL << TPI_DEVID_MANCVALID_Pos) /*!< TPI DEVID: MANCVALID Mask */ + +#define TPI_DEVID_PTINVALID_Pos 9U /*!< TPI DEVID: PTINVALID Position */ +#define TPI_DEVID_PTINVALID_Msk (0x1UL << TPI_DEVID_PTINVALID_Pos) /*!< TPI DEVID: PTINVALID Mask */ + +#define TPI_DEVID_FIFOSZ_Pos 6U /*!< TPI DEVID: FIFOSZ Position */ +#define TPI_DEVID_FIFOSZ_Msk (0x7UL << TPI_DEVID_FIFOSZ_Pos) /*!< TPI DEVID: FIFOSZ Mask */ + +#define TPI_DEVID_NrTraceInput_Pos 0U /*!< TPI DEVID: NrTraceInput Position */ +#define TPI_DEVID_NrTraceInput_Msk (0x3FUL /*<< TPI_DEVID_NrTraceInput_Pos*/) /*!< TPI DEVID: NrTraceInput Mask */ + +/* TPI DEVTYPE Register Definitions */ +#define TPI_DEVTYPE_SubType_Pos 4U /*!< TPI DEVTYPE: SubType Position */ +#define TPI_DEVTYPE_SubType_Msk (0xFUL /*<< TPI_DEVTYPE_SubType_Pos*/) /*!< TPI DEVTYPE: SubType Mask */ + +#define TPI_DEVTYPE_MajorType_Pos 0U /*!< TPI DEVTYPE: MajorType Position */ +#define TPI_DEVTYPE_MajorType_Msk (0xFUL << TPI_DEVTYPE_MajorType_Pos) /*!< TPI DEVTYPE: MajorType Mask */ + +/*@}*/ /* end of group CMSIS_TPI */ + + +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_MPU Memory Protection Unit (MPU) + \brief Type definitions for the Memory Protection Unit (MPU) + @{ + */ + +/** + \brief Structure type to access the Memory Protection Unit (MPU). + */ +typedef struct +{ + __IM uint32_t TYPE; /*!< Offset: 0x000 (R/ ) MPU Type Register */ + __IOM uint32_t CTRL; /*!< Offset: 0x004 (R/W) MPU Control Register */ + __IOM uint32_t RNR; /*!< Offset: 0x008 (R/W) MPU Region Number Register */ + __IOM uint32_t RBAR; /*!< Offset: 0x00C (R/W) MPU Region Base Address Register */ + __IOM uint32_t RLAR; /*!< Offset: 0x010 (R/W) MPU Region Limit Address Register */ + uint32_t RESERVED0[7U]; + union { + __IOM uint32_t MAIR[2]; + struct { + __IOM uint32_t MAIR0; /*!< Offset: 0x030 (R/W) MPU Memory Attribute Indirection Register 0 */ + __IOM uint32_t MAIR1; /*!< Offset: 0x034 (R/W) MPU Memory Attribute Indirection Register 1 */ + }; + }; +} MPU_Type; + +#define MPU_TYPE_RALIASES 1U + +/* MPU Type Register Definitions */ +#define MPU_TYPE_IREGION_Pos 16U /*!< MPU TYPE: IREGION Position */ +#define MPU_TYPE_IREGION_Msk (0xFFUL << MPU_TYPE_IREGION_Pos) /*!< MPU TYPE: IREGION Mask */ + +#define MPU_TYPE_DREGION_Pos 8U /*!< MPU TYPE: DREGION Position */ +#define MPU_TYPE_DREGION_Msk (0xFFUL << MPU_TYPE_DREGION_Pos) /*!< MPU TYPE: DREGION Mask */ + +#define MPU_TYPE_SEPARATE_Pos 0U /*!< MPU TYPE: SEPARATE Position */ +#define MPU_TYPE_SEPARATE_Msk (1UL /*<< MPU_TYPE_SEPARATE_Pos*/) /*!< MPU TYPE: SEPARATE Mask */ + +/* MPU Control Register Definitions */ +#define MPU_CTRL_PRIVDEFENA_Pos 2U /*!< MPU CTRL: PRIVDEFENA Position */ +#define MPU_CTRL_PRIVDEFENA_Msk (1UL << MPU_CTRL_PRIVDEFENA_Pos) /*!< MPU CTRL: PRIVDEFENA Mask */ + +#define MPU_CTRL_HFNMIENA_Pos 1U /*!< MPU CTRL: HFNMIENA Position */ +#define MPU_CTRL_HFNMIENA_Msk (1UL << MPU_CTRL_HFNMIENA_Pos) /*!< MPU CTRL: HFNMIENA Mask */ + +#define MPU_CTRL_ENABLE_Pos 0U /*!< MPU CTRL: ENABLE Position */ +#define MPU_CTRL_ENABLE_Msk (1UL /*<< MPU_CTRL_ENABLE_Pos*/) /*!< MPU CTRL: ENABLE Mask */ + +/* MPU Region Number Register Definitions */ +#define MPU_RNR_REGION_Pos 0U /*!< MPU RNR: REGION Position */ +#define MPU_RNR_REGION_Msk (0xFFUL /*<< MPU_RNR_REGION_Pos*/) /*!< MPU RNR: REGION Mask */ + +/* MPU Region Base Address Register Definitions */ +#define MPU_RBAR_BASE_Pos 5U /*!< MPU RBAR: BASE Position */ +#define MPU_RBAR_BASE_Msk (0x7FFFFFFUL << MPU_RBAR_BASE_Pos) /*!< MPU RBAR: BASE Mask */ + +#define MPU_RBAR_SH_Pos 3U /*!< MPU RBAR: SH Position */ +#define MPU_RBAR_SH_Msk (0x3UL << MPU_RBAR_SH_Pos) /*!< MPU RBAR: SH Mask */ + +#define MPU_RBAR_AP_Pos 1U /*!< MPU RBAR: AP Position */ +#define MPU_RBAR_AP_Msk (0x3UL << MPU_RBAR_AP_Pos) /*!< MPU RBAR: AP Mask */ + +#define MPU_RBAR_XN_Pos 0U /*!< MPU RBAR: XN Position */ +#define MPU_RBAR_XN_Msk (01UL /*<< MPU_RBAR_XN_Pos*/) /*!< MPU RBAR: XN Mask */ + +/* MPU Region Limit Address Register Definitions */ +#define MPU_RLAR_LIMIT_Pos 5U /*!< MPU RLAR: LIMIT Position */ +#define MPU_RLAR_LIMIT_Msk (0x7FFFFFFUL << MPU_RLAR_LIMIT_Pos) /*!< MPU RLAR: LIMIT Mask */ + +#define MPU_RLAR_AttrIndx_Pos 1U /*!< MPU RLAR: AttrIndx Position */ +#define MPU_RLAR_AttrIndx_Msk (0x7UL << MPU_RLAR_AttrIndx_Pos) /*!< MPU RLAR: AttrIndx Mask */ + +#define MPU_RLAR_EN_Pos 0U /*!< MPU RLAR: EN Position */ +#define MPU_RLAR_EN_Msk (1UL /*<< MPU_RLAR_EN_Pos*/) /*!< MPU RLAR: EN Mask */ + +/* MPU Memory Attribute Indirection Register 0 Definitions */ +#define MPU_MAIR0_Attr3_Pos 24U /*!< MPU MAIR0: Attr3 Position */ +#define MPU_MAIR0_Attr3_Msk (0xFFUL << MPU_MAIR0_Attr3_Pos) /*!< MPU MAIR0: Attr3 Mask */ + +#define MPU_MAIR0_Attr2_Pos 16U /*!< MPU MAIR0: Attr2 Position */ +#define MPU_MAIR0_Attr2_Msk (0xFFUL << MPU_MAIR0_Attr2_Pos) /*!< MPU MAIR0: Attr2 Mask */ + +#define MPU_MAIR0_Attr1_Pos 8U /*!< MPU MAIR0: Attr1 Position */ +#define MPU_MAIR0_Attr1_Msk (0xFFUL << MPU_MAIR0_Attr1_Pos) /*!< MPU MAIR0: Attr1 Mask */ + +#define MPU_MAIR0_Attr0_Pos 0U /*!< MPU MAIR0: Attr0 Position */ +#define MPU_MAIR0_Attr0_Msk (0xFFUL /*<< MPU_MAIR0_Attr0_Pos*/) /*!< MPU MAIR0: Attr0 Mask */ + +/* MPU Memory Attribute Indirection Register 1 Definitions */ +#define MPU_MAIR1_Attr7_Pos 24U /*!< MPU MAIR1: Attr7 Position */ +#define MPU_MAIR1_Attr7_Msk (0xFFUL << MPU_MAIR1_Attr7_Pos) /*!< MPU MAIR1: Attr7 Mask */ + +#define MPU_MAIR1_Attr6_Pos 16U /*!< MPU MAIR1: Attr6 Position */ +#define MPU_MAIR1_Attr6_Msk (0xFFUL << MPU_MAIR1_Attr6_Pos) /*!< MPU MAIR1: Attr6 Mask */ + +#define MPU_MAIR1_Attr5_Pos 8U /*!< MPU MAIR1: Attr5 Position */ +#define MPU_MAIR1_Attr5_Msk (0xFFUL << MPU_MAIR1_Attr5_Pos) /*!< MPU MAIR1: Attr5 Mask */ + +#define MPU_MAIR1_Attr4_Pos 0U /*!< MPU MAIR1: Attr4 Position */ +#define MPU_MAIR1_Attr4_Msk (0xFFUL /*<< MPU_MAIR1_Attr4_Pos*/) /*!< MPU MAIR1: Attr4 Mask */ + +/*@} end of group CMSIS_MPU */ +#endif + + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SAU Security Attribution Unit (SAU) + \brief Type definitions for the Security Attribution Unit (SAU) + @{ + */ + +/** + \brief Structure type to access the Security Attribution Unit (SAU). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SAU Control Register */ + __IM uint32_t TYPE; /*!< Offset: 0x004 (R/ ) SAU Type Register */ +#if defined (__SAUREGION_PRESENT) && (__SAUREGION_PRESENT == 1U) + __IOM uint32_t RNR; /*!< Offset: 0x008 (R/W) SAU Region Number Register */ + __IOM uint32_t RBAR; /*!< Offset: 0x00C (R/W) SAU Region Base Address Register */ + __IOM uint32_t RLAR; /*!< Offset: 0x010 (R/W) SAU Region Limit Address Register */ +#endif +} SAU_Type; + +/* SAU Control Register Definitions */ +#define SAU_CTRL_ALLNS_Pos 1U /*!< SAU CTRL: ALLNS Position */ +#define SAU_CTRL_ALLNS_Msk (1UL << SAU_CTRL_ALLNS_Pos) /*!< SAU CTRL: ALLNS Mask */ + +#define SAU_CTRL_ENABLE_Pos 0U /*!< SAU CTRL: ENABLE Position */ +#define SAU_CTRL_ENABLE_Msk (1UL /*<< SAU_CTRL_ENABLE_Pos*/) /*!< SAU CTRL: ENABLE Mask */ + +/* SAU Type Register Definitions */ +#define SAU_TYPE_SREGION_Pos 0U /*!< SAU TYPE: SREGION Position */ +#define SAU_TYPE_SREGION_Msk (0xFFUL /*<< SAU_TYPE_SREGION_Pos*/) /*!< SAU TYPE: SREGION Mask */ + +#if defined (__SAUREGION_PRESENT) && (__SAUREGION_PRESENT == 1U) +/* SAU Region Number Register Definitions */ +#define SAU_RNR_REGION_Pos 0U /*!< SAU RNR: REGION Position */ +#define SAU_RNR_REGION_Msk (0xFFUL /*<< SAU_RNR_REGION_Pos*/) /*!< SAU RNR: REGION Mask */ + +/* SAU Region Base Address Register Definitions */ +#define SAU_RBAR_BADDR_Pos 5U /*!< SAU RBAR: BADDR Position */ +#define SAU_RBAR_BADDR_Msk (0x7FFFFFFUL << SAU_RBAR_BADDR_Pos) /*!< SAU RBAR: BADDR Mask */ + +/* SAU Region Limit Address Register Definitions */ +#define SAU_RLAR_LADDR_Pos 5U /*!< SAU RLAR: LADDR Position */ +#define SAU_RLAR_LADDR_Msk (0x7FFFFFFUL << SAU_RLAR_LADDR_Pos) /*!< SAU RLAR: LADDR Mask */ + +#define SAU_RLAR_NSC_Pos 1U /*!< SAU RLAR: NSC Position */ +#define SAU_RLAR_NSC_Msk (1UL << SAU_RLAR_NSC_Pos) /*!< SAU RLAR: NSC Mask */ + +#define SAU_RLAR_ENABLE_Pos 0U /*!< SAU RLAR: ENABLE Position */ +#define SAU_RLAR_ENABLE_Msk (1UL /*<< SAU_RLAR_ENABLE_Pos*/) /*!< SAU RLAR: ENABLE Mask */ + +#endif /* defined (__SAUREGION_PRESENT) && (__SAUREGION_PRESENT == 1U) */ + +/*@} end of group CMSIS_SAU */ +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CoreDebug Core Debug Registers (CoreDebug) + \brief Type definitions for the Core Debug Registers + @{ + */ + +/** + \brief Structure type to access the Core Debug Register (CoreDebug). + */ +typedef struct +{ + __IOM uint32_t DHCSR; /*!< Offset: 0x000 (R/W) Debug Halting Control and Status Register */ + __OM uint32_t DCRSR; /*!< Offset: 0x004 ( /W) Debug Core Register Selector Register */ + __IOM uint32_t DCRDR; /*!< Offset: 0x008 (R/W) Debug Core Register Data Register */ + __IOM uint32_t DEMCR; /*!< Offset: 0x00C (R/W) Debug Exception and Monitor Control Register */ + uint32_t RESERVED4[1U]; + __IOM uint32_t DAUTHCTRL; /*!< Offset: 0x014 (R/W) Debug Authentication Control Register */ + __IOM uint32_t DSCSR; /*!< Offset: 0x018 (R/W) Debug Security Control and Status Register */ +} CoreDebug_Type; + +/* Debug Halting Control and Status Register Definitions */ +#define CoreDebug_DHCSR_DBGKEY_Pos 16U /*!< CoreDebug DHCSR: DBGKEY Position */ +#define CoreDebug_DHCSR_DBGKEY_Msk (0xFFFFUL << CoreDebug_DHCSR_DBGKEY_Pos) /*!< CoreDebug DHCSR: DBGKEY Mask */ + +#define CoreDebug_DHCSR_S_RESTART_ST_Pos 26U /*!< CoreDebug DHCSR: S_RESTART_ST Position */ +#define CoreDebug_DHCSR_S_RESTART_ST_Msk (1UL << CoreDebug_DHCSR_S_RESTART_ST_Pos) /*!< CoreDebug DHCSR: S_RESTART_ST Mask */ + +#define CoreDebug_DHCSR_S_RESET_ST_Pos 25U /*!< CoreDebug DHCSR: S_RESET_ST Position */ +#define CoreDebug_DHCSR_S_RESET_ST_Msk (1UL << CoreDebug_DHCSR_S_RESET_ST_Pos) /*!< CoreDebug DHCSR: S_RESET_ST Mask */ + +#define CoreDebug_DHCSR_S_RETIRE_ST_Pos 24U /*!< CoreDebug DHCSR: S_RETIRE_ST Position */ +#define CoreDebug_DHCSR_S_RETIRE_ST_Msk (1UL << CoreDebug_DHCSR_S_RETIRE_ST_Pos) /*!< CoreDebug DHCSR: S_RETIRE_ST Mask */ + +#define CoreDebug_DHCSR_S_LOCKUP_Pos 19U /*!< CoreDebug DHCSR: S_LOCKUP Position */ +#define CoreDebug_DHCSR_S_LOCKUP_Msk (1UL << CoreDebug_DHCSR_S_LOCKUP_Pos) /*!< CoreDebug DHCSR: S_LOCKUP Mask */ + +#define CoreDebug_DHCSR_S_SLEEP_Pos 18U /*!< CoreDebug DHCSR: S_SLEEP Position */ +#define CoreDebug_DHCSR_S_SLEEP_Msk (1UL << CoreDebug_DHCSR_S_SLEEP_Pos) /*!< CoreDebug DHCSR: S_SLEEP Mask */ + +#define CoreDebug_DHCSR_S_HALT_Pos 17U /*!< CoreDebug DHCSR: S_HALT Position */ +#define CoreDebug_DHCSR_S_HALT_Msk (1UL << CoreDebug_DHCSR_S_HALT_Pos) /*!< CoreDebug DHCSR: S_HALT Mask */ + +#define CoreDebug_DHCSR_S_REGRDY_Pos 16U /*!< CoreDebug DHCSR: S_REGRDY Position */ +#define CoreDebug_DHCSR_S_REGRDY_Msk (1UL << CoreDebug_DHCSR_S_REGRDY_Pos) /*!< CoreDebug DHCSR: S_REGRDY Mask */ + +#define CoreDebug_DHCSR_C_MASKINTS_Pos 3U /*!< CoreDebug DHCSR: C_MASKINTS Position */ +#define CoreDebug_DHCSR_C_MASKINTS_Msk (1UL << CoreDebug_DHCSR_C_MASKINTS_Pos) /*!< CoreDebug DHCSR: C_MASKINTS Mask */ + +#define CoreDebug_DHCSR_C_STEP_Pos 2U /*!< CoreDebug DHCSR: C_STEP Position */ +#define CoreDebug_DHCSR_C_STEP_Msk (1UL << CoreDebug_DHCSR_C_STEP_Pos) /*!< CoreDebug DHCSR: C_STEP Mask */ + +#define CoreDebug_DHCSR_C_HALT_Pos 1U /*!< CoreDebug DHCSR: C_HALT Position */ +#define CoreDebug_DHCSR_C_HALT_Msk (1UL << CoreDebug_DHCSR_C_HALT_Pos) /*!< CoreDebug DHCSR: C_HALT Mask */ + +#define CoreDebug_DHCSR_C_DEBUGEN_Pos 0U /*!< CoreDebug DHCSR: C_DEBUGEN Position */ +#define CoreDebug_DHCSR_C_DEBUGEN_Msk (1UL /*<< CoreDebug_DHCSR_C_DEBUGEN_Pos*/) /*!< CoreDebug DHCSR: C_DEBUGEN Mask */ + +/* Debug Core Register Selector Register Definitions */ +#define CoreDebug_DCRSR_REGWnR_Pos 16U /*!< CoreDebug DCRSR: REGWnR Position */ +#define CoreDebug_DCRSR_REGWnR_Msk (1UL << CoreDebug_DCRSR_REGWnR_Pos) /*!< CoreDebug DCRSR: REGWnR Mask */ + +#define CoreDebug_DCRSR_REGSEL_Pos 0U /*!< CoreDebug DCRSR: REGSEL Position */ +#define CoreDebug_DCRSR_REGSEL_Msk (0x1FUL /*<< CoreDebug_DCRSR_REGSEL_Pos*/) /*!< CoreDebug DCRSR: REGSEL Mask */ + +/* Debug Exception and Monitor Control Register */ +#define CoreDebug_DEMCR_DWTENA_Pos 24U /*!< CoreDebug DEMCR: DWTENA Position */ +#define CoreDebug_DEMCR_DWTENA_Msk (1UL << CoreDebug_DEMCR_DWTENA_Pos) /*!< CoreDebug DEMCR: DWTENA Mask */ + +#define CoreDebug_DEMCR_VC_HARDERR_Pos 10U /*!< CoreDebug DEMCR: VC_HARDERR Position */ +#define CoreDebug_DEMCR_VC_HARDERR_Msk (1UL << CoreDebug_DEMCR_VC_HARDERR_Pos) /*!< CoreDebug DEMCR: VC_HARDERR Mask */ + +#define CoreDebug_DEMCR_VC_CORERESET_Pos 0U /*!< CoreDebug DEMCR: VC_CORERESET Position */ +#define CoreDebug_DEMCR_VC_CORERESET_Msk (1UL /*<< CoreDebug_DEMCR_VC_CORERESET_Pos*/) /*!< CoreDebug DEMCR: VC_CORERESET Mask */ + +/* Debug Authentication Control Register Definitions */ +#define CoreDebug_DAUTHCTRL_INTSPNIDEN_Pos 3U /*!< CoreDebug DAUTHCTRL: INTSPNIDEN, Position */ +#define CoreDebug_DAUTHCTRL_INTSPNIDEN_Msk (1UL << CoreDebug_DAUTHCTRL_INTSPNIDEN_Pos) /*!< CoreDebug DAUTHCTRL: INTSPNIDEN, Mask */ + +#define CoreDebug_DAUTHCTRL_SPNIDENSEL_Pos 2U /*!< CoreDebug DAUTHCTRL: SPNIDENSEL Position */ +#define CoreDebug_DAUTHCTRL_SPNIDENSEL_Msk (1UL << CoreDebug_DAUTHCTRL_SPNIDENSEL_Pos) /*!< CoreDebug DAUTHCTRL: SPNIDENSEL Mask */ + +#define CoreDebug_DAUTHCTRL_INTSPIDEN_Pos 1U /*!< CoreDebug DAUTHCTRL: INTSPIDEN Position */ +#define CoreDebug_DAUTHCTRL_INTSPIDEN_Msk (1UL << CoreDebug_DAUTHCTRL_INTSPIDEN_Pos) /*!< CoreDebug DAUTHCTRL: INTSPIDEN Mask */ + +#define CoreDebug_DAUTHCTRL_SPIDENSEL_Pos 0U /*!< CoreDebug DAUTHCTRL: SPIDENSEL Position */ +#define CoreDebug_DAUTHCTRL_SPIDENSEL_Msk (1UL /*<< CoreDebug_DAUTHCTRL_SPIDENSEL_Pos*/) /*!< CoreDebug DAUTHCTRL: SPIDENSEL Mask */ + +/* Debug Security Control and Status Register Definitions */ +#define CoreDebug_DSCSR_CDS_Pos 16U /*!< CoreDebug DSCSR: CDS Position */ +#define CoreDebug_DSCSR_CDS_Msk (1UL << CoreDebug_DSCSR_CDS_Pos) /*!< CoreDebug DSCSR: CDS Mask */ + +#define CoreDebug_DSCSR_SBRSEL_Pos 1U /*!< CoreDebug DSCSR: SBRSEL Position */ +#define CoreDebug_DSCSR_SBRSEL_Msk (1UL << CoreDebug_DSCSR_SBRSEL_Pos) /*!< CoreDebug DSCSR: SBRSEL Mask */ + +#define CoreDebug_DSCSR_SBRSELEN_Pos 0U /*!< CoreDebug DSCSR: SBRSELEN Position */ +#define CoreDebug_DSCSR_SBRSELEN_Msk (1UL /*<< CoreDebug_DSCSR_SBRSELEN_Pos*/) /*!< CoreDebug DSCSR: SBRSELEN Mask */ + +/*@} end of group CMSIS_CoreDebug */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_bitfield Core register bit field macros + \brief Macros for use with bit field definitions (xxx_Pos, xxx_Msk). + @{ + */ + +/** + \brief Mask and shift a bit field value for use in a register bit range. + \param[in] field Name of the register bit field. + \param[in] value Value of the bit field. This parameter is interpreted as an uint32_t type. + \return Masked and shifted value. +*/ +#define _VAL2FLD(field, value) (((uint32_t)(value) << field ## _Pos) & field ## _Msk) + +/** + \brief Mask and shift a register value to extract a bit filed value. + \param[in] field Name of the register bit field. + \param[in] value Value of register. This parameter is interpreted as an uint32_t type. + \return Masked and shifted bit field value. +*/ +#define _FLD2VAL(field, value) (((uint32_t)(value) & field ## _Msk) >> field ## _Pos) + +/*@} end of group CMSIS_core_bitfield */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_base Core Definitions + \brief Definitions for base addresses, unions, and structures. + @{ + */ + +/* Memory mapping of Core Hardware */ + #define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ + #define DWT_BASE (0xE0001000UL) /*!< DWT Base Address */ + #define TPI_BASE (0xE0040000UL) /*!< TPI Base Address */ + #define CoreDebug_BASE (0xE000EDF0UL) /*!< Core Debug Base Address */ + #define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */ + #define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */ + #define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */ + + + #define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */ + #define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */ + #define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */ + #define DWT ((DWT_Type *) DWT_BASE ) /*!< DWT configuration struct */ + #define TPI ((TPI_Type *) TPI_BASE ) /*!< TPI configuration struct */ + #define CoreDebug ((CoreDebug_Type *) CoreDebug_BASE ) /*!< Core Debug configuration struct */ + + #if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + #define MPU_BASE (SCS_BASE + 0x0D90UL) /*!< Memory Protection Unit */ + #define MPU ((MPU_Type *) MPU_BASE ) /*!< Memory Protection Unit */ + #endif + + #if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + #define SAU_BASE (SCS_BASE + 0x0DD0UL) /*!< Security Attribution Unit */ + #define SAU ((SAU_Type *) SAU_BASE ) /*!< Security Attribution Unit */ + #endif + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + #define SCS_BASE_NS (0xE002E000UL) /*!< System Control Space Base Address (non-secure address space) */ + #define CoreDebug_BASE_NS (0xE002EDF0UL) /*!< Core Debug Base Address (non-secure address space) */ + #define SysTick_BASE_NS (SCS_BASE_NS + 0x0010UL) /*!< SysTick Base Address (non-secure address space) */ + #define NVIC_BASE_NS (SCS_BASE_NS + 0x0100UL) /*!< NVIC Base Address (non-secure address space) */ + #define SCB_BASE_NS (SCS_BASE_NS + 0x0D00UL) /*!< System Control Block Base Address (non-secure address space) */ + + #define SCB_NS ((SCB_Type *) SCB_BASE_NS ) /*!< SCB configuration struct (non-secure address space) */ + #define SysTick_NS ((SysTick_Type *) SysTick_BASE_NS ) /*!< SysTick configuration struct (non-secure address space) */ + #define NVIC_NS ((NVIC_Type *) NVIC_BASE_NS ) /*!< NVIC configuration struct (non-secure address space) */ + #define CoreDebug_NS ((CoreDebug_Type *) CoreDebug_BASE_NS) /*!< Core Debug configuration struct (non-secure address space) */ + + #if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + #define MPU_BASE_NS (SCS_BASE_NS + 0x0D90UL) /*!< Memory Protection Unit (non-secure address space) */ + #define MPU_NS ((MPU_Type *) MPU_BASE_NS ) /*!< Memory Protection Unit (non-secure address space) */ + #endif + +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ +/*@} */ + + + +/******************************************************************************* + * Hardware Abstraction Layer + Core Function Interface contains: + - Core NVIC Functions + - Core SysTick Functions + - Core Register Access Functions + ******************************************************************************/ +/** + \defgroup CMSIS_Core_FunctionInterface Functions and Instructions Reference +*/ + + + +/* ########################## NVIC functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_NVICFunctions NVIC Functions + \brief Functions that manage interrupts and exceptions via the NVIC. + @{ + */ + +#ifdef CMSIS_NVIC_VIRTUAL + #ifndef CMSIS_NVIC_VIRTUAL_HEADER_FILE + #define CMSIS_NVIC_VIRTUAL_HEADER_FILE "cmsis_nvic_virtual.h" + #endif + #include CMSIS_NVIC_VIRTUAL_HEADER_FILE +#else +/*#define NVIC_SetPriorityGrouping __NVIC_SetPriorityGrouping not available for Cortex-M23 */ +/*#define NVIC_GetPriorityGrouping __NVIC_GetPriorityGrouping not available for Cortex-M23 */ + #define NVIC_EnableIRQ __NVIC_EnableIRQ + #define NVIC_GetEnableIRQ __NVIC_GetEnableIRQ + #define NVIC_DisableIRQ __NVIC_DisableIRQ + #define NVIC_GetPendingIRQ __NVIC_GetPendingIRQ + #define NVIC_SetPendingIRQ __NVIC_SetPendingIRQ + #define NVIC_ClearPendingIRQ __NVIC_ClearPendingIRQ + #define NVIC_GetActive __NVIC_GetActive + #define NVIC_SetPriority __NVIC_SetPriority + #define NVIC_GetPriority __NVIC_GetPriority + #define NVIC_SystemReset __NVIC_SystemReset +#endif /* CMSIS_NVIC_VIRTUAL */ + +#ifdef CMSIS_VECTAB_VIRTUAL + #ifndef CMSIS_VECTAB_VIRTUAL_HEADER_FILE + #define CMSIS_VECTAB_VIRTUAL_HEADER_FILE "cmsis_vectab_virtual.h" + #endif + #include CMSIS_VECTAB_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetVector __NVIC_SetVector + #define NVIC_GetVector __NVIC_GetVector +#endif /* (CMSIS_VECTAB_VIRTUAL) */ + +#define NVIC_USER_IRQ_OFFSET 16 + + +/* Special LR values for Secure/Non-Secure call handling and exception handling */ + +/* Function Return Payload (from ARMv8-M Architecture Reference Manual) LR value on entry from Secure BLXNS */ +#define FNC_RETURN (0xFEFFFFFFUL) /* bit [0] ignored when processing a branch */ + +/* The following EXC_RETURN mask values are used to evaluate the LR on exception entry */ +#define EXC_RETURN_PREFIX (0xFF000000UL) /* bits [31:24] set to indicate an EXC_RETURN value */ +#define EXC_RETURN_S (0x00000040UL) /* bit [6] stack used to push registers: 0=Non-secure 1=Secure */ +#define EXC_RETURN_DCRS (0x00000020UL) /* bit [5] stacking rules for called registers: 0=skipped 1=saved */ +#define EXC_RETURN_FTYPE (0x00000010UL) /* bit [4] allocate stack for floating-point context: 0=done 1=skipped */ +#define EXC_RETURN_MODE (0x00000008UL) /* bit [3] processor mode for return: 0=Handler mode 1=Thread mode */ +#define EXC_RETURN_SPSEL (0x00000004UL) /* bit [2] stack pointer used to restore context: 0=MSP 1=PSP */ +#define EXC_RETURN_ES (0x00000001UL) /* bit [0] security state exception was taken to: 0=Non-secure 1=Secure */ + +/* Integrity Signature (from ARMv8-M Architecture Reference Manual) for exception context stacking */ +#if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) /* Value for processors with floating-point extension: */ +#define EXC_INTEGRITY_SIGNATURE (0xFEFA125AUL) /* bit [0] SFTC must match LR bit[4] EXC_RETURN_FTYPE */ +#else +#define EXC_INTEGRITY_SIGNATURE (0xFEFA125BUL) /* Value for processors without floating-point extension */ +#endif + + +/* Interrupt Priorities are WORD accessible only under Armv6-M */ +/* The following MACROS handle generation of the register offset and byte masks */ +#define _BIT_SHIFT(IRQn) ( ((((uint32_t)(int32_t)(IRQn)) ) & 0x03UL) * 8UL) +#define _SHP_IDX(IRQn) ( (((((uint32_t)(int32_t)(IRQn)) & 0x0FUL)-8UL) >> 2UL) ) +#define _IP_IDX(IRQn) ( (((uint32_t)(int32_t)(IRQn)) >> 2UL) ) + +#define __NVIC_SetPriorityGrouping(X) (void)(X) +#define __NVIC_GetPriorityGrouping() (0U) + +/** + \brief Enable Interrupt + \details Enables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Interrupt Enable status + \details Returns a device specific interrupt enable status from the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt is not enabled. + \return 1 Interrupt is enabled. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t __NVIC_GetEnableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Disable Interrupt + \details Disables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_DisableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + __DSB(); + __ISB(); + } +} + + +/** + \brief Get Pending Interrupt + \details Reads the NVIC pending register and returns the pending bit for the specified device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt status is not pending. + \return 1 Interrupt status is pending. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t __NVIC_GetPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Set Pending Interrupt + \details Sets the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_SetPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Clear Pending Interrupt + \details Clears the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_ClearPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Active Interrupt + \details Reads the active register in the NVIC and returns the active bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt status is not active. + \return 1 Interrupt status is active. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t __NVIC_GetActive(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->IABR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +/** + \brief Get Interrupt Target State + \details Reads the interrupt target field in the NVIC and returns the interrupt target bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 if interrupt is assigned to Secure + \return 1 if interrupt is assigned to Non Secure + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t NVIC_GetTargetState(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Set Interrupt Target State + \details Sets the interrupt target field in the NVIC and returns the interrupt target bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 if interrupt is assigned to Secure + 1 if interrupt is assigned to Non Secure + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t NVIC_SetTargetState(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] |= ((uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL))); + return((uint32_t)(((NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Clear Interrupt Target State + \details Clears the interrupt target field in the NVIC and returns the interrupt target bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 if interrupt is assigned to Secure + 1 if interrupt is assigned to Non Secure + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t NVIC_ClearTargetState(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] &= ~((uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL))); + return((uint32_t)(((NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ + + +/** + \brief Set Interrupt Priority + \details Sets the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \param [in] priority Priority to set. + \note The priority cannot be set for every processor exception. + */ +__STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->IPR[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IPR[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); + } + else + { + SCB->SHPR[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHPR[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); + } +} + + +/** + \brief Get Interrupt Priority + \details Reads the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Interrupt Priority. + Value is aligned automatically to the implemented priority bits of the microcontroller. + */ +__STATIC_INLINE uint32_t __NVIC_GetPriority(IRQn_Type IRQn) +{ + + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->IPR[ _IP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); + } + else + { + return((uint32_t)(((SCB->SHPR[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); + } +} + + +/** + \brief Encode Priority + \details Encodes the priority for an interrupt with the given priority group, + preemptive priority value, and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. + \param [in] PriorityGroup Used priority group. + \param [in] PreemptPriority Preemptive priority value (starting from 0). + \param [in] SubPriority Subpriority value (starting from 0). + \return Encoded priority. Value can be used in the function \ref NVIC_SetPriority(). + */ +__STATIC_INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + return ( + ((PreemptPriority & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL)) << SubPriorityBits) | + ((SubPriority & (uint32_t)((1UL << (SubPriorityBits )) - 1UL))) + ); +} + + +/** + \brief Decode Priority + \details Decodes an interrupt priority value with a given priority group to + preemptive priority value and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS) the smallest possible priority group is set. + \param [in] Priority Priority value, which can be retrieved with the function \ref NVIC_GetPriority(). + \param [in] PriorityGroup Used priority group. + \param [out] pPreemptPriority Preemptive priority value (starting from 0). + \param [out] pSubPriority Subpriority value (starting from 0). + */ +__STATIC_INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGroup, uint32_t* const pPreemptPriority, uint32_t* const pSubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + *pPreemptPriority = (Priority >> SubPriorityBits) & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL); + *pSubPriority = (Priority ) & (uint32_t)((1UL << (SubPriorityBits )) - 1UL); +} + + +/** + \brief Set Interrupt Vector + \details Sets an interrupt vector in SRAM based interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + VTOR must been relocated to SRAM before. + If VTOR is not present address 0 must be mapped to SRAM. + \param [in] IRQn Interrupt number + \param [in] vector Address of interrupt handler function + */ +__STATIC_INLINE void __NVIC_SetVector(IRQn_Type IRQn, uint32_t vector) +{ +#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U) + uint32_t *vectors = (uint32_t *)SCB->VTOR; +#else + uint32_t *vectors = (uint32_t *)0x0U; +#endif + vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET] = vector; +} + + +/** + \brief Get Interrupt Vector + \details Reads an interrupt vector from interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Address of interrupt handler function + */ +__STATIC_INLINE uint32_t __NVIC_GetVector(IRQn_Type IRQn) +{ +#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U) + uint32_t *vectors = (uint32_t *)SCB->VTOR; +#else + uint32_t *vectors = (uint32_t *)0x0U; +#endif + return vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET]; +} + + +/** + \brief System Reset + \details Initiates a system reset request to reset the MCU. + */ +__NO_RETURN __STATIC_INLINE void __NVIC_SystemReset(void) +{ + __DSB(); /* Ensure all outstanding memory accesses included + buffered write are completed before reset */ + SCB->AIRCR = ((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + SCB_AIRCR_SYSRESETREQ_Msk); + __DSB(); /* Ensure completion of memory access */ + + for(;;) /* wait until reset */ + { + __NOP(); + } +} + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +/** + \brief Enable Interrupt (non-secure) + \details Enables a device specific interrupt in the non-secure NVIC interrupt controller when in secure state. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void TZ_NVIC_EnableIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Interrupt Enable status (non-secure) + \details Returns a device specific interrupt enable status from the non-secure NVIC interrupt controller when in secure state. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt is not enabled. + \return 1 Interrupt is enabled. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t TZ_NVIC_GetEnableIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC_NS->ISER[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Disable Interrupt (non-secure) + \details Disables a device specific interrupt in the non-secure NVIC interrupt controller when in secure state. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void TZ_NVIC_DisableIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->ICER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Pending Interrupt (non-secure) + \details Reads the NVIC pending register in the non-secure NVIC when in secure state and returns the pending bit for the specified device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt status is not pending. + \return 1 Interrupt status is pending. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t TZ_NVIC_GetPendingIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC_NS->ISPR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Set Pending Interrupt (non-secure) + \details Sets the pending bit of a device specific interrupt in the non-secure NVIC pending register when in secure state. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void TZ_NVIC_SetPendingIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->ISPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Clear Pending Interrupt (non-secure) + \details Clears the pending bit of a device specific interrupt in the non-secure NVIC pending register when in secure state. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void TZ_NVIC_ClearPendingIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->ICPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Active Interrupt (non-secure) + \details Reads the active register in non-secure NVIC when in secure state and returns the active bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt status is not active. + \return 1 Interrupt status is active. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t TZ_NVIC_GetActive_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC_NS->IABR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Set Interrupt Priority (non-secure) + \details Sets the priority of a non-secure device specific interrupt or a non-secure processor exception when in secure state. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \param [in] priority Priority to set. + \note The priority cannot be set for every non-secure processor exception. + */ +__STATIC_INLINE void TZ_NVIC_SetPriority_NS(IRQn_Type IRQn, uint32_t priority) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->IPR[_IP_IDX(IRQn)] = ((uint32_t)(NVIC_NS->IPR[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); + } + else + { + SCB_NS->SHPR[_SHP_IDX(IRQn)] = ((uint32_t)(SCB_NS->SHPR[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); + } +} + + +/** + \brief Get Interrupt Priority (non-secure) + \details Reads the priority of a non-secure device specific interrupt or a non-secure processor exception when in secure state. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Interrupt Priority. Value is aligned automatically to the implemented priority bits of the microcontroller. + */ +__STATIC_INLINE uint32_t TZ_NVIC_GetPriority_NS(IRQn_Type IRQn) +{ + + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC_NS->IPR[ _IP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); + } + else + { + return((uint32_t)(((SCB_NS->SHPR[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); + } +} +#endif /* defined (__ARM_FEATURE_CMSE) &&(__ARM_FEATURE_CMSE == 3U) */ + +/*@} end of CMSIS_Core_NVICFunctions */ + +/* ########################## MPU functions #################################### */ + +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + +#include "mpu_armv8.h" + +#endif + +/* ########################## FPU functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_FpuFunctions FPU Functions + \brief Function that provides FPU type. + @{ + */ + +/** + \brief get FPU type + \details returns the FPU type + \returns + - \b 0: No FPU + - \b 1: Single precision FPU + - \b 2: Double + Single precision FPU + */ +__STATIC_INLINE uint32_t SCB_GetFPUType(void) +{ + return 0U; /* No FPU */ +} + + +/*@} end of CMSIS_Core_FpuFunctions */ + + + +/* ########################## SAU functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_SAUFunctions SAU Functions + \brief Functions that configure the SAU. + @{ + */ + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + +/** + \brief Enable SAU + \details Enables the Security Attribution Unit (SAU). + */ +__STATIC_INLINE void TZ_SAU_Enable(void) +{ + SAU->CTRL |= (SAU_CTRL_ENABLE_Msk); +} + + + +/** + \brief Disable SAU + \details Disables the Security Attribution Unit (SAU). + */ +__STATIC_INLINE void TZ_SAU_Disable(void) +{ + SAU->CTRL &= ~(SAU_CTRL_ENABLE_Msk); +} + +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ + +/*@} end of CMSIS_Core_SAUFunctions */ + + + + +/* ################################## SysTick function ############################################ */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_SysTickFunctions SysTick Functions + \brief Functions that configure the System. + @{ + */ + +#if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U) + +/** + \brief System Tick Configuration + \details Initializes the System Timer and its interrupt, and starts the System Tick Timer. + Counter is in free running mode to generate periodic interrupts. + \param [in] ticks Number of ticks between two interrupts. + \return 0 Function succeeded. + \return 1 Function failed. + \note When the variable __Vendor_SysTickConfig is set to 1, then the + function SysTick_Config is not included. In this case, the file device.h + must contain a vendor-specific implementation of this function. + */ +__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) +{ + if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) + { + return (1UL); /* Reload value impossible */ + } + + SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ + NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ + SysTick->VAL = 0UL; /* Load the SysTick Counter Value */ + SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + SysTick_CTRL_TICKINT_Msk | + SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ + return (0UL); /* Function successful */ +} + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +/** + \brief System Tick Configuration (non-secure) + \details Initializes the non-secure System Timer and its interrupt when in secure state, and starts the System Tick Timer. + Counter is in free running mode to generate periodic interrupts. + \param [in] ticks Number of ticks between two interrupts. + \return 0 Function succeeded. + \return 1 Function failed. + \note When the variable __Vendor_SysTickConfig is set to 1, then the + function TZ_SysTick_Config_NS is not included. In this case, the file device.h + must contain a vendor-specific implementation of this function. + + */ +__STATIC_INLINE uint32_t TZ_SysTick_Config_NS(uint32_t ticks) +{ + if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) + { + return (1UL); /* Reload value impossible */ + } + + SysTick_NS->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ + TZ_NVIC_SetPriority_NS (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ + SysTick_NS->VAL = 0UL; /* Load the SysTick Counter Value */ + SysTick_NS->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + SysTick_CTRL_TICKINT_Msk | + SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ + return (0UL); /* Function successful */ +} +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ + +#endif + +/*@} end of CMSIS_Core_SysTickFunctions */ + + + + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_CM23_H_DEPENDANT */ + +#endif /* __CMSIS_GENERIC */ diff --git a/lib/cmsis/inc/core_cm3.h b/lib/cmsis/inc/core_cm3.h index b4ac4c7b05..ea5405088c 100644 --- a/lib/cmsis/inc/core_cm3.h +++ b/lib/cmsis/inc/core_cm3.h @@ -1,40 +1,30 @@ /**************************************************************************//** * @file core_cm3.h * @brief CMSIS Cortex-M3 Core Peripheral Access Layer Header File - * @version V4.30 - * @date 20. October 2015 + * @version V5.1.0 + * @date 13. March 2019 ******************************************************************************/ -/* Copyright (c) 2009 - 2015 ARM LIMITED - - All rights reserved. - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 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. - - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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. - ---------------------------------------------------------------------------*/ - +/* + * Copyright (c) 2009-2019 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #if defined ( __ICCARM__ ) - #pragma system_include /* treat file as system include file for MISRA check */ -#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined (__clang__) #pragma clang system_header /* treat file as system include file */ #endif @@ -70,53 +60,15 @@ @{ */ +#include "cmsis_version.h" + /* CMSIS CM3 definitions */ -#define __CM3_CMSIS_VERSION_MAIN (0x04U) /*!< [31:16] CMSIS HAL main version */ -#define __CM3_CMSIS_VERSION_SUB (0x1EU) /*!< [15:0] CMSIS HAL sub version */ +#define __CM3_CMSIS_VERSION_MAIN (__CM_CMSIS_VERSION_MAIN) /*!< \deprecated [31:16] CMSIS HAL main version */ +#define __CM3_CMSIS_VERSION_SUB (__CM_CMSIS_VERSION_SUB) /*!< \deprecated [15:0] CMSIS HAL sub version */ #define __CM3_CMSIS_VERSION ((__CM3_CMSIS_VERSION_MAIN << 16U) | \ - __CM3_CMSIS_VERSION_SUB ) /*!< CMSIS HAL version number */ + __CM3_CMSIS_VERSION_SUB ) /*!< \deprecated CMSIS HAL version number */ -#define __CORTEX_M (0x03U) /*!< Cortex-M Core */ - - -#if defined ( __CC_ARM ) - #define __ASM __asm /*!< asm keyword for ARM Compiler */ - #define __INLINE __inline /*!< inline keyword for ARM Compiler */ - #define __STATIC_INLINE static __inline - -#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) - #define __ASM __asm /*!< asm keyword for ARM Compiler */ - #define __INLINE __inline /*!< inline keyword for ARM Compiler */ - #define __STATIC_INLINE static __inline - -#elif defined ( __GNUC__ ) - #define __ASM __asm /*!< asm keyword for GNU Compiler */ - #define __INLINE inline /*!< inline keyword for GNU Compiler */ - #define __STATIC_INLINE static inline - -#elif defined ( __ICCARM__ ) - #define __ASM __asm /*!< asm keyword for IAR Compiler */ - #define __INLINE inline /*!< inline keyword for IAR Compiler. Only available in High optimization mode! */ - #define __STATIC_INLINE static inline - -#elif defined ( __TMS470__ ) - #define __ASM __asm /*!< asm keyword for TI CCS Compiler */ - #define __STATIC_INLINE static inline - -#elif defined ( __TASKING__ ) - #define __ASM __asm /*!< asm keyword for TASKING Compiler */ - #define __INLINE inline /*!< inline keyword for TASKING Compiler */ - #define __STATIC_INLINE static inline - -#elif defined ( __CSMC__ ) - #define __packed - #define __ASM _asm /*!< asm keyword for COSMIC Compiler */ - #define __INLINE inline /*!< inline keyword for COSMIC Compiler. Use -pc99 on compile line */ - #define __STATIC_INLINE static inline - -#else - #error Unknown compiler -#endif +#define __CORTEX_M (3U) /*!< Cortex-M Core */ /** __FPU_USED indicates whether an FPU is used or not. This core does not support an FPU at all @@ -128,8 +80,8 @@ #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif -#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) - #if defined __ARM_PCS_VFP +#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #if defined __ARM_FP #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif @@ -143,7 +95,7 @@ #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif -#elif defined ( __TMS470__ ) +#elif defined ( __TI_ARM__ ) #if defined __TI_VFP_SUPPORT__ #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif @@ -160,8 +112,8 @@ #endif -#include "core_cmInstr.h" /* Core Instruction Access */ -#include "core_cmFunc.h" /* Core Function Access */ +#include "cmsis_compiler.h" /* CMSIS compiler specific defines */ + #ifdef __cplusplus } @@ -191,7 +143,7 @@ #endif #ifndef __NVIC_PRIO_BITS - #define __NVIC_PRIO_BITS 4U + #define __NVIC_PRIO_BITS 3U #warning "__NVIC_PRIO_BITS not defined in device header file; using default!" #endif @@ -308,9 +260,11 @@ typedef union struct { uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ - uint32_t _reserved0:15; /*!< bit: 9..23 Reserved */ - uint32_t T:1; /*!< bit: 24 Thumb bit (read 0) */ - uint32_t IT:2; /*!< bit: 25..26 saved IT state (read 0) */ + uint32_t _reserved0:1; /*!< bit: 9 Reserved */ + uint32_t ICI_IT_1:6; /*!< bit: 10..15 ICI/IT part 1 */ + uint32_t _reserved1:8; /*!< bit: 16..23 Reserved */ + uint32_t T:1; /*!< bit: 24 Thumb bit */ + uint32_t ICI_IT_2:2; /*!< bit: 25..26 ICI/IT part 2 */ uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ uint32_t C:1; /*!< bit: 29 Carry condition code flag */ @@ -336,12 +290,15 @@ typedef union #define xPSR_Q_Pos 27U /*!< xPSR: Q Position */ #define xPSR_Q_Msk (1UL << xPSR_Q_Pos) /*!< xPSR: Q Mask */ -#define xPSR_IT_Pos 25U /*!< xPSR: IT Position */ -#define xPSR_IT_Msk (3UL << xPSR_IT_Pos) /*!< xPSR: IT Mask */ +#define xPSR_ICI_IT_2_Pos 25U /*!< xPSR: ICI/IT part 2 Position */ +#define xPSR_ICI_IT_2_Msk (3UL << xPSR_ICI_IT_2_Pos) /*!< xPSR: ICI/IT part 2 Mask */ #define xPSR_T_Pos 24U /*!< xPSR: T Position */ #define xPSR_T_Msk (1UL << xPSR_T_Pos) /*!< xPSR: T Mask */ +#define xPSR_ICI_IT_1_Pos 10U /*!< xPSR: ICI/IT part 1 Position */ +#define xPSR_ICI_IT_1_Msk (0x3FUL << xPSR_ICI_IT_1_Pos) /*!< xPSR: ICI/IT part 1 Mask */ + #define xPSR_ISR_Pos 0U /*!< xPSR: ISR Position */ #define xPSR_ISR_Msk (0x1FFUL /*<< xPSR_ISR_Pos*/) /*!< xPSR: ISR Mask */ @@ -385,7 +342,7 @@ typedef struct __IOM uint32_t ISER[8U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ uint32_t RESERVED0[24U]; __IOM uint32_t ICER[8U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ - uint32_t RSERVED1[24U]; + uint32_t RESERVED1[24U]; __IOM uint32_t ISPR[8U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ uint32_t RESERVED2[24U]; __IOM uint32_t ICPR[8U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ @@ -487,7 +444,7 @@ typedef struct #define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL /*<< SCB_ICSR_VECTACTIVE_Pos*/) /*!< SCB ICSR: VECTACTIVE Mask */ /* SCB Vector Table Offset Register Definitions */ -#if (__CM3_REV < 0x0201U) /* core r2p1 */ +#if defined (__CM3_REV) && (__CM3_REV < 0x0201U) /* core r2p1 */ #define SCB_VTOR_TBLBASE_Pos 29U /*!< SCB VTOR: TBLBASE Position */ #define SCB_VTOR_TBLBASE_Msk (1UL << SCB_VTOR_TBLBASE_Pos) /*!< SCB VTOR: TBLBASE Mask */ @@ -602,6 +559,60 @@ typedef struct #define SCB_CFSR_MEMFAULTSR_Pos 0U /*!< SCB CFSR: Memory Manage Fault Status Register Position */ #define SCB_CFSR_MEMFAULTSR_Msk (0xFFUL /*<< SCB_CFSR_MEMFAULTSR_Pos*/) /*!< SCB CFSR: Memory Manage Fault Status Register Mask */ +/* MemManage Fault Status Register (part of SCB Configurable Fault Status Register) */ +#define SCB_CFSR_MMARVALID_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 7U) /*!< SCB CFSR (MMFSR): MMARVALID Position */ +#define SCB_CFSR_MMARVALID_Msk (1UL << SCB_CFSR_MMARVALID_Pos) /*!< SCB CFSR (MMFSR): MMARVALID Mask */ + +#define SCB_CFSR_MSTKERR_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 4U) /*!< SCB CFSR (MMFSR): MSTKERR Position */ +#define SCB_CFSR_MSTKERR_Msk (1UL << SCB_CFSR_MSTKERR_Pos) /*!< SCB CFSR (MMFSR): MSTKERR Mask */ + +#define SCB_CFSR_MUNSTKERR_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 3U) /*!< SCB CFSR (MMFSR): MUNSTKERR Position */ +#define SCB_CFSR_MUNSTKERR_Msk (1UL << SCB_CFSR_MUNSTKERR_Pos) /*!< SCB CFSR (MMFSR): MUNSTKERR Mask */ + +#define SCB_CFSR_DACCVIOL_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 1U) /*!< SCB CFSR (MMFSR): DACCVIOL Position */ +#define SCB_CFSR_DACCVIOL_Msk (1UL << SCB_CFSR_DACCVIOL_Pos) /*!< SCB CFSR (MMFSR): DACCVIOL Mask */ + +#define SCB_CFSR_IACCVIOL_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 0U) /*!< SCB CFSR (MMFSR): IACCVIOL Position */ +#define SCB_CFSR_IACCVIOL_Msk (1UL /*<< SCB_CFSR_IACCVIOL_Pos*/) /*!< SCB CFSR (MMFSR): IACCVIOL Mask */ + +/* BusFault Status Register (part of SCB Configurable Fault Status Register) */ +#define SCB_CFSR_BFARVALID_Pos (SCB_CFSR_BUSFAULTSR_Pos + 7U) /*!< SCB CFSR (BFSR): BFARVALID Position */ +#define SCB_CFSR_BFARVALID_Msk (1UL << SCB_CFSR_BFARVALID_Pos) /*!< SCB CFSR (BFSR): BFARVALID Mask */ + +#define SCB_CFSR_STKERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 4U) /*!< SCB CFSR (BFSR): STKERR Position */ +#define SCB_CFSR_STKERR_Msk (1UL << SCB_CFSR_STKERR_Pos) /*!< SCB CFSR (BFSR): STKERR Mask */ + +#define SCB_CFSR_UNSTKERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 3U) /*!< SCB CFSR (BFSR): UNSTKERR Position */ +#define SCB_CFSR_UNSTKERR_Msk (1UL << SCB_CFSR_UNSTKERR_Pos) /*!< SCB CFSR (BFSR): UNSTKERR Mask */ + +#define SCB_CFSR_IMPRECISERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 2U) /*!< SCB CFSR (BFSR): IMPRECISERR Position */ +#define SCB_CFSR_IMPRECISERR_Msk (1UL << SCB_CFSR_IMPRECISERR_Pos) /*!< SCB CFSR (BFSR): IMPRECISERR Mask */ + +#define SCB_CFSR_PRECISERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 1U) /*!< SCB CFSR (BFSR): PRECISERR Position */ +#define SCB_CFSR_PRECISERR_Msk (1UL << SCB_CFSR_PRECISERR_Pos) /*!< SCB CFSR (BFSR): PRECISERR Mask */ + +#define SCB_CFSR_IBUSERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 0U) /*!< SCB CFSR (BFSR): IBUSERR Position */ +#define SCB_CFSR_IBUSERR_Msk (1UL << SCB_CFSR_IBUSERR_Pos) /*!< SCB CFSR (BFSR): IBUSERR Mask */ + +/* UsageFault Status Register (part of SCB Configurable Fault Status Register) */ +#define SCB_CFSR_DIVBYZERO_Pos (SCB_CFSR_USGFAULTSR_Pos + 9U) /*!< SCB CFSR (UFSR): DIVBYZERO Position */ +#define SCB_CFSR_DIVBYZERO_Msk (1UL << SCB_CFSR_DIVBYZERO_Pos) /*!< SCB CFSR (UFSR): DIVBYZERO Mask */ + +#define SCB_CFSR_UNALIGNED_Pos (SCB_CFSR_USGFAULTSR_Pos + 8U) /*!< SCB CFSR (UFSR): UNALIGNED Position */ +#define SCB_CFSR_UNALIGNED_Msk (1UL << SCB_CFSR_UNALIGNED_Pos) /*!< SCB CFSR (UFSR): UNALIGNED Mask */ + +#define SCB_CFSR_NOCP_Pos (SCB_CFSR_USGFAULTSR_Pos + 3U) /*!< SCB CFSR (UFSR): NOCP Position */ +#define SCB_CFSR_NOCP_Msk (1UL << SCB_CFSR_NOCP_Pos) /*!< SCB CFSR (UFSR): NOCP Mask */ + +#define SCB_CFSR_INVPC_Pos (SCB_CFSR_USGFAULTSR_Pos + 2U) /*!< SCB CFSR (UFSR): INVPC Position */ +#define SCB_CFSR_INVPC_Msk (1UL << SCB_CFSR_INVPC_Pos) /*!< SCB CFSR (UFSR): INVPC Mask */ + +#define SCB_CFSR_INVSTATE_Pos (SCB_CFSR_USGFAULTSR_Pos + 1U) /*!< SCB CFSR (UFSR): INVSTATE Position */ +#define SCB_CFSR_INVSTATE_Msk (1UL << SCB_CFSR_INVSTATE_Pos) /*!< SCB CFSR (UFSR): INVSTATE Mask */ + +#define SCB_CFSR_UNDEFINSTR_Pos (SCB_CFSR_USGFAULTSR_Pos + 0U) /*!< SCB CFSR (UFSR): UNDEFINSTR Position */ +#define SCB_CFSR_UNDEFINSTR_Msk (1UL << SCB_CFSR_UNDEFINSTR_Pos) /*!< SCB CFSR (UFSR): UNDEFINSTR Mask */ + /* SCB Hard Fault Status Register Definitions */ #define SCB_HFSR_DEBUGEVT_Pos 31U /*!< SCB HFSR: DEBUGEVT Position */ #define SCB_HFSR_DEBUGEVT_Msk (1UL << SCB_HFSR_DEBUGEVT_Pos) /*!< SCB HFSR: DEBUGEVT Mask */ @@ -645,7 +656,7 @@ typedef struct { uint32_t RESERVED0[1U]; __IM uint32_t ICTR; /*!< Offset: 0x004 (R/ ) Interrupt Controller Type Register */ -#if ((defined __CM3_REV) && (__CM3_REV >= 0x200U)) +#if defined (__CM3_REV) && (__CM3_REV >= 0x200U) __IOM uint32_t ACTLR; /*!< Offset: 0x008 (R/W) Auxiliary Control Register */ #else uint32_t RESERVED1[1U]; @@ -657,6 +668,12 @@ typedef struct #define SCnSCB_ICTR_INTLINESNUM_Msk (0xFUL /*<< SCnSCB_ICTR_INTLINESNUM_Pos*/) /*!< ICTR: INTLINESNUM Mask */ /* Auxiliary Control Register Definitions */ +#if defined (__CM3_REV) && (__CM3_REV >= 0x200U) +#define SCnSCB_ACTLR_DISOOFP_Pos 9U /*!< ACTLR: DISOOFP Position */ +#define SCnSCB_ACTLR_DISOOFP_Msk (1UL << SCnSCB_ACTLR_DISOOFP_Pos) /*!< ACTLR: DISOOFP Mask */ + +#define SCnSCB_ACTLR_DISFPCA_Pos 8U /*!< ACTLR: DISFPCA Position */ +#define SCnSCB_ACTLR_DISFPCA_Msk (1UL << SCnSCB_ACTLR_DISFPCA_Pos) /*!< ACTLR: DISFPCA Mask */ #define SCnSCB_ACTLR_DISFOLD_Pos 2U /*!< ACTLR: DISFOLD Position */ #define SCnSCB_ACTLR_DISFOLD_Msk (1UL << SCnSCB_ACTLR_DISFOLD_Pos) /*!< ACTLR: DISFOLD Mask */ @@ -666,6 +683,7 @@ typedef struct #define SCnSCB_ACTLR_DISMCYCINT_Pos 0U /*!< ACTLR: DISMCYCINT Position */ #define SCnSCB_ACTLR_DISMCYCINT_Msk (1UL /*<< SCnSCB_ACTLR_DISMCYCINT_Pos*/) /*!< ACTLR: DISMCYCINT Mask */ +#endif /*@} end of group CMSIS_SCnotSCB */ @@ -746,10 +764,7 @@ typedef struct __IOM uint32_t TPR; /*!< Offset: 0xE40 (R/W) ITM Trace Privilege Register */ uint32_t RESERVED2[15U]; __IOM uint32_t TCR; /*!< Offset: 0xE80 (R/W) ITM Trace Control Register */ - uint32_t RESERVED3[29U]; - __OM uint32_t IWR; /*!< Offset: 0xEF8 ( /W) ITM Integration Write Register */ - __IM uint32_t IRR; /*!< Offset: 0xEFC (R/ ) ITM Integration Read Register */ - __IOM uint32_t IMCR; /*!< Offset: 0xF00 (R/W) ITM Integration Mode Control Register */ + uint32_t RESERVED3[32U]; uint32_t RESERVED4[43U]; __OM uint32_t LAR; /*!< Offset: 0xFB0 ( /W) ITM Lock Access Register */ __IM uint32_t LSR; /*!< Offset: 0xFB4 (R/ ) ITM Lock Status Register */ @@ -770,7 +785,7 @@ typedef struct /* ITM Trace Privilege Register Definitions */ #define ITM_TPR_PRIVMASK_Pos 0U /*!< ITM TPR: PRIVMASK Position */ -#define ITM_TPR_PRIVMASK_Msk (0xFUL /*<< ITM_TPR_PRIVMASK_Pos*/) /*!< ITM TPR: PRIVMASK Mask */ +#define ITM_TPR_PRIVMASK_Msk (0xFFFFFFFFUL /*<< ITM_TPR_PRIVMASK_Pos*/) /*!< ITM TPR: PRIVMASK Mask */ /* ITM Trace Control Register Definitions */ #define ITM_TCR_BUSY_Pos 23U /*!< ITM TCR: BUSY Position */ @@ -800,18 +815,6 @@ typedef struct #define ITM_TCR_ITMENA_Pos 0U /*!< ITM TCR: ITM Enable bit Position */ #define ITM_TCR_ITMENA_Msk (1UL /*<< ITM_TCR_ITMENA_Pos*/) /*!< ITM TCR: ITM Enable bit Mask */ -/* ITM Integration Write Register Definitions */ -#define ITM_IWR_ATVALIDM_Pos 0U /*!< ITM IWR: ATVALIDM Position */ -#define ITM_IWR_ATVALIDM_Msk (1UL /*<< ITM_IWR_ATVALIDM_Pos*/) /*!< ITM IWR: ATVALIDM Mask */ - -/* ITM Integration Read Register Definitions */ -#define ITM_IRR_ATREADYM_Pos 0U /*!< ITM IRR: ATREADYM Position */ -#define ITM_IRR_ATREADYM_Msk (1UL /*<< ITM_IRR_ATREADYM_Pos*/) /*!< ITM IRR: ATREADYM Mask */ - -/* ITM Integration Mode Control Register Definitions */ -#define ITM_IMCR_INTEGRATION_Pos 0U /*!< ITM IMCR: INTEGRATION Position */ -#define ITM_IMCR_INTEGRATION_Msk (1UL /*<< ITM_IMCR_INTEGRATION_Pos*/) /*!< ITM IMCR: INTEGRATION Mask */ - /* ITM Lock Status Register Definitions */ #define ITM_LSR_ByteAcc_Pos 2U /*!< ITM LSR: ByteAcc Position */ #define ITM_LSR_ByteAcc_Msk (1UL << ITM_LSR_ByteAcc_Pos) /*!< ITM LSR: ByteAcc Mask */ @@ -984,7 +987,7 @@ typedef struct */ typedef struct { - __IOM uint32_t SSPSR; /*!< Offset: 0x000 (R/ ) Supported Parallel Port Size Register */ + __IM uint32_t SSPSR; /*!< Offset: 0x000 (R/ ) Supported Parallel Port Size Register */ __IOM uint32_t CSPSR; /*!< Offset: 0x004 (R/W) Current Parallel Port Size Register */ uint32_t RESERVED0[2U]; __IOM uint32_t ACPR; /*!< Offset: 0x010 (R/W) Asynchronous Clock Prescaler Register */ @@ -995,7 +998,7 @@ typedef struct __IOM uint32_t FFCR; /*!< Offset: 0x304 (R/W) Formatter and Flush Control Register */ __IM uint32_t FSCR; /*!< Offset: 0x308 (R/ ) Formatter Synchronization Counter Register */ uint32_t RESERVED3[759U]; - __IM uint32_t TRIGGER; /*!< Offset: 0xEE8 (R/ ) TRIGGER */ + __IM uint32_t TRIGGER; /*!< Offset: 0xEE8 (R/ ) TRIGGER Register */ __IM uint32_t FIFO0; /*!< Offset: 0xEEC (R/ ) Integration ETM Data */ __IM uint32_t ITATBCTR2; /*!< Offset: 0xEF0 (R/ ) ITATBCTR2 */ uint32_t RESERVED4[1U]; @@ -1044,13 +1047,13 @@ typedef struct /* TPI Integration ETM Data Register Definitions (FIFO0) */ #define TPI_FIFO0_ITM_ATVALID_Pos 29U /*!< TPI FIFO0: ITM_ATVALID Position */ -#define TPI_FIFO0_ITM_ATVALID_Msk (0x3UL << TPI_FIFO0_ITM_ATVALID_Pos) /*!< TPI FIFO0: ITM_ATVALID Mask */ +#define TPI_FIFO0_ITM_ATVALID_Msk (0x1UL << TPI_FIFO0_ITM_ATVALID_Pos) /*!< TPI FIFO0: ITM_ATVALID Mask */ #define TPI_FIFO0_ITM_bytecount_Pos 27U /*!< TPI FIFO0: ITM_bytecount Position */ #define TPI_FIFO0_ITM_bytecount_Msk (0x3UL << TPI_FIFO0_ITM_bytecount_Pos) /*!< TPI FIFO0: ITM_bytecount Mask */ #define TPI_FIFO0_ETM_ATVALID_Pos 26U /*!< TPI FIFO0: ETM_ATVALID Position */ -#define TPI_FIFO0_ETM_ATVALID_Msk (0x3UL << TPI_FIFO0_ETM_ATVALID_Pos) /*!< TPI FIFO0: ETM_ATVALID Mask */ +#define TPI_FIFO0_ETM_ATVALID_Msk (0x1UL << TPI_FIFO0_ETM_ATVALID_Pos) /*!< TPI FIFO0: ETM_ATVALID Mask */ #define TPI_FIFO0_ETM_bytecount_Pos 24U /*!< TPI FIFO0: ETM_bytecount Position */ #define TPI_FIFO0_ETM_bytecount_Msk (0x3UL << TPI_FIFO0_ETM_bytecount_Pos) /*!< TPI FIFO0: ETM_bytecount Mask */ @@ -1065,18 +1068,21 @@ typedef struct #define TPI_FIFO0_ETM0_Msk (0xFFUL /*<< TPI_FIFO0_ETM0_Pos*/) /*!< TPI FIFO0: ETM0 Mask */ /* TPI ITATBCTR2 Register Definitions */ -#define TPI_ITATBCTR2_ATREADY_Pos 0U /*!< TPI ITATBCTR2: ATREADY Position */ -#define TPI_ITATBCTR2_ATREADY_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY_Pos*/) /*!< TPI ITATBCTR2: ATREADY Mask */ +#define TPI_ITATBCTR2_ATREADY2_Pos 0U /*!< TPI ITATBCTR2: ATREADY2 Position */ +#define TPI_ITATBCTR2_ATREADY2_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY2_Pos*/) /*!< TPI ITATBCTR2: ATREADY2 Mask */ + +#define TPI_ITATBCTR2_ATREADY1_Pos 0U /*!< TPI ITATBCTR2: ATREADY1 Position */ +#define TPI_ITATBCTR2_ATREADY1_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY1_Pos*/) /*!< TPI ITATBCTR2: ATREADY1 Mask */ /* TPI Integration ITM Data Register Definitions (FIFO1) */ #define TPI_FIFO1_ITM_ATVALID_Pos 29U /*!< TPI FIFO1: ITM_ATVALID Position */ -#define TPI_FIFO1_ITM_ATVALID_Msk (0x3UL << TPI_FIFO1_ITM_ATVALID_Pos) /*!< TPI FIFO1: ITM_ATVALID Mask */ +#define TPI_FIFO1_ITM_ATVALID_Msk (0x1UL << TPI_FIFO1_ITM_ATVALID_Pos) /*!< TPI FIFO1: ITM_ATVALID Mask */ #define TPI_FIFO1_ITM_bytecount_Pos 27U /*!< TPI FIFO1: ITM_bytecount Position */ #define TPI_FIFO1_ITM_bytecount_Msk (0x3UL << TPI_FIFO1_ITM_bytecount_Pos) /*!< TPI FIFO1: ITM_bytecount Mask */ #define TPI_FIFO1_ETM_ATVALID_Pos 26U /*!< TPI FIFO1: ETM_ATVALID Position */ -#define TPI_FIFO1_ETM_ATVALID_Msk (0x3UL << TPI_FIFO1_ETM_ATVALID_Pos) /*!< TPI FIFO1: ETM_ATVALID Mask */ +#define TPI_FIFO1_ETM_ATVALID_Msk (0x1UL << TPI_FIFO1_ETM_ATVALID_Pos) /*!< TPI FIFO1: ETM_ATVALID Mask */ #define TPI_FIFO1_ETM_bytecount_Pos 24U /*!< TPI FIFO1: ETM_bytecount Position */ #define TPI_FIFO1_ETM_bytecount_Msk (0x3UL << TPI_FIFO1_ETM_bytecount_Pos) /*!< TPI FIFO1: ETM_bytecount Mask */ @@ -1091,12 +1097,15 @@ typedef struct #define TPI_FIFO1_ITM0_Msk (0xFFUL /*<< TPI_FIFO1_ITM0_Pos*/) /*!< TPI FIFO1: ITM0 Mask */ /* TPI ITATBCTR0 Register Definitions */ -#define TPI_ITATBCTR0_ATREADY_Pos 0U /*!< TPI ITATBCTR0: ATREADY Position */ -#define TPI_ITATBCTR0_ATREADY_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY_Pos*/) /*!< TPI ITATBCTR0: ATREADY Mask */ +#define TPI_ITATBCTR0_ATREADY2_Pos 0U /*!< TPI ITATBCTR0: ATREADY2 Position */ +#define TPI_ITATBCTR0_ATREADY2_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY2_Pos*/) /*!< TPI ITATBCTR0: ATREADY2 Mask */ + +#define TPI_ITATBCTR0_ATREADY1_Pos 0U /*!< TPI ITATBCTR0: ATREADY1 Position */ +#define TPI_ITATBCTR0_ATREADY1_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY1_Pos*/) /*!< TPI ITATBCTR0: ATREADY1 Mask */ /* TPI Integration Mode Control Register Definitions */ #define TPI_ITCTRL_Mode_Pos 0U /*!< TPI ITCTRL: Mode Position */ -#define TPI_ITCTRL_Mode_Msk (0x1UL /*<< TPI_ITCTRL_Mode_Pos*/) /*!< TPI ITCTRL: Mode Mask */ +#define TPI_ITCTRL_Mode_Msk (0x3UL /*<< TPI_ITCTRL_Mode_Pos*/) /*!< TPI ITCTRL: Mode Mask */ /* TPI DEVID Register Definitions */ #define TPI_DEVID_NRZVALID_Pos 11U /*!< TPI DEVID: NRZVALID Position */ @@ -1118,16 +1127,16 @@ typedef struct #define TPI_DEVID_NrTraceInput_Msk (0x1FUL /*<< TPI_DEVID_NrTraceInput_Pos*/) /*!< TPI DEVID: NrTraceInput Mask */ /* TPI DEVTYPE Register Definitions */ -#define TPI_DEVTYPE_MajorType_Pos 4U /*!< TPI DEVTYPE: MajorType Position */ -#define TPI_DEVTYPE_MajorType_Msk (0xFUL << TPI_DEVTYPE_MajorType_Pos) /*!< TPI DEVTYPE: MajorType Mask */ - -#define TPI_DEVTYPE_SubType_Pos 0U /*!< TPI DEVTYPE: SubType Position */ +#define TPI_DEVTYPE_SubType_Pos 4U /*!< TPI DEVTYPE: SubType Position */ #define TPI_DEVTYPE_SubType_Msk (0xFUL /*<< TPI_DEVTYPE_SubType_Pos*/) /*!< TPI DEVTYPE: SubType Mask */ +#define TPI_DEVTYPE_MajorType_Pos 0U /*!< TPI DEVTYPE: MajorType Position */ +#define TPI_DEVTYPE_MajorType_Msk (0xFUL << TPI_DEVTYPE_MajorType_Pos) /*!< TPI DEVTYPE: MajorType Mask */ + /*@}*/ /* end of group CMSIS_TPI */ -#if (__MPU_PRESENT == 1U) +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) /** \ingroup CMSIS_core_register \defgroup CMSIS_MPU Memory Protection Unit (MPU) @@ -1153,6 +1162,8 @@ typedef struct __IOM uint32_t RASR_A3; /*!< Offset: 0x028 (R/W) MPU Alias 3 Region Attribute and Size Register */ } MPU_Type; +#define MPU_TYPE_RALIASES 4U + /* MPU Type Register Definitions */ #define MPU_TYPE_IREGION_Pos 16U /*!< MPU TYPE: IREGION Position */ #define MPU_TYPE_IREGION_Msk (0xFFUL << MPU_TYPE_IREGION_Pos) /*!< MPU TYPE: IREGION Mask */ @@ -1337,18 +1348,18 @@ typedef struct /** \brief Mask and shift a bit field value for use in a register bit range. \param[in] field Name of the register bit field. - \param[in] value Value of the bit field. + \param[in] value Value of the bit field. This parameter is interpreted as an uint32_t type. \return Masked and shifted value. */ -#define _VAL2FLD(field, value) ((value << field ## _Pos) & field ## _Msk) +#define _VAL2FLD(field, value) (((uint32_t)(value) << field ## _Pos) & field ## _Msk) /** \brief Mask and shift a register value to extract a bit filed value. \param[in] field Name of the register bit field. - \param[in] value Value of register. + \param[in] value Value of register. This parameter is interpreted as an uint32_t type. \return Masked and shifted bit field value. */ -#define _FLD2VAL(field, value) ((value & field ## _Msk) >> field ## _Pos) +#define _FLD2VAL(field, value) (((uint32_t)(value) & field ## _Msk) >> field ## _Pos) /*@} end of group CMSIS_core_bitfield */ @@ -1360,7 +1371,7 @@ typedef struct @{ */ -/* Memory mapping of Cortex-M3 Hardware */ +/* Memory mapping of Core Hardware */ #define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ #define ITM_BASE (0xE0000000UL) /*!< ITM Base Address */ #define DWT_BASE (0xE0001000UL) /*!< DWT Base Address */ @@ -1379,7 +1390,7 @@ typedef struct #define TPI ((TPI_Type *) TPI_BASE ) /*!< TPI configuration struct */ #define CoreDebug ((CoreDebug_Type *) CoreDebug_BASE) /*!< Core Debug configuration struct */ -#if (__MPU_PRESENT == 1U) +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) #define MPU_BASE (SCS_BASE + 0x0D90UL) /*!< Memory Protection Unit */ #define MPU ((MPU_Type *) MPU_BASE ) /*!< Memory Protection Unit */ #endif @@ -1410,6 +1421,45 @@ typedef struct @{ */ +#ifdef CMSIS_NVIC_VIRTUAL + #ifndef CMSIS_NVIC_VIRTUAL_HEADER_FILE + #define CMSIS_NVIC_VIRTUAL_HEADER_FILE "cmsis_nvic_virtual.h" + #endif + #include CMSIS_NVIC_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetPriorityGrouping __NVIC_SetPriorityGrouping + #define NVIC_GetPriorityGrouping __NVIC_GetPriorityGrouping + #define NVIC_EnableIRQ __NVIC_EnableIRQ + #define NVIC_GetEnableIRQ __NVIC_GetEnableIRQ + #define NVIC_DisableIRQ __NVIC_DisableIRQ + #define NVIC_GetPendingIRQ __NVIC_GetPendingIRQ + #define NVIC_SetPendingIRQ __NVIC_SetPendingIRQ + #define NVIC_ClearPendingIRQ __NVIC_ClearPendingIRQ + #define NVIC_GetActive __NVIC_GetActive + #define NVIC_SetPriority __NVIC_SetPriority + #define NVIC_GetPriority __NVIC_GetPriority + #define NVIC_SystemReset __NVIC_SystemReset +#endif /* CMSIS_NVIC_VIRTUAL */ + +#ifdef CMSIS_VECTAB_VIRTUAL + #ifndef CMSIS_VECTAB_VIRTUAL_HEADER_FILE + #define CMSIS_VECTAB_VIRTUAL_HEADER_FILE "cmsis_vectab_virtual.h" + #endif + #include CMSIS_VECTAB_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetVector __NVIC_SetVector + #define NVIC_GetVector __NVIC_GetVector +#endif /* (CMSIS_VECTAB_VIRTUAL) */ + +#define NVIC_USER_IRQ_OFFSET 16 + + +/* The following EXC_RETURN values are saved the LR on exception entry */ +#define EXC_RETURN_HANDLER (0xFFFFFFF1UL) /* return to Handler mode, uses MSP after return */ +#define EXC_RETURN_THREAD_MSP (0xFFFFFFF9UL) /* return to Thread mode, uses MSP after return */ +#define EXC_RETURN_THREAD_PSP (0xFFFFFFFDUL) /* return to Thread mode, uses PSP after return */ + + /** \brief Set Priority Grouping \details Sets the priority grouping field using the required unlock sequence. @@ -1419,7 +1469,7 @@ typedef struct priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. \param [in] PriorityGroup Priority grouping field. */ -__STATIC_INLINE void NVIC_SetPriorityGrouping(uint32_t PriorityGroup) +__STATIC_INLINE void __NVIC_SetPriorityGrouping(uint32_t PriorityGroup) { uint32_t reg_value; uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ @@ -1428,7 +1478,7 @@ __STATIC_INLINE void NVIC_SetPriorityGrouping(uint32_t PriorityGroup) reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk)); /* clear bits to change */ reg_value = (reg_value | ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | - (PriorityGroupTmp << 8U) ); /* Insert write key and priorty group */ + (PriorityGroupTmp << SCB_AIRCR_PRIGROUP_Pos) ); /* Insert write key and priority group */ SCB->AIRCR = reg_value; } @@ -1438,121 +1488,178 @@ __STATIC_INLINE void NVIC_SetPriorityGrouping(uint32_t PriorityGroup) \details Reads the priority grouping field from the NVIC Interrupt Controller. \return Priority grouping field (SCB->AIRCR [10:8] PRIGROUP field). */ -__STATIC_INLINE uint32_t NVIC_GetPriorityGrouping(void) +__STATIC_INLINE uint32_t __NVIC_GetPriorityGrouping(void) { return ((uint32_t)((SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) >> SCB_AIRCR_PRIGROUP_Pos)); } /** - \brief Enable External Interrupt - \details Enables a device-specific interrupt in the NVIC interrupt controller. - \param [in] IRQn External interrupt number. Value cannot be negative. + \brief Enable Interrupt + \details Enables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. */ -__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn) +__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn) { - NVIC->ISER[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } } /** - \brief Disable External Interrupt - \details Disables a device-specific interrupt in the NVIC interrupt controller. - \param [in] IRQn External interrupt number. Value cannot be negative. + \brief Get Interrupt Enable status + \details Returns a device specific interrupt enable status from the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt is not enabled. + \return 1 Interrupt is enabled. + \note IRQn must not be negative. */ -__STATIC_INLINE void NVIC_DisableIRQ(IRQn_Type IRQn) +__STATIC_INLINE uint32_t __NVIC_GetEnableIRQ(IRQn_Type IRQn) { - NVIC->ICER[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Disable Interrupt + \details Disables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_DisableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + __DSB(); + __ISB(); + } } /** \brief Get Pending Interrupt - \details Reads the pending register in the NVIC and returns the pending bit for the specified interrupt. - \param [in] IRQn Interrupt number. + \details Reads the NVIC pending register and returns the pending bit for the specified device specific interrupt. + \param [in] IRQn Device specific interrupt number. \return 0 Interrupt status is not pending. \return 1 Interrupt status is pending. + \note IRQn must not be negative. */ -__STATIC_INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn) +__STATIC_INLINE uint32_t __NVIC_GetPendingIRQ(IRQn_Type IRQn) { - return((uint32_t)(((NVIC->ISPR[(((uint32_t)(int32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } } /** \brief Set Pending Interrupt - \details Sets the pending bit of an external interrupt. - \param [in] IRQn Interrupt number. Value cannot be negative. + \details Sets the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. */ -__STATIC_INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn) +__STATIC_INLINE void __NVIC_SetPendingIRQ(IRQn_Type IRQn) { - NVIC->ISPR[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } } /** \brief Clear Pending Interrupt - \details Clears the pending bit of an external interrupt. - \param [in] IRQn External interrupt number. Value cannot be negative. + \details Clears the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. */ -__STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn) +__STATIC_INLINE void __NVIC_ClearPendingIRQ(IRQn_Type IRQn) { - NVIC->ICPR[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } } /** \brief Get Active Interrupt - \details Reads the active register in NVIC and returns the active bit. - \param [in] IRQn Interrupt number. + \details Reads the active register in the NVIC and returns the active bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. \return 0 Interrupt status is not active. \return 1 Interrupt status is active. + \note IRQn must not be negative. */ -__STATIC_INLINE uint32_t NVIC_GetActive(IRQn_Type IRQn) +__STATIC_INLINE uint32_t __NVIC_GetActive(IRQn_Type IRQn) { - return((uint32_t)(((NVIC->IABR[(((uint32_t)(int32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->IABR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } } /** \brief Set Interrupt Priority - \details Sets the priority of an interrupt. - \note The priority cannot be set for every core interrupt. + \details Sets the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. \param [in] IRQn Interrupt number. \param [in] priority Priority to set. + \note The priority cannot be set for every processor exception. */ -__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +__STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) { - if ((int32_t)(IRQn) < 0) + if ((int32_t)(IRQn) >= 0) { - SCB->SHP[(((uint32_t)(int32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + NVIC->IP[((uint32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); } else { - NVIC->IP[((uint32_t)(int32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + SCB->SHP[(((uint32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); } } /** \brief Get Interrupt Priority - \details Reads the priority of an interrupt. - The interrupt number can be positive to specify an external (device specific) interrupt, - or negative to specify an internal (core) interrupt. + \details Reads the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. \param [in] IRQn Interrupt number. \return Interrupt Priority. Value is aligned automatically to the implemented priority bits of the microcontroller. */ -__STATIC_INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn) +__STATIC_INLINE uint32_t __NVIC_GetPriority(IRQn_Type IRQn) { - if ((int32_t)(IRQn) < 0) + if ((int32_t)(IRQn) >= 0) { - return(((uint32_t)SCB->SHP[(((uint32_t)(int32_t)IRQn) & 0xFUL)-4UL] >> (8U - __NVIC_PRIO_BITS))); + return(((uint32_t)NVIC->IP[((uint32_t)IRQn)] >> (8U - __NVIC_PRIO_BITS))); } else { - return(((uint32_t)NVIC->IP[((uint32_t)(int32_t)IRQn)] >> (8U - __NVIC_PRIO_BITS))); + return(((uint32_t)SCB->SHP[(((uint32_t)IRQn) & 0xFUL)-4UL] >> (8U - __NVIC_PRIO_BITS))); } } @@ -1609,11 +1716,42 @@ __STATIC_INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGr } +/** + \brief Set Interrupt Vector + \details Sets an interrupt vector in SRAM based interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + VTOR must been relocated to SRAM before. + \param [in] IRQn Interrupt number + \param [in] vector Address of interrupt handler function + */ +__STATIC_INLINE void __NVIC_SetVector(IRQn_Type IRQn, uint32_t vector) +{ + uint32_t vectors = (uint32_t )SCB->VTOR; + (* (int *) (vectors + ((int32_t)IRQn + NVIC_USER_IRQ_OFFSET) * 4)) = vector; +} + + +/** + \brief Get Interrupt Vector + \details Reads an interrupt vector from interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Address of interrupt handler function + */ +__STATIC_INLINE uint32_t __NVIC_GetVector(IRQn_Type IRQn) +{ + uint32_t vectors = (uint32_t )SCB->VTOR; + return (uint32_t)(* (int *) (vectors + ((int32_t)IRQn + NVIC_USER_IRQ_OFFSET) * 4)); +} + + /** \brief System Reset \details Initiates a system reset request to reset the MCU. */ -__STATIC_INLINE void NVIC_SystemReset(void) +__NO_RETURN __STATIC_INLINE void __NVIC_SystemReset(void) { __DSB(); /* Ensure all outstanding memory accesses included buffered write are completed before reset */ @@ -1630,6 +1768,39 @@ __STATIC_INLINE void NVIC_SystemReset(void) /*@} end of CMSIS_Core_NVICFunctions */ +/* ########################## MPU functions #################################### */ + +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + +#include "mpu_armv7.h" + +#endif + + +/* ########################## FPU functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_FpuFunctions FPU Functions + \brief Function that provides FPU type. + @{ + */ + +/** + \brief get FPU type + \details returns the FPU type + \returns + - \b 0: No FPU + - \b 1: Single precision FPU + - \b 2: Double + Single precision FPU + */ +__STATIC_INLINE uint32_t SCB_GetFPUType(void) +{ + return 0U; /* No FPU */ +} + + +/*@} end of CMSIS_Core_FpuFunctions */ + /* ################################## SysTick function ############################################ */ @@ -1640,7 +1811,7 @@ __STATIC_INLINE void NVIC_SystemReset(void) @{ */ -#if (__Vendor_SysTickConfig == 0U) +#if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U) /** \brief System Tick Configuration @@ -1683,8 +1854,8 @@ __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) @{ */ -extern volatile int32_t ITM_RxBuffer; /*!< External variable to receive characters. */ -#define ITM_RXBUFFER_EMPTY 0x5AA55AA5U /*!< Value identifying \ref ITM_RxBuffer is ready for next character. */ +extern volatile int32_t ITM_RxBuffer; /*!< External variable to receive characters. */ +#define ITM_RXBUFFER_EMPTY ((int32_t)0x5AA55AA5U) /*!< Value identifying \ref ITM_RxBuffer is ready for next character. */ /** diff --git a/lib/cmsis/inc/core_cm33.h b/lib/cmsis/inc/core_cm33.h new file mode 100644 index 0000000000..d5d97a96f2 --- /dev/null +++ b/lib/cmsis/inc/core_cm33.h @@ -0,0 +1,2907 @@ +/**************************************************************************//** + * @file core_cm33.h + * @brief CMSIS Cortex-M33 Core Peripheral Access Layer Header File + * @version V5.1.0 + * @date 12. November 2018 + ******************************************************************************/ +/* + * Copyright (c) 2009-2018 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined (__clang__) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef __CORE_CM33_H_GENERIC +#define __CORE_CM33_H_GENERIC + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/** + \page CMSIS_MISRA_Exceptions MISRA-C:2004 Compliance Exceptions + CMSIS violates the following MISRA-C:2004 rules: + + \li Required Rule 8.5, object/function definition in header file.
+ Function definitions in header files are used to allow 'inlining'. + + \li Required Rule 18.4, declaration of union type or object of union type: '{...}'.
+ Unions are used for effective representation of core registers. + + \li Advisory Rule 19.7, Function-like macro defined.
+ Function-like macros are used to allow more efficient code. + */ + + +/******************************************************************************* + * CMSIS definitions + ******************************************************************************/ +/** + \ingroup Cortex_M33 + @{ + */ + +#include "cmsis_version.h" + +/* CMSIS CM33 definitions */ +#define __CM33_CMSIS_VERSION_MAIN (__CM_CMSIS_VERSION_MAIN) /*!< \deprecated [31:16] CMSIS HAL main version */ +#define __CM33_CMSIS_VERSION_SUB (__CM_CMSIS_VERSION_SUB) /*!< \deprecated [15:0] CMSIS HAL sub version */ +#define __CM33_CMSIS_VERSION ((__CM33_CMSIS_VERSION_MAIN << 16U) | \ + __CM33_CMSIS_VERSION_SUB ) /*!< \deprecated CMSIS HAL version number */ + +#define __CORTEX_M (33U) /*!< Cortex-M Core */ + +/** __FPU_USED indicates whether an FPU is used or not. + For this, __FPU_PRESENT has to be checked prior to making use of FPU specific registers and functions. +*/ +#if defined ( __CC_ARM ) + #if defined (__TARGET_FPU_VFP) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + + #if defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1U) + #if defined (__DSP_PRESENT) && (__DSP_PRESENT == 1U) + #define __DSP_USED 1U + #else + #error "Compiler generates DSP (SIMD) instructions for a devices without DSP extensions (check __DSP_PRESENT)" + #define __DSP_USED 0U + #endif + #else + #define __DSP_USED 0U + #endif + +#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #if defined (__ARM_FP) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #warning "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + + #if defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1U) + #if defined (__DSP_PRESENT) && (__DSP_PRESENT == 1U) + #define __DSP_USED 1U + #else + #error "Compiler generates DSP (SIMD) instructions for a devices without DSP extensions (check __DSP_PRESENT)" + #define __DSP_USED 0U + #endif + #else + #define __DSP_USED 0U + #endif + +#elif defined ( __GNUC__ ) + #if defined (__VFP_FP__) && !defined(__SOFTFP__) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + + #if defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1U) + #if defined (__DSP_PRESENT) && (__DSP_PRESENT == 1U) + #define __DSP_USED 1U + #else + #error "Compiler generates DSP (SIMD) instructions for a devices without DSP extensions (check __DSP_PRESENT)" + #define __DSP_USED 0U + #endif + #else + #define __DSP_USED 0U + #endif + +#elif defined ( __ICCARM__ ) + #if defined (__ARMVFP__) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + + #if defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1U) + #if defined (__DSP_PRESENT) && (__DSP_PRESENT == 1U) + #define __DSP_USED 1U + #else + #error "Compiler generates DSP (SIMD) instructions for a devices without DSP extensions (check __DSP_PRESENT)" + #define __DSP_USED 0U + #endif + #else + #define __DSP_USED 0U + #endif + +#elif defined ( __TI_ARM__ ) + #if defined (__TI_VFP_SUPPORT__) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#elif defined ( __TASKING__ ) + #if defined (__FPU_VFP__) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#elif defined ( __CSMC__ ) + #if ( __CSMC__ & 0x400U) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#endif + +#include "cmsis_compiler.h" /* CMSIS compiler specific defines */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_CM33_H_GENERIC */ + +#ifndef __CMSIS_GENERIC + +#ifndef __CORE_CM33_H_DEPENDANT +#define __CORE_CM33_H_DEPENDANT + +#ifdef __cplusplus + extern "C" { +#endif + +/* check device defines and use defaults */ +#if defined __CHECK_DEVICE_DEFINES + #ifndef __CM33_REV + #define __CM33_REV 0x0000U + #warning "__CM33_REV not defined in device header file; using default!" + #endif + + #ifndef __FPU_PRESENT + #define __FPU_PRESENT 0U + #warning "__FPU_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __MPU_PRESENT + #define __MPU_PRESENT 0U + #warning "__MPU_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __SAUREGION_PRESENT + #define __SAUREGION_PRESENT 0U + #warning "__SAUREGION_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __DSP_PRESENT + #define __DSP_PRESENT 0U + #warning "__DSP_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __NVIC_PRIO_BITS + #define __NVIC_PRIO_BITS 3U + #warning "__NVIC_PRIO_BITS not defined in device header file; using default!" + #endif + + #ifndef __Vendor_SysTickConfig + #define __Vendor_SysTickConfig 0U + #warning "__Vendor_SysTickConfig not defined in device header file; using default!" + #endif +#endif + +/* IO definitions (access restrictions to peripheral registers) */ +/** + \defgroup CMSIS_glob_defs CMSIS Global Defines + + IO Type Qualifiers are used + \li to specify the access to peripheral variables. + \li for automatic generation of peripheral register debug information. +*/ +#ifdef __cplusplus + #define __I volatile /*!< Defines 'read only' permissions */ +#else + #define __I volatile const /*!< Defines 'read only' permissions */ +#endif +#define __O volatile /*!< Defines 'write only' permissions */ +#define __IO volatile /*!< Defines 'read / write' permissions */ + +/* following defines should be used for structure members */ +#define __IM volatile const /*! Defines 'read only' structure member permissions */ +#define __OM volatile /*! Defines 'write only' structure member permissions */ +#define __IOM volatile /*! Defines 'read / write' structure member permissions */ + +/*@} end of group Cortex_M33 */ + + + +/******************************************************************************* + * Register Abstraction + Core Register contain: + - Core Register + - Core NVIC Register + - Core SCB Register + - Core SysTick Register + - Core Debug Register + - Core MPU Register + - Core SAU Register + - Core FPU Register + ******************************************************************************/ +/** + \defgroup CMSIS_core_register Defines and Type Definitions + \brief Type definitions and defines for Cortex-M processor based devices. +*/ + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CORE Status and Control Registers + \brief Core Register type definitions. + @{ + */ + +/** + \brief Union type to access the Application Program Status Register (APSR). + */ +typedef union +{ + struct + { + uint32_t _reserved0:16; /*!< bit: 0..15 Reserved */ + uint32_t GE:4; /*!< bit: 16..19 Greater than or Equal flags */ + uint32_t _reserved1:7; /*!< bit: 20..26 Reserved */ + uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} APSR_Type; + +/* APSR Register Definitions */ +#define APSR_N_Pos 31U /*!< APSR: N Position */ +#define APSR_N_Msk (1UL << APSR_N_Pos) /*!< APSR: N Mask */ + +#define APSR_Z_Pos 30U /*!< APSR: Z Position */ +#define APSR_Z_Msk (1UL << APSR_Z_Pos) /*!< APSR: Z Mask */ + +#define APSR_C_Pos 29U /*!< APSR: C Position */ +#define APSR_C_Msk (1UL << APSR_C_Pos) /*!< APSR: C Mask */ + +#define APSR_V_Pos 28U /*!< APSR: V Position */ +#define APSR_V_Msk (1UL << APSR_V_Pos) /*!< APSR: V Mask */ + +#define APSR_Q_Pos 27U /*!< APSR: Q Position */ +#define APSR_Q_Msk (1UL << APSR_Q_Pos) /*!< APSR: Q Mask */ + +#define APSR_GE_Pos 16U /*!< APSR: GE Position */ +#define APSR_GE_Msk (0xFUL << APSR_GE_Pos) /*!< APSR: GE Mask */ + + +/** + \brief Union type to access the Interrupt Program Status Register (IPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:23; /*!< bit: 9..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} IPSR_Type; + +/* IPSR Register Definitions */ +#define IPSR_ISR_Pos 0U /*!< IPSR: ISR Position */ +#define IPSR_ISR_Msk (0x1FFUL /*<< IPSR_ISR_Pos*/) /*!< IPSR: ISR Mask */ + + +/** + \brief Union type to access the Special-Purpose Program Status Registers (xPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:7; /*!< bit: 9..15 Reserved */ + uint32_t GE:4; /*!< bit: 16..19 Greater than or Equal flags */ + uint32_t _reserved1:4; /*!< bit: 20..23 Reserved */ + uint32_t T:1; /*!< bit: 24 Thumb bit (read 0) */ + uint32_t IT:2; /*!< bit: 25..26 saved IT state (read 0) */ + uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} xPSR_Type; + +/* xPSR Register Definitions */ +#define xPSR_N_Pos 31U /*!< xPSR: N Position */ +#define xPSR_N_Msk (1UL << xPSR_N_Pos) /*!< xPSR: N Mask */ + +#define xPSR_Z_Pos 30U /*!< xPSR: Z Position */ +#define xPSR_Z_Msk (1UL << xPSR_Z_Pos) /*!< xPSR: Z Mask */ + +#define xPSR_C_Pos 29U /*!< xPSR: C Position */ +#define xPSR_C_Msk (1UL << xPSR_C_Pos) /*!< xPSR: C Mask */ + +#define xPSR_V_Pos 28U /*!< xPSR: V Position */ +#define xPSR_V_Msk (1UL << xPSR_V_Pos) /*!< xPSR: V Mask */ + +#define xPSR_Q_Pos 27U /*!< xPSR: Q Position */ +#define xPSR_Q_Msk (1UL << xPSR_Q_Pos) /*!< xPSR: Q Mask */ + +#define xPSR_IT_Pos 25U /*!< xPSR: IT Position */ +#define xPSR_IT_Msk (3UL << xPSR_IT_Pos) /*!< xPSR: IT Mask */ + +#define xPSR_T_Pos 24U /*!< xPSR: T Position */ +#define xPSR_T_Msk (1UL << xPSR_T_Pos) /*!< xPSR: T Mask */ + +#define xPSR_GE_Pos 16U /*!< xPSR: GE Position */ +#define xPSR_GE_Msk (0xFUL << xPSR_GE_Pos) /*!< xPSR: GE Mask */ + +#define xPSR_ISR_Pos 0U /*!< xPSR: ISR Position */ +#define xPSR_ISR_Msk (0x1FFUL /*<< xPSR_ISR_Pos*/) /*!< xPSR: ISR Mask */ + + +/** + \brief Union type to access the Control Registers (CONTROL). + */ +typedef union +{ + struct + { + uint32_t nPRIV:1; /*!< bit: 0 Execution privilege in Thread mode */ + uint32_t SPSEL:1; /*!< bit: 1 Stack-pointer select */ + uint32_t FPCA:1; /*!< bit: 2 Floating-point context active */ + uint32_t SFPA:1; /*!< bit: 3 Secure floating-point active */ + uint32_t _reserved1:28; /*!< bit: 4..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} CONTROL_Type; + +/* CONTROL Register Definitions */ +#define CONTROL_SFPA_Pos 3U /*!< CONTROL: SFPA Position */ +#define CONTROL_SFPA_Msk (1UL << CONTROL_SFPA_Pos) /*!< CONTROL: SFPA Mask */ + +#define CONTROL_FPCA_Pos 2U /*!< CONTROL: FPCA Position */ +#define CONTROL_FPCA_Msk (1UL << CONTROL_FPCA_Pos) /*!< CONTROL: FPCA Mask */ + +#define CONTROL_SPSEL_Pos 1U /*!< CONTROL: SPSEL Position */ +#define CONTROL_SPSEL_Msk (1UL << CONTROL_SPSEL_Pos) /*!< CONTROL: SPSEL Mask */ + +#define CONTROL_nPRIV_Pos 0U /*!< CONTROL: nPRIV Position */ +#define CONTROL_nPRIV_Msk (1UL /*<< CONTROL_nPRIV_Pos*/) /*!< CONTROL: nPRIV Mask */ + +/*@} end of group CMSIS_CORE */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_NVIC Nested Vectored Interrupt Controller (NVIC) + \brief Type definitions for the NVIC Registers + @{ + */ + +/** + \brief Structure type to access the Nested Vectored Interrupt Controller (NVIC). + */ +typedef struct +{ + __IOM uint32_t ISER[16U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ + uint32_t RESERVED0[16U]; + __IOM uint32_t ICER[16U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ + uint32_t RSERVED1[16U]; + __IOM uint32_t ISPR[16U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ + uint32_t RESERVED2[16U]; + __IOM uint32_t ICPR[16U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ + uint32_t RESERVED3[16U]; + __IOM uint32_t IABR[16U]; /*!< Offset: 0x200 (R/W) Interrupt Active bit Register */ + uint32_t RESERVED4[16U]; + __IOM uint32_t ITNS[16U]; /*!< Offset: 0x280 (R/W) Interrupt Non-Secure State Register */ + uint32_t RESERVED5[16U]; + __IOM uint8_t IPR[496U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register (8Bit wide) */ + uint32_t RESERVED6[580U]; + __OM uint32_t STIR; /*!< Offset: 0xE00 ( /W) Software Trigger Interrupt Register */ +} NVIC_Type; + +/* Software Triggered Interrupt Register Definitions */ +#define NVIC_STIR_INTID_Pos 0U /*!< STIR: INTLINESNUM Position */ +#define NVIC_STIR_INTID_Msk (0x1FFUL /*<< NVIC_STIR_INTID_Pos*/) /*!< STIR: INTLINESNUM Mask */ + +/*@} end of group CMSIS_NVIC */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SCB System Control Block (SCB) + \brief Type definitions for the System Control Block Registers + @{ + */ + +/** + \brief Structure type to access the System Control Block (SCB). + */ +typedef struct +{ + __IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */ + __IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */ + __IOM uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */ + __IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */ + __IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */ + __IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */ + __IOM uint8_t SHPR[12U]; /*!< Offset: 0x018 (R/W) System Handlers Priority Registers (4-7, 8-11, 12-15) */ + __IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */ + __IOM uint32_t CFSR; /*!< Offset: 0x028 (R/W) Configurable Fault Status Register */ + __IOM uint32_t HFSR; /*!< Offset: 0x02C (R/W) HardFault Status Register */ + __IOM uint32_t DFSR; /*!< Offset: 0x030 (R/W) Debug Fault Status Register */ + __IOM uint32_t MMFAR; /*!< Offset: 0x034 (R/W) MemManage Fault Address Register */ + __IOM uint32_t BFAR; /*!< Offset: 0x038 (R/W) BusFault Address Register */ + __IOM uint32_t AFSR; /*!< Offset: 0x03C (R/W) Auxiliary Fault Status Register */ + __IM uint32_t ID_PFR[2U]; /*!< Offset: 0x040 (R/ ) Processor Feature Register */ + __IM uint32_t ID_DFR; /*!< Offset: 0x048 (R/ ) Debug Feature Register */ + __IM uint32_t ID_ADR; /*!< Offset: 0x04C (R/ ) Auxiliary Feature Register */ + __IM uint32_t ID_MMFR[4U]; /*!< Offset: 0x050 (R/ ) Memory Model Feature Register */ + __IM uint32_t ID_ISAR[6U]; /*!< Offset: 0x060 (R/ ) Instruction Set Attributes Register */ + __IM uint32_t CLIDR; /*!< Offset: 0x078 (R/ ) Cache Level ID register */ + __IM uint32_t CTR; /*!< Offset: 0x07C (R/ ) Cache Type register */ + __IM uint32_t CCSIDR; /*!< Offset: 0x080 (R/ ) Cache Size ID Register */ + __IOM uint32_t CSSELR; /*!< Offset: 0x084 (R/W) Cache Size Selection Register */ + __IOM uint32_t CPACR; /*!< Offset: 0x088 (R/W) Coprocessor Access Control Register */ + __IOM uint32_t NSACR; /*!< Offset: 0x08C (R/W) Non-Secure Access Control Register */ + uint32_t RESERVED3[92U]; + __OM uint32_t STIR; /*!< Offset: 0x200 ( /W) Software Triggered Interrupt Register */ + uint32_t RESERVED4[15U]; + __IM uint32_t MVFR0; /*!< Offset: 0x240 (R/ ) Media and VFP Feature Register 0 */ + __IM uint32_t MVFR1; /*!< Offset: 0x244 (R/ ) Media and VFP Feature Register 1 */ + __IM uint32_t MVFR2; /*!< Offset: 0x248 (R/ ) Media and VFP Feature Register 2 */ + uint32_t RESERVED5[1U]; + __OM uint32_t ICIALLU; /*!< Offset: 0x250 ( /W) I-Cache Invalidate All to PoU */ + uint32_t RESERVED6[1U]; + __OM uint32_t ICIMVAU; /*!< Offset: 0x258 ( /W) I-Cache Invalidate by MVA to PoU */ + __OM uint32_t DCIMVAC; /*!< Offset: 0x25C ( /W) D-Cache Invalidate by MVA to PoC */ + __OM uint32_t DCISW; /*!< Offset: 0x260 ( /W) D-Cache Invalidate by Set-way */ + __OM uint32_t DCCMVAU; /*!< Offset: 0x264 ( /W) D-Cache Clean by MVA to PoU */ + __OM uint32_t DCCMVAC; /*!< Offset: 0x268 ( /W) D-Cache Clean by MVA to PoC */ + __OM uint32_t DCCSW; /*!< Offset: 0x26C ( /W) D-Cache Clean by Set-way */ + __OM uint32_t DCCIMVAC; /*!< Offset: 0x270 ( /W) D-Cache Clean and Invalidate by MVA to PoC */ + __OM uint32_t DCCISW; /*!< Offset: 0x274 ( /W) D-Cache Clean and Invalidate by Set-way */ +} SCB_Type; + +/* SCB CPUID Register Definitions */ +#define SCB_CPUID_IMPLEMENTER_Pos 24U /*!< SCB CPUID: IMPLEMENTER Position */ +#define SCB_CPUID_IMPLEMENTER_Msk (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos) /*!< SCB CPUID: IMPLEMENTER Mask */ + +#define SCB_CPUID_VARIANT_Pos 20U /*!< SCB CPUID: VARIANT Position */ +#define SCB_CPUID_VARIANT_Msk (0xFUL << SCB_CPUID_VARIANT_Pos) /*!< SCB CPUID: VARIANT Mask */ + +#define SCB_CPUID_ARCHITECTURE_Pos 16U /*!< SCB CPUID: ARCHITECTURE Position */ +#define SCB_CPUID_ARCHITECTURE_Msk (0xFUL << SCB_CPUID_ARCHITECTURE_Pos) /*!< SCB CPUID: ARCHITECTURE Mask */ + +#define SCB_CPUID_PARTNO_Pos 4U /*!< SCB CPUID: PARTNO Position */ +#define SCB_CPUID_PARTNO_Msk (0xFFFUL << SCB_CPUID_PARTNO_Pos) /*!< SCB CPUID: PARTNO Mask */ + +#define SCB_CPUID_REVISION_Pos 0U /*!< SCB CPUID: REVISION Position */ +#define SCB_CPUID_REVISION_Msk (0xFUL /*<< SCB_CPUID_REVISION_Pos*/) /*!< SCB CPUID: REVISION Mask */ + +/* SCB Interrupt Control State Register Definitions */ +#define SCB_ICSR_PENDNMISET_Pos 31U /*!< SCB ICSR: PENDNMISET Position */ +#define SCB_ICSR_PENDNMISET_Msk (1UL << SCB_ICSR_PENDNMISET_Pos) /*!< SCB ICSR: PENDNMISET Mask */ + +#define SCB_ICSR_NMIPENDSET_Pos SCB_ICSR_PENDNMISET_Pos /*!< SCB ICSR: NMIPENDSET Position, backward compatibility */ +#define SCB_ICSR_NMIPENDSET_Msk SCB_ICSR_PENDNMISET_Msk /*!< SCB ICSR: NMIPENDSET Mask, backward compatibility */ + +#define SCB_ICSR_PENDNMICLR_Pos 30U /*!< SCB ICSR: PENDNMICLR Position */ +#define SCB_ICSR_PENDNMICLR_Msk (1UL << SCB_ICSR_PENDNMICLR_Pos) /*!< SCB ICSR: PENDNMICLR Mask */ + +#define SCB_ICSR_PENDSVSET_Pos 28U /*!< SCB ICSR: PENDSVSET Position */ +#define SCB_ICSR_PENDSVSET_Msk (1UL << SCB_ICSR_PENDSVSET_Pos) /*!< SCB ICSR: PENDSVSET Mask */ + +#define SCB_ICSR_PENDSVCLR_Pos 27U /*!< SCB ICSR: PENDSVCLR Position */ +#define SCB_ICSR_PENDSVCLR_Msk (1UL << SCB_ICSR_PENDSVCLR_Pos) /*!< SCB ICSR: PENDSVCLR Mask */ + +#define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */ +#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */ + +#define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */ +#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */ + +#define SCB_ICSR_STTNS_Pos 24U /*!< SCB ICSR: STTNS Position (Security Extension) */ +#define SCB_ICSR_STTNS_Msk (1UL << SCB_ICSR_STTNS_Pos) /*!< SCB ICSR: STTNS Mask (Security Extension) */ + +#define SCB_ICSR_ISRPREEMPT_Pos 23U /*!< SCB ICSR: ISRPREEMPT Position */ +#define SCB_ICSR_ISRPREEMPT_Msk (1UL << SCB_ICSR_ISRPREEMPT_Pos) /*!< SCB ICSR: ISRPREEMPT Mask */ + +#define SCB_ICSR_ISRPENDING_Pos 22U /*!< SCB ICSR: ISRPENDING Position */ +#define SCB_ICSR_ISRPENDING_Msk (1UL << SCB_ICSR_ISRPENDING_Pos) /*!< SCB ICSR: ISRPENDING Mask */ + +#define SCB_ICSR_VECTPENDING_Pos 12U /*!< SCB ICSR: VECTPENDING Position */ +#define SCB_ICSR_VECTPENDING_Msk (0x1FFUL << SCB_ICSR_VECTPENDING_Pos) /*!< SCB ICSR: VECTPENDING Mask */ + +#define SCB_ICSR_RETTOBASE_Pos 11U /*!< SCB ICSR: RETTOBASE Position */ +#define SCB_ICSR_RETTOBASE_Msk (1UL << SCB_ICSR_RETTOBASE_Pos) /*!< SCB ICSR: RETTOBASE Mask */ + +#define SCB_ICSR_VECTACTIVE_Pos 0U /*!< SCB ICSR: VECTACTIVE Position */ +#define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL /*<< SCB_ICSR_VECTACTIVE_Pos*/) /*!< SCB ICSR: VECTACTIVE Mask */ + +/* SCB Vector Table Offset Register Definitions */ +#define SCB_VTOR_TBLOFF_Pos 7U /*!< SCB VTOR: TBLOFF Position */ +#define SCB_VTOR_TBLOFF_Msk (0x1FFFFFFUL << SCB_VTOR_TBLOFF_Pos) /*!< SCB VTOR: TBLOFF Mask */ + +/* SCB Application Interrupt and Reset Control Register Definitions */ +#define SCB_AIRCR_VECTKEY_Pos 16U /*!< SCB AIRCR: VECTKEY Position */ +#define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */ + +#define SCB_AIRCR_VECTKEYSTAT_Pos 16U /*!< SCB AIRCR: VECTKEYSTAT Position */ +#define SCB_AIRCR_VECTKEYSTAT_Msk (0xFFFFUL << SCB_AIRCR_VECTKEYSTAT_Pos) /*!< SCB AIRCR: VECTKEYSTAT Mask */ + +#define SCB_AIRCR_ENDIANESS_Pos 15U /*!< SCB AIRCR: ENDIANESS Position */ +#define SCB_AIRCR_ENDIANESS_Msk (1UL << SCB_AIRCR_ENDIANESS_Pos) /*!< SCB AIRCR: ENDIANESS Mask */ + +#define SCB_AIRCR_PRIS_Pos 14U /*!< SCB AIRCR: PRIS Position */ +#define SCB_AIRCR_PRIS_Msk (1UL << SCB_AIRCR_PRIS_Pos) /*!< SCB AIRCR: PRIS Mask */ + +#define SCB_AIRCR_BFHFNMINS_Pos 13U /*!< SCB AIRCR: BFHFNMINS Position */ +#define SCB_AIRCR_BFHFNMINS_Msk (1UL << SCB_AIRCR_BFHFNMINS_Pos) /*!< SCB AIRCR: BFHFNMINS Mask */ + +#define SCB_AIRCR_PRIGROUP_Pos 8U /*!< SCB AIRCR: PRIGROUP Position */ +#define SCB_AIRCR_PRIGROUP_Msk (7UL << SCB_AIRCR_PRIGROUP_Pos) /*!< SCB AIRCR: PRIGROUP Mask */ + +#define SCB_AIRCR_SYSRESETREQS_Pos 3U /*!< SCB AIRCR: SYSRESETREQS Position */ +#define SCB_AIRCR_SYSRESETREQS_Msk (1UL << SCB_AIRCR_SYSRESETREQS_Pos) /*!< SCB AIRCR: SYSRESETREQS Mask */ + +#define SCB_AIRCR_SYSRESETREQ_Pos 2U /*!< SCB AIRCR: SYSRESETREQ Position */ +#define SCB_AIRCR_SYSRESETREQ_Msk (1UL << SCB_AIRCR_SYSRESETREQ_Pos) /*!< SCB AIRCR: SYSRESETREQ Mask */ + +#define SCB_AIRCR_VECTCLRACTIVE_Pos 1U /*!< SCB AIRCR: VECTCLRACTIVE Position */ +#define SCB_AIRCR_VECTCLRACTIVE_Msk (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos) /*!< SCB AIRCR: VECTCLRACTIVE Mask */ + +/* SCB System Control Register Definitions */ +#define SCB_SCR_SEVONPEND_Pos 4U /*!< SCB SCR: SEVONPEND Position */ +#define SCB_SCR_SEVONPEND_Msk (1UL << SCB_SCR_SEVONPEND_Pos) /*!< SCB SCR: SEVONPEND Mask */ + +#define SCB_SCR_SLEEPDEEPS_Pos 3U /*!< SCB SCR: SLEEPDEEPS Position */ +#define SCB_SCR_SLEEPDEEPS_Msk (1UL << SCB_SCR_SLEEPDEEPS_Pos) /*!< SCB SCR: SLEEPDEEPS Mask */ + +#define SCB_SCR_SLEEPDEEP_Pos 2U /*!< SCB SCR: SLEEPDEEP Position */ +#define SCB_SCR_SLEEPDEEP_Msk (1UL << SCB_SCR_SLEEPDEEP_Pos) /*!< SCB SCR: SLEEPDEEP Mask */ + +#define SCB_SCR_SLEEPONEXIT_Pos 1U /*!< SCB SCR: SLEEPONEXIT Position */ +#define SCB_SCR_SLEEPONEXIT_Msk (1UL << SCB_SCR_SLEEPONEXIT_Pos) /*!< SCB SCR: SLEEPONEXIT Mask */ + +/* SCB Configuration Control Register Definitions */ +#define SCB_CCR_BP_Pos 18U /*!< SCB CCR: BP Position */ +#define SCB_CCR_BP_Msk (1UL << SCB_CCR_BP_Pos) /*!< SCB CCR: BP Mask */ + +#define SCB_CCR_IC_Pos 17U /*!< SCB CCR: IC Position */ +#define SCB_CCR_IC_Msk (1UL << SCB_CCR_IC_Pos) /*!< SCB CCR: IC Mask */ + +#define SCB_CCR_DC_Pos 16U /*!< SCB CCR: DC Position */ +#define SCB_CCR_DC_Msk (1UL << SCB_CCR_DC_Pos) /*!< SCB CCR: DC Mask */ + +#define SCB_CCR_STKOFHFNMIGN_Pos 10U /*!< SCB CCR: STKOFHFNMIGN Position */ +#define SCB_CCR_STKOFHFNMIGN_Msk (1UL << SCB_CCR_STKOFHFNMIGN_Pos) /*!< SCB CCR: STKOFHFNMIGN Mask */ + +#define SCB_CCR_BFHFNMIGN_Pos 8U /*!< SCB CCR: BFHFNMIGN Position */ +#define SCB_CCR_BFHFNMIGN_Msk (1UL << SCB_CCR_BFHFNMIGN_Pos) /*!< SCB CCR: BFHFNMIGN Mask */ + +#define SCB_CCR_DIV_0_TRP_Pos 4U /*!< SCB CCR: DIV_0_TRP Position */ +#define SCB_CCR_DIV_0_TRP_Msk (1UL << SCB_CCR_DIV_0_TRP_Pos) /*!< SCB CCR: DIV_0_TRP Mask */ + +#define SCB_CCR_UNALIGN_TRP_Pos 3U /*!< SCB CCR: UNALIGN_TRP Position */ +#define SCB_CCR_UNALIGN_TRP_Msk (1UL << SCB_CCR_UNALIGN_TRP_Pos) /*!< SCB CCR: UNALIGN_TRP Mask */ + +#define SCB_CCR_USERSETMPEND_Pos 1U /*!< SCB CCR: USERSETMPEND Position */ +#define SCB_CCR_USERSETMPEND_Msk (1UL << SCB_CCR_USERSETMPEND_Pos) /*!< SCB CCR: USERSETMPEND Mask */ + +/* SCB System Handler Control and State Register Definitions */ +#define SCB_SHCSR_HARDFAULTPENDED_Pos 21U /*!< SCB SHCSR: HARDFAULTPENDED Position */ +#define SCB_SHCSR_HARDFAULTPENDED_Msk (1UL << SCB_SHCSR_HARDFAULTPENDED_Pos) /*!< SCB SHCSR: HARDFAULTPENDED Mask */ + +#define SCB_SHCSR_SECUREFAULTPENDED_Pos 20U /*!< SCB SHCSR: SECUREFAULTPENDED Position */ +#define SCB_SHCSR_SECUREFAULTPENDED_Msk (1UL << SCB_SHCSR_SECUREFAULTPENDED_Pos) /*!< SCB SHCSR: SECUREFAULTPENDED Mask */ + +#define SCB_SHCSR_SECUREFAULTENA_Pos 19U /*!< SCB SHCSR: SECUREFAULTENA Position */ +#define SCB_SHCSR_SECUREFAULTENA_Msk (1UL << SCB_SHCSR_SECUREFAULTENA_Pos) /*!< SCB SHCSR: SECUREFAULTENA Mask */ + +#define SCB_SHCSR_USGFAULTENA_Pos 18U /*!< SCB SHCSR: USGFAULTENA Position */ +#define SCB_SHCSR_USGFAULTENA_Msk (1UL << SCB_SHCSR_USGFAULTENA_Pos) /*!< SCB SHCSR: USGFAULTENA Mask */ + +#define SCB_SHCSR_BUSFAULTENA_Pos 17U /*!< SCB SHCSR: BUSFAULTENA Position */ +#define SCB_SHCSR_BUSFAULTENA_Msk (1UL << SCB_SHCSR_BUSFAULTENA_Pos) /*!< SCB SHCSR: BUSFAULTENA Mask */ + +#define SCB_SHCSR_MEMFAULTENA_Pos 16U /*!< SCB SHCSR: MEMFAULTENA Position */ +#define SCB_SHCSR_MEMFAULTENA_Msk (1UL << SCB_SHCSR_MEMFAULTENA_Pos) /*!< SCB SHCSR: MEMFAULTENA Mask */ + +#define SCB_SHCSR_SVCALLPENDED_Pos 15U /*!< SCB SHCSR: SVCALLPENDED Position */ +#define SCB_SHCSR_SVCALLPENDED_Msk (1UL << SCB_SHCSR_SVCALLPENDED_Pos) /*!< SCB SHCSR: SVCALLPENDED Mask */ + +#define SCB_SHCSR_BUSFAULTPENDED_Pos 14U /*!< SCB SHCSR: BUSFAULTPENDED Position */ +#define SCB_SHCSR_BUSFAULTPENDED_Msk (1UL << SCB_SHCSR_BUSFAULTPENDED_Pos) /*!< SCB SHCSR: BUSFAULTPENDED Mask */ + +#define SCB_SHCSR_MEMFAULTPENDED_Pos 13U /*!< SCB SHCSR: MEMFAULTPENDED Position */ +#define SCB_SHCSR_MEMFAULTPENDED_Msk (1UL << SCB_SHCSR_MEMFAULTPENDED_Pos) /*!< SCB SHCSR: MEMFAULTPENDED Mask */ + +#define SCB_SHCSR_USGFAULTPENDED_Pos 12U /*!< SCB SHCSR: USGFAULTPENDED Position */ +#define SCB_SHCSR_USGFAULTPENDED_Msk (1UL << SCB_SHCSR_USGFAULTPENDED_Pos) /*!< SCB SHCSR: USGFAULTPENDED Mask */ + +#define SCB_SHCSR_SYSTICKACT_Pos 11U /*!< SCB SHCSR: SYSTICKACT Position */ +#define SCB_SHCSR_SYSTICKACT_Msk (1UL << SCB_SHCSR_SYSTICKACT_Pos) /*!< SCB SHCSR: SYSTICKACT Mask */ + +#define SCB_SHCSR_PENDSVACT_Pos 10U /*!< SCB SHCSR: PENDSVACT Position */ +#define SCB_SHCSR_PENDSVACT_Msk (1UL << SCB_SHCSR_PENDSVACT_Pos) /*!< SCB SHCSR: PENDSVACT Mask */ + +#define SCB_SHCSR_MONITORACT_Pos 8U /*!< SCB SHCSR: MONITORACT Position */ +#define SCB_SHCSR_MONITORACT_Msk (1UL << SCB_SHCSR_MONITORACT_Pos) /*!< SCB SHCSR: MONITORACT Mask */ + +#define SCB_SHCSR_SVCALLACT_Pos 7U /*!< SCB SHCSR: SVCALLACT Position */ +#define SCB_SHCSR_SVCALLACT_Msk (1UL << SCB_SHCSR_SVCALLACT_Pos) /*!< SCB SHCSR: SVCALLACT Mask */ + +#define SCB_SHCSR_NMIACT_Pos 5U /*!< SCB SHCSR: NMIACT Position */ +#define SCB_SHCSR_NMIACT_Msk (1UL << SCB_SHCSR_NMIACT_Pos) /*!< SCB SHCSR: NMIACT Mask */ + +#define SCB_SHCSR_SECUREFAULTACT_Pos 4U /*!< SCB SHCSR: SECUREFAULTACT Position */ +#define SCB_SHCSR_SECUREFAULTACT_Msk (1UL << SCB_SHCSR_SECUREFAULTACT_Pos) /*!< SCB SHCSR: SECUREFAULTACT Mask */ + +#define SCB_SHCSR_USGFAULTACT_Pos 3U /*!< SCB SHCSR: USGFAULTACT Position */ +#define SCB_SHCSR_USGFAULTACT_Msk (1UL << SCB_SHCSR_USGFAULTACT_Pos) /*!< SCB SHCSR: USGFAULTACT Mask */ + +#define SCB_SHCSR_HARDFAULTACT_Pos 2U /*!< SCB SHCSR: HARDFAULTACT Position */ +#define SCB_SHCSR_HARDFAULTACT_Msk (1UL << SCB_SHCSR_HARDFAULTACT_Pos) /*!< SCB SHCSR: HARDFAULTACT Mask */ + +#define SCB_SHCSR_BUSFAULTACT_Pos 1U /*!< SCB SHCSR: BUSFAULTACT Position */ +#define SCB_SHCSR_BUSFAULTACT_Msk (1UL << SCB_SHCSR_BUSFAULTACT_Pos) /*!< SCB SHCSR: BUSFAULTACT Mask */ + +#define SCB_SHCSR_MEMFAULTACT_Pos 0U /*!< SCB SHCSR: MEMFAULTACT Position */ +#define SCB_SHCSR_MEMFAULTACT_Msk (1UL /*<< SCB_SHCSR_MEMFAULTACT_Pos*/) /*!< SCB SHCSR: MEMFAULTACT Mask */ + +/* SCB Configurable Fault Status Register Definitions */ +#define SCB_CFSR_USGFAULTSR_Pos 16U /*!< SCB CFSR: Usage Fault Status Register Position */ +#define SCB_CFSR_USGFAULTSR_Msk (0xFFFFUL << SCB_CFSR_USGFAULTSR_Pos) /*!< SCB CFSR: Usage Fault Status Register Mask */ + +#define SCB_CFSR_BUSFAULTSR_Pos 8U /*!< SCB CFSR: Bus Fault Status Register Position */ +#define SCB_CFSR_BUSFAULTSR_Msk (0xFFUL << SCB_CFSR_BUSFAULTSR_Pos) /*!< SCB CFSR: Bus Fault Status Register Mask */ + +#define SCB_CFSR_MEMFAULTSR_Pos 0U /*!< SCB CFSR: Memory Manage Fault Status Register Position */ +#define SCB_CFSR_MEMFAULTSR_Msk (0xFFUL /*<< SCB_CFSR_MEMFAULTSR_Pos*/) /*!< SCB CFSR: Memory Manage Fault Status Register Mask */ + +/* MemManage Fault Status Register (part of SCB Configurable Fault Status Register) */ +#define SCB_CFSR_MMARVALID_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 7U) /*!< SCB CFSR (MMFSR): MMARVALID Position */ +#define SCB_CFSR_MMARVALID_Msk (1UL << SCB_CFSR_MMARVALID_Pos) /*!< SCB CFSR (MMFSR): MMARVALID Mask */ + +#define SCB_CFSR_MLSPERR_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 5U) /*!< SCB CFSR (MMFSR): MLSPERR Position */ +#define SCB_CFSR_MLSPERR_Msk (1UL << SCB_CFSR_MLSPERR_Pos) /*!< SCB CFSR (MMFSR): MLSPERR Mask */ + +#define SCB_CFSR_MSTKERR_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 4U) /*!< SCB CFSR (MMFSR): MSTKERR Position */ +#define SCB_CFSR_MSTKERR_Msk (1UL << SCB_CFSR_MSTKERR_Pos) /*!< SCB CFSR (MMFSR): MSTKERR Mask */ + +#define SCB_CFSR_MUNSTKERR_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 3U) /*!< SCB CFSR (MMFSR): MUNSTKERR Position */ +#define SCB_CFSR_MUNSTKERR_Msk (1UL << SCB_CFSR_MUNSTKERR_Pos) /*!< SCB CFSR (MMFSR): MUNSTKERR Mask */ + +#define SCB_CFSR_DACCVIOL_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 1U) /*!< SCB CFSR (MMFSR): DACCVIOL Position */ +#define SCB_CFSR_DACCVIOL_Msk (1UL << SCB_CFSR_DACCVIOL_Pos) /*!< SCB CFSR (MMFSR): DACCVIOL Mask */ + +#define SCB_CFSR_IACCVIOL_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 0U) /*!< SCB CFSR (MMFSR): IACCVIOL Position */ +#define SCB_CFSR_IACCVIOL_Msk (1UL /*<< SCB_CFSR_IACCVIOL_Pos*/) /*!< SCB CFSR (MMFSR): IACCVIOL Mask */ + +/* BusFault Status Register (part of SCB Configurable Fault Status Register) */ +#define SCB_CFSR_BFARVALID_Pos (SCB_CFSR_BUSFAULTSR_Pos + 7U) /*!< SCB CFSR (BFSR): BFARVALID Position */ +#define SCB_CFSR_BFARVALID_Msk (1UL << SCB_CFSR_BFARVALID_Pos) /*!< SCB CFSR (BFSR): BFARVALID Mask */ + +#define SCB_CFSR_LSPERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 5U) /*!< SCB CFSR (BFSR): LSPERR Position */ +#define SCB_CFSR_LSPERR_Msk (1UL << SCB_CFSR_LSPERR_Pos) /*!< SCB CFSR (BFSR): LSPERR Mask */ + +#define SCB_CFSR_STKERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 4U) /*!< SCB CFSR (BFSR): STKERR Position */ +#define SCB_CFSR_STKERR_Msk (1UL << SCB_CFSR_STKERR_Pos) /*!< SCB CFSR (BFSR): STKERR Mask */ + +#define SCB_CFSR_UNSTKERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 3U) /*!< SCB CFSR (BFSR): UNSTKERR Position */ +#define SCB_CFSR_UNSTKERR_Msk (1UL << SCB_CFSR_UNSTKERR_Pos) /*!< SCB CFSR (BFSR): UNSTKERR Mask */ + +#define SCB_CFSR_IMPRECISERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 2U) /*!< SCB CFSR (BFSR): IMPRECISERR Position */ +#define SCB_CFSR_IMPRECISERR_Msk (1UL << SCB_CFSR_IMPRECISERR_Pos) /*!< SCB CFSR (BFSR): IMPRECISERR Mask */ + +#define SCB_CFSR_PRECISERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 1U) /*!< SCB CFSR (BFSR): PRECISERR Position */ +#define SCB_CFSR_PRECISERR_Msk (1UL << SCB_CFSR_PRECISERR_Pos) /*!< SCB CFSR (BFSR): PRECISERR Mask */ + +#define SCB_CFSR_IBUSERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 0U) /*!< SCB CFSR (BFSR): IBUSERR Position */ +#define SCB_CFSR_IBUSERR_Msk (1UL << SCB_CFSR_IBUSERR_Pos) /*!< SCB CFSR (BFSR): IBUSERR Mask */ + +/* UsageFault Status Register (part of SCB Configurable Fault Status Register) */ +#define SCB_CFSR_DIVBYZERO_Pos (SCB_CFSR_USGFAULTSR_Pos + 9U) /*!< SCB CFSR (UFSR): DIVBYZERO Position */ +#define SCB_CFSR_DIVBYZERO_Msk (1UL << SCB_CFSR_DIVBYZERO_Pos) /*!< SCB CFSR (UFSR): DIVBYZERO Mask */ + +#define SCB_CFSR_UNALIGNED_Pos (SCB_CFSR_USGFAULTSR_Pos + 8U) /*!< SCB CFSR (UFSR): UNALIGNED Position */ +#define SCB_CFSR_UNALIGNED_Msk (1UL << SCB_CFSR_UNALIGNED_Pos) /*!< SCB CFSR (UFSR): UNALIGNED Mask */ + +#define SCB_CFSR_STKOF_Pos (SCB_CFSR_USGFAULTSR_Pos + 4U) /*!< SCB CFSR (UFSR): STKOF Position */ +#define SCB_CFSR_STKOF_Msk (1UL << SCB_CFSR_STKOF_Pos) /*!< SCB CFSR (UFSR): STKOF Mask */ + +#define SCB_CFSR_NOCP_Pos (SCB_CFSR_USGFAULTSR_Pos + 3U) /*!< SCB CFSR (UFSR): NOCP Position */ +#define SCB_CFSR_NOCP_Msk (1UL << SCB_CFSR_NOCP_Pos) /*!< SCB CFSR (UFSR): NOCP Mask */ + +#define SCB_CFSR_INVPC_Pos (SCB_CFSR_USGFAULTSR_Pos + 2U) /*!< SCB CFSR (UFSR): INVPC Position */ +#define SCB_CFSR_INVPC_Msk (1UL << SCB_CFSR_INVPC_Pos) /*!< SCB CFSR (UFSR): INVPC Mask */ + +#define SCB_CFSR_INVSTATE_Pos (SCB_CFSR_USGFAULTSR_Pos + 1U) /*!< SCB CFSR (UFSR): INVSTATE Position */ +#define SCB_CFSR_INVSTATE_Msk (1UL << SCB_CFSR_INVSTATE_Pos) /*!< SCB CFSR (UFSR): INVSTATE Mask */ + +#define SCB_CFSR_UNDEFINSTR_Pos (SCB_CFSR_USGFAULTSR_Pos + 0U) /*!< SCB CFSR (UFSR): UNDEFINSTR Position */ +#define SCB_CFSR_UNDEFINSTR_Msk (1UL << SCB_CFSR_UNDEFINSTR_Pos) /*!< SCB CFSR (UFSR): UNDEFINSTR Mask */ + +/* SCB Hard Fault Status Register Definitions */ +#define SCB_HFSR_DEBUGEVT_Pos 31U /*!< SCB HFSR: DEBUGEVT Position */ +#define SCB_HFSR_DEBUGEVT_Msk (1UL << SCB_HFSR_DEBUGEVT_Pos) /*!< SCB HFSR: DEBUGEVT Mask */ + +#define SCB_HFSR_FORCED_Pos 30U /*!< SCB HFSR: FORCED Position */ +#define SCB_HFSR_FORCED_Msk (1UL << SCB_HFSR_FORCED_Pos) /*!< SCB HFSR: FORCED Mask */ + +#define SCB_HFSR_VECTTBL_Pos 1U /*!< SCB HFSR: VECTTBL Position */ +#define SCB_HFSR_VECTTBL_Msk (1UL << SCB_HFSR_VECTTBL_Pos) /*!< SCB HFSR: VECTTBL Mask */ + +/* SCB Debug Fault Status Register Definitions */ +#define SCB_DFSR_EXTERNAL_Pos 4U /*!< SCB DFSR: EXTERNAL Position */ +#define SCB_DFSR_EXTERNAL_Msk (1UL << SCB_DFSR_EXTERNAL_Pos) /*!< SCB DFSR: EXTERNAL Mask */ + +#define SCB_DFSR_VCATCH_Pos 3U /*!< SCB DFSR: VCATCH Position */ +#define SCB_DFSR_VCATCH_Msk (1UL << SCB_DFSR_VCATCH_Pos) /*!< SCB DFSR: VCATCH Mask */ + +#define SCB_DFSR_DWTTRAP_Pos 2U /*!< SCB DFSR: DWTTRAP Position */ +#define SCB_DFSR_DWTTRAP_Msk (1UL << SCB_DFSR_DWTTRAP_Pos) /*!< SCB DFSR: DWTTRAP Mask */ + +#define SCB_DFSR_BKPT_Pos 1U /*!< SCB DFSR: BKPT Position */ +#define SCB_DFSR_BKPT_Msk (1UL << SCB_DFSR_BKPT_Pos) /*!< SCB DFSR: BKPT Mask */ + +#define SCB_DFSR_HALTED_Pos 0U /*!< SCB DFSR: HALTED Position */ +#define SCB_DFSR_HALTED_Msk (1UL /*<< SCB_DFSR_HALTED_Pos*/) /*!< SCB DFSR: HALTED Mask */ + +/* SCB Non-Secure Access Control Register Definitions */ +#define SCB_NSACR_CP11_Pos 11U /*!< SCB NSACR: CP11 Position */ +#define SCB_NSACR_CP11_Msk (1UL << SCB_NSACR_CP11_Pos) /*!< SCB NSACR: CP11 Mask */ + +#define SCB_NSACR_CP10_Pos 10U /*!< SCB NSACR: CP10 Position */ +#define SCB_NSACR_CP10_Msk (1UL << SCB_NSACR_CP10_Pos) /*!< SCB NSACR: CP10 Mask */ + +#define SCB_NSACR_CPn_Pos 0U /*!< SCB NSACR: CPn Position */ +#define SCB_NSACR_CPn_Msk (1UL /*<< SCB_NSACR_CPn_Pos*/) /*!< SCB NSACR: CPn Mask */ + +/* SCB Cache Level ID Register Definitions */ +#define SCB_CLIDR_LOUU_Pos 27U /*!< SCB CLIDR: LoUU Position */ +#define SCB_CLIDR_LOUU_Msk (7UL << SCB_CLIDR_LOUU_Pos) /*!< SCB CLIDR: LoUU Mask */ + +#define SCB_CLIDR_LOC_Pos 24U /*!< SCB CLIDR: LoC Position */ +#define SCB_CLIDR_LOC_Msk (7UL << SCB_CLIDR_LOC_Pos) /*!< SCB CLIDR: LoC Mask */ + +/* SCB Cache Type Register Definitions */ +#define SCB_CTR_FORMAT_Pos 29U /*!< SCB CTR: Format Position */ +#define SCB_CTR_FORMAT_Msk (7UL << SCB_CTR_FORMAT_Pos) /*!< SCB CTR: Format Mask */ + +#define SCB_CTR_CWG_Pos 24U /*!< SCB CTR: CWG Position */ +#define SCB_CTR_CWG_Msk (0xFUL << SCB_CTR_CWG_Pos) /*!< SCB CTR: CWG Mask */ + +#define SCB_CTR_ERG_Pos 20U /*!< SCB CTR: ERG Position */ +#define SCB_CTR_ERG_Msk (0xFUL << SCB_CTR_ERG_Pos) /*!< SCB CTR: ERG Mask */ + +#define SCB_CTR_DMINLINE_Pos 16U /*!< SCB CTR: DminLine Position */ +#define SCB_CTR_DMINLINE_Msk (0xFUL << SCB_CTR_DMINLINE_Pos) /*!< SCB CTR: DminLine Mask */ + +#define SCB_CTR_IMINLINE_Pos 0U /*!< SCB CTR: ImInLine Position */ +#define SCB_CTR_IMINLINE_Msk (0xFUL /*<< SCB_CTR_IMINLINE_Pos*/) /*!< SCB CTR: ImInLine Mask */ + +/* SCB Cache Size ID Register Definitions */ +#define SCB_CCSIDR_WT_Pos 31U /*!< SCB CCSIDR: WT Position */ +#define SCB_CCSIDR_WT_Msk (1UL << SCB_CCSIDR_WT_Pos) /*!< SCB CCSIDR: WT Mask */ + +#define SCB_CCSIDR_WB_Pos 30U /*!< SCB CCSIDR: WB Position */ +#define SCB_CCSIDR_WB_Msk (1UL << SCB_CCSIDR_WB_Pos) /*!< SCB CCSIDR: WB Mask */ + +#define SCB_CCSIDR_RA_Pos 29U /*!< SCB CCSIDR: RA Position */ +#define SCB_CCSIDR_RA_Msk (1UL << SCB_CCSIDR_RA_Pos) /*!< SCB CCSIDR: RA Mask */ + +#define SCB_CCSIDR_WA_Pos 28U /*!< SCB CCSIDR: WA Position */ +#define SCB_CCSIDR_WA_Msk (1UL << SCB_CCSIDR_WA_Pos) /*!< SCB CCSIDR: WA Mask */ + +#define SCB_CCSIDR_NUMSETS_Pos 13U /*!< SCB CCSIDR: NumSets Position */ +#define SCB_CCSIDR_NUMSETS_Msk (0x7FFFUL << SCB_CCSIDR_NUMSETS_Pos) /*!< SCB CCSIDR: NumSets Mask */ + +#define SCB_CCSIDR_ASSOCIATIVITY_Pos 3U /*!< SCB CCSIDR: Associativity Position */ +#define SCB_CCSIDR_ASSOCIATIVITY_Msk (0x3FFUL << SCB_CCSIDR_ASSOCIATIVITY_Pos) /*!< SCB CCSIDR: Associativity Mask */ + +#define SCB_CCSIDR_LINESIZE_Pos 0U /*!< SCB CCSIDR: LineSize Position */ +#define SCB_CCSIDR_LINESIZE_Msk (7UL /*<< SCB_CCSIDR_LINESIZE_Pos*/) /*!< SCB CCSIDR: LineSize Mask */ + +/* SCB Cache Size Selection Register Definitions */ +#define SCB_CSSELR_LEVEL_Pos 1U /*!< SCB CSSELR: Level Position */ +#define SCB_CSSELR_LEVEL_Msk (7UL << SCB_CSSELR_LEVEL_Pos) /*!< SCB CSSELR: Level Mask */ + +#define SCB_CSSELR_IND_Pos 0U /*!< SCB CSSELR: InD Position */ +#define SCB_CSSELR_IND_Msk (1UL /*<< SCB_CSSELR_IND_Pos*/) /*!< SCB CSSELR: InD Mask */ + +/* SCB Software Triggered Interrupt Register Definitions */ +#define SCB_STIR_INTID_Pos 0U /*!< SCB STIR: INTID Position */ +#define SCB_STIR_INTID_Msk (0x1FFUL /*<< SCB_STIR_INTID_Pos*/) /*!< SCB STIR: INTID Mask */ + +/* SCB D-Cache Invalidate by Set-way Register Definitions */ +#define SCB_DCISW_WAY_Pos 30U /*!< SCB DCISW: Way Position */ +#define SCB_DCISW_WAY_Msk (3UL << SCB_DCISW_WAY_Pos) /*!< SCB DCISW: Way Mask */ + +#define SCB_DCISW_SET_Pos 5U /*!< SCB DCISW: Set Position */ +#define SCB_DCISW_SET_Msk (0x1FFUL << SCB_DCISW_SET_Pos) /*!< SCB DCISW: Set Mask */ + +/* SCB D-Cache Clean by Set-way Register Definitions */ +#define SCB_DCCSW_WAY_Pos 30U /*!< SCB DCCSW: Way Position */ +#define SCB_DCCSW_WAY_Msk (3UL << SCB_DCCSW_WAY_Pos) /*!< SCB DCCSW: Way Mask */ + +#define SCB_DCCSW_SET_Pos 5U /*!< SCB DCCSW: Set Position */ +#define SCB_DCCSW_SET_Msk (0x1FFUL << SCB_DCCSW_SET_Pos) /*!< SCB DCCSW: Set Mask */ + +/* SCB D-Cache Clean and Invalidate by Set-way Register Definitions */ +#define SCB_DCCISW_WAY_Pos 30U /*!< SCB DCCISW: Way Position */ +#define SCB_DCCISW_WAY_Msk (3UL << SCB_DCCISW_WAY_Pos) /*!< SCB DCCISW: Way Mask */ + +#define SCB_DCCISW_SET_Pos 5U /*!< SCB DCCISW: Set Position */ +#define SCB_DCCISW_SET_Msk (0x1FFUL << SCB_DCCISW_SET_Pos) /*!< SCB DCCISW: Set Mask */ + +/*@} end of group CMSIS_SCB */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SCnSCB System Controls not in SCB (SCnSCB) + \brief Type definitions for the System Control and ID Register not in the SCB + @{ + */ + +/** + \brief Structure type to access the System Control and ID Register not in the SCB. + */ +typedef struct +{ + uint32_t RESERVED0[1U]; + __IM uint32_t ICTR; /*!< Offset: 0x004 (R/ ) Interrupt Controller Type Register */ + __IOM uint32_t ACTLR; /*!< Offset: 0x008 (R/W) Auxiliary Control Register */ + __IOM uint32_t CPPWR; /*!< Offset: 0x00C (R/W) Coprocessor Power Control Register */ +} SCnSCB_Type; + +/* Interrupt Controller Type Register Definitions */ +#define SCnSCB_ICTR_INTLINESNUM_Pos 0U /*!< ICTR: INTLINESNUM Position */ +#define SCnSCB_ICTR_INTLINESNUM_Msk (0xFUL /*<< SCnSCB_ICTR_INTLINESNUM_Pos*/) /*!< ICTR: INTLINESNUM Mask */ + +/*@} end of group CMSIS_SCnotSCB */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SysTick System Tick Timer (SysTick) + \brief Type definitions for the System Timer Registers. + @{ + */ + +/** + \brief Structure type to access the System Timer (SysTick). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */ + __IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */ + __IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */ + __IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */ +} SysTick_Type; + +/* SysTick Control / Status Register Definitions */ +#define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */ +#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */ + +#define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */ +#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */ + +#define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */ +#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */ + +#define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */ +#define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */ + +/* SysTick Reload Register Definitions */ +#define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */ +#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */ + +/* SysTick Current Register Definitions */ +#define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */ +#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */ + +/* SysTick Calibration Register Definitions */ +#define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */ +#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */ + +#define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */ +#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */ + +#define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */ +#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */ + +/*@} end of group CMSIS_SysTick */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_ITM Instrumentation Trace Macrocell (ITM) + \brief Type definitions for the Instrumentation Trace Macrocell (ITM) + @{ + */ + +/** + \brief Structure type to access the Instrumentation Trace Macrocell Register (ITM). + */ +typedef struct +{ + __OM union + { + __OM uint8_t u8; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 8-bit */ + __OM uint16_t u16; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 16-bit */ + __OM uint32_t u32; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 32-bit */ + } PORT [32U]; /*!< Offset: 0x000 ( /W) ITM Stimulus Port Registers */ + uint32_t RESERVED0[864U]; + __IOM uint32_t TER; /*!< Offset: 0xE00 (R/W) ITM Trace Enable Register */ + uint32_t RESERVED1[15U]; + __IOM uint32_t TPR; /*!< Offset: 0xE40 (R/W) ITM Trace Privilege Register */ + uint32_t RESERVED2[15U]; + __IOM uint32_t TCR; /*!< Offset: 0xE80 (R/W) ITM Trace Control Register */ + uint32_t RESERVED3[32U]; + uint32_t RESERVED4[43U]; + __OM uint32_t LAR; /*!< Offset: 0xFB0 ( /W) ITM Lock Access Register */ + __IM uint32_t LSR; /*!< Offset: 0xFB4 (R/ ) ITM Lock Status Register */ + uint32_t RESERVED5[1U]; + __IM uint32_t DEVARCH; /*!< Offset: 0xFBC (R/ ) ITM Device Architecture Register */ + uint32_t RESERVED6[4U]; + __IM uint32_t PID4; /*!< Offset: 0xFD0 (R/ ) ITM Peripheral Identification Register #4 */ + __IM uint32_t PID5; /*!< Offset: 0xFD4 (R/ ) ITM Peripheral Identification Register #5 */ + __IM uint32_t PID6; /*!< Offset: 0xFD8 (R/ ) ITM Peripheral Identification Register #6 */ + __IM uint32_t PID7; /*!< Offset: 0xFDC (R/ ) ITM Peripheral Identification Register #7 */ + __IM uint32_t PID0; /*!< Offset: 0xFE0 (R/ ) ITM Peripheral Identification Register #0 */ + __IM uint32_t PID1; /*!< Offset: 0xFE4 (R/ ) ITM Peripheral Identification Register #1 */ + __IM uint32_t PID2; /*!< Offset: 0xFE8 (R/ ) ITM Peripheral Identification Register #2 */ + __IM uint32_t PID3; /*!< Offset: 0xFEC (R/ ) ITM Peripheral Identification Register #3 */ + __IM uint32_t CID0; /*!< Offset: 0xFF0 (R/ ) ITM Component Identification Register #0 */ + __IM uint32_t CID1; /*!< Offset: 0xFF4 (R/ ) ITM Component Identification Register #1 */ + __IM uint32_t CID2; /*!< Offset: 0xFF8 (R/ ) ITM Component Identification Register #2 */ + __IM uint32_t CID3; /*!< Offset: 0xFFC (R/ ) ITM Component Identification Register #3 */ +} ITM_Type; + +/* ITM Stimulus Port Register Definitions */ +#define ITM_STIM_DISABLED_Pos 1U /*!< ITM STIM: DISABLED Position */ +#define ITM_STIM_DISABLED_Msk (0x1UL << ITM_STIM_DISABLED_Pos) /*!< ITM STIM: DISABLED Mask */ + +#define ITM_STIM_FIFOREADY_Pos 0U /*!< ITM STIM: FIFOREADY Position */ +#define ITM_STIM_FIFOREADY_Msk (0x1UL /*<< ITM_STIM_FIFOREADY_Pos*/) /*!< ITM STIM: FIFOREADY Mask */ + +/* ITM Trace Privilege Register Definitions */ +#define ITM_TPR_PRIVMASK_Pos 0U /*!< ITM TPR: PRIVMASK Position */ +#define ITM_TPR_PRIVMASK_Msk (0xFFFFFFFFUL /*<< ITM_TPR_PRIVMASK_Pos*/) /*!< ITM TPR: PRIVMASK Mask */ + +/* ITM Trace Control Register Definitions */ +#define ITM_TCR_BUSY_Pos 23U /*!< ITM TCR: BUSY Position */ +#define ITM_TCR_BUSY_Msk (1UL << ITM_TCR_BUSY_Pos) /*!< ITM TCR: BUSY Mask */ + +#define ITM_TCR_TRACEBUSID_Pos 16U /*!< ITM TCR: ATBID Position */ +#define ITM_TCR_TRACEBUSID_Msk (0x7FUL << ITM_TCR_TRACEBUSID_Pos) /*!< ITM TCR: ATBID Mask */ + +#define ITM_TCR_GTSFREQ_Pos 10U /*!< ITM TCR: Global timestamp frequency Position */ +#define ITM_TCR_GTSFREQ_Msk (3UL << ITM_TCR_GTSFREQ_Pos) /*!< ITM TCR: Global timestamp frequency Mask */ + +#define ITM_TCR_TSPRESCALE_Pos 8U /*!< ITM TCR: TSPRESCALE Position */ +#define ITM_TCR_TSPRESCALE_Msk (3UL << ITM_TCR_TSPRESCALE_Pos) /*!< ITM TCR: TSPRESCALE Mask */ + +#define ITM_TCR_STALLENA_Pos 5U /*!< ITM TCR: STALLENA Position */ +#define ITM_TCR_STALLENA_Msk (1UL << ITM_TCR_STALLENA_Pos) /*!< ITM TCR: STALLENA Mask */ + +#define ITM_TCR_SWOENA_Pos 4U /*!< ITM TCR: SWOENA Position */ +#define ITM_TCR_SWOENA_Msk (1UL << ITM_TCR_SWOENA_Pos) /*!< ITM TCR: SWOENA Mask */ + +#define ITM_TCR_DWTENA_Pos 3U /*!< ITM TCR: DWTENA Position */ +#define ITM_TCR_DWTENA_Msk (1UL << ITM_TCR_DWTENA_Pos) /*!< ITM TCR: DWTENA Mask */ + +#define ITM_TCR_SYNCENA_Pos 2U /*!< ITM TCR: SYNCENA Position */ +#define ITM_TCR_SYNCENA_Msk (1UL << ITM_TCR_SYNCENA_Pos) /*!< ITM TCR: SYNCENA Mask */ + +#define ITM_TCR_TSENA_Pos 1U /*!< ITM TCR: TSENA Position */ +#define ITM_TCR_TSENA_Msk (1UL << ITM_TCR_TSENA_Pos) /*!< ITM TCR: TSENA Mask */ + +#define ITM_TCR_ITMENA_Pos 0U /*!< ITM TCR: ITM Enable bit Position */ +#define ITM_TCR_ITMENA_Msk (1UL /*<< ITM_TCR_ITMENA_Pos*/) /*!< ITM TCR: ITM Enable bit Mask */ + +/* ITM Lock Status Register Definitions */ +#define ITM_LSR_ByteAcc_Pos 2U /*!< ITM LSR: ByteAcc Position */ +#define ITM_LSR_ByteAcc_Msk (1UL << ITM_LSR_ByteAcc_Pos) /*!< ITM LSR: ByteAcc Mask */ + +#define ITM_LSR_Access_Pos 1U /*!< ITM LSR: Access Position */ +#define ITM_LSR_Access_Msk (1UL << ITM_LSR_Access_Pos) /*!< ITM LSR: Access Mask */ + +#define ITM_LSR_Present_Pos 0U /*!< ITM LSR: Present Position */ +#define ITM_LSR_Present_Msk (1UL /*<< ITM_LSR_Present_Pos*/) /*!< ITM LSR: Present Mask */ + +/*@}*/ /* end of group CMSIS_ITM */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_DWT Data Watchpoint and Trace (DWT) + \brief Type definitions for the Data Watchpoint and Trace (DWT) + @{ + */ + +/** + \brief Structure type to access the Data Watchpoint and Trace Register (DWT). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) Control Register */ + __IOM uint32_t CYCCNT; /*!< Offset: 0x004 (R/W) Cycle Count Register */ + __IOM uint32_t CPICNT; /*!< Offset: 0x008 (R/W) CPI Count Register */ + __IOM uint32_t EXCCNT; /*!< Offset: 0x00C (R/W) Exception Overhead Count Register */ + __IOM uint32_t SLEEPCNT; /*!< Offset: 0x010 (R/W) Sleep Count Register */ + __IOM uint32_t LSUCNT; /*!< Offset: 0x014 (R/W) LSU Count Register */ + __IOM uint32_t FOLDCNT; /*!< Offset: 0x018 (R/W) Folded-instruction Count Register */ + __IM uint32_t PCSR; /*!< Offset: 0x01C (R/ ) Program Counter Sample Register */ + __IOM uint32_t COMP0; /*!< Offset: 0x020 (R/W) Comparator Register 0 */ + uint32_t RESERVED1[1U]; + __IOM uint32_t FUNCTION0; /*!< Offset: 0x028 (R/W) Function Register 0 */ + uint32_t RESERVED2[1U]; + __IOM uint32_t COMP1; /*!< Offset: 0x030 (R/W) Comparator Register 1 */ + uint32_t RESERVED3[1U]; + __IOM uint32_t FUNCTION1; /*!< Offset: 0x038 (R/W) Function Register 1 */ + uint32_t RESERVED4[1U]; + __IOM uint32_t COMP2; /*!< Offset: 0x040 (R/W) Comparator Register 2 */ + uint32_t RESERVED5[1U]; + __IOM uint32_t FUNCTION2; /*!< Offset: 0x048 (R/W) Function Register 2 */ + uint32_t RESERVED6[1U]; + __IOM uint32_t COMP3; /*!< Offset: 0x050 (R/W) Comparator Register 3 */ + uint32_t RESERVED7[1U]; + __IOM uint32_t FUNCTION3; /*!< Offset: 0x058 (R/W) Function Register 3 */ + uint32_t RESERVED8[1U]; + __IOM uint32_t COMP4; /*!< Offset: 0x060 (R/W) Comparator Register 4 */ + uint32_t RESERVED9[1U]; + __IOM uint32_t FUNCTION4; /*!< Offset: 0x068 (R/W) Function Register 4 */ + uint32_t RESERVED10[1U]; + __IOM uint32_t COMP5; /*!< Offset: 0x070 (R/W) Comparator Register 5 */ + uint32_t RESERVED11[1U]; + __IOM uint32_t FUNCTION5; /*!< Offset: 0x078 (R/W) Function Register 5 */ + uint32_t RESERVED12[1U]; + __IOM uint32_t COMP6; /*!< Offset: 0x080 (R/W) Comparator Register 6 */ + uint32_t RESERVED13[1U]; + __IOM uint32_t FUNCTION6; /*!< Offset: 0x088 (R/W) Function Register 6 */ + uint32_t RESERVED14[1U]; + __IOM uint32_t COMP7; /*!< Offset: 0x090 (R/W) Comparator Register 7 */ + uint32_t RESERVED15[1U]; + __IOM uint32_t FUNCTION7; /*!< Offset: 0x098 (R/W) Function Register 7 */ + uint32_t RESERVED16[1U]; + __IOM uint32_t COMP8; /*!< Offset: 0x0A0 (R/W) Comparator Register 8 */ + uint32_t RESERVED17[1U]; + __IOM uint32_t FUNCTION8; /*!< Offset: 0x0A8 (R/W) Function Register 8 */ + uint32_t RESERVED18[1U]; + __IOM uint32_t COMP9; /*!< Offset: 0x0B0 (R/W) Comparator Register 9 */ + uint32_t RESERVED19[1U]; + __IOM uint32_t FUNCTION9; /*!< Offset: 0x0B8 (R/W) Function Register 9 */ + uint32_t RESERVED20[1U]; + __IOM uint32_t COMP10; /*!< Offset: 0x0C0 (R/W) Comparator Register 10 */ + uint32_t RESERVED21[1U]; + __IOM uint32_t FUNCTION10; /*!< Offset: 0x0C8 (R/W) Function Register 10 */ + uint32_t RESERVED22[1U]; + __IOM uint32_t COMP11; /*!< Offset: 0x0D0 (R/W) Comparator Register 11 */ + uint32_t RESERVED23[1U]; + __IOM uint32_t FUNCTION11; /*!< Offset: 0x0D8 (R/W) Function Register 11 */ + uint32_t RESERVED24[1U]; + __IOM uint32_t COMP12; /*!< Offset: 0x0E0 (R/W) Comparator Register 12 */ + uint32_t RESERVED25[1U]; + __IOM uint32_t FUNCTION12; /*!< Offset: 0x0E8 (R/W) Function Register 12 */ + uint32_t RESERVED26[1U]; + __IOM uint32_t COMP13; /*!< Offset: 0x0F0 (R/W) Comparator Register 13 */ + uint32_t RESERVED27[1U]; + __IOM uint32_t FUNCTION13; /*!< Offset: 0x0F8 (R/W) Function Register 13 */ + uint32_t RESERVED28[1U]; + __IOM uint32_t COMP14; /*!< Offset: 0x100 (R/W) Comparator Register 14 */ + uint32_t RESERVED29[1U]; + __IOM uint32_t FUNCTION14; /*!< Offset: 0x108 (R/W) Function Register 14 */ + uint32_t RESERVED30[1U]; + __IOM uint32_t COMP15; /*!< Offset: 0x110 (R/W) Comparator Register 15 */ + uint32_t RESERVED31[1U]; + __IOM uint32_t FUNCTION15; /*!< Offset: 0x118 (R/W) Function Register 15 */ + uint32_t RESERVED32[934U]; + __IM uint32_t LSR; /*!< Offset: 0xFB4 (R ) Lock Status Register */ + uint32_t RESERVED33[1U]; + __IM uint32_t DEVARCH; /*!< Offset: 0xFBC (R/ ) Device Architecture Register */ +} DWT_Type; + +/* DWT Control Register Definitions */ +#define DWT_CTRL_NUMCOMP_Pos 28U /*!< DWT CTRL: NUMCOMP Position */ +#define DWT_CTRL_NUMCOMP_Msk (0xFUL << DWT_CTRL_NUMCOMP_Pos) /*!< DWT CTRL: NUMCOMP Mask */ + +#define DWT_CTRL_NOTRCPKT_Pos 27U /*!< DWT CTRL: NOTRCPKT Position */ +#define DWT_CTRL_NOTRCPKT_Msk (0x1UL << DWT_CTRL_NOTRCPKT_Pos) /*!< DWT CTRL: NOTRCPKT Mask */ + +#define DWT_CTRL_NOEXTTRIG_Pos 26U /*!< DWT CTRL: NOEXTTRIG Position */ +#define DWT_CTRL_NOEXTTRIG_Msk (0x1UL << DWT_CTRL_NOEXTTRIG_Pos) /*!< DWT CTRL: NOEXTTRIG Mask */ + +#define DWT_CTRL_NOCYCCNT_Pos 25U /*!< DWT CTRL: NOCYCCNT Position */ +#define DWT_CTRL_NOCYCCNT_Msk (0x1UL << DWT_CTRL_NOCYCCNT_Pos) /*!< DWT CTRL: NOCYCCNT Mask */ + +#define DWT_CTRL_NOPRFCNT_Pos 24U /*!< DWT CTRL: NOPRFCNT Position */ +#define DWT_CTRL_NOPRFCNT_Msk (0x1UL << DWT_CTRL_NOPRFCNT_Pos) /*!< DWT CTRL: NOPRFCNT Mask */ + +#define DWT_CTRL_CYCDISS_Pos 23U /*!< DWT CTRL: CYCDISS Position */ +#define DWT_CTRL_CYCDISS_Msk (0x1UL << DWT_CTRL_CYCDISS_Pos) /*!< DWT CTRL: CYCDISS Mask */ + +#define DWT_CTRL_CYCEVTENA_Pos 22U /*!< DWT CTRL: CYCEVTENA Position */ +#define DWT_CTRL_CYCEVTENA_Msk (0x1UL << DWT_CTRL_CYCEVTENA_Pos) /*!< DWT CTRL: CYCEVTENA Mask */ + +#define DWT_CTRL_FOLDEVTENA_Pos 21U /*!< DWT CTRL: FOLDEVTENA Position */ +#define DWT_CTRL_FOLDEVTENA_Msk (0x1UL << DWT_CTRL_FOLDEVTENA_Pos) /*!< DWT CTRL: FOLDEVTENA Mask */ + +#define DWT_CTRL_LSUEVTENA_Pos 20U /*!< DWT CTRL: LSUEVTENA Position */ +#define DWT_CTRL_LSUEVTENA_Msk (0x1UL << DWT_CTRL_LSUEVTENA_Pos) /*!< DWT CTRL: LSUEVTENA Mask */ + +#define DWT_CTRL_SLEEPEVTENA_Pos 19U /*!< DWT CTRL: SLEEPEVTENA Position */ +#define DWT_CTRL_SLEEPEVTENA_Msk (0x1UL << DWT_CTRL_SLEEPEVTENA_Pos) /*!< DWT CTRL: SLEEPEVTENA Mask */ + +#define DWT_CTRL_EXCEVTENA_Pos 18U /*!< DWT CTRL: EXCEVTENA Position */ +#define DWT_CTRL_EXCEVTENA_Msk (0x1UL << DWT_CTRL_EXCEVTENA_Pos) /*!< DWT CTRL: EXCEVTENA Mask */ + +#define DWT_CTRL_CPIEVTENA_Pos 17U /*!< DWT CTRL: CPIEVTENA Position */ +#define DWT_CTRL_CPIEVTENA_Msk (0x1UL << DWT_CTRL_CPIEVTENA_Pos) /*!< DWT CTRL: CPIEVTENA Mask */ + +#define DWT_CTRL_EXCTRCENA_Pos 16U /*!< DWT CTRL: EXCTRCENA Position */ +#define DWT_CTRL_EXCTRCENA_Msk (0x1UL << DWT_CTRL_EXCTRCENA_Pos) /*!< DWT CTRL: EXCTRCENA Mask */ + +#define DWT_CTRL_PCSAMPLENA_Pos 12U /*!< DWT CTRL: PCSAMPLENA Position */ +#define DWT_CTRL_PCSAMPLENA_Msk (0x1UL << DWT_CTRL_PCSAMPLENA_Pos) /*!< DWT CTRL: PCSAMPLENA Mask */ + +#define DWT_CTRL_SYNCTAP_Pos 10U /*!< DWT CTRL: SYNCTAP Position */ +#define DWT_CTRL_SYNCTAP_Msk (0x3UL << DWT_CTRL_SYNCTAP_Pos) /*!< DWT CTRL: SYNCTAP Mask */ + +#define DWT_CTRL_CYCTAP_Pos 9U /*!< DWT CTRL: CYCTAP Position */ +#define DWT_CTRL_CYCTAP_Msk (0x1UL << DWT_CTRL_CYCTAP_Pos) /*!< DWT CTRL: CYCTAP Mask */ + +#define DWT_CTRL_POSTINIT_Pos 5U /*!< DWT CTRL: POSTINIT Position */ +#define DWT_CTRL_POSTINIT_Msk (0xFUL << DWT_CTRL_POSTINIT_Pos) /*!< DWT CTRL: POSTINIT Mask */ + +#define DWT_CTRL_POSTPRESET_Pos 1U /*!< DWT CTRL: POSTPRESET Position */ +#define DWT_CTRL_POSTPRESET_Msk (0xFUL << DWT_CTRL_POSTPRESET_Pos) /*!< DWT CTRL: POSTPRESET Mask */ + +#define DWT_CTRL_CYCCNTENA_Pos 0U /*!< DWT CTRL: CYCCNTENA Position */ +#define DWT_CTRL_CYCCNTENA_Msk (0x1UL /*<< DWT_CTRL_CYCCNTENA_Pos*/) /*!< DWT CTRL: CYCCNTENA Mask */ + +/* DWT CPI Count Register Definitions */ +#define DWT_CPICNT_CPICNT_Pos 0U /*!< DWT CPICNT: CPICNT Position */ +#define DWT_CPICNT_CPICNT_Msk (0xFFUL /*<< DWT_CPICNT_CPICNT_Pos*/) /*!< DWT CPICNT: CPICNT Mask */ + +/* DWT Exception Overhead Count Register Definitions */ +#define DWT_EXCCNT_EXCCNT_Pos 0U /*!< DWT EXCCNT: EXCCNT Position */ +#define DWT_EXCCNT_EXCCNT_Msk (0xFFUL /*<< DWT_EXCCNT_EXCCNT_Pos*/) /*!< DWT EXCCNT: EXCCNT Mask */ + +/* DWT Sleep Count Register Definitions */ +#define DWT_SLEEPCNT_SLEEPCNT_Pos 0U /*!< DWT SLEEPCNT: SLEEPCNT Position */ +#define DWT_SLEEPCNT_SLEEPCNT_Msk (0xFFUL /*<< DWT_SLEEPCNT_SLEEPCNT_Pos*/) /*!< DWT SLEEPCNT: SLEEPCNT Mask */ + +/* DWT LSU Count Register Definitions */ +#define DWT_LSUCNT_LSUCNT_Pos 0U /*!< DWT LSUCNT: LSUCNT Position */ +#define DWT_LSUCNT_LSUCNT_Msk (0xFFUL /*<< DWT_LSUCNT_LSUCNT_Pos*/) /*!< DWT LSUCNT: LSUCNT Mask */ + +/* DWT Folded-instruction Count Register Definitions */ +#define DWT_FOLDCNT_FOLDCNT_Pos 0U /*!< DWT FOLDCNT: FOLDCNT Position */ +#define DWT_FOLDCNT_FOLDCNT_Msk (0xFFUL /*<< DWT_FOLDCNT_FOLDCNT_Pos*/) /*!< DWT FOLDCNT: FOLDCNT Mask */ + +/* DWT Comparator Function Register Definitions */ +#define DWT_FUNCTION_ID_Pos 27U /*!< DWT FUNCTION: ID Position */ +#define DWT_FUNCTION_ID_Msk (0x1FUL << DWT_FUNCTION_ID_Pos) /*!< DWT FUNCTION: ID Mask */ + +#define DWT_FUNCTION_MATCHED_Pos 24U /*!< DWT FUNCTION: MATCHED Position */ +#define DWT_FUNCTION_MATCHED_Msk (0x1UL << DWT_FUNCTION_MATCHED_Pos) /*!< DWT FUNCTION: MATCHED Mask */ + +#define DWT_FUNCTION_DATAVSIZE_Pos 10U /*!< DWT FUNCTION: DATAVSIZE Position */ +#define DWT_FUNCTION_DATAVSIZE_Msk (0x3UL << DWT_FUNCTION_DATAVSIZE_Pos) /*!< DWT FUNCTION: DATAVSIZE Mask */ + +#define DWT_FUNCTION_ACTION_Pos 4U /*!< DWT FUNCTION: ACTION Position */ +#define DWT_FUNCTION_ACTION_Msk (0x1UL << DWT_FUNCTION_ACTION_Pos) /*!< DWT FUNCTION: ACTION Mask */ + +#define DWT_FUNCTION_MATCH_Pos 0U /*!< DWT FUNCTION: MATCH Position */ +#define DWT_FUNCTION_MATCH_Msk (0xFUL /*<< DWT_FUNCTION_MATCH_Pos*/) /*!< DWT FUNCTION: MATCH Mask */ + +/*@}*/ /* end of group CMSIS_DWT */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_TPI Trace Port Interface (TPI) + \brief Type definitions for the Trace Port Interface (TPI) + @{ + */ + +/** + \brief Structure type to access the Trace Port Interface Register (TPI). + */ +typedef struct +{ + __IM uint32_t SSPSR; /*!< Offset: 0x000 (R/ ) Supported Parallel Port Size Register */ + __IOM uint32_t CSPSR; /*!< Offset: 0x004 (R/W) Current Parallel Port Size Register */ + uint32_t RESERVED0[2U]; + __IOM uint32_t ACPR; /*!< Offset: 0x010 (R/W) Asynchronous Clock Prescaler Register */ + uint32_t RESERVED1[55U]; + __IOM uint32_t SPPR; /*!< Offset: 0x0F0 (R/W) Selected Pin Protocol Register */ + uint32_t RESERVED2[131U]; + __IM uint32_t FFSR; /*!< Offset: 0x300 (R/ ) Formatter and Flush Status Register */ + __IOM uint32_t FFCR; /*!< Offset: 0x304 (R/W) Formatter and Flush Control Register */ + __IOM uint32_t PSCR; /*!< Offset: 0x308 (R/W) Periodic Synchronization Control Register */ + uint32_t RESERVED3[759U]; + __IM uint32_t TRIGGER; /*!< Offset: 0xEE8 (R/ ) TRIGGER Register */ + __IM uint32_t ITFTTD0; /*!< Offset: 0xEEC (R/ ) Integration Test FIFO Test Data 0 Register */ + __IOM uint32_t ITATBCTR2; /*!< Offset: 0xEF0 (R/W) Integration Test ATB Control Register 2 */ + uint32_t RESERVED4[1U]; + __IM uint32_t ITATBCTR0; /*!< Offset: 0xEF8 (R/ ) Integration Test ATB Control Register 0 */ + __IM uint32_t ITFTTD1; /*!< Offset: 0xEFC (R/ ) Integration Test FIFO Test Data 1 Register */ + __IOM uint32_t ITCTRL; /*!< Offset: 0xF00 (R/W) Integration Mode Control */ + uint32_t RESERVED5[39U]; + __IOM uint32_t CLAIMSET; /*!< Offset: 0xFA0 (R/W) Claim tag set */ + __IOM uint32_t CLAIMCLR; /*!< Offset: 0xFA4 (R/W) Claim tag clear */ + uint32_t RESERVED7[8U]; + __IM uint32_t DEVID; /*!< Offset: 0xFC8 (R/ ) Device Configuration Register */ + __IM uint32_t DEVTYPE; /*!< Offset: 0xFCC (R/ ) Device Type Identifier Register */ +} TPI_Type; + +/* TPI Asynchronous Clock Prescaler Register Definitions */ +#define TPI_ACPR_PRESCALER_Pos 0U /*!< TPI ACPR: PRESCALER Position */ +#define TPI_ACPR_PRESCALER_Msk (0x1FFFUL /*<< TPI_ACPR_PRESCALER_Pos*/) /*!< TPI ACPR: PRESCALER Mask */ + +/* TPI Selected Pin Protocol Register Definitions */ +#define TPI_SPPR_TXMODE_Pos 0U /*!< TPI SPPR: TXMODE Position */ +#define TPI_SPPR_TXMODE_Msk (0x3UL /*<< TPI_SPPR_TXMODE_Pos*/) /*!< TPI SPPR: TXMODE Mask */ + +/* TPI Formatter and Flush Status Register Definitions */ +#define TPI_FFSR_FtNonStop_Pos 3U /*!< TPI FFSR: FtNonStop Position */ +#define TPI_FFSR_FtNonStop_Msk (0x1UL << TPI_FFSR_FtNonStop_Pos) /*!< TPI FFSR: FtNonStop Mask */ + +#define TPI_FFSR_TCPresent_Pos 2U /*!< TPI FFSR: TCPresent Position */ +#define TPI_FFSR_TCPresent_Msk (0x1UL << TPI_FFSR_TCPresent_Pos) /*!< TPI FFSR: TCPresent Mask */ + +#define TPI_FFSR_FtStopped_Pos 1U /*!< TPI FFSR: FtStopped Position */ +#define TPI_FFSR_FtStopped_Msk (0x1UL << TPI_FFSR_FtStopped_Pos) /*!< TPI FFSR: FtStopped Mask */ + +#define TPI_FFSR_FlInProg_Pos 0U /*!< TPI FFSR: FlInProg Position */ +#define TPI_FFSR_FlInProg_Msk (0x1UL /*<< TPI_FFSR_FlInProg_Pos*/) /*!< TPI FFSR: FlInProg Mask */ + +/* TPI Formatter and Flush Control Register Definitions */ +#define TPI_FFCR_TrigIn_Pos 8U /*!< TPI FFCR: TrigIn Position */ +#define TPI_FFCR_TrigIn_Msk (0x1UL << TPI_FFCR_TrigIn_Pos) /*!< TPI FFCR: TrigIn Mask */ + +#define TPI_FFCR_FOnMan_Pos 6U /*!< TPI FFCR: FOnMan Position */ +#define TPI_FFCR_FOnMan_Msk (0x1UL << TPI_FFCR_FOnMan_Pos) /*!< TPI FFCR: FOnMan Mask */ + +#define TPI_FFCR_EnFCont_Pos 1U /*!< TPI FFCR: EnFCont Position */ +#define TPI_FFCR_EnFCont_Msk (0x1UL << TPI_FFCR_EnFCont_Pos) /*!< TPI FFCR: EnFCont Mask */ + +/* TPI TRIGGER Register Definitions */ +#define TPI_TRIGGER_TRIGGER_Pos 0U /*!< TPI TRIGGER: TRIGGER Position */ +#define TPI_TRIGGER_TRIGGER_Msk (0x1UL /*<< TPI_TRIGGER_TRIGGER_Pos*/) /*!< TPI TRIGGER: TRIGGER Mask */ + +/* TPI Integration Test FIFO Test Data 0 Register Definitions */ +#define TPI_ITFTTD0_ATB_IF2_ATVALID_Pos 29U /*!< TPI ITFTTD0: ATB Interface 2 ATVALIDPosition */ +#define TPI_ITFTTD0_ATB_IF2_ATVALID_Msk (0x3UL << TPI_ITFTTD0_ATB_IF2_ATVALID_Pos) /*!< TPI ITFTTD0: ATB Interface 2 ATVALID Mask */ + +#define TPI_ITFTTD0_ATB_IF2_bytecount_Pos 27U /*!< TPI ITFTTD0: ATB Interface 2 byte count Position */ +#define TPI_ITFTTD0_ATB_IF2_bytecount_Msk (0x3UL << TPI_ITFTTD0_ATB_IF2_bytecount_Pos) /*!< TPI ITFTTD0: ATB Interface 2 byte count Mask */ + +#define TPI_ITFTTD0_ATB_IF1_ATVALID_Pos 26U /*!< TPI ITFTTD0: ATB Interface 1 ATVALID Position */ +#define TPI_ITFTTD0_ATB_IF1_ATVALID_Msk (0x3UL << TPI_ITFTTD0_ATB_IF1_ATVALID_Pos) /*!< TPI ITFTTD0: ATB Interface 1 ATVALID Mask */ + +#define TPI_ITFTTD0_ATB_IF1_bytecount_Pos 24U /*!< TPI ITFTTD0: ATB Interface 1 byte count Position */ +#define TPI_ITFTTD0_ATB_IF1_bytecount_Msk (0x3UL << TPI_ITFTTD0_ATB_IF1_bytecount_Pos) /*!< TPI ITFTTD0: ATB Interface 1 byte countt Mask */ + +#define TPI_ITFTTD0_ATB_IF1_data2_Pos 16U /*!< TPI ITFTTD0: ATB Interface 1 data2 Position */ +#define TPI_ITFTTD0_ATB_IF1_data2_Msk (0xFFUL << TPI_ITFTTD0_ATB_IF1_data1_Pos) /*!< TPI ITFTTD0: ATB Interface 1 data2 Mask */ + +#define TPI_ITFTTD0_ATB_IF1_data1_Pos 8U /*!< TPI ITFTTD0: ATB Interface 1 data1 Position */ +#define TPI_ITFTTD0_ATB_IF1_data1_Msk (0xFFUL << TPI_ITFTTD0_ATB_IF1_data1_Pos) /*!< TPI ITFTTD0: ATB Interface 1 data1 Mask */ + +#define TPI_ITFTTD0_ATB_IF1_data0_Pos 0U /*!< TPI ITFTTD0: ATB Interface 1 data0 Position */ +#define TPI_ITFTTD0_ATB_IF1_data0_Msk (0xFFUL /*<< TPI_ITFTTD0_ATB_IF1_data0_Pos*/) /*!< TPI ITFTTD0: ATB Interface 1 data0 Mask */ + +/* TPI Integration Test ATB Control Register 2 Register Definitions */ +#define TPI_ITATBCTR2_AFVALID2S_Pos 1U /*!< TPI ITATBCTR2: AFVALID2S Position */ +#define TPI_ITATBCTR2_AFVALID2S_Msk (0x1UL << TPI_ITATBCTR2_AFVALID2S_Pos) /*!< TPI ITATBCTR2: AFVALID2SS Mask */ + +#define TPI_ITATBCTR2_AFVALID1S_Pos 1U /*!< TPI ITATBCTR2: AFVALID1S Position */ +#define TPI_ITATBCTR2_AFVALID1S_Msk (0x1UL << TPI_ITATBCTR2_AFVALID1S_Pos) /*!< TPI ITATBCTR2: AFVALID1SS Mask */ + +#define TPI_ITATBCTR2_ATREADY2S_Pos 0U /*!< TPI ITATBCTR2: ATREADY2S Position */ +#define TPI_ITATBCTR2_ATREADY2S_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY2S_Pos*/) /*!< TPI ITATBCTR2: ATREADY2S Mask */ + +#define TPI_ITATBCTR2_ATREADY1S_Pos 0U /*!< TPI ITATBCTR2: ATREADY1S Position */ +#define TPI_ITATBCTR2_ATREADY1S_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY1S_Pos*/) /*!< TPI ITATBCTR2: ATREADY1S Mask */ + +/* TPI Integration Test FIFO Test Data 1 Register Definitions */ +#define TPI_ITFTTD1_ATB_IF2_ATVALID_Pos 29U /*!< TPI ITFTTD1: ATB Interface 2 ATVALID Position */ +#define TPI_ITFTTD1_ATB_IF2_ATVALID_Msk (0x3UL << TPI_ITFTTD1_ATB_IF2_ATVALID_Pos) /*!< TPI ITFTTD1: ATB Interface 2 ATVALID Mask */ + +#define TPI_ITFTTD1_ATB_IF2_bytecount_Pos 27U /*!< TPI ITFTTD1: ATB Interface 2 byte count Position */ +#define TPI_ITFTTD1_ATB_IF2_bytecount_Msk (0x3UL << TPI_ITFTTD1_ATB_IF2_bytecount_Pos) /*!< TPI ITFTTD1: ATB Interface 2 byte count Mask */ + +#define TPI_ITFTTD1_ATB_IF1_ATVALID_Pos 26U /*!< TPI ITFTTD1: ATB Interface 1 ATVALID Position */ +#define TPI_ITFTTD1_ATB_IF1_ATVALID_Msk (0x3UL << TPI_ITFTTD1_ATB_IF1_ATVALID_Pos) /*!< TPI ITFTTD1: ATB Interface 1 ATVALID Mask */ + +#define TPI_ITFTTD1_ATB_IF1_bytecount_Pos 24U /*!< TPI ITFTTD1: ATB Interface 1 byte count Position */ +#define TPI_ITFTTD1_ATB_IF1_bytecount_Msk (0x3UL << TPI_ITFTTD1_ATB_IF1_bytecount_Pos) /*!< TPI ITFTTD1: ATB Interface 1 byte countt Mask */ + +#define TPI_ITFTTD1_ATB_IF2_data2_Pos 16U /*!< TPI ITFTTD1: ATB Interface 2 data2 Position */ +#define TPI_ITFTTD1_ATB_IF2_data2_Msk (0xFFUL << TPI_ITFTTD1_ATB_IF2_data1_Pos) /*!< TPI ITFTTD1: ATB Interface 2 data2 Mask */ + +#define TPI_ITFTTD1_ATB_IF2_data1_Pos 8U /*!< TPI ITFTTD1: ATB Interface 2 data1 Position */ +#define TPI_ITFTTD1_ATB_IF2_data1_Msk (0xFFUL << TPI_ITFTTD1_ATB_IF2_data1_Pos) /*!< TPI ITFTTD1: ATB Interface 2 data1 Mask */ + +#define TPI_ITFTTD1_ATB_IF2_data0_Pos 0U /*!< TPI ITFTTD1: ATB Interface 2 data0 Position */ +#define TPI_ITFTTD1_ATB_IF2_data0_Msk (0xFFUL /*<< TPI_ITFTTD1_ATB_IF2_data0_Pos*/) /*!< TPI ITFTTD1: ATB Interface 2 data0 Mask */ + +/* TPI Integration Test ATB Control Register 0 Definitions */ +#define TPI_ITATBCTR0_AFVALID2S_Pos 1U /*!< TPI ITATBCTR0: AFVALID2S Position */ +#define TPI_ITATBCTR0_AFVALID2S_Msk (0x1UL << TPI_ITATBCTR0_AFVALID2S_Pos) /*!< TPI ITATBCTR0: AFVALID2SS Mask */ + +#define TPI_ITATBCTR0_AFVALID1S_Pos 1U /*!< TPI ITATBCTR0: AFVALID1S Position */ +#define TPI_ITATBCTR0_AFVALID1S_Msk (0x1UL << TPI_ITATBCTR0_AFVALID1S_Pos) /*!< TPI ITATBCTR0: AFVALID1SS Mask */ + +#define TPI_ITATBCTR0_ATREADY2S_Pos 0U /*!< TPI ITATBCTR0: ATREADY2S Position */ +#define TPI_ITATBCTR0_ATREADY2S_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY2S_Pos*/) /*!< TPI ITATBCTR0: ATREADY2S Mask */ + +#define TPI_ITATBCTR0_ATREADY1S_Pos 0U /*!< TPI ITATBCTR0: ATREADY1S Position */ +#define TPI_ITATBCTR0_ATREADY1S_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY1S_Pos*/) /*!< TPI ITATBCTR0: ATREADY1S Mask */ + +/* TPI Integration Mode Control Register Definitions */ +#define TPI_ITCTRL_Mode_Pos 0U /*!< TPI ITCTRL: Mode Position */ +#define TPI_ITCTRL_Mode_Msk (0x3UL /*<< TPI_ITCTRL_Mode_Pos*/) /*!< TPI ITCTRL: Mode Mask */ + +/* TPI DEVID Register Definitions */ +#define TPI_DEVID_NRZVALID_Pos 11U /*!< TPI DEVID: NRZVALID Position */ +#define TPI_DEVID_NRZVALID_Msk (0x1UL << TPI_DEVID_NRZVALID_Pos) /*!< TPI DEVID: NRZVALID Mask */ + +#define TPI_DEVID_MANCVALID_Pos 10U /*!< TPI DEVID: MANCVALID Position */ +#define TPI_DEVID_MANCVALID_Msk (0x1UL << TPI_DEVID_MANCVALID_Pos) /*!< TPI DEVID: MANCVALID Mask */ + +#define TPI_DEVID_PTINVALID_Pos 9U /*!< TPI DEVID: PTINVALID Position */ +#define TPI_DEVID_PTINVALID_Msk (0x1UL << TPI_DEVID_PTINVALID_Pos) /*!< TPI DEVID: PTINVALID Mask */ + +#define TPI_DEVID_FIFOSZ_Pos 6U /*!< TPI DEVID: FIFOSZ Position */ +#define TPI_DEVID_FIFOSZ_Msk (0x7UL << TPI_DEVID_FIFOSZ_Pos) /*!< TPI DEVID: FIFOSZ Mask */ + +#define TPI_DEVID_NrTraceInput_Pos 0U /*!< TPI DEVID: NrTraceInput Position */ +#define TPI_DEVID_NrTraceInput_Msk (0x3FUL /*<< TPI_DEVID_NrTraceInput_Pos*/) /*!< TPI DEVID: NrTraceInput Mask */ + +/* TPI DEVTYPE Register Definitions */ +#define TPI_DEVTYPE_SubType_Pos 4U /*!< TPI DEVTYPE: SubType Position */ +#define TPI_DEVTYPE_SubType_Msk (0xFUL /*<< TPI_DEVTYPE_SubType_Pos*/) /*!< TPI DEVTYPE: SubType Mask */ + +#define TPI_DEVTYPE_MajorType_Pos 0U /*!< TPI DEVTYPE: MajorType Position */ +#define TPI_DEVTYPE_MajorType_Msk (0xFUL << TPI_DEVTYPE_MajorType_Pos) /*!< TPI DEVTYPE: MajorType Mask */ + +/*@}*/ /* end of group CMSIS_TPI */ + + +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_MPU Memory Protection Unit (MPU) + \brief Type definitions for the Memory Protection Unit (MPU) + @{ + */ + +/** + \brief Structure type to access the Memory Protection Unit (MPU). + */ +typedef struct +{ + __IM uint32_t TYPE; /*!< Offset: 0x000 (R/ ) MPU Type Register */ + __IOM uint32_t CTRL; /*!< Offset: 0x004 (R/W) MPU Control Register */ + __IOM uint32_t RNR; /*!< Offset: 0x008 (R/W) MPU Region Number Register */ + __IOM uint32_t RBAR; /*!< Offset: 0x00C (R/W) MPU Region Base Address Register */ + __IOM uint32_t RLAR; /*!< Offset: 0x010 (R/W) MPU Region Limit Address Register */ + __IOM uint32_t RBAR_A1; /*!< Offset: 0x014 (R/W) MPU Region Base Address Register Alias 1 */ + __IOM uint32_t RLAR_A1; /*!< Offset: 0x018 (R/W) MPU Region Limit Address Register Alias 1 */ + __IOM uint32_t RBAR_A2; /*!< Offset: 0x01C (R/W) MPU Region Base Address Register Alias 2 */ + __IOM uint32_t RLAR_A2; /*!< Offset: 0x020 (R/W) MPU Region Limit Address Register Alias 2 */ + __IOM uint32_t RBAR_A3; /*!< Offset: 0x024 (R/W) MPU Region Base Address Register Alias 3 */ + __IOM uint32_t RLAR_A3; /*!< Offset: 0x028 (R/W) MPU Region Limit Address Register Alias 3 */ + uint32_t RESERVED0[1]; + union { + __IOM uint32_t MAIR[2]; + struct { + __IOM uint32_t MAIR0; /*!< Offset: 0x030 (R/W) MPU Memory Attribute Indirection Register 0 */ + __IOM uint32_t MAIR1; /*!< Offset: 0x034 (R/W) MPU Memory Attribute Indirection Register 1 */ + }; + }; +} MPU_Type; + +#define MPU_TYPE_RALIASES 4U + +/* MPU Type Register Definitions */ +#define MPU_TYPE_IREGION_Pos 16U /*!< MPU TYPE: IREGION Position */ +#define MPU_TYPE_IREGION_Msk (0xFFUL << MPU_TYPE_IREGION_Pos) /*!< MPU TYPE: IREGION Mask */ + +#define MPU_TYPE_DREGION_Pos 8U /*!< MPU TYPE: DREGION Position */ +#define MPU_TYPE_DREGION_Msk (0xFFUL << MPU_TYPE_DREGION_Pos) /*!< MPU TYPE: DREGION Mask */ + +#define MPU_TYPE_SEPARATE_Pos 0U /*!< MPU TYPE: SEPARATE Position */ +#define MPU_TYPE_SEPARATE_Msk (1UL /*<< MPU_TYPE_SEPARATE_Pos*/) /*!< MPU TYPE: SEPARATE Mask */ + +/* MPU Control Register Definitions */ +#define MPU_CTRL_PRIVDEFENA_Pos 2U /*!< MPU CTRL: PRIVDEFENA Position */ +#define MPU_CTRL_PRIVDEFENA_Msk (1UL << MPU_CTRL_PRIVDEFENA_Pos) /*!< MPU CTRL: PRIVDEFENA Mask */ + +#define MPU_CTRL_HFNMIENA_Pos 1U /*!< MPU CTRL: HFNMIENA Position */ +#define MPU_CTRL_HFNMIENA_Msk (1UL << MPU_CTRL_HFNMIENA_Pos) /*!< MPU CTRL: HFNMIENA Mask */ + +#define MPU_CTRL_ENABLE_Pos 0U /*!< MPU CTRL: ENABLE Position */ +#define MPU_CTRL_ENABLE_Msk (1UL /*<< MPU_CTRL_ENABLE_Pos*/) /*!< MPU CTRL: ENABLE Mask */ + +/* MPU Region Number Register Definitions */ +#define MPU_RNR_REGION_Pos 0U /*!< MPU RNR: REGION Position */ +#define MPU_RNR_REGION_Msk (0xFFUL /*<< MPU_RNR_REGION_Pos*/) /*!< MPU RNR: REGION Mask */ + +/* MPU Region Base Address Register Definitions */ +#define MPU_RBAR_BASE_Pos 5U /*!< MPU RBAR: BASE Position */ +#define MPU_RBAR_BASE_Msk (0x7FFFFFFUL << MPU_RBAR_BASE_Pos) /*!< MPU RBAR: BASE Mask */ + +#define MPU_RBAR_SH_Pos 3U /*!< MPU RBAR: SH Position */ +#define MPU_RBAR_SH_Msk (0x3UL << MPU_RBAR_SH_Pos) /*!< MPU RBAR: SH Mask */ + +#define MPU_RBAR_AP_Pos 1U /*!< MPU RBAR: AP Position */ +#define MPU_RBAR_AP_Msk (0x3UL << MPU_RBAR_AP_Pos) /*!< MPU RBAR: AP Mask */ + +#define MPU_RBAR_XN_Pos 0U /*!< MPU RBAR: XN Position */ +#define MPU_RBAR_XN_Msk (01UL /*<< MPU_RBAR_XN_Pos*/) /*!< MPU RBAR: XN Mask */ + +/* MPU Region Limit Address Register Definitions */ +#define MPU_RLAR_LIMIT_Pos 5U /*!< MPU RLAR: LIMIT Position */ +#define MPU_RLAR_LIMIT_Msk (0x7FFFFFFUL << MPU_RLAR_LIMIT_Pos) /*!< MPU RLAR: LIMIT Mask */ + +#define MPU_RLAR_AttrIndx_Pos 1U /*!< MPU RLAR: AttrIndx Position */ +#define MPU_RLAR_AttrIndx_Msk (0x7UL << MPU_RLAR_AttrIndx_Pos) /*!< MPU RLAR: AttrIndx Mask */ + +#define MPU_RLAR_EN_Pos 0U /*!< MPU RLAR: Region enable bit Position */ +#define MPU_RLAR_EN_Msk (1UL /*<< MPU_RLAR_EN_Pos*/) /*!< MPU RLAR: Region enable bit Disable Mask */ + +/* MPU Memory Attribute Indirection Register 0 Definitions */ +#define MPU_MAIR0_Attr3_Pos 24U /*!< MPU MAIR0: Attr3 Position */ +#define MPU_MAIR0_Attr3_Msk (0xFFUL << MPU_MAIR0_Attr3_Pos) /*!< MPU MAIR0: Attr3 Mask */ + +#define MPU_MAIR0_Attr2_Pos 16U /*!< MPU MAIR0: Attr2 Position */ +#define MPU_MAIR0_Attr2_Msk (0xFFUL << MPU_MAIR0_Attr2_Pos) /*!< MPU MAIR0: Attr2 Mask */ + +#define MPU_MAIR0_Attr1_Pos 8U /*!< MPU MAIR0: Attr1 Position */ +#define MPU_MAIR0_Attr1_Msk (0xFFUL << MPU_MAIR0_Attr1_Pos) /*!< MPU MAIR0: Attr1 Mask */ + +#define MPU_MAIR0_Attr0_Pos 0U /*!< MPU MAIR0: Attr0 Position */ +#define MPU_MAIR0_Attr0_Msk (0xFFUL /*<< MPU_MAIR0_Attr0_Pos*/) /*!< MPU MAIR0: Attr0 Mask */ + +/* MPU Memory Attribute Indirection Register 1 Definitions */ +#define MPU_MAIR1_Attr7_Pos 24U /*!< MPU MAIR1: Attr7 Position */ +#define MPU_MAIR1_Attr7_Msk (0xFFUL << MPU_MAIR1_Attr7_Pos) /*!< MPU MAIR1: Attr7 Mask */ + +#define MPU_MAIR1_Attr6_Pos 16U /*!< MPU MAIR1: Attr6 Position */ +#define MPU_MAIR1_Attr6_Msk (0xFFUL << MPU_MAIR1_Attr6_Pos) /*!< MPU MAIR1: Attr6 Mask */ + +#define MPU_MAIR1_Attr5_Pos 8U /*!< MPU MAIR1: Attr5 Position */ +#define MPU_MAIR1_Attr5_Msk (0xFFUL << MPU_MAIR1_Attr5_Pos) /*!< MPU MAIR1: Attr5 Mask */ + +#define MPU_MAIR1_Attr4_Pos 0U /*!< MPU MAIR1: Attr4 Position */ +#define MPU_MAIR1_Attr4_Msk (0xFFUL /*<< MPU_MAIR1_Attr4_Pos*/) /*!< MPU MAIR1: Attr4 Mask */ + +/*@} end of group CMSIS_MPU */ +#endif + + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SAU Security Attribution Unit (SAU) + \brief Type definitions for the Security Attribution Unit (SAU) + @{ + */ + +/** + \brief Structure type to access the Security Attribution Unit (SAU). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SAU Control Register */ + __IM uint32_t TYPE; /*!< Offset: 0x004 (R/ ) SAU Type Register */ +#if defined (__SAUREGION_PRESENT) && (__SAUREGION_PRESENT == 1U) + __IOM uint32_t RNR; /*!< Offset: 0x008 (R/W) SAU Region Number Register */ + __IOM uint32_t RBAR; /*!< Offset: 0x00C (R/W) SAU Region Base Address Register */ + __IOM uint32_t RLAR; /*!< Offset: 0x010 (R/W) SAU Region Limit Address Register */ +#else + uint32_t RESERVED0[3]; +#endif + __IOM uint32_t SFSR; /*!< Offset: 0x014 (R/W) Secure Fault Status Register */ + __IOM uint32_t SFAR; /*!< Offset: 0x018 (R/W) Secure Fault Address Register */ +} SAU_Type; + +/* SAU Control Register Definitions */ +#define SAU_CTRL_ALLNS_Pos 1U /*!< SAU CTRL: ALLNS Position */ +#define SAU_CTRL_ALLNS_Msk (1UL << SAU_CTRL_ALLNS_Pos) /*!< SAU CTRL: ALLNS Mask */ + +#define SAU_CTRL_ENABLE_Pos 0U /*!< SAU CTRL: ENABLE Position */ +#define SAU_CTRL_ENABLE_Msk (1UL /*<< SAU_CTRL_ENABLE_Pos*/) /*!< SAU CTRL: ENABLE Mask */ + +/* SAU Type Register Definitions */ +#define SAU_TYPE_SREGION_Pos 0U /*!< SAU TYPE: SREGION Position */ +#define SAU_TYPE_SREGION_Msk (0xFFUL /*<< SAU_TYPE_SREGION_Pos*/) /*!< SAU TYPE: SREGION Mask */ + +#if defined (__SAUREGION_PRESENT) && (__SAUREGION_PRESENT == 1U) +/* SAU Region Number Register Definitions */ +#define SAU_RNR_REGION_Pos 0U /*!< SAU RNR: REGION Position */ +#define SAU_RNR_REGION_Msk (0xFFUL /*<< SAU_RNR_REGION_Pos*/) /*!< SAU RNR: REGION Mask */ + +/* SAU Region Base Address Register Definitions */ +#define SAU_RBAR_BADDR_Pos 5U /*!< SAU RBAR: BADDR Position */ +#define SAU_RBAR_BADDR_Msk (0x7FFFFFFUL << SAU_RBAR_BADDR_Pos) /*!< SAU RBAR: BADDR Mask */ + +/* SAU Region Limit Address Register Definitions */ +#define SAU_RLAR_LADDR_Pos 5U /*!< SAU RLAR: LADDR Position */ +#define SAU_RLAR_LADDR_Msk (0x7FFFFFFUL << SAU_RLAR_LADDR_Pos) /*!< SAU RLAR: LADDR Mask */ + +#define SAU_RLAR_NSC_Pos 1U /*!< SAU RLAR: NSC Position */ +#define SAU_RLAR_NSC_Msk (1UL << SAU_RLAR_NSC_Pos) /*!< SAU RLAR: NSC Mask */ + +#define SAU_RLAR_ENABLE_Pos 0U /*!< SAU RLAR: ENABLE Position */ +#define SAU_RLAR_ENABLE_Msk (1UL /*<< SAU_RLAR_ENABLE_Pos*/) /*!< SAU RLAR: ENABLE Mask */ + +#endif /* defined (__SAUREGION_PRESENT) && (__SAUREGION_PRESENT == 1U) */ + +/* Secure Fault Status Register Definitions */ +#define SAU_SFSR_LSERR_Pos 7U /*!< SAU SFSR: LSERR Position */ +#define SAU_SFSR_LSERR_Msk (1UL << SAU_SFSR_LSERR_Pos) /*!< SAU SFSR: LSERR Mask */ + +#define SAU_SFSR_SFARVALID_Pos 6U /*!< SAU SFSR: SFARVALID Position */ +#define SAU_SFSR_SFARVALID_Msk (1UL << SAU_SFSR_SFARVALID_Pos) /*!< SAU SFSR: SFARVALID Mask */ + +#define SAU_SFSR_LSPERR_Pos 5U /*!< SAU SFSR: LSPERR Position */ +#define SAU_SFSR_LSPERR_Msk (1UL << SAU_SFSR_LSPERR_Pos) /*!< SAU SFSR: LSPERR Mask */ + +#define SAU_SFSR_INVTRAN_Pos 4U /*!< SAU SFSR: INVTRAN Position */ +#define SAU_SFSR_INVTRAN_Msk (1UL << SAU_SFSR_INVTRAN_Pos) /*!< SAU SFSR: INVTRAN Mask */ + +#define SAU_SFSR_AUVIOL_Pos 3U /*!< SAU SFSR: AUVIOL Position */ +#define SAU_SFSR_AUVIOL_Msk (1UL << SAU_SFSR_AUVIOL_Pos) /*!< SAU SFSR: AUVIOL Mask */ + +#define SAU_SFSR_INVER_Pos 2U /*!< SAU SFSR: INVER Position */ +#define SAU_SFSR_INVER_Msk (1UL << SAU_SFSR_INVER_Pos) /*!< SAU SFSR: INVER Mask */ + +#define SAU_SFSR_INVIS_Pos 1U /*!< SAU SFSR: INVIS Position */ +#define SAU_SFSR_INVIS_Msk (1UL << SAU_SFSR_INVIS_Pos) /*!< SAU SFSR: INVIS Mask */ + +#define SAU_SFSR_INVEP_Pos 0U /*!< SAU SFSR: INVEP Position */ +#define SAU_SFSR_INVEP_Msk (1UL /*<< SAU_SFSR_INVEP_Pos*/) /*!< SAU SFSR: INVEP Mask */ + +/*@} end of group CMSIS_SAU */ +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_FPU Floating Point Unit (FPU) + \brief Type definitions for the Floating Point Unit (FPU) + @{ + */ + +/** + \brief Structure type to access the Floating Point Unit (FPU). + */ +typedef struct +{ + uint32_t RESERVED0[1U]; + __IOM uint32_t FPCCR; /*!< Offset: 0x004 (R/W) Floating-Point Context Control Register */ + __IOM uint32_t FPCAR; /*!< Offset: 0x008 (R/W) Floating-Point Context Address Register */ + __IOM uint32_t FPDSCR; /*!< Offset: 0x00C (R/W) Floating-Point Default Status Control Register */ + __IM uint32_t MVFR0; /*!< Offset: 0x010 (R/ ) Media and FP Feature Register 0 */ + __IM uint32_t MVFR1; /*!< Offset: 0x014 (R/ ) Media and FP Feature Register 1 */ +} FPU_Type; + +/* Floating-Point Context Control Register Definitions */ +#define FPU_FPCCR_ASPEN_Pos 31U /*!< FPCCR: ASPEN bit Position */ +#define FPU_FPCCR_ASPEN_Msk (1UL << FPU_FPCCR_ASPEN_Pos) /*!< FPCCR: ASPEN bit Mask */ + +#define FPU_FPCCR_LSPEN_Pos 30U /*!< FPCCR: LSPEN Position */ +#define FPU_FPCCR_LSPEN_Msk (1UL << FPU_FPCCR_LSPEN_Pos) /*!< FPCCR: LSPEN bit Mask */ + +#define FPU_FPCCR_LSPENS_Pos 29U /*!< FPCCR: LSPENS Position */ +#define FPU_FPCCR_LSPENS_Msk (1UL << FPU_FPCCR_LSPENS_Pos) /*!< FPCCR: LSPENS bit Mask */ + +#define FPU_FPCCR_CLRONRET_Pos 28U /*!< FPCCR: CLRONRET Position */ +#define FPU_FPCCR_CLRONRET_Msk (1UL << FPU_FPCCR_CLRONRET_Pos) /*!< FPCCR: CLRONRET bit Mask */ + +#define FPU_FPCCR_CLRONRETS_Pos 27U /*!< FPCCR: CLRONRETS Position */ +#define FPU_FPCCR_CLRONRETS_Msk (1UL << FPU_FPCCR_CLRONRETS_Pos) /*!< FPCCR: CLRONRETS bit Mask */ + +#define FPU_FPCCR_TS_Pos 26U /*!< FPCCR: TS Position */ +#define FPU_FPCCR_TS_Msk (1UL << FPU_FPCCR_TS_Pos) /*!< FPCCR: TS bit Mask */ + +#define FPU_FPCCR_UFRDY_Pos 10U /*!< FPCCR: UFRDY Position */ +#define FPU_FPCCR_UFRDY_Msk (1UL << FPU_FPCCR_UFRDY_Pos) /*!< FPCCR: UFRDY bit Mask */ + +#define FPU_FPCCR_SPLIMVIOL_Pos 9U /*!< FPCCR: SPLIMVIOL Position */ +#define FPU_FPCCR_SPLIMVIOL_Msk (1UL << FPU_FPCCR_SPLIMVIOL_Pos) /*!< FPCCR: SPLIMVIOL bit Mask */ + +#define FPU_FPCCR_MONRDY_Pos 8U /*!< FPCCR: MONRDY Position */ +#define FPU_FPCCR_MONRDY_Msk (1UL << FPU_FPCCR_MONRDY_Pos) /*!< FPCCR: MONRDY bit Mask */ + +#define FPU_FPCCR_SFRDY_Pos 7U /*!< FPCCR: SFRDY Position */ +#define FPU_FPCCR_SFRDY_Msk (1UL << FPU_FPCCR_SFRDY_Pos) /*!< FPCCR: SFRDY bit Mask */ + +#define FPU_FPCCR_BFRDY_Pos 6U /*!< FPCCR: BFRDY Position */ +#define FPU_FPCCR_BFRDY_Msk (1UL << FPU_FPCCR_BFRDY_Pos) /*!< FPCCR: BFRDY bit Mask */ + +#define FPU_FPCCR_MMRDY_Pos 5U /*!< FPCCR: MMRDY Position */ +#define FPU_FPCCR_MMRDY_Msk (1UL << FPU_FPCCR_MMRDY_Pos) /*!< FPCCR: MMRDY bit Mask */ + +#define FPU_FPCCR_HFRDY_Pos 4U /*!< FPCCR: HFRDY Position */ +#define FPU_FPCCR_HFRDY_Msk (1UL << FPU_FPCCR_HFRDY_Pos) /*!< FPCCR: HFRDY bit Mask */ + +#define FPU_FPCCR_THREAD_Pos 3U /*!< FPCCR: processor mode bit Position */ +#define FPU_FPCCR_THREAD_Msk (1UL << FPU_FPCCR_THREAD_Pos) /*!< FPCCR: processor mode active bit Mask */ + +#define FPU_FPCCR_S_Pos 2U /*!< FPCCR: Security status of the FP context bit Position */ +#define FPU_FPCCR_S_Msk (1UL << FPU_FPCCR_S_Pos) /*!< FPCCR: Security status of the FP context bit Mask */ + +#define FPU_FPCCR_USER_Pos 1U /*!< FPCCR: privilege level bit Position */ +#define FPU_FPCCR_USER_Msk (1UL << FPU_FPCCR_USER_Pos) /*!< FPCCR: privilege level bit Mask */ + +#define FPU_FPCCR_LSPACT_Pos 0U /*!< FPCCR: Lazy state preservation active bit Position */ +#define FPU_FPCCR_LSPACT_Msk (1UL /*<< FPU_FPCCR_LSPACT_Pos*/) /*!< FPCCR: Lazy state preservation active bit Mask */ + +/* Floating-Point Context Address Register Definitions */ +#define FPU_FPCAR_ADDRESS_Pos 3U /*!< FPCAR: ADDRESS bit Position */ +#define FPU_FPCAR_ADDRESS_Msk (0x1FFFFFFFUL << FPU_FPCAR_ADDRESS_Pos) /*!< FPCAR: ADDRESS bit Mask */ + +/* Floating-Point Default Status Control Register Definitions */ +#define FPU_FPDSCR_AHP_Pos 26U /*!< FPDSCR: AHP bit Position */ +#define FPU_FPDSCR_AHP_Msk (1UL << FPU_FPDSCR_AHP_Pos) /*!< FPDSCR: AHP bit Mask */ + +#define FPU_FPDSCR_DN_Pos 25U /*!< FPDSCR: DN bit Position */ +#define FPU_FPDSCR_DN_Msk (1UL << FPU_FPDSCR_DN_Pos) /*!< FPDSCR: DN bit Mask */ + +#define FPU_FPDSCR_FZ_Pos 24U /*!< FPDSCR: FZ bit Position */ +#define FPU_FPDSCR_FZ_Msk (1UL << FPU_FPDSCR_FZ_Pos) /*!< FPDSCR: FZ bit Mask */ + +#define FPU_FPDSCR_RMode_Pos 22U /*!< FPDSCR: RMode bit Position */ +#define FPU_FPDSCR_RMode_Msk (3UL << FPU_FPDSCR_RMode_Pos) /*!< FPDSCR: RMode bit Mask */ + +/* Media and FP Feature Register 0 Definitions */ +#define FPU_MVFR0_FP_rounding_modes_Pos 28U /*!< MVFR0: FP rounding modes bits Position */ +#define FPU_MVFR0_FP_rounding_modes_Msk (0xFUL << FPU_MVFR0_FP_rounding_modes_Pos) /*!< MVFR0: FP rounding modes bits Mask */ + +#define FPU_MVFR0_Short_vectors_Pos 24U /*!< MVFR0: Short vectors bits Position */ +#define FPU_MVFR0_Short_vectors_Msk (0xFUL << FPU_MVFR0_Short_vectors_Pos) /*!< MVFR0: Short vectors bits Mask */ + +#define FPU_MVFR0_Square_root_Pos 20U /*!< MVFR0: Square root bits Position */ +#define FPU_MVFR0_Square_root_Msk (0xFUL << FPU_MVFR0_Square_root_Pos) /*!< MVFR0: Square root bits Mask */ + +#define FPU_MVFR0_Divide_Pos 16U /*!< MVFR0: Divide bits Position */ +#define FPU_MVFR0_Divide_Msk (0xFUL << FPU_MVFR0_Divide_Pos) /*!< MVFR0: Divide bits Mask */ + +#define FPU_MVFR0_FP_excep_trapping_Pos 12U /*!< MVFR0: FP exception trapping bits Position */ +#define FPU_MVFR0_FP_excep_trapping_Msk (0xFUL << FPU_MVFR0_FP_excep_trapping_Pos) /*!< MVFR0: FP exception trapping bits Mask */ + +#define FPU_MVFR0_Double_precision_Pos 8U /*!< MVFR0: Double-precision bits Position */ +#define FPU_MVFR0_Double_precision_Msk (0xFUL << FPU_MVFR0_Double_precision_Pos) /*!< MVFR0: Double-precision bits Mask */ + +#define FPU_MVFR0_Single_precision_Pos 4U /*!< MVFR0: Single-precision bits Position */ +#define FPU_MVFR0_Single_precision_Msk (0xFUL << FPU_MVFR0_Single_precision_Pos) /*!< MVFR0: Single-precision bits Mask */ + +#define FPU_MVFR0_A_SIMD_registers_Pos 0U /*!< MVFR0: A_SIMD registers bits Position */ +#define FPU_MVFR0_A_SIMD_registers_Msk (0xFUL /*<< FPU_MVFR0_A_SIMD_registers_Pos*/) /*!< MVFR0: A_SIMD registers bits Mask */ + +/* Media and FP Feature Register 1 Definitions */ +#define FPU_MVFR1_FP_fused_MAC_Pos 28U /*!< MVFR1: FP fused MAC bits Position */ +#define FPU_MVFR1_FP_fused_MAC_Msk (0xFUL << FPU_MVFR1_FP_fused_MAC_Pos) /*!< MVFR1: FP fused MAC bits Mask */ + +#define FPU_MVFR1_FP_HPFP_Pos 24U /*!< MVFR1: FP HPFP bits Position */ +#define FPU_MVFR1_FP_HPFP_Msk (0xFUL << FPU_MVFR1_FP_HPFP_Pos) /*!< MVFR1: FP HPFP bits Mask */ + +#define FPU_MVFR1_D_NaN_mode_Pos 4U /*!< MVFR1: D_NaN mode bits Position */ +#define FPU_MVFR1_D_NaN_mode_Msk (0xFUL << FPU_MVFR1_D_NaN_mode_Pos) /*!< MVFR1: D_NaN mode bits Mask */ + +#define FPU_MVFR1_FtZ_mode_Pos 0U /*!< MVFR1: FtZ mode bits Position */ +#define FPU_MVFR1_FtZ_mode_Msk (0xFUL /*<< FPU_MVFR1_FtZ_mode_Pos*/) /*!< MVFR1: FtZ mode bits Mask */ + +/*@} end of group CMSIS_FPU */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CoreDebug Core Debug Registers (CoreDebug) + \brief Type definitions for the Core Debug Registers + @{ + */ + +/** + \brief Structure type to access the Core Debug Register (CoreDebug). + */ +typedef struct +{ + __IOM uint32_t DHCSR; /*!< Offset: 0x000 (R/W) Debug Halting Control and Status Register */ + __OM uint32_t DCRSR; /*!< Offset: 0x004 ( /W) Debug Core Register Selector Register */ + __IOM uint32_t DCRDR; /*!< Offset: 0x008 (R/W) Debug Core Register Data Register */ + __IOM uint32_t DEMCR; /*!< Offset: 0x00C (R/W) Debug Exception and Monitor Control Register */ + uint32_t RESERVED4[1U]; + __IOM uint32_t DAUTHCTRL; /*!< Offset: 0x014 (R/W) Debug Authentication Control Register */ + __IOM uint32_t DSCSR; /*!< Offset: 0x018 (R/W) Debug Security Control and Status Register */ +} CoreDebug_Type; + +/* Debug Halting Control and Status Register Definitions */ +#define CoreDebug_DHCSR_DBGKEY_Pos 16U /*!< CoreDebug DHCSR: DBGKEY Position */ +#define CoreDebug_DHCSR_DBGKEY_Msk (0xFFFFUL << CoreDebug_DHCSR_DBGKEY_Pos) /*!< CoreDebug DHCSR: DBGKEY Mask */ + +#define CoreDebug_DHCSR_S_RESTART_ST_Pos 26U /*!< CoreDebug DHCSR: S_RESTART_ST Position */ +#define CoreDebug_DHCSR_S_RESTART_ST_Msk (1UL << CoreDebug_DHCSR_S_RESTART_ST_Pos) /*!< CoreDebug DHCSR: S_RESTART_ST Mask */ + +#define CoreDebug_DHCSR_S_RESET_ST_Pos 25U /*!< CoreDebug DHCSR: S_RESET_ST Position */ +#define CoreDebug_DHCSR_S_RESET_ST_Msk (1UL << CoreDebug_DHCSR_S_RESET_ST_Pos) /*!< CoreDebug DHCSR: S_RESET_ST Mask */ + +#define CoreDebug_DHCSR_S_RETIRE_ST_Pos 24U /*!< CoreDebug DHCSR: S_RETIRE_ST Position */ +#define CoreDebug_DHCSR_S_RETIRE_ST_Msk (1UL << CoreDebug_DHCSR_S_RETIRE_ST_Pos) /*!< CoreDebug DHCSR: S_RETIRE_ST Mask */ + +#define CoreDebug_DHCSR_S_LOCKUP_Pos 19U /*!< CoreDebug DHCSR: S_LOCKUP Position */ +#define CoreDebug_DHCSR_S_LOCKUP_Msk (1UL << CoreDebug_DHCSR_S_LOCKUP_Pos) /*!< CoreDebug DHCSR: S_LOCKUP Mask */ + +#define CoreDebug_DHCSR_S_SLEEP_Pos 18U /*!< CoreDebug DHCSR: S_SLEEP Position */ +#define CoreDebug_DHCSR_S_SLEEP_Msk (1UL << CoreDebug_DHCSR_S_SLEEP_Pos) /*!< CoreDebug DHCSR: S_SLEEP Mask */ + +#define CoreDebug_DHCSR_S_HALT_Pos 17U /*!< CoreDebug DHCSR: S_HALT Position */ +#define CoreDebug_DHCSR_S_HALT_Msk (1UL << CoreDebug_DHCSR_S_HALT_Pos) /*!< CoreDebug DHCSR: S_HALT Mask */ + +#define CoreDebug_DHCSR_S_REGRDY_Pos 16U /*!< CoreDebug DHCSR: S_REGRDY Position */ +#define CoreDebug_DHCSR_S_REGRDY_Msk (1UL << CoreDebug_DHCSR_S_REGRDY_Pos) /*!< CoreDebug DHCSR: S_REGRDY Mask */ + +#define CoreDebug_DHCSR_C_SNAPSTALL_Pos 5U /*!< CoreDebug DHCSR: C_SNAPSTALL Position */ +#define CoreDebug_DHCSR_C_SNAPSTALL_Msk (1UL << CoreDebug_DHCSR_C_SNAPSTALL_Pos) /*!< CoreDebug DHCSR: C_SNAPSTALL Mask */ + +#define CoreDebug_DHCSR_C_MASKINTS_Pos 3U /*!< CoreDebug DHCSR: C_MASKINTS Position */ +#define CoreDebug_DHCSR_C_MASKINTS_Msk (1UL << CoreDebug_DHCSR_C_MASKINTS_Pos) /*!< CoreDebug DHCSR: C_MASKINTS Mask */ + +#define CoreDebug_DHCSR_C_STEP_Pos 2U /*!< CoreDebug DHCSR: C_STEP Position */ +#define CoreDebug_DHCSR_C_STEP_Msk (1UL << CoreDebug_DHCSR_C_STEP_Pos) /*!< CoreDebug DHCSR: C_STEP Mask */ + +#define CoreDebug_DHCSR_C_HALT_Pos 1U /*!< CoreDebug DHCSR: C_HALT Position */ +#define CoreDebug_DHCSR_C_HALT_Msk (1UL << CoreDebug_DHCSR_C_HALT_Pos) /*!< CoreDebug DHCSR: C_HALT Mask */ + +#define CoreDebug_DHCSR_C_DEBUGEN_Pos 0U /*!< CoreDebug DHCSR: C_DEBUGEN Position */ +#define CoreDebug_DHCSR_C_DEBUGEN_Msk (1UL /*<< CoreDebug_DHCSR_C_DEBUGEN_Pos*/) /*!< CoreDebug DHCSR: C_DEBUGEN Mask */ + +/* Debug Core Register Selector Register Definitions */ +#define CoreDebug_DCRSR_REGWnR_Pos 16U /*!< CoreDebug DCRSR: REGWnR Position */ +#define CoreDebug_DCRSR_REGWnR_Msk (1UL << CoreDebug_DCRSR_REGWnR_Pos) /*!< CoreDebug DCRSR: REGWnR Mask */ + +#define CoreDebug_DCRSR_REGSEL_Pos 0U /*!< CoreDebug DCRSR: REGSEL Position */ +#define CoreDebug_DCRSR_REGSEL_Msk (0x1FUL /*<< CoreDebug_DCRSR_REGSEL_Pos*/) /*!< CoreDebug DCRSR: REGSEL Mask */ + +/* Debug Exception and Monitor Control Register Definitions */ +#define CoreDebug_DEMCR_TRCENA_Pos 24U /*!< CoreDebug DEMCR: TRCENA Position */ +#define CoreDebug_DEMCR_TRCENA_Msk (1UL << CoreDebug_DEMCR_TRCENA_Pos) /*!< CoreDebug DEMCR: TRCENA Mask */ + +#define CoreDebug_DEMCR_MON_REQ_Pos 19U /*!< CoreDebug DEMCR: MON_REQ Position */ +#define CoreDebug_DEMCR_MON_REQ_Msk (1UL << CoreDebug_DEMCR_MON_REQ_Pos) /*!< CoreDebug DEMCR: MON_REQ Mask */ + +#define CoreDebug_DEMCR_MON_STEP_Pos 18U /*!< CoreDebug DEMCR: MON_STEP Position */ +#define CoreDebug_DEMCR_MON_STEP_Msk (1UL << CoreDebug_DEMCR_MON_STEP_Pos) /*!< CoreDebug DEMCR: MON_STEP Mask */ + +#define CoreDebug_DEMCR_MON_PEND_Pos 17U /*!< CoreDebug DEMCR: MON_PEND Position */ +#define CoreDebug_DEMCR_MON_PEND_Msk (1UL << CoreDebug_DEMCR_MON_PEND_Pos) /*!< CoreDebug DEMCR: MON_PEND Mask */ + +#define CoreDebug_DEMCR_MON_EN_Pos 16U /*!< CoreDebug DEMCR: MON_EN Position */ +#define CoreDebug_DEMCR_MON_EN_Msk (1UL << CoreDebug_DEMCR_MON_EN_Pos) /*!< CoreDebug DEMCR: MON_EN Mask */ + +#define CoreDebug_DEMCR_VC_HARDERR_Pos 10U /*!< CoreDebug DEMCR: VC_HARDERR Position */ +#define CoreDebug_DEMCR_VC_HARDERR_Msk (1UL << CoreDebug_DEMCR_VC_HARDERR_Pos) /*!< CoreDebug DEMCR: VC_HARDERR Mask */ + +#define CoreDebug_DEMCR_VC_INTERR_Pos 9U /*!< CoreDebug DEMCR: VC_INTERR Position */ +#define CoreDebug_DEMCR_VC_INTERR_Msk (1UL << CoreDebug_DEMCR_VC_INTERR_Pos) /*!< CoreDebug DEMCR: VC_INTERR Mask */ + +#define CoreDebug_DEMCR_VC_BUSERR_Pos 8U /*!< CoreDebug DEMCR: VC_BUSERR Position */ +#define CoreDebug_DEMCR_VC_BUSERR_Msk (1UL << CoreDebug_DEMCR_VC_BUSERR_Pos) /*!< CoreDebug DEMCR: VC_BUSERR Mask */ + +#define CoreDebug_DEMCR_VC_STATERR_Pos 7U /*!< CoreDebug DEMCR: VC_STATERR Position */ +#define CoreDebug_DEMCR_VC_STATERR_Msk (1UL << CoreDebug_DEMCR_VC_STATERR_Pos) /*!< CoreDebug DEMCR: VC_STATERR Mask */ + +#define CoreDebug_DEMCR_VC_CHKERR_Pos 6U /*!< CoreDebug DEMCR: VC_CHKERR Position */ +#define CoreDebug_DEMCR_VC_CHKERR_Msk (1UL << CoreDebug_DEMCR_VC_CHKERR_Pos) /*!< CoreDebug DEMCR: VC_CHKERR Mask */ + +#define CoreDebug_DEMCR_VC_NOCPERR_Pos 5U /*!< CoreDebug DEMCR: VC_NOCPERR Position */ +#define CoreDebug_DEMCR_VC_NOCPERR_Msk (1UL << CoreDebug_DEMCR_VC_NOCPERR_Pos) /*!< CoreDebug DEMCR: VC_NOCPERR Mask */ + +#define CoreDebug_DEMCR_VC_MMERR_Pos 4U /*!< CoreDebug DEMCR: VC_MMERR Position */ +#define CoreDebug_DEMCR_VC_MMERR_Msk (1UL << CoreDebug_DEMCR_VC_MMERR_Pos) /*!< CoreDebug DEMCR: VC_MMERR Mask */ + +#define CoreDebug_DEMCR_VC_CORERESET_Pos 0U /*!< CoreDebug DEMCR: VC_CORERESET Position */ +#define CoreDebug_DEMCR_VC_CORERESET_Msk (1UL /*<< CoreDebug_DEMCR_VC_CORERESET_Pos*/) /*!< CoreDebug DEMCR: VC_CORERESET Mask */ + +/* Debug Authentication Control Register Definitions */ +#define CoreDebug_DAUTHCTRL_INTSPNIDEN_Pos 3U /*!< CoreDebug DAUTHCTRL: INTSPNIDEN, Position */ +#define CoreDebug_DAUTHCTRL_INTSPNIDEN_Msk (1UL << CoreDebug_DAUTHCTRL_INTSPNIDEN_Pos) /*!< CoreDebug DAUTHCTRL: INTSPNIDEN, Mask */ + +#define CoreDebug_DAUTHCTRL_SPNIDENSEL_Pos 2U /*!< CoreDebug DAUTHCTRL: SPNIDENSEL Position */ +#define CoreDebug_DAUTHCTRL_SPNIDENSEL_Msk (1UL << CoreDebug_DAUTHCTRL_SPNIDENSEL_Pos) /*!< CoreDebug DAUTHCTRL: SPNIDENSEL Mask */ + +#define CoreDebug_DAUTHCTRL_INTSPIDEN_Pos 1U /*!< CoreDebug DAUTHCTRL: INTSPIDEN Position */ +#define CoreDebug_DAUTHCTRL_INTSPIDEN_Msk (1UL << CoreDebug_DAUTHCTRL_INTSPIDEN_Pos) /*!< CoreDebug DAUTHCTRL: INTSPIDEN Mask */ + +#define CoreDebug_DAUTHCTRL_SPIDENSEL_Pos 0U /*!< CoreDebug DAUTHCTRL: SPIDENSEL Position */ +#define CoreDebug_DAUTHCTRL_SPIDENSEL_Msk (1UL /*<< CoreDebug_DAUTHCTRL_SPIDENSEL_Pos*/) /*!< CoreDebug DAUTHCTRL: SPIDENSEL Mask */ + +/* Debug Security Control and Status Register Definitions */ +#define CoreDebug_DSCSR_CDS_Pos 16U /*!< CoreDebug DSCSR: CDS Position */ +#define CoreDebug_DSCSR_CDS_Msk (1UL << CoreDebug_DSCSR_CDS_Pos) /*!< CoreDebug DSCSR: CDS Mask */ + +#define CoreDebug_DSCSR_SBRSEL_Pos 1U /*!< CoreDebug DSCSR: SBRSEL Position */ +#define CoreDebug_DSCSR_SBRSEL_Msk (1UL << CoreDebug_DSCSR_SBRSEL_Pos) /*!< CoreDebug DSCSR: SBRSEL Mask */ + +#define CoreDebug_DSCSR_SBRSELEN_Pos 0U /*!< CoreDebug DSCSR: SBRSELEN Position */ +#define CoreDebug_DSCSR_SBRSELEN_Msk (1UL /*<< CoreDebug_DSCSR_SBRSELEN_Pos*/) /*!< CoreDebug DSCSR: SBRSELEN Mask */ + +/*@} end of group CMSIS_CoreDebug */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_bitfield Core register bit field macros + \brief Macros for use with bit field definitions (xxx_Pos, xxx_Msk). + @{ + */ + +/** + \brief Mask and shift a bit field value for use in a register bit range. + \param[in] field Name of the register bit field. + \param[in] value Value of the bit field. This parameter is interpreted as an uint32_t type. + \return Masked and shifted value. +*/ +#define _VAL2FLD(field, value) (((uint32_t)(value) << field ## _Pos) & field ## _Msk) + +/** + \brief Mask and shift a register value to extract a bit filed value. + \param[in] field Name of the register bit field. + \param[in] value Value of register. This parameter is interpreted as an uint32_t type. + \return Masked and shifted bit field value. +*/ +#define _FLD2VAL(field, value) (((uint32_t)(value) & field ## _Msk) >> field ## _Pos) + +/*@} end of group CMSIS_core_bitfield */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_base Core Definitions + \brief Definitions for base addresses, unions, and structures. + @{ + */ + +/* Memory mapping of Core Hardware */ + #define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ + #define ITM_BASE (0xE0000000UL) /*!< ITM Base Address */ + #define DWT_BASE (0xE0001000UL) /*!< DWT Base Address */ + #define TPI_BASE (0xE0040000UL) /*!< TPI Base Address */ + #define CoreDebug_BASE (0xE000EDF0UL) /*!< Core Debug Base Address */ + #define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */ + #define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */ + #define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */ + + #define SCnSCB ((SCnSCB_Type *) SCS_BASE ) /*!< System control Register not in SCB */ + #define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */ + #define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */ + #define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */ + #define ITM ((ITM_Type *) ITM_BASE ) /*!< ITM configuration struct */ + #define DWT ((DWT_Type *) DWT_BASE ) /*!< DWT configuration struct */ + #define TPI ((TPI_Type *) TPI_BASE ) /*!< TPI configuration struct */ + #define CoreDebug ((CoreDebug_Type *) CoreDebug_BASE ) /*!< Core Debug configuration struct */ + + #if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + #define MPU_BASE (SCS_BASE + 0x0D90UL) /*!< Memory Protection Unit */ + #define MPU ((MPU_Type *) MPU_BASE ) /*!< Memory Protection Unit */ + #endif + + #if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + #define SAU_BASE (SCS_BASE + 0x0DD0UL) /*!< Security Attribution Unit */ + #define SAU ((SAU_Type *) SAU_BASE ) /*!< Security Attribution Unit */ + #endif + + #define FPU_BASE (SCS_BASE + 0x0F30UL) /*!< Floating Point Unit */ + #define FPU ((FPU_Type *) FPU_BASE ) /*!< Floating Point Unit */ + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + #define SCS_BASE_NS (0xE002E000UL) /*!< System Control Space Base Address (non-secure address space) */ + #define CoreDebug_BASE_NS (0xE002EDF0UL) /*!< Core Debug Base Address (non-secure address space) */ + #define SysTick_BASE_NS (SCS_BASE_NS + 0x0010UL) /*!< SysTick Base Address (non-secure address space) */ + #define NVIC_BASE_NS (SCS_BASE_NS + 0x0100UL) /*!< NVIC Base Address (non-secure address space) */ + #define SCB_BASE_NS (SCS_BASE_NS + 0x0D00UL) /*!< System Control Block Base Address (non-secure address space) */ + + #define SCnSCB_NS ((SCnSCB_Type *) SCS_BASE_NS ) /*!< System control Register not in SCB(non-secure address space) */ + #define SCB_NS ((SCB_Type *) SCB_BASE_NS ) /*!< SCB configuration struct (non-secure address space) */ + #define SysTick_NS ((SysTick_Type *) SysTick_BASE_NS ) /*!< SysTick configuration struct (non-secure address space) */ + #define NVIC_NS ((NVIC_Type *) NVIC_BASE_NS ) /*!< NVIC configuration struct (non-secure address space) */ + #define CoreDebug_NS ((CoreDebug_Type *) CoreDebug_BASE_NS) /*!< Core Debug configuration struct (non-secure address space) */ + + #if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + #define MPU_BASE_NS (SCS_BASE_NS + 0x0D90UL) /*!< Memory Protection Unit (non-secure address space) */ + #define MPU_NS ((MPU_Type *) MPU_BASE_NS ) /*!< Memory Protection Unit (non-secure address space) */ + #endif + + #define FPU_BASE_NS (SCS_BASE_NS + 0x0F30UL) /*!< Floating Point Unit (non-secure address space) */ + #define FPU_NS ((FPU_Type *) FPU_BASE_NS ) /*!< Floating Point Unit (non-secure address space) */ + +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ +/*@} */ + + + +/******************************************************************************* + * Hardware Abstraction Layer + Core Function Interface contains: + - Core NVIC Functions + - Core SysTick Functions + - Core Debug Functions + - Core Register Access Functions + ******************************************************************************/ +/** + \defgroup CMSIS_Core_FunctionInterface Functions and Instructions Reference +*/ + + + +/* ########################## NVIC functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_NVICFunctions NVIC Functions + \brief Functions that manage interrupts and exceptions via the NVIC. + @{ + */ + +#ifdef CMSIS_NVIC_VIRTUAL + #ifndef CMSIS_NVIC_VIRTUAL_HEADER_FILE + #define CMSIS_NVIC_VIRTUAL_HEADER_FILE "cmsis_nvic_virtual.h" + #endif + #include CMSIS_NVIC_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetPriorityGrouping __NVIC_SetPriorityGrouping + #define NVIC_GetPriorityGrouping __NVIC_GetPriorityGrouping + #define NVIC_EnableIRQ __NVIC_EnableIRQ + #define NVIC_GetEnableIRQ __NVIC_GetEnableIRQ + #define NVIC_DisableIRQ __NVIC_DisableIRQ + #define NVIC_GetPendingIRQ __NVIC_GetPendingIRQ + #define NVIC_SetPendingIRQ __NVIC_SetPendingIRQ + #define NVIC_ClearPendingIRQ __NVIC_ClearPendingIRQ + #define NVIC_GetActive __NVIC_GetActive + #define NVIC_SetPriority __NVIC_SetPriority + #define NVIC_GetPriority __NVIC_GetPriority + #define NVIC_SystemReset __NVIC_SystemReset +#endif /* CMSIS_NVIC_VIRTUAL */ + +#ifdef CMSIS_VECTAB_VIRTUAL + #ifndef CMSIS_VECTAB_VIRTUAL_HEADER_FILE + #define CMSIS_VECTAB_VIRTUAL_HEADER_FILE "cmsis_vectab_virtual.h" + #endif + #include CMSIS_VECTAB_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetVector __NVIC_SetVector + #define NVIC_GetVector __NVIC_GetVector +#endif /* (CMSIS_VECTAB_VIRTUAL) */ + +#define NVIC_USER_IRQ_OFFSET 16 + + +/* Special LR values for Secure/Non-Secure call handling and exception handling */ + +/* Function Return Payload (from ARMv8-M Architecture Reference Manual) LR value on entry from Secure BLXNS */ +#define FNC_RETURN (0xFEFFFFFFUL) /* bit [0] ignored when processing a branch */ + +/* The following EXC_RETURN mask values are used to evaluate the LR on exception entry */ +#define EXC_RETURN_PREFIX (0xFF000000UL) /* bits [31:24] set to indicate an EXC_RETURN value */ +#define EXC_RETURN_S (0x00000040UL) /* bit [6] stack used to push registers: 0=Non-secure 1=Secure */ +#define EXC_RETURN_DCRS (0x00000020UL) /* bit [5] stacking rules for called registers: 0=skipped 1=saved */ +#define EXC_RETURN_FTYPE (0x00000010UL) /* bit [4] allocate stack for floating-point context: 0=done 1=skipped */ +#define EXC_RETURN_MODE (0x00000008UL) /* bit [3] processor mode for return: 0=Handler mode 1=Thread mode */ +#define EXC_RETURN_SPSEL (0x00000004UL) /* bit [2] stack pointer used to restore context: 0=MSP 1=PSP */ +#define EXC_RETURN_ES (0x00000001UL) /* bit [0] security state exception was taken to: 0=Non-secure 1=Secure */ + +/* Integrity Signature (from ARMv8-M Architecture Reference Manual) for exception context stacking */ +#if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) /* Value for processors with floating-point extension: */ +#define EXC_INTEGRITY_SIGNATURE (0xFEFA125AUL) /* bit [0] SFTC must match LR bit[4] EXC_RETURN_FTYPE */ +#else +#define EXC_INTEGRITY_SIGNATURE (0xFEFA125BUL) /* Value for processors without floating-point extension */ +#endif + + +/** + \brief Set Priority Grouping + \details Sets the priority grouping field using the required unlock sequence. + The parameter PriorityGroup is assigned to the field SCB->AIRCR [10:8] PRIGROUP field. + Only values from 0..7 are used. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. + \param [in] PriorityGroup Priority grouping field. + */ +__STATIC_INLINE void __NVIC_SetPriorityGrouping(uint32_t PriorityGroup) +{ + uint32_t reg_value; + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + + reg_value = SCB->AIRCR; /* read old register configuration */ + reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk)); /* clear bits to change */ + reg_value = (reg_value | + ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + (PriorityGroupTmp << SCB_AIRCR_PRIGROUP_Pos) ); /* Insert write key and priority group */ + SCB->AIRCR = reg_value; +} + + +/** + \brief Get Priority Grouping + \details Reads the priority grouping field from the NVIC Interrupt Controller. + \return Priority grouping field (SCB->AIRCR [10:8] PRIGROUP field). + */ +__STATIC_INLINE uint32_t __NVIC_GetPriorityGrouping(void) +{ + return ((uint32_t)((SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) >> SCB_AIRCR_PRIGROUP_Pos)); +} + + +/** + \brief Enable Interrupt + \details Enables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Interrupt Enable status + \details Returns a device specific interrupt enable status from the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt is not enabled. + \return 1 Interrupt is enabled. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t __NVIC_GetEnableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Disable Interrupt + \details Disables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_DisableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + __DSB(); + __ISB(); + } +} + + +/** + \brief Get Pending Interrupt + \details Reads the NVIC pending register and returns the pending bit for the specified device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt status is not pending. + \return 1 Interrupt status is pending. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t __NVIC_GetPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Set Pending Interrupt + \details Sets the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_SetPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Clear Pending Interrupt + \details Clears the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_ClearPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Active Interrupt + \details Reads the active register in the NVIC and returns the active bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt status is not active. + \return 1 Interrupt status is active. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t __NVIC_GetActive(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->IABR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +/** + \brief Get Interrupt Target State + \details Reads the interrupt target field in the NVIC and returns the interrupt target bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 if interrupt is assigned to Secure + \return 1 if interrupt is assigned to Non Secure + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t NVIC_GetTargetState(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Set Interrupt Target State + \details Sets the interrupt target field in the NVIC and returns the interrupt target bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 if interrupt is assigned to Secure + 1 if interrupt is assigned to Non Secure + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t NVIC_SetTargetState(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] |= ((uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL))); + return((uint32_t)(((NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Clear Interrupt Target State + \details Clears the interrupt target field in the NVIC and returns the interrupt target bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 if interrupt is assigned to Secure + 1 if interrupt is assigned to Non Secure + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t NVIC_ClearTargetState(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] &= ~((uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL))); + return((uint32_t)(((NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ + + +/** + \brief Set Interrupt Priority + \details Sets the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \param [in] priority Priority to set. + \note The priority cannot be set for every processor exception. + */ +__STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->IPR[((uint32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + } + else + { + SCB->SHPR[(((uint32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + } +} + + +/** + \brief Get Interrupt Priority + \details Reads the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Interrupt Priority. + Value is aligned automatically to the implemented priority bits of the microcontroller. + */ +__STATIC_INLINE uint32_t __NVIC_GetPriority(IRQn_Type IRQn) +{ + + if ((int32_t)(IRQn) >= 0) + { + return(((uint32_t)NVIC->IPR[((uint32_t)IRQn)] >> (8U - __NVIC_PRIO_BITS))); + } + else + { + return(((uint32_t)SCB->SHPR[(((uint32_t)IRQn) & 0xFUL)-4UL] >> (8U - __NVIC_PRIO_BITS))); + } +} + + +/** + \brief Encode Priority + \details Encodes the priority for an interrupt with the given priority group, + preemptive priority value, and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. + \param [in] PriorityGroup Used priority group. + \param [in] PreemptPriority Preemptive priority value (starting from 0). + \param [in] SubPriority Subpriority value (starting from 0). + \return Encoded priority. Value can be used in the function \ref NVIC_SetPriority(). + */ +__STATIC_INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + return ( + ((PreemptPriority & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL)) << SubPriorityBits) | + ((SubPriority & (uint32_t)((1UL << (SubPriorityBits )) - 1UL))) + ); +} + + +/** + \brief Decode Priority + \details Decodes an interrupt priority value with a given priority group to + preemptive priority value and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS) the smallest possible priority group is set. + \param [in] Priority Priority value, which can be retrieved with the function \ref NVIC_GetPriority(). + \param [in] PriorityGroup Used priority group. + \param [out] pPreemptPriority Preemptive priority value (starting from 0). + \param [out] pSubPriority Subpriority value (starting from 0). + */ +__STATIC_INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGroup, uint32_t* const pPreemptPriority, uint32_t* const pSubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + *pPreemptPriority = (Priority >> SubPriorityBits) & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL); + *pSubPriority = (Priority ) & (uint32_t)((1UL << (SubPriorityBits )) - 1UL); +} + + +/** + \brief Set Interrupt Vector + \details Sets an interrupt vector in SRAM based interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + VTOR must been relocated to SRAM before. + \param [in] IRQn Interrupt number + \param [in] vector Address of interrupt handler function + */ +__STATIC_INLINE void __NVIC_SetVector(IRQn_Type IRQn, uint32_t vector) +{ + uint32_t *vectors = (uint32_t *)SCB->VTOR; + vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET] = vector; +} + + +/** + \brief Get Interrupt Vector + \details Reads an interrupt vector from interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Address of interrupt handler function + */ +__STATIC_INLINE uint32_t __NVIC_GetVector(IRQn_Type IRQn) +{ + uint32_t *vectors = (uint32_t *)SCB->VTOR; + return vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET]; +} + + +/** + \brief System Reset + \details Initiates a system reset request to reset the MCU. + */ +__NO_RETURN __STATIC_INLINE void __NVIC_SystemReset(void) +{ + __DSB(); /* Ensure all outstanding memory accesses included + buffered write are completed before reset */ + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + SCB_AIRCR_SYSRESETREQ_Msk ); /* Keep priority group unchanged */ + __DSB(); /* Ensure completion of memory access */ + + for(;;) /* wait until reset */ + { + __NOP(); + } +} + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +/** + \brief Set Priority Grouping (non-secure) + \details Sets the non-secure priority grouping field when in secure state using the required unlock sequence. + The parameter PriorityGroup is assigned to the field SCB->AIRCR [10:8] PRIGROUP field. + Only values from 0..7 are used. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. + \param [in] PriorityGroup Priority grouping field. + */ +__STATIC_INLINE void TZ_NVIC_SetPriorityGrouping_NS(uint32_t PriorityGroup) +{ + uint32_t reg_value; + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + + reg_value = SCB_NS->AIRCR; /* read old register configuration */ + reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk)); /* clear bits to change */ + reg_value = (reg_value | + ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + (PriorityGroupTmp << SCB_AIRCR_PRIGROUP_Pos) ); /* Insert write key and priority group */ + SCB_NS->AIRCR = reg_value; +} + + +/** + \brief Get Priority Grouping (non-secure) + \details Reads the priority grouping field from the non-secure NVIC when in secure state. + \return Priority grouping field (SCB->AIRCR [10:8] PRIGROUP field). + */ +__STATIC_INLINE uint32_t TZ_NVIC_GetPriorityGrouping_NS(void) +{ + return ((uint32_t)((SCB_NS->AIRCR & SCB_AIRCR_PRIGROUP_Msk) >> SCB_AIRCR_PRIGROUP_Pos)); +} + + +/** + \brief Enable Interrupt (non-secure) + \details Enables a device specific interrupt in the non-secure NVIC interrupt controller when in secure state. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void TZ_NVIC_EnableIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Interrupt Enable status (non-secure) + \details Returns a device specific interrupt enable status from the non-secure NVIC interrupt controller when in secure state. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt is not enabled. + \return 1 Interrupt is enabled. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t TZ_NVIC_GetEnableIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC_NS->ISER[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Disable Interrupt (non-secure) + \details Disables a device specific interrupt in the non-secure NVIC interrupt controller when in secure state. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void TZ_NVIC_DisableIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->ICER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Pending Interrupt (non-secure) + \details Reads the NVIC pending register in the non-secure NVIC when in secure state and returns the pending bit for the specified device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt status is not pending. + \return 1 Interrupt status is pending. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t TZ_NVIC_GetPendingIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC_NS->ISPR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Set Pending Interrupt (non-secure) + \details Sets the pending bit of a device specific interrupt in the non-secure NVIC pending register when in secure state. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void TZ_NVIC_SetPendingIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->ISPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Clear Pending Interrupt (non-secure) + \details Clears the pending bit of a device specific interrupt in the non-secure NVIC pending register when in secure state. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void TZ_NVIC_ClearPendingIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->ICPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Active Interrupt (non-secure) + \details Reads the active register in non-secure NVIC when in secure state and returns the active bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt status is not active. + \return 1 Interrupt status is active. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t TZ_NVIC_GetActive_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC_NS->IABR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Set Interrupt Priority (non-secure) + \details Sets the priority of a non-secure device specific interrupt or a non-secure processor exception when in secure state. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \param [in] priority Priority to set. + \note The priority cannot be set for every non-secure processor exception. + */ +__STATIC_INLINE void TZ_NVIC_SetPriority_NS(IRQn_Type IRQn, uint32_t priority) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->IPR[((uint32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + } + else + { + SCB_NS->SHPR[(((uint32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + } +} + + +/** + \brief Get Interrupt Priority (non-secure) + \details Reads the priority of a non-secure device specific interrupt or a non-secure processor exception when in secure state. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Interrupt Priority. Value is aligned automatically to the implemented priority bits of the microcontroller. + */ +__STATIC_INLINE uint32_t TZ_NVIC_GetPriority_NS(IRQn_Type IRQn) +{ + + if ((int32_t)(IRQn) >= 0) + { + return(((uint32_t)NVIC_NS->IPR[((uint32_t)IRQn)] >> (8U - __NVIC_PRIO_BITS))); + } + else + { + return(((uint32_t)SCB_NS->SHPR[(((uint32_t)IRQn) & 0xFUL)-4UL] >> (8U - __NVIC_PRIO_BITS))); + } +} +#endif /* defined (__ARM_FEATURE_CMSE) &&(__ARM_FEATURE_CMSE == 3U) */ + +/*@} end of CMSIS_Core_NVICFunctions */ + +/* ########################## MPU functions #################################### */ + +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + +#include "mpu_armv8.h" + +#endif + +/* ########################## FPU functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_FpuFunctions FPU Functions + \brief Function that provides FPU type. + @{ + */ + +/** + \brief get FPU type + \details returns the FPU type + \returns + - \b 0: No FPU + - \b 1: Single precision FPU + - \b 2: Double + Single precision FPU + */ +__STATIC_INLINE uint32_t SCB_GetFPUType(void) +{ + uint32_t mvfr0; + + mvfr0 = FPU->MVFR0; + if ((mvfr0 & (FPU_MVFR0_Single_precision_Msk | FPU_MVFR0_Double_precision_Msk)) == 0x220U) + { + return 2U; /* Double + Single precision FPU */ + } + else if ((mvfr0 & (FPU_MVFR0_Single_precision_Msk | FPU_MVFR0_Double_precision_Msk)) == 0x020U) + { + return 1U; /* Single precision FPU */ + } + else + { + return 0U; /* No FPU */ + } +} + + +/*@} end of CMSIS_Core_FpuFunctions */ + + + +/* ########################## SAU functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_SAUFunctions SAU Functions + \brief Functions that configure the SAU. + @{ + */ + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + +/** + \brief Enable SAU + \details Enables the Security Attribution Unit (SAU). + */ +__STATIC_INLINE void TZ_SAU_Enable(void) +{ + SAU->CTRL |= (SAU_CTRL_ENABLE_Msk); +} + + + +/** + \brief Disable SAU + \details Disables the Security Attribution Unit (SAU). + */ +__STATIC_INLINE void TZ_SAU_Disable(void) +{ + SAU->CTRL &= ~(SAU_CTRL_ENABLE_Msk); +} + +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ + +/*@} end of CMSIS_Core_SAUFunctions */ + + + + +/* ################################## SysTick function ############################################ */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_SysTickFunctions SysTick Functions + \brief Functions that configure the System. + @{ + */ + +#if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U) + +/** + \brief System Tick Configuration + \details Initializes the System Timer and its interrupt, and starts the System Tick Timer. + Counter is in free running mode to generate periodic interrupts. + \param [in] ticks Number of ticks between two interrupts. + \return 0 Function succeeded. + \return 1 Function failed. + \note When the variable __Vendor_SysTickConfig is set to 1, then the + function SysTick_Config is not included. In this case, the file device.h + must contain a vendor-specific implementation of this function. + */ +__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) +{ + if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) + { + return (1UL); /* Reload value impossible */ + } + + SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ + NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ + SysTick->VAL = 0UL; /* Load the SysTick Counter Value */ + SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + SysTick_CTRL_TICKINT_Msk | + SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ + return (0UL); /* Function successful */ +} + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +/** + \brief System Tick Configuration (non-secure) + \details Initializes the non-secure System Timer and its interrupt when in secure state, and starts the System Tick Timer. + Counter is in free running mode to generate periodic interrupts. + \param [in] ticks Number of ticks between two interrupts. + \return 0 Function succeeded. + \return 1 Function failed. + \note When the variable __Vendor_SysTickConfig is set to 1, then the + function TZ_SysTick_Config_NS is not included. In this case, the file device.h + must contain a vendor-specific implementation of this function. + + */ +__STATIC_INLINE uint32_t TZ_SysTick_Config_NS(uint32_t ticks) +{ + if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) + { + return (1UL); /* Reload value impossible */ + } + + SysTick_NS->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ + TZ_NVIC_SetPriority_NS (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ + SysTick_NS->VAL = 0UL; /* Load the SysTick Counter Value */ + SysTick_NS->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + SysTick_CTRL_TICKINT_Msk | + SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ + return (0UL); /* Function successful */ +} +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ + +#endif + +/*@} end of CMSIS_Core_SysTickFunctions */ + + + +/* ##################################### Debug In/Output function ########################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_core_DebugFunctions ITM Functions + \brief Functions that access the ITM debug interface. + @{ + */ + +extern volatile int32_t ITM_RxBuffer; /*!< External variable to receive characters. */ +#define ITM_RXBUFFER_EMPTY ((int32_t)0x5AA55AA5U) /*!< Value identifying \ref ITM_RxBuffer is ready for next character. */ + + +/** + \brief ITM Send Character + \details Transmits a character via the ITM channel 0, and + \li Just returns when no debugger is connected that has booked the output. + \li Is blocking when a debugger is connected, but the previous character sent has not been transmitted. + \param [in] ch Character to transmit. + \returns Character to transmit. + */ +__STATIC_INLINE uint32_t ITM_SendChar (uint32_t ch) +{ + if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && /* ITM enabled */ + ((ITM->TER & 1UL ) != 0UL) ) /* ITM Port #0 enabled */ + { + while (ITM->PORT[0U].u32 == 0UL) + { + __NOP(); + } + ITM->PORT[0U].u8 = (uint8_t)ch; + } + return (ch); +} + + +/** + \brief ITM Receive Character + \details Inputs a character via the external variable \ref ITM_RxBuffer. + \return Received character. + \return -1 No character pending. + */ +__STATIC_INLINE int32_t ITM_ReceiveChar (void) +{ + int32_t ch = -1; /* no character available */ + + if (ITM_RxBuffer != ITM_RXBUFFER_EMPTY) + { + ch = ITM_RxBuffer; + ITM_RxBuffer = ITM_RXBUFFER_EMPTY; /* ready for next character */ + } + + return (ch); +} + + +/** + \brief ITM Check Character + \details Checks whether a character is pending for reading in the variable \ref ITM_RxBuffer. + \return 0 No character available. + \return 1 Character available. + */ +__STATIC_INLINE int32_t ITM_CheckChar (void) +{ + + if (ITM_RxBuffer == ITM_RXBUFFER_EMPTY) + { + return (0); /* no character available */ + } + else + { + return (1); /* character available */ + } +} + +/*@} end of CMSIS_core_DebugFunctions */ + + + + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_CM33_H_DEPENDANT */ + +#endif /* __CMSIS_GENERIC */ diff --git a/lib/cmsis/inc/core_cm35p.h b/lib/cmsis/inc/core_cm35p.h new file mode 100644 index 0000000000..c00e54ca7a --- /dev/null +++ b/lib/cmsis/inc/core_cm35p.h @@ -0,0 +1,2907 @@ +/**************************************************************************//** + * @file core_cm35p.h + * @brief CMSIS Cortex-M35P Core Peripheral Access Layer Header File + * @version V1.0.0 + * @date 12. November 2018 + ******************************************************************************/ +/* + * Copyright (c) 2018 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined (__clang__) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef __CORE_CM35P_H_GENERIC +#define __CORE_CM35P_H_GENERIC + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/** + \page CMSIS_MISRA_Exceptions MISRA-C:2004 Compliance Exceptions + CMSIS violates the following MISRA-C:2004 rules: + + \li Required Rule 8.5, object/function definition in header file.
+ Function definitions in header files are used to allow 'inlining'. + + \li Required Rule 18.4, declaration of union type or object of union type: '{...}'.
+ Unions are used for effective representation of core registers. + + \li Advisory Rule 19.7, Function-like macro defined.
+ Function-like macros are used to allow more efficient code. + */ + + +/******************************************************************************* + * CMSIS definitions + ******************************************************************************/ +/** + \ingroup Cortex_M35P + @{ + */ + +#include "cmsis_version.h" + +/* CMSIS CM35P definitions */ +#define __CM35P_CMSIS_VERSION_MAIN (__CM_CMSIS_VERSION_MAIN) /*!< \deprecated [31:16] CMSIS HAL main version */ +#define __CM35P_CMSIS_VERSION_SUB (__CM_CMSIS_VERSION_SUB) /*!< \deprecated [15:0] CMSIS HAL sub version */ +#define __CM35P_CMSIS_VERSION ((__CM35P_CMSIS_VERSION_MAIN << 16U) | \ + __CM35P_CMSIS_VERSION_SUB ) /*!< \deprecated CMSIS HAL version number */ + +#define __CORTEX_M (35U) /*!< Cortex-M Core */ + +/** __FPU_USED indicates whether an FPU is used or not. + For this, __FPU_PRESENT has to be checked prior to making use of FPU specific registers and functions. +*/ +#if defined ( __CC_ARM ) + #if defined (__TARGET_FPU_VFP) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + + #if defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1U) + #if defined (__DSP_PRESENT) && (__DSP_PRESENT == 1U) + #define __DSP_USED 1U + #else + #error "Compiler generates DSP (SIMD) instructions for a devices without DSP extensions (check __DSP_PRESENT)" + #define __DSP_USED 0U + #endif + #else + #define __DSP_USED 0U + #endif + +#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #if defined (__ARM_FP) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #warning "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + + #if defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1U) + #if defined (__DSP_PRESENT) && (__DSP_PRESENT == 1U) + #define __DSP_USED 1U + #else + #error "Compiler generates DSP (SIMD) instructions for a devices without DSP extensions (check __DSP_PRESENT)" + #define __DSP_USED 0U + #endif + #else + #define __DSP_USED 0U + #endif + +#elif defined ( __GNUC__ ) + #if defined (__VFP_FP__) && !defined(__SOFTFP__) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + + #if defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1U) + #if defined (__DSP_PRESENT) && (__DSP_PRESENT == 1U) + #define __DSP_USED 1U + #else + #error "Compiler generates DSP (SIMD) instructions for a devices without DSP extensions (check __DSP_PRESENT)" + #define __DSP_USED 0U + #endif + #else + #define __DSP_USED 0U + #endif + +#elif defined ( __ICCARM__ ) + #if defined (__ARMVFP__) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + + #if defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1U) + #if defined (__DSP_PRESENT) && (__DSP_PRESENT == 1U) + #define __DSP_USED 1U + #else + #error "Compiler generates DSP (SIMD) instructions for a devices without DSP extensions (check __DSP_PRESENT)" + #define __DSP_USED 0U + #endif + #else + #define __DSP_USED 0U + #endif + +#elif defined ( __TI_ARM__ ) + #if defined (__TI_VFP_SUPPORT__) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#elif defined ( __TASKING__ ) + #if defined (__FPU_VFP__) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#elif defined ( __CSMC__ ) + #if ( __CSMC__ & 0x400U) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#endif + +#include "cmsis_compiler.h" /* CMSIS compiler specific defines */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_CM35P_H_GENERIC */ + +#ifndef __CMSIS_GENERIC + +#ifndef __CORE_CM35P_H_DEPENDANT +#define __CORE_CM35P_H_DEPENDANT + +#ifdef __cplusplus + extern "C" { +#endif + +/* check device defines and use defaults */ +#if defined __CHECK_DEVICE_DEFINES + #ifndef __CM35P_REV + #define __CM35P_REV 0x0000U + #warning "__CM35P_REV not defined in device header file; using default!" + #endif + + #ifndef __FPU_PRESENT + #define __FPU_PRESENT 0U + #warning "__FPU_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __MPU_PRESENT + #define __MPU_PRESENT 0U + #warning "__MPU_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __SAUREGION_PRESENT + #define __SAUREGION_PRESENT 0U + #warning "__SAUREGION_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __DSP_PRESENT + #define __DSP_PRESENT 0U + #warning "__DSP_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __NVIC_PRIO_BITS + #define __NVIC_PRIO_BITS 3U + #warning "__NVIC_PRIO_BITS not defined in device header file; using default!" + #endif + + #ifndef __Vendor_SysTickConfig + #define __Vendor_SysTickConfig 0U + #warning "__Vendor_SysTickConfig not defined in device header file; using default!" + #endif +#endif + +/* IO definitions (access restrictions to peripheral registers) */ +/** + \defgroup CMSIS_glob_defs CMSIS Global Defines + + IO Type Qualifiers are used + \li to specify the access to peripheral variables. + \li for automatic generation of peripheral register debug information. +*/ +#ifdef __cplusplus + #define __I volatile /*!< Defines 'read only' permissions */ +#else + #define __I volatile const /*!< Defines 'read only' permissions */ +#endif +#define __O volatile /*!< Defines 'write only' permissions */ +#define __IO volatile /*!< Defines 'read / write' permissions */ + +/* following defines should be used for structure members */ +#define __IM volatile const /*! Defines 'read only' structure member permissions */ +#define __OM volatile /*! Defines 'write only' structure member permissions */ +#define __IOM volatile /*! Defines 'read / write' structure member permissions */ + +/*@} end of group Cortex_M35P */ + + + +/******************************************************************************* + * Register Abstraction + Core Register contain: + - Core Register + - Core NVIC Register + - Core SCB Register + - Core SysTick Register + - Core Debug Register + - Core MPU Register + - Core SAU Register + - Core FPU Register + ******************************************************************************/ +/** + \defgroup CMSIS_core_register Defines and Type Definitions + \brief Type definitions and defines for Cortex-M processor based devices. +*/ + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CORE Status and Control Registers + \brief Core Register type definitions. + @{ + */ + +/** + \brief Union type to access the Application Program Status Register (APSR). + */ +typedef union +{ + struct + { + uint32_t _reserved0:16; /*!< bit: 0..15 Reserved */ + uint32_t GE:4; /*!< bit: 16..19 Greater than or Equal flags */ + uint32_t _reserved1:7; /*!< bit: 20..26 Reserved */ + uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} APSR_Type; + +/* APSR Register Definitions */ +#define APSR_N_Pos 31U /*!< APSR: N Position */ +#define APSR_N_Msk (1UL << APSR_N_Pos) /*!< APSR: N Mask */ + +#define APSR_Z_Pos 30U /*!< APSR: Z Position */ +#define APSR_Z_Msk (1UL << APSR_Z_Pos) /*!< APSR: Z Mask */ + +#define APSR_C_Pos 29U /*!< APSR: C Position */ +#define APSR_C_Msk (1UL << APSR_C_Pos) /*!< APSR: C Mask */ + +#define APSR_V_Pos 28U /*!< APSR: V Position */ +#define APSR_V_Msk (1UL << APSR_V_Pos) /*!< APSR: V Mask */ + +#define APSR_Q_Pos 27U /*!< APSR: Q Position */ +#define APSR_Q_Msk (1UL << APSR_Q_Pos) /*!< APSR: Q Mask */ + +#define APSR_GE_Pos 16U /*!< APSR: GE Position */ +#define APSR_GE_Msk (0xFUL << APSR_GE_Pos) /*!< APSR: GE Mask */ + + +/** + \brief Union type to access the Interrupt Program Status Register (IPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:23; /*!< bit: 9..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} IPSR_Type; + +/* IPSR Register Definitions */ +#define IPSR_ISR_Pos 0U /*!< IPSR: ISR Position */ +#define IPSR_ISR_Msk (0x1FFUL /*<< IPSR_ISR_Pos*/) /*!< IPSR: ISR Mask */ + + +/** + \brief Union type to access the Special-Purpose Program Status Registers (xPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:7; /*!< bit: 9..15 Reserved */ + uint32_t GE:4; /*!< bit: 16..19 Greater than or Equal flags */ + uint32_t _reserved1:4; /*!< bit: 20..23 Reserved */ + uint32_t T:1; /*!< bit: 24 Thumb bit (read 0) */ + uint32_t IT:2; /*!< bit: 25..26 saved IT state (read 0) */ + uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} xPSR_Type; + +/* xPSR Register Definitions */ +#define xPSR_N_Pos 31U /*!< xPSR: N Position */ +#define xPSR_N_Msk (1UL << xPSR_N_Pos) /*!< xPSR: N Mask */ + +#define xPSR_Z_Pos 30U /*!< xPSR: Z Position */ +#define xPSR_Z_Msk (1UL << xPSR_Z_Pos) /*!< xPSR: Z Mask */ + +#define xPSR_C_Pos 29U /*!< xPSR: C Position */ +#define xPSR_C_Msk (1UL << xPSR_C_Pos) /*!< xPSR: C Mask */ + +#define xPSR_V_Pos 28U /*!< xPSR: V Position */ +#define xPSR_V_Msk (1UL << xPSR_V_Pos) /*!< xPSR: V Mask */ + +#define xPSR_Q_Pos 27U /*!< xPSR: Q Position */ +#define xPSR_Q_Msk (1UL << xPSR_Q_Pos) /*!< xPSR: Q Mask */ + +#define xPSR_IT_Pos 25U /*!< xPSR: IT Position */ +#define xPSR_IT_Msk (3UL << xPSR_IT_Pos) /*!< xPSR: IT Mask */ + +#define xPSR_T_Pos 24U /*!< xPSR: T Position */ +#define xPSR_T_Msk (1UL << xPSR_T_Pos) /*!< xPSR: T Mask */ + +#define xPSR_GE_Pos 16U /*!< xPSR: GE Position */ +#define xPSR_GE_Msk (0xFUL << xPSR_GE_Pos) /*!< xPSR: GE Mask */ + +#define xPSR_ISR_Pos 0U /*!< xPSR: ISR Position */ +#define xPSR_ISR_Msk (0x1FFUL /*<< xPSR_ISR_Pos*/) /*!< xPSR: ISR Mask */ + + +/** + \brief Union type to access the Control Registers (CONTROL). + */ +typedef union +{ + struct + { + uint32_t nPRIV:1; /*!< bit: 0 Execution privilege in Thread mode */ + uint32_t SPSEL:1; /*!< bit: 1 Stack-pointer select */ + uint32_t FPCA:1; /*!< bit: 2 Floating-point context active */ + uint32_t SFPA:1; /*!< bit: 3 Secure floating-point active */ + uint32_t _reserved1:28; /*!< bit: 4..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} CONTROL_Type; + +/* CONTROL Register Definitions */ +#define CONTROL_SFPA_Pos 3U /*!< CONTROL: SFPA Position */ +#define CONTROL_SFPA_Msk (1UL << CONTROL_SFPA_Pos) /*!< CONTROL: SFPA Mask */ + +#define CONTROL_FPCA_Pos 2U /*!< CONTROL: FPCA Position */ +#define CONTROL_FPCA_Msk (1UL << CONTROL_FPCA_Pos) /*!< CONTROL: FPCA Mask */ + +#define CONTROL_SPSEL_Pos 1U /*!< CONTROL: SPSEL Position */ +#define CONTROL_SPSEL_Msk (1UL << CONTROL_SPSEL_Pos) /*!< CONTROL: SPSEL Mask */ + +#define CONTROL_nPRIV_Pos 0U /*!< CONTROL: nPRIV Position */ +#define CONTROL_nPRIV_Msk (1UL /*<< CONTROL_nPRIV_Pos*/) /*!< CONTROL: nPRIV Mask */ + +/*@} end of group CMSIS_CORE */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_NVIC Nested Vectored Interrupt Controller (NVIC) + \brief Type definitions for the NVIC Registers + @{ + */ + +/** + \brief Structure type to access the Nested Vectored Interrupt Controller (NVIC). + */ +typedef struct +{ + __IOM uint32_t ISER[16U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ + uint32_t RESERVED0[16U]; + __IOM uint32_t ICER[16U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ + uint32_t RSERVED1[16U]; + __IOM uint32_t ISPR[16U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ + uint32_t RESERVED2[16U]; + __IOM uint32_t ICPR[16U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ + uint32_t RESERVED3[16U]; + __IOM uint32_t IABR[16U]; /*!< Offset: 0x200 (R/W) Interrupt Active bit Register */ + uint32_t RESERVED4[16U]; + __IOM uint32_t ITNS[16U]; /*!< Offset: 0x280 (R/W) Interrupt Non-Secure State Register */ + uint32_t RESERVED5[16U]; + __IOM uint8_t IPR[496U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register (8Bit wide) */ + uint32_t RESERVED6[580U]; + __OM uint32_t STIR; /*!< Offset: 0xE00 ( /W) Software Trigger Interrupt Register */ +} NVIC_Type; + +/* Software Triggered Interrupt Register Definitions */ +#define NVIC_STIR_INTID_Pos 0U /*!< STIR: INTLINESNUM Position */ +#define NVIC_STIR_INTID_Msk (0x1FFUL /*<< NVIC_STIR_INTID_Pos*/) /*!< STIR: INTLINESNUM Mask */ + +/*@} end of group CMSIS_NVIC */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SCB System Control Block (SCB) + \brief Type definitions for the System Control Block Registers + @{ + */ + +/** + \brief Structure type to access the System Control Block (SCB). + */ +typedef struct +{ + __IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */ + __IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */ + __IOM uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */ + __IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */ + __IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */ + __IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */ + __IOM uint8_t SHPR[12U]; /*!< Offset: 0x018 (R/W) System Handlers Priority Registers (4-7, 8-11, 12-15) */ + __IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */ + __IOM uint32_t CFSR; /*!< Offset: 0x028 (R/W) Configurable Fault Status Register */ + __IOM uint32_t HFSR; /*!< Offset: 0x02C (R/W) HardFault Status Register */ + __IOM uint32_t DFSR; /*!< Offset: 0x030 (R/W) Debug Fault Status Register */ + __IOM uint32_t MMFAR; /*!< Offset: 0x034 (R/W) MemManage Fault Address Register */ + __IOM uint32_t BFAR; /*!< Offset: 0x038 (R/W) BusFault Address Register */ + __IOM uint32_t AFSR; /*!< Offset: 0x03C (R/W) Auxiliary Fault Status Register */ + __IM uint32_t ID_PFR[2U]; /*!< Offset: 0x040 (R/ ) Processor Feature Register */ + __IM uint32_t ID_DFR; /*!< Offset: 0x048 (R/ ) Debug Feature Register */ + __IM uint32_t ID_ADR; /*!< Offset: 0x04C (R/ ) Auxiliary Feature Register */ + __IM uint32_t ID_MMFR[4U]; /*!< Offset: 0x050 (R/ ) Memory Model Feature Register */ + __IM uint32_t ID_ISAR[6U]; /*!< Offset: 0x060 (R/ ) Instruction Set Attributes Register */ + __IM uint32_t CLIDR; /*!< Offset: 0x078 (R/ ) Cache Level ID register */ + __IM uint32_t CTR; /*!< Offset: 0x07C (R/ ) Cache Type register */ + __IM uint32_t CCSIDR; /*!< Offset: 0x080 (R/ ) Cache Size ID Register */ + __IOM uint32_t CSSELR; /*!< Offset: 0x084 (R/W) Cache Size Selection Register */ + __IOM uint32_t CPACR; /*!< Offset: 0x088 (R/W) Coprocessor Access Control Register */ + __IOM uint32_t NSACR; /*!< Offset: 0x08C (R/W) Non-Secure Access Control Register */ + uint32_t RESERVED3[92U]; + __OM uint32_t STIR; /*!< Offset: 0x200 ( /W) Software Triggered Interrupt Register */ + uint32_t RESERVED4[15U]; + __IM uint32_t MVFR0; /*!< Offset: 0x240 (R/ ) Media and VFP Feature Register 0 */ + __IM uint32_t MVFR1; /*!< Offset: 0x244 (R/ ) Media and VFP Feature Register 1 */ + __IM uint32_t MVFR2; /*!< Offset: 0x248 (R/ ) Media and VFP Feature Register 2 */ + uint32_t RESERVED5[1U]; + __OM uint32_t ICIALLU; /*!< Offset: 0x250 ( /W) I-Cache Invalidate All to PoU */ + uint32_t RESERVED6[1U]; + __OM uint32_t ICIMVAU; /*!< Offset: 0x258 ( /W) I-Cache Invalidate by MVA to PoU */ + __OM uint32_t DCIMVAC; /*!< Offset: 0x25C ( /W) D-Cache Invalidate by MVA to PoC */ + __OM uint32_t DCISW; /*!< Offset: 0x260 ( /W) D-Cache Invalidate by Set-way */ + __OM uint32_t DCCMVAU; /*!< Offset: 0x264 ( /W) D-Cache Clean by MVA to PoU */ + __OM uint32_t DCCMVAC; /*!< Offset: 0x268 ( /W) D-Cache Clean by MVA to PoC */ + __OM uint32_t DCCSW; /*!< Offset: 0x26C ( /W) D-Cache Clean by Set-way */ + __OM uint32_t DCCIMVAC; /*!< Offset: 0x270 ( /W) D-Cache Clean and Invalidate by MVA to PoC */ + __OM uint32_t DCCISW; /*!< Offset: 0x274 ( /W) D-Cache Clean and Invalidate by Set-way */ +} SCB_Type; + +/* SCB CPUID Register Definitions */ +#define SCB_CPUID_IMPLEMENTER_Pos 24U /*!< SCB CPUID: IMPLEMENTER Position */ +#define SCB_CPUID_IMPLEMENTER_Msk (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos) /*!< SCB CPUID: IMPLEMENTER Mask */ + +#define SCB_CPUID_VARIANT_Pos 20U /*!< SCB CPUID: VARIANT Position */ +#define SCB_CPUID_VARIANT_Msk (0xFUL << SCB_CPUID_VARIANT_Pos) /*!< SCB CPUID: VARIANT Mask */ + +#define SCB_CPUID_ARCHITECTURE_Pos 16U /*!< SCB CPUID: ARCHITECTURE Position */ +#define SCB_CPUID_ARCHITECTURE_Msk (0xFUL << SCB_CPUID_ARCHITECTURE_Pos) /*!< SCB CPUID: ARCHITECTURE Mask */ + +#define SCB_CPUID_PARTNO_Pos 4U /*!< SCB CPUID: PARTNO Position */ +#define SCB_CPUID_PARTNO_Msk (0xFFFUL << SCB_CPUID_PARTNO_Pos) /*!< SCB CPUID: PARTNO Mask */ + +#define SCB_CPUID_REVISION_Pos 0U /*!< SCB CPUID: REVISION Position */ +#define SCB_CPUID_REVISION_Msk (0xFUL /*<< SCB_CPUID_REVISION_Pos*/) /*!< SCB CPUID: REVISION Mask */ + +/* SCB Interrupt Control State Register Definitions */ +#define SCB_ICSR_PENDNMISET_Pos 31U /*!< SCB ICSR: PENDNMISET Position */ +#define SCB_ICSR_PENDNMISET_Msk (1UL << SCB_ICSR_PENDNMISET_Pos) /*!< SCB ICSR: PENDNMISET Mask */ + +#define SCB_ICSR_NMIPENDSET_Pos SCB_ICSR_PENDNMISET_Pos /*!< SCB ICSR: NMIPENDSET Position, backward compatibility */ +#define SCB_ICSR_NMIPENDSET_Msk SCB_ICSR_PENDNMISET_Msk /*!< SCB ICSR: NMIPENDSET Mask, backward compatibility */ + +#define SCB_ICSR_PENDNMICLR_Pos 30U /*!< SCB ICSR: PENDNMICLR Position */ +#define SCB_ICSR_PENDNMICLR_Msk (1UL << SCB_ICSR_PENDNMICLR_Pos) /*!< SCB ICSR: PENDNMICLR Mask */ + +#define SCB_ICSR_PENDSVSET_Pos 28U /*!< SCB ICSR: PENDSVSET Position */ +#define SCB_ICSR_PENDSVSET_Msk (1UL << SCB_ICSR_PENDSVSET_Pos) /*!< SCB ICSR: PENDSVSET Mask */ + +#define SCB_ICSR_PENDSVCLR_Pos 27U /*!< SCB ICSR: PENDSVCLR Position */ +#define SCB_ICSR_PENDSVCLR_Msk (1UL << SCB_ICSR_PENDSVCLR_Pos) /*!< SCB ICSR: PENDSVCLR Mask */ + +#define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */ +#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */ + +#define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */ +#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */ + +#define SCB_ICSR_STTNS_Pos 24U /*!< SCB ICSR: STTNS Position (Security Extension) */ +#define SCB_ICSR_STTNS_Msk (1UL << SCB_ICSR_STTNS_Pos) /*!< SCB ICSR: STTNS Mask (Security Extension) */ + +#define SCB_ICSR_ISRPREEMPT_Pos 23U /*!< SCB ICSR: ISRPREEMPT Position */ +#define SCB_ICSR_ISRPREEMPT_Msk (1UL << SCB_ICSR_ISRPREEMPT_Pos) /*!< SCB ICSR: ISRPREEMPT Mask */ + +#define SCB_ICSR_ISRPENDING_Pos 22U /*!< SCB ICSR: ISRPENDING Position */ +#define SCB_ICSR_ISRPENDING_Msk (1UL << SCB_ICSR_ISRPENDING_Pos) /*!< SCB ICSR: ISRPENDING Mask */ + +#define SCB_ICSR_VECTPENDING_Pos 12U /*!< SCB ICSR: VECTPENDING Position */ +#define SCB_ICSR_VECTPENDING_Msk (0x1FFUL << SCB_ICSR_VECTPENDING_Pos) /*!< SCB ICSR: VECTPENDING Mask */ + +#define SCB_ICSR_RETTOBASE_Pos 11U /*!< SCB ICSR: RETTOBASE Position */ +#define SCB_ICSR_RETTOBASE_Msk (1UL << SCB_ICSR_RETTOBASE_Pos) /*!< SCB ICSR: RETTOBASE Mask */ + +#define SCB_ICSR_VECTACTIVE_Pos 0U /*!< SCB ICSR: VECTACTIVE Position */ +#define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL /*<< SCB_ICSR_VECTACTIVE_Pos*/) /*!< SCB ICSR: VECTACTIVE Mask */ + +/* SCB Vector Table Offset Register Definitions */ +#define SCB_VTOR_TBLOFF_Pos 7U /*!< SCB VTOR: TBLOFF Position */ +#define SCB_VTOR_TBLOFF_Msk (0x1FFFFFFUL << SCB_VTOR_TBLOFF_Pos) /*!< SCB VTOR: TBLOFF Mask */ + +/* SCB Application Interrupt and Reset Control Register Definitions */ +#define SCB_AIRCR_VECTKEY_Pos 16U /*!< SCB AIRCR: VECTKEY Position */ +#define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */ + +#define SCB_AIRCR_VECTKEYSTAT_Pos 16U /*!< SCB AIRCR: VECTKEYSTAT Position */ +#define SCB_AIRCR_VECTKEYSTAT_Msk (0xFFFFUL << SCB_AIRCR_VECTKEYSTAT_Pos) /*!< SCB AIRCR: VECTKEYSTAT Mask */ + +#define SCB_AIRCR_ENDIANESS_Pos 15U /*!< SCB AIRCR: ENDIANESS Position */ +#define SCB_AIRCR_ENDIANESS_Msk (1UL << SCB_AIRCR_ENDIANESS_Pos) /*!< SCB AIRCR: ENDIANESS Mask */ + +#define SCB_AIRCR_PRIS_Pos 14U /*!< SCB AIRCR: PRIS Position */ +#define SCB_AIRCR_PRIS_Msk (1UL << SCB_AIRCR_PRIS_Pos) /*!< SCB AIRCR: PRIS Mask */ + +#define SCB_AIRCR_BFHFNMINS_Pos 13U /*!< SCB AIRCR: BFHFNMINS Position */ +#define SCB_AIRCR_BFHFNMINS_Msk (1UL << SCB_AIRCR_BFHFNMINS_Pos) /*!< SCB AIRCR: BFHFNMINS Mask */ + +#define SCB_AIRCR_PRIGROUP_Pos 8U /*!< SCB AIRCR: PRIGROUP Position */ +#define SCB_AIRCR_PRIGROUP_Msk (7UL << SCB_AIRCR_PRIGROUP_Pos) /*!< SCB AIRCR: PRIGROUP Mask */ + +#define SCB_AIRCR_SYSRESETREQS_Pos 3U /*!< SCB AIRCR: SYSRESETREQS Position */ +#define SCB_AIRCR_SYSRESETREQS_Msk (1UL << SCB_AIRCR_SYSRESETREQS_Pos) /*!< SCB AIRCR: SYSRESETREQS Mask */ + +#define SCB_AIRCR_SYSRESETREQ_Pos 2U /*!< SCB AIRCR: SYSRESETREQ Position */ +#define SCB_AIRCR_SYSRESETREQ_Msk (1UL << SCB_AIRCR_SYSRESETREQ_Pos) /*!< SCB AIRCR: SYSRESETREQ Mask */ + +#define SCB_AIRCR_VECTCLRACTIVE_Pos 1U /*!< SCB AIRCR: VECTCLRACTIVE Position */ +#define SCB_AIRCR_VECTCLRACTIVE_Msk (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos) /*!< SCB AIRCR: VECTCLRACTIVE Mask */ + +/* SCB System Control Register Definitions */ +#define SCB_SCR_SEVONPEND_Pos 4U /*!< SCB SCR: SEVONPEND Position */ +#define SCB_SCR_SEVONPEND_Msk (1UL << SCB_SCR_SEVONPEND_Pos) /*!< SCB SCR: SEVONPEND Mask */ + +#define SCB_SCR_SLEEPDEEPS_Pos 3U /*!< SCB SCR: SLEEPDEEPS Position */ +#define SCB_SCR_SLEEPDEEPS_Msk (1UL << SCB_SCR_SLEEPDEEPS_Pos) /*!< SCB SCR: SLEEPDEEPS Mask */ + +#define SCB_SCR_SLEEPDEEP_Pos 2U /*!< SCB SCR: SLEEPDEEP Position */ +#define SCB_SCR_SLEEPDEEP_Msk (1UL << SCB_SCR_SLEEPDEEP_Pos) /*!< SCB SCR: SLEEPDEEP Mask */ + +#define SCB_SCR_SLEEPONEXIT_Pos 1U /*!< SCB SCR: SLEEPONEXIT Position */ +#define SCB_SCR_SLEEPONEXIT_Msk (1UL << SCB_SCR_SLEEPONEXIT_Pos) /*!< SCB SCR: SLEEPONEXIT Mask */ + +/* SCB Configuration Control Register Definitions */ +#define SCB_CCR_BP_Pos 18U /*!< SCB CCR: BP Position */ +#define SCB_CCR_BP_Msk (1UL << SCB_CCR_BP_Pos) /*!< SCB CCR: BP Mask */ + +#define SCB_CCR_IC_Pos 17U /*!< SCB CCR: IC Position */ +#define SCB_CCR_IC_Msk (1UL << SCB_CCR_IC_Pos) /*!< SCB CCR: IC Mask */ + +#define SCB_CCR_DC_Pos 16U /*!< SCB CCR: DC Position */ +#define SCB_CCR_DC_Msk (1UL << SCB_CCR_DC_Pos) /*!< SCB CCR: DC Mask */ + +#define SCB_CCR_STKOFHFNMIGN_Pos 10U /*!< SCB CCR: STKOFHFNMIGN Position */ +#define SCB_CCR_STKOFHFNMIGN_Msk (1UL << SCB_CCR_STKOFHFNMIGN_Pos) /*!< SCB CCR: STKOFHFNMIGN Mask */ + +#define SCB_CCR_BFHFNMIGN_Pos 8U /*!< SCB CCR: BFHFNMIGN Position */ +#define SCB_CCR_BFHFNMIGN_Msk (1UL << SCB_CCR_BFHFNMIGN_Pos) /*!< SCB CCR: BFHFNMIGN Mask */ + +#define SCB_CCR_DIV_0_TRP_Pos 4U /*!< SCB CCR: DIV_0_TRP Position */ +#define SCB_CCR_DIV_0_TRP_Msk (1UL << SCB_CCR_DIV_0_TRP_Pos) /*!< SCB CCR: DIV_0_TRP Mask */ + +#define SCB_CCR_UNALIGN_TRP_Pos 3U /*!< SCB CCR: UNALIGN_TRP Position */ +#define SCB_CCR_UNALIGN_TRP_Msk (1UL << SCB_CCR_UNALIGN_TRP_Pos) /*!< SCB CCR: UNALIGN_TRP Mask */ + +#define SCB_CCR_USERSETMPEND_Pos 1U /*!< SCB CCR: USERSETMPEND Position */ +#define SCB_CCR_USERSETMPEND_Msk (1UL << SCB_CCR_USERSETMPEND_Pos) /*!< SCB CCR: USERSETMPEND Mask */ + +/* SCB System Handler Control and State Register Definitions */ +#define SCB_SHCSR_HARDFAULTPENDED_Pos 21U /*!< SCB SHCSR: HARDFAULTPENDED Position */ +#define SCB_SHCSR_HARDFAULTPENDED_Msk (1UL << SCB_SHCSR_HARDFAULTPENDED_Pos) /*!< SCB SHCSR: HARDFAULTPENDED Mask */ + +#define SCB_SHCSR_SECUREFAULTPENDED_Pos 20U /*!< SCB SHCSR: SECUREFAULTPENDED Position */ +#define SCB_SHCSR_SECUREFAULTPENDED_Msk (1UL << SCB_SHCSR_SECUREFAULTPENDED_Pos) /*!< SCB SHCSR: SECUREFAULTPENDED Mask */ + +#define SCB_SHCSR_SECUREFAULTENA_Pos 19U /*!< SCB SHCSR: SECUREFAULTENA Position */ +#define SCB_SHCSR_SECUREFAULTENA_Msk (1UL << SCB_SHCSR_SECUREFAULTENA_Pos) /*!< SCB SHCSR: SECUREFAULTENA Mask */ + +#define SCB_SHCSR_USGFAULTENA_Pos 18U /*!< SCB SHCSR: USGFAULTENA Position */ +#define SCB_SHCSR_USGFAULTENA_Msk (1UL << SCB_SHCSR_USGFAULTENA_Pos) /*!< SCB SHCSR: USGFAULTENA Mask */ + +#define SCB_SHCSR_BUSFAULTENA_Pos 17U /*!< SCB SHCSR: BUSFAULTENA Position */ +#define SCB_SHCSR_BUSFAULTENA_Msk (1UL << SCB_SHCSR_BUSFAULTENA_Pos) /*!< SCB SHCSR: BUSFAULTENA Mask */ + +#define SCB_SHCSR_MEMFAULTENA_Pos 16U /*!< SCB SHCSR: MEMFAULTENA Position */ +#define SCB_SHCSR_MEMFAULTENA_Msk (1UL << SCB_SHCSR_MEMFAULTENA_Pos) /*!< SCB SHCSR: MEMFAULTENA Mask */ + +#define SCB_SHCSR_SVCALLPENDED_Pos 15U /*!< SCB SHCSR: SVCALLPENDED Position */ +#define SCB_SHCSR_SVCALLPENDED_Msk (1UL << SCB_SHCSR_SVCALLPENDED_Pos) /*!< SCB SHCSR: SVCALLPENDED Mask */ + +#define SCB_SHCSR_BUSFAULTPENDED_Pos 14U /*!< SCB SHCSR: BUSFAULTPENDED Position */ +#define SCB_SHCSR_BUSFAULTPENDED_Msk (1UL << SCB_SHCSR_BUSFAULTPENDED_Pos) /*!< SCB SHCSR: BUSFAULTPENDED Mask */ + +#define SCB_SHCSR_MEMFAULTPENDED_Pos 13U /*!< SCB SHCSR: MEMFAULTPENDED Position */ +#define SCB_SHCSR_MEMFAULTPENDED_Msk (1UL << SCB_SHCSR_MEMFAULTPENDED_Pos) /*!< SCB SHCSR: MEMFAULTPENDED Mask */ + +#define SCB_SHCSR_USGFAULTPENDED_Pos 12U /*!< SCB SHCSR: USGFAULTPENDED Position */ +#define SCB_SHCSR_USGFAULTPENDED_Msk (1UL << SCB_SHCSR_USGFAULTPENDED_Pos) /*!< SCB SHCSR: USGFAULTPENDED Mask */ + +#define SCB_SHCSR_SYSTICKACT_Pos 11U /*!< SCB SHCSR: SYSTICKACT Position */ +#define SCB_SHCSR_SYSTICKACT_Msk (1UL << SCB_SHCSR_SYSTICKACT_Pos) /*!< SCB SHCSR: SYSTICKACT Mask */ + +#define SCB_SHCSR_PENDSVACT_Pos 10U /*!< SCB SHCSR: PENDSVACT Position */ +#define SCB_SHCSR_PENDSVACT_Msk (1UL << SCB_SHCSR_PENDSVACT_Pos) /*!< SCB SHCSR: PENDSVACT Mask */ + +#define SCB_SHCSR_MONITORACT_Pos 8U /*!< SCB SHCSR: MONITORACT Position */ +#define SCB_SHCSR_MONITORACT_Msk (1UL << SCB_SHCSR_MONITORACT_Pos) /*!< SCB SHCSR: MONITORACT Mask */ + +#define SCB_SHCSR_SVCALLACT_Pos 7U /*!< SCB SHCSR: SVCALLACT Position */ +#define SCB_SHCSR_SVCALLACT_Msk (1UL << SCB_SHCSR_SVCALLACT_Pos) /*!< SCB SHCSR: SVCALLACT Mask */ + +#define SCB_SHCSR_NMIACT_Pos 5U /*!< SCB SHCSR: NMIACT Position */ +#define SCB_SHCSR_NMIACT_Msk (1UL << SCB_SHCSR_NMIACT_Pos) /*!< SCB SHCSR: NMIACT Mask */ + +#define SCB_SHCSR_SECUREFAULTACT_Pos 4U /*!< SCB SHCSR: SECUREFAULTACT Position */ +#define SCB_SHCSR_SECUREFAULTACT_Msk (1UL << SCB_SHCSR_SECUREFAULTACT_Pos) /*!< SCB SHCSR: SECUREFAULTACT Mask */ + +#define SCB_SHCSR_USGFAULTACT_Pos 3U /*!< SCB SHCSR: USGFAULTACT Position */ +#define SCB_SHCSR_USGFAULTACT_Msk (1UL << SCB_SHCSR_USGFAULTACT_Pos) /*!< SCB SHCSR: USGFAULTACT Mask */ + +#define SCB_SHCSR_HARDFAULTACT_Pos 2U /*!< SCB SHCSR: HARDFAULTACT Position */ +#define SCB_SHCSR_HARDFAULTACT_Msk (1UL << SCB_SHCSR_HARDFAULTACT_Pos) /*!< SCB SHCSR: HARDFAULTACT Mask */ + +#define SCB_SHCSR_BUSFAULTACT_Pos 1U /*!< SCB SHCSR: BUSFAULTACT Position */ +#define SCB_SHCSR_BUSFAULTACT_Msk (1UL << SCB_SHCSR_BUSFAULTACT_Pos) /*!< SCB SHCSR: BUSFAULTACT Mask */ + +#define SCB_SHCSR_MEMFAULTACT_Pos 0U /*!< SCB SHCSR: MEMFAULTACT Position */ +#define SCB_SHCSR_MEMFAULTACT_Msk (1UL /*<< SCB_SHCSR_MEMFAULTACT_Pos*/) /*!< SCB SHCSR: MEMFAULTACT Mask */ + +/* SCB Configurable Fault Status Register Definitions */ +#define SCB_CFSR_USGFAULTSR_Pos 16U /*!< SCB CFSR: Usage Fault Status Register Position */ +#define SCB_CFSR_USGFAULTSR_Msk (0xFFFFUL << SCB_CFSR_USGFAULTSR_Pos) /*!< SCB CFSR: Usage Fault Status Register Mask */ + +#define SCB_CFSR_BUSFAULTSR_Pos 8U /*!< SCB CFSR: Bus Fault Status Register Position */ +#define SCB_CFSR_BUSFAULTSR_Msk (0xFFUL << SCB_CFSR_BUSFAULTSR_Pos) /*!< SCB CFSR: Bus Fault Status Register Mask */ + +#define SCB_CFSR_MEMFAULTSR_Pos 0U /*!< SCB CFSR: Memory Manage Fault Status Register Position */ +#define SCB_CFSR_MEMFAULTSR_Msk (0xFFUL /*<< SCB_CFSR_MEMFAULTSR_Pos*/) /*!< SCB CFSR: Memory Manage Fault Status Register Mask */ + +/* MemManage Fault Status Register (part of SCB Configurable Fault Status Register) */ +#define SCB_CFSR_MMARVALID_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 7U) /*!< SCB CFSR (MMFSR): MMARVALID Position */ +#define SCB_CFSR_MMARVALID_Msk (1UL << SCB_CFSR_MMARVALID_Pos) /*!< SCB CFSR (MMFSR): MMARVALID Mask */ + +#define SCB_CFSR_MLSPERR_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 5U) /*!< SCB CFSR (MMFSR): MLSPERR Position */ +#define SCB_CFSR_MLSPERR_Msk (1UL << SCB_CFSR_MLSPERR_Pos) /*!< SCB CFSR (MMFSR): MLSPERR Mask */ + +#define SCB_CFSR_MSTKERR_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 4U) /*!< SCB CFSR (MMFSR): MSTKERR Position */ +#define SCB_CFSR_MSTKERR_Msk (1UL << SCB_CFSR_MSTKERR_Pos) /*!< SCB CFSR (MMFSR): MSTKERR Mask */ + +#define SCB_CFSR_MUNSTKERR_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 3U) /*!< SCB CFSR (MMFSR): MUNSTKERR Position */ +#define SCB_CFSR_MUNSTKERR_Msk (1UL << SCB_CFSR_MUNSTKERR_Pos) /*!< SCB CFSR (MMFSR): MUNSTKERR Mask */ + +#define SCB_CFSR_DACCVIOL_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 1U) /*!< SCB CFSR (MMFSR): DACCVIOL Position */ +#define SCB_CFSR_DACCVIOL_Msk (1UL << SCB_CFSR_DACCVIOL_Pos) /*!< SCB CFSR (MMFSR): DACCVIOL Mask */ + +#define SCB_CFSR_IACCVIOL_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 0U) /*!< SCB CFSR (MMFSR): IACCVIOL Position */ +#define SCB_CFSR_IACCVIOL_Msk (1UL /*<< SCB_CFSR_IACCVIOL_Pos*/) /*!< SCB CFSR (MMFSR): IACCVIOL Mask */ + +/* BusFault Status Register (part of SCB Configurable Fault Status Register) */ +#define SCB_CFSR_BFARVALID_Pos (SCB_CFSR_BUSFAULTSR_Pos + 7U) /*!< SCB CFSR (BFSR): BFARVALID Position */ +#define SCB_CFSR_BFARVALID_Msk (1UL << SCB_CFSR_BFARVALID_Pos) /*!< SCB CFSR (BFSR): BFARVALID Mask */ + +#define SCB_CFSR_LSPERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 5U) /*!< SCB CFSR (BFSR): LSPERR Position */ +#define SCB_CFSR_LSPERR_Msk (1UL << SCB_CFSR_LSPERR_Pos) /*!< SCB CFSR (BFSR): LSPERR Mask */ + +#define SCB_CFSR_STKERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 4U) /*!< SCB CFSR (BFSR): STKERR Position */ +#define SCB_CFSR_STKERR_Msk (1UL << SCB_CFSR_STKERR_Pos) /*!< SCB CFSR (BFSR): STKERR Mask */ + +#define SCB_CFSR_UNSTKERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 3U) /*!< SCB CFSR (BFSR): UNSTKERR Position */ +#define SCB_CFSR_UNSTKERR_Msk (1UL << SCB_CFSR_UNSTKERR_Pos) /*!< SCB CFSR (BFSR): UNSTKERR Mask */ + +#define SCB_CFSR_IMPRECISERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 2U) /*!< SCB CFSR (BFSR): IMPRECISERR Position */ +#define SCB_CFSR_IMPRECISERR_Msk (1UL << SCB_CFSR_IMPRECISERR_Pos) /*!< SCB CFSR (BFSR): IMPRECISERR Mask */ + +#define SCB_CFSR_PRECISERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 1U) /*!< SCB CFSR (BFSR): PRECISERR Position */ +#define SCB_CFSR_PRECISERR_Msk (1UL << SCB_CFSR_PRECISERR_Pos) /*!< SCB CFSR (BFSR): PRECISERR Mask */ + +#define SCB_CFSR_IBUSERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 0U) /*!< SCB CFSR (BFSR): IBUSERR Position */ +#define SCB_CFSR_IBUSERR_Msk (1UL << SCB_CFSR_IBUSERR_Pos) /*!< SCB CFSR (BFSR): IBUSERR Mask */ + +/* UsageFault Status Register (part of SCB Configurable Fault Status Register) */ +#define SCB_CFSR_DIVBYZERO_Pos (SCB_CFSR_USGFAULTSR_Pos + 9U) /*!< SCB CFSR (UFSR): DIVBYZERO Position */ +#define SCB_CFSR_DIVBYZERO_Msk (1UL << SCB_CFSR_DIVBYZERO_Pos) /*!< SCB CFSR (UFSR): DIVBYZERO Mask */ + +#define SCB_CFSR_UNALIGNED_Pos (SCB_CFSR_USGFAULTSR_Pos + 8U) /*!< SCB CFSR (UFSR): UNALIGNED Position */ +#define SCB_CFSR_UNALIGNED_Msk (1UL << SCB_CFSR_UNALIGNED_Pos) /*!< SCB CFSR (UFSR): UNALIGNED Mask */ + +#define SCB_CFSR_STKOF_Pos (SCB_CFSR_USGFAULTSR_Pos + 4U) /*!< SCB CFSR (UFSR): STKOF Position */ +#define SCB_CFSR_STKOF_Msk (1UL << SCB_CFSR_STKOF_Pos) /*!< SCB CFSR (UFSR): STKOF Mask */ + +#define SCB_CFSR_NOCP_Pos (SCB_CFSR_USGFAULTSR_Pos + 3U) /*!< SCB CFSR (UFSR): NOCP Position */ +#define SCB_CFSR_NOCP_Msk (1UL << SCB_CFSR_NOCP_Pos) /*!< SCB CFSR (UFSR): NOCP Mask */ + +#define SCB_CFSR_INVPC_Pos (SCB_CFSR_USGFAULTSR_Pos + 2U) /*!< SCB CFSR (UFSR): INVPC Position */ +#define SCB_CFSR_INVPC_Msk (1UL << SCB_CFSR_INVPC_Pos) /*!< SCB CFSR (UFSR): INVPC Mask */ + +#define SCB_CFSR_INVSTATE_Pos (SCB_CFSR_USGFAULTSR_Pos + 1U) /*!< SCB CFSR (UFSR): INVSTATE Position */ +#define SCB_CFSR_INVSTATE_Msk (1UL << SCB_CFSR_INVSTATE_Pos) /*!< SCB CFSR (UFSR): INVSTATE Mask */ + +#define SCB_CFSR_UNDEFINSTR_Pos (SCB_CFSR_USGFAULTSR_Pos + 0U) /*!< SCB CFSR (UFSR): UNDEFINSTR Position */ +#define SCB_CFSR_UNDEFINSTR_Msk (1UL << SCB_CFSR_UNDEFINSTR_Pos) /*!< SCB CFSR (UFSR): UNDEFINSTR Mask */ + +/* SCB Hard Fault Status Register Definitions */ +#define SCB_HFSR_DEBUGEVT_Pos 31U /*!< SCB HFSR: DEBUGEVT Position */ +#define SCB_HFSR_DEBUGEVT_Msk (1UL << SCB_HFSR_DEBUGEVT_Pos) /*!< SCB HFSR: DEBUGEVT Mask */ + +#define SCB_HFSR_FORCED_Pos 30U /*!< SCB HFSR: FORCED Position */ +#define SCB_HFSR_FORCED_Msk (1UL << SCB_HFSR_FORCED_Pos) /*!< SCB HFSR: FORCED Mask */ + +#define SCB_HFSR_VECTTBL_Pos 1U /*!< SCB HFSR: VECTTBL Position */ +#define SCB_HFSR_VECTTBL_Msk (1UL << SCB_HFSR_VECTTBL_Pos) /*!< SCB HFSR: VECTTBL Mask */ + +/* SCB Debug Fault Status Register Definitions */ +#define SCB_DFSR_EXTERNAL_Pos 4U /*!< SCB DFSR: EXTERNAL Position */ +#define SCB_DFSR_EXTERNAL_Msk (1UL << SCB_DFSR_EXTERNAL_Pos) /*!< SCB DFSR: EXTERNAL Mask */ + +#define SCB_DFSR_VCATCH_Pos 3U /*!< SCB DFSR: VCATCH Position */ +#define SCB_DFSR_VCATCH_Msk (1UL << SCB_DFSR_VCATCH_Pos) /*!< SCB DFSR: VCATCH Mask */ + +#define SCB_DFSR_DWTTRAP_Pos 2U /*!< SCB DFSR: DWTTRAP Position */ +#define SCB_DFSR_DWTTRAP_Msk (1UL << SCB_DFSR_DWTTRAP_Pos) /*!< SCB DFSR: DWTTRAP Mask */ + +#define SCB_DFSR_BKPT_Pos 1U /*!< SCB DFSR: BKPT Position */ +#define SCB_DFSR_BKPT_Msk (1UL << SCB_DFSR_BKPT_Pos) /*!< SCB DFSR: BKPT Mask */ + +#define SCB_DFSR_HALTED_Pos 0U /*!< SCB DFSR: HALTED Position */ +#define SCB_DFSR_HALTED_Msk (1UL /*<< SCB_DFSR_HALTED_Pos*/) /*!< SCB DFSR: HALTED Mask */ + +/* SCB Non-Secure Access Control Register Definitions */ +#define SCB_NSACR_CP11_Pos 11U /*!< SCB NSACR: CP11 Position */ +#define SCB_NSACR_CP11_Msk (1UL << SCB_NSACR_CP11_Pos) /*!< SCB NSACR: CP11 Mask */ + +#define SCB_NSACR_CP10_Pos 10U /*!< SCB NSACR: CP10 Position */ +#define SCB_NSACR_CP10_Msk (1UL << SCB_NSACR_CP10_Pos) /*!< SCB NSACR: CP10 Mask */ + +#define SCB_NSACR_CPn_Pos 0U /*!< SCB NSACR: CPn Position */ +#define SCB_NSACR_CPn_Msk (1UL /*<< SCB_NSACR_CPn_Pos*/) /*!< SCB NSACR: CPn Mask */ + +/* SCB Cache Level ID Register Definitions */ +#define SCB_CLIDR_LOUU_Pos 27U /*!< SCB CLIDR: LoUU Position */ +#define SCB_CLIDR_LOUU_Msk (7UL << SCB_CLIDR_LOUU_Pos) /*!< SCB CLIDR: LoUU Mask */ + +#define SCB_CLIDR_LOC_Pos 24U /*!< SCB CLIDR: LoC Position */ +#define SCB_CLIDR_LOC_Msk (7UL << SCB_CLIDR_LOC_Pos) /*!< SCB CLIDR: LoC Mask */ + +/* SCB Cache Type Register Definitions */ +#define SCB_CTR_FORMAT_Pos 29U /*!< SCB CTR: Format Position */ +#define SCB_CTR_FORMAT_Msk (7UL << SCB_CTR_FORMAT_Pos) /*!< SCB CTR: Format Mask */ + +#define SCB_CTR_CWG_Pos 24U /*!< SCB CTR: CWG Position */ +#define SCB_CTR_CWG_Msk (0xFUL << SCB_CTR_CWG_Pos) /*!< SCB CTR: CWG Mask */ + +#define SCB_CTR_ERG_Pos 20U /*!< SCB CTR: ERG Position */ +#define SCB_CTR_ERG_Msk (0xFUL << SCB_CTR_ERG_Pos) /*!< SCB CTR: ERG Mask */ + +#define SCB_CTR_DMINLINE_Pos 16U /*!< SCB CTR: DminLine Position */ +#define SCB_CTR_DMINLINE_Msk (0xFUL << SCB_CTR_DMINLINE_Pos) /*!< SCB CTR: DminLine Mask */ + +#define SCB_CTR_IMINLINE_Pos 0U /*!< SCB CTR: ImInLine Position */ +#define SCB_CTR_IMINLINE_Msk (0xFUL /*<< SCB_CTR_IMINLINE_Pos*/) /*!< SCB CTR: ImInLine Mask */ + +/* SCB Cache Size ID Register Definitions */ +#define SCB_CCSIDR_WT_Pos 31U /*!< SCB CCSIDR: WT Position */ +#define SCB_CCSIDR_WT_Msk (1UL << SCB_CCSIDR_WT_Pos) /*!< SCB CCSIDR: WT Mask */ + +#define SCB_CCSIDR_WB_Pos 30U /*!< SCB CCSIDR: WB Position */ +#define SCB_CCSIDR_WB_Msk (1UL << SCB_CCSIDR_WB_Pos) /*!< SCB CCSIDR: WB Mask */ + +#define SCB_CCSIDR_RA_Pos 29U /*!< SCB CCSIDR: RA Position */ +#define SCB_CCSIDR_RA_Msk (1UL << SCB_CCSIDR_RA_Pos) /*!< SCB CCSIDR: RA Mask */ + +#define SCB_CCSIDR_WA_Pos 28U /*!< SCB CCSIDR: WA Position */ +#define SCB_CCSIDR_WA_Msk (1UL << SCB_CCSIDR_WA_Pos) /*!< SCB CCSIDR: WA Mask */ + +#define SCB_CCSIDR_NUMSETS_Pos 13U /*!< SCB CCSIDR: NumSets Position */ +#define SCB_CCSIDR_NUMSETS_Msk (0x7FFFUL << SCB_CCSIDR_NUMSETS_Pos) /*!< SCB CCSIDR: NumSets Mask */ + +#define SCB_CCSIDR_ASSOCIATIVITY_Pos 3U /*!< SCB CCSIDR: Associativity Position */ +#define SCB_CCSIDR_ASSOCIATIVITY_Msk (0x3FFUL << SCB_CCSIDR_ASSOCIATIVITY_Pos) /*!< SCB CCSIDR: Associativity Mask */ + +#define SCB_CCSIDR_LINESIZE_Pos 0U /*!< SCB CCSIDR: LineSize Position */ +#define SCB_CCSIDR_LINESIZE_Msk (7UL /*<< SCB_CCSIDR_LINESIZE_Pos*/) /*!< SCB CCSIDR: LineSize Mask */ + +/* SCB Cache Size Selection Register Definitions */ +#define SCB_CSSELR_LEVEL_Pos 1U /*!< SCB CSSELR: Level Position */ +#define SCB_CSSELR_LEVEL_Msk (7UL << SCB_CSSELR_LEVEL_Pos) /*!< SCB CSSELR: Level Mask */ + +#define SCB_CSSELR_IND_Pos 0U /*!< SCB CSSELR: InD Position */ +#define SCB_CSSELR_IND_Msk (1UL /*<< SCB_CSSELR_IND_Pos*/) /*!< SCB CSSELR: InD Mask */ + +/* SCB Software Triggered Interrupt Register Definitions */ +#define SCB_STIR_INTID_Pos 0U /*!< SCB STIR: INTID Position */ +#define SCB_STIR_INTID_Msk (0x1FFUL /*<< SCB_STIR_INTID_Pos*/) /*!< SCB STIR: INTID Mask */ + +/* SCB D-Cache Invalidate by Set-way Register Definitions */ +#define SCB_DCISW_WAY_Pos 30U /*!< SCB DCISW: Way Position */ +#define SCB_DCISW_WAY_Msk (3UL << SCB_DCISW_WAY_Pos) /*!< SCB DCISW: Way Mask */ + +#define SCB_DCISW_SET_Pos 5U /*!< SCB DCISW: Set Position */ +#define SCB_DCISW_SET_Msk (0x1FFUL << SCB_DCISW_SET_Pos) /*!< SCB DCISW: Set Mask */ + +/* SCB D-Cache Clean by Set-way Register Definitions */ +#define SCB_DCCSW_WAY_Pos 30U /*!< SCB DCCSW: Way Position */ +#define SCB_DCCSW_WAY_Msk (3UL << SCB_DCCSW_WAY_Pos) /*!< SCB DCCSW: Way Mask */ + +#define SCB_DCCSW_SET_Pos 5U /*!< SCB DCCSW: Set Position */ +#define SCB_DCCSW_SET_Msk (0x1FFUL << SCB_DCCSW_SET_Pos) /*!< SCB DCCSW: Set Mask */ + +/* SCB D-Cache Clean and Invalidate by Set-way Register Definitions */ +#define SCB_DCCISW_WAY_Pos 30U /*!< SCB DCCISW: Way Position */ +#define SCB_DCCISW_WAY_Msk (3UL << SCB_DCCISW_WAY_Pos) /*!< SCB DCCISW: Way Mask */ + +#define SCB_DCCISW_SET_Pos 5U /*!< SCB DCCISW: Set Position */ +#define SCB_DCCISW_SET_Msk (0x1FFUL << SCB_DCCISW_SET_Pos) /*!< SCB DCCISW: Set Mask */ + +/*@} end of group CMSIS_SCB */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SCnSCB System Controls not in SCB (SCnSCB) + \brief Type definitions for the System Control and ID Register not in the SCB + @{ + */ + +/** + \brief Structure type to access the System Control and ID Register not in the SCB. + */ +typedef struct +{ + uint32_t RESERVED0[1U]; + __IM uint32_t ICTR; /*!< Offset: 0x004 (R/ ) Interrupt Controller Type Register */ + __IOM uint32_t ACTLR; /*!< Offset: 0x008 (R/W) Auxiliary Control Register */ + __IOM uint32_t CPPWR; /*!< Offset: 0x00C (R/W) Coprocessor Power Control Register */ +} SCnSCB_Type; + +/* Interrupt Controller Type Register Definitions */ +#define SCnSCB_ICTR_INTLINESNUM_Pos 0U /*!< ICTR: INTLINESNUM Position */ +#define SCnSCB_ICTR_INTLINESNUM_Msk (0xFUL /*<< SCnSCB_ICTR_INTLINESNUM_Pos*/) /*!< ICTR: INTLINESNUM Mask */ + +/*@} end of group CMSIS_SCnotSCB */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SysTick System Tick Timer (SysTick) + \brief Type definitions for the System Timer Registers. + @{ + */ + +/** + \brief Structure type to access the System Timer (SysTick). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */ + __IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */ + __IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */ + __IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */ +} SysTick_Type; + +/* SysTick Control / Status Register Definitions */ +#define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */ +#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */ + +#define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */ +#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */ + +#define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */ +#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */ + +#define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */ +#define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */ + +/* SysTick Reload Register Definitions */ +#define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */ +#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */ + +/* SysTick Current Register Definitions */ +#define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */ +#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */ + +/* SysTick Calibration Register Definitions */ +#define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */ +#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */ + +#define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */ +#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */ + +#define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */ +#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */ + +/*@} end of group CMSIS_SysTick */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_ITM Instrumentation Trace Macrocell (ITM) + \brief Type definitions for the Instrumentation Trace Macrocell (ITM) + @{ + */ + +/** + \brief Structure type to access the Instrumentation Trace Macrocell Register (ITM). + */ +typedef struct +{ + __OM union + { + __OM uint8_t u8; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 8-bit */ + __OM uint16_t u16; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 16-bit */ + __OM uint32_t u32; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 32-bit */ + } PORT [32U]; /*!< Offset: 0x000 ( /W) ITM Stimulus Port Registers */ + uint32_t RESERVED0[864U]; + __IOM uint32_t TER; /*!< Offset: 0xE00 (R/W) ITM Trace Enable Register */ + uint32_t RESERVED1[15U]; + __IOM uint32_t TPR; /*!< Offset: 0xE40 (R/W) ITM Trace Privilege Register */ + uint32_t RESERVED2[15U]; + __IOM uint32_t TCR; /*!< Offset: 0xE80 (R/W) ITM Trace Control Register */ + uint32_t RESERVED3[32U]; + uint32_t RESERVED4[43U]; + __OM uint32_t LAR; /*!< Offset: 0xFB0 ( /W) ITM Lock Access Register */ + __IM uint32_t LSR; /*!< Offset: 0xFB4 (R/ ) ITM Lock Status Register */ + uint32_t RESERVED5[1U]; + __IM uint32_t DEVARCH; /*!< Offset: 0xFBC (R/ ) ITM Device Architecture Register */ + uint32_t RESERVED6[4U]; + __IM uint32_t PID4; /*!< Offset: 0xFD0 (R/ ) ITM Peripheral Identification Register #4 */ + __IM uint32_t PID5; /*!< Offset: 0xFD4 (R/ ) ITM Peripheral Identification Register #5 */ + __IM uint32_t PID6; /*!< Offset: 0xFD8 (R/ ) ITM Peripheral Identification Register #6 */ + __IM uint32_t PID7; /*!< Offset: 0xFDC (R/ ) ITM Peripheral Identification Register #7 */ + __IM uint32_t PID0; /*!< Offset: 0xFE0 (R/ ) ITM Peripheral Identification Register #0 */ + __IM uint32_t PID1; /*!< Offset: 0xFE4 (R/ ) ITM Peripheral Identification Register #1 */ + __IM uint32_t PID2; /*!< Offset: 0xFE8 (R/ ) ITM Peripheral Identification Register #2 */ + __IM uint32_t PID3; /*!< Offset: 0xFEC (R/ ) ITM Peripheral Identification Register #3 */ + __IM uint32_t CID0; /*!< Offset: 0xFF0 (R/ ) ITM Component Identification Register #0 */ + __IM uint32_t CID1; /*!< Offset: 0xFF4 (R/ ) ITM Component Identification Register #1 */ + __IM uint32_t CID2; /*!< Offset: 0xFF8 (R/ ) ITM Component Identification Register #2 */ + __IM uint32_t CID3; /*!< Offset: 0xFFC (R/ ) ITM Component Identification Register #3 */ +} ITM_Type; + +/* ITM Stimulus Port Register Definitions */ +#define ITM_STIM_DISABLED_Pos 1U /*!< ITM STIM: DISABLED Position */ +#define ITM_STIM_DISABLED_Msk (0x1UL << ITM_STIM_DISABLED_Pos) /*!< ITM STIM: DISABLED Mask */ + +#define ITM_STIM_FIFOREADY_Pos 0U /*!< ITM STIM: FIFOREADY Position */ +#define ITM_STIM_FIFOREADY_Msk (0x1UL /*<< ITM_STIM_FIFOREADY_Pos*/) /*!< ITM STIM: FIFOREADY Mask */ + +/* ITM Trace Privilege Register Definitions */ +#define ITM_TPR_PRIVMASK_Pos 0U /*!< ITM TPR: PRIVMASK Position */ +#define ITM_TPR_PRIVMASK_Msk (0xFFFFFFFFUL /*<< ITM_TPR_PRIVMASK_Pos*/) /*!< ITM TPR: PRIVMASK Mask */ + +/* ITM Trace Control Register Definitions */ +#define ITM_TCR_BUSY_Pos 23U /*!< ITM TCR: BUSY Position */ +#define ITM_TCR_BUSY_Msk (1UL << ITM_TCR_BUSY_Pos) /*!< ITM TCR: BUSY Mask */ + +#define ITM_TCR_TRACEBUSID_Pos 16U /*!< ITM TCR: ATBID Position */ +#define ITM_TCR_TRACEBUSID_Msk (0x7FUL << ITM_TCR_TRACEBUSID_Pos) /*!< ITM TCR: ATBID Mask */ + +#define ITM_TCR_GTSFREQ_Pos 10U /*!< ITM TCR: Global timestamp frequency Position */ +#define ITM_TCR_GTSFREQ_Msk (3UL << ITM_TCR_GTSFREQ_Pos) /*!< ITM TCR: Global timestamp frequency Mask */ + +#define ITM_TCR_TSPRESCALE_Pos 8U /*!< ITM TCR: TSPRESCALE Position */ +#define ITM_TCR_TSPRESCALE_Msk (3UL << ITM_TCR_TSPRESCALE_Pos) /*!< ITM TCR: TSPRESCALE Mask */ + +#define ITM_TCR_STALLENA_Pos 5U /*!< ITM TCR: STALLENA Position */ +#define ITM_TCR_STALLENA_Msk (1UL << ITM_TCR_STALLENA_Pos) /*!< ITM TCR: STALLENA Mask */ + +#define ITM_TCR_SWOENA_Pos 4U /*!< ITM TCR: SWOENA Position */ +#define ITM_TCR_SWOENA_Msk (1UL << ITM_TCR_SWOENA_Pos) /*!< ITM TCR: SWOENA Mask */ + +#define ITM_TCR_DWTENA_Pos 3U /*!< ITM TCR: DWTENA Position */ +#define ITM_TCR_DWTENA_Msk (1UL << ITM_TCR_DWTENA_Pos) /*!< ITM TCR: DWTENA Mask */ + +#define ITM_TCR_SYNCENA_Pos 2U /*!< ITM TCR: SYNCENA Position */ +#define ITM_TCR_SYNCENA_Msk (1UL << ITM_TCR_SYNCENA_Pos) /*!< ITM TCR: SYNCENA Mask */ + +#define ITM_TCR_TSENA_Pos 1U /*!< ITM TCR: TSENA Position */ +#define ITM_TCR_TSENA_Msk (1UL << ITM_TCR_TSENA_Pos) /*!< ITM TCR: TSENA Mask */ + +#define ITM_TCR_ITMENA_Pos 0U /*!< ITM TCR: ITM Enable bit Position */ +#define ITM_TCR_ITMENA_Msk (1UL /*<< ITM_TCR_ITMENA_Pos*/) /*!< ITM TCR: ITM Enable bit Mask */ + +/* ITM Lock Status Register Definitions */ +#define ITM_LSR_ByteAcc_Pos 2U /*!< ITM LSR: ByteAcc Position */ +#define ITM_LSR_ByteAcc_Msk (1UL << ITM_LSR_ByteAcc_Pos) /*!< ITM LSR: ByteAcc Mask */ + +#define ITM_LSR_Access_Pos 1U /*!< ITM LSR: Access Position */ +#define ITM_LSR_Access_Msk (1UL << ITM_LSR_Access_Pos) /*!< ITM LSR: Access Mask */ + +#define ITM_LSR_Present_Pos 0U /*!< ITM LSR: Present Position */ +#define ITM_LSR_Present_Msk (1UL /*<< ITM_LSR_Present_Pos*/) /*!< ITM LSR: Present Mask */ + +/*@}*/ /* end of group CMSIS_ITM */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_DWT Data Watchpoint and Trace (DWT) + \brief Type definitions for the Data Watchpoint and Trace (DWT) + @{ + */ + +/** + \brief Structure type to access the Data Watchpoint and Trace Register (DWT). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) Control Register */ + __IOM uint32_t CYCCNT; /*!< Offset: 0x004 (R/W) Cycle Count Register */ + __IOM uint32_t CPICNT; /*!< Offset: 0x008 (R/W) CPI Count Register */ + __IOM uint32_t EXCCNT; /*!< Offset: 0x00C (R/W) Exception Overhead Count Register */ + __IOM uint32_t SLEEPCNT; /*!< Offset: 0x010 (R/W) Sleep Count Register */ + __IOM uint32_t LSUCNT; /*!< Offset: 0x014 (R/W) LSU Count Register */ + __IOM uint32_t FOLDCNT; /*!< Offset: 0x018 (R/W) Folded-instruction Count Register */ + __IM uint32_t PCSR; /*!< Offset: 0x01C (R/ ) Program Counter Sample Register */ + __IOM uint32_t COMP0; /*!< Offset: 0x020 (R/W) Comparator Register 0 */ + uint32_t RESERVED1[1U]; + __IOM uint32_t FUNCTION0; /*!< Offset: 0x028 (R/W) Function Register 0 */ + uint32_t RESERVED2[1U]; + __IOM uint32_t COMP1; /*!< Offset: 0x030 (R/W) Comparator Register 1 */ + uint32_t RESERVED3[1U]; + __IOM uint32_t FUNCTION1; /*!< Offset: 0x038 (R/W) Function Register 1 */ + uint32_t RESERVED4[1U]; + __IOM uint32_t COMP2; /*!< Offset: 0x040 (R/W) Comparator Register 2 */ + uint32_t RESERVED5[1U]; + __IOM uint32_t FUNCTION2; /*!< Offset: 0x048 (R/W) Function Register 2 */ + uint32_t RESERVED6[1U]; + __IOM uint32_t COMP3; /*!< Offset: 0x050 (R/W) Comparator Register 3 */ + uint32_t RESERVED7[1U]; + __IOM uint32_t FUNCTION3; /*!< Offset: 0x058 (R/W) Function Register 3 */ + uint32_t RESERVED8[1U]; + __IOM uint32_t COMP4; /*!< Offset: 0x060 (R/W) Comparator Register 4 */ + uint32_t RESERVED9[1U]; + __IOM uint32_t FUNCTION4; /*!< Offset: 0x068 (R/W) Function Register 4 */ + uint32_t RESERVED10[1U]; + __IOM uint32_t COMP5; /*!< Offset: 0x070 (R/W) Comparator Register 5 */ + uint32_t RESERVED11[1U]; + __IOM uint32_t FUNCTION5; /*!< Offset: 0x078 (R/W) Function Register 5 */ + uint32_t RESERVED12[1U]; + __IOM uint32_t COMP6; /*!< Offset: 0x080 (R/W) Comparator Register 6 */ + uint32_t RESERVED13[1U]; + __IOM uint32_t FUNCTION6; /*!< Offset: 0x088 (R/W) Function Register 6 */ + uint32_t RESERVED14[1U]; + __IOM uint32_t COMP7; /*!< Offset: 0x090 (R/W) Comparator Register 7 */ + uint32_t RESERVED15[1U]; + __IOM uint32_t FUNCTION7; /*!< Offset: 0x098 (R/W) Function Register 7 */ + uint32_t RESERVED16[1U]; + __IOM uint32_t COMP8; /*!< Offset: 0x0A0 (R/W) Comparator Register 8 */ + uint32_t RESERVED17[1U]; + __IOM uint32_t FUNCTION8; /*!< Offset: 0x0A8 (R/W) Function Register 8 */ + uint32_t RESERVED18[1U]; + __IOM uint32_t COMP9; /*!< Offset: 0x0B0 (R/W) Comparator Register 9 */ + uint32_t RESERVED19[1U]; + __IOM uint32_t FUNCTION9; /*!< Offset: 0x0B8 (R/W) Function Register 9 */ + uint32_t RESERVED20[1U]; + __IOM uint32_t COMP10; /*!< Offset: 0x0C0 (R/W) Comparator Register 10 */ + uint32_t RESERVED21[1U]; + __IOM uint32_t FUNCTION10; /*!< Offset: 0x0C8 (R/W) Function Register 10 */ + uint32_t RESERVED22[1U]; + __IOM uint32_t COMP11; /*!< Offset: 0x0D0 (R/W) Comparator Register 11 */ + uint32_t RESERVED23[1U]; + __IOM uint32_t FUNCTION11; /*!< Offset: 0x0D8 (R/W) Function Register 11 */ + uint32_t RESERVED24[1U]; + __IOM uint32_t COMP12; /*!< Offset: 0x0E0 (R/W) Comparator Register 12 */ + uint32_t RESERVED25[1U]; + __IOM uint32_t FUNCTION12; /*!< Offset: 0x0E8 (R/W) Function Register 12 */ + uint32_t RESERVED26[1U]; + __IOM uint32_t COMP13; /*!< Offset: 0x0F0 (R/W) Comparator Register 13 */ + uint32_t RESERVED27[1U]; + __IOM uint32_t FUNCTION13; /*!< Offset: 0x0F8 (R/W) Function Register 13 */ + uint32_t RESERVED28[1U]; + __IOM uint32_t COMP14; /*!< Offset: 0x100 (R/W) Comparator Register 14 */ + uint32_t RESERVED29[1U]; + __IOM uint32_t FUNCTION14; /*!< Offset: 0x108 (R/W) Function Register 14 */ + uint32_t RESERVED30[1U]; + __IOM uint32_t COMP15; /*!< Offset: 0x110 (R/W) Comparator Register 15 */ + uint32_t RESERVED31[1U]; + __IOM uint32_t FUNCTION15; /*!< Offset: 0x118 (R/W) Function Register 15 */ + uint32_t RESERVED32[934U]; + __IM uint32_t LSR; /*!< Offset: 0xFB4 (R ) Lock Status Register */ + uint32_t RESERVED33[1U]; + __IM uint32_t DEVARCH; /*!< Offset: 0xFBC (R/ ) Device Architecture Register */ +} DWT_Type; + +/* DWT Control Register Definitions */ +#define DWT_CTRL_NUMCOMP_Pos 28U /*!< DWT CTRL: NUMCOMP Position */ +#define DWT_CTRL_NUMCOMP_Msk (0xFUL << DWT_CTRL_NUMCOMP_Pos) /*!< DWT CTRL: NUMCOMP Mask */ + +#define DWT_CTRL_NOTRCPKT_Pos 27U /*!< DWT CTRL: NOTRCPKT Position */ +#define DWT_CTRL_NOTRCPKT_Msk (0x1UL << DWT_CTRL_NOTRCPKT_Pos) /*!< DWT CTRL: NOTRCPKT Mask */ + +#define DWT_CTRL_NOEXTTRIG_Pos 26U /*!< DWT CTRL: NOEXTTRIG Position */ +#define DWT_CTRL_NOEXTTRIG_Msk (0x1UL << DWT_CTRL_NOEXTTRIG_Pos) /*!< DWT CTRL: NOEXTTRIG Mask */ + +#define DWT_CTRL_NOCYCCNT_Pos 25U /*!< DWT CTRL: NOCYCCNT Position */ +#define DWT_CTRL_NOCYCCNT_Msk (0x1UL << DWT_CTRL_NOCYCCNT_Pos) /*!< DWT CTRL: NOCYCCNT Mask */ + +#define DWT_CTRL_NOPRFCNT_Pos 24U /*!< DWT CTRL: NOPRFCNT Position */ +#define DWT_CTRL_NOPRFCNT_Msk (0x1UL << DWT_CTRL_NOPRFCNT_Pos) /*!< DWT CTRL: NOPRFCNT Mask */ + +#define DWT_CTRL_CYCDISS_Pos 23U /*!< DWT CTRL: CYCDISS Position */ +#define DWT_CTRL_CYCDISS_Msk (0x1UL << DWT_CTRL_CYCDISS_Pos) /*!< DWT CTRL: CYCDISS Mask */ + +#define DWT_CTRL_CYCEVTENA_Pos 22U /*!< DWT CTRL: CYCEVTENA Position */ +#define DWT_CTRL_CYCEVTENA_Msk (0x1UL << DWT_CTRL_CYCEVTENA_Pos) /*!< DWT CTRL: CYCEVTENA Mask */ + +#define DWT_CTRL_FOLDEVTENA_Pos 21U /*!< DWT CTRL: FOLDEVTENA Position */ +#define DWT_CTRL_FOLDEVTENA_Msk (0x1UL << DWT_CTRL_FOLDEVTENA_Pos) /*!< DWT CTRL: FOLDEVTENA Mask */ + +#define DWT_CTRL_LSUEVTENA_Pos 20U /*!< DWT CTRL: LSUEVTENA Position */ +#define DWT_CTRL_LSUEVTENA_Msk (0x1UL << DWT_CTRL_LSUEVTENA_Pos) /*!< DWT CTRL: LSUEVTENA Mask */ + +#define DWT_CTRL_SLEEPEVTENA_Pos 19U /*!< DWT CTRL: SLEEPEVTENA Position */ +#define DWT_CTRL_SLEEPEVTENA_Msk (0x1UL << DWT_CTRL_SLEEPEVTENA_Pos) /*!< DWT CTRL: SLEEPEVTENA Mask */ + +#define DWT_CTRL_EXCEVTENA_Pos 18U /*!< DWT CTRL: EXCEVTENA Position */ +#define DWT_CTRL_EXCEVTENA_Msk (0x1UL << DWT_CTRL_EXCEVTENA_Pos) /*!< DWT CTRL: EXCEVTENA Mask */ + +#define DWT_CTRL_CPIEVTENA_Pos 17U /*!< DWT CTRL: CPIEVTENA Position */ +#define DWT_CTRL_CPIEVTENA_Msk (0x1UL << DWT_CTRL_CPIEVTENA_Pos) /*!< DWT CTRL: CPIEVTENA Mask */ + +#define DWT_CTRL_EXCTRCENA_Pos 16U /*!< DWT CTRL: EXCTRCENA Position */ +#define DWT_CTRL_EXCTRCENA_Msk (0x1UL << DWT_CTRL_EXCTRCENA_Pos) /*!< DWT CTRL: EXCTRCENA Mask */ + +#define DWT_CTRL_PCSAMPLENA_Pos 12U /*!< DWT CTRL: PCSAMPLENA Position */ +#define DWT_CTRL_PCSAMPLENA_Msk (0x1UL << DWT_CTRL_PCSAMPLENA_Pos) /*!< DWT CTRL: PCSAMPLENA Mask */ + +#define DWT_CTRL_SYNCTAP_Pos 10U /*!< DWT CTRL: SYNCTAP Position */ +#define DWT_CTRL_SYNCTAP_Msk (0x3UL << DWT_CTRL_SYNCTAP_Pos) /*!< DWT CTRL: SYNCTAP Mask */ + +#define DWT_CTRL_CYCTAP_Pos 9U /*!< DWT CTRL: CYCTAP Position */ +#define DWT_CTRL_CYCTAP_Msk (0x1UL << DWT_CTRL_CYCTAP_Pos) /*!< DWT CTRL: CYCTAP Mask */ + +#define DWT_CTRL_POSTINIT_Pos 5U /*!< DWT CTRL: POSTINIT Position */ +#define DWT_CTRL_POSTINIT_Msk (0xFUL << DWT_CTRL_POSTINIT_Pos) /*!< DWT CTRL: POSTINIT Mask */ + +#define DWT_CTRL_POSTPRESET_Pos 1U /*!< DWT CTRL: POSTPRESET Position */ +#define DWT_CTRL_POSTPRESET_Msk (0xFUL << DWT_CTRL_POSTPRESET_Pos) /*!< DWT CTRL: POSTPRESET Mask */ + +#define DWT_CTRL_CYCCNTENA_Pos 0U /*!< DWT CTRL: CYCCNTENA Position */ +#define DWT_CTRL_CYCCNTENA_Msk (0x1UL /*<< DWT_CTRL_CYCCNTENA_Pos*/) /*!< DWT CTRL: CYCCNTENA Mask */ + +/* DWT CPI Count Register Definitions */ +#define DWT_CPICNT_CPICNT_Pos 0U /*!< DWT CPICNT: CPICNT Position */ +#define DWT_CPICNT_CPICNT_Msk (0xFFUL /*<< DWT_CPICNT_CPICNT_Pos*/) /*!< DWT CPICNT: CPICNT Mask */ + +/* DWT Exception Overhead Count Register Definitions */ +#define DWT_EXCCNT_EXCCNT_Pos 0U /*!< DWT EXCCNT: EXCCNT Position */ +#define DWT_EXCCNT_EXCCNT_Msk (0xFFUL /*<< DWT_EXCCNT_EXCCNT_Pos*/) /*!< DWT EXCCNT: EXCCNT Mask */ + +/* DWT Sleep Count Register Definitions */ +#define DWT_SLEEPCNT_SLEEPCNT_Pos 0U /*!< DWT SLEEPCNT: SLEEPCNT Position */ +#define DWT_SLEEPCNT_SLEEPCNT_Msk (0xFFUL /*<< DWT_SLEEPCNT_SLEEPCNT_Pos*/) /*!< DWT SLEEPCNT: SLEEPCNT Mask */ + +/* DWT LSU Count Register Definitions */ +#define DWT_LSUCNT_LSUCNT_Pos 0U /*!< DWT LSUCNT: LSUCNT Position */ +#define DWT_LSUCNT_LSUCNT_Msk (0xFFUL /*<< DWT_LSUCNT_LSUCNT_Pos*/) /*!< DWT LSUCNT: LSUCNT Mask */ + +/* DWT Folded-instruction Count Register Definitions */ +#define DWT_FOLDCNT_FOLDCNT_Pos 0U /*!< DWT FOLDCNT: FOLDCNT Position */ +#define DWT_FOLDCNT_FOLDCNT_Msk (0xFFUL /*<< DWT_FOLDCNT_FOLDCNT_Pos*/) /*!< DWT FOLDCNT: FOLDCNT Mask */ + +/* DWT Comparator Function Register Definitions */ +#define DWT_FUNCTION_ID_Pos 27U /*!< DWT FUNCTION: ID Position */ +#define DWT_FUNCTION_ID_Msk (0x1FUL << DWT_FUNCTION_ID_Pos) /*!< DWT FUNCTION: ID Mask */ + +#define DWT_FUNCTION_MATCHED_Pos 24U /*!< DWT FUNCTION: MATCHED Position */ +#define DWT_FUNCTION_MATCHED_Msk (0x1UL << DWT_FUNCTION_MATCHED_Pos) /*!< DWT FUNCTION: MATCHED Mask */ + +#define DWT_FUNCTION_DATAVSIZE_Pos 10U /*!< DWT FUNCTION: DATAVSIZE Position */ +#define DWT_FUNCTION_DATAVSIZE_Msk (0x3UL << DWT_FUNCTION_DATAVSIZE_Pos) /*!< DWT FUNCTION: DATAVSIZE Mask */ + +#define DWT_FUNCTION_ACTION_Pos 4U /*!< DWT FUNCTION: ACTION Position */ +#define DWT_FUNCTION_ACTION_Msk (0x1UL << DWT_FUNCTION_ACTION_Pos) /*!< DWT FUNCTION: ACTION Mask */ + +#define DWT_FUNCTION_MATCH_Pos 0U /*!< DWT FUNCTION: MATCH Position */ +#define DWT_FUNCTION_MATCH_Msk (0xFUL /*<< DWT_FUNCTION_MATCH_Pos*/) /*!< DWT FUNCTION: MATCH Mask */ + +/*@}*/ /* end of group CMSIS_DWT */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_TPI Trace Port Interface (TPI) + \brief Type definitions for the Trace Port Interface (TPI) + @{ + */ + +/** + \brief Structure type to access the Trace Port Interface Register (TPI). + */ +typedef struct +{ + __IM uint32_t SSPSR; /*!< Offset: 0x000 (R/ ) Supported Parallel Port Size Register */ + __IOM uint32_t CSPSR; /*!< Offset: 0x004 (R/W) Current Parallel Port Size Register */ + uint32_t RESERVED0[2U]; + __IOM uint32_t ACPR; /*!< Offset: 0x010 (R/W) Asynchronous Clock Prescaler Register */ + uint32_t RESERVED1[55U]; + __IOM uint32_t SPPR; /*!< Offset: 0x0F0 (R/W) Selected Pin Protocol Register */ + uint32_t RESERVED2[131U]; + __IM uint32_t FFSR; /*!< Offset: 0x300 (R/ ) Formatter and Flush Status Register */ + __IOM uint32_t FFCR; /*!< Offset: 0x304 (R/W) Formatter and Flush Control Register */ + __IOM uint32_t PSCR; /*!< Offset: 0x308 (R/W) Periodic Synchronization Control Register */ + uint32_t RESERVED3[759U]; + __IM uint32_t TRIGGER; /*!< Offset: 0xEE8 (R/ ) TRIGGER Register */ + __IM uint32_t ITFTTD0; /*!< Offset: 0xEEC (R/ ) Integration Test FIFO Test Data 0 Register */ + __IOM uint32_t ITATBCTR2; /*!< Offset: 0xEF0 (R/W) Integration Test ATB Control Register 2 */ + uint32_t RESERVED4[1U]; + __IM uint32_t ITATBCTR0; /*!< Offset: 0xEF8 (R/ ) Integration Test ATB Control Register 0 */ + __IM uint32_t ITFTTD1; /*!< Offset: 0xEFC (R/ ) Integration Test FIFO Test Data 1 Register */ + __IOM uint32_t ITCTRL; /*!< Offset: 0xF00 (R/W) Integration Mode Control */ + uint32_t RESERVED5[39U]; + __IOM uint32_t CLAIMSET; /*!< Offset: 0xFA0 (R/W) Claim tag set */ + __IOM uint32_t CLAIMCLR; /*!< Offset: 0xFA4 (R/W) Claim tag clear */ + uint32_t RESERVED7[8U]; + __IM uint32_t DEVID; /*!< Offset: 0xFC8 (R/ ) Device Configuration Register */ + __IM uint32_t DEVTYPE; /*!< Offset: 0xFCC (R/ ) Device Type Identifier Register */ +} TPI_Type; + +/* TPI Asynchronous Clock Prescaler Register Definitions */ +#define TPI_ACPR_PRESCALER_Pos 0U /*!< TPI ACPR: PRESCALER Position */ +#define TPI_ACPR_PRESCALER_Msk (0x1FFFUL /*<< TPI_ACPR_PRESCALER_Pos*/) /*!< TPI ACPR: PRESCALER Mask */ + +/* TPI Selected Pin Protocol Register Definitions */ +#define TPI_SPPR_TXMODE_Pos 0U /*!< TPI SPPR: TXMODE Position */ +#define TPI_SPPR_TXMODE_Msk (0x3UL /*<< TPI_SPPR_TXMODE_Pos*/) /*!< TPI SPPR: TXMODE Mask */ + +/* TPI Formatter and Flush Status Register Definitions */ +#define TPI_FFSR_FtNonStop_Pos 3U /*!< TPI FFSR: FtNonStop Position */ +#define TPI_FFSR_FtNonStop_Msk (0x1UL << TPI_FFSR_FtNonStop_Pos) /*!< TPI FFSR: FtNonStop Mask */ + +#define TPI_FFSR_TCPresent_Pos 2U /*!< TPI FFSR: TCPresent Position */ +#define TPI_FFSR_TCPresent_Msk (0x1UL << TPI_FFSR_TCPresent_Pos) /*!< TPI FFSR: TCPresent Mask */ + +#define TPI_FFSR_FtStopped_Pos 1U /*!< TPI FFSR: FtStopped Position */ +#define TPI_FFSR_FtStopped_Msk (0x1UL << TPI_FFSR_FtStopped_Pos) /*!< TPI FFSR: FtStopped Mask */ + +#define TPI_FFSR_FlInProg_Pos 0U /*!< TPI FFSR: FlInProg Position */ +#define TPI_FFSR_FlInProg_Msk (0x1UL /*<< TPI_FFSR_FlInProg_Pos*/) /*!< TPI FFSR: FlInProg Mask */ + +/* TPI Formatter and Flush Control Register Definitions */ +#define TPI_FFCR_TrigIn_Pos 8U /*!< TPI FFCR: TrigIn Position */ +#define TPI_FFCR_TrigIn_Msk (0x1UL << TPI_FFCR_TrigIn_Pos) /*!< TPI FFCR: TrigIn Mask */ + +#define TPI_FFCR_FOnMan_Pos 6U /*!< TPI FFCR: FOnMan Position */ +#define TPI_FFCR_FOnMan_Msk (0x1UL << TPI_FFCR_FOnMan_Pos) /*!< TPI FFCR: FOnMan Mask */ + +#define TPI_FFCR_EnFCont_Pos 1U /*!< TPI FFCR: EnFCont Position */ +#define TPI_FFCR_EnFCont_Msk (0x1UL << TPI_FFCR_EnFCont_Pos) /*!< TPI FFCR: EnFCont Mask */ + +/* TPI TRIGGER Register Definitions */ +#define TPI_TRIGGER_TRIGGER_Pos 0U /*!< TPI TRIGGER: TRIGGER Position */ +#define TPI_TRIGGER_TRIGGER_Msk (0x1UL /*<< TPI_TRIGGER_TRIGGER_Pos*/) /*!< TPI TRIGGER: TRIGGER Mask */ + +/* TPI Integration Test FIFO Test Data 0 Register Definitions */ +#define TPI_ITFTTD0_ATB_IF2_ATVALID_Pos 29U /*!< TPI ITFTTD0: ATB Interface 2 ATVALIDPosition */ +#define TPI_ITFTTD0_ATB_IF2_ATVALID_Msk (0x3UL << TPI_ITFTTD0_ATB_IF2_ATVALID_Pos) /*!< TPI ITFTTD0: ATB Interface 2 ATVALID Mask */ + +#define TPI_ITFTTD0_ATB_IF2_bytecount_Pos 27U /*!< TPI ITFTTD0: ATB Interface 2 byte count Position */ +#define TPI_ITFTTD0_ATB_IF2_bytecount_Msk (0x3UL << TPI_ITFTTD0_ATB_IF2_bytecount_Pos) /*!< TPI ITFTTD0: ATB Interface 2 byte count Mask */ + +#define TPI_ITFTTD0_ATB_IF1_ATVALID_Pos 26U /*!< TPI ITFTTD0: ATB Interface 1 ATVALID Position */ +#define TPI_ITFTTD0_ATB_IF1_ATVALID_Msk (0x3UL << TPI_ITFTTD0_ATB_IF1_ATVALID_Pos) /*!< TPI ITFTTD0: ATB Interface 1 ATVALID Mask */ + +#define TPI_ITFTTD0_ATB_IF1_bytecount_Pos 24U /*!< TPI ITFTTD0: ATB Interface 1 byte count Position */ +#define TPI_ITFTTD0_ATB_IF1_bytecount_Msk (0x3UL << TPI_ITFTTD0_ATB_IF1_bytecount_Pos) /*!< TPI ITFTTD0: ATB Interface 1 byte countt Mask */ + +#define TPI_ITFTTD0_ATB_IF1_data2_Pos 16U /*!< TPI ITFTTD0: ATB Interface 1 data2 Position */ +#define TPI_ITFTTD0_ATB_IF1_data2_Msk (0xFFUL << TPI_ITFTTD0_ATB_IF1_data1_Pos) /*!< TPI ITFTTD0: ATB Interface 1 data2 Mask */ + +#define TPI_ITFTTD0_ATB_IF1_data1_Pos 8U /*!< TPI ITFTTD0: ATB Interface 1 data1 Position */ +#define TPI_ITFTTD0_ATB_IF1_data1_Msk (0xFFUL << TPI_ITFTTD0_ATB_IF1_data1_Pos) /*!< TPI ITFTTD0: ATB Interface 1 data1 Mask */ + +#define TPI_ITFTTD0_ATB_IF1_data0_Pos 0U /*!< TPI ITFTTD0: ATB Interface 1 data0 Position */ +#define TPI_ITFTTD0_ATB_IF1_data0_Msk (0xFFUL /*<< TPI_ITFTTD0_ATB_IF1_data0_Pos*/) /*!< TPI ITFTTD0: ATB Interface 1 data0 Mask */ + +/* TPI Integration Test ATB Control Register 2 Register Definitions */ +#define TPI_ITATBCTR2_AFVALID2S_Pos 1U /*!< TPI ITATBCTR2: AFVALID2S Position */ +#define TPI_ITATBCTR2_AFVALID2S_Msk (0x1UL << TPI_ITATBCTR2_AFVALID2S_Pos) /*!< TPI ITATBCTR2: AFVALID2SS Mask */ + +#define TPI_ITATBCTR2_AFVALID1S_Pos 1U /*!< TPI ITATBCTR2: AFVALID1S Position */ +#define TPI_ITATBCTR2_AFVALID1S_Msk (0x1UL << TPI_ITATBCTR2_AFVALID1S_Pos) /*!< TPI ITATBCTR2: AFVALID1SS Mask */ + +#define TPI_ITATBCTR2_ATREADY2S_Pos 0U /*!< TPI ITATBCTR2: ATREADY2S Position */ +#define TPI_ITATBCTR2_ATREADY2S_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY2S_Pos*/) /*!< TPI ITATBCTR2: ATREADY2S Mask */ + +#define TPI_ITATBCTR2_ATREADY1S_Pos 0U /*!< TPI ITATBCTR2: ATREADY1S Position */ +#define TPI_ITATBCTR2_ATREADY1S_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY1S_Pos*/) /*!< TPI ITATBCTR2: ATREADY1S Mask */ + +/* TPI Integration Test FIFO Test Data 1 Register Definitions */ +#define TPI_ITFTTD1_ATB_IF2_ATVALID_Pos 29U /*!< TPI ITFTTD1: ATB Interface 2 ATVALID Position */ +#define TPI_ITFTTD1_ATB_IF2_ATVALID_Msk (0x3UL << TPI_ITFTTD1_ATB_IF2_ATVALID_Pos) /*!< TPI ITFTTD1: ATB Interface 2 ATVALID Mask */ + +#define TPI_ITFTTD1_ATB_IF2_bytecount_Pos 27U /*!< TPI ITFTTD1: ATB Interface 2 byte count Position */ +#define TPI_ITFTTD1_ATB_IF2_bytecount_Msk (0x3UL << TPI_ITFTTD1_ATB_IF2_bytecount_Pos) /*!< TPI ITFTTD1: ATB Interface 2 byte count Mask */ + +#define TPI_ITFTTD1_ATB_IF1_ATVALID_Pos 26U /*!< TPI ITFTTD1: ATB Interface 1 ATVALID Position */ +#define TPI_ITFTTD1_ATB_IF1_ATVALID_Msk (0x3UL << TPI_ITFTTD1_ATB_IF1_ATVALID_Pos) /*!< TPI ITFTTD1: ATB Interface 1 ATVALID Mask */ + +#define TPI_ITFTTD1_ATB_IF1_bytecount_Pos 24U /*!< TPI ITFTTD1: ATB Interface 1 byte count Position */ +#define TPI_ITFTTD1_ATB_IF1_bytecount_Msk (0x3UL << TPI_ITFTTD1_ATB_IF1_bytecount_Pos) /*!< TPI ITFTTD1: ATB Interface 1 byte countt Mask */ + +#define TPI_ITFTTD1_ATB_IF2_data2_Pos 16U /*!< TPI ITFTTD1: ATB Interface 2 data2 Position */ +#define TPI_ITFTTD1_ATB_IF2_data2_Msk (0xFFUL << TPI_ITFTTD1_ATB_IF2_data1_Pos) /*!< TPI ITFTTD1: ATB Interface 2 data2 Mask */ + +#define TPI_ITFTTD1_ATB_IF2_data1_Pos 8U /*!< TPI ITFTTD1: ATB Interface 2 data1 Position */ +#define TPI_ITFTTD1_ATB_IF2_data1_Msk (0xFFUL << TPI_ITFTTD1_ATB_IF2_data1_Pos) /*!< TPI ITFTTD1: ATB Interface 2 data1 Mask */ + +#define TPI_ITFTTD1_ATB_IF2_data0_Pos 0U /*!< TPI ITFTTD1: ATB Interface 2 data0 Position */ +#define TPI_ITFTTD1_ATB_IF2_data0_Msk (0xFFUL /*<< TPI_ITFTTD1_ATB_IF2_data0_Pos*/) /*!< TPI ITFTTD1: ATB Interface 2 data0 Mask */ + +/* TPI Integration Test ATB Control Register 0 Definitions */ +#define TPI_ITATBCTR0_AFVALID2S_Pos 1U /*!< TPI ITATBCTR0: AFVALID2S Position */ +#define TPI_ITATBCTR0_AFVALID2S_Msk (0x1UL << TPI_ITATBCTR0_AFVALID2S_Pos) /*!< TPI ITATBCTR0: AFVALID2SS Mask */ + +#define TPI_ITATBCTR0_AFVALID1S_Pos 1U /*!< TPI ITATBCTR0: AFVALID1S Position */ +#define TPI_ITATBCTR0_AFVALID1S_Msk (0x1UL << TPI_ITATBCTR0_AFVALID1S_Pos) /*!< TPI ITATBCTR0: AFVALID1SS Mask */ + +#define TPI_ITATBCTR0_ATREADY2S_Pos 0U /*!< TPI ITATBCTR0: ATREADY2S Position */ +#define TPI_ITATBCTR0_ATREADY2S_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY2S_Pos*/) /*!< TPI ITATBCTR0: ATREADY2S Mask */ + +#define TPI_ITATBCTR0_ATREADY1S_Pos 0U /*!< TPI ITATBCTR0: ATREADY1S Position */ +#define TPI_ITATBCTR0_ATREADY1S_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY1S_Pos*/) /*!< TPI ITATBCTR0: ATREADY1S Mask */ + +/* TPI Integration Mode Control Register Definitions */ +#define TPI_ITCTRL_Mode_Pos 0U /*!< TPI ITCTRL: Mode Position */ +#define TPI_ITCTRL_Mode_Msk (0x3UL /*<< TPI_ITCTRL_Mode_Pos*/) /*!< TPI ITCTRL: Mode Mask */ + +/* TPI DEVID Register Definitions */ +#define TPI_DEVID_NRZVALID_Pos 11U /*!< TPI DEVID: NRZVALID Position */ +#define TPI_DEVID_NRZVALID_Msk (0x1UL << TPI_DEVID_NRZVALID_Pos) /*!< TPI DEVID: NRZVALID Mask */ + +#define TPI_DEVID_MANCVALID_Pos 10U /*!< TPI DEVID: MANCVALID Position */ +#define TPI_DEVID_MANCVALID_Msk (0x1UL << TPI_DEVID_MANCVALID_Pos) /*!< TPI DEVID: MANCVALID Mask */ + +#define TPI_DEVID_PTINVALID_Pos 9U /*!< TPI DEVID: PTINVALID Position */ +#define TPI_DEVID_PTINVALID_Msk (0x1UL << TPI_DEVID_PTINVALID_Pos) /*!< TPI DEVID: PTINVALID Mask */ + +#define TPI_DEVID_FIFOSZ_Pos 6U /*!< TPI DEVID: FIFOSZ Position */ +#define TPI_DEVID_FIFOSZ_Msk (0x7UL << TPI_DEVID_FIFOSZ_Pos) /*!< TPI DEVID: FIFOSZ Mask */ + +#define TPI_DEVID_NrTraceInput_Pos 0U /*!< TPI DEVID: NrTraceInput Position */ +#define TPI_DEVID_NrTraceInput_Msk (0x3FUL /*<< TPI_DEVID_NrTraceInput_Pos*/) /*!< TPI DEVID: NrTraceInput Mask */ + +/* TPI DEVTYPE Register Definitions */ +#define TPI_DEVTYPE_SubType_Pos 4U /*!< TPI DEVTYPE: SubType Position */ +#define TPI_DEVTYPE_SubType_Msk (0xFUL /*<< TPI_DEVTYPE_SubType_Pos*/) /*!< TPI DEVTYPE: SubType Mask */ + +#define TPI_DEVTYPE_MajorType_Pos 0U /*!< TPI DEVTYPE: MajorType Position */ +#define TPI_DEVTYPE_MajorType_Msk (0xFUL << TPI_DEVTYPE_MajorType_Pos) /*!< TPI DEVTYPE: MajorType Mask */ + +/*@}*/ /* end of group CMSIS_TPI */ + + +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_MPU Memory Protection Unit (MPU) + \brief Type definitions for the Memory Protection Unit (MPU) + @{ + */ + +/** + \brief Structure type to access the Memory Protection Unit (MPU). + */ +typedef struct +{ + __IM uint32_t TYPE; /*!< Offset: 0x000 (R/ ) MPU Type Register */ + __IOM uint32_t CTRL; /*!< Offset: 0x004 (R/W) MPU Control Register */ + __IOM uint32_t RNR; /*!< Offset: 0x008 (R/W) MPU Region Number Register */ + __IOM uint32_t RBAR; /*!< Offset: 0x00C (R/W) MPU Region Base Address Register */ + __IOM uint32_t RLAR; /*!< Offset: 0x010 (R/W) MPU Region Limit Address Register */ + __IOM uint32_t RBAR_A1; /*!< Offset: 0x014 (R/W) MPU Region Base Address Register Alias 1 */ + __IOM uint32_t RLAR_A1; /*!< Offset: 0x018 (R/W) MPU Region Limit Address Register Alias 1 */ + __IOM uint32_t RBAR_A2; /*!< Offset: 0x01C (R/W) MPU Region Base Address Register Alias 2 */ + __IOM uint32_t RLAR_A2; /*!< Offset: 0x020 (R/W) MPU Region Limit Address Register Alias 2 */ + __IOM uint32_t RBAR_A3; /*!< Offset: 0x024 (R/W) MPU Region Base Address Register Alias 3 */ + __IOM uint32_t RLAR_A3; /*!< Offset: 0x028 (R/W) MPU Region Limit Address Register Alias 3 */ + uint32_t RESERVED0[1]; + union { + __IOM uint32_t MAIR[2]; + struct { + __IOM uint32_t MAIR0; /*!< Offset: 0x030 (R/W) MPU Memory Attribute Indirection Register 0 */ + __IOM uint32_t MAIR1; /*!< Offset: 0x034 (R/W) MPU Memory Attribute Indirection Register 1 */ + }; + }; +} MPU_Type; + +#define MPU_TYPE_RALIASES 4U + +/* MPU Type Register Definitions */ +#define MPU_TYPE_IREGION_Pos 16U /*!< MPU TYPE: IREGION Position */ +#define MPU_TYPE_IREGION_Msk (0xFFUL << MPU_TYPE_IREGION_Pos) /*!< MPU TYPE: IREGION Mask */ + +#define MPU_TYPE_DREGION_Pos 8U /*!< MPU TYPE: DREGION Position */ +#define MPU_TYPE_DREGION_Msk (0xFFUL << MPU_TYPE_DREGION_Pos) /*!< MPU TYPE: DREGION Mask */ + +#define MPU_TYPE_SEPARATE_Pos 0U /*!< MPU TYPE: SEPARATE Position */ +#define MPU_TYPE_SEPARATE_Msk (1UL /*<< MPU_TYPE_SEPARATE_Pos*/) /*!< MPU TYPE: SEPARATE Mask */ + +/* MPU Control Register Definitions */ +#define MPU_CTRL_PRIVDEFENA_Pos 2U /*!< MPU CTRL: PRIVDEFENA Position */ +#define MPU_CTRL_PRIVDEFENA_Msk (1UL << MPU_CTRL_PRIVDEFENA_Pos) /*!< MPU CTRL: PRIVDEFENA Mask */ + +#define MPU_CTRL_HFNMIENA_Pos 1U /*!< MPU CTRL: HFNMIENA Position */ +#define MPU_CTRL_HFNMIENA_Msk (1UL << MPU_CTRL_HFNMIENA_Pos) /*!< MPU CTRL: HFNMIENA Mask */ + +#define MPU_CTRL_ENABLE_Pos 0U /*!< MPU CTRL: ENABLE Position */ +#define MPU_CTRL_ENABLE_Msk (1UL /*<< MPU_CTRL_ENABLE_Pos*/) /*!< MPU CTRL: ENABLE Mask */ + +/* MPU Region Number Register Definitions */ +#define MPU_RNR_REGION_Pos 0U /*!< MPU RNR: REGION Position */ +#define MPU_RNR_REGION_Msk (0xFFUL /*<< MPU_RNR_REGION_Pos*/) /*!< MPU RNR: REGION Mask */ + +/* MPU Region Base Address Register Definitions */ +#define MPU_RBAR_BASE_Pos 5U /*!< MPU RBAR: BASE Position */ +#define MPU_RBAR_BASE_Msk (0x7FFFFFFUL << MPU_RBAR_BASE_Pos) /*!< MPU RBAR: BASE Mask */ + +#define MPU_RBAR_SH_Pos 3U /*!< MPU RBAR: SH Position */ +#define MPU_RBAR_SH_Msk (0x3UL << MPU_RBAR_SH_Pos) /*!< MPU RBAR: SH Mask */ + +#define MPU_RBAR_AP_Pos 1U /*!< MPU RBAR: AP Position */ +#define MPU_RBAR_AP_Msk (0x3UL << MPU_RBAR_AP_Pos) /*!< MPU RBAR: AP Mask */ + +#define MPU_RBAR_XN_Pos 0U /*!< MPU RBAR: XN Position */ +#define MPU_RBAR_XN_Msk (01UL /*<< MPU_RBAR_XN_Pos*/) /*!< MPU RBAR: XN Mask */ + +/* MPU Region Limit Address Register Definitions */ +#define MPU_RLAR_LIMIT_Pos 5U /*!< MPU RLAR: LIMIT Position */ +#define MPU_RLAR_LIMIT_Msk (0x7FFFFFFUL << MPU_RLAR_LIMIT_Pos) /*!< MPU RLAR: LIMIT Mask */ + +#define MPU_RLAR_AttrIndx_Pos 1U /*!< MPU RLAR: AttrIndx Position */ +#define MPU_RLAR_AttrIndx_Msk (0x7UL << MPU_RLAR_AttrIndx_Pos) /*!< MPU RLAR: AttrIndx Mask */ + +#define MPU_RLAR_EN_Pos 0U /*!< MPU RLAR: Region enable bit Position */ +#define MPU_RLAR_EN_Msk (1UL /*<< MPU_RLAR_EN_Pos*/) /*!< MPU RLAR: Region enable bit Disable Mask */ + +/* MPU Memory Attribute Indirection Register 0 Definitions */ +#define MPU_MAIR0_Attr3_Pos 24U /*!< MPU MAIR0: Attr3 Position */ +#define MPU_MAIR0_Attr3_Msk (0xFFUL << MPU_MAIR0_Attr3_Pos) /*!< MPU MAIR0: Attr3 Mask */ + +#define MPU_MAIR0_Attr2_Pos 16U /*!< MPU MAIR0: Attr2 Position */ +#define MPU_MAIR0_Attr2_Msk (0xFFUL << MPU_MAIR0_Attr2_Pos) /*!< MPU MAIR0: Attr2 Mask */ + +#define MPU_MAIR0_Attr1_Pos 8U /*!< MPU MAIR0: Attr1 Position */ +#define MPU_MAIR0_Attr1_Msk (0xFFUL << MPU_MAIR0_Attr1_Pos) /*!< MPU MAIR0: Attr1 Mask */ + +#define MPU_MAIR0_Attr0_Pos 0U /*!< MPU MAIR0: Attr0 Position */ +#define MPU_MAIR0_Attr0_Msk (0xFFUL /*<< MPU_MAIR0_Attr0_Pos*/) /*!< MPU MAIR0: Attr0 Mask */ + +/* MPU Memory Attribute Indirection Register 1 Definitions */ +#define MPU_MAIR1_Attr7_Pos 24U /*!< MPU MAIR1: Attr7 Position */ +#define MPU_MAIR1_Attr7_Msk (0xFFUL << MPU_MAIR1_Attr7_Pos) /*!< MPU MAIR1: Attr7 Mask */ + +#define MPU_MAIR1_Attr6_Pos 16U /*!< MPU MAIR1: Attr6 Position */ +#define MPU_MAIR1_Attr6_Msk (0xFFUL << MPU_MAIR1_Attr6_Pos) /*!< MPU MAIR1: Attr6 Mask */ + +#define MPU_MAIR1_Attr5_Pos 8U /*!< MPU MAIR1: Attr5 Position */ +#define MPU_MAIR1_Attr5_Msk (0xFFUL << MPU_MAIR1_Attr5_Pos) /*!< MPU MAIR1: Attr5 Mask */ + +#define MPU_MAIR1_Attr4_Pos 0U /*!< MPU MAIR1: Attr4 Position */ +#define MPU_MAIR1_Attr4_Msk (0xFFUL /*<< MPU_MAIR1_Attr4_Pos*/) /*!< MPU MAIR1: Attr4 Mask */ + +/*@} end of group CMSIS_MPU */ +#endif + + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SAU Security Attribution Unit (SAU) + \brief Type definitions for the Security Attribution Unit (SAU) + @{ + */ + +/** + \brief Structure type to access the Security Attribution Unit (SAU). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SAU Control Register */ + __IM uint32_t TYPE; /*!< Offset: 0x004 (R/ ) SAU Type Register */ +#if defined (__SAUREGION_PRESENT) && (__SAUREGION_PRESENT == 1U) + __IOM uint32_t RNR; /*!< Offset: 0x008 (R/W) SAU Region Number Register */ + __IOM uint32_t RBAR; /*!< Offset: 0x00C (R/W) SAU Region Base Address Register */ + __IOM uint32_t RLAR; /*!< Offset: 0x010 (R/W) SAU Region Limit Address Register */ +#else + uint32_t RESERVED0[3]; +#endif + __IOM uint32_t SFSR; /*!< Offset: 0x014 (R/W) Secure Fault Status Register */ + __IOM uint32_t SFAR; /*!< Offset: 0x018 (R/W) Secure Fault Address Register */ +} SAU_Type; + +/* SAU Control Register Definitions */ +#define SAU_CTRL_ALLNS_Pos 1U /*!< SAU CTRL: ALLNS Position */ +#define SAU_CTRL_ALLNS_Msk (1UL << SAU_CTRL_ALLNS_Pos) /*!< SAU CTRL: ALLNS Mask */ + +#define SAU_CTRL_ENABLE_Pos 0U /*!< SAU CTRL: ENABLE Position */ +#define SAU_CTRL_ENABLE_Msk (1UL /*<< SAU_CTRL_ENABLE_Pos*/) /*!< SAU CTRL: ENABLE Mask */ + +/* SAU Type Register Definitions */ +#define SAU_TYPE_SREGION_Pos 0U /*!< SAU TYPE: SREGION Position */ +#define SAU_TYPE_SREGION_Msk (0xFFUL /*<< SAU_TYPE_SREGION_Pos*/) /*!< SAU TYPE: SREGION Mask */ + +#if defined (__SAUREGION_PRESENT) && (__SAUREGION_PRESENT == 1U) +/* SAU Region Number Register Definitions */ +#define SAU_RNR_REGION_Pos 0U /*!< SAU RNR: REGION Position */ +#define SAU_RNR_REGION_Msk (0xFFUL /*<< SAU_RNR_REGION_Pos*/) /*!< SAU RNR: REGION Mask */ + +/* SAU Region Base Address Register Definitions */ +#define SAU_RBAR_BADDR_Pos 5U /*!< SAU RBAR: BADDR Position */ +#define SAU_RBAR_BADDR_Msk (0x7FFFFFFUL << SAU_RBAR_BADDR_Pos) /*!< SAU RBAR: BADDR Mask */ + +/* SAU Region Limit Address Register Definitions */ +#define SAU_RLAR_LADDR_Pos 5U /*!< SAU RLAR: LADDR Position */ +#define SAU_RLAR_LADDR_Msk (0x7FFFFFFUL << SAU_RLAR_LADDR_Pos) /*!< SAU RLAR: LADDR Mask */ + +#define SAU_RLAR_NSC_Pos 1U /*!< SAU RLAR: NSC Position */ +#define SAU_RLAR_NSC_Msk (1UL << SAU_RLAR_NSC_Pos) /*!< SAU RLAR: NSC Mask */ + +#define SAU_RLAR_ENABLE_Pos 0U /*!< SAU RLAR: ENABLE Position */ +#define SAU_RLAR_ENABLE_Msk (1UL /*<< SAU_RLAR_ENABLE_Pos*/) /*!< SAU RLAR: ENABLE Mask */ + +#endif /* defined (__SAUREGION_PRESENT) && (__SAUREGION_PRESENT == 1U) */ + +/* Secure Fault Status Register Definitions */ +#define SAU_SFSR_LSERR_Pos 7U /*!< SAU SFSR: LSERR Position */ +#define SAU_SFSR_LSERR_Msk (1UL << SAU_SFSR_LSERR_Pos) /*!< SAU SFSR: LSERR Mask */ + +#define SAU_SFSR_SFARVALID_Pos 6U /*!< SAU SFSR: SFARVALID Position */ +#define SAU_SFSR_SFARVALID_Msk (1UL << SAU_SFSR_SFARVALID_Pos) /*!< SAU SFSR: SFARVALID Mask */ + +#define SAU_SFSR_LSPERR_Pos 5U /*!< SAU SFSR: LSPERR Position */ +#define SAU_SFSR_LSPERR_Msk (1UL << SAU_SFSR_LSPERR_Pos) /*!< SAU SFSR: LSPERR Mask */ + +#define SAU_SFSR_INVTRAN_Pos 4U /*!< SAU SFSR: INVTRAN Position */ +#define SAU_SFSR_INVTRAN_Msk (1UL << SAU_SFSR_INVTRAN_Pos) /*!< SAU SFSR: INVTRAN Mask */ + +#define SAU_SFSR_AUVIOL_Pos 3U /*!< SAU SFSR: AUVIOL Position */ +#define SAU_SFSR_AUVIOL_Msk (1UL << SAU_SFSR_AUVIOL_Pos) /*!< SAU SFSR: AUVIOL Mask */ + +#define SAU_SFSR_INVER_Pos 2U /*!< SAU SFSR: INVER Position */ +#define SAU_SFSR_INVER_Msk (1UL << SAU_SFSR_INVER_Pos) /*!< SAU SFSR: INVER Mask */ + +#define SAU_SFSR_INVIS_Pos 1U /*!< SAU SFSR: INVIS Position */ +#define SAU_SFSR_INVIS_Msk (1UL << SAU_SFSR_INVIS_Pos) /*!< SAU SFSR: INVIS Mask */ + +#define SAU_SFSR_INVEP_Pos 0U /*!< SAU SFSR: INVEP Position */ +#define SAU_SFSR_INVEP_Msk (1UL /*<< SAU_SFSR_INVEP_Pos*/) /*!< SAU SFSR: INVEP Mask */ + +/*@} end of group CMSIS_SAU */ +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_FPU Floating Point Unit (FPU) + \brief Type definitions for the Floating Point Unit (FPU) + @{ + */ + +/** + \brief Structure type to access the Floating Point Unit (FPU). + */ +typedef struct +{ + uint32_t RESERVED0[1U]; + __IOM uint32_t FPCCR; /*!< Offset: 0x004 (R/W) Floating-Point Context Control Register */ + __IOM uint32_t FPCAR; /*!< Offset: 0x008 (R/W) Floating-Point Context Address Register */ + __IOM uint32_t FPDSCR; /*!< Offset: 0x00C (R/W) Floating-Point Default Status Control Register */ + __IM uint32_t MVFR0; /*!< Offset: 0x010 (R/ ) Media and FP Feature Register 0 */ + __IM uint32_t MVFR1; /*!< Offset: 0x014 (R/ ) Media and FP Feature Register 1 */ +} FPU_Type; + +/* Floating-Point Context Control Register Definitions */ +#define FPU_FPCCR_ASPEN_Pos 31U /*!< FPCCR: ASPEN bit Position */ +#define FPU_FPCCR_ASPEN_Msk (1UL << FPU_FPCCR_ASPEN_Pos) /*!< FPCCR: ASPEN bit Mask */ + +#define FPU_FPCCR_LSPEN_Pos 30U /*!< FPCCR: LSPEN Position */ +#define FPU_FPCCR_LSPEN_Msk (1UL << FPU_FPCCR_LSPEN_Pos) /*!< FPCCR: LSPEN bit Mask */ + +#define FPU_FPCCR_LSPENS_Pos 29U /*!< FPCCR: LSPENS Position */ +#define FPU_FPCCR_LSPENS_Msk (1UL << FPU_FPCCR_LSPENS_Pos) /*!< FPCCR: LSPENS bit Mask */ + +#define FPU_FPCCR_CLRONRET_Pos 28U /*!< FPCCR: CLRONRET Position */ +#define FPU_FPCCR_CLRONRET_Msk (1UL << FPU_FPCCR_CLRONRET_Pos) /*!< FPCCR: CLRONRET bit Mask */ + +#define FPU_FPCCR_CLRONRETS_Pos 27U /*!< FPCCR: CLRONRETS Position */ +#define FPU_FPCCR_CLRONRETS_Msk (1UL << FPU_FPCCR_CLRONRETS_Pos) /*!< FPCCR: CLRONRETS bit Mask */ + +#define FPU_FPCCR_TS_Pos 26U /*!< FPCCR: TS Position */ +#define FPU_FPCCR_TS_Msk (1UL << FPU_FPCCR_TS_Pos) /*!< FPCCR: TS bit Mask */ + +#define FPU_FPCCR_UFRDY_Pos 10U /*!< FPCCR: UFRDY Position */ +#define FPU_FPCCR_UFRDY_Msk (1UL << FPU_FPCCR_UFRDY_Pos) /*!< FPCCR: UFRDY bit Mask */ + +#define FPU_FPCCR_SPLIMVIOL_Pos 9U /*!< FPCCR: SPLIMVIOL Position */ +#define FPU_FPCCR_SPLIMVIOL_Msk (1UL << FPU_FPCCR_SPLIMVIOL_Pos) /*!< FPCCR: SPLIMVIOL bit Mask */ + +#define FPU_FPCCR_MONRDY_Pos 8U /*!< FPCCR: MONRDY Position */ +#define FPU_FPCCR_MONRDY_Msk (1UL << FPU_FPCCR_MONRDY_Pos) /*!< FPCCR: MONRDY bit Mask */ + +#define FPU_FPCCR_SFRDY_Pos 7U /*!< FPCCR: SFRDY Position */ +#define FPU_FPCCR_SFRDY_Msk (1UL << FPU_FPCCR_SFRDY_Pos) /*!< FPCCR: SFRDY bit Mask */ + +#define FPU_FPCCR_BFRDY_Pos 6U /*!< FPCCR: BFRDY Position */ +#define FPU_FPCCR_BFRDY_Msk (1UL << FPU_FPCCR_BFRDY_Pos) /*!< FPCCR: BFRDY bit Mask */ + +#define FPU_FPCCR_MMRDY_Pos 5U /*!< FPCCR: MMRDY Position */ +#define FPU_FPCCR_MMRDY_Msk (1UL << FPU_FPCCR_MMRDY_Pos) /*!< FPCCR: MMRDY bit Mask */ + +#define FPU_FPCCR_HFRDY_Pos 4U /*!< FPCCR: HFRDY Position */ +#define FPU_FPCCR_HFRDY_Msk (1UL << FPU_FPCCR_HFRDY_Pos) /*!< FPCCR: HFRDY bit Mask */ + +#define FPU_FPCCR_THREAD_Pos 3U /*!< FPCCR: processor mode bit Position */ +#define FPU_FPCCR_THREAD_Msk (1UL << FPU_FPCCR_THREAD_Pos) /*!< FPCCR: processor mode active bit Mask */ + +#define FPU_FPCCR_S_Pos 2U /*!< FPCCR: Security status of the FP context bit Position */ +#define FPU_FPCCR_S_Msk (1UL << FPU_FPCCR_S_Pos) /*!< FPCCR: Security status of the FP context bit Mask */ + +#define FPU_FPCCR_USER_Pos 1U /*!< FPCCR: privilege level bit Position */ +#define FPU_FPCCR_USER_Msk (1UL << FPU_FPCCR_USER_Pos) /*!< FPCCR: privilege level bit Mask */ + +#define FPU_FPCCR_LSPACT_Pos 0U /*!< FPCCR: Lazy state preservation active bit Position */ +#define FPU_FPCCR_LSPACT_Msk (1UL /*<< FPU_FPCCR_LSPACT_Pos*/) /*!< FPCCR: Lazy state preservation active bit Mask */ + +/* Floating-Point Context Address Register Definitions */ +#define FPU_FPCAR_ADDRESS_Pos 3U /*!< FPCAR: ADDRESS bit Position */ +#define FPU_FPCAR_ADDRESS_Msk (0x1FFFFFFFUL << FPU_FPCAR_ADDRESS_Pos) /*!< FPCAR: ADDRESS bit Mask */ + +/* Floating-Point Default Status Control Register Definitions */ +#define FPU_FPDSCR_AHP_Pos 26U /*!< FPDSCR: AHP bit Position */ +#define FPU_FPDSCR_AHP_Msk (1UL << FPU_FPDSCR_AHP_Pos) /*!< FPDSCR: AHP bit Mask */ + +#define FPU_FPDSCR_DN_Pos 25U /*!< FPDSCR: DN bit Position */ +#define FPU_FPDSCR_DN_Msk (1UL << FPU_FPDSCR_DN_Pos) /*!< FPDSCR: DN bit Mask */ + +#define FPU_FPDSCR_FZ_Pos 24U /*!< FPDSCR: FZ bit Position */ +#define FPU_FPDSCR_FZ_Msk (1UL << FPU_FPDSCR_FZ_Pos) /*!< FPDSCR: FZ bit Mask */ + +#define FPU_FPDSCR_RMode_Pos 22U /*!< FPDSCR: RMode bit Position */ +#define FPU_FPDSCR_RMode_Msk (3UL << FPU_FPDSCR_RMode_Pos) /*!< FPDSCR: RMode bit Mask */ + +/* Media and FP Feature Register 0 Definitions */ +#define FPU_MVFR0_FP_rounding_modes_Pos 28U /*!< MVFR0: FP rounding modes bits Position */ +#define FPU_MVFR0_FP_rounding_modes_Msk (0xFUL << FPU_MVFR0_FP_rounding_modes_Pos) /*!< MVFR0: FP rounding modes bits Mask */ + +#define FPU_MVFR0_Short_vectors_Pos 24U /*!< MVFR0: Short vectors bits Position */ +#define FPU_MVFR0_Short_vectors_Msk (0xFUL << FPU_MVFR0_Short_vectors_Pos) /*!< MVFR0: Short vectors bits Mask */ + +#define FPU_MVFR0_Square_root_Pos 20U /*!< MVFR0: Square root bits Position */ +#define FPU_MVFR0_Square_root_Msk (0xFUL << FPU_MVFR0_Square_root_Pos) /*!< MVFR0: Square root bits Mask */ + +#define FPU_MVFR0_Divide_Pos 16U /*!< MVFR0: Divide bits Position */ +#define FPU_MVFR0_Divide_Msk (0xFUL << FPU_MVFR0_Divide_Pos) /*!< MVFR0: Divide bits Mask */ + +#define FPU_MVFR0_FP_excep_trapping_Pos 12U /*!< MVFR0: FP exception trapping bits Position */ +#define FPU_MVFR0_FP_excep_trapping_Msk (0xFUL << FPU_MVFR0_FP_excep_trapping_Pos) /*!< MVFR0: FP exception trapping bits Mask */ + +#define FPU_MVFR0_Double_precision_Pos 8U /*!< MVFR0: Double-precision bits Position */ +#define FPU_MVFR0_Double_precision_Msk (0xFUL << FPU_MVFR0_Double_precision_Pos) /*!< MVFR0: Double-precision bits Mask */ + +#define FPU_MVFR0_Single_precision_Pos 4U /*!< MVFR0: Single-precision bits Position */ +#define FPU_MVFR0_Single_precision_Msk (0xFUL << FPU_MVFR0_Single_precision_Pos) /*!< MVFR0: Single-precision bits Mask */ + +#define FPU_MVFR0_A_SIMD_registers_Pos 0U /*!< MVFR0: A_SIMD registers bits Position */ +#define FPU_MVFR0_A_SIMD_registers_Msk (0xFUL /*<< FPU_MVFR0_A_SIMD_registers_Pos*/) /*!< MVFR0: A_SIMD registers bits Mask */ + +/* Media and FP Feature Register 1 Definitions */ +#define FPU_MVFR1_FP_fused_MAC_Pos 28U /*!< MVFR1: FP fused MAC bits Position */ +#define FPU_MVFR1_FP_fused_MAC_Msk (0xFUL << FPU_MVFR1_FP_fused_MAC_Pos) /*!< MVFR1: FP fused MAC bits Mask */ + +#define FPU_MVFR1_FP_HPFP_Pos 24U /*!< MVFR1: FP HPFP bits Position */ +#define FPU_MVFR1_FP_HPFP_Msk (0xFUL << FPU_MVFR1_FP_HPFP_Pos) /*!< MVFR1: FP HPFP bits Mask */ + +#define FPU_MVFR1_D_NaN_mode_Pos 4U /*!< MVFR1: D_NaN mode bits Position */ +#define FPU_MVFR1_D_NaN_mode_Msk (0xFUL << FPU_MVFR1_D_NaN_mode_Pos) /*!< MVFR1: D_NaN mode bits Mask */ + +#define FPU_MVFR1_FtZ_mode_Pos 0U /*!< MVFR1: FtZ mode bits Position */ +#define FPU_MVFR1_FtZ_mode_Msk (0xFUL /*<< FPU_MVFR1_FtZ_mode_Pos*/) /*!< MVFR1: FtZ mode bits Mask */ + +/*@} end of group CMSIS_FPU */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CoreDebug Core Debug Registers (CoreDebug) + \brief Type definitions for the Core Debug Registers + @{ + */ + +/** + \brief Structure type to access the Core Debug Register (CoreDebug). + */ +typedef struct +{ + __IOM uint32_t DHCSR; /*!< Offset: 0x000 (R/W) Debug Halting Control and Status Register */ + __OM uint32_t DCRSR; /*!< Offset: 0x004 ( /W) Debug Core Register Selector Register */ + __IOM uint32_t DCRDR; /*!< Offset: 0x008 (R/W) Debug Core Register Data Register */ + __IOM uint32_t DEMCR; /*!< Offset: 0x00C (R/W) Debug Exception and Monitor Control Register */ + uint32_t RESERVED4[1U]; + __IOM uint32_t DAUTHCTRL; /*!< Offset: 0x014 (R/W) Debug Authentication Control Register */ + __IOM uint32_t DSCSR; /*!< Offset: 0x018 (R/W) Debug Security Control and Status Register */ +} CoreDebug_Type; + +/* Debug Halting Control and Status Register Definitions */ +#define CoreDebug_DHCSR_DBGKEY_Pos 16U /*!< CoreDebug DHCSR: DBGKEY Position */ +#define CoreDebug_DHCSR_DBGKEY_Msk (0xFFFFUL << CoreDebug_DHCSR_DBGKEY_Pos) /*!< CoreDebug DHCSR: DBGKEY Mask */ + +#define CoreDebug_DHCSR_S_RESTART_ST_Pos 26U /*!< CoreDebug DHCSR: S_RESTART_ST Position */ +#define CoreDebug_DHCSR_S_RESTART_ST_Msk (1UL << CoreDebug_DHCSR_S_RESTART_ST_Pos) /*!< CoreDebug DHCSR: S_RESTART_ST Mask */ + +#define CoreDebug_DHCSR_S_RESET_ST_Pos 25U /*!< CoreDebug DHCSR: S_RESET_ST Position */ +#define CoreDebug_DHCSR_S_RESET_ST_Msk (1UL << CoreDebug_DHCSR_S_RESET_ST_Pos) /*!< CoreDebug DHCSR: S_RESET_ST Mask */ + +#define CoreDebug_DHCSR_S_RETIRE_ST_Pos 24U /*!< CoreDebug DHCSR: S_RETIRE_ST Position */ +#define CoreDebug_DHCSR_S_RETIRE_ST_Msk (1UL << CoreDebug_DHCSR_S_RETIRE_ST_Pos) /*!< CoreDebug DHCSR: S_RETIRE_ST Mask */ + +#define CoreDebug_DHCSR_S_LOCKUP_Pos 19U /*!< CoreDebug DHCSR: S_LOCKUP Position */ +#define CoreDebug_DHCSR_S_LOCKUP_Msk (1UL << CoreDebug_DHCSR_S_LOCKUP_Pos) /*!< CoreDebug DHCSR: S_LOCKUP Mask */ + +#define CoreDebug_DHCSR_S_SLEEP_Pos 18U /*!< CoreDebug DHCSR: S_SLEEP Position */ +#define CoreDebug_DHCSR_S_SLEEP_Msk (1UL << CoreDebug_DHCSR_S_SLEEP_Pos) /*!< CoreDebug DHCSR: S_SLEEP Mask */ + +#define CoreDebug_DHCSR_S_HALT_Pos 17U /*!< CoreDebug DHCSR: S_HALT Position */ +#define CoreDebug_DHCSR_S_HALT_Msk (1UL << CoreDebug_DHCSR_S_HALT_Pos) /*!< CoreDebug DHCSR: S_HALT Mask */ + +#define CoreDebug_DHCSR_S_REGRDY_Pos 16U /*!< CoreDebug DHCSR: S_REGRDY Position */ +#define CoreDebug_DHCSR_S_REGRDY_Msk (1UL << CoreDebug_DHCSR_S_REGRDY_Pos) /*!< CoreDebug DHCSR: S_REGRDY Mask */ + +#define CoreDebug_DHCSR_C_SNAPSTALL_Pos 5U /*!< CoreDebug DHCSR: C_SNAPSTALL Position */ +#define CoreDebug_DHCSR_C_SNAPSTALL_Msk (1UL << CoreDebug_DHCSR_C_SNAPSTALL_Pos) /*!< CoreDebug DHCSR: C_SNAPSTALL Mask */ + +#define CoreDebug_DHCSR_C_MASKINTS_Pos 3U /*!< CoreDebug DHCSR: C_MASKINTS Position */ +#define CoreDebug_DHCSR_C_MASKINTS_Msk (1UL << CoreDebug_DHCSR_C_MASKINTS_Pos) /*!< CoreDebug DHCSR: C_MASKINTS Mask */ + +#define CoreDebug_DHCSR_C_STEP_Pos 2U /*!< CoreDebug DHCSR: C_STEP Position */ +#define CoreDebug_DHCSR_C_STEP_Msk (1UL << CoreDebug_DHCSR_C_STEP_Pos) /*!< CoreDebug DHCSR: C_STEP Mask */ + +#define CoreDebug_DHCSR_C_HALT_Pos 1U /*!< CoreDebug DHCSR: C_HALT Position */ +#define CoreDebug_DHCSR_C_HALT_Msk (1UL << CoreDebug_DHCSR_C_HALT_Pos) /*!< CoreDebug DHCSR: C_HALT Mask */ + +#define CoreDebug_DHCSR_C_DEBUGEN_Pos 0U /*!< CoreDebug DHCSR: C_DEBUGEN Position */ +#define CoreDebug_DHCSR_C_DEBUGEN_Msk (1UL /*<< CoreDebug_DHCSR_C_DEBUGEN_Pos*/) /*!< CoreDebug DHCSR: C_DEBUGEN Mask */ + +/* Debug Core Register Selector Register Definitions */ +#define CoreDebug_DCRSR_REGWnR_Pos 16U /*!< CoreDebug DCRSR: REGWnR Position */ +#define CoreDebug_DCRSR_REGWnR_Msk (1UL << CoreDebug_DCRSR_REGWnR_Pos) /*!< CoreDebug DCRSR: REGWnR Mask */ + +#define CoreDebug_DCRSR_REGSEL_Pos 0U /*!< CoreDebug DCRSR: REGSEL Position */ +#define CoreDebug_DCRSR_REGSEL_Msk (0x1FUL /*<< CoreDebug_DCRSR_REGSEL_Pos*/) /*!< CoreDebug DCRSR: REGSEL Mask */ + +/* Debug Exception and Monitor Control Register Definitions */ +#define CoreDebug_DEMCR_TRCENA_Pos 24U /*!< CoreDebug DEMCR: TRCENA Position */ +#define CoreDebug_DEMCR_TRCENA_Msk (1UL << CoreDebug_DEMCR_TRCENA_Pos) /*!< CoreDebug DEMCR: TRCENA Mask */ + +#define CoreDebug_DEMCR_MON_REQ_Pos 19U /*!< CoreDebug DEMCR: MON_REQ Position */ +#define CoreDebug_DEMCR_MON_REQ_Msk (1UL << CoreDebug_DEMCR_MON_REQ_Pos) /*!< CoreDebug DEMCR: MON_REQ Mask */ + +#define CoreDebug_DEMCR_MON_STEP_Pos 18U /*!< CoreDebug DEMCR: MON_STEP Position */ +#define CoreDebug_DEMCR_MON_STEP_Msk (1UL << CoreDebug_DEMCR_MON_STEP_Pos) /*!< CoreDebug DEMCR: MON_STEP Mask */ + +#define CoreDebug_DEMCR_MON_PEND_Pos 17U /*!< CoreDebug DEMCR: MON_PEND Position */ +#define CoreDebug_DEMCR_MON_PEND_Msk (1UL << CoreDebug_DEMCR_MON_PEND_Pos) /*!< CoreDebug DEMCR: MON_PEND Mask */ + +#define CoreDebug_DEMCR_MON_EN_Pos 16U /*!< CoreDebug DEMCR: MON_EN Position */ +#define CoreDebug_DEMCR_MON_EN_Msk (1UL << CoreDebug_DEMCR_MON_EN_Pos) /*!< CoreDebug DEMCR: MON_EN Mask */ + +#define CoreDebug_DEMCR_VC_HARDERR_Pos 10U /*!< CoreDebug DEMCR: VC_HARDERR Position */ +#define CoreDebug_DEMCR_VC_HARDERR_Msk (1UL << CoreDebug_DEMCR_VC_HARDERR_Pos) /*!< CoreDebug DEMCR: VC_HARDERR Mask */ + +#define CoreDebug_DEMCR_VC_INTERR_Pos 9U /*!< CoreDebug DEMCR: VC_INTERR Position */ +#define CoreDebug_DEMCR_VC_INTERR_Msk (1UL << CoreDebug_DEMCR_VC_INTERR_Pos) /*!< CoreDebug DEMCR: VC_INTERR Mask */ + +#define CoreDebug_DEMCR_VC_BUSERR_Pos 8U /*!< CoreDebug DEMCR: VC_BUSERR Position */ +#define CoreDebug_DEMCR_VC_BUSERR_Msk (1UL << CoreDebug_DEMCR_VC_BUSERR_Pos) /*!< CoreDebug DEMCR: VC_BUSERR Mask */ + +#define CoreDebug_DEMCR_VC_STATERR_Pos 7U /*!< CoreDebug DEMCR: VC_STATERR Position */ +#define CoreDebug_DEMCR_VC_STATERR_Msk (1UL << CoreDebug_DEMCR_VC_STATERR_Pos) /*!< CoreDebug DEMCR: VC_STATERR Mask */ + +#define CoreDebug_DEMCR_VC_CHKERR_Pos 6U /*!< CoreDebug DEMCR: VC_CHKERR Position */ +#define CoreDebug_DEMCR_VC_CHKERR_Msk (1UL << CoreDebug_DEMCR_VC_CHKERR_Pos) /*!< CoreDebug DEMCR: VC_CHKERR Mask */ + +#define CoreDebug_DEMCR_VC_NOCPERR_Pos 5U /*!< CoreDebug DEMCR: VC_NOCPERR Position */ +#define CoreDebug_DEMCR_VC_NOCPERR_Msk (1UL << CoreDebug_DEMCR_VC_NOCPERR_Pos) /*!< CoreDebug DEMCR: VC_NOCPERR Mask */ + +#define CoreDebug_DEMCR_VC_MMERR_Pos 4U /*!< CoreDebug DEMCR: VC_MMERR Position */ +#define CoreDebug_DEMCR_VC_MMERR_Msk (1UL << CoreDebug_DEMCR_VC_MMERR_Pos) /*!< CoreDebug DEMCR: VC_MMERR Mask */ + +#define CoreDebug_DEMCR_VC_CORERESET_Pos 0U /*!< CoreDebug DEMCR: VC_CORERESET Position */ +#define CoreDebug_DEMCR_VC_CORERESET_Msk (1UL /*<< CoreDebug_DEMCR_VC_CORERESET_Pos*/) /*!< CoreDebug DEMCR: VC_CORERESET Mask */ + +/* Debug Authentication Control Register Definitions */ +#define CoreDebug_DAUTHCTRL_INTSPNIDEN_Pos 3U /*!< CoreDebug DAUTHCTRL: INTSPNIDEN, Position */ +#define CoreDebug_DAUTHCTRL_INTSPNIDEN_Msk (1UL << CoreDebug_DAUTHCTRL_INTSPNIDEN_Pos) /*!< CoreDebug DAUTHCTRL: INTSPNIDEN, Mask */ + +#define CoreDebug_DAUTHCTRL_SPNIDENSEL_Pos 2U /*!< CoreDebug DAUTHCTRL: SPNIDENSEL Position */ +#define CoreDebug_DAUTHCTRL_SPNIDENSEL_Msk (1UL << CoreDebug_DAUTHCTRL_SPNIDENSEL_Pos) /*!< CoreDebug DAUTHCTRL: SPNIDENSEL Mask */ + +#define CoreDebug_DAUTHCTRL_INTSPIDEN_Pos 1U /*!< CoreDebug DAUTHCTRL: INTSPIDEN Position */ +#define CoreDebug_DAUTHCTRL_INTSPIDEN_Msk (1UL << CoreDebug_DAUTHCTRL_INTSPIDEN_Pos) /*!< CoreDebug DAUTHCTRL: INTSPIDEN Mask */ + +#define CoreDebug_DAUTHCTRL_SPIDENSEL_Pos 0U /*!< CoreDebug DAUTHCTRL: SPIDENSEL Position */ +#define CoreDebug_DAUTHCTRL_SPIDENSEL_Msk (1UL /*<< CoreDebug_DAUTHCTRL_SPIDENSEL_Pos*/) /*!< CoreDebug DAUTHCTRL: SPIDENSEL Mask */ + +/* Debug Security Control and Status Register Definitions */ +#define CoreDebug_DSCSR_CDS_Pos 16U /*!< CoreDebug DSCSR: CDS Position */ +#define CoreDebug_DSCSR_CDS_Msk (1UL << CoreDebug_DSCSR_CDS_Pos) /*!< CoreDebug DSCSR: CDS Mask */ + +#define CoreDebug_DSCSR_SBRSEL_Pos 1U /*!< CoreDebug DSCSR: SBRSEL Position */ +#define CoreDebug_DSCSR_SBRSEL_Msk (1UL << CoreDebug_DSCSR_SBRSEL_Pos) /*!< CoreDebug DSCSR: SBRSEL Mask */ + +#define CoreDebug_DSCSR_SBRSELEN_Pos 0U /*!< CoreDebug DSCSR: SBRSELEN Position */ +#define CoreDebug_DSCSR_SBRSELEN_Msk (1UL /*<< CoreDebug_DSCSR_SBRSELEN_Pos*/) /*!< CoreDebug DSCSR: SBRSELEN Mask */ + +/*@} end of group CMSIS_CoreDebug */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_bitfield Core register bit field macros + \brief Macros for use with bit field definitions (xxx_Pos, xxx_Msk). + @{ + */ + +/** + \brief Mask and shift a bit field value for use in a register bit range. + \param[in] field Name of the register bit field. + \param[in] value Value of the bit field. This parameter is interpreted as an uint32_t type. + \return Masked and shifted value. +*/ +#define _VAL2FLD(field, value) (((uint32_t)(value) << field ## _Pos) & field ## _Msk) + +/** + \brief Mask and shift a register value to extract a bit filed value. + \param[in] field Name of the register bit field. + \param[in] value Value of register. This parameter is interpreted as an uint32_t type. + \return Masked and shifted bit field value. +*/ +#define _FLD2VAL(field, value) (((uint32_t)(value) & field ## _Msk) >> field ## _Pos) + +/*@} end of group CMSIS_core_bitfield */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_base Core Definitions + \brief Definitions for base addresses, unions, and structures. + @{ + */ + +/* Memory mapping of Core Hardware */ + #define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ + #define ITM_BASE (0xE0000000UL) /*!< ITM Base Address */ + #define DWT_BASE (0xE0001000UL) /*!< DWT Base Address */ + #define TPI_BASE (0xE0040000UL) /*!< TPI Base Address */ + #define CoreDebug_BASE (0xE000EDF0UL) /*!< Core Debug Base Address */ + #define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */ + #define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */ + #define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */ + + #define SCnSCB ((SCnSCB_Type *) SCS_BASE ) /*!< System control Register not in SCB */ + #define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */ + #define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */ + #define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */ + #define ITM ((ITM_Type *) ITM_BASE ) /*!< ITM configuration struct */ + #define DWT ((DWT_Type *) DWT_BASE ) /*!< DWT configuration struct */ + #define TPI ((TPI_Type *) TPI_BASE ) /*!< TPI configuration struct */ + #define CoreDebug ((CoreDebug_Type *) CoreDebug_BASE ) /*!< Core Debug configuration struct */ + + #if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + #define MPU_BASE (SCS_BASE + 0x0D90UL) /*!< Memory Protection Unit */ + #define MPU ((MPU_Type *) MPU_BASE ) /*!< Memory Protection Unit */ + #endif + + #if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + #define SAU_BASE (SCS_BASE + 0x0DD0UL) /*!< Security Attribution Unit */ + #define SAU ((SAU_Type *) SAU_BASE ) /*!< Security Attribution Unit */ + #endif + + #define FPU_BASE (SCS_BASE + 0x0F30UL) /*!< Floating Point Unit */ + #define FPU ((FPU_Type *) FPU_BASE ) /*!< Floating Point Unit */ + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + #define SCS_BASE_NS (0xE002E000UL) /*!< System Control Space Base Address (non-secure address space) */ + #define CoreDebug_BASE_NS (0xE002EDF0UL) /*!< Core Debug Base Address (non-secure address space) */ + #define SysTick_BASE_NS (SCS_BASE_NS + 0x0010UL) /*!< SysTick Base Address (non-secure address space) */ + #define NVIC_BASE_NS (SCS_BASE_NS + 0x0100UL) /*!< NVIC Base Address (non-secure address space) */ + #define SCB_BASE_NS (SCS_BASE_NS + 0x0D00UL) /*!< System Control Block Base Address (non-secure address space) */ + + #define SCnSCB_NS ((SCnSCB_Type *) SCS_BASE_NS ) /*!< System control Register not in SCB(non-secure address space) */ + #define SCB_NS ((SCB_Type *) SCB_BASE_NS ) /*!< SCB configuration struct (non-secure address space) */ + #define SysTick_NS ((SysTick_Type *) SysTick_BASE_NS ) /*!< SysTick configuration struct (non-secure address space) */ + #define NVIC_NS ((NVIC_Type *) NVIC_BASE_NS ) /*!< NVIC configuration struct (non-secure address space) */ + #define CoreDebug_NS ((CoreDebug_Type *) CoreDebug_BASE_NS) /*!< Core Debug configuration struct (non-secure address space) */ + + #if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + #define MPU_BASE_NS (SCS_BASE_NS + 0x0D90UL) /*!< Memory Protection Unit (non-secure address space) */ + #define MPU_NS ((MPU_Type *) MPU_BASE_NS ) /*!< Memory Protection Unit (non-secure address space) */ + #endif + + #define FPU_BASE_NS (SCS_BASE_NS + 0x0F30UL) /*!< Floating Point Unit (non-secure address space) */ + #define FPU_NS ((FPU_Type *) FPU_BASE_NS ) /*!< Floating Point Unit (non-secure address space) */ + +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ +/*@} */ + + + +/******************************************************************************* + * Hardware Abstraction Layer + Core Function Interface contains: + - Core NVIC Functions + - Core SysTick Functions + - Core Debug Functions + - Core Register Access Functions + ******************************************************************************/ +/** + \defgroup CMSIS_Core_FunctionInterface Functions and Instructions Reference +*/ + + + +/* ########################## NVIC functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_NVICFunctions NVIC Functions + \brief Functions that manage interrupts and exceptions via the NVIC. + @{ + */ + +#ifdef CMSIS_NVIC_VIRTUAL + #ifndef CMSIS_NVIC_VIRTUAL_HEADER_FILE + #define CMSIS_NVIC_VIRTUAL_HEADER_FILE "cmsis_nvic_virtual.h" + #endif + #include CMSIS_NVIC_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetPriorityGrouping __NVIC_SetPriorityGrouping + #define NVIC_GetPriorityGrouping __NVIC_GetPriorityGrouping + #define NVIC_EnableIRQ __NVIC_EnableIRQ + #define NVIC_GetEnableIRQ __NVIC_GetEnableIRQ + #define NVIC_DisableIRQ __NVIC_DisableIRQ + #define NVIC_GetPendingIRQ __NVIC_GetPendingIRQ + #define NVIC_SetPendingIRQ __NVIC_SetPendingIRQ + #define NVIC_ClearPendingIRQ __NVIC_ClearPendingIRQ + #define NVIC_GetActive __NVIC_GetActive + #define NVIC_SetPriority __NVIC_SetPriority + #define NVIC_GetPriority __NVIC_GetPriority + #define NVIC_SystemReset __NVIC_SystemReset +#endif /* CMSIS_NVIC_VIRTUAL */ + +#ifdef CMSIS_VECTAB_VIRTUAL + #ifndef CMSIS_VECTAB_VIRTUAL_HEADER_FILE + #define CMSIS_VECTAB_VIRTUAL_HEADER_FILE "cmsis_vectab_virtual.h" + #endif + #include CMSIS_VECTAB_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetVector __NVIC_SetVector + #define NVIC_GetVector __NVIC_GetVector +#endif /* (CMSIS_VECTAB_VIRTUAL) */ + +#define NVIC_USER_IRQ_OFFSET 16 + + +/* Special LR values for Secure/Non-Secure call handling and exception handling */ + +/* Function Return Payload (from ARMv8-M Architecture Reference Manual) LR value on entry from Secure BLXNS */ +#define FNC_RETURN (0xFEFFFFFFUL) /* bit [0] ignored when processing a branch */ + +/* The following EXC_RETURN mask values are used to evaluate the LR on exception entry */ +#define EXC_RETURN_PREFIX (0xFF000000UL) /* bits [31:24] set to indicate an EXC_RETURN value */ +#define EXC_RETURN_S (0x00000040UL) /* bit [6] stack used to push registers: 0=Non-secure 1=Secure */ +#define EXC_RETURN_DCRS (0x00000020UL) /* bit [5] stacking rules for called registers: 0=skipped 1=saved */ +#define EXC_RETURN_FTYPE (0x00000010UL) /* bit [4] allocate stack for floating-point context: 0=done 1=skipped */ +#define EXC_RETURN_MODE (0x00000008UL) /* bit [3] processor mode for return: 0=Handler mode 1=Thread mode */ +#define EXC_RETURN_SPSEL (0x00000004UL) /* bit [2] stack pointer used to restore context: 0=MSP 1=PSP */ +#define EXC_RETURN_ES (0x00000001UL) /* bit [0] security state exception was taken to: 0=Non-secure 1=Secure */ + +/* Integrity Signature (from ARMv8-M Architecture Reference Manual) for exception context stacking */ +#if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) /* Value for processors with floating-point extension: */ +#define EXC_INTEGRITY_SIGNATURE (0xFEFA125AUL) /* bit [0] SFTC must match LR bit[4] EXC_RETURN_FTYPE */ +#else +#define EXC_INTEGRITY_SIGNATURE (0xFEFA125BUL) /* Value for processors without floating-point extension */ +#endif + + +/** + \brief Set Priority Grouping + \details Sets the priority grouping field using the required unlock sequence. + The parameter PriorityGroup is assigned to the field SCB->AIRCR [10:8] PRIGROUP field. + Only values from 0..7 are used. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. + \param [in] PriorityGroup Priority grouping field. + */ +__STATIC_INLINE void __NVIC_SetPriorityGrouping(uint32_t PriorityGroup) +{ + uint32_t reg_value; + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + + reg_value = SCB->AIRCR; /* read old register configuration */ + reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk)); /* clear bits to change */ + reg_value = (reg_value | + ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + (PriorityGroupTmp << SCB_AIRCR_PRIGROUP_Pos) ); /* Insert write key and priority group */ + SCB->AIRCR = reg_value; +} + + +/** + \brief Get Priority Grouping + \details Reads the priority grouping field from the NVIC Interrupt Controller. + \return Priority grouping field (SCB->AIRCR [10:8] PRIGROUP field). + */ +__STATIC_INLINE uint32_t __NVIC_GetPriorityGrouping(void) +{ + return ((uint32_t)((SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) >> SCB_AIRCR_PRIGROUP_Pos)); +} + + +/** + \brief Enable Interrupt + \details Enables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Interrupt Enable status + \details Returns a device specific interrupt enable status from the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt is not enabled. + \return 1 Interrupt is enabled. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t __NVIC_GetEnableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Disable Interrupt + \details Disables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_DisableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + __DSB(); + __ISB(); + } +} + + +/** + \brief Get Pending Interrupt + \details Reads the NVIC pending register and returns the pending bit for the specified device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt status is not pending. + \return 1 Interrupt status is pending. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t __NVIC_GetPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Set Pending Interrupt + \details Sets the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_SetPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Clear Pending Interrupt + \details Clears the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_ClearPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Active Interrupt + \details Reads the active register in the NVIC and returns the active bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt status is not active. + \return 1 Interrupt status is active. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t __NVIC_GetActive(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->IABR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +/** + \brief Get Interrupt Target State + \details Reads the interrupt target field in the NVIC and returns the interrupt target bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 if interrupt is assigned to Secure + \return 1 if interrupt is assigned to Non Secure + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t NVIC_GetTargetState(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Set Interrupt Target State + \details Sets the interrupt target field in the NVIC and returns the interrupt target bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 if interrupt is assigned to Secure + 1 if interrupt is assigned to Non Secure + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t NVIC_SetTargetState(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] |= ((uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL))); + return((uint32_t)(((NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Clear Interrupt Target State + \details Clears the interrupt target field in the NVIC and returns the interrupt target bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 if interrupt is assigned to Secure + 1 if interrupt is assigned to Non Secure + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t NVIC_ClearTargetState(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] &= ~((uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL))); + return((uint32_t)(((NVIC->ITNS[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ + + +/** + \brief Set Interrupt Priority + \details Sets the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \param [in] priority Priority to set. + \note The priority cannot be set for every processor exception. + */ +__STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->IPR[((uint32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + } + else + { + SCB->SHPR[(((uint32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + } +} + + +/** + \brief Get Interrupt Priority + \details Reads the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Interrupt Priority. + Value is aligned automatically to the implemented priority bits of the microcontroller. + */ +__STATIC_INLINE uint32_t __NVIC_GetPriority(IRQn_Type IRQn) +{ + + if ((int32_t)(IRQn) >= 0) + { + return(((uint32_t)NVIC->IPR[((uint32_t)IRQn)] >> (8U - __NVIC_PRIO_BITS))); + } + else + { + return(((uint32_t)SCB->SHPR[(((uint32_t)IRQn) & 0xFUL)-4UL] >> (8U - __NVIC_PRIO_BITS))); + } +} + + +/** + \brief Encode Priority + \details Encodes the priority for an interrupt with the given priority group, + preemptive priority value, and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. + \param [in] PriorityGroup Used priority group. + \param [in] PreemptPriority Preemptive priority value (starting from 0). + \param [in] SubPriority Subpriority value (starting from 0). + \return Encoded priority. Value can be used in the function \ref NVIC_SetPriority(). + */ +__STATIC_INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + return ( + ((PreemptPriority & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL)) << SubPriorityBits) | + ((SubPriority & (uint32_t)((1UL << (SubPriorityBits )) - 1UL))) + ); +} + + +/** + \brief Decode Priority + \details Decodes an interrupt priority value with a given priority group to + preemptive priority value and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS) the smallest possible priority group is set. + \param [in] Priority Priority value, which can be retrieved with the function \ref NVIC_GetPriority(). + \param [in] PriorityGroup Used priority group. + \param [out] pPreemptPriority Preemptive priority value (starting from 0). + \param [out] pSubPriority Subpriority value (starting from 0). + */ +__STATIC_INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGroup, uint32_t* const pPreemptPriority, uint32_t* const pSubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + *pPreemptPriority = (Priority >> SubPriorityBits) & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL); + *pSubPriority = (Priority ) & (uint32_t)((1UL << (SubPriorityBits )) - 1UL); +} + + +/** + \brief Set Interrupt Vector + \details Sets an interrupt vector in SRAM based interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + VTOR must been relocated to SRAM before. + \param [in] IRQn Interrupt number + \param [in] vector Address of interrupt handler function + */ +__STATIC_INLINE void __NVIC_SetVector(IRQn_Type IRQn, uint32_t vector) +{ + uint32_t *vectors = (uint32_t *)SCB->VTOR; + vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET] = vector; +} + + +/** + \brief Get Interrupt Vector + \details Reads an interrupt vector from interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Address of interrupt handler function + */ +__STATIC_INLINE uint32_t __NVIC_GetVector(IRQn_Type IRQn) +{ + uint32_t *vectors = (uint32_t *)SCB->VTOR; + return vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET]; +} + + +/** + \brief System Reset + \details Initiates a system reset request to reset the MCU. + */ +__NO_RETURN __STATIC_INLINE void __NVIC_SystemReset(void) +{ + __DSB(); /* Ensure all outstanding memory accesses included + buffered write are completed before reset */ + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + SCB_AIRCR_SYSRESETREQ_Msk ); /* Keep priority group unchanged */ + __DSB(); /* Ensure completion of memory access */ + + for(;;) /* wait until reset */ + { + __NOP(); + } +} + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +/** + \brief Set Priority Grouping (non-secure) + \details Sets the non-secure priority grouping field when in secure state using the required unlock sequence. + The parameter PriorityGroup is assigned to the field SCB->AIRCR [10:8] PRIGROUP field. + Only values from 0..7 are used. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. + \param [in] PriorityGroup Priority grouping field. + */ +__STATIC_INLINE void TZ_NVIC_SetPriorityGrouping_NS(uint32_t PriorityGroup) +{ + uint32_t reg_value; + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + + reg_value = SCB_NS->AIRCR; /* read old register configuration */ + reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk)); /* clear bits to change */ + reg_value = (reg_value | + ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + (PriorityGroupTmp << SCB_AIRCR_PRIGROUP_Pos) ); /* Insert write key and priority group */ + SCB_NS->AIRCR = reg_value; +} + + +/** + \brief Get Priority Grouping (non-secure) + \details Reads the priority grouping field from the non-secure NVIC when in secure state. + \return Priority grouping field (SCB->AIRCR [10:8] PRIGROUP field). + */ +__STATIC_INLINE uint32_t TZ_NVIC_GetPriorityGrouping_NS(void) +{ + return ((uint32_t)((SCB_NS->AIRCR & SCB_AIRCR_PRIGROUP_Msk) >> SCB_AIRCR_PRIGROUP_Pos)); +} + + +/** + \brief Enable Interrupt (non-secure) + \details Enables a device specific interrupt in the non-secure NVIC interrupt controller when in secure state. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void TZ_NVIC_EnableIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Interrupt Enable status (non-secure) + \details Returns a device specific interrupt enable status from the non-secure NVIC interrupt controller when in secure state. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt is not enabled. + \return 1 Interrupt is enabled. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t TZ_NVIC_GetEnableIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC_NS->ISER[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Disable Interrupt (non-secure) + \details Disables a device specific interrupt in the non-secure NVIC interrupt controller when in secure state. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void TZ_NVIC_DisableIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->ICER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Pending Interrupt (non-secure) + \details Reads the NVIC pending register in the non-secure NVIC when in secure state and returns the pending bit for the specified device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt status is not pending. + \return 1 Interrupt status is pending. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t TZ_NVIC_GetPendingIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC_NS->ISPR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Set Pending Interrupt (non-secure) + \details Sets the pending bit of a device specific interrupt in the non-secure NVIC pending register when in secure state. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void TZ_NVIC_SetPendingIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->ISPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Clear Pending Interrupt (non-secure) + \details Clears the pending bit of a device specific interrupt in the non-secure NVIC pending register when in secure state. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void TZ_NVIC_ClearPendingIRQ_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->ICPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Active Interrupt (non-secure) + \details Reads the active register in non-secure NVIC when in secure state and returns the active bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt status is not active. + \return 1 Interrupt status is active. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t TZ_NVIC_GetActive_NS(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC_NS->IABR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Set Interrupt Priority (non-secure) + \details Sets the priority of a non-secure device specific interrupt or a non-secure processor exception when in secure state. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \param [in] priority Priority to set. + \note The priority cannot be set for every non-secure processor exception. + */ +__STATIC_INLINE void TZ_NVIC_SetPriority_NS(IRQn_Type IRQn, uint32_t priority) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC_NS->IPR[((uint32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + } + else + { + SCB_NS->SHPR[(((uint32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + } +} + + +/** + \brief Get Interrupt Priority (non-secure) + \details Reads the priority of a non-secure device specific interrupt or a non-secure processor exception when in secure state. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Interrupt Priority. Value is aligned automatically to the implemented priority bits of the microcontroller. + */ +__STATIC_INLINE uint32_t TZ_NVIC_GetPriority_NS(IRQn_Type IRQn) +{ + + if ((int32_t)(IRQn) >= 0) + { + return(((uint32_t)NVIC_NS->IPR[((uint32_t)IRQn)] >> (8U - __NVIC_PRIO_BITS))); + } + else + { + return(((uint32_t)SCB_NS->SHPR[(((uint32_t)IRQn) & 0xFUL)-4UL] >> (8U - __NVIC_PRIO_BITS))); + } +} +#endif /* defined (__ARM_FEATURE_CMSE) &&(__ARM_FEATURE_CMSE == 3U) */ + +/*@} end of CMSIS_Core_NVICFunctions */ + +/* ########################## MPU functions #################################### */ + +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + +#include "mpu_armv8.h" + +#endif + +/* ########################## FPU functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_FpuFunctions FPU Functions + \brief Function that provides FPU type. + @{ + */ + +/** + \brief get FPU type + \details returns the FPU type + \returns + - \b 0: No FPU + - \b 1: Single precision FPU + - \b 2: Double + Single precision FPU + */ +__STATIC_INLINE uint32_t SCB_GetFPUType(void) +{ + uint32_t mvfr0; + + mvfr0 = FPU->MVFR0; + if ((mvfr0 & (FPU_MVFR0_Single_precision_Msk | FPU_MVFR0_Double_precision_Msk)) == 0x220U) + { + return 2U; /* Double + Single precision FPU */ + } + else if ((mvfr0 & (FPU_MVFR0_Single_precision_Msk | FPU_MVFR0_Double_precision_Msk)) == 0x020U) + { + return 1U; /* Single precision FPU */ + } + else + { + return 0U; /* No FPU */ + } +} + + +/*@} end of CMSIS_Core_FpuFunctions */ + + + +/* ########################## SAU functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_SAUFunctions SAU Functions + \brief Functions that configure the SAU. + @{ + */ + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + +/** + \brief Enable SAU + \details Enables the Security Attribution Unit (SAU). + */ +__STATIC_INLINE void TZ_SAU_Enable(void) +{ + SAU->CTRL |= (SAU_CTRL_ENABLE_Msk); +} + + + +/** + \brief Disable SAU + \details Disables the Security Attribution Unit (SAU). + */ +__STATIC_INLINE void TZ_SAU_Disable(void) +{ + SAU->CTRL &= ~(SAU_CTRL_ENABLE_Msk); +} + +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ + +/*@} end of CMSIS_Core_SAUFunctions */ + + + + +/* ################################## SysTick function ############################################ */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_SysTickFunctions SysTick Functions + \brief Functions that configure the System. + @{ + */ + +#if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U) + +/** + \brief System Tick Configuration + \details Initializes the System Timer and its interrupt, and starts the System Tick Timer. + Counter is in free running mode to generate periodic interrupts. + \param [in] ticks Number of ticks between two interrupts. + \return 0 Function succeeded. + \return 1 Function failed. + \note When the variable __Vendor_SysTickConfig is set to 1, then the + function SysTick_Config is not included. In this case, the file device.h + must contain a vendor-specific implementation of this function. + */ +__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) +{ + if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) + { + return (1UL); /* Reload value impossible */ + } + + SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ + NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ + SysTick->VAL = 0UL; /* Load the SysTick Counter Value */ + SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + SysTick_CTRL_TICKINT_Msk | + SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ + return (0UL); /* Function successful */ +} + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +/** + \brief System Tick Configuration (non-secure) + \details Initializes the non-secure System Timer and its interrupt when in secure state, and starts the System Tick Timer. + Counter is in free running mode to generate periodic interrupts. + \param [in] ticks Number of ticks between two interrupts. + \return 0 Function succeeded. + \return 1 Function failed. + \note When the variable __Vendor_SysTickConfig is set to 1, then the + function TZ_SysTick_Config_NS is not included. In this case, the file device.h + must contain a vendor-specific implementation of this function. + + */ +__STATIC_INLINE uint32_t TZ_SysTick_Config_NS(uint32_t ticks) +{ + if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) + { + return (1UL); /* Reload value impossible */ + } + + SysTick_NS->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ + TZ_NVIC_SetPriority_NS (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ + SysTick_NS->VAL = 0UL; /* Load the SysTick Counter Value */ + SysTick_NS->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + SysTick_CTRL_TICKINT_Msk | + SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ + return (0UL); /* Function successful */ +} +#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ + +#endif + +/*@} end of CMSIS_Core_SysTickFunctions */ + + + +/* ##################################### Debug In/Output function ########################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_core_DebugFunctions ITM Functions + \brief Functions that access the ITM debug interface. + @{ + */ + +extern volatile int32_t ITM_RxBuffer; /*!< External variable to receive characters. */ +#define ITM_RXBUFFER_EMPTY ((int32_t)0x5AA55AA5U) /*!< Value identifying \ref ITM_RxBuffer is ready for next character. */ + + +/** + \brief ITM Send Character + \details Transmits a character via the ITM channel 0, and + \li Just returns when no debugger is connected that has booked the output. + \li Is blocking when a debugger is connected, but the previous character sent has not been transmitted. + \param [in] ch Character to transmit. + \returns Character to transmit. + */ +__STATIC_INLINE uint32_t ITM_SendChar (uint32_t ch) +{ + if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && /* ITM enabled */ + ((ITM->TER & 1UL ) != 0UL) ) /* ITM Port #0 enabled */ + { + while (ITM->PORT[0U].u32 == 0UL) + { + __NOP(); + } + ITM->PORT[0U].u8 = (uint8_t)ch; + } + return (ch); +} + + +/** + \brief ITM Receive Character + \details Inputs a character via the external variable \ref ITM_RxBuffer. + \return Received character. + \return -1 No character pending. + */ +__STATIC_INLINE int32_t ITM_ReceiveChar (void) +{ + int32_t ch = -1; /* no character available */ + + if (ITM_RxBuffer != ITM_RXBUFFER_EMPTY) + { + ch = ITM_RxBuffer; + ITM_RxBuffer = ITM_RXBUFFER_EMPTY; /* ready for next character */ + } + + return (ch); +} + + +/** + \brief ITM Check Character + \details Checks whether a character is pending for reading in the variable \ref ITM_RxBuffer. + \return 0 No character available. + \return 1 Character available. + */ +__STATIC_INLINE int32_t ITM_CheckChar (void) +{ + + if (ITM_RxBuffer == ITM_RXBUFFER_EMPTY) + { + return (0); /* no character available */ + } + else + { + return (1); /* character available */ + } +} + +/*@} end of CMSIS_core_DebugFunctions */ + + + + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_CM35P_H_DEPENDANT */ + +#endif /* __CMSIS_GENERIC */ diff --git a/lib/cmsis/inc/core_cm4.h b/lib/cmsis/inc/core_cm4.h index dc840ebf22..f205b333f3 100644 --- a/lib/cmsis/inc/core_cm4.h +++ b/lib/cmsis/inc/core_cm4.h @@ -1,40 +1,30 @@ /**************************************************************************//** * @file core_cm4.h * @brief CMSIS Cortex-M4 Core Peripheral Access Layer Header File - * @version V4.30 - * @date 20. October 2015 + * @version V5.1.0 + * @date 13. March 2019 ******************************************************************************/ -/* Copyright (c) 2009 - 2015 ARM LIMITED - - All rights reserved. - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 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. - - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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. - ---------------------------------------------------------------------------*/ - +/* + * Copyright (c) 2009-2019 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #if defined ( __ICCARM__ ) - #pragma system_include /* treat file as system include file for MISRA check */ -#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined (__clang__) #pragma clang system_header /* treat file as system include file */ #endif @@ -70,60 +60,22 @@ @{ */ -/* CMSIS CM4 definitions */ -#define __CM4_CMSIS_VERSION_MAIN (0x04U) /*!< [31:16] CMSIS HAL main version */ -#define __CM4_CMSIS_VERSION_SUB (0x1EU) /*!< [15:0] CMSIS HAL sub version */ +#include "cmsis_version.h" + +/* CMSIS CM4 definitions */ +#define __CM4_CMSIS_VERSION_MAIN (__CM_CMSIS_VERSION_MAIN) /*!< \deprecated [31:16] CMSIS HAL main version */ +#define __CM4_CMSIS_VERSION_SUB (__CM_CMSIS_VERSION_SUB) /*!< \deprecated [15:0] CMSIS HAL sub version */ #define __CM4_CMSIS_VERSION ((__CM4_CMSIS_VERSION_MAIN << 16U) | \ - __CM4_CMSIS_VERSION_SUB ) /*!< CMSIS HAL version number */ + __CM4_CMSIS_VERSION_SUB ) /*!< \deprecated CMSIS HAL version number */ -#define __CORTEX_M (0x04U) /*!< Cortex-M Core */ - - -#if defined ( __CC_ARM ) - #define __ASM __asm /*!< asm keyword for ARM Compiler */ - #define __INLINE __inline /*!< inline keyword for ARM Compiler */ - #define __STATIC_INLINE static __inline - -#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) - #define __ASM __asm /*!< asm keyword for ARM Compiler */ - #define __INLINE __inline /*!< inline keyword for ARM Compiler */ - #define __STATIC_INLINE static __inline - -#elif defined ( __GNUC__ ) - #define __ASM __asm /*!< asm keyword for GNU Compiler */ - #define __INLINE inline /*!< inline keyword for GNU Compiler */ - #define __STATIC_INLINE static inline - -#elif defined ( __ICCARM__ ) - #define __ASM __asm /*!< asm keyword for IAR Compiler */ - #define __INLINE inline /*!< inline keyword for IAR Compiler. Only available in High optimization mode! */ - #define __STATIC_INLINE static inline - -#elif defined ( __TMS470__ ) - #define __ASM __asm /*!< asm keyword for TI CCS Compiler */ - #define __STATIC_INLINE static inline - -#elif defined ( __TASKING__ ) - #define __ASM __asm /*!< asm keyword for TASKING Compiler */ - #define __INLINE inline /*!< inline keyword for TASKING Compiler */ - #define __STATIC_INLINE static inline - -#elif defined ( __CSMC__ ) - #define __packed - #define __ASM _asm /*!< asm keyword for COSMIC Compiler */ - #define __INLINE inline /*!< inline keyword for COSMIC Compiler. Use -pc99 on compile line */ - #define __STATIC_INLINE static inline - -#else - #error Unknown compiler -#endif +#define __CORTEX_M (4U) /*!< Cortex-M Core */ /** __FPU_USED indicates whether an FPU is used or not. For this, __FPU_PRESENT has to be checked prior to making use of FPU specific registers and functions. */ #if defined ( __CC_ARM ) #if defined __TARGET_FPU_VFP - #if (__FPU_PRESENT == 1U) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) #define __FPU_USED 1U #else #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" @@ -133,9 +85,9 @@ #define __FPU_USED 0U #endif -#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) - #if defined __ARM_PCS_VFP - #if (__FPU_PRESENT == 1) +#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #if defined __ARM_FP + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) #define __FPU_USED 1U #else #warning "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" @@ -147,7 +99,7 @@ #elif defined ( __GNUC__ ) #if defined (__VFP_FP__) && !defined(__SOFTFP__) - #if (__FPU_PRESENT == 1U) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) #define __FPU_USED 1U #else #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" @@ -159,7 +111,7 @@ #elif defined ( __ICCARM__ ) #if defined __ARMVFP__ - #if (__FPU_PRESENT == 1U) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) #define __FPU_USED 1U #else #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" @@ -169,9 +121,9 @@ #define __FPU_USED 0U #endif -#elif defined ( __TMS470__ ) +#elif defined ( __TI_ARM__ ) #if defined __TI_VFP_SUPPORT__ - #if (__FPU_PRESENT == 1U) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) #define __FPU_USED 1U #else #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" @@ -183,7 +135,7 @@ #elif defined ( __TASKING__ ) #if defined __FPU_VFP__ - #if (__FPU_PRESENT == 1U) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) #define __FPU_USED 1U #else #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" @@ -195,7 +147,7 @@ #elif defined ( __CSMC__ ) #if ( __CSMC__ & 0x400U) - #if (__FPU_PRESENT == 1U) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) #define __FPU_USED 1U #else #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" @@ -207,9 +159,8 @@ #endif -#include "core_cmInstr.h" /* Core Instruction Access */ -#include "core_cmFunc.h" /* Core Function Access */ -#include "core_cmSimd.h" /* Compiler specific SIMD Intrinsics */ +#include "cmsis_compiler.h" /* CMSIS compiler specific defines */ + #ifdef __cplusplus } @@ -244,7 +195,7 @@ #endif #ifndef __NVIC_PRIO_BITS - #define __NVIC_PRIO_BITS 4U + #define __NVIC_PRIO_BITS 3U #warning "__NVIC_PRIO_BITS not defined in device header file; using default!" #endif @@ -367,11 +318,12 @@ typedef union struct { uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ - uint32_t _reserved0:7; /*!< bit: 9..15 Reserved */ + uint32_t _reserved0:1; /*!< bit: 9 Reserved */ + uint32_t ICI_IT_1:6; /*!< bit: 10..15 ICI/IT part 1 */ uint32_t GE:4; /*!< bit: 16..19 Greater than or Equal flags */ uint32_t _reserved1:4; /*!< bit: 20..23 Reserved */ - uint32_t T:1; /*!< bit: 24 Thumb bit (read 0) */ - uint32_t IT:2; /*!< bit: 25..26 saved IT state (read 0) */ + uint32_t T:1; /*!< bit: 24 Thumb bit */ + uint32_t ICI_IT_2:2; /*!< bit: 25..26 ICI/IT part 2 */ uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ uint32_t C:1; /*!< bit: 29 Carry condition code flag */ @@ -397,8 +349,8 @@ typedef union #define xPSR_Q_Pos 27U /*!< xPSR: Q Position */ #define xPSR_Q_Msk (1UL << xPSR_Q_Pos) /*!< xPSR: Q Mask */ -#define xPSR_IT_Pos 25U /*!< xPSR: IT Position */ -#define xPSR_IT_Msk (3UL << xPSR_IT_Pos) /*!< xPSR: IT Mask */ +#define xPSR_ICI_IT_2_Pos 25U /*!< xPSR: ICI/IT part 2 Position */ +#define xPSR_ICI_IT_2_Msk (3UL << xPSR_ICI_IT_2_Pos) /*!< xPSR: ICI/IT part 2 Mask */ #define xPSR_T_Pos 24U /*!< xPSR: T Position */ #define xPSR_T_Msk (1UL << xPSR_T_Pos) /*!< xPSR: T Mask */ @@ -406,6 +358,9 @@ typedef union #define xPSR_GE_Pos 16U /*!< xPSR: GE Position */ #define xPSR_GE_Msk (0xFUL << xPSR_GE_Pos) /*!< xPSR: GE Mask */ +#define xPSR_ICI_IT_1_Pos 10U /*!< xPSR: ICI/IT part 1 Position */ +#define xPSR_ICI_IT_1_Msk (0x3FUL << xPSR_ICI_IT_1_Pos) /*!< xPSR: ICI/IT part 1 Mask */ + #define xPSR_ISR_Pos 0U /*!< xPSR: ISR Position */ #define xPSR_ISR_Msk (0x1FFUL /*<< xPSR_ISR_Pos*/) /*!< xPSR: ISR Mask */ @@ -453,7 +408,7 @@ typedef struct __IOM uint32_t ISER[8U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ uint32_t RESERVED0[24U]; __IOM uint32_t ICER[8U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ - uint32_t RSERVED1[24U]; + uint32_t RESERVED1[24U]; __IOM uint32_t ISPR[8U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ uint32_t RESERVED2[24U]; __IOM uint32_t ICPR[8U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ @@ -662,6 +617,66 @@ typedef struct #define SCB_CFSR_MEMFAULTSR_Pos 0U /*!< SCB CFSR: Memory Manage Fault Status Register Position */ #define SCB_CFSR_MEMFAULTSR_Msk (0xFFUL /*<< SCB_CFSR_MEMFAULTSR_Pos*/) /*!< SCB CFSR: Memory Manage Fault Status Register Mask */ +/* MemManage Fault Status Register (part of SCB Configurable Fault Status Register) */ +#define SCB_CFSR_MMARVALID_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 7U) /*!< SCB CFSR (MMFSR): MMARVALID Position */ +#define SCB_CFSR_MMARVALID_Msk (1UL << SCB_CFSR_MMARVALID_Pos) /*!< SCB CFSR (MMFSR): MMARVALID Mask */ + +#define SCB_CFSR_MLSPERR_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 5U) /*!< SCB CFSR (MMFSR): MLSPERR Position */ +#define SCB_CFSR_MLSPERR_Msk (1UL << SCB_CFSR_MLSPERR_Pos) /*!< SCB CFSR (MMFSR): MLSPERR Mask */ + +#define SCB_CFSR_MSTKERR_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 4U) /*!< SCB CFSR (MMFSR): MSTKERR Position */ +#define SCB_CFSR_MSTKERR_Msk (1UL << SCB_CFSR_MSTKERR_Pos) /*!< SCB CFSR (MMFSR): MSTKERR Mask */ + +#define SCB_CFSR_MUNSTKERR_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 3U) /*!< SCB CFSR (MMFSR): MUNSTKERR Position */ +#define SCB_CFSR_MUNSTKERR_Msk (1UL << SCB_CFSR_MUNSTKERR_Pos) /*!< SCB CFSR (MMFSR): MUNSTKERR Mask */ + +#define SCB_CFSR_DACCVIOL_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 1U) /*!< SCB CFSR (MMFSR): DACCVIOL Position */ +#define SCB_CFSR_DACCVIOL_Msk (1UL << SCB_CFSR_DACCVIOL_Pos) /*!< SCB CFSR (MMFSR): DACCVIOL Mask */ + +#define SCB_CFSR_IACCVIOL_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 0U) /*!< SCB CFSR (MMFSR): IACCVIOL Position */ +#define SCB_CFSR_IACCVIOL_Msk (1UL /*<< SCB_CFSR_IACCVIOL_Pos*/) /*!< SCB CFSR (MMFSR): IACCVIOL Mask */ + +/* BusFault Status Register (part of SCB Configurable Fault Status Register) */ +#define SCB_CFSR_BFARVALID_Pos (SCB_CFSR_BUSFAULTSR_Pos + 7U) /*!< SCB CFSR (BFSR): BFARVALID Position */ +#define SCB_CFSR_BFARVALID_Msk (1UL << SCB_CFSR_BFARVALID_Pos) /*!< SCB CFSR (BFSR): BFARVALID Mask */ + +#define SCB_CFSR_LSPERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 5U) /*!< SCB CFSR (BFSR): LSPERR Position */ +#define SCB_CFSR_LSPERR_Msk (1UL << SCB_CFSR_LSPERR_Pos) /*!< SCB CFSR (BFSR): LSPERR Mask */ + +#define SCB_CFSR_STKERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 4U) /*!< SCB CFSR (BFSR): STKERR Position */ +#define SCB_CFSR_STKERR_Msk (1UL << SCB_CFSR_STKERR_Pos) /*!< SCB CFSR (BFSR): STKERR Mask */ + +#define SCB_CFSR_UNSTKERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 3U) /*!< SCB CFSR (BFSR): UNSTKERR Position */ +#define SCB_CFSR_UNSTKERR_Msk (1UL << SCB_CFSR_UNSTKERR_Pos) /*!< SCB CFSR (BFSR): UNSTKERR Mask */ + +#define SCB_CFSR_IMPRECISERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 2U) /*!< SCB CFSR (BFSR): IMPRECISERR Position */ +#define SCB_CFSR_IMPRECISERR_Msk (1UL << SCB_CFSR_IMPRECISERR_Pos) /*!< SCB CFSR (BFSR): IMPRECISERR Mask */ + +#define SCB_CFSR_PRECISERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 1U) /*!< SCB CFSR (BFSR): PRECISERR Position */ +#define SCB_CFSR_PRECISERR_Msk (1UL << SCB_CFSR_PRECISERR_Pos) /*!< SCB CFSR (BFSR): PRECISERR Mask */ + +#define SCB_CFSR_IBUSERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 0U) /*!< SCB CFSR (BFSR): IBUSERR Position */ +#define SCB_CFSR_IBUSERR_Msk (1UL << SCB_CFSR_IBUSERR_Pos) /*!< SCB CFSR (BFSR): IBUSERR Mask */ + +/* UsageFault Status Register (part of SCB Configurable Fault Status Register) */ +#define SCB_CFSR_DIVBYZERO_Pos (SCB_CFSR_USGFAULTSR_Pos + 9U) /*!< SCB CFSR (UFSR): DIVBYZERO Position */ +#define SCB_CFSR_DIVBYZERO_Msk (1UL << SCB_CFSR_DIVBYZERO_Pos) /*!< SCB CFSR (UFSR): DIVBYZERO Mask */ + +#define SCB_CFSR_UNALIGNED_Pos (SCB_CFSR_USGFAULTSR_Pos + 8U) /*!< SCB CFSR (UFSR): UNALIGNED Position */ +#define SCB_CFSR_UNALIGNED_Msk (1UL << SCB_CFSR_UNALIGNED_Pos) /*!< SCB CFSR (UFSR): UNALIGNED Mask */ + +#define SCB_CFSR_NOCP_Pos (SCB_CFSR_USGFAULTSR_Pos + 3U) /*!< SCB CFSR (UFSR): NOCP Position */ +#define SCB_CFSR_NOCP_Msk (1UL << SCB_CFSR_NOCP_Pos) /*!< SCB CFSR (UFSR): NOCP Mask */ + +#define SCB_CFSR_INVPC_Pos (SCB_CFSR_USGFAULTSR_Pos + 2U) /*!< SCB CFSR (UFSR): INVPC Position */ +#define SCB_CFSR_INVPC_Msk (1UL << SCB_CFSR_INVPC_Pos) /*!< SCB CFSR (UFSR): INVPC Mask */ + +#define SCB_CFSR_INVSTATE_Pos (SCB_CFSR_USGFAULTSR_Pos + 1U) /*!< SCB CFSR (UFSR): INVSTATE Position */ +#define SCB_CFSR_INVSTATE_Msk (1UL << SCB_CFSR_INVSTATE_Pos) /*!< SCB CFSR (UFSR): INVSTATE Mask */ + +#define SCB_CFSR_UNDEFINSTR_Pos (SCB_CFSR_USGFAULTSR_Pos + 0U) /*!< SCB CFSR (UFSR): UNDEFINSTR Position */ +#define SCB_CFSR_UNDEFINSTR_Msk (1UL << SCB_CFSR_UNDEFINSTR_Pos) /*!< SCB CFSR (UFSR): UNDEFINSTR Mask */ + /* SCB Hard Fault Status Register Definitions */ #define SCB_HFSR_DEBUGEVT_Pos 31U /*!< SCB HFSR: DEBUGEVT Position */ #define SCB_HFSR_DEBUGEVT_Msk (1UL << SCB_HFSR_DEBUGEVT_Pos) /*!< SCB HFSR: DEBUGEVT Mask */ @@ -807,10 +822,7 @@ typedef struct __IOM uint32_t TPR; /*!< Offset: 0xE40 (R/W) ITM Trace Privilege Register */ uint32_t RESERVED2[15U]; __IOM uint32_t TCR; /*!< Offset: 0xE80 (R/W) ITM Trace Control Register */ - uint32_t RESERVED3[29U]; - __OM uint32_t IWR; /*!< Offset: 0xEF8 ( /W) ITM Integration Write Register */ - __IM uint32_t IRR; /*!< Offset: 0xEFC (R/ ) ITM Integration Read Register */ - __IOM uint32_t IMCR; /*!< Offset: 0xF00 (R/W) ITM Integration Mode Control Register */ + uint32_t RESERVED3[32U]; uint32_t RESERVED4[43U]; __OM uint32_t LAR; /*!< Offset: 0xFB0 ( /W) ITM Lock Access Register */ __IM uint32_t LSR; /*!< Offset: 0xFB4 (R/ ) ITM Lock Status Register */ @@ -831,7 +843,7 @@ typedef struct /* ITM Trace Privilege Register Definitions */ #define ITM_TPR_PRIVMASK_Pos 0U /*!< ITM TPR: PRIVMASK Position */ -#define ITM_TPR_PRIVMASK_Msk (0xFUL /*<< ITM_TPR_PRIVMASK_Pos*/) /*!< ITM TPR: PRIVMASK Mask */ +#define ITM_TPR_PRIVMASK_Msk (0xFFFFFFFFUL /*<< ITM_TPR_PRIVMASK_Pos*/) /*!< ITM TPR: PRIVMASK Mask */ /* ITM Trace Control Register Definitions */ #define ITM_TCR_BUSY_Pos 23U /*!< ITM TCR: BUSY Position */ @@ -861,18 +873,6 @@ typedef struct #define ITM_TCR_ITMENA_Pos 0U /*!< ITM TCR: ITM Enable bit Position */ #define ITM_TCR_ITMENA_Msk (1UL /*<< ITM_TCR_ITMENA_Pos*/) /*!< ITM TCR: ITM Enable bit Mask */ -/* ITM Integration Write Register Definitions */ -#define ITM_IWR_ATVALIDM_Pos 0U /*!< ITM IWR: ATVALIDM Position */ -#define ITM_IWR_ATVALIDM_Msk (1UL /*<< ITM_IWR_ATVALIDM_Pos*/) /*!< ITM IWR: ATVALIDM Mask */ - -/* ITM Integration Read Register Definitions */ -#define ITM_IRR_ATREADYM_Pos 0U /*!< ITM IRR: ATREADYM Position */ -#define ITM_IRR_ATREADYM_Msk (1UL /*<< ITM_IRR_ATREADYM_Pos*/) /*!< ITM IRR: ATREADYM Mask */ - -/* ITM Integration Mode Control Register Definitions */ -#define ITM_IMCR_INTEGRATION_Pos 0U /*!< ITM IMCR: INTEGRATION Position */ -#define ITM_IMCR_INTEGRATION_Msk (1UL /*<< ITM_IMCR_INTEGRATION_Pos*/) /*!< ITM IMCR: INTEGRATION Mask */ - /* ITM Lock Status Register Definitions */ #define ITM_LSR_ByteAcc_Pos 2U /*!< ITM LSR: ByteAcc Position */ #define ITM_LSR_ByteAcc_Msk (1UL << ITM_LSR_ByteAcc_Pos) /*!< ITM LSR: ByteAcc Mask */ @@ -1045,7 +1045,7 @@ typedef struct */ typedef struct { - __IOM uint32_t SSPSR; /*!< Offset: 0x000 (R/ ) Supported Parallel Port Size Register */ + __IM uint32_t SSPSR; /*!< Offset: 0x000 (R/ ) Supported Parallel Port Size Register */ __IOM uint32_t CSPSR; /*!< Offset: 0x004 (R/W) Current Parallel Port Size Register */ uint32_t RESERVED0[2U]; __IOM uint32_t ACPR; /*!< Offset: 0x010 (R/W) Asynchronous Clock Prescaler Register */ @@ -1056,7 +1056,7 @@ typedef struct __IOM uint32_t FFCR; /*!< Offset: 0x304 (R/W) Formatter and Flush Control Register */ __IM uint32_t FSCR; /*!< Offset: 0x308 (R/ ) Formatter Synchronization Counter Register */ uint32_t RESERVED3[759U]; - __IM uint32_t TRIGGER; /*!< Offset: 0xEE8 (R/ ) TRIGGER */ + __IM uint32_t TRIGGER; /*!< Offset: 0xEE8 (R/ ) TRIGGER Register */ __IM uint32_t FIFO0; /*!< Offset: 0xEEC (R/ ) Integration ETM Data */ __IM uint32_t ITATBCTR2; /*!< Offset: 0xEF0 (R/ ) ITATBCTR2 */ uint32_t RESERVED4[1U]; @@ -1105,13 +1105,13 @@ typedef struct /* TPI Integration ETM Data Register Definitions (FIFO0) */ #define TPI_FIFO0_ITM_ATVALID_Pos 29U /*!< TPI FIFO0: ITM_ATVALID Position */ -#define TPI_FIFO0_ITM_ATVALID_Msk (0x3UL << TPI_FIFO0_ITM_ATVALID_Pos) /*!< TPI FIFO0: ITM_ATVALID Mask */ +#define TPI_FIFO0_ITM_ATVALID_Msk (0x1UL << TPI_FIFO0_ITM_ATVALID_Pos) /*!< TPI FIFO0: ITM_ATVALID Mask */ #define TPI_FIFO0_ITM_bytecount_Pos 27U /*!< TPI FIFO0: ITM_bytecount Position */ #define TPI_FIFO0_ITM_bytecount_Msk (0x3UL << TPI_FIFO0_ITM_bytecount_Pos) /*!< TPI FIFO0: ITM_bytecount Mask */ #define TPI_FIFO0_ETM_ATVALID_Pos 26U /*!< TPI FIFO0: ETM_ATVALID Position */ -#define TPI_FIFO0_ETM_ATVALID_Msk (0x3UL << TPI_FIFO0_ETM_ATVALID_Pos) /*!< TPI FIFO0: ETM_ATVALID Mask */ +#define TPI_FIFO0_ETM_ATVALID_Msk (0x1UL << TPI_FIFO0_ETM_ATVALID_Pos) /*!< TPI FIFO0: ETM_ATVALID Mask */ #define TPI_FIFO0_ETM_bytecount_Pos 24U /*!< TPI FIFO0: ETM_bytecount Position */ #define TPI_FIFO0_ETM_bytecount_Msk (0x3UL << TPI_FIFO0_ETM_bytecount_Pos) /*!< TPI FIFO0: ETM_bytecount Mask */ @@ -1126,18 +1126,21 @@ typedef struct #define TPI_FIFO0_ETM0_Msk (0xFFUL /*<< TPI_FIFO0_ETM0_Pos*/) /*!< TPI FIFO0: ETM0 Mask */ /* TPI ITATBCTR2 Register Definitions */ -#define TPI_ITATBCTR2_ATREADY_Pos 0U /*!< TPI ITATBCTR2: ATREADY Position */ -#define TPI_ITATBCTR2_ATREADY_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY_Pos*/) /*!< TPI ITATBCTR2: ATREADY Mask */ +#define TPI_ITATBCTR2_ATREADY2_Pos 0U /*!< TPI ITATBCTR2: ATREADY2 Position */ +#define TPI_ITATBCTR2_ATREADY2_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY2_Pos*/) /*!< TPI ITATBCTR2: ATREADY2 Mask */ + +#define TPI_ITATBCTR2_ATREADY1_Pos 0U /*!< TPI ITATBCTR2: ATREADY1 Position */ +#define TPI_ITATBCTR2_ATREADY1_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY1_Pos*/) /*!< TPI ITATBCTR2: ATREADY1 Mask */ /* TPI Integration ITM Data Register Definitions (FIFO1) */ #define TPI_FIFO1_ITM_ATVALID_Pos 29U /*!< TPI FIFO1: ITM_ATVALID Position */ -#define TPI_FIFO1_ITM_ATVALID_Msk (0x3UL << TPI_FIFO1_ITM_ATVALID_Pos) /*!< TPI FIFO1: ITM_ATVALID Mask */ +#define TPI_FIFO1_ITM_ATVALID_Msk (0x1UL << TPI_FIFO1_ITM_ATVALID_Pos) /*!< TPI FIFO1: ITM_ATVALID Mask */ #define TPI_FIFO1_ITM_bytecount_Pos 27U /*!< TPI FIFO1: ITM_bytecount Position */ #define TPI_FIFO1_ITM_bytecount_Msk (0x3UL << TPI_FIFO1_ITM_bytecount_Pos) /*!< TPI FIFO1: ITM_bytecount Mask */ #define TPI_FIFO1_ETM_ATVALID_Pos 26U /*!< TPI FIFO1: ETM_ATVALID Position */ -#define TPI_FIFO1_ETM_ATVALID_Msk (0x3UL << TPI_FIFO1_ETM_ATVALID_Pos) /*!< TPI FIFO1: ETM_ATVALID Mask */ +#define TPI_FIFO1_ETM_ATVALID_Msk (0x1UL << TPI_FIFO1_ETM_ATVALID_Pos) /*!< TPI FIFO1: ETM_ATVALID Mask */ #define TPI_FIFO1_ETM_bytecount_Pos 24U /*!< TPI FIFO1: ETM_bytecount Position */ #define TPI_FIFO1_ETM_bytecount_Msk (0x3UL << TPI_FIFO1_ETM_bytecount_Pos) /*!< TPI FIFO1: ETM_bytecount Mask */ @@ -1152,12 +1155,15 @@ typedef struct #define TPI_FIFO1_ITM0_Msk (0xFFUL /*<< TPI_FIFO1_ITM0_Pos*/) /*!< TPI FIFO1: ITM0 Mask */ /* TPI ITATBCTR0 Register Definitions */ -#define TPI_ITATBCTR0_ATREADY_Pos 0U /*!< TPI ITATBCTR0: ATREADY Position */ -#define TPI_ITATBCTR0_ATREADY_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY_Pos*/) /*!< TPI ITATBCTR0: ATREADY Mask */ +#define TPI_ITATBCTR0_ATREADY2_Pos 0U /*!< TPI ITATBCTR0: ATREADY2 Position */ +#define TPI_ITATBCTR0_ATREADY2_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY2_Pos*/) /*!< TPI ITATBCTR0: ATREADY2 Mask */ + +#define TPI_ITATBCTR0_ATREADY1_Pos 0U /*!< TPI ITATBCTR0: ATREADY1 Position */ +#define TPI_ITATBCTR0_ATREADY1_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY1_Pos*/) /*!< TPI ITATBCTR0: ATREADY1 Mask */ /* TPI Integration Mode Control Register Definitions */ #define TPI_ITCTRL_Mode_Pos 0U /*!< TPI ITCTRL: Mode Position */ -#define TPI_ITCTRL_Mode_Msk (0x1UL /*<< TPI_ITCTRL_Mode_Pos*/) /*!< TPI ITCTRL: Mode Mask */ +#define TPI_ITCTRL_Mode_Msk (0x3UL /*<< TPI_ITCTRL_Mode_Pos*/) /*!< TPI ITCTRL: Mode Mask */ /* TPI DEVID Register Definitions */ #define TPI_DEVID_NRZVALID_Pos 11U /*!< TPI DEVID: NRZVALID Position */ @@ -1179,16 +1185,16 @@ typedef struct #define TPI_DEVID_NrTraceInput_Msk (0x1FUL /*<< TPI_DEVID_NrTraceInput_Pos*/) /*!< TPI DEVID: NrTraceInput Mask */ /* TPI DEVTYPE Register Definitions */ -#define TPI_DEVTYPE_MajorType_Pos 4U /*!< TPI DEVTYPE: MajorType Position */ -#define TPI_DEVTYPE_MajorType_Msk (0xFUL << TPI_DEVTYPE_MajorType_Pos) /*!< TPI DEVTYPE: MajorType Mask */ - -#define TPI_DEVTYPE_SubType_Pos 0U /*!< TPI DEVTYPE: SubType Position */ +#define TPI_DEVTYPE_SubType_Pos 4U /*!< TPI DEVTYPE: SubType Position */ #define TPI_DEVTYPE_SubType_Msk (0xFUL /*<< TPI_DEVTYPE_SubType_Pos*/) /*!< TPI DEVTYPE: SubType Mask */ +#define TPI_DEVTYPE_MajorType_Pos 0U /*!< TPI DEVTYPE: MajorType Position */ +#define TPI_DEVTYPE_MajorType_Msk (0xFUL << TPI_DEVTYPE_MajorType_Pos) /*!< TPI DEVTYPE: MajorType Mask */ + /*@}*/ /* end of group CMSIS_TPI */ -#if (__MPU_PRESENT == 1U) +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) /** \ingroup CMSIS_core_register \defgroup CMSIS_MPU Memory Protection Unit (MPU) @@ -1214,6 +1220,8 @@ typedef struct __IOM uint32_t RASR_A3; /*!< Offset: 0x028 (R/W) MPU Alias 3 Region Attribute and Size Register */ } MPU_Type; +#define MPU_TYPE_RALIASES 4U + /* MPU Type Register Definitions */ #define MPU_TYPE_IREGION_Pos 16U /*!< MPU TYPE: IREGION Position */ #define MPU_TYPE_IREGION_Msk (0xFFUL << MPU_TYPE_IREGION_Pos) /*!< MPU TYPE: IREGION Mask */ @@ -1280,10 +1288,9 @@ typedef struct #define MPU_RASR_ENABLE_Msk (1UL /*<< MPU_RASR_ENABLE_Pos*/) /*!< MPU RASR: Region enable bit Disable Mask */ /*@} end of group CMSIS_MPU */ -#endif +#endif /* defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) */ -#if (__FPU_PRESENT == 1U) /** \ingroup CMSIS_core_register \defgroup CMSIS_FPU Floating Point Unit (FPU) @@ -1302,6 +1309,7 @@ typedef struct __IOM uint32_t FPDSCR; /*!< Offset: 0x00C (R/W) Floating-Point Default Status Control Register */ __IM uint32_t MVFR0; /*!< Offset: 0x010 (R/ ) Media and FP Feature Register 0 */ __IM uint32_t MVFR1; /*!< Offset: 0x014 (R/ ) Media and FP Feature Register 1 */ + __IM uint32_t MVFR2; /*!< Offset: 0x018 (R/ ) Media and FP Feature Register 2 */ } FPU_Type; /* Floating-Point Context Control Register Definitions */ @@ -1387,8 +1395,12 @@ typedef struct #define FPU_MVFR1_FtZ_mode_Pos 0U /*!< MVFR1: FtZ mode bits Position */ #define FPU_MVFR1_FtZ_mode_Msk (0xFUL /*<< FPU_MVFR1_FtZ_mode_Pos*/) /*!< MVFR1: FtZ mode bits Mask */ +/* Media and FP Feature Register 2 Definitions */ + +#define FPU_MVFR2_VFP_Misc_Pos 4U /*!< MVFR2: VFP Misc bits Position */ +#define FPU_MVFR2_VFP_Misc_Msk (0xFUL << FPU_MVFR2_VFP_Misc_Pos) /*!< MVFR2: VFP Misc bits Mask */ + /*@} end of group CMSIS_FPU */ -#endif /** @@ -1506,18 +1518,18 @@ typedef struct /** \brief Mask and shift a bit field value for use in a register bit range. \param[in] field Name of the register bit field. - \param[in] value Value of the bit field. + \param[in] value Value of the bit field. This parameter is interpreted as an uint32_t type. \return Masked and shifted value. */ -#define _VAL2FLD(field, value) ((value << field ## _Pos) & field ## _Msk) +#define _VAL2FLD(field, value) (((uint32_t)(value) << field ## _Pos) & field ## _Msk) /** \brief Mask and shift a register value to extract a bit filed value. \param[in] field Name of the register bit field. - \param[in] value Value of register. + \param[in] value Value of register. This parameter is interpreted as an uint32_t type. \return Masked and shifted bit field value. */ -#define _FLD2VAL(field, value) ((value & field ## _Msk) >> field ## _Pos) +#define _FLD2VAL(field, value) (((uint32_t)(value) & field ## _Msk) >> field ## _Pos) /*@} end of group CMSIS_core_bitfield */ @@ -1529,7 +1541,7 @@ typedef struct @{ */ -/* Memory mapping of Cortex-M4 Hardware */ +/* Memory mapping of Core Hardware */ #define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ #define ITM_BASE (0xE0000000UL) /*!< ITM Base Address */ #define DWT_BASE (0xE0001000UL) /*!< DWT Base Address */ @@ -1548,15 +1560,13 @@ typedef struct #define TPI ((TPI_Type *) TPI_BASE ) /*!< TPI configuration struct */ #define CoreDebug ((CoreDebug_Type *) CoreDebug_BASE) /*!< Core Debug configuration struct */ -#if (__MPU_PRESENT == 1U) +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) #define MPU_BASE (SCS_BASE + 0x0D90UL) /*!< Memory Protection Unit */ #define MPU ((MPU_Type *) MPU_BASE ) /*!< Memory Protection Unit */ #endif -#if (__FPU_PRESENT == 1U) - #define FPU_BASE (SCS_BASE + 0x0F30UL) /*!< Floating Point Unit */ - #define FPU ((FPU_Type *) FPU_BASE ) /*!< Floating Point Unit */ -#endif +#define FPU_BASE (SCS_BASE + 0x0F30UL) /*!< Floating Point Unit */ +#define FPU ((FPU_Type *) FPU_BASE ) /*!< Floating Point Unit */ /*@} */ @@ -1584,6 +1594,48 @@ typedef struct @{ */ +#ifdef CMSIS_NVIC_VIRTUAL + #ifndef CMSIS_NVIC_VIRTUAL_HEADER_FILE + #define CMSIS_NVIC_VIRTUAL_HEADER_FILE "cmsis_nvic_virtual.h" + #endif + #include CMSIS_NVIC_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetPriorityGrouping __NVIC_SetPriorityGrouping + #define NVIC_GetPriorityGrouping __NVIC_GetPriorityGrouping + #define NVIC_EnableIRQ __NVIC_EnableIRQ + #define NVIC_GetEnableIRQ __NVIC_GetEnableIRQ + #define NVIC_DisableIRQ __NVIC_DisableIRQ + #define NVIC_GetPendingIRQ __NVIC_GetPendingIRQ + #define NVIC_SetPendingIRQ __NVIC_SetPendingIRQ + #define NVIC_ClearPendingIRQ __NVIC_ClearPendingIRQ + #define NVIC_GetActive __NVIC_GetActive + #define NVIC_SetPriority __NVIC_SetPriority + #define NVIC_GetPriority __NVIC_GetPriority + #define NVIC_SystemReset __NVIC_SystemReset +#endif /* CMSIS_NVIC_VIRTUAL */ + +#ifdef CMSIS_VECTAB_VIRTUAL + #ifndef CMSIS_VECTAB_VIRTUAL_HEADER_FILE + #define CMSIS_VECTAB_VIRTUAL_HEADER_FILE "cmsis_vectab_virtual.h" + #endif + #include CMSIS_VECTAB_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetVector __NVIC_SetVector + #define NVIC_GetVector __NVIC_GetVector +#endif /* (CMSIS_VECTAB_VIRTUAL) */ + +#define NVIC_USER_IRQ_OFFSET 16 + + +/* The following EXC_RETURN values are saved the LR on exception entry */ +#define EXC_RETURN_HANDLER (0xFFFFFFF1UL) /* return to Handler mode, uses MSP after return */ +#define EXC_RETURN_THREAD_MSP (0xFFFFFFF9UL) /* return to Thread mode, uses MSP after return */ +#define EXC_RETURN_THREAD_PSP (0xFFFFFFFDUL) /* return to Thread mode, uses PSP after return */ +#define EXC_RETURN_HANDLER_FPU (0xFFFFFFE1UL) /* return to Handler mode, uses MSP after return, restore floating-point state */ +#define EXC_RETURN_THREAD_MSP_FPU (0xFFFFFFE9UL) /* return to Thread mode, uses MSP after return, restore floating-point state */ +#define EXC_RETURN_THREAD_PSP_FPU (0xFFFFFFEDUL) /* return to Thread mode, uses PSP after return, restore floating-point state */ + + /** \brief Set Priority Grouping \details Sets the priority grouping field using the required unlock sequence. @@ -1593,7 +1645,7 @@ typedef struct priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. \param [in] PriorityGroup Priority grouping field. */ -__STATIC_INLINE void NVIC_SetPriorityGrouping(uint32_t PriorityGroup) +__STATIC_INLINE void __NVIC_SetPriorityGrouping(uint32_t PriorityGroup) { uint32_t reg_value; uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ @@ -1602,7 +1654,7 @@ __STATIC_INLINE void NVIC_SetPriorityGrouping(uint32_t PriorityGroup) reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk)); /* clear bits to change */ reg_value = (reg_value | ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | - (PriorityGroupTmp << 8U) ); /* Insert write key and priorty group */ + (PriorityGroupTmp << SCB_AIRCR_PRIGROUP_Pos) ); /* Insert write key and priority group */ SCB->AIRCR = reg_value; } @@ -1612,121 +1664,178 @@ __STATIC_INLINE void NVIC_SetPriorityGrouping(uint32_t PriorityGroup) \details Reads the priority grouping field from the NVIC Interrupt Controller. \return Priority grouping field (SCB->AIRCR [10:8] PRIGROUP field). */ -__STATIC_INLINE uint32_t NVIC_GetPriorityGrouping(void) +__STATIC_INLINE uint32_t __NVIC_GetPriorityGrouping(void) { return ((uint32_t)((SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) >> SCB_AIRCR_PRIGROUP_Pos)); } /** - \brief Enable External Interrupt - \details Enables a device-specific interrupt in the NVIC interrupt controller. - \param [in] IRQn External interrupt number. Value cannot be negative. + \brief Enable Interrupt + \details Enables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. */ -__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn) +__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn) { - NVIC->ISER[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } } /** - \brief Disable External Interrupt - \details Disables a device-specific interrupt in the NVIC interrupt controller. - \param [in] IRQn External interrupt number. Value cannot be negative. + \brief Get Interrupt Enable status + \details Returns a device specific interrupt enable status from the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt is not enabled. + \return 1 Interrupt is enabled. + \note IRQn must not be negative. */ -__STATIC_INLINE void NVIC_DisableIRQ(IRQn_Type IRQn) +__STATIC_INLINE uint32_t __NVIC_GetEnableIRQ(IRQn_Type IRQn) { - NVIC->ICER[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Disable Interrupt + \details Disables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_DisableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + __DSB(); + __ISB(); + } } /** \brief Get Pending Interrupt - \details Reads the pending register in the NVIC and returns the pending bit for the specified interrupt. - \param [in] IRQn Interrupt number. + \details Reads the NVIC pending register and returns the pending bit for the specified device specific interrupt. + \param [in] IRQn Device specific interrupt number. \return 0 Interrupt status is not pending. \return 1 Interrupt status is pending. + \note IRQn must not be negative. */ -__STATIC_INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn) +__STATIC_INLINE uint32_t __NVIC_GetPendingIRQ(IRQn_Type IRQn) { - return((uint32_t)(((NVIC->ISPR[(((uint32_t)(int32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } } /** \brief Set Pending Interrupt - \details Sets the pending bit of an external interrupt. - \param [in] IRQn Interrupt number. Value cannot be negative. + \details Sets the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. */ -__STATIC_INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn) +__STATIC_INLINE void __NVIC_SetPendingIRQ(IRQn_Type IRQn) { - NVIC->ISPR[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } } /** \brief Clear Pending Interrupt - \details Clears the pending bit of an external interrupt. - \param [in] IRQn External interrupt number. Value cannot be negative. + \details Clears the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. */ -__STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn) +__STATIC_INLINE void __NVIC_ClearPendingIRQ(IRQn_Type IRQn) { - NVIC->ICPR[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } } /** \brief Get Active Interrupt - \details Reads the active register in NVIC and returns the active bit. - \param [in] IRQn Interrupt number. + \details Reads the active register in the NVIC and returns the active bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. \return 0 Interrupt status is not active. \return 1 Interrupt status is active. + \note IRQn must not be negative. */ -__STATIC_INLINE uint32_t NVIC_GetActive(IRQn_Type IRQn) +__STATIC_INLINE uint32_t __NVIC_GetActive(IRQn_Type IRQn) { - return((uint32_t)(((NVIC->IABR[(((uint32_t)(int32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->IABR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } } /** \brief Set Interrupt Priority - \details Sets the priority of an interrupt. - \note The priority cannot be set for every core interrupt. + \details Sets the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. \param [in] IRQn Interrupt number. \param [in] priority Priority to set. + \note The priority cannot be set for every processor exception. */ -__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +__STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) { - if ((int32_t)(IRQn) < 0) + if ((int32_t)(IRQn) >= 0) { - SCB->SHP[(((uint32_t)(int32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + NVIC->IP[((uint32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); } else { - NVIC->IP[((uint32_t)(int32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + SCB->SHP[(((uint32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); } } /** \brief Get Interrupt Priority - \details Reads the priority of an interrupt. - The interrupt number can be positive to specify an external (device specific) interrupt, - or negative to specify an internal (core) interrupt. + \details Reads the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. \param [in] IRQn Interrupt number. \return Interrupt Priority. Value is aligned automatically to the implemented priority bits of the microcontroller. */ -__STATIC_INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn) +__STATIC_INLINE uint32_t __NVIC_GetPriority(IRQn_Type IRQn) { - if ((int32_t)(IRQn) < 0) + if ((int32_t)(IRQn) >= 0) { - return(((uint32_t)SCB->SHP[(((uint32_t)(int32_t)IRQn) & 0xFUL)-4UL] >> (8U - __NVIC_PRIO_BITS))); + return(((uint32_t)NVIC->IP[((uint32_t)IRQn)] >> (8U - __NVIC_PRIO_BITS))); } else { - return(((uint32_t)NVIC->IP[((uint32_t)(int32_t)IRQn)] >> (8U - __NVIC_PRIO_BITS))); + return(((uint32_t)SCB->SHP[(((uint32_t)IRQn) & 0xFUL)-4UL] >> (8U - __NVIC_PRIO_BITS))); } } @@ -1783,11 +1892,42 @@ __STATIC_INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGr } +/** + \brief Set Interrupt Vector + \details Sets an interrupt vector in SRAM based interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + VTOR must been relocated to SRAM before. + \param [in] IRQn Interrupt number + \param [in] vector Address of interrupt handler function + */ +__STATIC_INLINE void __NVIC_SetVector(IRQn_Type IRQn, uint32_t vector) +{ + uint32_t vectors = (uint32_t )SCB->VTOR; + (* (int *) (vectors + ((int32_t)IRQn + NVIC_USER_IRQ_OFFSET) * 4)) = vector; +} + + +/** + \brief Get Interrupt Vector + \details Reads an interrupt vector from interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Address of interrupt handler function + */ +__STATIC_INLINE uint32_t __NVIC_GetVector(IRQn_Type IRQn) +{ + uint32_t vectors = (uint32_t )SCB->VTOR; + return (uint32_t)(* (int *) (vectors + ((int32_t)IRQn + NVIC_USER_IRQ_OFFSET) * 4)); +} + + /** \brief System Reset \details Initiates a system reset request to reset the MCU. */ -__STATIC_INLINE void NVIC_SystemReset(void) +__NO_RETURN __STATIC_INLINE void __NVIC_SystemReset(void) { __DSB(); /* Ensure all outstanding memory accesses included buffered write are completed before reset */ @@ -1805,6 +1945,50 @@ __STATIC_INLINE void NVIC_SystemReset(void) /*@} end of CMSIS_Core_NVICFunctions */ +/* ########################## MPU functions #################################### */ + +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + +#include "mpu_armv7.h" + +#endif + + +/* ########################## FPU functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_FpuFunctions FPU Functions + \brief Function that provides FPU type. + @{ + */ + +/** + \brief get FPU type + \details returns the FPU type + \returns + - \b 0: No FPU + - \b 1: Single precision FPU + - \b 2: Double + Single precision FPU + */ +__STATIC_INLINE uint32_t SCB_GetFPUType(void) +{ + uint32_t mvfr0; + + mvfr0 = FPU->MVFR0; + if ((mvfr0 & (FPU_MVFR0_Single_precision_Msk | FPU_MVFR0_Double_precision_Msk)) == 0x020U) + { + return 1U; /* Single precision FPU */ + } + else + { + return 0U; /* No FPU */ + } +} + + +/*@} end of CMSIS_Core_FpuFunctions */ + + /* ################################## SysTick function ############################################ */ /** @@ -1814,7 +1998,7 @@ __STATIC_INLINE void NVIC_SystemReset(void) @{ */ -#if (__Vendor_SysTickConfig == 0U) +#if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U) /** \brief System Tick Configuration @@ -1857,8 +2041,8 @@ __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) @{ */ -extern volatile int32_t ITM_RxBuffer; /*!< External variable to receive characters. */ -#define ITM_RXBUFFER_EMPTY 0x5AA55AA5U /*!< Value identifying \ref ITM_RxBuffer is ready for next character. */ +extern volatile int32_t ITM_RxBuffer; /*!< External variable to receive characters. */ +#define ITM_RXBUFFER_EMPTY ((int32_t)0x5AA55AA5U) /*!< Value identifying \ref ITM_RxBuffer is ready for next character. */ /** diff --git a/lib/cmsis/inc/core_cm7.h b/lib/cmsis/inc/core_cm7.h index 3b7530ad50..41f9afb64d 100644 --- a/lib/cmsis/inc/core_cm7.h +++ b/lib/cmsis/inc/core_cm7.h @@ -1,40 +1,30 @@ /**************************************************************************//** * @file core_cm7.h * @brief CMSIS Cortex-M7 Core Peripheral Access Layer Header File - * @version V4.30 - * @date 20. October 2015 + * @version V5.1.0 + * @date 13. March 2019 ******************************************************************************/ -/* Copyright (c) 2009 - 2015 ARM LIMITED - - All rights reserved. - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 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. - - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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. - ---------------------------------------------------------------------------*/ - +/* + * Copyright (c) 2009-2019 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #if defined ( __ICCARM__ ) - #pragma system_include /* treat file as system include file for MISRA check */ -#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined (__clang__) #pragma clang system_header /* treat file as system include file */ #endif @@ -70,60 +60,22 @@ @{ */ -/* CMSIS CM7 definitions */ -#define __CM7_CMSIS_VERSION_MAIN (0x04U) /*!< [31:16] CMSIS HAL main version */ -#define __CM7_CMSIS_VERSION_SUB (0x1EU) /*!< [15:0] CMSIS HAL sub version */ +#include "cmsis_version.h" + +/* CMSIS CM7 definitions */ +#define __CM7_CMSIS_VERSION_MAIN (__CM_CMSIS_VERSION_MAIN) /*!< \deprecated [31:16] CMSIS HAL main version */ +#define __CM7_CMSIS_VERSION_SUB ( __CM_CMSIS_VERSION_SUB) /*!< \deprecated [15:0] CMSIS HAL sub version */ #define __CM7_CMSIS_VERSION ((__CM7_CMSIS_VERSION_MAIN << 16U) | \ - __CM7_CMSIS_VERSION_SUB ) /*!< CMSIS HAL version number */ + __CM7_CMSIS_VERSION_SUB ) /*!< \deprecated CMSIS HAL version number */ -#define __CORTEX_M (0x07U) /*!< Cortex-M Core */ - - -#if defined ( __CC_ARM ) - #define __ASM __asm /*!< asm keyword for ARM Compiler */ - #define __INLINE __inline /*!< inline keyword for ARM Compiler */ - #define __STATIC_INLINE static __inline - -#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) - #define __ASM __asm /*!< asm keyword for ARM Compiler */ - #define __INLINE __inline /*!< inline keyword for ARM Compiler */ - #define __STATIC_INLINE static __inline - -#elif defined ( __GNUC__ ) - #define __ASM __asm /*!< asm keyword for GNU Compiler */ - #define __INLINE inline /*!< inline keyword for GNU Compiler */ - #define __STATIC_INLINE static inline - -#elif defined ( __ICCARM__ ) - #define __ASM __asm /*!< asm keyword for IAR Compiler */ - #define __INLINE inline /*!< inline keyword for IAR Compiler. Only available in High optimization mode! */ - #define __STATIC_INLINE static inline - -#elif defined ( __TMS470__ ) - #define __ASM __asm /*!< asm keyword for TI CCS Compiler */ - #define __STATIC_INLINE static inline - -#elif defined ( __TASKING__ ) - #define __ASM __asm /*!< asm keyword for TASKING Compiler */ - #define __INLINE inline /*!< inline keyword for TASKING Compiler */ - #define __STATIC_INLINE static inline - -#elif defined ( __CSMC__ ) - #define __packed - #define __ASM _asm /*!< asm keyword for COSMIC Compiler */ - #define __INLINE inline /*!< inline keyword for COSMIC Compiler. Use -pc99 on compile line */ - #define __STATIC_INLINE static inline - -#else - #error Unknown compiler -#endif +#define __CORTEX_M (7U) /*!< Cortex-M Core */ /** __FPU_USED indicates whether an FPU is used or not. For this, __FPU_PRESENT has to be checked prior to making use of FPU specific registers and functions. */ #if defined ( __CC_ARM ) #if defined __TARGET_FPU_VFP - #if (__FPU_PRESENT == 1U) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) #define __FPU_USED 1U #else #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" @@ -133,9 +85,9 @@ #define __FPU_USED 0U #endif -#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) - #if defined __ARM_PCS_VFP - #if (__FPU_PRESENT == 1) +#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #if defined __ARM_FP + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) #define __FPU_USED 1U #else #warning "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" @@ -147,7 +99,7 @@ #elif defined ( __GNUC__ ) #if defined (__VFP_FP__) && !defined(__SOFTFP__) - #if (__FPU_PRESENT == 1U) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) #define __FPU_USED 1U #else #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" @@ -159,7 +111,7 @@ #elif defined ( __ICCARM__ ) #if defined __ARMVFP__ - #if (__FPU_PRESENT == 1U) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) #define __FPU_USED 1U #else #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" @@ -169,9 +121,9 @@ #define __FPU_USED 0U #endif -#elif defined ( __TMS470__ ) +#elif defined ( __TI_ARM__ ) #if defined __TI_VFP_SUPPORT__ - #if (__FPU_PRESENT == 1U) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) #define __FPU_USED 1U #else #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" @@ -183,7 +135,7 @@ #elif defined ( __TASKING__ ) #if defined __FPU_VFP__ - #if (__FPU_PRESENT == 1U) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) #define __FPU_USED 1U #else #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" @@ -195,7 +147,7 @@ #elif defined ( __CSMC__ ) #if ( __CSMC__ & 0x400U) - #if (__FPU_PRESENT == 1U) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) #define __FPU_USED 1U #else #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" @@ -207,9 +159,8 @@ #endif -#include "core_cmInstr.h" /* Core Instruction Access */ -#include "core_cmFunc.h" /* Core Function Access */ -#include "core_cmSimd.h" /* Compiler specific SIMD Intrinsics */ +#include "cmsis_compiler.h" /* CMSIS compiler specific defines */ + #ifdef __cplusplus } @@ -382,11 +333,12 @@ typedef union struct { uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ - uint32_t _reserved0:7; /*!< bit: 9..15 Reserved */ + uint32_t _reserved0:1; /*!< bit: 9 Reserved */ + uint32_t ICI_IT_1:6; /*!< bit: 10..15 ICI/IT part 1 */ uint32_t GE:4; /*!< bit: 16..19 Greater than or Equal flags */ uint32_t _reserved1:4; /*!< bit: 20..23 Reserved */ - uint32_t T:1; /*!< bit: 24 Thumb bit (read 0) */ - uint32_t IT:2; /*!< bit: 25..26 saved IT state (read 0) */ + uint32_t T:1; /*!< bit: 24 Thumb bit */ + uint32_t ICI_IT_2:2; /*!< bit: 25..26 ICI/IT part 2 */ uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ uint32_t C:1; /*!< bit: 29 Carry condition code flag */ @@ -412,8 +364,8 @@ typedef union #define xPSR_Q_Pos 27U /*!< xPSR: Q Position */ #define xPSR_Q_Msk (1UL << xPSR_Q_Pos) /*!< xPSR: Q Mask */ -#define xPSR_IT_Pos 25U /*!< xPSR: IT Position */ -#define xPSR_IT_Msk (3UL << xPSR_IT_Pos) /*!< xPSR: IT Mask */ +#define xPSR_ICI_IT_2_Pos 25U /*!< xPSR: ICI/IT part 2 Position */ +#define xPSR_ICI_IT_2_Msk (3UL << xPSR_ICI_IT_2_Pos) /*!< xPSR: ICI/IT part 2 Mask */ #define xPSR_T_Pos 24U /*!< xPSR: T Position */ #define xPSR_T_Msk (1UL << xPSR_T_Pos) /*!< xPSR: T Mask */ @@ -421,6 +373,9 @@ typedef union #define xPSR_GE_Pos 16U /*!< xPSR: GE Position */ #define xPSR_GE_Msk (0xFUL << xPSR_GE_Pos) /*!< xPSR: GE Mask */ +#define xPSR_ICI_IT_1_Pos 10U /*!< xPSR: ICI/IT part 1 Position */ +#define xPSR_ICI_IT_1_Msk (0x3FUL << xPSR_ICI_IT_1_Pos) /*!< xPSR: ICI/IT part 1 Mask */ + #define xPSR_ISR_Pos 0U /*!< xPSR: ISR Position */ #define xPSR_ISR_Msk (0x1FFUL /*<< xPSR_ISR_Pos*/) /*!< xPSR: ISR Mask */ @@ -468,7 +423,7 @@ typedef struct __IOM uint32_t ISER[8U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ uint32_t RESERVED0[24U]; __IOM uint32_t ICER[8U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ - uint32_t RSERVED1[24U]; + uint32_t RESERVED1[24U]; __IOM uint32_t ISPR[8U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ uint32_t RESERVED2[24U]; __IOM uint32_t ICPR[8U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ @@ -529,7 +484,7 @@ typedef struct uint32_t RESERVED4[15U]; __IM uint32_t MVFR0; /*!< Offset: 0x240 (R/ ) Media and VFP Feature Register 0 */ __IM uint32_t MVFR1; /*!< Offset: 0x244 (R/ ) Media and VFP Feature Register 1 */ - __IM uint32_t MVFR2; /*!< Offset: 0x248 (R/ ) Media and VFP Feature Register 1 */ + __IM uint32_t MVFR2; /*!< Offset: 0x248 (R/ ) Media and VFP Feature Register 2 */ uint32_t RESERVED5[1U]; __OM uint32_t ICIALLU; /*!< Offset: 0x250 ( /W) I-Cache Invalidate All to PoU */ uint32_t RESERVED6[1U]; @@ -715,6 +670,66 @@ typedef struct #define SCB_CFSR_MEMFAULTSR_Pos 0U /*!< SCB CFSR: Memory Manage Fault Status Register Position */ #define SCB_CFSR_MEMFAULTSR_Msk (0xFFUL /*<< SCB_CFSR_MEMFAULTSR_Pos*/) /*!< SCB CFSR: Memory Manage Fault Status Register Mask */ +/* MemManage Fault Status Register (part of SCB Configurable Fault Status Register) */ +#define SCB_CFSR_MMARVALID_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 7U) /*!< SCB CFSR (MMFSR): MMARVALID Position */ +#define SCB_CFSR_MMARVALID_Msk (1UL << SCB_CFSR_MMARVALID_Pos) /*!< SCB CFSR (MMFSR): MMARVALID Mask */ + +#define SCB_CFSR_MLSPERR_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 5U) /*!< SCB CFSR (MMFSR): MLSPERR Position */ +#define SCB_CFSR_MLSPERR_Msk (1UL << SCB_CFSR_MLSPERR_Pos) /*!< SCB CFSR (MMFSR): MLSPERR Mask */ + +#define SCB_CFSR_MSTKERR_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 4U) /*!< SCB CFSR (MMFSR): MSTKERR Position */ +#define SCB_CFSR_MSTKERR_Msk (1UL << SCB_CFSR_MSTKERR_Pos) /*!< SCB CFSR (MMFSR): MSTKERR Mask */ + +#define SCB_CFSR_MUNSTKERR_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 3U) /*!< SCB CFSR (MMFSR): MUNSTKERR Position */ +#define SCB_CFSR_MUNSTKERR_Msk (1UL << SCB_CFSR_MUNSTKERR_Pos) /*!< SCB CFSR (MMFSR): MUNSTKERR Mask */ + +#define SCB_CFSR_DACCVIOL_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 1U) /*!< SCB CFSR (MMFSR): DACCVIOL Position */ +#define SCB_CFSR_DACCVIOL_Msk (1UL << SCB_CFSR_DACCVIOL_Pos) /*!< SCB CFSR (MMFSR): DACCVIOL Mask */ + +#define SCB_CFSR_IACCVIOL_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 0U) /*!< SCB CFSR (MMFSR): IACCVIOL Position */ +#define SCB_CFSR_IACCVIOL_Msk (1UL /*<< SCB_CFSR_IACCVIOL_Pos*/) /*!< SCB CFSR (MMFSR): IACCVIOL Mask */ + +/* BusFault Status Register (part of SCB Configurable Fault Status Register) */ +#define SCB_CFSR_BFARVALID_Pos (SCB_CFSR_BUSFAULTSR_Pos + 7U) /*!< SCB CFSR (BFSR): BFARVALID Position */ +#define SCB_CFSR_BFARVALID_Msk (1UL << SCB_CFSR_BFARVALID_Pos) /*!< SCB CFSR (BFSR): BFARVALID Mask */ + +#define SCB_CFSR_LSPERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 5U) /*!< SCB CFSR (BFSR): LSPERR Position */ +#define SCB_CFSR_LSPERR_Msk (1UL << SCB_CFSR_LSPERR_Pos) /*!< SCB CFSR (BFSR): LSPERR Mask */ + +#define SCB_CFSR_STKERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 4U) /*!< SCB CFSR (BFSR): STKERR Position */ +#define SCB_CFSR_STKERR_Msk (1UL << SCB_CFSR_STKERR_Pos) /*!< SCB CFSR (BFSR): STKERR Mask */ + +#define SCB_CFSR_UNSTKERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 3U) /*!< SCB CFSR (BFSR): UNSTKERR Position */ +#define SCB_CFSR_UNSTKERR_Msk (1UL << SCB_CFSR_UNSTKERR_Pos) /*!< SCB CFSR (BFSR): UNSTKERR Mask */ + +#define SCB_CFSR_IMPRECISERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 2U) /*!< SCB CFSR (BFSR): IMPRECISERR Position */ +#define SCB_CFSR_IMPRECISERR_Msk (1UL << SCB_CFSR_IMPRECISERR_Pos) /*!< SCB CFSR (BFSR): IMPRECISERR Mask */ + +#define SCB_CFSR_PRECISERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 1U) /*!< SCB CFSR (BFSR): PRECISERR Position */ +#define SCB_CFSR_PRECISERR_Msk (1UL << SCB_CFSR_PRECISERR_Pos) /*!< SCB CFSR (BFSR): PRECISERR Mask */ + +#define SCB_CFSR_IBUSERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 0U) /*!< SCB CFSR (BFSR): IBUSERR Position */ +#define SCB_CFSR_IBUSERR_Msk (1UL << SCB_CFSR_IBUSERR_Pos) /*!< SCB CFSR (BFSR): IBUSERR Mask */ + +/* UsageFault Status Register (part of SCB Configurable Fault Status Register) */ +#define SCB_CFSR_DIVBYZERO_Pos (SCB_CFSR_USGFAULTSR_Pos + 9U) /*!< SCB CFSR (UFSR): DIVBYZERO Position */ +#define SCB_CFSR_DIVBYZERO_Msk (1UL << SCB_CFSR_DIVBYZERO_Pos) /*!< SCB CFSR (UFSR): DIVBYZERO Mask */ + +#define SCB_CFSR_UNALIGNED_Pos (SCB_CFSR_USGFAULTSR_Pos + 8U) /*!< SCB CFSR (UFSR): UNALIGNED Position */ +#define SCB_CFSR_UNALIGNED_Msk (1UL << SCB_CFSR_UNALIGNED_Pos) /*!< SCB CFSR (UFSR): UNALIGNED Mask */ + +#define SCB_CFSR_NOCP_Pos (SCB_CFSR_USGFAULTSR_Pos + 3U) /*!< SCB CFSR (UFSR): NOCP Position */ +#define SCB_CFSR_NOCP_Msk (1UL << SCB_CFSR_NOCP_Pos) /*!< SCB CFSR (UFSR): NOCP Mask */ + +#define SCB_CFSR_INVPC_Pos (SCB_CFSR_USGFAULTSR_Pos + 2U) /*!< SCB CFSR (UFSR): INVPC Position */ +#define SCB_CFSR_INVPC_Msk (1UL << SCB_CFSR_INVPC_Pos) /*!< SCB CFSR (UFSR): INVPC Mask */ + +#define SCB_CFSR_INVSTATE_Pos (SCB_CFSR_USGFAULTSR_Pos + 1U) /*!< SCB CFSR (UFSR): INVSTATE Position */ +#define SCB_CFSR_INVSTATE_Msk (1UL << SCB_CFSR_INVSTATE_Pos) /*!< SCB CFSR (UFSR): INVSTATE Mask */ + +#define SCB_CFSR_UNDEFINSTR_Pos (SCB_CFSR_USGFAULTSR_Pos + 0U) /*!< SCB CFSR (UFSR): UNDEFINSTR Position */ +#define SCB_CFSR_UNDEFINSTR_Msk (1UL << SCB_CFSR_UNDEFINSTR_Pos) /*!< SCB CFSR (UFSR): UNDEFINSTR Mask */ + /* SCB Hard Fault Status Register Definitions */ #define SCB_HFSR_DEBUGEVT_Pos 31U /*!< SCB HFSR: DEBUGEVT Position */ #define SCB_HFSR_DEBUGEVT_Msk (1UL << SCB_HFSR_DEBUGEVT_Pos) /*!< SCB HFSR: DEBUGEVT Mask */ @@ -915,6 +930,24 @@ typedef struct #define SCnSCB_ICTR_INTLINESNUM_Msk (0xFUL /*<< SCnSCB_ICTR_INTLINESNUM_Pos*/) /*!< ICTR: INTLINESNUM Mask */ /* Auxiliary Control Register Definitions */ +#define SCnSCB_ACTLR_DISDYNADD_Pos 26U /*!< ACTLR: DISDYNADD Position */ +#define SCnSCB_ACTLR_DISDYNADD_Msk (1UL << SCnSCB_ACTLR_DISDYNADD_Pos) /*!< ACTLR: DISDYNADD Mask */ + +#define SCnSCB_ACTLR_DISISSCH1_Pos 21U /*!< ACTLR: DISISSCH1 Position */ +#define SCnSCB_ACTLR_DISISSCH1_Msk (0x1FUL << SCnSCB_ACTLR_DISISSCH1_Pos) /*!< ACTLR: DISISSCH1 Mask */ + +#define SCnSCB_ACTLR_DISDI_Pos 16U /*!< ACTLR: DISDI Position */ +#define SCnSCB_ACTLR_DISDI_Msk (0x1FUL << SCnSCB_ACTLR_DISDI_Pos) /*!< ACTLR: DISDI Mask */ + +#define SCnSCB_ACTLR_DISCRITAXIRUR_Pos 15U /*!< ACTLR: DISCRITAXIRUR Position */ +#define SCnSCB_ACTLR_DISCRITAXIRUR_Msk (1UL << SCnSCB_ACTLR_DISCRITAXIRUR_Pos) /*!< ACTLR: DISCRITAXIRUR Mask */ + +#define SCnSCB_ACTLR_DISBTACALLOC_Pos 14U /*!< ACTLR: DISBTACALLOC Position */ +#define SCnSCB_ACTLR_DISBTACALLOC_Msk (1UL << SCnSCB_ACTLR_DISBTACALLOC_Pos) /*!< ACTLR: DISBTACALLOC Mask */ + +#define SCnSCB_ACTLR_DISBTACREAD_Pos 13U /*!< ACTLR: DISBTACREAD Position */ +#define SCnSCB_ACTLR_DISBTACREAD_Msk (1UL << SCnSCB_ACTLR_DISBTACREAD_Pos) /*!< ACTLR: DISBTACREAD Mask */ + #define SCnSCB_ACTLR_DISITMATBFLUSH_Pos 12U /*!< ACTLR: DISITMATBFLUSH Position */ #define SCnSCB_ACTLR_DISITMATBFLUSH_Msk (1UL << SCnSCB_ACTLR_DISITMATBFLUSH_Pos) /*!< ACTLR: DISITMATBFLUSH Mask */ @@ -1009,10 +1042,7 @@ typedef struct __IOM uint32_t TPR; /*!< Offset: 0xE40 (R/W) ITM Trace Privilege Register */ uint32_t RESERVED2[15U]; __IOM uint32_t TCR; /*!< Offset: 0xE80 (R/W) ITM Trace Control Register */ - uint32_t RESERVED3[29U]; - __OM uint32_t IWR; /*!< Offset: 0xEF8 ( /W) ITM Integration Write Register */ - __IM uint32_t IRR; /*!< Offset: 0xEFC (R/ ) ITM Integration Read Register */ - __IOM uint32_t IMCR; /*!< Offset: 0xF00 (R/W) ITM Integration Mode Control Register */ + uint32_t RESERVED3[32U]; uint32_t RESERVED4[43U]; __OM uint32_t LAR; /*!< Offset: 0xFB0 ( /W) ITM Lock Access Register */ __IM uint32_t LSR; /*!< Offset: 0xFB4 (R/ ) ITM Lock Status Register */ @@ -1033,7 +1063,7 @@ typedef struct /* ITM Trace Privilege Register Definitions */ #define ITM_TPR_PRIVMASK_Pos 0U /*!< ITM TPR: PRIVMASK Position */ -#define ITM_TPR_PRIVMASK_Msk (0xFUL /*<< ITM_TPR_PRIVMASK_Pos*/) /*!< ITM TPR: PRIVMASK Mask */ +#define ITM_TPR_PRIVMASK_Msk (0xFFFFFFFFUL /*<< ITM_TPR_PRIVMASK_Pos*/) /*!< ITM TPR: PRIVMASK Mask */ /* ITM Trace Control Register Definitions */ #define ITM_TCR_BUSY_Pos 23U /*!< ITM TCR: BUSY Position */ @@ -1063,18 +1093,6 @@ typedef struct #define ITM_TCR_ITMENA_Pos 0U /*!< ITM TCR: ITM Enable bit Position */ #define ITM_TCR_ITMENA_Msk (1UL /*<< ITM_TCR_ITMENA_Pos*/) /*!< ITM TCR: ITM Enable bit Mask */ -/* ITM Integration Write Register Definitions */ -#define ITM_IWR_ATVALIDM_Pos 0U /*!< ITM IWR: ATVALIDM Position */ -#define ITM_IWR_ATVALIDM_Msk (1UL /*<< ITM_IWR_ATVALIDM_Pos*/) /*!< ITM IWR: ATVALIDM Mask */ - -/* ITM Integration Read Register Definitions */ -#define ITM_IRR_ATREADYM_Pos 0U /*!< ITM IRR: ATREADYM Position */ -#define ITM_IRR_ATREADYM_Msk (1UL /*<< ITM_IRR_ATREADYM_Pos*/) /*!< ITM IRR: ATREADYM Mask */ - -/* ITM Integration Mode Control Register Definitions */ -#define ITM_IMCR_INTEGRATION_Pos 0U /*!< ITM IMCR: INTEGRATION Position */ -#define ITM_IMCR_INTEGRATION_Msk (1UL /*<< ITM_IMCR_INTEGRATION_Pos*/) /*!< ITM IMCR: INTEGRATION Mask */ - /* ITM Lock Status Register Definitions */ #define ITM_LSR_ByteAcc_Pos 2U /*!< ITM LSR: ByteAcc Position */ #define ITM_LSR_ByteAcc_Msk (1UL << ITM_LSR_ByteAcc_Pos) /*!< ITM LSR: ByteAcc Mask */ @@ -1250,7 +1268,7 @@ typedef struct */ typedef struct { - __IOM uint32_t SSPSR; /*!< Offset: 0x000 (R/ ) Supported Parallel Port Size Register */ + __IM uint32_t SSPSR; /*!< Offset: 0x000 (R/ ) Supported Parallel Port Size Register */ __IOM uint32_t CSPSR; /*!< Offset: 0x004 (R/W) Current Parallel Port Size Register */ uint32_t RESERVED0[2U]; __IOM uint32_t ACPR; /*!< Offset: 0x010 (R/W) Asynchronous Clock Prescaler Register */ @@ -1261,7 +1279,7 @@ typedef struct __IOM uint32_t FFCR; /*!< Offset: 0x304 (R/W) Formatter and Flush Control Register */ __IM uint32_t FSCR; /*!< Offset: 0x308 (R/ ) Formatter Synchronization Counter Register */ uint32_t RESERVED3[759U]; - __IM uint32_t TRIGGER; /*!< Offset: 0xEE8 (R/ ) TRIGGER */ + __IM uint32_t TRIGGER; /*!< Offset: 0xEE8 (R/ ) TRIGGER Register */ __IM uint32_t FIFO0; /*!< Offset: 0xEEC (R/ ) Integration ETM Data */ __IM uint32_t ITATBCTR2; /*!< Offset: 0xEF0 (R/ ) ITATBCTR2 */ uint32_t RESERVED4[1U]; @@ -1310,13 +1328,13 @@ typedef struct /* TPI Integration ETM Data Register Definitions (FIFO0) */ #define TPI_FIFO0_ITM_ATVALID_Pos 29U /*!< TPI FIFO0: ITM_ATVALID Position */ -#define TPI_FIFO0_ITM_ATVALID_Msk (0x3UL << TPI_FIFO0_ITM_ATVALID_Pos) /*!< TPI FIFO0: ITM_ATVALID Mask */ +#define TPI_FIFO0_ITM_ATVALID_Msk (0x1UL << TPI_FIFO0_ITM_ATVALID_Pos) /*!< TPI FIFO0: ITM_ATVALID Mask */ #define TPI_FIFO0_ITM_bytecount_Pos 27U /*!< TPI FIFO0: ITM_bytecount Position */ #define TPI_FIFO0_ITM_bytecount_Msk (0x3UL << TPI_FIFO0_ITM_bytecount_Pos) /*!< TPI FIFO0: ITM_bytecount Mask */ #define TPI_FIFO0_ETM_ATVALID_Pos 26U /*!< TPI FIFO0: ETM_ATVALID Position */ -#define TPI_FIFO0_ETM_ATVALID_Msk (0x3UL << TPI_FIFO0_ETM_ATVALID_Pos) /*!< TPI FIFO0: ETM_ATVALID Mask */ +#define TPI_FIFO0_ETM_ATVALID_Msk (0x1UL << TPI_FIFO0_ETM_ATVALID_Pos) /*!< TPI FIFO0: ETM_ATVALID Mask */ #define TPI_FIFO0_ETM_bytecount_Pos 24U /*!< TPI FIFO0: ETM_bytecount Position */ #define TPI_FIFO0_ETM_bytecount_Msk (0x3UL << TPI_FIFO0_ETM_bytecount_Pos) /*!< TPI FIFO0: ETM_bytecount Mask */ @@ -1331,18 +1349,21 @@ typedef struct #define TPI_FIFO0_ETM0_Msk (0xFFUL /*<< TPI_FIFO0_ETM0_Pos*/) /*!< TPI FIFO0: ETM0 Mask */ /* TPI ITATBCTR2 Register Definitions */ -#define TPI_ITATBCTR2_ATREADY_Pos 0U /*!< TPI ITATBCTR2: ATREADY Position */ -#define TPI_ITATBCTR2_ATREADY_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY_Pos*/) /*!< TPI ITATBCTR2: ATREADY Mask */ +#define TPI_ITATBCTR2_ATREADY2_Pos 0U /*!< TPI ITATBCTR2: ATREADY2 Position */ +#define TPI_ITATBCTR2_ATREADY2_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY2_Pos*/) /*!< TPI ITATBCTR2: ATREADY2 Mask */ + +#define TPI_ITATBCTR2_ATREADY1_Pos 0U /*!< TPI ITATBCTR2: ATREADY1 Position */ +#define TPI_ITATBCTR2_ATREADY1_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY1_Pos*/) /*!< TPI ITATBCTR2: ATREADY1 Mask */ /* TPI Integration ITM Data Register Definitions (FIFO1) */ #define TPI_FIFO1_ITM_ATVALID_Pos 29U /*!< TPI FIFO1: ITM_ATVALID Position */ -#define TPI_FIFO1_ITM_ATVALID_Msk (0x3UL << TPI_FIFO1_ITM_ATVALID_Pos) /*!< TPI FIFO1: ITM_ATVALID Mask */ +#define TPI_FIFO1_ITM_ATVALID_Msk (0x1UL << TPI_FIFO1_ITM_ATVALID_Pos) /*!< TPI FIFO1: ITM_ATVALID Mask */ #define TPI_FIFO1_ITM_bytecount_Pos 27U /*!< TPI FIFO1: ITM_bytecount Position */ #define TPI_FIFO1_ITM_bytecount_Msk (0x3UL << TPI_FIFO1_ITM_bytecount_Pos) /*!< TPI FIFO1: ITM_bytecount Mask */ #define TPI_FIFO1_ETM_ATVALID_Pos 26U /*!< TPI FIFO1: ETM_ATVALID Position */ -#define TPI_FIFO1_ETM_ATVALID_Msk (0x3UL << TPI_FIFO1_ETM_ATVALID_Pos) /*!< TPI FIFO1: ETM_ATVALID Mask */ +#define TPI_FIFO1_ETM_ATVALID_Msk (0x1UL << TPI_FIFO1_ETM_ATVALID_Pos) /*!< TPI FIFO1: ETM_ATVALID Mask */ #define TPI_FIFO1_ETM_bytecount_Pos 24U /*!< TPI FIFO1: ETM_bytecount Position */ #define TPI_FIFO1_ETM_bytecount_Msk (0x3UL << TPI_FIFO1_ETM_bytecount_Pos) /*!< TPI FIFO1: ETM_bytecount Mask */ @@ -1357,12 +1378,15 @@ typedef struct #define TPI_FIFO1_ITM0_Msk (0xFFUL /*<< TPI_FIFO1_ITM0_Pos*/) /*!< TPI FIFO1: ITM0 Mask */ /* TPI ITATBCTR0 Register Definitions */ -#define TPI_ITATBCTR0_ATREADY_Pos 0U /*!< TPI ITATBCTR0: ATREADY Position */ -#define TPI_ITATBCTR0_ATREADY_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY_Pos*/) /*!< TPI ITATBCTR0: ATREADY Mask */ +#define TPI_ITATBCTR0_ATREADY2_Pos 0U /*!< TPI ITATBCTR0: ATREADY2 Position */ +#define TPI_ITATBCTR0_ATREADY2_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY2_Pos*/) /*!< TPI ITATBCTR0: ATREADY2 Mask */ + +#define TPI_ITATBCTR0_ATREADY1_Pos 0U /*!< TPI ITATBCTR0: ATREADY1 Position */ +#define TPI_ITATBCTR0_ATREADY1_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY1_Pos*/) /*!< TPI ITATBCTR0: ATREADY1 Mask */ /* TPI Integration Mode Control Register Definitions */ #define TPI_ITCTRL_Mode_Pos 0U /*!< TPI ITCTRL: Mode Position */ -#define TPI_ITCTRL_Mode_Msk (0x1UL /*<< TPI_ITCTRL_Mode_Pos*/) /*!< TPI ITCTRL: Mode Mask */ +#define TPI_ITCTRL_Mode_Msk (0x3UL /*<< TPI_ITCTRL_Mode_Pos*/) /*!< TPI ITCTRL: Mode Mask */ /* TPI DEVID Register Definitions */ #define TPI_DEVID_NRZVALID_Pos 11U /*!< TPI DEVID: NRZVALID Position */ @@ -1384,16 +1408,16 @@ typedef struct #define TPI_DEVID_NrTraceInput_Msk (0x1FUL /*<< TPI_DEVID_NrTraceInput_Pos*/) /*!< TPI DEVID: NrTraceInput Mask */ /* TPI DEVTYPE Register Definitions */ -#define TPI_DEVTYPE_MajorType_Pos 4U /*!< TPI DEVTYPE: MajorType Position */ -#define TPI_DEVTYPE_MajorType_Msk (0xFUL << TPI_DEVTYPE_MajorType_Pos) /*!< TPI DEVTYPE: MajorType Mask */ - -#define TPI_DEVTYPE_SubType_Pos 0U /*!< TPI DEVTYPE: SubType Position */ +#define TPI_DEVTYPE_SubType_Pos 4U /*!< TPI DEVTYPE: SubType Position */ #define TPI_DEVTYPE_SubType_Msk (0xFUL /*<< TPI_DEVTYPE_SubType_Pos*/) /*!< TPI DEVTYPE: SubType Mask */ +#define TPI_DEVTYPE_MajorType_Pos 0U /*!< TPI DEVTYPE: MajorType Position */ +#define TPI_DEVTYPE_MajorType_Msk (0xFUL << TPI_DEVTYPE_MajorType_Pos) /*!< TPI DEVTYPE: MajorType Mask */ + /*@}*/ /* end of group CMSIS_TPI */ -#if (__MPU_PRESENT == 1U) +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) /** \ingroup CMSIS_core_register \defgroup CMSIS_MPU Memory Protection Unit (MPU) @@ -1419,6 +1443,8 @@ typedef struct __IOM uint32_t RASR_A3; /*!< Offset: 0x028 (R/W) MPU Alias 3 Region Attribute and Size Register */ } MPU_Type; +#define MPU_TYPE_RALIASES 4U + /* MPU Type Register Definitions */ #define MPU_TYPE_IREGION_Pos 16U /*!< MPU TYPE: IREGION Position */ #define MPU_TYPE_IREGION_Msk (0xFFUL << MPU_TYPE_IREGION_Pos) /*!< MPU TYPE: IREGION Mask */ @@ -1485,10 +1511,9 @@ typedef struct #define MPU_RASR_ENABLE_Msk (1UL /*<< MPU_RASR_ENABLE_Pos*/) /*!< MPU RASR: Region enable bit Disable Mask */ /*@} end of group CMSIS_MPU */ -#endif +#endif /* defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) */ -#if (__FPU_PRESENT == 1U) /** \ingroup CMSIS_core_register \defgroup CMSIS_FPU Floating Point Unit (FPU) @@ -1595,8 +1620,10 @@ typedef struct /* Media and FP Feature Register 2 Definitions */ +#define FPU_MVFR2_VFP_Misc_Pos 4U /*!< MVFR2: VFP Misc bits Position */ +#define FPU_MVFR2_VFP_Misc_Msk (0xFUL << FPU_MVFR2_VFP_Misc_Pos) /*!< MVFR2: VFP Misc bits Mask */ + /*@} end of group CMSIS_FPU */ -#endif /** @@ -1714,18 +1741,18 @@ typedef struct /** \brief Mask and shift a bit field value for use in a register bit range. \param[in] field Name of the register bit field. - \param[in] value Value of the bit field. + \param[in] value Value of the bit field. This parameter is interpreted as an uint32_t type. \return Masked and shifted value. */ -#define _VAL2FLD(field, value) ((value << field ## _Pos) & field ## _Msk) +#define _VAL2FLD(field, value) (((uint32_t)(value) << field ## _Pos) & field ## _Msk) /** \brief Mask and shift a register value to extract a bit filed value. \param[in] field Name of the register bit field. - \param[in] value Value of register. + \param[in] value Value of register. This parameter is interpreted as an uint32_t type. \return Masked and shifted bit field value. */ -#define _FLD2VAL(field, value) ((value & field ## _Msk) >> field ## _Pos) +#define _FLD2VAL(field, value) (((uint32_t)(value) & field ## _Msk) >> field ## _Pos) /*@} end of group CMSIS_core_bitfield */ @@ -1737,7 +1764,7 @@ typedef struct @{ */ -/* Memory mapping of Cortex-M4 Hardware */ +/* Memory mapping of Core Hardware */ #define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ #define ITM_BASE (0xE0000000UL) /*!< ITM Base Address */ #define DWT_BASE (0xE0001000UL) /*!< DWT Base Address */ @@ -1756,15 +1783,13 @@ typedef struct #define TPI ((TPI_Type *) TPI_BASE ) /*!< TPI configuration struct */ #define CoreDebug ((CoreDebug_Type *) CoreDebug_BASE) /*!< Core Debug configuration struct */ -#if (__MPU_PRESENT == 1U) +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) #define MPU_BASE (SCS_BASE + 0x0D90UL) /*!< Memory Protection Unit */ #define MPU ((MPU_Type *) MPU_BASE ) /*!< Memory Protection Unit */ #endif -#if (__FPU_PRESENT == 1U) - #define FPU_BASE (SCS_BASE + 0x0F30UL) /*!< Floating Point Unit */ - #define FPU ((FPU_Type *) FPU_BASE ) /*!< Floating Point Unit */ -#endif +#define FPU_BASE (SCS_BASE + 0x0F30UL) /*!< Floating Point Unit */ +#define FPU ((FPU_Type *) FPU_BASE ) /*!< Floating Point Unit */ /*@} */ @@ -1792,6 +1817,48 @@ typedef struct @{ */ +#ifdef CMSIS_NVIC_VIRTUAL + #ifndef CMSIS_NVIC_VIRTUAL_HEADER_FILE + #define CMSIS_NVIC_VIRTUAL_HEADER_FILE "cmsis_nvic_virtual.h" + #endif + #include CMSIS_NVIC_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetPriorityGrouping __NVIC_SetPriorityGrouping + #define NVIC_GetPriorityGrouping __NVIC_GetPriorityGrouping + #define NVIC_EnableIRQ __NVIC_EnableIRQ + #define NVIC_GetEnableIRQ __NVIC_GetEnableIRQ + #define NVIC_DisableIRQ __NVIC_DisableIRQ + #define NVIC_GetPendingIRQ __NVIC_GetPendingIRQ + #define NVIC_SetPendingIRQ __NVIC_SetPendingIRQ + #define NVIC_ClearPendingIRQ __NVIC_ClearPendingIRQ + #define NVIC_GetActive __NVIC_GetActive + #define NVIC_SetPriority __NVIC_SetPriority + #define NVIC_GetPriority __NVIC_GetPriority + #define NVIC_SystemReset __NVIC_SystemReset +#endif /* CMSIS_NVIC_VIRTUAL */ + +#ifdef CMSIS_VECTAB_VIRTUAL + #ifndef CMSIS_VECTAB_VIRTUAL_HEADER_FILE + #define CMSIS_VECTAB_VIRTUAL_HEADER_FILE "cmsis_vectab_virtual.h" + #endif + #include CMSIS_VECTAB_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetVector __NVIC_SetVector + #define NVIC_GetVector __NVIC_GetVector +#endif /* (CMSIS_VECTAB_VIRTUAL) */ + +#define NVIC_USER_IRQ_OFFSET 16 + + +/* The following EXC_RETURN values are saved the LR on exception entry */ +#define EXC_RETURN_HANDLER (0xFFFFFFF1UL) /* return to Handler mode, uses MSP after return */ +#define EXC_RETURN_THREAD_MSP (0xFFFFFFF9UL) /* return to Thread mode, uses MSP after return */ +#define EXC_RETURN_THREAD_PSP (0xFFFFFFFDUL) /* return to Thread mode, uses PSP after return */ +#define EXC_RETURN_HANDLER_FPU (0xFFFFFFE1UL) /* return to Handler mode, uses MSP after return, restore floating-point state */ +#define EXC_RETURN_THREAD_MSP_FPU (0xFFFFFFE9UL) /* return to Thread mode, uses MSP after return, restore floating-point state */ +#define EXC_RETURN_THREAD_PSP_FPU (0xFFFFFFEDUL) /* return to Thread mode, uses PSP after return, restore floating-point state */ + + /** \brief Set Priority Grouping \details Sets the priority grouping field using the required unlock sequence. @@ -1801,7 +1868,7 @@ typedef struct priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. \param [in] PriorityGroup Priority grouping field. */ -__STATIC_INLINE void NVIC_SetPriorityGrouping(uint32_t PriorityGroup) +__STATIC_INLINE void __NVIC_SetPriorityGrouping(uint32_t PriorityGroup) { uint32_t reg_value; uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ @@ -1810,7 +1877,7 @@ __STATIC_INLINE void NVIC_SetPriorityGrouping(uint32_t PriorityGroup) reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk)); /* clear bits to change */ reg_value = (reg_value | ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | - (PriorityGroupTmp << 8U) ); /* Insert write key and priorty group */ + (PriorityGroupTmp << SCB_AIRCR_PRIGROUP_Pos) ); /* Insert write key and priority group */ SCB->AIRCR = reg_value; } @@ -1820,121 +1887,178 @@ __STATIC_INLINE void NVIC_SetPriorityGrouping(uint32_t PriorityGroup) \details Reads the priority grouping field from the NVIC Interrupt Controller. \return Priority grouping field (SCB->AIRCR [10:8] PRIGROUP field). */ -__STATIC_INLINE uint32_t NVIC_GetPriorityGrouping(void) +__STATIC_INLINE uint32_t __NVIC_GetPriorityGrouping(void) { return ((uint32_t)((SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) >> SCB_AIRCR_PRIGROUP_Pos)); } /** - \brief Enable External Interrupt - \details Enables a device-specific interrupt in the NVIC interrupt controller. - \param [in] IRQn External interrupt number. Value cannot be negative. + \brief Enable Interrupt + \details Enables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. */ -__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn) +__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn) { - NVIC->ISER[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } } /** - \brief Disable External Interrupt - \details Disables a device-specific interrupt in the NVIC interrupt controller. - \param [in] IRQn External interrupt number. Value cannot be negative. + \brief Get Interrupt Enable status + \details Returns a device specific interrupt enable status from the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt is not enabled. + \return 1 Interrupt is enabled. + \note IRQn must not be negative. */ -__STATIC_INLINE void NVIC_DisableIRQ(IRQn_Type IRQn) +__STATIC_INLINE uint32_t __NVIC_GetEnableIRQ(IRQn_Type IRQn) { - NVIC->ICER[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Disable Interrupt + \details Disables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_DisableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + __DSB(); + __ISB(); + } } /** \brief Get Pending Interrupt - \details Reads the pending register in the NVIC and returns the pending bit for the specified interrupt. - \param [in] IRQn Interrupt number. + \details Reads the NVIC pending register and returns the pending bit for the specified device specific interrupt. + \param [in] IRQn Device specific interrupt number. \return 0 Interrupt status is not pending. \return 1 Interrupt status is pending. + \note IRQn must not be negative. */ -__STATIC_INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn) +__STATIC_INLINE uint32_t __NVIC_GetPendingIRQ(IRQn_Type IRQn) { - return((uint32_t)(((NVIC->ISPR[(((uint32_t)(int32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } } /** \brief Set Pending Interrupt - \details Sets the pending bit of an external interrupt. - \param [in] IRQn Interrupt number. Value cannot be negative. + \details Sets the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. */ -__STATIC_INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn) +__STATIC_INLINE void __NVIC_SetPendingIRQ(IRQn_Type IRQn) { - NVIC->ISPR[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } } /** \brief Clear Pending Interrupt - \details Clears the pending bit of an external interrupt. - \param [in] IRQn External interrupt number. Value cannot be negative. + \details Clears the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. */ -__STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn) +__STATIC_INLINE void __NVIC_ClearPendingIRQ(IRQn_Type IRQn) { - NVIC->ICPR[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } } /** \brief Get Active Interrupt - \details Reads the active register in NVIC and returns the active bit. - \param [in] IRQn Interrupt number. + \details Reads the active register in the NVIC and returns the active bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. \return 0 Interrupt status is not active. \return 1 Interrupt status is active. + \note IRQn must not be negative. */ -__STATIC_INLINE uint32_t NVIC_GetActive(IRQn_Type IRQn) +__STATIC_INLINE uint32_t __NVIC_GetActive(IRQn_Type IRQn) { - return((uint32_t)(((NVIC->IABR[(((uint32_t)(int32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->IABR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } } /** \brief Set Interrupt Priority - \details Sets the priority of an interrupt. - \note The priority cannot be set for every core interrupt. + \details Sets the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. \param [in] IRQn Interrupt number. \param [in] priority Priority to set. + \note The priority cannot be set for every processor exception. */ -__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +__STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) { - if ((int32_t)(IRQn) < 0) + if ((int32_t)(IRQn) >= 0) { - SCB->SHPR[(((uint32_t)(int32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + NVIC->IP[((uint32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); } else { - NVIC->IP[((uint32_t)(int32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + SCB->SHPR[(((uint32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); } } /** \brief Get Interrupt Priority - \details Reads the priority of an interrupt. - The interrupt number can be positive to specify an external (device specific) interrupt, - or negative to specify an internal (core) interrupt. + \details Reads the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. \param [in] IRQn Interrupt number. \return Interrupt Priority. Value is aligned automatically to the implemented priority bits of the microcontroller. */ -__STATIC_INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn) +__STATIC_INLINE uint32_t __NVIC_GetPriority(IRQn_Type IRQn) { - if ((int32_t)(IRQn) < 0) + if ((int32_t)(IRQn) >= 0) { - return(((uint32_t)SCB->SHPR[(((uint32_t)(int32_t)IRQn) & 0xFUL)-4UL] >> (8U - __NVIC_PRIO_BITS))); + return(((uint32_t)NVIC->IP[((uint32_t)IRQn)] >> (8U - __NVIC_PRIO_BITS))); } else { - return(((uint32_t)NVIC->IP[((uint32_t)(int32_t)IRQn)] >> (8U - __NVIC_PRIO_BITS))); + return(((uint32_t)SCB->SHPR[(((uint32_t)IRQn) & 0xFUL)-4UL] >> (8U - __NVIC_PRIO_BITS))); } } @@ -1991,11 +2115,42 @@ __STATIC_INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGr } +/** + \brief Set Interrupt Vector + \details Sets an interrupt vector in SRAM based interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + VTOR must been relocated to SRAM before. + \param [in] IRQn Interrupt number + \param [in] vector Address of interrupt handler function + */ +__STATIC_INLINE void __NVIC_SetVector(IRQn_Type IRQn, uint32_t vector) +{ + uint32_t vectors = (uint32_t )SCB->VTOR; + (* (int *) (vectors + ((int32_t)IRQn + NVIC_USER_IRQ_OFFSET) * 4)) = vector; +} + + +/** + \brief Get Interrupt Vector + \details Reads an interrupt vector from interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Address of interrupt handler function + */ +__STATIC_INLINE uint32_t __NVIC_GetVector(IRQn_Type IRQn) +{ + uint32_t vectors = (uint32_t )SCB->VTOR; + return (uint32_t)(* (int *) (vectors + ((int32_t)IRQn + NVIC_USER_IRQ_OFFSET) * 4)); +} + + /** \brief System Reset \details Initiates a system reset request to reset the MCU. */ -__STATIC_INLINE void NVIC_SystemReset(void) +__NO_RETURN __STATIC_INLINE void __NVIC_SystemReset(void) { __DSB(); /* Ensure all outstanding memory accesses included buffered write are completed before reset */ @@ -2013,6 +2168,15 @@ __STATIC_INLINE void NVIC_SystemReset(void) /*@} end of CMSIS_Core_NVICFunctions */ +/* ########################## MPU functions #################################### */ + +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + +#include "mpu_armv7.h" + +#endif + + /* ########################## FPU functions #################################### */ /** \ingroup CMSIS_Core_FunctionInterface @@ -2034,21 +2198,20 @@ __STATIC_INLINE uint32_t SCB_GetFPUType(void) uint32_t mvfr0; mvfr0 = SCB->MVFR0; - if ((mvfr0 & 0x00000FF0UL) == 0x220UL) + if ((mvfr0 & (FPU_MVFR0_Single_precision_Msk | FPU_MVFR0_Double_precision_Msk)) == 0x220U) { - return 2UL; /* Double + Single precision FPU */ + return 2U; /* Double + Single precision FPU */ } - else if ((mvfr0 & 0x00000FF0UL) == 0x020UL) + else if ((mvfr0 & (FPU_MVFR0_Single_precision_Msk | FPU_MVFR0_Double_precision_Msk)) == 0x020U) { - return 1UL; /* Single precision FPU */ + return 1U; /* Single precision FPU */ } else { - return 0UL; /* No FPU */ + return 0U; /* No FPU */ } } - /*@} end of CMSIS_Core_FpuFunctions */ @@ -2065,17 +2228,22 @@ __STATIC_INLINE uint32_t SCB_GetFPUType(void) #define CCSIDR_WAYS(x) (((x) & SCB_CCSIDR_ASSOCIATIVITY_Msk) >> SCB_CCSIDR_ASSOCIATIVITY_Pos) #define CCSIDR_SETS(x) (((x) & SCB_CCSIDR_NUMSETS_Msk ) >> SCB_CCSIDR_NUMSETS_Pos ) +#define __SCB_DCACHE_LINE_SIZE 32U /*!< Cortex-M7 cache line size is fixed to 32 bytes (8 words). See also register SCB_CCSIDR */ /** \brief Enable I-Cache \details Turns on I-Cache */ -__STATIC_INLINE void SCB_EnableICache (void) +__STATIC_FORCEINLINE void SCB_EnableICache (void) { - #if (__ICACHE_PRESENT == 1U) + #if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U) + if (SCB->CCR & SCB_CCR_IC_Msk) return; /* return if ICache is already enabled */ + __DSB(); __ISB(); SCB->ICIALLU = 0UL; /* invalidate I-Cache */ + __DSB(); + __ISB(); SCB->CCR |= (uint32_t)SCB_CCR_IC_Msk; /* enable I-Cache */ __DSB(); __ISB(); @@ -2087,9 +2255,9 @@ __STATIC_INLINE void SCB_EnableICache (void) \brief Disable I-Cache \details Turns off I-Cache */ -__STATIC_INLINE void SCB_DisableICache (void) +__STATIC_FORCEINLINE void SCB_DisableICache (void) { - #if (__ICACHE_PRESENT == 1U) + #if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U) __DSB(); __ISB(); SCB->CCR &= ~(uint32_t)SCB_CCR_IC_Msk; /* disable I-Cache */ @@ -2104,9 +2272,9 @@ __STATIC_INLINE void SCB_DisableICache (void) \brief Invalidate I-Cache \details Invalidates I-Cache */ -__STATIC_INLINE void SCB_InvalidateICache (void) +__STATIC_FORCEINLINE void SCB_InvalidateICache (void) { - #if (__ICACHE_PRESENT == 1U) + #if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U) __DSB(); __ISB(); SCB->ICIALLU = 0UL; @@ -2120,14 +2288,16 @@ __STATIC_INLINE void SCB_InvalidateICache (void) \brief Enable D-Cache \details Turns on D-Cache */ -__STATIC_INLINE void SCB_EnableDCache (void) +__STATIC_FORCEINLINE void SCB_EnableDCache (void) { - #if (__DCACHE_PRESENT == 1U) + #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) uint32_t ccsidr; uint32_t sets; uint32_t ways; - SCB->CSSELR = (0U << 1U) | 0U; /* Level 1 data cache */ + if (SCB->CCR & SCB_CCR_DC_Msk) return; /* return if DCache is already enabled */ + + SCB->CSSELR = 0U; /* select Level 1 data cache */ __DSB(); ccsidr = SCB->CCSIDR; @@ -2142,8 +2312,8 @@ __STATIC_INLINE void SCB_EnableDCache (void) #if defined ( __CC_ARM ) __schedule_barrier(); #endif - } while (ways--); - } while(sets--); + } while (ways-- != 0U); + } while(sets-- != 0U); __DSB(); SCB->CCR |= (uint32_t)SCB_CCR_DC_Msk; /* enable D-Cache */ @@ -2158,20 +2328,21 @@ __STATIC_INLINE void SCB_EnableDCache (void) \brief Disable D-Cache \details Turns off D-Cache */ -__STATIC_INLINE void SCB_DisableDCache (void) +__STATIC_FORCEINLINE void SCB_DisableDCache (void) { - #if (__DCACHE_PRESENT == 1U) + #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) uint32_t ccsidr; uint32_t sets; uint32_t ways; - SCB->CSSELR = (0U << 1U) | 0U; /* Level 1 data cache */ + SCB->CSSELR = 0U; /* select Level 1 data cache */ + __DSB(); + + SCB->CCR &= ~(uint32_t)SCB_CCR_DC_Msk; /* disable D-Cache */ __DSB(); ccsidr = SCB->CCSIDR; - SCB->CCR &= ~(uint32_t)SCB_CCR_DC_Msk; /* disable D-Cache */ - /* clean & invalidate D-Cache */ sets = (uint32_t)(CCSIDR_SETS(ccsidr)); do { @@ -2182,8 +2353,8 @@ __STATIC_INLINE void SCB_DisableDCache (void) #if defined ( __CC_ARM ) __schedule_barrier(); #endif - } while (ways--); - } while(sets--); + } while (ways-- != 0U); + } while(sets-- != 0U); __DSB(); __ISB(); @@ -2195,14 +2366,14 @@ __STATIC_INLINE void SCB_DisableDCache (void) \brief Invalidate D-Cache \details Invalidates D-Cache */ -__STATIC_INLINE void SCB_InvalidateDCache (void) +__STATIC_FORCEINLINE void SCB_InvalidateDCache (void) { - #if (__DCACHE_PRESENT == 1U) + #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) uint32_t ccsidr; uint32_t sets; uint32_t ways; - SCB->CSSELR = (0U << 1U) | 0U; /* Level 1 data cache */ + SCB->CSSELR = 0U; /* select Level 1 data cache */ __DSB(); ccsidr = SCB->CCSIDR; @@ -2217,8 +2388,8 @@ __STATIC_INLINE void SCB_InvalidateDCache (void) #if defined ( __CC_ARM ) __schedule_barrier(); #endif - } while (ways--); - } while(sets--); + } while (ways-- != 0U); + } while(sets-- != 0U); __DSB(); __ISB(); @@ -2230,14 +2401,14 @@ __STATIC_INLINE void SCB_InvalidateDCache (void) \brief Clean D-Cache \details Cleans D-Cache */ -__STATIC_INLINE void SCB_CleanDCache (void) +__STATIC_FORCEINLINE void SCB_CleanDCache (void) { - #if (__DCACHE_PRESENT == 1U) + #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) uint32_t ccsidr; uint32_t sets; uint32_t ways; - SCB->CSSELR = (0U << 1U) | 0U; /* Level 1 data cache */ + SCB->CSSELR = 0U; /* select Level 1 data cache */ __DSB(); ccsidr = SCB->CCSIDR; @@ -2252,8 +2423,8 @@ __STATIC_INLINE void SCB_CleanDCache (void) #if defined ( __CC_ARM ) __schedule_barrier(); #endif - } while (ways--); - } while(sets--); + } while (ways-- != 0U); + } while(sets-- != 0U); __DSB(); __ISB(); @@ -2265,14 +2436,14 @@ __STATIC_INLINE void SCB_CleanDCache (void) \brief Clean & Invalidate D-Cache \details Cleans and Invalidates D-Cache */ -__STATIC_INLINE void SCB_CleanInvalidateDCache (void) +__STATIC_FORCEINLINE void SCB_CleanInvalidateDCache (void) { - #if (__DCACHE_PRESENT == 1U) + #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) uint32_t ccsidr; uint32_t sets; uint32_t ways; - SCB->CSSELR = (0U << 1U) | 0U; /* Level 1 data cache */ + SCB->CSSELR = 0U; /* select Level 1 data cache */ __DSB(); ccsidr = SCB->CCSIDR; @@ -2287,8 +2458,8 @@ __STATIC_INLINE void SCB_CleanInvalidateDCache (void) #if defined ( __CC_ARM ) __schedule_barrier(); #endif - } while (ways--); - } while(sets--); + } while (ways-- != 0U); + } while(sets-- != 0U); __DSB(); __ISB(); @@ -2298,27 +2469,30 @@ __STATIC_INLINE void SCB_CleanInvalidateDCache (void) /** \brief D-Cache Invalidate by address - \details Invalidates D-Cache for the given address - \param[in] addr address (aligned to 32-byte boundary) + \details Invalidates D-Cache for the given address. + D-Cache is invalidated starting from a 32 byte aligned address in 32 byte granularity. + D-Cache memory blocks which are part of given address + given size are invalidated. + \param[in] addr address \param[in] dsize size of memory block (in number of bytes) */ -__STATIC_INLINE void SCB_InvalidateDCache_by_Addr (uint32_t *addr, int32_t dsize) +__STATIC_FORCEINLINE void SCB_InvalidateDCache_by_Addr (void *addr, int32_t dsize) { - #if (__DCACHE_PRESENT == 1U) - int32_t op_size = dsize; - uint32_t op_addr = (uint32_t)addr; - int32_t linesize = 32U; /* in Cortex-M7 size of cache line is fixed to 8 words (32 bytes) */ + #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) + if ( dsize > 0 ) { + int32_t op_size = dsize + (((uint32_t)addr) & (__SCB_DCACHE_LINE_SIZE - 1U)); + uint32_t op_addr = (uint32_t)addr /* & ~(__SCB_DCACHE_LINE_SIZE - 1U) */; + + __DSB(); - __DSB(); + do { + SCB->DCIMVAC = op_addr; /* register accepts only 32byte aligned values, only bits 31..5 are valid */ + op_addr += __SCB_DCACHE_LINE_SIZE; + op_size -= __SCB_DCACHE_LINE_SIZE; + } while ( op_size > 0 ); - while (op_size > 0) { - SCB->DCIMVAC = op_addr; - op_addr += linesize; - op_size -= linesize; + __DSB(); + __ISB(); } - - __DSB(); - __ISB(); #endif } @@ -2326,26 +2500,29 @@ __STATIC_INLINE void SCB_InvalidateDCache_by_Addr (uint32_t *addr, int32_t dsize /** \brief D-Cache Clean by address \details Cleans D-Cache for the given address - \param[in] addr address (aligned to 32-byte boundary) + D-Cache is cleaned starting from a 32 byte aligned address in 32 byte granularity. + D-Cache memory blocks which are part of given address + given size are cleaned. + \param[in] addr address \param[in] dsize size of memory block (in number of bytes) */ -__STATIC_INLINE void SCB_CleanDCache_by_Addr (uint32_t *addr, int32_t dsize) +__STATIC_FORCEINLINE void SCB_CleanDCache_by_Addr (uint32_t *addr, int32_t dsize) { - #if (__DCACHE_PRESENT == 1) - int32_t op_size = dsize; - uint32_t op_addr = (uint32_t) addr; - int32_t linesize = 32U; /* in Cortex-M7 size of cache line is fixed to 8 words (32 bytes) */ + #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) + if ( dsize > 0 ) { + int32_t op_size = dsize + (((uint32_t)addr) & (__SCB_DCACHE_LINE_SIZE - 1U)); + uint32_t op_addr = (uint32_t)addr /* & ~(__SCB_DCACHE_LINE_SIZE - 1U) */; + + __DSB(); - __DSB(); + do { + SCB->DCCMVAC = op_addr; /* register accepts only 32byte aligned values, only bits 31..5 are valid */ + op_addr += __SCB_DCACHE_LINE_SIZE; + op_size -= __SCB_DCACHE_LINE_SIZE; + } while ( op_size > 0 ); - while (op_size > 0) { - SCB->DCCMVAC = op_addr; - op_addr += linesize; - op_size -= linesize; + __DSB(); + __ISB(); } - - __DSB(); - __ISB(); #endif } @@ -2353,30 +2530,32 @@ __STATIC_INLINE void SCB_CleanDCache_by_Addr (uint32_t *addr, int32_t dsize) /** \brief D-Cache Clean and Invalidate by address \details Cleans and invalidates D_Cache for the given address + D-Cache is cleaned and invalidated starting from a 32 byte aligned address in 32 byte granularity. + D-Cache memory blocks which are part of given address + given size are cleaned and invalidated. \param[in] addr address (aligned to 32-byte boundary) \param[in] dsize size of memory block (in number of bytes) */ -__STATIC_INLINE void SCB_CleanInvalidateDCache_by_Addr (uint32_t *addr, int32_t dsize) +__STATIC_FORCEINLINE void SCB_CleanInvalidateDCache_by_Addr (uint32_t *addr, int32_t dsize) { - #if (__DCACHE_PRESENT == 1U) - int32_t op_size = dsize; - uint32_t op_addr = (uint32_t) addr; - int32_t linesize = 32U; /* in Cortex-M7 size of cache line is fixed to 8 words (32 bytes) */ + #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) + if ( dsize > 0 ) { + int32_t op_size = dsize + (((uint32_t)addr) & (__SCB_DCACHE_LINE_SIZE - 1U)); + uint32_t op_addr = (uint32_t)addr /* & ~(__SCB_DCACHE_LINE_SIZE - 1U) */; + + __DSB(); - __DSB(); + do { + SCB->DCCIMVAC = op_addr; /* register accepts only 32byte aligned values, only bits 31..5 are valid */ + op_addr += __SCB_DCACHE_LINE_SIZE; + op_size -= __SCB_DCACHE_LINE_SIZE; + } while ( op_size > 0 ); - while (op_size > 0) { - SCB->DCCIMVAC = op_addr; - op_addr += linesize; - op_size -= linesize; + __DSB(); + __ISB(); } - - __DSB(); - __ISB(); #endif } - /*@} end of CMSIS_Core_CacheFunctions */ @@ -2389,7 +2568,7 @@ __STATIC_INLINE void SCB_CleanInvalidateDCache_by_Addr (uint32_t *addr, int32_t @{ */ -#if (__Vendor_SysTickConfig == 0U) +#if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U) /** \brief System Tick Configuration @@ -2432,8 +2611,8 @@ __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) @{ */ -extern volatile int32_t ITM_RxBuffer; /*!< External variable to receive characters. */ -#define ITM_RXBUFFER_EMPTY 0x5AA55AA5U /*!< Value identifying \ref ITM_RxBuffer is ready for next character. */ +extern volatile int32_t ITM_RxBuffer; /*!< External variable to receive characters. */ +#define ITM_RXBUFFER_EMPTY ((int32_t)0x5AA55AA5U) /*!< Value identifying \ref ITM_RxBuffer is ready for next character. */ /** diff --git a/lib/cmsis/inc/core_cmFunc.h b/lib/cmsis/inc/core_cmFunc.h deleted file mode 100644 index 652a48af07..0000000000 --- a/lib/cmsis/inc/core_cmFunc.h +++ /dev/null @@ -1,87 +0,0 @@ -/**************************************************************************//** - * @file core_cmFunc.h - * @brief CMSIS Cortex-M Core Function Access Header File - * @version V4.30 - * @date 20. October 2015 - ******************************************************************************/ -/* Copyright (c) 2009 - 2015 ARM LIMITED - - All rights reserved. - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 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. - - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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. - ---------------------------------------------------------------------------*/ - - -#if defined ( __ICCARM__ ) - #pragma system_include /* treat file as system include file for MISRA check */ -#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) - #pragma clang system_header /* treat file as system include file */ -#endif - -#ifndef __CORE_CMFUNC_H -#define __CORE_CMFUNC_H - - -/* ########################### Core Function Access ########################### */ -/** \ingroup CMSIS_Core_FunctionInterface - \defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions - @{ -*/ - -/*------------------ RealView Compiler -----------------*/ -#if defined ( __CC_ARM ) - #include "cmsis_armcc.h" - -/*------------------ ARM Compiler V6 -------------------*/ -#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) - #include "cmsis_armcc_V6.h" - -/*------------------ GNU Compiler ----------------------*/ -#elif defined ( __GNUC__ ) - #include "cmsis_gcc.h" - -/*------------------ ICC Compiler ----------------------*/ -#elif defined ( __ICCARM__ ) - #include - -/*------------------ TI CCS Compiler -------------------*/ -#elif defined ( __TMS470__ ) - #include - -/*------------------ TASKING Compiler ------------------*/ -#elif defined ( __TASKING__ ) - /* - * The CMSIS functions have been implemented as intrinsics in the compiler. - * Please use "carm -?i" to get an up to date list of all intrinsics, - * Including the CMSIS ones. - */ - -/*------------------ COSMIC Compiler -------------------*/ -#elif defined ( __CSMC__ ) - #include - -#endif - -/*@} end of CMSIS_Core_RegAccFunctions */ - -#endif /* __CORE_CMFUNC_H */ diff --git a/lib/cmsis/inc/core_cmInstr.h b/lib/cmsis/inc/core_cmInstr.h deleted file mode 100644 index f474b0e6f3..0000000000 --- a/lib/cmsis/inc/core_cmInstr.h +++ /dev/null @@ -1,87 +0,0 @@ -/**************************************************************************//** - * @file core_cmInstr.h - * @brief CMSIS Cortex-M Core Instruction Access Header File - * @version V4.30 - * @date 20. October 2015 - ******************************************************************************/ -/* Copyright (c) 2009 - 2015 ARM LIMITED - - All rights reserved. - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 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. - - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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. - ---------------------------------------------------------------------------*/ - - -#if defined ( __ICCARM__ ) - #pragma system_include /* treat file as system include file for MISRA check */ -#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) - #pragma clang system_header /* treat file as system include file */ -#endif - -#ifndef __CORE_CMINSTR_H -#define __CORE_CMINSTR_H - - -/* ########################## Core Instruction Access ######################### */ -/** \defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface - Access to dedicated instructions - @{ -*/ - -/*------------------ RealView Compiler -----------------*/ -#if defined ( __CC_ARM ) - #include "cmsis_armcc.h" - -/*------------------ ARM Compiler V6 -------------------*/ -#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) - #include "cmsis_armcc_V6.h" - -/*------------------ GNU Compiler ----------------------*/ -#elif defined ( __GNUC__ ) - #include "cmsis_gcc.h" - -/*------------------ ICC Compiler ----------------------*/ -#elif defined ( __ICCARM__ ) - #include - -/*------------------ TI CCS Compiler -------------------*/ -#elif defined ( __TMS470__ ) - #include - -/*------------------ TASKING Compiler ------------------*/ -#elif defined ( __TASKING__ ) - /* - * The CMSIS functions have been implemented as intrinsics in the compiler. - * Please use "carm -?i" to get an up to date list of all intrinsics, - * Including the CMSIS ones. - */ - -/*------------------ COSMIC Compiler -------------------*/ -#elif defined ( __CSMC__ ) - #include - -#endif - -/*@}*/ /* end of group CMSIS_Core_InstructionInterface */ - -#endif /* __CORE_CMINSTR_H */ diff --git a/lib/cmsis/inc/core_cmSimd.h b/lib/cmsis/inc/core_cmSimd.h deleted file mode 100644 index 66bf5c2a72..0000000000 --- a/lib/cmsis/inc/core_cmSimd.h +++ /dev/null @@ -1,96 +0,0 @@ -/**************************************************************************//** - * @file core_cmSimd.h - * @brief CMSIS Cortex-M SIMD Header File - * @version V4.30 - * @date 20. October 2015 - ******************************************************************************/ -/* Copyright (c) 2009 - 2015 ARM LIMITED - - All rights reserved. - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 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. - - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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. - ---------------------------------------------------------------------------*/ - - -#if defined ( __ICCARM__ ) - #pragma system_include /* treat file as system include file for MISRA check */ -#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) - #pragma clang system_header /* treat file as system include file */ -#endif - -#ifndef __CORE_CMSIMD_H -#define __CORE_CMSIMD_H - -#ifdef __cplusplus - extern "C" { -#endif - - -/* ################### Compiler specific Intrinsics ########################### */ -/** \defgroup CMSIS_SIMD_intrinsics CMSIS SIMD Intrinsics - Access to dedicated SIMD instructions - @{ -*/ - -/*------------------ RealView Compiler -----------------*/ -#if defined ( __CC_ARM ) - #include "cmsis_armcc.h" - -/*------------------ ARM Compiler V6 -------------------*/ -#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) - #include "cmsis_armcc_V6.h" - -/*------------------ GNU Compiler ----------------------*/ -#elif defined ( __GNUC__ ) - #include "cmsis_gcc.h" - -/*------------------ ICC Compiler ----------------------*/ -#elif defined ( __ICCARM__ ) - #include - -/*------------------ TI CCS Compiler -------------------*/ -#elif defined ( __TMS470__ ) - #include - -/*------------------ TASKING Compiler ------------------*/ -#elif defined ( __TASKING__ ) - /* - * The CMSIS functions have been implemented as intrinsics in the compiler. - * Please use "carm -?i" to get an up to date list of all intrinsics, - * Including the CMSIS ones. - */ - -/*------------------ COSMIC Compiler -------------------*/ -#elif defined ( __CSMC__ ) - #include - -#endif - -/*@} end of group CMSIS_SIMD_intrinsics */ - - -#ifdef __cplusplus -} -#endif - -#endif /* __CORE_CMSIMD_H */ diff --git a/lib/cmsis/inc/core_sc000.h b/lib/cmsis/inc/core_sc000.h index 514dbd81b9..389535a7cf 100644 --- a/lib/cmsis/inc/core_sc000.h +++ b/lib/cmsis/inc/core_sc000.h @@ -1,40 +1,30 @@ /**************************************************************************//** * @file core_sc000.h * @brief CMSIS SC000 Core Peripheral Access Layer Header File - * @version V4.30 - * @date 20. October 2015 + * @version V5.0.6 + * @date 12. November 2018 ******************************************************************************/ -/* Copyright (c) 2009 - 2015 ARM LIMITED - - All rights reserved. - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 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. - - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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. - ---------------------------------------------------------------------------*/ - +/* + * Copyright (c) 2009-2018 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #if defined ( __ICCARM__ ) - #pragma system_include /* treat file as system include file for MISRA check */ -#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined (__clang__) #pragma clang system_header /* treat file as system include file */ #endif @@ -70,53 +60,15 @@ @{ */ +#include "cmsis_version.h" + /* CMSIS SC000 definitions */ -#define __SC000_CMSIS_VERSION_MAIN (0x04U) /*!< [31:16] CMSIS HAL main version */ -#define __SC000_CMSIS_VERSION_SUB (0x1EU) /*!< [15:0] CMSIS HAL sub version */ +#define __SC000_CMSIS_VERSION_MAIN (__CM_CMSIS_VERSION_MAIN) /*!< \deprecated [31:16] CMSIS HAL main version */ +#define __SC000_CMSIS_VERSION_SUB (__CM_CMSIS_VERSION_SUB) /*!< \deprecated [15:0] CMSIS HAL sub version */ #define __SC000_CMSIS_VERSION ((__SC000_CMSIS_VERSION_MAIN << 16U) | \ - __SC000_CMSIS_VERSION_SUB ) /*!< CMSIS HAL version number */ + __SC000_CMSIS_VERSION_SUB ) /*!< \deprecated CMSIS HAL version number */ -#define __CORTEX_SC (000U) /*!< Cortex secure core */ - - -#if defined ( __CC_ARM ) - #define __ASM __asm /*!< asm keyword for ARM Compiler */ - #define __INLINE __inline /*!< inline keyword for ARM Compiler */ - #define __STATIC_INLINE static __inline - -#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) - #define __ASM __asm /*!< asm keyword for ARM Compiler */ - #define __INLINE __inline /*!< inline keyword for ARM Compiler */ - #define __STATIC_INLINE static __inline - -#elif defined ( __GNUC__ ) - #define __ASM __asm /*!< asm keyword for GNU Compiler */ - #define __INLINE inline /*!< inline keyword for GNU Compiler */ - #define __STATIC_INLINE static inline - -#elif defined ( __ICCARM__ ) - #define __ASM __asm /*!< asm keyword for IAR Compiler */ - #define __INLINE inline /*!< inline keyword for IAR Compiler. Only available in High optimization mode! */ - #define __STATIC_INLINE static inline - -#elif defined ( __TMS470__ ) - #define __ASM __asm /*!< asm keyword for TI CCS Compiler */ - #define __STATIC_INLINE static inline - -#elif defined ( __TASKING__ ) - #define __ASM __asm /*!< asm keyword for TASKING Compiler */ - #define __INLINE inline /*!< inline keyword for TASKING Compiler */ - #define __STATIC_INLINE static inline - -#elif defined ( __CSMC__ ) - #define __packed - #define __ASM _asm /*!< asm keyword for COSMIC Compiler */ - #define __INLINE inline /*!< inline keyword for COSMIC Compiler. Use -pc99 on compile line */ - #define __STATIC_INLINE static inline - -#else - #error Unknown compiler -#endif +#define __CORTEX_SC (000U) /*!< Cortex secure core */ /** __FPU_USED indicates whether an FPU is used or not. This core does not support an FPU at all @@ -128,8 +80,8 @@ #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif -#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) - #if defined __ARM_PCS_VFP +#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #if defined __ARM_FP #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif @@ -143,7 +95,7 @@ #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif -#elif defined ( __TMS470__ ) +#elif defined ( __TI_ARM__ ) #if defined __TI_VFP_SUPPORT__ #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif @@ -160,8 +112,8 @@ #endif -#include "core_cmInstr.h" /* Core Instruction Access */ -#include "core_cmFunc.h" /* Core Function Access */ +#include "cmsis_compiler.h" /* CMSIS compiler specific defines */ + #ifdef __cplusplus } @@ -569,7 +521,7 @@ typedef struct /*@} end of group CMSIS_SysTick */ -#if (__MPU_PRESENT == 1U) +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) /** \ingroup CMSIS_core_register \defgroup CMSIS_MPU Memory Protection Unit (MPU) @@ -678,18 +630,18 @@ typedef struct /** \brief Mask and shift a bit field value for use in a register bit range. \param[in] field Name of the register bit field. - \param[in] value Value of the bit field. + \param[in] value Value of the bit field. This parameter is interpreted as an uint32_t type. \return Masked and shifted value. */ -#define _VAL2FLD(field, value) ((value << field ## _Pos) & field ## _Msk) +#define _VAL2FLD(field, value) (((uint32_t)(value) << field ## _Pos) & field ## _Msk) /** \brief Mask and shift a register value to extract a bit filed value. \param[in] field Name of the register bit field. - \param[in] value Value of register. + \param[in] value Value of register. This parameter is interpreted as an uint32_t type. \return Masked and shifted bit field value. */ -#define _FLD2VAL(field, value) ((value & field ## _Msk) >> field ## _Pos) +#define _FLD2VAL(field, value) (((uint32_t)(value) & field ## _Msk) >> field ## _Pos) /*@} end of group CMSIS_core_bitfield */ @@ -701,7 +653,7 @@ typedef struct @{ */ -/* Memory mapping of SC000 Hardware */ +/* Memory mapping of Core Hardware */ #define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ #define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */ #define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */ @@ -712,7 +664,7 @@ typedef struct #define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */ #define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */ -#if (__MPU_PRESENT == 1U) +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) #define MPU_BASE (SCS_BASE + 0x0D90UL) /*!< Memory Protection Unit */ #define MPU ((MPU_Type *) MPU_BASE ) /*!< Memory Protection Unit */ #endif @@ -742,7 +694,46 @@ typedef struct @{ */ -/* Interrupt Priorities are WORD accessible only under ARMv6M */ +#ifdef CMSIS_NVIC_VIRTUAL + #ifndef CMSIS_NVIC_VIRTUAL_HEADER_FILE + #define CMSIS_NVIC_VIRTUAL_HEADER_FILE "cmsis_nvic_virtual.h" + #endif + #include CMSIS_NVIC_VIRTUAL_HEADER_FILE +#else +/*#define NVIC_SetPriorityGrouping __NVIC_SetPriorityGrouping not available for SC000 */ +/*#define NVIC_GetPriorityGrouping __NVIC_GetPriorityGrouping not available for SC000 */ + #define NVIC_EnableIRQ __NVIC_EnableIRQ + #define NVIC_GetEnableIRQ __NVIC_GetEnableIRQ + #define NVIC_DisableIRQ __NVIC_DisableIRQ + #define NVIC_GetPendingIRQ __NVIC_GetPendingIRQ + #define NVIC_SetPendingIRQ __NVIC_SetPendingIRQ + #define NVIC_ClearPendingIRQ __NVIC_ClearPendingIRQ +/*#define NVIC_GetActive __NVIC_GetActive not available for SC000 */ + #define NVIC_SetPriority __NVIC_SetPriority + #define NVIC_GetPriority __NVIC_GetPriority + #define NVIC_SystemReset __NVIC_SystemReset +#endif /* CMSIS_NVIC_VIRTUAL */ + +#ifdef CMSIS_VECTAB_VIRTUAL + #ifndef CMSIS_VECTAB_VIRTUAL_HEADER_FILE + #define CMSIS_VECTAB_VIRTUAL_HEADER_FILE "cmsis_vectab_virtual.h" + #endif + #include CMSIS_VECTAB_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetVector __NVIC_SetVector + #define NVIC_GetVector __NVIC_GetVector +#endif /* (CMSIS_VECTAB_VIRTUAL) */ + +#define NVIC_USER_IRQ_OFFSET 16 + + +/* The following EXC_RETURN values are saved the LR on exception entry */ +#define EXC_RETURN_HANDLER (0xFFFFFFF1UL) /* return to Handler mode, uses MSP after return */ +#define EXC_RETURN_THREAD_MSP (0xFFFFFFF9UL) /* return to Thread mode, uses MSP after return */ +#define EXC_RETURN_THREAD_PSP (0xFFFFFFFDUL) /* return to Thread mode, uses PSP after return */ + + +/* Interrupt Priorities are WORD accessible only under Armv6-M */ /* The following MACROS handle generation of the register offset and byte masks */ #define _BIT_SHIFT(IRQn) ( ((((uint32_t)(int32_t)(IRQn)) ) & 0x03UL) * 8UL) #define _SHP_IDX(IRQn) ( (((((uint32_t)(int32_t)(IRQn)) & 0x0FUL)-8UL) >> 2UL) ) @@ -750,79 +741,128 @@ typedef struct /** - \brief Enable External Interrupt - \details Enables a device-specific interrupt in the NVIC interrupt controller. - \param [in] IRQn External interrupt number. Value cannot be negative. + \brief Enable Interrupt + \details Enables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. */ -__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn) +__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn) { - NVIC->ISER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISER[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } } /** - \brief Disable External Interrupt - \details Disables a device-specific interrupt in the NVIC interrupt controller. - \param [in] IRQn External interrupt number. Value cannot be negative. + \brief Get Interrupt Enable status + \details Returns a device specific interrupt enable status from the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt is not enabled. + \return 1 Interrupt is enabled. + \note IRQn must not be negative. */ -__STATIC_INLINE void NVIC_DisableIRQ(IRQn_Type IRQn) +__STATIC_INLINE uint32_t __NVIC_GetEnableIRQ(IRQn_Type IRQn) { - NVIC->ICER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISER[0U] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Disable Interrupt + \details Disables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_DisableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICER[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + __DSB(); + __ISB(); + } } /** \brief Get Pending Interrupt - \details Reads the pending register in the NVIC and returns the pending bit for the specified interrupt. - \param [in] IRQn Interrupt number. + \details Reads the NVIC pending register and returns the pending bit for the specified device specific interrupt. + \param [in] IRQn Device specific interrupt number. \return 0 Interrupt status is not pending. \return 1 Interrupt status is pending. + \note IRQn must not be negative. */ -__STATIC_INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn) +__STATIC_INLINE uint32_t __NVIC_GetPendingIRQ(IRQn_Type IRQn) { - return((uint32_t)(((NVIC->ISPR[0U] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISPR[0U] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } } /** \brief Set Pending Interrupt - \details Sets the pending bit of an external interrupt. - \param [in] IRQn Interrupt number. Value cannot be negative. + \details Sets the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. */ -__STATIC_INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn) +__STATIC_INLINE void __NVIC_SetPendingIRQ(IRQn_Type IRQn) { - NVIC->ISPR[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISPR[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } } /** \brief Clear Pending Interrupt - \details Clears the pending bit of an external interrupt. - \param [in] IRQn External interrupt number. Value cannot be negative. + \details Clears the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. */ -__STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn) +__STATIC_INLINE void __NVIC_ClearPendingIRQ(IRQn_Type IRQn) { - NVIC->ICPR[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICPR[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } } /** \brief Set Interrupt Priority - \details Sets the priority of an interrupt. - \note The priority cannot be set for every core interrupt. + \details Sets the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. \param [in] IRQn Interrupt number. \param [in] priority Priority to set. + \note The priority cannot be set for every processor exception. */ -__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +__STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) { - if ((int32_t)(IRQn) < 0) + if ((int32_t)(IRQn) >= 0) { - SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); } else { - NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); } } @@ -830,24 +870,55 @@ __STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) /** \brief Get Interrupt Priority - \details Reads the priority of an interrupt. - The interrupt number can be positive to specify an external (device specific) interrupt, - or negative to specify an internal (core) interrupt. + \details Reads the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. \param [in] IRQn Interrupt number. \return Interrupt Priority. Value is aligned automatically to the implemented priority bits of the microcontroller. */ -__STATIC_INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn) +__STATIC_INLINE uint32_t __NVIC_GetPriority(IRQn_Type IRQn) { - if ((int32_t)(IRQn) < 0) - { - return((uint32_t)(((SCB->SHP[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); - } - else + if ((int32_t)(IRQn) >= 0) { return((uint32_t)(((NVIC->IP[ _IP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); } + else + { + return((uint32_t)(((SCB->SHP[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); + } +} + + +/** + \brief Set Interrupt Vector + \details Sets an interrupt vector in SRAM based interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + VTOR must been relocated to SRAM before. + \param [in] IRQn Interrupt number + \param [in] vector Address of interrupt handler function + */ +__STATIC_INLINE void __NVIC_SetVector(IRQn_Type IRQn, uint32_t vector) +{ + uint32_t *vectors = (uint32_t *)SCB->VTOR; + vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET] = vector; +} + + +/** + \brief Get Interrupt Vector + \details Reads an interrupt vector from interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Address of interrupt handler function + */ +__STATIC_INLINE uint32_t __NVIC_GetVector(IRQn_Type IRQn) +{ + uint32_t *vectors = (uint32_t *)SCB->VTOR; + return vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET]; } @@ -855,7 +926,7 @@ __STATIC_INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn) \brief System Reset \details Initiates a system reset request to reset the MCU. */ -__STATIC_INLINE void NVIC_SystemReset(void) +__NO_RETURN __STATIC_INLINE void __NVIC_SystemReset(void) { __DSB(); /* Ensure all outstanding memory accesses included buffered write are completed before reset */ @@ -872,6 +943,31 @@ __STATIC_INLINE void NVIC_SystemReset(void) /*@} end of CMSIS_Core_NVICFunctions */ +/* ########################## FPU functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_FpuFunctions FPU Functions + \brief Function that provides FPU type. + @{ + */ + +/** + \brief get FPU type + \details returns the FPU type + \returns + - \b 0: No FPU + - \b 1: Single precision FPU + - \b 2: Double + Single precision FPU + */ +__STATIC_INLINE uint32_t SCB_GetFPUType(void) +{ + return 0U; /* No FPU */ +} + + +/*@} end of CMSIS_Core_FpuFunctions */ + + /* ################################## SysTick function ############################################ */ /** @@ -881,7 +977,7 @@ __STATIC_INLINE void NVIC_SystemReset(void) @{ */ -#if (__Vendor_SysTickConfig == 0U) +#if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U) /** \brief System Tick Configuration diff --git a/lib/cmsis/inc/core_sc300.h b/lib/cmsis/inc/core_sc300.h index 8bd18aa318..5478ea74a5 100644 --- a/lib/cmsis/inc/core_sc300.h +++ b/lib/cmsis/inc/core_sc300.h @@ -1,40 +1,30 @@ /**************************************************************************//** * @file core_sc300.h * @brief CMSIS SC300 Core Peripheral Access Layer Header File - * @version V4.30 - * @date 20. October 2015 + * @version V5.0.7 + * @date 12. November 2018 ******************************************************************************/ -/* Copyright (c) 2009 - 2015 ARM LIMITED - - All rights reserved. - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 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. - - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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. - ---------------------------------------------------------------------------*/ - +/* + * Copyright (c) 2009-2018 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #if defined ( __ICCARM__ ) - #pragma system_include /* treat file as system include file for MISRA check */ -#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined (__clang__) #pragma clang system_header /* treat file as system include file */ #endif @@ -70,53 +60,15 @@ @{ */ +#include "cmsis_version.h" + /* CMSIS SC300 definitions */ -#define __SC300_CMSIS_VERSION_MAIN (0x04U) /*!< [31:16] CMSIS HAL main version */ -#define __SC300_CMSIS_VERSION_SUB (0x1EU) /*!< [15:0] CMSIS HAL sub version */ +#define __SC300_CMSIS_VERSION_MAIN (__CM_CMSIS_VERSION_MAIN) /*!< \deprecated [31:16] CMSIS HAL main version */ +#define __SC300_CMSIS_VERSION_SUB (__CM_CMSIS_VERSION_SUB) /*!< \deprecated [15:0] CMSIS HAL sub version */ #define __SC300_CMSIS_VERSION ((__SC300_CMSIS_VERSION_MAIN << 16U) | \ - __SC300_CMSIS_VERSION_SUB ) /*!< CMSIS HAL version number */ + __SC300_CMSIS_VERSION_SUB ) /*!< \deprecated CMSIS HAL version number */ -#define __CORTEX_SC (300U) /*!< Cortex secure core */ - - -#if defined ( __CC_ARM ) - #define __ASM __asm /*!< asm keyword for ARM Compiler */ - #define __INLINE __inline /*!< inline keyword for ARM Compiler */ - #define __STATIC_INLINE static __inline - -#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) - #define __ASM __asm /*!< asm keyword for ARM Compiler */ - #define __INLINE __inline /*!< inline keyword for ARM Compiler */ - #define __STATIC_INLINE static __inline - -#elif defined ( __GNUC__ ) - #define __ASM __asm /*!< asm keyword for GNU Compiler */ - #define __INLINE inline /*!< inline keyword for GNU Compiler */ - #define __STATIC_INLINE static inline - -#elif defined ( __ICCARM__ ) - #define __ASM __asm /*!< asm keyword for IAR Compiler */ - #define __INLINE inline /*!< inline keyword for IAR Compiler. Only available in High optimization mode! */ - #define __STATIC_INLINE static inline - -#elif defined ( __TMS470__ ) - #define __ASM __asm /*!< asm keyword for TI CCS Compiler */ - #define __STATIC_INLINE static inline - -#elif defined ( __TASKING__ ) - #define __ASM __asm /*!< asm keyword for TASKING Compiler */ - #define __INLINE inline /*!< inline keyword for TASKING Compiler */ - #define __STATIC_INLINE static inline - -#elif defined ( __CSMC__ ) - #define __packed - #define __ASM _asm /*!< asm keyword for COSMIC Compiler */ - #define __INLINE inline /*!< inline keyword for COSMIC Compiler. Use -pc99 on compile line */ - #define __STATIC_INLINE static inline - -#else - #error Unknown compiler -#endif +#define __CORTEX_SC (300U) /*!< Cortex secure core */ /** __FPU_USED indicates whether an FPU is used or not. This core does not support an FPU at all @@ -128,8 +80,8 @@ #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif -#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) - #if defined __ARM_PCS_VFP +#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #if defined __ARM_FP #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif @@ -143,7 +95,7 @@ #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif -#elif defined ( __TMS470__ ) +#elif defined ( __TI_ARM__ ) #if defined __TI_VFP_SUPPORT__ #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif @@ -160,8 +112,8 @@ #endif -#include "core_cmInstr.h" /* Core Instruction Access */ -#include "core_cmFunc.h" /* Core Function Access */ +#include "cmsis_compiler.h" /* CMSIS compiler specific defines */ + #ifdef __cplusplus } @@ -191,7 +143,7 @@ #endif #ifndef __NVIC_PRIO_BITS - #define __NVIC_PRIO_BITS 4U + #define __NVIC_PRIO_BITS 3U #warning "__NVIC_PRIO_BITS not defined in device header file; using default!" #endif @@ -308,9 +260,11 @@ typedef union struct { uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ - uint32_t _reserved0:15; /*!< bit: 9..23 Reserved */ - uint32_t T:1; /*!< bit: 24 Thumb bit (read 0) */ - uint32_t IT:2; /*!< bit: 25..26 saved IT state (read 0) */ + uint32_t _reserved0:1; /*!< bit: 9 Reserved */ + uint32_t ICI_IT_1:6; /*!< bit: 10..15 ICI/IT part 1 */ + uint32_t _reserved1:8; /*!< bit: 16..23 Reserved */ + uint32_t T:1; /*!< bit: 24 Thumb bit */ + uint32_t ICI_IT_2:2; /*!< bit: 25..26 ICI/IT part 2 */ uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ uint32_t C:1; /*!< bit: 29 Carry condition code flag */ @@ -336,12 +290,15 @@ typedef union #define xPSR_Q_Pos 27U /*!< xPSR: Q Position */ #define xPSR_Q_Msk (1UL << xPSR_Q_Pos) /*!< xPSR: Q Mask */ -#define xPSR_IT_Pos 25U /*!< xPSR: IT Position */ -#define xPSR_IT_Msk (3UL << xPSR_IT_Pos) /*!< xPSR: IT Mask */ +#define xPSR_ICI_IT_2_Pos 25U /*!< xPSR: ICI/IT part 2 Position */ +#define xPSR_ICI_IT_2_Msk (3UL << xPSR_ICI_IT_2_Pos) /*!< xPSR: ICI/IT part 2 Mask */ #define xPSR_T_Pos 24U /*!< xPSR: T Position */ #define xPSR_T_Msk (1UL << xPSR_T_Pos) /*!< xPSR: T Mask */ +#define xPSR_ICI_IT_1_Pos 10U /*!< xPSR: ICI/IT part 1 Position */ +#define xPSR_ICI_IT_1_Msk (0x3FUL << xPSR_ICI_IT_1_Pos) /*!< xPSR: ICI/IT part 1 Mask */ + #define xPSR_ISR_Pos 0U /*!< xPSR: ISR Position */ #define xPSR_ISR_Msk (0x1FFUL /*<< xPSR_ISR_Pos*/) /*!< xPSR: ISR Mask */ @@ -599,6 +556,60 @@ typedef struct #define SCB_CFSR_MEMFAULTSR_Pos 0U /*!< SCB CFSR: Memory Manage Fault Status Register Position */ #define SCB_CFSR_MEMFAULTSR_Msk (0xFFUL /*<< SCB_CFSR_MEMFAULTSR_Pos*/) /*!< SCB CFSR: Memory Manage Fault Status Register Mask */ +/* MemManage Fault Status Register (part of SCB Configurable Fault Status Register) */ +#define SCB_CFSR_MMARVALID_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 7U) /*!< SCB CFSR (MMFSR): MMARVALID Position */ +#define SCB_CFSR_MMARVALID_Msk (1UL << SCB_CFSR_MMARVALID_Pos) /*!< SCB CFSR (MMFSR): MMARVALID Mask */ + +#define SCB_CFSR_MSTKERR_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 4U) /*!< SCB CFSR (MMFSR): MSTKERR Position */ +#define SCB_CFSR_MSTKERR_Msk (1UL << SCB_CFSR_MSTKERR_Pos) /*!< SCB CFSR (MMFSR): MSTKERR Mask */ + +#define SCB_CFSR_MUNSTKERR_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 3U) /*!< SCB CFSR (MMFSR): MUNSTKERR Position */ +#define SCB_CFSR_MUNSTKERR_Msk (1UL << SCB_CFSR_MUNSTKERR_Pos) /*!< SCB CFSR (MMFSR): MUNSTKERR Mask */ + +#define SCB_CFSR_DACCVIOL_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 1U) /*!< SCB CFSR (MMFSR): DACCVIOL Position */ +#define SCB_CFSR_DACCVIOL_Msk (1UL << SCB_CFSR_DACCVIOL_Pos) /*!< SCB CFSR (MMFSR): DACCVIOL Mask */ + +#define SCB_CFSR_IACCVIOL_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 0U) /*!< SCB CFSR (MMFSR): IACCVIOL Position */ +#define SCB_CFSR_IACCVIOL_Msk (1UL /*<< SCB_CFSR_IACCVIOL_Pos*/) /*!< SCB CFSR (MMFSR): IACCVIOL Mask */ + +/* BusFault Status Register (part of SCB Configurable Fault Status Register) */ +#define SCB_CFSR_BFARVALID_Pos (SCB_CFSR_BUSFAULTSR_Pos + 7U) /*!< SCB CFSR (BFSR): BFARVALID Position */ +#define SCB_CFSR_BFARVALID_Msk (1UL << SCB_CFSR_BFARVALID_Pos) /*!< SCB CFSR (BFSR): BFARVALID Mask */ + +#define SCB_CFSR_STKERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 4U) /*!< SCB CFSR (BFSR): STKERR Position */ +#define SCB_CFSR_STKERR_Msk (1UL << SCB_CFSR_STKERR_Pos) /*!< SCB CFSR (BFSR): STKERR Mask */ + +#define SCB_CFSR_UNSTKERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 3U) /*!< SCB CFSR (BFSR): UNSTKERR Position */ +#define SCB_CFSR_UNSTKERR_Msk (1UL << SCB_CFSR_UNSTKERR_Pos) /*!< SCB CFSR (BFSR): UNSTKERR Mask */ + +#define SCB_CFSR_IMPRECISERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 2U) /*!< SCB CFSR (BFSR): IMPRECISERR Position */ +#define SCB_CFSR_IMPRECISERR_Msk (1UL << SCB_CFSR_IMPRECISERR_Pos) /*!< SCB CFSR (BFSR): IMPRECISERR Mask */ + +#define SCB_CFSR_PRECISERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 1U) /*!< SCB CFSR (BFSR): PRECISERR Position */ +#define SCB_CFSR_PRECISERR_Msk (1UL << SCB_CFSR_PRECISERR_Pos) /*!< SCB CFSR (BFSR): PRECISERR Mask */ + +#define SCB_CFSR_IBUSERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 0U) /*!< SCB CFSR (BFSR): IBUSERR Position */ +#define SCB_CFSR_IBUSERR_Msk (1UL << SCB_CFSR_IBUSERR_Pos) /*!< SCB CFSR (BFSR): IBUSERR Mask */ + +/* UsageFault Status Register (part of SCB Configurable Fault Status Register) */ +#define SCB_CFSR_DIVBYZERO_Pos (SCB_CFSR_USGFAULTSR_Pos + 9U) /*!< SCB CFSR (UFSR): DIVBYZERO Position */ +#define SCB_CFSR_DIVBYZERO_Msk (1UL << SCB_CFSR_DIVBYZERO_Pos) /*!< SCB CFSR (UFSR): DIVBYZERO Mask */ + +#define SCB_CFSR_UNALIGNED_Pos (SCB_CFSR_USGFAULTSR_Pos + 8U) /*!< SCB CFSR (UFSR): UNALIGNED Position */ +#define SCB_CFSR_UNALIGNED_Msk (1UL << SCB_CFSR_UNALIGNED_Pos) /*!< SCB CFSR (UFSR): UNALIGNED Mask */ + +#define SCB_CFSR_NOCP_Pos (SCB_CFSR_USGFAULTSR_Pos + 3U) /*!< SCB CFSR (UFSR): NOCP Position */ +#define SCB_CFSR_NOCP_Msk (1UL << SCB_CFSR_NOCP_Pos) /*!< SCB CFSR (UFSR): NOCP Mask */ + +#define SCB_CFSR_INVPC_Pos (SCB_CFSR_USGFAULTSR_Pos + 2U) /*!< SCB CFSR (UFSR): INVPC Position */ +#define SCB_CFSR_INVPC_Msk (1UL << SCB_CFSR_INVPC_Pos) /*!< SCB CFSR (UFSR): INVPC Mask */ + +#define SCB_CFSR_INVSTATE_Pos (SCB_CFSR_USGFAULTSR_Pos + 1U) /*!< SCB CFSR (UFSR): INVSTATE Position */ +#define SCB_CFSR_INVSTATE_Msk (1UL << SCB_CFSR_INVSTATE_Pos) /*!< SCB CFSR (UFSR): INVSTATE Mask */ + +#define SCB_CFSR_UNDEFINSTR_Pos (SCB_CFSR_USGFAULTSR_Pos + 0U) /*!< SCB CFSR (UFSR): UNDEFINSTR Position */ +#define SCB_CFSR_UNDEFINSTR_Msk (1UL << SCB_CFSR_UNDEFINSTR_Pos) /*!< SCB CFSR (UFSR): UNDEFINSTR Mask */ + /* SCB Hard Fault Status Register Definitions */ #define SCB_HFSR_DEBUGEVT_Pos 31U /*!< SCB HFSR: DEBUGEVT Position */ #define SCB_HFSR_DEBUGEVT_Msk (1UL << SCB_HFSR_DEBUGEVT_Pos) /*!< SCB HFSR: DEBUGEVT Mask */ @@ -966,7 +977,7 @@ typedef struct */ typedef struct { - __IOM uint32_t SSPSR; /*!< Offset: 0x000 (R/ ) Supported Parallel Port Size Register */ + __IM uint32_t SSPSR; /*!< Offset: 0x000 (R/ ) Supported Parallel Port Size Register */ __IOM uint32_t CSPSR; /*!< Offset: 0x004 (R/W) Current Parallel Port Size Register */ uint32_t RESERVED0[2U]; __IOM uint32_t ACPR; /*!< Offset: 0x010 (R/W) Asynchronous Clock Prescaler Register */ @@ -977,7 +988,7 @@ typedef struct __IOM uint32_t FFCR; /*!< Offset: 0x304 (R/W) Formatter and Flush Control Register */ __IM uint32_t FSCR; /*!< Offset: 0x308 (R/ ) Formatter Synchronization Counter Register */ uint32_t RESERVED3[759U]; - __IM uint32_t TRIGGER; /*!< Offset: 0xEE8 (R/ ) TRIGGER */ + __IM uint32_t TRIGGER; /*!< Offset: 0xEE8 (R/ ) TRIGGER Register */ __IM uint32_t FIFO0; /*!< Offset: 0xEEC (R/ ) Integration ETM Data */ __IM uint32_t ITATBCTR2; /*!< Offset: 0xEF0 (R/ ) ITATBCTR2 */ uint32_t RESERVED4[1U]; @@ -1047,8 +1058,11 @@ typedef struct #define TPI_FIFO0_ETM0_Msk (0xFFUL /*<< TPI_FIFO0_ETM0_Pos*/) /*!< TPI FIFO0: ETM0 Mask */ /* TPI ITATBCTR2 Register Definitions */ -#define TPI_ITATBCTR2_ATREADY_Pos 0U /*!< TPI ITATBCTR2: ATREADY Position */ -#define TPI_ITATBCTR2_ATREADY_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY_Pos*/) /*!< TPI ITATBCTR2: ATREADY Mask */ +#define TPI_ITATBCTR2_ATREADY2_Pos 0U /*!< TPI ITATBCTR2: ATREADY2 Position */ +#define TPI_ITATBCTR2_ATREADY2_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY2_Pos*/) /*!< TPI ITATBCTR2: ATREADY2 Mask */ + +#define TPI_ITATBCTR2_ATREADY1_Pos 0U /*!< TPI ITATBCTR2: ATREADY1 Position */ +#define TPI_ITATBCTR2_ATREADY1_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY1_Pos*/) /*!< TPI ITATBCTR2: ATREADY1 Mask */ /* TPI Integration ITM Data Register Definitions (FIFO1) */ #define TPI_FIFO1_ITM_ATVALID_Pos 29U /*!< TPI FIFO1: ITM_ATVALID Position */ @@ -1073,12 +1087,15 @@ typedef struct #define TPI_FIFO1_ITM0_Msk (0xFFUL /*<< TPI_FIFO1_ITM0_Pos*/) /*!< TPI FIFO1: ITM0 Mask */ /* TPI ITATBCTR0 Register Definitions */ -#define TPI_ITATBCTR0_ATREADY_Pos 0U /*!< TPI ITATBCTR0: ATREADY Position */ -#define TPI_ITATBCTR0_ATREADY_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY_Pos*/) /*!< TPI ITATBCTR0: ATREADY Mask */ +#define TPI_ITATBCTR0_ATREADY2_Pos 0U /*!< TPI ITATBCTR0: ATREADY2 Position */ +#define TPI_ITATBCTR0_ATREADY2_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY2_Pos*/) /*!< TPI ITATBCTR0: ATREADY2 Mask */ + +#define TPI_ITATBCTR0_ATREADY1_Pos 0U /*!< TPI ITATBCTR0: ATREADY1 Position */ +#define TPI_ITATBCTR0_ATREADY1_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY1_Pos*/) /*!< TPI ITATBCTR0: ATREADY1 Mask */ /* TPI Integration Mode Control Register Definitions */ #define TPI_ITCTRL_Mode_Pos 0U /*!< TPI ITCTRL: Mode Position */ -#define TPI_ITCTRL_Mode_Msk (0x1UL /*<< TPI_ITCTRL_Mode_Pos*/) /*!< TPI ITCTRL: Mode Mask */ +#define TPI_ITCTRL_Mode_Msk (0x3UL /*<< TPI_ITCTRL_Mode_Pos*/) /*!< TPI ITCTRL: Mode Mask */ /* TPI DEVID Register Definitions */ #define TPI_DEVID_NRZVALID_Pos 11U /*!< TPI DEVID: NRZVALID Position */ @@ -1100,16 +1117,16 @@ typedef struct #define TPI_DEVID_NrTraceInput_Msk (0x1FUL /*<< TPI_DEVID_NrTraceInput_Pos*/) /*!< TPI DEVID: NrTraceInput Mask */ /* TPI DEVTYPE Register Definitions */ -#define TPI_DEVTYPE_MajorType_Pos 4U /*!< TPI DEVTYPE: MajorType Position */ -#define TPI_DEVTYPE_MajorType_Msk (0xFUL << TPI_DEVTYPE_MajorType_Pos) /*!< TPI DEVTYPE: MajorType Mask */ - -#define TPI_DEVTYPE_SubType_Pos 0U /*!< TPI DEVTYPE: SubType Position */ +#define TPI_DEVTYPE_SubType_Pos 4U /*!< TPI DEVTYPE: SubType Position */ #define TPI_DEVTYPE_SubType_Msk (0xFUL /*<< TPI_DEVTYPE_SubType_Pos*/) /*!< TPI DEVTYPE: SubType Mask */ +#define TPI_DEVTYPE_MajorType_Pos 0U /*!< TPI DEVTYPE: MajorType Position */ +#define TPI_DEVTYPE_MajorType_Msk (0xFUL << TPI_DEVTYPE_MajorType_Pos) /*!< TPI DEVTYPE: MajorType Mask */ + /*@}*/ /* end of group CMSIS_TPI */ -#if (__MPU_PRESENT == 1U) +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) /** \ingroup CMSIS_core_register \defgroup CMSIS_MPU Memory Protection Unit (MPU) @@ -1319,18 +1336,18 @@ typedef struct /** \brief Mask and shift a bit field value for use in a register bit range. \param[in] field Name of the register bit field. - \param[in] value Value of the bit field. + \param[in] value Value of the bit field. This parameter is interpreted as an uint32_t type. \return Masked and shifted value. */ -#define _VAL2FLD(field, value) ((value << field ## _Pos) & field ## _Msk) +#define _VAL2FLD(field, value) (((uint32_t)(value) << field ## _Pos) & field ## _Msk) /** \brief Mask and shift a register value to extract a bit filed value. \param[in] field Name of the register bit field. - \param[in] value Value of register. + \param[in] value Value of register. This parameter is interpreted as an uint32_t type. \return Masked and shifted bit field value. */ -#define _FLD2VAL(field, value) ((value & field ## _Msk) >> field ## _Pos) +#define _FLD2VAL(field, value) (((uint32_t)(value) & field ## _Msk) >> field ## _Pos) /*@} end of group CMSIS_core_bitfield */ @@ -1342,7 +1359,7 @@ typedef struct @{ */ -/* Memory mapping of Cortex-M3 Hardware */ +/* Memory mapping of Core Hardware */ #define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ #define ITM_BASE (0xE0000000UL) /*!< ITM Base Address */ #define DWT_BASE (0xE0001000UL) /*!< DWT Base Address */ @@ -1361,7 +1378,7 @@ typedef struct #define TPI ((TPI_Type *) TPI_BASE ) /*!< TPI configuration struct */ #define CoreDebug ((CoreDebug_Type *) CoreDebug_BASE) /*!< Core Debug configuration struct */ -#if (__MPU_PRESENT == 1U) +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) #define MPU_BASE (SCS_BASE + 0x0D90UL) /*!< Memory Protection Unit */ #define MPU ((MPU_Type *) MPU_BASE ) /*!< Memory Protection Unit */ #endif @@ -1392,6 +1409,46 @@ typedef struct @{ */ +#ifdef CMSIS_NVIC_VIRTUAL + #ifndef CMSIS_NVIC_VIRTUAL_HEADER_FILE + #define CMSIS_NVIC_VIRTUAL_HEADER_FILE "cmsis_nvic_virtual.h" + #endif + #include CMSIS_NVIC_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetPriorityGrouping __NVIC_SetPriorityGrouping + #define NVIC_GetPriorityGrouping __NVIC_GetPriorityGrouping + #define NVIC_EnableIRQ __NVIC_EnableIRQ + #define NVIC_GetEnableIRQ __NVIC_GetEnableIRQ + #define NVIC_DisableIRQ __NVIC_DisableIRQ + #define NVIC_GetPendingIRQ __NVIC_GetPendingIRQ + #define NVIC_SetPendingIRQ __NVIC_SetPendingIRQ + #define NVIC_ClearPendingIRQ __NVIC_ClearPendingIRQ + #define NVIC_GetActive __NVIC_GetActive + #define NVIC_SetPriority __NVIC_SetPriority + #define NVIC_GetPriority __NVIC_GetPriority + #define NVIC_SystemReset __NVIC_SystemReset +#endif /* CMSIS_NVIC_VIRTUAL */ + +#ifdef CMSIS_VECTAB_VIRTUAL + #ifndef CMSIS_VECTAB_VIRTUAL_HEADER_FILE + #define CMSIS_VECTAB_VIRTUAL_HEADER_FILE "cmsis_vectab_virtual.h" + #endif + #include CMSIS_VECTAB_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetVector __NVIC_SetVector + #define NVIC_GetVector __NVIC_GetVector +#endif /* (CMSIS_VECTAB_VIRTUAL) */ + +#define NVIC_USER_IRQ_OFFSET 16 + + +/* The following EXC_RETURN values are saved the LR on exception entry */ +#define EXC_RETURN_HANDLER (0xFFFFFFF1UL) /* return to Handler mode, uses MSP after return */ +#define EXC_RETURN_THREAD_MSP (0xFFFFFFF9UL) /* return to Thread mode, uses MSP after return */ +#define EXC_RETURN_THREAD_PSP (0xFFFFFFFDUL) /* return to Thread mode, uses PSP after return */ + + + /** \brief Set Priority Grouping \details Sets the priority grouping field using the required unlock sequence. @@ -1401,7 +1458,7 @@ typedef struct priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. \param [in] PriorityGroup Priority grouping field. */ -__STATIC_INLINE void NVIC_SetPriorityGrouping(uint32_t PriorityGroup) +__STATIC_INLINE void __NVIC_SetPriorityGrouping(uint32_t PriorityGroup) { uint32_t reg_value; uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ @@ -1420,121 +1477,178 @@ __STATIC_INLINE void NVIC_SetPriorityGrouping(uint32_t PriorityGroup) \details Reads the priority grouping field from the NVIC Interrupt Controller. \return Priority grouping field (SCB->AIRCR [10:8] PRIGROUP field). */ -__STATIC_INLINE uint32_t NVIC_GetPriorityGrouping(void) +__STATIC_INLINE uint32_t __NVIC_GetPriorityGrouping(void) { return ((uint32_t)((SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) >> SCB_AIRCR_PRIGROUP_Pos)); } /** - \brief Enable External Interrupt - \details Enables a device-specific interrupt in the NVIC interrupt controller. - \param [in] IRQn External interrupt number. Value cannot be negative. + \brief Enable Interrupt + \details Enables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. */ -__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn) +__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn) { - NVIC->ISER[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } } /** - \brief Disable External Interrupt - \details Disables a device-specific interrupt in the NVIC interrupt controller. - \param [in] IRQn External interrupt number. Value cannot be negative. + \brief Get Interrupt Enable status + \details Returns a device specific interrupt enable status from the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt is not enabled. + \return 1 Interrupt is enabled. + \note IRQn must not be negative. */ -__STATIC_INLINE void NVIC_DisableIRQ(IRQn_Type IRQn) +__STATIC_INLINE uint32_t __NVIC_GetEnableIRQ(IRQn_Type IRQn) { - NVIC->ICER[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Disable Interrupt + \details Disables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_DisableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + __DSB(); + __ISB(); + } } /** \brief Get Pending Interrupt - \details Reads the pending register in the NVIC and returns the pending bit for the specified interrupt. - \param [in] IRQn Interrupt number. + \details Reads the NVIC pending register and returns the pending bit for the specified device specific interrupt. + \param [in] IRQn Device specific interrupt number. \return 0 Interrupt status is not pending. \return 1 Interrupt status is pending. + \note IRQn must not be negative. */ -__STATIC_INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn) +__STATIC_INLINE uint32_t __NVIC_GetPendingIRQ(IRQn_Type IRQn) { - return((uint32_t)(((NVIC->ISPR[(((uint32_t)(int32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } } /** \brief Set Pending Interrupt - \details Sets the pending bit of an external interrupt. - \param [in] IRQn Interrupt number. Value cannot be negative. + \details Sets the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. */ -__STATIC_INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn) +__STATIC_INLINE void __NVIC_SetPendingIRQ(IRQn_Type IRQn) { - NVIC->ISPR[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } } /** \brief Clear Pending Interrupt - \details Clears the pending bit of an external interrupt. - \param [in] IRQn External interrupt number. Value cannot be negative. + \details Clears the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. */ -__STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn) +__STATIC_INLINE void __NVIC_ClearPendingIRQ(IRQn_Type IRQn) { - NVIC->ICPR[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } } /** \brief Get Active Interrupt - \details Reads the active register in NVIC and returns the active bit. - \param [in] IRQn Interrupt number. + \details Reads the active register in the NVIC and returns the active bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. \return 0 Interrupt status is not active. \return 1 Interrupt status is active. + \note IRQn must not be negative. */ -__STATIC_INLINE uint32_t NVIC_GetActive(IRQn_Type IRQn) +__STATIC_INLINE uint32_t __NVIC_GetActive(IRQn_Type IRQn) { - return((uint32_t)(((NVIC->IABR[(((uint32_t)(int32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->IABR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } } /** \brief Set Interrupt Priority - \details Sets the priority of an interrupt. - \note The priority cannot be set for every core interrupt. + \details Sets the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. \param [in] IRQn Interrupt number. \param [in] priority Priority to set. + \note The priority cannot be set for every processor exception. */ -__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +__STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) { - if ((int32_t)(IRQn) < 0) + if ((int32_t)(IRQn) >= 0) { - SCB->SHP[(((uint32_t)(int32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + NVIC->IP[((uint32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); } else { - NVIC->IP[((uint32_t)(int32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + SCB->SHP[(((uint32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); } } /** \brief Get Interrupt Priority - \details Reads the priority of an interrupt. - The interrupt number can be positive to specify an external (device specific) interrupt, - or negative to specify an internal (core) interrupt. + \details Reads the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. \param [in] IRQn Interrupt number. \return Interrupt Priority. Value is aligned automatically to the implemented priority bits of the microcontroller. */ -__STATIC_INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn) +__STATIC_INLINE uint32_t __NVIC_GetPriority(IRQn_Type IRQn) { - if ((int32_t)(IRQn) < 0) + if ((int32_t)(IRQn) >= 0) { - return(((uint32_t)SCB->SHP[(((uint32_t)(int32_t)IRQn) & 0xFUL)-4UL] >> (8U - __NVIC_PRIO_BITS))); + return(((uint32_t)NVIC->IP[((uint32_t)IRQn)] >> (8U - __NVIC_PRIO_BITS))); } else { - return(((uint32_t)NVIC->IP[((uint32_t)(int32_t)IRQn)] >> (8U - __NVIC_PRIO_BITS))); + return(((uint32_t)SCB->SHP[(((uint32_t)IRQn) & 0xFUL)-4UL] >> (8U - __NVIC_PRIO_BITS))); } } @@ -1591,11 +1705,42 @@ __STATIC_INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGr } +/** + \brief Set Interrupt Vector + \details Sets an interrupt vector in SRAM based interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + VTOR must been relocated to SRAM before. + \param [in] IRQn Interrupt number + \param [in] vector Address of interrupt handler function + */ +__STATIC_INLINE void __NVIC_SetVector(IRQn_Type IRQn, uint32_t vector) +{ + uint32_t *vectors = (uint32_t *)SCB->VTOR; + vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET] = vector; +} + + +/** + \brief Get Interrupt Vector + \details Reads an interrupt vector from interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Address of interrupt handler function + */ +__STATIC_INLINE uint32_t __NVIC_GetVector(IRQn_Type IRQn) +{ + uint32_t *vectors = (uint32_t *)SCB->VTOR; + return vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET]; +} + + /** \brief System Reset \details Initiates a system reset request to reset the MCU. */ -__STATIC_INLINE void NVIC_SystemReset(void) +__NO_RETURN __STATIC_INLINE void __NVIC_SystemReset(void) { __DSB(); /* Ensure all outstanding memory accesses included buffered write are completed before reset */ @@ -1613,6 +1758,31 @@ __STATIC_INLINE void NVIC_SystemReset(void) /*@} end of CMSIS_Core_NVICFunctions */ +/* ########################## FPU functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_FpuFunctions FPU Functions + \brief Function that provides FPU type. + @{ + */ + +/** + \brief get FPU type + \details returns the FPU type + \returns + - \b 0: No FPU + - \b 1: Single precision FPU + - \b 2: Double + Single precision FPU + */ +__STATIC_INLINE uint32_t SCB_GetFPUType(void) +{ + return 0U; /* No FPU */ +} + + +/*@} end of CMSIS_Core_FpuFunctions */ + + /* ################################## SysTick function ############################################ */ /** @@ -1622,7 +1792,7 @@ __STATIC_INLINE void NVIC_SystemReset(void) @{ */ -#if (__Vendor_SysTickConfig == 0U) +#if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U) /** \brief System Tick Configuration @@ -1665,8 +1835,8 @@ __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) @{ */ -extern volatile int32_t ITM_RxBuffer; /*!< External variable to receive characters. */ -#define ITM_RXBUFFER_EMPTY 0x5AA55AA5U /*!< Value identifying \ref ITM_RxBuffer is ready for next character. */ +extern volatile int32_t ITM_RxBuffer; /*!< External variable to receive characters. */ +#define ITM_RXBUFFER_EMPTY ((int32_t)0x5AA55AA5U) /*!< Value identifying \ref ITM_RxBuffer is ready for next character. */ /** diff --git a/lib/cmsis/inc/mpu_armv7.h b/lib/cmsis/inc/mpu_armv7.h new file mode 100644 index 0000000000..66ef59b4a0 --- /dev/null +++ b/lib/cmsis/inc/mpu_armv7.h @@ -0,0 +1,272 @@ +/****************************************************************************** + * @file mpu_armv7.h + * @brief CMSIS MPU API for Armv7-M MPU + * @version V5.1.0 + * @date 08. March 2019 + ******************************************************************************/ +/* + * Copyright (c) 2017-2019 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined (__clang__) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef ARM_MPU_ARMV7_H +#define ARM_MPU_ARMV7_H + +#define ARM_MPU_REGION_SIZE_32B ((uint8_t)0x04U) ///!< MPU Region Size 32 Bytes +#define ARM_MPU_REGION_SIZE_64B ((uint8_t)0x05U) ///!< MPU Region Size 64 Bytes +#define ARM_MPU_REGION_SIZE_128B ((uint8_t)0x06U) ///!< MPU Region Size 128 Bytes +#define ARM_MPU_REGION_SIZE_256B ((uint8_t)0x07U) ///!< MPU Region Size 256 Bytes +#define ARM_MPU_REGION_SIZE_512B ((uint8_t)0x08U) ///!< MPU Region Size 512 Bytes +#define ARM_MPU_REGION_SIZE_1KB ((uint8_t)0x09U) ///!< MPU Region Size 1 KByte +#define ARM_MPU_REGION_SIZE_2KB ((uint8_t)0x0AU) ///!< MPU Region Size 2 KBytes +#define ARM_MPU_REGION_SIZE_4KB ((uint8_t)0x0BU) ///!< MPU Region Size 4 KBytes +#define ARM_MPU_REGION_SIZE_8KB ((uint8_t)0x0CU) ///!< MPU Region Size 8 KBytes +#define ARM_MPU_REGION_SIZE_16KB ((uint8_t)0x0DU) ///!< MPU Region Size 16 KBytes +#define ARM_MPU_REGION_SIZE_32KB ((uint8_t)0x0EU) ///!< MPU Region Size 32 KBytes +#define ARM_MPU_REGION_SIZE_64KB ((uint8_t)0x0FU) ///!< MPU Region Size 64 KBytes +#define ARM_MPU_REGION_SIZE_128KB ((uint8_t)0x10U) ///!< MPU Region Size 128 KBytes +#define ARM_MPU_REGION_SIZE_256KB ((uint8_t)0x11U) ///!< MPU Region Size 256 KBytes +#define ARM_MPU_REGION_SIZE_512KB ((uint8_t)0x12U) ///!< MPU Region Size 512 KBytes +#define ARM_MPU_REGION_SIZE_1MB ((uint8_t)0x13U) ///!< MPU Region Size 1 MByte +#define ARM_MPU_REGION_SIZE_2MB ((uint8_t)0x14U) ///!< MPU Region Size 2 MBytes +#define ARM_MPU_REGION_SIZE_4MB ((uint8_t)0x15U) ///!< MPU Region Size 4 MBytes +#define ARM_MPU_REGION_SIZE_8MB ((uint8_t)0x16U) ///!< MPU Region Size 8 MBytes +#define ARM_MPU_REGION_SIZE_16MB ((uint8_t)0x17U) ///!< MPU Region Size 16 MBytes +#define ARM_MPU_REGION_SIZE_32MB ((uint8_t)0x18U) ///!< MPU Region Size 32 MBytes +#define ARM_MPU_REGION_SIZE_64MB ((uint8_t)0x19U) ///!< MPU Region Size 64 MBytes +#define ARM_MPU_REGION_SIZE_128MB ((uint8_t)0x1AU) ///!< MPU Region Size 128 MBytes +#define ARM_MPU_REGION_SIZE_256MB ((uint8_t)0x1BU) ///!< MPU Region Size 256 MBytes +#define ARM_MPU_REGION_SIZE_512MB ((uint8_t)0x1CU) ///!< MPU Region Size 512 MBytes +#define ARM_MPU_REGION_SIZE_1GB ((uint8_t)0x1DU) ///!< MPU Region Size 1 GByte +#define ARM_MPU_REGION_SIZE_2GB ((uint8_t)0x1EU) ///!< MPU Region Size 2 GBytes +#define ARM_MPU_REGION_SIZE_4GB ((uint8_t)0x1FU) ///!< MPU Region Size 4 GBytes + +#define ARM_MPU_AP_NONE 0U ///!< MPU Access Permission no access +#define ARM_MPU_AP_PRIV 1U ///!< MPU Access Permission privileged access only +#define ARM_MPU_AP_URO 2U ///!< MPU Access Permission unprivileged access read-only +#define ARM_MPU_AP_FULL 3U ///!< MPU Access Permission full access +#define ARM_MPU_AP_PRO 5U ///!< MPU Access Permission privileged access read-only +#define ARM_MPU_AP_RO 6U ///!< MPU Access Permission read-only access + +/** MPU Region Base Address Register Value +* +* \param Region The region to be configured, number 0 to 15. +* \param BaseAddress The base address for the region. +*/ +#define ARM_MPU_RBAR(Region, BaseAddress) \ + (((BaseAddress) & MPU_RBAR_ADDR_Msk) | \ + ((Region) & MPU_RBAR_REGION_Msk) | \ + (MPU_RBAR_VALID_Msk)) + +/** +* MPU Memory Access Attributes +* +* \param TypeExtField Type extension field, allows you to configure memory access type, for example strongly ordered, peripheral. +* \param IsShareable Region is shareable between multiple bus masters. +* \param IsCacheable Region is cacheable, i.e. its value may be kept in cache. +* \param IsBufferable Region is bufferable, i.e. using write-back caching. Cacheable but non-bufferable regions use write-through policy. +*/ +#define ARM_MPU_ACCESS_(TypeExtField, IsShareable, IsCacheable, IsBufferable) \ + ((((TypeExtField) << MPU_RASR_TEX_Pos) & MPU_RASR_TEX_Msk) | \ + (((IsShareable) << MPU_RASR_S_Pos) & MPU_RASR_S_Msk) | \ + (((IsCacheable) << MPU_RASR_C_Pos) & MPU_RASR_C_Msk) | \ + (((IsBufferable) << MPU_RASR_B_Pos) & MPU_RASR_B_Msk)) + +/** +* MPU Region Attribute and Size Register Value +* +* \param DisableExec Instruction access disable bit, 1= disable instruction fetches. +* \param AccessPermission Data access permissions, allows you to configure read/write access for User and Privileged mode. +* \param AccessAttributes Memory access attribution, see \ref ARM_MPU_ACCESS_. +* \param SubRegionDisable Sub-region disable field. +* \param Size Region size of the region to be configured, for example 4K, 8K. +*/ +#define ARM_MPU_RASR_EX(DisableExec, AccessPermission, AccessAttributes, SubRegionDisable, Size) \ + ((((DisableExec) << MPU_RASR_XN_Pos) & MPU_RASR_XN_Msk) | \ + (((AccessPermission) << MPU_RASR_AP_Pos) & MPU_RASR_AP_Msk) | \ + (((AccessAttributes) & (MPU_RASR_TEX_Msk | MPU_RASR_S_Msk | MPU_RASR_C_Msk | MPU_RASR_B_Msk))) | \ + (((SubRegionDisable) << MPU_RASR_SRD_Pos) & MPU_RASR_SRD_Msk) | \ + (((Size) << MPU_RASR_SIZE_Pos) & MPU_RASR_SIZE_Msk) | \ + (((MPU_RASR_ENABLE_Msk)))) + +/** +* MPU Region Attribute and Size Register Value +* +* \param DisableExec Instruction access disable bit, 1= disable instruction fetches. +* \param AccessPermission Data access permissions, allows you to configure read/write access for User and Privileged mode. +* \param TypeExtField Type extension field, allows you to configure memory access type, for example strongly ordered, peripheral. +* \param IsShareable Region is shareable between multiple bus masters. +* \param IsCacheable Region is cacheable, i.e. its value may be kept in cache. +* \param IsBufferable Region is bufferable, i.e. using write-back caching. Cacheable but non-bufferable regions use write-through policy. +* \param SubRegionDisable Sub-region disable field. +* \param Size Region size of the region to be configured, for example 4K, 8K. +*/ +#define ARM_MPU_RASR(DisableExec, AccessPermission, TypeExtField, IsShareable, IsCacheable, IsBufferable, SubRegionDisable, Size) \ + ARM_MPU_RASR_EX(DisableExec, AccessPermission, ARM_MPU_ACCESS_(TypeExtField, IsShareable, IsCacheable, IsBufferable), SubRegionDisable, Size) + +/** +* MPU Memory Access Attribute for strongly ordered memory. +* - TEX: 000b +* - Shareable +* - Non-cacheable +* - Non-bufferable +*/ +#define ARM_MPU_ACCESS_ORDERED ARM_MPU_ACCESS_(0U, 1U, 0U, 0U) + +/** +* MPU Memory Access Attribute for device memory. +* - TEX: 000b (if shareable) or 010b (if non-shareable) +* - Shareable or non-shareable +* - Non-cacheable +* - Bufferable (if shareable) or non-bufferable (if non-shareable) +* +* \param IsShareable Configures the device memory as shareable or non-shareable. +*/ +#define ARM_MPU_ACCESS_DEVICE(IsShareable) ((IsShareable) ? ARM_MPU_ACCESS_(0U, 1U, 0U, 1U) : ARM_MPU_ACCESS_(2U, 0U, 0U, 0U)) + +/** +* MPU Memory Access Attribute for normal memory. +* - TEX: 1BBb (reflecting outer cacheability rules) +* - Shareable or non-shareable +* - Cacheable or non-cacheable (reflecting inner cacheability rules) +* - Bufferable or non-bufferable (reflecting inner cacheability rules) +* +* \param OuterCp Configures the outer cache policy. +* \param InnerCp Configures the inner cache policy. +* \param IsShareable Configures the memory as shareable or non-shareable. +*/ +#define ARM_MPU_ACCESS_NORMAL(OuterCp, InnerCp, IsShareable) ARM_MPU_ACCESS_((4U | (OuterCp)), IsShareable, ((InnerCp) & 2U), ((InnerCp) & 1U)) + +/** +* MPU Memory Access Attribute non-cacheable policy. +*/ +#define ARM_MPU_CACHEP_NOCACHE 0U + +/** +* MPU Memory Access Attribute write-back, write and read allocate policy. +*/ +#define ARM_MPU_CACHEP_WB_WRA 1U + +/** +* MPU Memory Access Attribute write-through, no write allocate policy. +*/ +#define ARM_MPU_CACHEP_WT_NWA 2U + +/** +* MPU Memory Access Attribute write-back, no write allocate policy. +*/ +#define ARM_MPU_CACHEP_WB_NWA 3U + + +/** +* Struct for a single MPU Region +*/ +typedef struct { + uint32_t RBAR; //!< The region base address register value (RBAR) + uint32_t RASR; //!< The region attribute and size register value (RASR) \ref MPU_RASR +} ARM_MPU_Region_t; + +/** Enable the MPU. +* \param MPU_Control Default access permissions for unconfigured regions. +*/ +__STATIC_INLINE void ARM_MPU_Enable(uint32_t MPU_Control) +{ + MPU->CTRL = MPU_Control | MPU_CTRL_ENABLE_Msk; +#ifdef SCB_SHCSR_MEMFAULTENA_Msk + SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk; +#endif + __DSB(); + __ISB(); +} + +/** Disable the MPU. +*/ +__STATIC_INLINE void ARM_MPU_Disable(void) +{ + __DMB(); +#ifdef SCB_SHCSR_MEMFAULTENA_Msk + SCB->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk; +#endif + MPU->CTRL &= ~MPU_CTRL_ENABLE_Msk; +} + +/** Clear and disable the given MPU region. +* \param rnr Region number to be cleared. +*/ +__STATIC_INLINE void ARM_MPU_ClrRegion(uint32_t rnr) +{ + MPU->RNR = rnr; + MPU->RASR = 0U; +} + +/** Configure an MPU region. +* \param rbar Value for RBAR register. +* \param rsar Value for RSAR register. +*/ +__STATIC_INLINE void ARM_MPU_SetRegion(uint32_t rbar, uint32_t rasr) +{ + MPU->RBAR = rbar; + MPU->RASR = rasr; +} + +/** Configure the given MPU region. +* \param rnr Region number to be configured. +* \param rbar Value for RBAR register. +* \param rsar Value for RSAR register. +*/ +__STATIC_INLINE void ARM_MPU_SetRegionEx(uint32_t rnr, uint32_t rbar, uint32_t rasr) +{ + MPU->RNR = rnr; + MPU->RBAR = rbar; + MPU->RASR = rasr; +} + +/** Memcopy with strictly ordered memory access, e.g. for register targets. +* \param dst Destination data is copied to. +* \param src Source data is copied from. +* \param len Amount of data words to be copied. +*/ +__STATIC_INLINE void ARM_MPU_OrderedMemcpy(volatile uint32_t* dst, const uint32_t* __RESTRICT src, uint32_t len) +{ + uint32_t i; + for (i = 0U; i < len; ++i) + { + dst[i] = src[i]; + } +} + +/** Load the given number of MPU regions from a table. +* \param table Pointer to the MPU configuration table. +* \param cnt Amount of regions to be configured. +*/ +__STATIC_INLINE void ARM_MPU_Load(ARM_MPU_Region_t const* table, uint32_t cnt) +{ + const uint32_t rowWordSize = sizeof(ARM_MPU_Region_t)/4U; + while (cnt > MPU_TYPE_RALIASES) { + ARM_MPU_OrderedMemcpy(&(MPU->RBAR), &(table->RBAR), MPU_TYPE_RALIASES*rowWordSize); + table += MPU_TYPE_RALIASES; + cnt -= MPU_TYPE_RALIASES; + } + ARM_MPU_OrderedMemcpy(&(MPU->RBAR), &(table->RBAR), cnt*rowWordSize); +} + +#endif diff --git a/lib/cmsis/inc/mpu_armv8.h b/lib/cmsis/inc/mpu_armv8.h new file mode 100644 index 0000000000..0041d4dc6f --- /dev/null +++ b/lib/cmsis/inc/mpu_armv8.h @@ -0,0 +1,346 @@ +/****************************************************************************** + * @file mpu_armv8.h + * @brief CMSIS MPU API for Armv8-M and Armv8.1-M MPU + * @version V5.1.0 + * @date 08. March 2019 + ******************************************************************************/ +/* + * Copyright (c) 2017-2019 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined (__clang__) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef ARM_MPU_ARMV8_H +#define ARM_MPU_ARMV8_H + +/** \brief Attribute for device memory (outer only) */ +#define ARM_MPU_ATTR_DEVICE ( 0U ) + +/** \brief Attribute for non-cacheable, normal memory */ +#define ARM_MPU_ATTR_NON_CACHEABLE ( 4U ) + +/** \brief Attribute for normal memory (outer and inner) +* \param NT Non-Transient: Set to 1 for non-transient data. +* \param WB Write-Back: Set to 1 to use write-back update policy. +* \param RA Read Allocation: Set to 1 to use cache allocation on read miss. +* \param WA Write Allocation: Set to 1 to use cache allocation on write miss. +*/ +#define ARM_MPU_ATTR_MEMORY_(NT, WB, RA, WA) \ + (((NT & 1U) << 3U) | ((WB & 1U) << 2U) | ((RA & 1U) << 1U) | (WA & 1U)) + +/** \brief Device memory type non Gathering, non Re-ordering, non Early Write Acknowledgement */ +#define ARM_MPU_ATTR_DEVICE_nGnRnE (0U) + +/** \brief Device memory type non Gathering, non Re-ordering, Early Write Acknowledgement */ +#define ARM_MPU_ATTR_DEVICE_nGnRE (1U) + +/** \brief Device memory type non Gathering, Re-ordering, Early Write Acknowledgement */ +#define ARM_MPU_ATTR_DEVICE_nGRE (2U) + +/** \brief Device memory type Gathering, Re-ordering, Early Write Acknowledgement */ +#define ARM_MPU_ATTR_DEVICE_GRE (3U) + +/** \brief Memory Attribute +* \param O Outer memory attributes +* \param I O == ARM_MPU_ATTR_DEVICE: Device memory attributes, else: Inner memory attributes +*/ +#define ARM_MPU_ATTR(O, I) (((O & 0xFU) << 4U) | (((O & 0xFU) != 0U) ? (I & 0xFU) : ((I & 0x3U) << 2U))) + +/** \brief Normal memory non-shareable */ +#define ARM_MPU_SH_NON (0U) + +/** \brief Normal memory outer shareable */ +#define ARM_MPU_SH_OUTER (2U) + +/** \brief Normal memory inner shareable */ +#define ARM_MPU_SH_INNER (3U) + +/** \brief Memory access permissions +* \param RO Read-Only: Set to 1 for read-only memory. +* \param NP Non-Privileged: Set to 1 for non-privileged memory. +*/ +#define ARM_MPU_AP_(RO, NP) (((RO & 1U) << 1U) | (NP & 1U)) + +/** \brief Region Base Address Register value +* \param BASE The base address bits [31:5] of a memory region. The value is zero extended. Effective address gets 32 byte aligned. +* \param SH Defines the Shareability domain for this memory region. +* \param RO Read-Only: Set to 1 for a read-only memory region. +* \param NP Non-Privileged: Set to 1 for a non-privileged memory region. +* \oaram XN eXecute Never: Set to 1 for a non-executable memory region. +*/ +#define ARM_MPU_RBAR(BASE, SH, RO, NP, XN) \ + ((BASE & MPU_RBAR_BASE_Msk) | \ + ((SH << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) | \ + ((ARM_MPU_AP_(RO, NP) << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk) | \ + ((XN << MPU_RBAR_XN_Pos) & MPU_RBAR_XN_Msk)) + +/** \brief Region Limit Address Register value +* \param LIMIT The limit address bits [31:5] for this memory region. The value is one extended. +* \param IDX The attribute index to be associated with this memory region. +*/ +#define ARM_MPU_RLAR(LIMIT, IDX) \ + ((LIMIT & MPU_RLAR_LIMIT_Msk) | \ + ((IDX << MPU_RLAR_AttrIndx_Pos) & MPU_RLAR_AttrIndx_Msk) | \ + (MPU_RLAR_EN_Msk)) + +#if defined(MPU_RLAR_PXN_Pos) + +/** \brief Region Limit Address Register with PXN value +* \param LIMIT The limit address bits [31:5] for this memory region. The value is one extended. +* \param PXN Privileged execute never. Defines whether code can be executed from this privileged region. +* \param IDX The attribute index to be associated with this memory region. +*/ +#define ARM_MPU_RLAR_PXN(LIMIT, PXN, IDX) \ + ((LIMIT & MPU_RLAR_LIMIT_Msk) | \ + ((PXN << MPU_RLAR_PXN_Pos) & MPU_RLAR_PXN_Msk) | \ + ((IDX << MPU_RLAR_AttrIndx_Pos) & MPU_RLAR_AttrIndx_Msk) | \ + (MPU_RLAR_EN_Msk)) + +#endif + +/** +* Struct for a single MPU Region +*/ +typedef struct { + uint32_t RBAR; /*!< Region Base Address Register value */ + uint32_t RLAR; /*!< Region Limit Address Register value */ +} ARM_MPU_Region_t; + +/** Enable the MPU. +* \param MPU_Control Default access permissions for unconfigured regions. +*/ +__STATIC_INLINE void ARM_MPU_Enable(uint32_t MPU_Control) +{ + MPU->CTRL = MPU_Control | MPU_CTRL_ENABLE_Msk; +#ifdef SCB_SHCSR_MEMFAULTENA_Msk + SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk; +#endif + __DSB(); + __ISB(); +} + +/** Disable the MPU. +*/ +__STATIC_INLINE void ARM_MPU_Disable(void) +{ + __DMB(); +#ifdef SCB_SHCSR_MEMFAULTENA_Msk + SCB->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk; +#endif + MPU->CTRL &= ~MPU_CTRL_ENABLE_Msk; +} + +#ifdef MPU_NS +/** Enable the Non-secure MPU. +* \param MPU_Control Default access permissions for unconfigured regions. +*/ +__STATIC_INLINE void ARM_MPU_Enable_NS(uint32_t MPU_Control) +{ + MPU_NS->CTRL = MPU_Control | MPU_CTRL_ENABLE_Msk; +#ifdef SCB_SHCSR_MEMFAULTENA_Msk + SCB_NS->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk; +#endif + __DSB(); + __ISB(); +} + +/** Disable the Non-secure MPU. +*/ +__STATIC_INLINE void ARM_MPU_Disable_NS(void) +{ + __DMB(); +#ifdef SCB_SHCSR_MEMFAULTENA_Msk + SCB_NS->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk; +#endif + MPU_NS->CTRL &= ~MPU_CTRL_ENABLE_Msk; +} +#endif + +/** Set the memory attribute encoding to the given MPU. +* \param mpu Pointer to the MPU to be configured. +* \param idx The attribute index to be set [0-7] +* \param attr The attribute value to be set. +*/ +__STATIC_INLINE void ARM_MPU_SetMemAttrEx(MPU_Type* mpu, uint8_t idx, uint8_t attr) +{ + const uint8_t reg = idx / 4U; + const uint32_t pos = ((idx % 4U) * 8U); + const uint32_t mask = 0xFFU << pos; + + if (reg >= (sizeof(mpu->MAIR) / sizeof(mpu->MAIR[0]))) { + return; // invalid index + } + + mpu->MAIR[reg] = ((mpu->MAIR[reg] & ~mask) | ((attr << pos) & mask)); +} + +/** Set the memory attribute encoding. +* \param idx The attribute index to be set [0-7] +* \param attr The attribute value to be set. +*/ +__STATIC_INLINE void ARM_MPU_SetMemAttr(uint8_t idx, uint8_t attr) +{ + ARM_MPU_SetMemAttrEx(MPU, idx, attr); +} + +#ifdef MPU_NS +/** Set the memory attribute encoding to the Non-secure MPU. +* \param idx The attribute index to be set [0-7] +* \param attr The attribute value to be set. +*/ +__STATIC_INLINE void ARM_MPU_SetMemAttr_NS(uint8_t idx, uint8_t attr) +{ + ARM_MPU_SetMemAttrEx(MPU_NS, idx, attr); +} +#endif + +/** Clear and disable the given MPU region of the given MPU. +* \param mpu Pointer to MPU to be used. +* \param rnr Region number to be cleared. +*/ +__STATIC_INLINE void ARM_MPU_ClrRegionEx(MPU_Type* mpu, uint32_t rnr) +{ + mpu->RNR = rnr; + mpu->RLAR = 0U; +} + +/** Clear and disable the given MPU region. +* \param rnr Region number to be cleared. +*/ +__STATIC_INLINE void ARM_MPU_ClrRegion(uint32_t rnr) +{ + ARM_MPU_ClrRegionEx(MPU, rnr); +} + +#ifdef MPU_NS +/** Clear and disable the given Non-secure MPU region. +* \param rnr Region number to be cleared. +*/ +__STATIC_INLINE void ARM_MPU_ClrRegion_NS(uint32_t rnr) +{ + ARM_MPU_ClrRegionEx(MPU_NS, rnr); +} +#endif + +/** Configure the given MPU region of the given MPU. +* \param mpu Pointer to MPU to be used. +* \param rnr Region number to be configured. +* \param rbar Value for RBAR register. +* \param rlar Value for RLAR register. +*/ +__STATIC_INLINE void ARM_MPU_SetRegionEx(MPU_Type* mpu, uint32_t rnr, uint32_t rbar, uint32_t rlar) +{ + mpu->RNR = rnr; + mpu->RBAR = rbar; + mpu->RLAR = rlar; +} + +/** Configure the given MPU region. +* \param rnr Region number to be configured. +* \param rbar Value for RBAR register. +* \param rlar Value for RLAR register. +*/ +__STATIC_INLINE void ARM_MPU_SetRegion(uint32_t rnr, uint32_t rbar, uint32_t rlar) +{ + ARM_MPU_SetRegionEx(MPU, rnr, rbar, rlar); +} + +#ifdef MPU_NS +/** Configure the given Non-secure MPU region. +* \param rnr Region number to be configured. +* \param rbar Value for RBAR register. +* \param rlar Value for RLAR register. +*/ +__STATIC_INLINE void ARM_MPU_SetRegion_NS(uint32_t rnr, uint32_t rbar, uint32_t rlar) +{ + ARM_MPU_SetRegionEx(MPU_NS, rnr, rbar, rlar); +} +#endif + +/** Memcopy with strictly ordered memory access, e.g. for register targets. +* \param dst Destination data is copied to. +* \param src Source data is copied from. +* \param len Amount of data words to be copied. +*/ +__STATIC_INLINE void ARM_MPU_OrderedMemcpy(volatile uint32_t* dst, const uint32_t* __RESTRICT src, uint32_t len) +{ + uint32_t i; + for (i = 0U; i < len; ++i) + { + dst[i] = src[i]; + } +} + +/** Load the given number of MPU regions from a table to the given MPU. +* \param mpu Pointer to the MPU registers to be used. +* \param rnr First region number to be configured. +* \param table Pointer to the MPU configuration table. +* \param cnt Amount of regions to be configured. +*/ +__STATIC_INLINE void ARM_MPU_LoadEx(MPU_Type* mpu, uint32_t rnr, ARM_MPU_Region_t const* table, uint32_t cnt) +{ + const uint32_t rowWordSize = sizeof(ARM_MPU_Region_t)/4U; + if (cnt == 1U) { + mpu->RNR = rnr; + ARM_MPU_OrderedMemcpy(&(mpu->RBAR), &(table->RBAR), rowWordSize); + } else { + uint32_t rnrBase = rnr & ~(MPU_TYPE_RALIASES-1U); + uint32_t rnrOffset = rnr % MPU_TYPE_RALIASES; + + mpu->RNR = rnrBase; + while ((rnrOffset + cnt) > MPU_TYPE_RALIASES) { + uint32_t c = MPU_TYPE_RALIASES - rnrOffset; + ARM_MPU_OrderedMemcpy(&(mpu->RBAR)+(rnrOffset*2U), &(table->RBAR), c*rowWordSize); + table += c; + cnt -= c; + rnrOffset = 0U; + rnrBase += MPU_TYPE_RALIASES; + mpu->RNR = rnrBase; + } + + ARM_MPU_OrderedMemcpy(&(mpu->RBAR)+(rnrOffset*2U), &(table->RBAR), cnt*rowWordSize); + } +} + +/** Load the given number of MPU regions from a table. +* \param rnr First region number to be configured. +* \param table Pointer to the MPU configuration table. +* \param cnt Amount of regions to be configured. +*/ +__STATIC_INLINE void ARM_MPU_Load(uint32_t rnr, ARM_MPU_Region_t const* table, uint32_t cnt) +{ + ARM_MPU_LoadEx(MPU, rnr, table, cnt); +} + +#ifdef MPU_NS +/** Load the given number of MPU regions from a table to the Non-secure MPU. +* \param rnr First region number to be configured. +* \param table Pointer to the MPU configuration table. +* \param cnt Amount of regions to be configured. +*/ +__STATIC_INLINE void ARM_MPU_Load_NS(uint32_t rnr, ARM_MPU_Region_t const* table, uint32_t cnt) +{ + ARM_MPU_LoadEx(MPU_NS, rnr, table, cnt); +} +#endif + +#endif + diff --git a/lib/cmsis/inc/tz_context.h b/lib/cmsis/inc/tz_context.h new file mode 100644 index 0000000000..0d09749f3a --- /dev/null +++ b/lib/cmsis/inc/tz_context.h @@ -0,0 +1,70 @@ +/****************************************************************************** + * @file tz_context.h + * @brief Context Management for Armv8-M TrustZone + * @version V1.0.1 + * @date 10. January 2018 + ******************************************************************************/ +/* + * Copyright (c) 2017-2018 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined (__clang__) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef TZ_CONTEXT_H +#define TZ_CONTEXT_H + +#include + +#ifndef TZ_MODULEID_T +#define TZ_MODULEID_T +/// \details Data type that identifies secure software modules called by a process. +typedef uint32_t TZ_ModuleId_t; +#endif + +/// \details TZ Memory ID identifies an allocated memory slot. +typedef uint32_t TZ_MemoryId_t; + +/// Initialize secure context memory system +/// \return execution status (1: success, 0: error) +uint32_t TZ_InitContextSystem_S (void); + +/// Allocate context memory for calling secure software modules in TrustZone +/// \param[in] module identifies software modules called from non-secure mode +/// \return value != 0 id TrustZone memory slot identifier +/// \return value 0 no memory available or internal error +TZ_MemoryId_t TZ_AllocModuleContext_S (TZ_ModuleId_t module); + +/// Free context memory that was previously allocated with \ref TZ_AllocModuleContext_S +/// \param[in] id TrustZone memory slot identifier +/// \return execution status (1: success, 0: error) +uint32_t TZ_FreeModuleContext_S (TZ_MemoryId_t id); + +/// Load secure context (called on RTOS thread context switch) +/// \param[in] id TrustZone memory slot identifier +/// \return execution status (1: success, 0: error) +uint32_t TZ_LoadContext_S (TZ_MemoryId_t id); + +/// Store secure context (called on RTOS thread context switch) +/// \param[in] id TrustZone memory slot identifier +/// \return execution status (1: success, 0: error) +uint32_t TZ_StoreContext_S (TZ_MemoryId_t id); + +#endif // TZ_CONTEXT_H From 41739506589ec8397613c86d8f682fb7f86c0a9f Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 31 May 2019 14:37:11 +1000 Subject: [PATCH 0411/1788] mpy-cross: Do not automatically build mpy-cross, rather do it manually. Building mpy-cross automatically leads to some issues with the build process and slows it down. Instead, require it to be built manually. --- README.md | 11 +++++++++++ mpy-cross/Makefile | 17 ----------------- py/mkrules.mk | 6 +----- 3 files changed, 12 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 843511a60b..aaf310b662 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,17 @@ You will also need bash, gcc, and Python 3.3+ available as the command `python3` (if your system only has Python 2.7 then invoke make with the additional option `PYTHON=python2`). +The MicroPython cross-compiler, mpy-cross +----------------------------------------- + +Most ports require the MicroPython cross-compiler to be built first. This +program, called mpy-cross, is used to pre-compile Python scripts to .mpy +files which can then be included (frozen) into the firmware/executable for +a port. To build mpy-cross use: + + $ cd mpy-cross + $ make + The Unix version ---------------- diff --git a/mpy-cross/Makefile b/mpy-cross/Makefile index 4ff96fc80c..2116cc6708 100644 --- a/mpy-cross/Makefile +++ b/mpy-cross/Makefile @@ -1,20 +1,3 @@ -# The following is a temporary hack to forefully undefine vars that might have -# be defined by a calling Makefile (from recursive make). -# TODO: Find a better way to be able to call this Makefile recursively. -ifneq ($(findstring undefine,$(.FEATURES)),) -override undefine COPT -override undefine CFLAGS_EXTRA -override undefine LDFLAGS_EXTRA -override undefine MICROPY_FORCE_32BIT -override undefine CROSS_COMPILE -override undefine FROZEN_DIR -override undefine FROZEN_MPY_DIR -override undefine USER_C_MODULES -override undefine SRC_MOD -override undefine BUILD -override undefine PROG -endif - include ../py/mkenv.mk # define main target diff --git a/py/mkrules.mk b/py/mkrules.mk index 4e4fdef55c..5c214090cc 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -103,16 +103,12 @@ $(BUILD)/frozen.c: $(wildcard $(FROZEN_DIR)/*) $(HEADER_BUILD) $(FROZEN_EXTRA_DE endif ifneq ($(FROZEN_MPY_DIR),) -# to build the MicroPython cross compiler -$(TOP)/mpy-cross/mpy-cross: $(TOP)/py/*.[ch] $(TOP)/mpy-cross/*.[ch] $(TOP)/ports/windows/fmode.c - $(Q)$(MAKE) -C $(TOP)/mpy-cross - # make a list of all the .py files that need compiling and freezing FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py' | $(SED) -e 's=^$(FROZEN_MPY_DIR)/==') FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/frozen_mpy/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) # to build .mpy files from .py files -$(BUILD)/frozen_mpy/%.mpy: $(FROZEN_MPY_DIR)/%.py $(TOP)/mpy-cross/mpy-cross +$(BUILD)/frozen_mpy/%.mpy: $(FROZEN_MPY_DIR)/%.py @$(ECHO) "MPY $<" $(Q)$(MKDIR) -p $(dir $@) $(Q)$(MPY_CROSS) -o $@ -s $(<:$(FROZEN_MPY_DIR)/%=%) $(MPY_CROSS_FLAGS) $< From 1043f1a0471757fb46350494aff32114b5e2574b Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 1 Jun 2019 15:58:23 +1000 Subject: [PATCH 0412/1788] lib/netutils: Add DHCP server component. --- lib/netutils/dhcpserver.c | 304 ++++++++++++++++++++++++++++++++++++++ lib/netutils/dhcpserver.h | 49 ++++++ 2 files changed, 353 insertions(+) create mode 100644 lib/netutils/dhcpserver.c create mode 100644 lib/netutils/dhcpserver.h diff --git a/lib/netutils/dhcpserver.c b/lib/netutils/dhcpserver.c new file mode 100644 index 0000000000..476eb3d69b --- /dev/null +++ b/lib/netutils/dhcpserver.c @@ -0,0 +1,304 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2019 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. + */ + +// For DHCP specs see: +// https://www.ietf.org/rfc/rfc2131.txt +// https://tools.ietf.org/html/rfc2132 -- DHCP Options and BOOTP Vendor Extensions + +#include +#include +#include "py/mperrno.h" +#include "py/mphal.h" + +#if MICROPY_PY_LWIP + +#include "lib/netutils/dhcpserver.h" +#include "lwip/udp.h" + +#define DHCPDISCOVER (1) +#define DHCPOFFER (2) +#define DHCPREQUEST (3) +#define DHCPDECLINE (4) +#define DHCPACK (5) +#define DHCPNACK (6) +#define DHCPRELEASE (7) +#define DHCPINFORM (8) + +#define DHCP_OPT_PAD (0) +#define DHCP_OPT_SUBNET_MASK (1) +#define DHCP_OPT_ROUTER (3) +#define DHCP_OPT_DNS (6) +#define DHCP_OPT_HOST_NAME (12) +#define DHCP_OPT_REQUESTED_IP (50) +#define DHCP_OPT_IP_LEASE_TIME (51) +#define DHCP_OPT_MSG_TYPE (53) +#define DHCP_OPT_SERVER_ID (54) +#define DHCP_OPT_PARAM_REQUEST_LIST (55) +#define DHCP_OPT_MAX_MSG_SIZE (57) +#define DHCP_OPT_VENDOR_CLASS_ID (60) +#define DHCP_OPT_CLIENT_ID (61) +#define DHCP_OPT_END (255) + +#define PORT_DHCP_SERVER (67) +#define PORT_DHCP_CLIENT (68) + +#define DEFAULT_DNS MAKE_IP4(8, 8, 8, 8) +#define DEFAULT_LEASE_TIME_S (24 * 60 * 60) // in seconds + +#define MAC_LEN (6) +#define MAKE_IP4(a, b, c, d) ((a) << 24 | (b) << 16 | (c) << 8 | (d)) + +typedef struct { + uint8_t op; // message opcode + uint8_t htype; // hardware address type + uint8_t hlen; // hardware address length + uint8_t hops; + uint32_t xid; // transaction id, chosen by client + uint16_t secs; // client seconds elapsed + uint16_t flags; + uint8_t ciaddr[4]; // client IP address + uint8_t yiaddr[4]; // your IP address + uint8_t siaddr[4]; // next server IP address + uint8_t giaddr[4]; // relay agent IP address + uint8_t chaddr[16]; // client hardware address + uint8_t sname[64]; // server host name + uint8_t file[128]; // boot file name + uint8_t options[312]; // optional parameters, variable, starts with magic +} dhcp_msg_t; + +static int dhcp_socket_new_dgram(struct udp_pcb **udp, void *cb_data, udp_recv_fn cb_udp_recv) { + // family is AF_INET + // type is SOCK_DGRAM + + *udp = udp_new(); + if (*udp == NULL) { + return -MP_ENOMEM; + } + + // Register callback + udp_recv(*udp, cb_udp_recv, (void*)cb_data); + + return 0; // success +} + +static void dhcp_socket_free(struct udp_pcb **udp) { + if (*udp != NULL) { + udp_remove(*udp); + *udp = NULL; + } +} + +static int dhcp_socket_bind(struct udp_pcb **udp, uint32_t ip, uint16_t port) { + ip_addr_t addr; + IP4_ADDR(&addr, ip >> 24 & 0xff, ip >> 16 & 0xff, ip >> 8 & 0xff, ip & 0xff); + // TODO convert lwIP errors to errno + return udp_bind(*udp, &addr, port); +} + +static int dhcp_socket_sendto(struct udp_pcb **udp, const void *buf, size_t len, uint32_t ip, uint16_t port) { + if (len > 0xffff) { + len = 0xffff; + } + + struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); + if (p == NULL) { + return -MP_ENOMEM; + } + + memcpy(p->payload, buf, len); + + ip_addr_t dest; + IP4_ADDR(&dest, ip >> 24 & 0xff, ip >> 16 & 0xff, ip >> 8 & 0xff, ip & 0xff); + err_t err = udp_sendto(*udp, p, &dest, port); + + pbuf_free(p); + + if (err != ERR_OK) { + return err; + } + + return len; +} + +static uint8_t *opt_find(uint8_t *opt, uint8_t cmd) { + for (int i = 0; i < 308 && opt[i] != DHCP_OPT_END;) { + if (opt[i] == cmd) { + return &opt[i]; + } + i += 2 + opt[i + 1]; + } + return NULL; +} + +static void opt_write_n(uint8_t **opt, uint8_t cmd, size_t n, void *data) { + uint8_t *o = *opt; + *o++ = cmd; + *o++ = n; + memcpy(o, data, n); + *opt = o + n; +} + +static void opt_write_u8(uint8_t **opt, uint8_t cmd, uint8_t val) { + uint8_t *o = *opt; + *o++ = cmd; + *o++ = 1; + *o++ = val; + *opt = o; +} + +static void opt_write_u32(uint8_t **opt, uint8_t cmd, uint32_t val) { + uint8_t *o = *opt; + *o++ = cmd; + *o++ = 4; + *o++ = val >> 24; + *o++ = val >> 16; + *o++ = val >> 8; + *o++ = val; + *opt = o; +} + +static void dhcp_server_process(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *src_addr, u16_t src_port) { + dhcp_server_t *d = arg; + (void)upcb; + (void)src_addr; + (void)src_port; + + // This is around 548 bytes + dhcp_msg_t dhcp_msg; + + #define DHCP_MIN_SIZE (240 + 3) + if (p->tot_len < DHCP_MIN_SIZE) { + goto ignore_request; + } + + size_t len = pbuf_copy_partial(p, &dhcp_msg, sizeof(dhcp_msg), 0); + if (len < DHCP_MIN_SIZE) { + goto ignore_request; + } + + dhcp_msg.op = DHCPOFFER; + memcpy(&dhcp_msg.yiaddr, &d->ip.addr, 4); + + uint8_t *opt = (uint8_t*)&dhcp_msg.options; + opt += 4; // assume magic cookie: 99, 130, 83, 99 + + switch (opt[2]) { + case DHCPDISCOVER: { + int yi = DHCPS_MAX_IP; + for (int i = 0; i < DHCPS_MAX_IP; ++i) { + if (memcmp(d->lease[i].mac, dhcp_msg.chaddr, MAC_LEN) == 0) { + // MAC match, use this IP address + yi = i; + break; + } + if (yi == DHCPS_MAX_IP) { + // Look for a free IP address + if (memcmp(d->lease[i].mac, "\x00\x00\x00\x00\x00\x00", MAC_LEN) == 0) { + // IP available + yi = i; + } + uint32_t expiry = d->lease[i].expiry << 16 | 0xffff; + if ((int32_t)(expiry - mp_hal_ticks_ms()) < 0) { + // IP expired, reuse it + memset(d->lease[i].mac, 0, MAC_LEN); + yi = i; + } + } + } + if (yi == DHCPS_MAX_IP) { + // No more IP addresses left + goto ignore_request; + } + dhcp_msg.yiaddr[3] = DHCPS_BASE_IP + yi; + opt_write_u8(&opt, DHCP_OPT_MSG_TYPE, DHCPOFFER); + break; + } + + case DHCPREQUEST: { + uint8_t *o = opt_find(opt, DHCP_OPT_REQUESTED_IP); + if (o == NULL) { + // Should be NACK + goto ignore_request; + } + if (memcmp(o + 2, &d->ip.addr, 3) != 0) { + // Should be NACK + goto ignore_request; + } + uint8_t yi = o[5] - DHCPS_BASE_IP; + if (yi >= DHCPS_MAX_IP) { + // Should be NACK + goto ignore_request; + } + if (memcmp(d->lease[yi].mac, dhcp_msg.chaddr, MAC_LEN) == 0) { + // MAC match, ok to use this IP address + } else if (memcmp(d->lease[yi].mac, "\x00\x00\x00\x00\x00\x00", MAC_LEN) == 0) { + // IP unused, ok to use this IP address + memcpy(d->lease[yi].mac, dhcp_msg.chaddr, MAC_LEN); + } else { + // IP already in use + // Should be NACK + goto ignore_request; + } + d->lease[yi].expiry = (mp_hal_ticks_ms() + DEFAULT_LEASE_TIME_S * 1000) >> 16; + dhcp_msg.yiaddr[3] = DHCPS_BASE_IP + yi; + opt_write_u8(&opt, DHCP_OPT_MSG_TYPE, DHCPACK); + printf("DHCPS: client connected: MAC=%02x:%02x:%02x:%02x:%02x:%02x IP=%u.%u.%u.%u\n", + dhcp_msg.chaddr[0], dhcp_msg.chaddr[1], dhcp_msg.chaddr[2], dhcp_msg.chaddr[3], dhcp_msg.chaddr[4], dhcp_msg.chaddr[5], + dhcp_msg.yiaddr[0], dhcp_msg.yiaddr[1], dhcp_msg.yiaddr[2], dhcp_msg.yiaddr[3]); + break; + } + + default: + goto ignore_request; + } + + opt_write_n(&opt, DHCP_OPT_SERVER_ID, 4, &d->ip.addr); + opt_write_n(&opt, DHCP_OPT_SUBNET_MASK, 4, &d->nm.addr); + opt_write_n(&opt, DHCP_OPT_ROUTER, 4, &d->ip.addr); // aka gateway; can have mulitple addresses + opt_write_u32(&opt, DHCP_OPT_DNS, DEFAULT_DNS); // can have mulitple addresses + opt_write_u32(&opt, DHCP_OPT_IP_LEASE_TIME, DEFAULT_LEASE_TIME_S); + *opt++ = DHCP_OPT_END; + dhcp_socket_sendto(&d->udp, &dhcp_msg, opt - (uint8_t*)&dhcp_msg, 0xffffffff, PORT_DHCP_CLIENT); + +ignore_request: + pbuf_free(p); +} + +void dhcp_server_init(dhcp_server_t *d, ip_addr_t *ip, ip_addr_t *nm) { + ip_addr_copy(d->ip, *ip); + ip_addr_copy(d->nm, *nm); + memset(d->lease, 0, sizeof(d->lease)); + if (dhcp_socket_new_dgram(&d->udp, d, dhcp_server_process) != 0) { + return; + } + dhcp_socket_bind(&d->udp, 0, PORT_DHCP_SERVER); +} + +void dhcp_server_deinit(dhcp_server_t *d) { + dhcp_socket_free(&d->udp); +} + +#endif // MICROPY_PY_LWIP diff --git a/lib/netutils/dhcpserver.h b/lib/netutils/dhcpserver.h new file mode 100644 index 0000000000..2349d2ea42 --- /dev/null +++ b/lib/netutils/dhcpserver.h @@ -0,0 +1,49 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2019 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_LIB_NETUTILS_DHCPSERVER_H +#define MICROPY_INCLUDED_LIB_NETUTILS_DHCPSERVER_H + +#include "lwip/ip_addr.h" + +#define DHCPS_BASE_IP (16) +#define DHCPS_MAX_IP (8) + +typedef struct _dhcp_server_lease_t { + uint8_t mac[6]; + uint16_t expiry; +} dhcp_server_lease_t; + +typedef struct _dhcp_server_t { + ip_addr_t ip; + ip_addr_t nm; + dhcp_server_lease_t lease[DHCPS_MAX_IP]; + struct udp_pcb *udp; +} dhcp_server_t; + +void dhcp_server_init(dhcp_server_t *d, ip_addr_t *ip, ip_addr_t *nm); +void dhcp_server_deinit(dhcp_server_t *d); + +#endif // MICROPY_INCLUDED_LIB_NETUTILS_DHCPSERVER_H From 53f2ac9017e616975194b509dd1b29c4a30cfb1d Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 1 Jun 2019 15:59:48 +1000 Subject: [PATCH 0413/1788] gitattributes: Mark *.a files as binary. --- .gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitattributes b/.gitattributes index fdd31021f7..e6d31d6aa3 100644 --- a/.gitattributes +++ b/.gitattributes @@ -7,6 +7,7 @@ *.bat text eol=crlf # These are binary so should never be modified by git. +*.a binary *.png binary *.jpg binary *.dxf binary From 7b70ab7258986567dd970d5108cd45c706b36a96 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 1 Jun 2019 16:00:56 +1000 Subject: [PATCH 0414/1788] drivers: Add driver for CYW43xx WiFi SoCs. --- drivers/cyw43/README.md | 17 ++ drivers/cyw43/cyw43.h | 135 +++++++++ drivers/cyw43/cyw43_ctrl.c | 588 +++++++++++++++++++++++++++++++++++++ drivers/cyw43/cyw43_ll.h | 135 +++++++++ drivers/cyw43/cyw43_lwip.c | 197 +++++++++++++ drivers/cyw43/libcyw43.a | Bin 0 -> 437538 bytes 6 files changed, 1072 insertions(+) create mode 100644 drivers/cyw43/README.md create mode 100644 drivers/cyw43/cyw43.h create mode 100644 drivers/cyw43/cyw43_ctrl.c create mode 100644 drivers/cyw43/cyw43_ll.h create mode 100644 drivers/cyw43/cyw43_lwip.c create mode 100644 drivers/cyw43/libcyw43.a diff --git a/drivers/cyw43/README.md b/drivers/cyw43/README.md new file mode 100644 index 0000000000..5af6f65580 --- /dev/null +++ b/drivers/cyw43/README.md @@ -0,0 +1,17 @@ +CYW43xx WiFi SoC driver +======================= + +This is a driver for the CYW43xx WiFi SoC. + +There are four layers to the driver: + +1. SDIO bus interface, provided by the host device/system. + +2. Low-level CYW43xx interface, managing the bus, control messages, Ethernet + frames and asynchronous events. Includes download of SoC firmware. The + header file `cyw43_ll.h` defines the interface to this layer. + +3. Mid-level CYW43xx control, to control and set WiFi parameters and manage + events. See `cyw43_ctrl.c`. + +4. TCP/IP bindings to lwIP. See `cyw43_lwip.c`. diff --git a/drivers/cyw43/cyw43.h b/drivers/cyw43/cyw43.h new file mode 100644 index 0000000000..d7f08cb5df --- /dev/null +++ b/drivers/cyw43/cyw43.h @@ -0,0 +1,135 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2019 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_CYW43_H +#define MICROPY_INCLUDED_STM32_CYW43_H + +#include "lwip/netif.h" +#include "lwip/dhcp.h" +#include "lib/netutils/dhcpserver.h" +#include "drivers/cyw43/cyw43_ll.h" + +// For trace_flags +#define CYW43_TRACE_ASYNC_EV (0x0001) +#define CYW43_TRACE_ETH_TX (0x0002) +#define CYW43_TRACE_ETH_RX (0x0004) +#define CYW43_TRACE_ETH_FULL (0x0008) +#define CYW43_TRACE_MAC (0x0010) + +// Return value of cyw43_wifi_link_status +#define CYW43_LINK_DOWN (0) +#define CYW43_LINK_JOIN (1) +#define CYW43_LINK_NOIP (2) +#define CYW43_LINK_UP (3) +#define CYW43_LINK_FAIL (-1) +#define CYW43_LINK_NONET (-2) +#define CYW43_LINK_BADAUTH (-3) + +typedef struct _cyw43_t { + cyw43_ll_t cyw43_ll; + + uint8_t itf_state; + uint32_t trace_flags; + + // State for async events + volatile uint32_t wifi_scan_state; + uint32_t wifi_join_state; + void *wifi_scan_env; + int (*wifi_scan_cb)(void*, const cyw43_ev_scan_result_t*); + + // Pending things to do + bool pend_disassoc; + bool pend_rejoin; + bool pend_rejoin_wpa; + + // AP settings + uint8_t ap_channel; + uint8_t ap_auth; + uint8_t ap_ssid_len; + uint8_t ap_key_len; + uint8_t ap_ssid[32]; + uint8_t ap_key[64]; + + // lwIP data + struct netif netif[2]; + struct dhcp dhcp_client; + dhcp_server_t dhcp_server; +} cyw43_t; + +extern cyw43_t cyw43_state; +extern void (*cyw43_poll)(void); +extern uint32_t cyw43_sleep; + +void cyw43_init(cyw43_t *self); +void cyw43_deinit(cyw43_t *self); + +int cyw43_ioctl(cyw43_t *self, uint32_t cmd, size_t len, uint8_t *buf, uint32_t iface); +int cyw43_send_ethernet(cyw43_t *self, int itf, size_t len, const void *buf, bool is_pbuf); + +int cyw43_wifi_pm(cyw43_t *self, uint32_t pm); +int cyw43_wifi_link_status(cyw43_t *self, int itf); +void cyw43_wifi_set_up(cyw43_t *self, int itf, bool up); +int cyw43_wifi_get_mac(cyw43_t *self, int itf, uint8_t mac[6]); +int cyw43_wifi_scan(cyw43_t *self, cyw43_wifi_scan_options_t *opts, void *env, int (*result_cb)(void*, const cyw43_ev_scan_result_t*)); + +static inline bool cyw43_wifi_scan_active(cyw43_t *self) { + return self->wifi_scan_state == 1; +} + +int cyw43_wifi_join(cyw43_t *self, size_t ssid_len, const uint8_t *ssid, size_t key_len, const uint8_t *key, uint32_t auth_type, const uint8_t *bssid, uint32_t channel); +int cyw43_wifi_leave(cyw43_t *self, int itf); + +static inline void cyw43_wifi_ap_get_ssid(cyw43_t *self, size_t *len, const uint8_t **buf) { + *len = self->ap_ssid_len; + *buf = self->ap_ssid; +} + +static inline void cyw43_wifi_ap_set_channel(cyw43_t *self, uint32_t channel) { + self->ap_channel = channel; +} + +static inline void cyw43_wifi_ap_set_ssid(cyw43_t *self, size_t len, const uint8_t *buf) { + self->ap_ssid_len = MIN(len, sizeof(self->ap_ssid)); + memcpy(self->ap_ssid, buf, self->ap_ssid_len); +} + +static inline void cyw43_wifi_ap_set_password(cyw43_t *self, size_t len, const uint8_t *buf) { + self->ap_key_len = MIN(len, sizeof(self->ap_key)); + memcpy(self->ap_key, buf, self->ap_key_len); +} + +static inline void cyw43_wifi_ap_set_auth(cyw43_t *self, uint32_t auth) { + self->ap_auth = auth; +} + +void cyw43_wifi_ap_get_stas(cyw43_t *self, int *num_stas, uint8_t *macs); + +void cyw43_tcpip_init(cyw43_t *self, int itf); +void cyw43_tcpip_deinit(cyw43_t *self, int itf); +void cyw43_tcpip_set_link_up(cyw43_t *self, int itf); +void cyw43_tcpip_set_link_down(cyw43_t *self, int itf); +int cyw43_tcpip_link_status(cyw43_t *self, int itf); + +#endif // MICROPY_INCLUDED_STM32_CYW43_H diff --git a/drivers/cyw43/cyw43_ctrl.c b/drivers/cyw43/cyw43_ctrl.c new file mode 100644 index 0000000000..3a8bbf8646 --- /dev/null +++ b/drivers/cyw43/cyw43_ctrl.c @@ -0,0 +1,588 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2019 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/mphal.h" +#include "drivers/cyw43/cyw43.h" +#include "pendsv.h" +#include "sdio.h" + +#define CYW_ENTER MICROPY_PY_LWIP_ENTER +#define CYW_EXIT MICROPY_PY_LWIP_EXIT + +#ifdef pyb_pin_WL_HOST_WAKE +#define USE_SDIOIT (0) +#else +#define USE_SDIOIT (1) +#endif + +#define CYW43_SLEEP_MAX (50) + +#define WIFI_JOIN_STATE_ACTIVE (0x0001) +#define WIFI_JOIN_STATE_FAIL (0x0002) +#define WIFI_JOIN_STATE_NONET (0x0003) +#define WIFI_JOIN_STATE_BADAUTH (0x0004) +#define WIFI_JOIN_STATE_AUTH (0x0200) +#define WIFI_JOIN_STATE_LINK (0x0400) +#define WIFI_JOIN_STATE_KEYED (0x0800) +#define WIFI_JOIN_STATE_ALL (0x0e01) + +cyw43_t cyw43_state; +void (*cyw43_poll)(void); +uint32_t cyw43_sleep; + +STATIC void cyw43_poll_func(void); +STATIC void cyw43_wifi_ap_init(cyw43_t *self); +STATIC void cyw43_wifi_ap_set_up(cyw43_t *self, bool up); + +static inline uint32_t cyw43_get_be16(const uint8_t *buf) { + return buf[0] << 8 | buf[1]; +} + +static inline uint32_t cyw43_get_be32(const uint8_t *buf) { + return buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; +} + +static inline void cyw43_delay_ms(uint32_t ms) { + mp_hal_delay_ms(ms); +} + +/*******************************************************************************/ +// Initialisation and polling + +void cyw43_init(cyw43_t *self) { + #ifdef pyb_pin_WL_HOST_WAKE + mp_hal_pin_config(pyb_pin_WL_HOST_WAKE, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_NONE, 0); + #endif + mp_hal_pin_config(pyb_pin_WL_REG_ON, MP_HAL_PIN_MODE_OUTPUT, MP_HAL_PIN_PULL_NONE, 0); + mp_hal_pin_low(pyb_pin_WL_REG_ON); + #ifdef pyb_pin_WL_RFSW_VDD + mp_hal_pin_config(pyb_pin_WL_RFSW_VDD, MP_HAL_PIN_MODE_OUTPUT, MP_HAL_PIN_PULL_NONE, 0); // RF-switch power + mp_hal_pin_low(pyb_pin_WL_RFSW_VDD); + #endif + + cyw43_ll_init(&self->cyw43_ll, self); + + self->itf_state = 0; + self->wifi_scan_state = 0; + self->wifi_join_state = 0; + self->pend_disassoc = false; + self->pend_rejoin= false; + self->pend_rejoin_wpa = false; + self->ap_channel = 3; + self->ap_ssid_len = 0; + self->ap_key_len = 0; + + cyw43_poll = NULL; +} + +void cyw43_deinit(cyw43_t *self) { + CYW_ENTER + + cyw43_ll_bus_sleep(&self->cyw43_ll, true); + cyw43_delay_ms(2); + cyw43_tcpip_deinit(self, 0); + cyw43_tcpip_deinit(self, 1); + + self->itf_state = 0; + + // Disable async polling + SDMMC1->MASK &= ~SDMMC_MASK_SDIOITIE; + cyw43_poll = NULL; + + #ifdef pyb_pin_WL_RFSW_VDD + // Turn the RF-switch off + mp_hal_pin_low(pyb_pin_WL_RFSW_VDD); + #endif + + // Power down the WL chip and the SDIO bus + mp_hal_pin_low(pyb_pin_WL_REG_ON); + sdio_deinit(); + + CYW_EXIT +} + +STATIC int cyw43_ensure_up(cyw43_t *self) { + if (cyw43_poll != NULL) { + cyw43_ll_bus_sleep(&self->cyw43_ll, false); + return 0; + } + + CYW_ENTER + + // Disable the netif if it was previously up + cyw43_tcpip_deinit(self, CYW43_ITF_STA); + cyw43_tcpip_deinit(self, CYW43_ITF_AP); + self->itf_state = 0; + + // Reset and power up the WL chip + mp_hal_pin_low(pyb_pin_WL_REG_ON); + cyw43_delay_ms(20); + mp_hal_pin_high(pyb_pin_WL_REG_ON); + cyw43_delay_ms(50); + + // Initialise SDIO bus + // IRQ priority only needs to be higher than CYW_ENTER/EXIT protection (PENDSV) + sdio_init(NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 14, 0)); + + // Initialise the low-level driver + uint8_t mac[6]; + mp_hal_get_mac(MP_HAL_MAC_WLAN0, mac); + int ret = cyw43_ll_bus_init(&self->cyw43_ll, mac); + + if (ret != 0) { + CYW_EXIT + return ret; + } + + // Enable async events from low-level driver + cyw43_sleep = CYW43_SLEEP_MAX; + cyw43_poll = cyw43_poll_func; + #if USE_SDIOIT + SDMMC1->MASK |= SDMMC_MASK_SDIOITIE; + #else + extern void extint_set(const pin_obj_t *pin, uint32_t mode); + extint_set(pyb_pin_WL_HOST_WAKE, GPIO_MODE_IT_FALLING); + #endif + + CYW_EXIT + + return ret; +} + +// This function must always be executed at the level where CYW_ENTER is effectively active +STATIC void cyw43_poll_func(void) { + if (cyw43_poll == NULL) { + // Poll scheduled during deinit, just ignore it + return; + } + + cyw43_t *self = &cyw43_state; + cyw43_ll_process_packets(&self->cyw43_ll); + + if (self->pend_disassoc) { + self->pend_disassoc = false; + cyw43_ll_ioctl(&self->cyw43_ll, CYW43_IOCTL_SET_DISASSOC, 0, NULL, CYW43_ITF_STA); + } + + if (self->pend_rejoin_wpa) { + self->pend_rejoin_wpa = false; + cyw43_ll_wifi_set_wpa_auth(&self->cyw43_ll); + } + + if (self->pend_rejoin) { + self->pend_rejoin = false; + cyw43_ll_wifi_rejoin(&self->cyw43_ll); + self->wifi_join_state = WIFI_JOIN_STATE_ACTIVE; + } + + if (cyw43_sleep == 0) { + cyw43_ll_bus_sleep(&self->cyw43_ll, true); + #if !USE_SDIOIT + sdio_deinit(); // save power while WLAN bus sleeps + #endif + } + + #if USE_SDIOIT + SDMMC1->MASK |= SDMMC_MASK_SDIOITIE; + #endif +} + +/*******************************************************************************/ +// Callback interface to low-level driver + +int cyw43_cb_read_host_interrupt_pin(void *cb_data) { + #ifdef pyb_pin_WL_HOST_WAKE + return mp_hal_pin_read(pyb_pin_WL_HOST_WAKE); + #else + return mp_hal_pin_read(pyb_pin_WL_SDIO_1); + #endif +} + +void cyw43_cb_ensure_awake(void *cb_data) { + cyw43_sleep = CYW43_SLEEP_MAX; + #if !USE_SDIOIT + if (__HAL_RCC_SDMMC1_IS_CLK_DISABLED()) { + __HAL_RCC_SDMMC1_CLK_ENABLE(); // enable SDIO peripheral + sdio_enable_high_speed_4bit(); + } + #endif +} + +STATIC const char *cyw43_async_event_name_table[89] = { + [0 ... 88] = NULL, + [CYW43_EV_SET_SSID] = "SET_SSID", + [CYW43_EV_JOIN] = "JOIN", + [CYW43_EV_AUTH] = "AUTH", + [CYW43_EV_DEAUTH_IND] = "DEAUTH_IND", + [CYW43_EV_ASSOC] = "ASSOC", + [CYW43_EV_DISASSOC] = "DISASSOC", + [CYW43_EV_DISASSOC_IND] = "DISASSOC_IND", + [CYW43_EV_LINK] = "LINK", + [CYW43_EV_PSK_SUP] = "PSK_SUP", + [CYW43_EV_ESCAN_RESULT] = "ESCAN_RESULT", + [CYW43_EV_CSA_COMPLETE_IND] = "CSA_COMPLETE_IND", + [CYW43_EV_ASSOC_REQ_IE] = "ASSOC_REQ_IE", + [CYW43_EV_ASSOC_RESP_IE] = "ASSOC_RESP_IE", +}; + +STATIC void cyw43_dump_async_event(const cyw43_async_event_t *ev) { + printf("[% 8d] ASYNC(%04x,", + mp_hal_ticks_ms(), + (unsigned int)ev->flags + ); + if (ev->event_type < MP_ARRAY_SIZE(cyw43_async_event_name_table) + && cyw43_async_event_name_table[ev->event_type] != NULL) { + printf("%s", cyw43_async_event_name_table[ev->event_type]); + } else { + printf("%u", (unsigned int)ev->event_type); + } + printf(",%u,%u,%u)\n", + (unsigned int)ev->status, + (unsigned int)ev->reason, + (unsigned int)ev->interface + ); +} + +void cyw43_cb_process_async_event(void *cb_data, const cyw43_async_event_t *ev) { + cyw43_t *self = cb_data; + + if (self->trace_flags & CYW43_TRACE_ASYNC_EV) { + cyw43_dump_async_event(ev); + } + + if (ev->event_type == CYW43_EV_ESCAN_RESULT && self->wifi_scan_state == 1) { + // Escan result event + if (ev->status == 8) { + // Partial result + int ret = self->wifi_scan_cb(self->wifi_scan_env, &ev->u.scan_result); + if (ret != 0) { + // TODO need to abort scan, or just ignore any more results + } + } else if (ev->status == 0) { + // Scan complete + self->wifi_scan_state = 2; + } + + } else if (ev->event_type == CYW43_EV_DISASSOC) { + cyw43_tcpip_set_link_down(self, CYW43_ITF_STA); + self->wifi_join_state = 0x0000; + + /* + } else if (ev->event_type == CYW43_EV_DISASSOC_IND) { + if (ev->interface == CYW43_ITF_AP) { + // Station disassociated with our AP, let DHCP server know so it can free the IP address + dhcp_server_disassoc(&self->dhcp_server, buf + 24); + } + */ + + // WiFi join events + } else if (ev->event_type == CYW43_EV_PRUNE) { + if (ev->status == 0 && ev->reason == 8) { + // RSN mismatch, retry join with WPA auth + self->pend_rejoin = true; + self->pend_rejoin_wpa = true; + pendsv_schedule_dispatch(PENDSV_DISPATCH_CYW43, cyw43_poll_func); + } + } else if (ev->event_type == CYW43_EV_SET_SSID) { + if (ev->status == 0) { + // Success setting SSID + } else if (ev->status == 3 && ev->reason == 0) { + self->wifi_join_state = WIFI_JOIN_STATE_NONET; + // No matching SSID found (could be out of range, or down) + } else { + // Other failure setting SSID + self->wifi_join_state = WIFI_JOIN_STATE_FAIL; + } + } else if (ev->event_type == CYW43_EV_AUTH) { + if (ev->status == 0) { + self->wifi_join_state |= WIFI_JOIN_STATE_AUTH; + } else if (ev->status == 6) { + // Unsolicited auth packet, ignore it + } else { + // Cannot authenticate + self->wifi_join_state = WIFI_JOIN_STATE_BADAUTH; + } + } else if (ev->event_type == CYW43_EV_DEAUTH_IND) { + if (ev->status == 0 && ev->reason == 2) { + // Deauth, probably because password was wrong; disassociate + self->pend_disassoc = true; + pendsv_schedule_dispatch(PENDSV_DISPATCH_CYW43, cyw43_poll_func); + } + } else if (ev->event_type == CYW43_EV_LINK) { + if (ev->status == 0) { + if (ev->flags & 1) { + // Link is up + if (ev->interface == CYW43_ITF_STA) { + self->wifi_join_state |= WIFI_JOIN_STATE_LINK; + } else { + cyw43_tcpip_set_link_up(self, ev->interface); + } + } else { + // Link is down + cyw43_tcpip_set_link_down(self, ev->interface); + } + } + } else if (ev->event_type == CYW43_EV_PSK_SUP) { + if (ev->status == 6) { // WLC_SUP_KEYED + self->wifi_join_state |= WIFI_JOIN_STATE_KEYED; + } else if ((ev->status == 4 || ev->status == 8 || ev->status == 11) && ev->reason == 15) { + // Timeout waiting for key exchange M1/M3/G1 + // Probably at edge of the cell, retry + self->pend_rejoin = true; + pendsv_schedule_dispatch(PENDSV_DISPATCH_CYW43, cyw43_poll_func); + } else { + // PSK_SUP failure + self->wifi_join_state = WIFI_JOIN_STATE_BADAUTH; + } + } + + if (self->wifi_join_state == WIFI_JOIN_STATE_ALL) { + // STA connected + self->wifi_join_state = WIFI_JOIN_STATE_ACTIVE; + cyw43_tcpip_set_link_up(self, CYW43_ITF_STA); + } +} + +/*******************************************************************************/ +// Ioctl and Ethernet interface + +int cyw43_ioctl(cyw43_t *self, uint32_t cmd, size_t len, uint8_t *buf, uint32_t iface) { + int ret = cyw43_ensure_up(self); + if (ret) { + return ret; + } + + CYW_ENTER + ret = cyw43_ll_ioctl(&self->cyw43_ll, cmd, len, buf, iface); + CYW_EXIT + + return ret; +} + +int cyw43_send_ethernet(cyw43_t *self, int itf, size_t len, const void *buf, bool is_pbuf) { + int ret = cyw43_ensure_up(self); + if (ret) { + return ret; + } + + CYW_ENTER + ret = cyw43_ll_send_ethernet(&self->cyw43_ll, itf, len, buf, is_pbuf); + CYW_EXIT + + return ret; +} + +/*******************************************************************************/ +// WiFi control + +STATIC int cyw43_wifi_on(cyw43_t *self, uint32_t country) { + int ret = cyw43_ensure_up(self); + if (ret) { + return ret; + } + + #ifdef pyb_pin_WL_RFSW_VDD + // Turn the RF-switch on + mp_hal_pin_high(pyb_pin_WL_RFSW_VDD); + #endif + + CYW_ENTER + ret = cyw43_ll_wifi_on(&self->cyw43_ll, country); + CYW_EXIT + + return ret; +} + +int cyw43_wifi_pm(cyw43_t *self, uint32_t pm_in) { + int ret = cyw43_ensure_up(self); + if (ret) { + return ret; + } + + // pm_in: 0x00adbrrm + uint32_t pm = pm_in & 0xf; + uint32_t pm_sleep_ret = (pm_in >> 4) & 0xff; + uint32_t li_bcn = (pm_in >> 12) & 0xf; + uint32_t li_dtim = (pm_in >> 16) & 0xf; + uint32_t li_assoc = (pm_in >> 20) & 0xf; + + CYW_ENTER + ret = cyw43_ll_wifi_pm(&self->cyw43_ll, pm, pm_sleep_ret, li_bcn, li_dtim, li_assoc); + CYW_EXIT + + return ret; +} + +int cyw43_wifi_get_mac(cyw43_t *self, int itf, uint8_t mac[6]) { + mp_hal_get_mac(MP_HAL_MAC_WLAN0, &mac[0]); + return 0; +} + +#define MAKE_COUNTRY(a, b, rev) ((a) | (b) << 8 | (rev) << 16) + +void cyw43_wifi_set_up(cyw43_t *self, int itf, bool up) { + if (up) { + if (self->itf_state == 0) { + uint32_t country; + extern char pyb_country_code[2]; + if (pyb_country_code[0] == '\0' || pyb_country_code[1] == '\0') { + country = MAKE_COUNTRY('X', 'X', 17); // default to world-wide (passive ch 12-14) + } else { + country = MAKE_COUNTRY(pyb_country_code[0], pyb_country_code[1], 0); + } + cyw43_wifi_on(self, country); + cyw43_wifi_pm(self, 10 << 20 | 1 << 16 | 1 << 12 | 20 << 4 | 2); + } + if (itf == CYW43_ITF_AP) { + cyw43_wifi_ap_init(self); + cyw43_wifi_ap_set_up(self, true); + } + if ((self->itf_state & (1 << itf)) == 0) { + CYW_ENTER + cyw43_tcpip_deinit(self, itf); + cyw43_tcpip_init(self, itf); + self->itf_state |= 1 << itf; + CYW_EXIT + } + } else { + if (itf == CYW43_ITF_AP) { + cyw43_wifi_ap_set_up(self, false); + } + } +} + +int cyw43_wifi_scan(cyw43_t *self, cyw43_wifi_scan_options_t *opts, void *env, int (*result_cb)(void*, const cyw43_ev_scan_result_t*)) { + if (self->itf_state == 0) { + return -1; + } + + cyw43_ensure_up(self); + + CYW_ENTER + + // Set state and callback data + self->wifi_scan_state = 1; + self->wifi_scan_env = env; + self->wifi_scan_cb = result_cb; + + // Start the scan + int ret = cyw43_ll_wifi_scan(&self->cyw43_ll, opts); + + CYW_EXIT + + return ret; +} + +int cyw43_wifi_link_status(cyw43_t *self, int itf) { + if (itf == CYW43_ITF_STA) { + int s = self->wifi_join_state & 0xf; + if (s == WIFI_JOIN_STATE_ACTIVE) { + return CYW43_LINK_JOIN; + } else if (s == WIFI_JOIN_STATE_FAIL) { + return CYW43_LINK_FAIL; + } else if (s == WIFI_JOIN_STATE_NONET) { + return CYW43_LINK_NONET; + } else if (s == WIFI_JOIN_STATE_BADAUTH) { + return CYW43_LINK_BADAUTH; + } else { + return CYW43_LINK_DOWN; + } + } else { + return CYW43_LINK_DOWN; + } +} + +/*******************************************************************************/ +// WiFi STA + +int cyw43_wifi_join(cyw43_t *self, size_t ssid_len, const uint8_t *ssid, size_t key_len, const uint8_t *key, uint32_t auth_type, const uint8_t *bssid, uint32_t channel) { + int ret = cyw43_ensure_up(self); + if (ret) { + return ret; + } + + CYW_ENTER + + ret = cyw43_ll_wifi_join(&self->cyw43_ll, ssid_len, ssid, key_len, key, auth_type, bssid, channel); + + if (ret == 0) { + // Wait for responses: EV_AUTH, EV_LINK, EV_SET_SSID, EV_PSK_SUP + // Will get EV_DEAUTH_IND if password is invalid + self->wifi_join_state = WIFI_JOIN_STATE_ACTIVE; + + if (auth_type == 0) { + // For open security we don't need EV_PSK_SUP, so set that flag indicator now + self->wifi_join_state |= WIFI_JOIN_STATE_KEYED; + } + } + + CYW_EXIT + + return ret; +} + +int cyw43_wifi_leave(cyw43_t *self, int itf) { + // Disassociate with SSID + return cyw43_ioctl(self, CYW43_IOCTL_SET_DISASSOC, 0, NULL, itf); +} + +/*******************************************************************************/ +// WiFi AP + +STATIC void cyw43_wifi_ap_init(cyw43_t *self) { + int ret = cyw43_ensure_up(self); + if (ret) { + return; + } + + CYW_ENTER + cyw43_ll_wifi_ap_init(&self->cyw43_ll, self->ap_ssid_len, self->ap_ssid, self->ap_auth, self->ap_key_len, self->ap_key, self->ap_channel); + CYW_EXIT +} + +STATIC void cyw43_wifi_ap_set_up(cyw43_t *self, bool up) { + int ret = cyw43_ensure_up(self); + if (ret) { + return; + } + + CYW_ENTER + cyw43_ll_wifi_ap_set_up(&self->cyw43_ll, up); + CYW_EXIT +} + +void cyw43_wifi_ap_get_stas(cyw43_t *self, int *num_stas, uint8_t *macs) { + int ret = cyw43_ensure_up(self); + if (ret) { + return; + } + + CYW_ENTER + cyw43_ll_wifi_ap_get_stas(&self->cyw43_ll, num_stas, macs); + CYW_EXIT +} diff --git a/drivers/cyw43/cyw43_ll.h b/drivers/cyw43/cyw43_ll.h new file mode 100644 index 0000000000..879367a2ed --- /dev/null +++ b/drivers/cyw43/cyw43_ll.h @@ -0,0 +1,135 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2019 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_CYW43_LL_H +#define MICROPY_INCLUDED_STM32_CYW43_LL_H + +// IOCTL commands +#define CYW43_IOCTL_GET_SSID (0x32) +#define CYW43_IOCTL_GET_CHANNEL (0x3a) +#define CYW43_IOCTL_SET_DISASSOC (0x69) +#define CYW43_IOCTL_GET_ANTDIV (0x7e) +#define CYW43_IOCTL_SET_ANTDIV (0x81) +#define CYW43_IOCTL_SET_MONITOR (0xd9) +#define CYW43_IOCTL_GET_VAR (0x20c) +#define CYW43_IOCTL_SET_VAR (0x20f) + +// Async events, event_type field +#define CYW43_EV_SET_SSID (0) +#define CYW43_EV_JOIN (1) +#define CYW43_EV_AUTH (3) +#define CYW43_EV_DEAUTH_IND (6) +#define CYW43_EV_ASSOC (7) +#define CYW43_EV_DISASSOC (11) +#define CYW43_EV_DISASSOC_IND (12) +#define CYW43_EV_LINK (16) +#define CYW43_EV_PRUNE (23) +#define CYW43_EV_PSK_SUP (46) +#define CYW43_EV_ESCAN_RESULT (69) +#define CYW43_EV_CSA_COMPLETE_IND (80) +#define CYW43_EV_ASSOC_REQ_IE (87) +#define CYW43_EV_ASSOC_RESP_IE (88) + +enum { + CYW43_ITF_STA, + CYW43_ITF_AP, +}; + +typedef struct _cyw43_ev_scan_result_t { + uint32_t _0[5]; + uint8_t bssid[6]; + uint16_t _1[2]; + uint8_t ssid_len; + uint8_t ssid[32]; + uint32_t _2[5]; + uint16_t channel; + uint16_t _3; + uint8_t auth_mode; + int16_t rssi; +} cyw43_ev_scan_result_t; + +typedef struct _cyw43_async_event_t { + uint16_t _0; + uint16_t flags; + uint32_t event_type; + uint32_t status; + uint32_t reason; + uint8_t _1[30]; + uint8_t interface; + uint8_t _2; + union { + cyw43_ev_scan_result_t scan_result; + } u; +} cyw43_async_event_t; + +typedef struct _cyw43_wifi_scan_options_t { + uint32_t version; + uint16_t action; + uint16_t _; + uint32_t ssid_len; // 0 to select all + uint8_t ssid[32]; + uint8_t bssid[6]; + int8_t bss_type; // fill with 0xff to select all + int8_t scan_type; // 0=active, 1=passive + int32_t nprobes; + int32_t active_time; + int32_t passive_time; + int32_t home_time; + int32_t channel_num; + uint16_t channel_list[1]; +} cyw43_wifi_scan_options_t; + +typedef struct _cyw43_ll_t { + uint32_t opaque[528]; +} cyw43_ll_t; + +void cyw43_ll_init(cyw43_ll_t *self, void *cb_data); +void cyw43_ll_deinit(cyw43_ll_t *self); + +int cyw43_ll_bus_init(cyw43_ll_t *self, const uint8_t *mac); +void cyw43_ll_bus_sleep(cyw43_ll_t *self, bool can_sleep); +void cyw43_ll_process_packets(cyw43_ll_t *self); +int cyw43_ll_ioctl(cyw43_ll_t *self, uint32_t cmd, size_t len, uint8_t *buf, uint32_t iface); +int cyw43_ll_send_ethernet(cyw43_ll_t *self, int itf, size_t len, const void *buf, bool is_pbuf); + +int cyw43_ll_wifi_on(cyw43_ll_t *self, uint32_t country); +int cyw43_ll_wifi_pm(cyw43_ll_t *self, uint32_t pm, uint32_t pm_sleep_ret, uint32_t li_bcn, uint32_t li_dtim, uint32_t li_assoc); +int cyw43_ll_wifi_scan(cyw43_ll_t *self, cyw43_wifi_scan_options_t *opts); + +int cyw43_ll_wifi_join(cyw43_ll_t *self, size_t ssid_len, const uint8_t *ssid, size_t key_len, const uint8_t *key, uint32_t auth_type, const uint8_t *bssid, uint32_t channel); +void cyw43_ll_wifi_set_wpa_auth(cyw43_ll_t *self); +void cyw43_ll_wifi_rejoin(cyw43_ll_t *self); + +int cyw43_ll_wifi_ap_init(cyw43_ll_t *self, size_t ssid_len, const uint8_t *ssid, uint32_t auth, size_t key_len, const uint8_t *key, uint32_t channel); +int cyw43_ll_wifi_ap_set_up(cyw43_ll_t *self, bool up); +int cyw43_ll_wifi_ap_get_stas(cyw43_ll_t *self, int *num_stas, uint8_t *macs); + +// Callbacks to be provided by mid-level interface +int cyw43_cb_read_host_interrupt_pin(void *cb_data); +void cyw43_cb_ensure_awake(void *cb_data); +void cyw43_cb_process_async_event(void *cb_data, const cyw43_async_event_t *ev); +void cyw43_cb_process_ethernet(void *cb_data, int itf, size_t len, const uint8_t *buf); + +#endif // MICROPY_INCLUDED_STM32_CYW43_LL_H diff --git a/drivers/cyw43/cyw43_lwip.c b/drivers/cyw43/cyw43_lwip.c new file mode 100644 index 0000000000..8f4223029e --- /dev/null +++ b/drivers/cyw43/cyw43_lwip.c @@ -0,0 +1,197 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2019 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/mphal.h" +#include "lib/netutils/netutils.h" +#include "lwip/etharp.h" +#include "lwip/dns.h" +#include "lwip/apps/mdns.h" +#include "drivers/cyw43/cyw43.h" + +STATIC void cyw43_ethernet_trace(cyw43_t *self, struct netif *netif, size_t len, const void *data, unsigned int flags) { + bool is_tx = flags & NETUTILS_TRACE_IS_TX; + if ((is_tx && (self->trace_flags & CYW43_TRACE_ETH_TX)) + || (!is_tx && (self->trace_flags & CYW43_TRACE_ETH_RX))) { + const uint8_t *buf; + if (len == (size_t)-1) { + // data is a pbuf + const struct pbuf *pbuf = data; + buf = pbuf->payload; + len = pbuf->len; // restricted to print only the first chunk of the pbuf + } else { + // data is actual data buffer + buf = data; + } + + if (self->trace_flags & CYW43_TRACE_MAC) { + printf("[% 8d] ETH%cX itf=%c%c len=%u", mp_hal_ticks_ms(), is_tx ? 'T' : 'R', netif->name[0], netif->name[1], len); + printf(" MAC type=%d subtype=%d data=", buf[0] >> 2 & 3, buf[0] >> 4); + for (size_t i = 0; i < len; ++i) { + printf(" %02x", buf[i]); + } + printf("\n"); + return; + } + + if (self->trace_flags & CYW43_TRACE_ETH_FULL) { + flags |= NETUTILS_TRACE_PAYLOAD; + } + netutils_ethernet_trace(MP_PYTHON_PRINTER, len, buf, flags); + } +} + +STATIC err_t cyw43_netif_output(struct netif *netif, struct pbuf *p) { + cyw43_t *self = netif->state; + if (self->trace_flags != 0) { + cyw43_ethernet_trace(self, netif, (size_t)-1, p, NETUTILS_TRACE_IS_TX | NETUTILS_TRACE_NEWLINE); + } + int itf = netif->name[1] - '0'; + int ret = cyw43_send_ethernet(self, itf, p->tot_len, (void*)p, true); + if (ret) { + printf("[CYW43] send_ethernet failed: %d\n", ret); + return ERR_IF; + } + return ERR_OK; +} + +STATIC err_t cyw43_netif_init(struct netif *netif) { + netif->linkoutput = cyw43_netif_output; + netif->output = etharp_output; + netif->mtu = 1500; + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP; + cyw43_wifi_get_mac(netif->state, netif->name[1] - '0', netif->hwaddr); + netif->hwaddr_len = sizeof(netif->hwaddr); + return ERR_OK; +} + +void cyw43_tcpip_init(cyw43_t *self, int itf) { + ip_addr_t ipconfig[4]; + #if LWIP_IPV6 + #define IP(x) ((x).u_addr.ip4) + #else + #define IP(x) (x) + #endif + if (itf == 0) { + // need to zero out to get isconnected() working + IP4_ADDR(&IP(ipconfig[0]), 0, 0, 0, 0); + IP4_ADDR(&IP(ipconfig[2]), 192, 168, 0, 1); + } else { + IP4_ADDR(&IP(ipconfig[0]), 192, 168, 4, 1); + IP4_ADDR(&IP(ipconfig[2]), 192, 168, 4, 1); + } + IP4_ADDR(&IP(ipconfig[1]), 255, 255, 255, 0); + IP4_ADDR(&IP(ipconfig[3]), 8, 8, 8, 8); + #undef IP + + struct netif *n = &self->netif[itf]; + n->name[0] = 'w'; + n->name[1] = '0' + itf; + #if LWIP_IPV6 + netif_add(n, &ipconfig[0].u_addr.ip4, &ipconfig[1].u_addr.ip4, &ipconfig[2].u_addr.ip4, self, cyw43_netif_init, ethernet_input); + #else + netif_add(n, &ipconfig[0], &ipconfig[1], &ipconfig[2], self, cyw43_netif_init, netif_input); + #endif + netif_set_hostname(n, "PYBD"); + netif_set_default(n); + netif_set_up(n); + + if (itf == CYW43_ITF_STA) { + dns_setserver(0, &ipconfig[3]); + dhcp_set_struct(n, &self->dhcp_client); + dhcp_start(n); + } else { + dhcp_server_init(&self->dhcp_server, &ipconfig[0], &ipconfig[1]); + } + + #if LWIP_MDNS_RESPONDER + // TODO better to call after IP address is set + char mdns_hostname[9]; + memcpy(&mdns_hostname[0], "PYBD", 4); + mp_hal_get_mac_ascii(MP_HAL_MAC_WLAN0, 8, 4, &mdns_hostname[4]); + mdns_hostname[8] = '\0'; + mdns_resp_add_netif(n, mdns_hostname, 60); + #endif +} + +void cyw43_tcpip_deinit(cyw43_t *self, int itf) { + struct netif *n = &self->netif[itf]; + if (itf == CYW43_ITF_STA) { + dhcp_stop(n); + } else { + dhcp_server_deinit(&self->dhcp_server); + } + #if LWIP_MDNS_RESPONDER + mdns_resp_remove_netif(n); + #endif + for (struct netif *netif = netif_list; netif != NULL; netif = netif->next) { + if (netif == n) { + netif_remove(netif); + netif->ip_addr.addr = 0; + netif->flags = 0; + } + } +} + +void cyw43_cb_process_ethernet(void *cb_data, int itf, size_t len, const uint8_t *buf) { + cyw43_t *self = cb_data; + struct netif *netif = &self->netif[itf]; + if (self->trace_flags) { + cyw43_ethernet_trace(self, netif, len, buf, NETUTILS_TRACE_NEWLINE); + } + if (netif->flags & NETIF_FLAG_LINK_UP) { + struct pbuf *p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); + if (p != NULL) { + pbuf_take(p, buf, len); + if (netif->input(p, netif) != ERR_OK) { + pbuf_free(p); + } + } + } +} + +void cyw43_tcpip_set_link_up(cyw43_t *self, int itf) { + netif_set_link_up(&self->netif[itf]); +} + +void cyw43_tcpip_set_link_down(cyw43_t *self, int itf) { + netif_set_link_down(&self->netif[itf]); +} + +int cyw43_tcpip_link_status(cyw43_t *self, int itf) { + struct netif *netif = &self->netif[itf]; + if ((netif->flags & (NETIF_FLAG_UP | NETIF_FLAG_LINK_UP)) + == (NETIF_FLAG_UP | NETIF_FLAG_LINK_UP)) { + if (netif->ip_addr.addr != 0) { + return CYW43_LINK_UP; + } else { + return CYW43_LINK_NOIP; + } + } else { + return cyw43_wifi_link_status(self, itf); + } +} diff --git a/drivers/cyw43/libcyw43.a b/drivers/cyw43/libcyw43.a new file mode 100644 index 0000000000000000000000000000000000000000..7d0ff93dcbe686e225efd2e119694d13e36ece5b GIT binary patch literal 437538 zcmeFa2~<>9+BUk+IaO3qfEJ>r1c#!^p#U+(pyJqNfd>?gsOiLLIusP>K~XAz35g~F zH3?++gJKet3??Ss4oSB-d@V6FCMIb!eO=|y4Gyu4NpMIy2gRJDAa$R8PLU9Af8T%C z`tSPxyYA{@z4botyWc(U{qB7RcEwK3D|HLg4R@M<{jv8ERowU6Y)(x}4O+Migpepg z*oXetD1I*?D!CtdI5j1=xHz|HRZ%(lSt=;}wOm%Xsvx(pTqrDERoKVOQ(EFKEGx_P zPmOyFYzp&5q+|~k0=FrlFR`)4)uYMWyW#xHgWa-1XsVS)` z_s&SlotT?CK6g@D?sz*5DlPvn!qArgMMzoEqlJXrdHVqAGd}(mOiJt3x(sR$mKK(k ztS)sIjw`t{s6h|AS5Aa%{;x*cgj98uCE1fxRU4P#iJ5bFhG8)1)DJ^!KD;i!!s#(7_tCR}9>1&hX<2750QM@7V;MPh+`{-!YWdme}+y zJNe&c{H=Wl-_=f9Xp=b-#Qo2u-*Wws8jL*2tlxkj%oiHe5BK&J8*2T^D-$-H9IfQh-G%o5XlUhzP{;ISwpxzzmqjxX$N9E0~ws4 zq=`5 zN3Vy044}kI(!5H35I=(N$HyJoem$!!Dr2AAZ~J@KZ$7~utCJ(FTN{UG(Gr!2v^>oh z#TP=+3U6HrMKARP7Bz-;FrlB#>}NSUpD4{b<|Id~-2YFSLHr zPF*DZhzCfAUV8`s1}|%+uTg z()0i`j^-8SvqL&VW~jM_(2+Z=E|=5Eqh@@G*gF<=x$PUF>B z9#G^TdWePF&7u#Cyv7=kCiXPT;l^gUpLzaemNWR=t2KTi&{kn=|M0QY)7fE9y8+$50mOZXy;V@(t_Zwp#gg*>q?Av$4+} zOW(A2qw@h@SX^$K>xs>>*-XU#tOn9*+ENKdI>d(cBzv2Gc9uxPQw)W@EMNd1Y`%+Vl{DtVxqf=aC zUB7QP#-+7=^Tg1MuPZcH*0Gx8;|O`9BK`6QWht(B*GmXbX#4t!=!_E;?3E3{@W?gQ zaaP~_HN|mepKopGp~%OKal?J{A2Y?p_)Jqw$tkY$?Ij{Z9>zCI%JI#S2l1^TtMIKQ zEASmc1bpjAA-?q_AK#%Q7k&@5H9d|ok$6d*H;iAu=E*%8zJ|Ypk7;tQ;nr+*PW93D z-gf;++B*K6{QjOD9ozI&6E}O?6+IWi*EvJl_V9YE#xh#zL$vKKb|>v!f?m@3&R$}f zfb@@U2BU<=dt=Rzru;Qlq}<>4`zwZ!2WE!0xz||M+z}kFD~VR|QTCS4+jSk`TvG?z zAKsWHFE;EAZ|N5s9?O^$Do>}csI;!R^dK9X@F0`&q^zyo^<{))dG&JRt|@csFH*GWk&KcbZ@BBKt=BP&zwi-+#p>yS0~ zJLK@G5e*J`oN>6h8`WZog`r_wrTI!s(hhmoZtKOp4?sP3HnTrF*(=k`!( z+Z6-JnyGI~;hp>>KBl*B+J1g!SCJCy!5%HYsEKT4w(NC=*V|f>mDaKGs)uH5p=ddR zmYe)@%h_9e?W|4jGYbfbiWQ0T)BZHCtL?-lo@V$(N(xs{=j*8Jh&OcPQ>9<8Ws;6m zjh5H*Tlh_UwPKYyG=!hQPY(9UeBM7KAbsCeHq3EVH-L?`@n2pdvjS34fTex$bmAp7 zjgZ^Y(Ei`j_^eA9Hj6i7Rrt7zSk=_*G_`bXM=1Kl5lm5ncTUyz!>Xm>BNeapZkNWI z%(Jm(YJG1&N(gY6+tmM3OEu?ej7wVMjG>d^L2W2=4?OY=B|cX4zWFV@fY4B+f%2~> zR;*Q}jBCAXUDf(BE^qxhPo^gmBYwtkp6wXGY2cseSa?-7d4{%{t(CIP7;h)CW-74~ znVU*vX6mv=hTpW8t{!Ut?;3^`Cl;yC$onoy(O$!x8bqL}nh38KHMh5?*WPjtW%w8` zH|#omhd$V^cXjp7h|B-7SI@Q6b*m?Ex}Do&Zze6n8A2u=2zhl5LHmr4;%DnMBAr<; z_t0>Tk8NZhi*6)l)9Sar@qeS#Ze9)MGPjYYLM$#Y5XGV$Mz7OwGbulhOWVlbR{@*6J8ZOrJJ=4@#z$t*p0m- zOR-aA*?_dF%V9ApAw^v(AKLA(h43NXgIOQ9GZPBN9ryh?>u@{EtD*OFCG+z-s~@E4 z<|tUB;MrZo;^rP1mIj z=F4`e=^yA~Flqx*ayK2l0cl*2&*|pi71t|Xu@bXEW2sW`qg_k*%GpG*HFrIpJ+IST z`nVD@r0cP4jpZ=~FAJs`*UeZSQ8X`g5%_h+#(E!8dWx~ER`kzw9oDfYA5?VM(?3)= zPpw-~7lXQ8s}zxQv0^!`i-vPp%Zn6we3#y`OsVNBH`Th#>vE#4&R4n>ZB|#_tPl4x z!G3(^rrshdZSdqx){?DQRNlN#;VE55bRj1`+Bu54J2hLwuIQNRmcL%t-*Z$Z=4$Ng zHJolm=CXpIkJ8< z*8PB_yY=VmVlL+Y!cTm6W;^-N>oJcklr=HgGoARp;TuwI<{K&^D@kmfCklRIeJSEr z1*9w8?iEpuBb8R=8bT}LF+w;JBOQC{K18Xd91)l`Y3)=s!o3^}LcwqJi z(Hor+t=#niDcp6rY*;kaS0Y8a8tTcD&Ks@w%+_>FB~gOgy-;{>Zy7vNKx&jHg*(I- zDg)LHvctYXo&j=#((PnaB(LenAk3J6^qM>{=-rjREeuF8-NP+`Sk)hIMl3q_tfGmd zDQuQA>{c-nI0JYlumgA|aHgFTp8(FZr)EbB`R>I+sVlms;nCzOx>oHg9d1SMBlYjQ zlF@!EMWPHFGC-ef+|2ygEoPFoW&9k_?w`2LF)c~I3K<5XuPfEsKtP`A=cUH{jsJ? z@TgRZ0Pg70Y^691_)3>n!J)w4c2R9Se@|>citi?7PcvgVgE4&&X@3IpfzE;$OBioF z@WCZw!MZTAN=`OoPo6xd;0-y;@xi4C%LkYGTjp3;q!`m}=8etRrqg|9=9_!^V<)nO z*ITeM&(iQ?Upsp#{z+Qj6+=UP^je>Y)s^&0KkI6UR^LKK5$ol>PbnVr>#l^MbU)~v zWolup)W7WMqW2PreyP6vr>ul^1xE=4x2K&3R9@lm~0oL3j zJ&qm2yw0ae*;uBI-HjU8W#F3Q$D4Hg4^;Ac2VQ$H5SEGx3S#4X zr1^o#{Cr;X(@^wJPvD__yoJQFJ1CySvpagE8A>>(Xo%G=@RsN0v36QwW38DVIP1$x z;VEBU>X)*w`dy4x#yX%bu^}Da>Row`o!uRf9`7P%3mpSb&*ay%WAxlJ(i)9biPn6} zO|hMh18n+905q5*Bo0Jp>f7kMIfsZKvf%@C z&+stE;c_x+>Vaf4<3B2V26GJeLCB71Zy(NzCew{1LP- zZR>Gp-^n0sGYAiU4@iH2&ICHnm&0D)oC}>Lo9>!7^3eiDFTAYNJx^rxiv_gwqjCJY zU@K3xN1&CbRnk_To)a>rQvOX&rR>O2z0l4ZcC_{I9+qc#ieh?nUF@|u{&kBcMX7~= z{hwkJjuuX1K9dR2b&;!CO6vxF$J3|nTvb+!m3ga{78OjhS0oqM32qn{D1v=r z@&xh_?u05*Qfgr;DJXnM5mHkMlSzI_UTH!3Bc4J;RBRPRY2ibVlalR0gH@|nPD@TE zEA!lW1qG$k?Dol%?2}X7lilMdCnZl#Nh4*YB`ay9q$D-PrNw#6%4m}IRC{W&y{|Tf zs?+Sshg6j36)!C|^Z}?ldH@!t-!x z$QPrDJr)A*B$e4u|3$?N%>^u>WacudHJ+!?WFACf})3V3s)gO z6)y7>l|aD9UA(fmBo8-~f`Hy-FJE0ogPG$26n({j{EQ<@wt4hkvON&+&n3Wm=macp_ue9)ItA!b}=9%3q3&tm#3rkB& zN`p@kR+N>{X9BiS1#y$jOY@3~3kwWC$8ndG7AgrBtuo^tJRX(w=BXqx*(?;4npYN; zt;{QT3+7Sw)C%(h3i~CAg?D2_*+#9NGHP|=sMW}$yl7=%$?Ec7EDB0;mB%ZS&C5`Q z)vF3CJcaJ^!UD7U6vjNNPl0-EZKH};k2R}b|1#14c~VMy6k^5|mgbcg2HT{!dP-nf zVKEAFTga*s+7h0URb_?drI?Lor4xQ`7d*@vQ*K5}ne&TF+$+q=6Oi6igH<;_oL5v{ zv}&1oX-TO$ACH8PI@9gk`LyO=ZPlPXeO zFr>61cWIux90RKmey}`uW!bVa%;vnZ^4#L0vU1{CnXEoD%PmE5^WCeU&IRj*1!x_j zjB&-ja1|+39*tr6yO%DTT(;UnAAr%>&__(pEzI*gREXmKN}XH2vVybEf+PIW)b}}Ocvoo(S zFTaQ|ae&&1GZW{MkOBc z?Pn!}s})>t^pR=!i9Rxg{ys7ducYgg@=@bg_mOFMXCIkHmHWsv{2i>j>PL-#u#Zf` z_4G^msNn7l6t~ZNHu_TqnTC7&|2n+0k4(eo7=Impe;=8KKi5a5<*V%@ z({O*}uj6<2k!g5V)UU$}`p7iAypK%NujnJwaLvG9;`buTIigj@-!D4tFHi~pxuX<4 z?xNfl{_{WyhSS`B`Ecatj#HEzuH5@-XfxdLi#eh4@Z03%+hoUW^32=hxwpx8-zG1= zO@8(^dB<(?pKg=?e4FgMO>Tv(#rUI5J^=0Y9rzH)bjnfrC-4}^i-U4RpC+aC9|3ta z!WRX@(;$BdIXWn3LT-mVASf?}d;_uxO;6J=hTQw1=~dq*zXdrGjV^M(r_P>GMh|_d`VkkcS3kE94jyc6QKy668XR z&))W#5BU+uwLyC_vYd=8AS*q&LSAuhd69cXSuXZQD+^b;S9(ZUK~YI=d1>CNvZaNk zcom>ve9EtN#IqVNaFmsouA=6i(xO%6OM_b;cRsdbWvfdIbMqd~TT%FnmM)sPLJ3wZ zSYwB?+EbqE`T120MC*M&B(Lm|RqkA6ol^?rd4#f+B@gvUtk?GEw@gr$VytREzmxLo zw?+Q@H&i_NtC!}wOFWO@)s)imqP#xuqV(qTzw*wC(wcP3T3nbb6fF~S%RGgJ1-YsD zc!%b{dmrTIy7a#5f>xlLkzecoKmW=LF=Nabk_Z_c_Yc`2=;nWfKV50GaYrR1dpvf_8MhrTSHHk5vDA$|n-C2b}8Pr*ax0H-ma3<}TGA z12;^`R0EDav8Di}IoLTTNyy*BRQ=^3 zzZeb~`8lw@Q+pTX=r_9l(|pzjd1a7q2=Z4bk3;_i(L;u401o^v(Z2Bvy{{Q1&wzi$XkQ_OpyD7{37MZ=lh_H$L&fy zy8oc@bAtTtAYT;ZbpJua2Sg%2w9oP&e~5DAUmcX`K7`tR6XX|z{QDpmgS;00oW`rC z9O?ZOl<7NtRHpkCTFyC?({cs*-9dhTkh_AM?q8_gPvA5@-LKI2_hbGIPr>9ISN6!t z^1OWT@=}!xy{NRXcw9N|T##`EdAM8|M>q20aC=4(R8C_hjY}fq+$Ael;u?jFo3UW- zxV-Z6(xUv;xF>)N{-1qDzzjtqn0CqsLzU=J*4_`Mt@4S%cPPlANEpu+LUv%TQyq;@ z?J!kvgG-eWqG4&0COq3Qi{EuiL01K@fTJGeUK^U+}3 zcj!$#7)H~<6jSVIy7V&!n~=WyGipOA2ZZPzFy%87cC>AJKh%bPDDN#BmDj?~jxDDF zI0;1C#R#J9)TcP)9W?xkJ`sDxz3&dDCQlfj zs=ST(^Sgt2zohx=cL$5B)X|{U*Y@*{x-k~_`py4mh-8sWn*aZdV&|@(3sf4;oi)X2=IfCl8#4U0B7CbD&G0@v!-HBSTscb{g`hTNrW@ z{7LBDAl)dAybeALb*6FWk3qR!V98(CvgBDzzL!Dw;ek`ci!AwVJxi9XV@cR!EO~Vk zOFn)MZL*#vKIpc9sz7T%e?{2YDwZUGpWn!m8?Zk)j3YxvaAYph$OO^69)pd9d>Dkk z{47geM_$(bu zh&=uZ-P0(~y}-{S&M@FNz>84kI@sO;qUE3z2fXhomTW{=CdxSlo$)3Z8S$h@en2g_#~(c;eSKeeO8YA7GX5rh50I{_*@@M`aO4vDf96__ECa0oJq%LP!sadA!;x(8C(D0H z^Tmz7;NCp{-{K#S#CV4z?3>;stg|ygXS08;@3ooHr0Vxs326guK^i{LdHBM!sB z`UgVZ21V{bU3cO6KlsUa)O!6!M4k4cjQd~@S`8}vGwjfom)=7#`z+Zrv(G2-3ZtOid zks(D>7;-+HAv?1fQg}B*KE_4)`F9zz9G3hBb0Qn0y^kaJf@(ltf;vDq zK(|2eF6KxhXbi?TLzIu+Oc~Z)4OoCv*LfO7iRyZBFTV&IsyFELWYrJ=d>AM+_@nP* z{QL9o7Wj7y{JRDI-2(q^fq%Eazgyt{uPwlJUd3(_pUzeLDZ@L?uTtJ4EvTpbrnC(^ zTguM_x#cxgeqXV>DMd94?%Kg?C7= zDCvmOnxLNU*6}`_RIbQBO5MS9M=0t3C>>PN`B4f4?e+xuRi(V0lBmS%lr|{&{va(^ z;{PaZQ1q9B^}Ht86#EY8mJ)tNs#MYyrOS%`qGVI@yC{7Z%=cl%?t=7*(oX-B_A2@d zl2hSdOJ1cM=cUbx-Fc~Ak-wGxQ_1&RX_sR6jr5)p{~KwflFtRHpJI1G8XT0rQ25u< zhf4XsmaZ!0`daFz=+8?ZDCwP-nuGal49cOw{1*gyof7}NbW6$iy!2`?-S>m(zNy&x zrKw7J&P!7jy)qTP|=@}1}XWSk>)DpIxBsmgkP3Y6#2CDQ;?qt z#(P=G|BN(7;isgHO86;hnH{J8XxqCYN~f_7?uv zap`d-yfxTg$AkTTEI7W7NpqC?9+Mtb_yy@Mr956KOUeIl(ql@y{Y}y<{A=k&h5My^ zCEag>ec!3sg$AQ^Qn}k@Xw@jCH`m9UlsdLrQa&?Kb52)|56FRAlVdtRJx+n z@2}ENO8k!{O)po%KbBrs!oQSqmG=EodR)`hD;LQ)J_%N`iRK-Vuv&vNL1s2Oy+zLGK5f%G^JJ+iC zBJk$NRV)I36vQ&cPpEnlNyxS;73+b$PpQ}lOrBG*iRxceu^IULdKKG%tGB7x4!q$_ z6{i6kJ5}re&XQD|1-wXBaSm_=yH077MZoX(SFsCt{|FTez{}|<1H0Z$@X(zqwgLP9sA4t9N_L26)ysQ|05N< zsQy1yEC6S;sn`R2@SiHK0CvP}Q2MSC_(YkrrIw% zfOFDS`#r$VWvlog@YJ~~J`8*?h>ueITUGA`F3wYNEASk*iv7Udg(|)Xym^(1Mc@-2 z70bY1l&P3Lk2gN5VmZ*&4a-98LItZU~`U&k5ZevRO|)5 zf2V5S3jF5IT(q>5$WZ_3nk=u2+3kE@uzC$Qm9YFs05`DRsb z0@lBzVl(izAhrQ7+O6vCz;89HI1RYsFDiBbYd%zQ7PSxJ9N^X?s(ul0^+zgp0e63* zVgcCmsfsXD8-JtXR$%+b!S<&%L3|PToujH=1pXpVwU>e4 z%2zQNgm(A;RN3}l+Jdmhu;sx#w zj+s_!U;ebxr+#38Utct%DC_`Nv>5-t*Ka@lAHk6QM}&34454Q~Cwy4+<2A0T-~M&r z+NzNKToxmcxE`;-S7#2~Lz=5&@vkla;mIroX=dpi#Kw8KSq6bkH@I-Z5(xw_pU)G& z8m3Xg4yUsY8cM?|5ys966>2Tji>Q4q(xdV#mg<~d`Rse|9zrVr<%gXeDHvV)q12w1 z=bo&4XAz4bhY{|XZE)N(ufO9rIDsaICr;Muz;~Rlr@cFN#v+5z-x}rUpU~lD5*V*0 z>8EymQg(KfBYVzv*c0&sxsoU1XL1#PsXY_A?|fk+Vg!DU)nOWW!SM>h_Q>n--6XH) zTia*MinTa%CeC)us#z4U4sj0g&KIU<4{;9iMhdCfLmbDK8~xjz{k(_yaQ`IO3~}nc zX_Py*IB)tUWJeYaadvxW@xO6ueD&7P7a5TU<4?-|e9_R6RtG@|iMUC2@Z)CbU0Hl0 zzH^js7e5ww?5zH-v2zn=MYs~P5>b22;VNf$t7h7}JbCr|bffj`jCY(y-^lQ{$e6if zT`TyQn9*6I=h|FktkyeB(7H4!8oOrdjWbnyEZH%$B7`5JBV5J&H_>nN0*@DXm?wEw zJaV(A9i3nr7!vGP3{?`qOKb6ZyzB>p+Rwm;A)LOIWC9PT7<)MSKL@mLH-qXyuYjHd zA%vv0a-4Ug&SpB(V-{{0$#7+vt#ZsKr2_ufEb^bpGTG zh9az|-F|>rL;N4#|Hb`pJ423h9Sj%JTIc-9N6hwSdR~sbnE~SB>1i+P`MGUb4kOMK z$o6GBIg#UzMRWe}`@>}7VC?nI8@>_oVOI#pWEk2k;s~NQHC`0&*bb`3|8le92)0(w zq=neVw4S?2L``VFDAO^dN}<>Hz8>dWwud zMvkILphyk{sZK zs78kn%hzWbo2kt~*l0um-Qp(Z~}tHzc}ZO z4m}&~T4D;%B9U&}*Uv{p4sD&fW;Hn77<96Q3@Sgd4u!!g8nS zS*O-FL|7s$FzJ(LLgRLE0`g$jncj5j6q^Q)D3XSj$tt+_W(;{g)uuxNNj zy#JIj+v+lAyFuGQ7eLlL$e`_@3m|JgWYBid1(4MZ8MGaA!Hu46!HggSHgQopJ5g!>bO zVYAz6jDkk|=mwLD|J!XeWt#+6oYJ;^$RX#Crw3=p2_}KDuwwYl!Ty1FB~@%`GSr9t zoa^7(3`(xww&}AXX3=td-$sxhV@>gB#er>+I29)q{r7e2)8rp@9Qg?SSPps7w;aj9 z9591wzj&H3$QA2C3vCnp2Y==h2O?%iWDgP|X2%Ev@jXCzv~h67s>Um(3(?&5$IEr8 zZyCtufi=wL1vTuZklBnVwmpG1relTnA00n5pTUEx@&C^2m!~um>-zjk*=#r3wc>ki z4F2!gbHI9+UBJO--Z1fvuNbpdeE&3K#_2FU%*et1VcA24Q2zyCm{aQ=b(zz;g|NnL zLVe~)A)*mmZl6|+Y#WrV;Z1^8tUhfQ!o?q22V}!XJI?#a*mFMP+yuee7=yXJ2o}CG zz0wl&LA#fp`VzQBloQCbVr7E|WluwSJs<}t3q;>1XL0TWlN?Rg=$4^qtKN2^n0m!m z_ZaZM`n!4p(gQdpE+FLv3=Lsh`)@fG-LE0y)gxD!(8w*uhE;cc9v!~roJ`hza77zd zmys;A%EZWCCkqxt&(1hzTAVR($VgM@=5z8lZxqZam}e1A$t1^}^{#2Mps)M*3LE~V zJoGRl_O$97La#smAXA4vDAT1h7<5Tt*B>vfG3b)nI=yw1fo$aJ?&Guh-(vi=x26bY zVUlo`#;xV*$o0oPG+y}i#~)%4OJ~=mR2q;*vTnkE7&aN$T1{P6mYc^RB;u#7p?nf);^Z1yTQK!Z>IJ&Yp4i!fW7nyvUKeKxH60{M?kIoUg z_GrYvpoCg+{b{ZE@M$xA$3x2Z+_tWE{ecI0>>)*MD?KF-`$dtwH}oZrNC$K{xp5$D zN4G87M@E_Xh>j3uIsdL4l0#n9in(V=Jw1`{jcyI!+8D=^twd}-=N7IGU3P6CXTeJ8 zb}^G=`0yU0tr4o{+C)x2GsE#y8uzMmbZg>18&A)?x))`V8=brEdIM*Zq~TmJaYhKvGP?umJ=3b;X$=PSjPuj8L*h@9J8h?@ znhDN+2tf%=`>xfr>|GKvr{%zk@%-)zoO6+~+cVWd#3ASQ3U0xf(Obr4N*OQIyy;5E zi7|hux}daWM(f*db0zVUk!HI4sG@z%Se?Rp&yng6uMK3`D+>p#hfi4&u|#{!q|g3h zsMT>idcEsNO;r`w8NTpH6^S+4ZI z`M`*~7)t~X{~fClH{B$$dW#N{Mttrjo5=7+pYAfz4D75d2=Us5*v`s4?6t+mZ;s_} zYKEW85H*?@zcvw8ouuGI2ct=AAtMiIBTw3e89`g&W`=0i=>6lH>_Qx`MSI8&jrhCw zXuHbI)K|wfaoLgZ|2Wx8oKMfFRmv5DJzxaRi6gObt`zJEnUv@Xb9|TAurFQ+Z*<5O zJChvm3in&$Lw!{u!=yIm4qsfs$xH%?zv-L8Q~T&f68BG^IsSXPl6Xn{SuakSghg9> zMw1OYMaEu9=-Ds&CYuZU#8h_dUwv5HEe_dgmYXLYh=RvDE^o`>D!Lk(odIcofN9Y1 zQ<|!q?(ieNK*T4$GBy4nkVMI6@UIYd2+S4>_MckuPp4>a%{F+3<)N%&m57sgDUdk}D`aav_FM^^ zFB5BgnE3rEtFRrX5%!PQv}&lA%fzXH?{f+LeU8}|iY+*etIiqf%P$T|smpU0(-V54 zU5ee)ld>n@RahJ&bQC2EX;~j%;S4yY_3ZXy)Tho}jJ-$Qb|EE;t-BzQF=Uv`vVC%LoZ{oSSexDNY#k1R2XgctMXx)VsqhVn!KFG65 zNcGt(f;EfOy?7D-HY8S^y;7uAQW}v(<2`cL_fr>5q__SHTIhTHbo`8Z zx>DH}j)YIig1>zLR0sM5bR87+GNf#%5T{n%j+{+n^u&# zz#-?jmhZ@9Y+QPFVT~0u(qGE`QaOO#KSV@?7*swsoAy+U!1yWO^$hiFBvJOUexA!d@+){GAne%&6*qAgjpHy%3s%V;&WZNH(?{< z-zq1+J6;Y+^ve3mbyZ0?nTUwyGjTYr$bnvcOm3FHw(C1sayp&r5ErKgmCAaYIm*<% zD}U$O$1nFUn!URwQrO9}{@R+2e2l3{9%!B~Tg)W>Cm)TmTZn#S$S`&zx9Jd89?qLs zy;~lbWAbxbX3y4lXow+w^3EBuF;Q0XN%U=8ULHci;6#|gVuB|gDfM`5vxOHat#Vv&Mz;qWD< zeO*_tElh8gzcV-Ny)XJ*`5SwK33aeD4LfC{@ztRwe$q}BDX{YAJoBR3#wMlBpZCS_ z3zV_3^vvJUQu}IlbcB=elzLp%Ms$3~?5koedt5!zw*jPXr<&90tYt@sfzb4Oq_)5; z(cw<-bd)JIou)^a9&ZSJ89-f=(r8_i;&?qy(M-m;NjFf&=-`a{b3%*ds$)GkJi&O0A*nQ(P zv6=Z3E%QX8r{fho6n?PB;opYUh7q@S1xJrl+m?oVeRLFuotftUqd=_t9^8!i8po%U z(lXN$m!Wm_$*$!L&M4O>mp&4oy-uuTkA*g1{vK>PAGwrA5aV*Y6sC%`hIe2UoE zv(y95!Y+itZ2a+*PMKM+VD`N=Uza%Ct4~b!GKrj*T1^PN;8*=h$Z;wkzD2(i0#Euk z%a6yBc!yYpc$=9M@+*-V(S2$))hAh-re?dA$E>W+^rPqNlU{e4j-8PAB$0$A-n}&^ z3omRr}1sc7UXYB?rKuf4u-Fl;h{!RTLX6f zU2W7FwhJPZ`p(8E>8oYai;)UH8W3HLDxwd0hn+%Woa2rkQ&6?k1 z7xhzggK2x!?_Cazp0hVJe;OmR5jX|ULeDPy_!iFbwol@z_t-P^UEm(+(5)9`eeAr; z1}oR;aYvoDuplcLrA zYZ}(v$Fb&SH+s?TJ<_`Y65HE1iES62Ckc1?Hp}tJF^z5^a*8%V-*!SC%Gw&aikL=5 z9C(9{1RB0gz{(Pt5VT@iJCj(9or_8LnK&_5#=PAJD+^tHERFd}uhh46rtHQ#8j!ed zs^2A;`D3PCu3a^8{PF1BRrG9heIN(p!I(_voiQ2y13nP*J}IsFgdDDD!;{mR;s4-` z=njCUcBbou+?lijr3y=;>&8}RxEH&E*oNp6GO?WATj$g$R{%!r<||vMPxKrJ=Skdn zZ`N{ROIG#=Bw-vl-7my@eR4Nu)oAa)yZ(+H$c{{SCHRlw$I6slN$-w><~hOi(_ZX5 z@|Gxh;};bEWxgKdo6*v{H&M%OhQEJ2DIk4_t2FAZG5?#rGD)hH*TjaU9|pSIxLBt> ziTzP5&eV2O4GoVH4gH69c%YGTuiP8ARfq}WQt)x$4_irRWlX4!%NAw=-IYRanh zlN=2xE z`!qaKfzlTRNtJ#sUf1fCvmhVFw^uf?6@J#j;1tKD-8%(bmlHOLwe(22IL#8*mR(01 zH_O`OT|#yvuCt99*`KD@?B$Ze9H-N9^=_xv-p%+OfYa$)_EzJLNmOM@<-4-Ro?H#B zebe5pPS$%u9%+ehJcX4z#7Iw}ALvc4rXd=H%u&iYC-yWA#k#)Lc_*|vN@;VF;{3ZX zQb*=T4cqP7T{C1v&EB0=4>aoHw5=zU8hnKBJN)6v;Zt_Gc317J(Zw0tb_@DR(G{%~ zHGB0byIni01~+Y^yB+_wj)C0iy<439;CW4~8FM145o>}d2k6>~(>+B^fS3ovuZ1Sz zymyr1?xYPEiF6F#jjr{i?Oi^g0(OeUH-c63yd)QR%s;*(W8UiD$6tZ6VkJ z&^o-?L;MjqjUAVnzMf`f-%*5fz~MJ6`NXPSj(vare>T<1k0tGc57`j81>fpUWVXW~ z7Jao@egd_AEN_EcnMc=%T6md9Z*7pD$XiZAPGScyUcucSy*T((?0J%S=P7s51HxcY z6Jo;bsfdijI-?iAJ43$*ouRY5B8iqa>5RJwCyWYgtW(tBo<4s4q9@W%uLIQZ62wSC zoKKaQ@@aQbv|v#zkt*i1L%dRXMW;jlOsrn~4_Gm{?=iDyoKAm|dJF13=t!d@cIB-d zy3ms}?KMg8AxSZfxCa31aXpu`be;&x*bXH9yD^&`2{ zPUGptC(i67uJB8I83vUtMc^ zq`!B=Z{%g%HO?^_Wx{?@{Gly`$Bh7_z9I4k&TvJ`C%KD;Enl*Hm}8JAYU!RsFLs}e zgm2M120M-d)XCH|eg1h#R1pg)vQcG)C-b z%-GRP^`VT|vrO~#uHu|%_=>LKsdRP6byskwbIiJ;Avhwrgwe{5&Xydl*sOqeuvr$s z@7KrHIzx_GR%{X$RM7Fx#Yg%Gb_BKsz4gC`)_*>2ol!~~)!xL8Y_y$+cg1zw=QYLy zG1`77=$_#F*fYv6Lo}GS*6=@7r*Cx*Y=Mum;95$#!xWH?9a=cl;AP{n^W=!v(6kO` zqDS3iuO8b=`~eHSGG*ezTcXpgmsz$Fei-+--(O!;Uqr;RLp4PlUtKhWuIqU6O!p{H z?%_7|-^y+@Zn*>ZV9v^E+n7xaJW0S#cg!1&&kM7KQNOzWa~2Owu5&WSDuwC(XKRep zj498%o~_F9bH&aT9Ip2(OtsF@EpK)h^+&Gg^#}QF!i)@7+}n-2Jhu5>ckz?L4<PJRzR)W3AaHsR0Cw3g|ZC#?8< zx0X+9LaNy7DEotXtoZi(^KqhVCH6P#Zjgrf>b)5)F7is!(XuZ0Q0tU}aO;`^jrFf`c;$50W3KmIhYIL#AJO}X zw4GlN8j;5#VdI|AI$}M9I~@POlgCQz3?u6L)%CB_7W2i9tN*NeREP|Z*ktf-+WYLx zh)vpK5p~0PeO-wdp}TP2z(+LT*=8=+Mn*@xq<^XP{O%58*y5RKEp>dpum<-h>2-R8 z>FesGVIN+bJ%C9*W;zzr6^*oy4lo=MFt+K;N9s54LVla&6 zqx@@D92B;q?hE-Lyta-NE4#D}q>)tT&)T!jAS{s0uIY_OU`yj)JfnM+jGpA*{>%c| zYW)4WgNnDS>C)A+;=-~3Hs!%u3u?t^pm$%g*MP%%Od{JhI8^;wIOxBjHc^vK4EL|@lDs)KQY@I(n^10 z=d> z_w8r!p2YN1J%JYsE6J_sYC`9g|4Iz8@lGWLuCuzyksYx$Mj*8`?(0Qye8ld9nH)wD zp5}>9w(9uL_$1U0*AO#88bZUO;P1k{{dY5U{dTi;4CWH9({YA4p3U#!>U4hN?uBxA z1h?t=i=l*C&~z5?2^c?q$4*LyP}8& zB7W7T_hY=8$+&?nDZG{6T7?t0>-sn1Sz(=iOHxxTPp$P^Sx&5qX<$>ip_VzC#zH2YRmKYXc8b>fKZ-_oIwtU!iK9A? zNo4Rg3-Nm^s>>USiTN0wUq6Et1}i1%x#tFh)9Ojwkrkn5*As-0fd=Gc-E{XQrEl)7T-`XWAPt6umaYUG!ZZlj6=}{TFcO=t4d{IbU5T zqzOWj8b!599q*!tdvZcizCdA7)TwRxG%oZ{(^8 z-le&)PQzRLyHT#)`F~UHU1_~^X0Se{VarUTmsl^XODWp1;)ng< z7v__V^j#ba+H+aA-$iWUxJMVT6Z0Vd7H6dI$cj3=8}<}>GSqJ^=B`v~7vh})#vaua z@0y>_`S&=lou>9{n?0Gv15?C1x~GVvx+jZF&lJ&zr+bsd_i*oKhPdX&E$I$C)1p_M zJyKc|{gn$HkCkKOblmMIUyn8|8jN?G#(Oynen%t@a$K#h%f}{gUM?ZZJ0xoW^(bkk zEV}07*GJN*M9JDm#u2Akfos-|Sl$ReqN7y~AJQrtk=npXt@6-NQX2++R7Y4Ao{wJZ z-@&A6#{Wb1q`cyM|G4^Wa|NC=tN}d@`s2`QQV;G0(YZZ>Cs!Cf>FCGR&s2V)jpy2G zZ}hX1gqf%ANc>G(>{|C)O~(NI{vu;NZmOR-;rN9$Z?1tKwq#vpxUJ4)-_R^gM-;)07ae-@u?vq;FU=&3@?|EDXxl6&+BeH%&5G}KZHYoI8h4|6ZB!Fhz3Ids&xa>#u6)QY#66dduwuq< zU;C=_`_t~V>(OiOaykPEaS9>X#sjnSH2e$~vCy}12FlhNCdFE1Y^Lwc;8|>qmM?D1 zz^d;qisjQ?T0HAvMFw{d-FXQ$%#;M&-$_$!>Als=mH3Se_=c>e3u~j`A8>yPBai+b zrk3|KF0EMFl-sy$rI~+YCGIj?4`!P2+@6LX3XI2ZM#%I&52XG0ZNK!U?Q2sSt!u5g zI#lnMY`~oydT%=fJHHod*v1y)e%Vk-Mh*1a`SUgT@CtuFTgBHSS9pSJMu{1p)@TPN z7Di0MFDM4a<2f&$z8`XacN+J3{n&MAx39G#k0|63knYC4Tza3_Su-`x)-pAg<2O3T zw&?NOQ1w-wOlCFpkJ@Yk-=y(BQ&VYrhCZ<|k~rDt$)s~#4deXJJj2-4kQ)e5*K+#- zj(@K)B1mJc1Cba&PhYI$}Mt&faX~?ZIcz z;sH&?xOp5u{dbIguxJjEdKyGX_cXZW!Pn&S51jg<;! z{CoEg5HtGAzAzW{GGeotAI6WZU{daoHHU{HB-}ex)Zj|MK2_@eM2jAT`81uHln70j&xmK5ynH?ljOjAJBHZn6Rkeq1C9X8;#xgjsYS+;2x%H!tE|5+ z=OwKQ`!lj>u3ztPLR$}`l}2p$bZ&Yk>QT_Nt8>k1>Lmj`hp+Rwy3?v9E+;s2MtAxz zpf~Pno-u7zuyj|s@Z*LG?2{2euS~fEJ8 zX-YCPMb|~o;+BjCQa8|3qCAb8rVd8u79f=UI(^N~6c%0x76>l`Ls28v3D?tzD=U3< zTp6A!{Zf(Oc&Xisf&tuxBaweuc!E)V@O+7*P69=d4qxk}WwYNaPYW<0yOF)F>b ziCdaOCSGP5JKGV@QtV#II~=xzfY)XW7;UiuNWLGB#*xX>(e(@3z`<+GmLWO{K4%gA z7hetJ@D5WdcEiD)d_wzHK>nHg300SDYJS2n(w87P@>Icb>=&aeM;~$P#Mk4-u@=eU zTyR;v;EmB=jQ($TKyEN!c6UN^>G#VwxOaNaYGYed*e^_nJpb_gepRuf$g|9`%7Ha{ zr_r~d*E@a#G$eKw?SQO2$rCTJajIU&^aY@{s-^|KOg_z?<=P7Qgb};)LMrdNyu(!? ze`q8g)pdFP$_n|E5&JQ1!5o%fA!i%)K0LKn$QS6Um)R1K>y3EAC%TQN8{~R>w6{Ut z<VMiyCCXXhfd~`kX~c1p)bEvv*^XV|+6H`u7?S%4Z$NY}>F*wlEGqo1HtB zb5u6I>%0bz(Rdm(j`W6Hh{rMBZ&1cNwIryd4O+g@qIcATP0x6$A2gFVb*h zcDG}8uL#JWdSBX@1nDceB%x3pYE1y=R8w=Zy!P{|Fk~${brt zRETobAa77g+wR+`l=gFTK(1hhmp6d&ZbW%kJ^i1{i&)GJaN-e_m<`Yf5FF$O-W z-dF0eUS`=S*Ey}B)l~$|Kj`hGx?M%7o}^yp>7=I7Zqgjt>4ud8<_05n7(|X~7vJ>N z0XBnbnhPF7`7Giw)cm7G?>eJ`lMBwF#@^XD-SK}Z({Hy5pJ5CZ;LWGYG8_jsE>1z1 zW#x?-4!!jp=nx!3Z(y_8IZ;Xr1I0=IbAX;vo(>{+?j(kQ=a4c58d}57rBHlQzvbahK_^$1EVPY^DZ`8O? z#kv^lW9Jw=@yfqMOkVkwF({GkM0~ae0HCov~)@2nW(I{v2^^Ty}p-rlT&Io%^xe zW^ei?Z9^toZrbaKUCPeb>rUIS$8^q3Ur~7a?q9#*fJ-vsJy=)D3O_`3ie6@q_Ju>Q zH_`fP_6ap)nZIIIL5{H07w+l1s=`jEt$0Gn^dI`wB0HWJ4;2!}($>cUl?{h3gjwJO zy}{{9xQNDEICSzQvG|Ze3CI^eeT_O&`LCtFUmt8x;( zjF?!4XW*Lln^ysAoZZ9;s2L{LccT1=lWS|-!2l~=k@CL0%*=?5I}on;e^bIHZ1diA z(6d%Es z=tZBWQN$-oX@>R4#t-v^3vMgG-PjoGQXOG^a?q;Kw%ae+a zqwgP=b1N_+F0)a;Us&s@EpGuDO)qHofsMIBDr|AZGa(8|K(MeisM>N?Y{3qe4jPJ%j zrr(+L2)*B~+xNMRZwLBsR#&p%&(y&Cn5gTJSNw`8!PqGB@#QL;woTP-W}aU>(DT^U z637aE#e_p&+|W^8jOtoYuLbpmS-6CLW>I+HqZ#1oN7lRUZ=dIq2&ld#4ucF7Z$xtC&JHqTv% zv-}3pkYA(yW`cI?F9t1v{tDw_rWl&;22XkY*_f)|z+~rz6snDFquIOOKu?LObxPh9 zF_ke#jyhYK*edpQrZPuZfo#mH#wibs}vuVQh;Q z{OKDC6Z0lJ_id*Nt>j%9Qx#Klq&)WMe2JOwl2v2S>ky}NFwU3zPsl6K<2Tq_Wk*G; zyueF2WoO>WC#8m*Ld$-9{RfRNqx*5J&*e5)^;J4p&A>}BH zO2$k|OB*WUqsGWgX~3$c0krXeJqn{S+5swaNGCdJ-?|<806-G7A=4 z6f`#1Xtb@4>yuc+|>;r%Ff$%s^q;85y5+k99*WHb-J8e#(=TqpY za3gCy>L8u}#TZ%48`z~CyE?L#gg#A=4fVlPM&5)&pAAg7%&6I!pelh=C&u{VAz_TlyT(04)}K9C_zohkqlGcMr%TUQmwb>?BM34RH5NCkAkn@?9mBYxI}R9gAvk)4Gub2oIMYlRVQvzEU7$gHLB z;GYQeedf}-NBF9lblorm*Id;My7o?Adf*YQ$V@mSaIYT~_}32$)1b{lEfS-&NF)!D z7FpOy_Mg-yyhv9{4wQDJy6x?vuj264Dve=SJ7#ujFGumm9Fg3s#mF7Lt%B4IW6^Q- z5q#a+#n+Yka{HpM>Mlp=aE68z_g04Rt|Pin)f16)Lj$cTBAsTM7Ghp`0RM;acjI4x zf6LE#M#TBA_!GuR)JP{y?_kn2$g@uR(FNjT!y!N9*mQ60S_}l;DawYDvW{T;e#+QSlx~k;-y0_ z(nz8ivs%CmR>8iG-F?Gs#hsXkQ*sNJ7P$qwAhx$GB-GR5;U#yBoZy@k)VzgPp+t!U4LwLU3KLwlc4? zZ;}nFN+|Qca%l(Sutwf>K_h_j#@EgE*DZK#f$RF4*0-HvJM>sEpG8`l+OcMku8c>T!d@6>#R%H50lGz-6z89VjL@6u6G2_LC_qPXcwXmE_+xWufv&{FdC zlP>V)0NvN{s+Ne9EF9VszEh9GbMVXCF-Fo4xBn*^{_b}|UIwBTcFlFm{szxZVq}IxroJ;J?8LWW@8?tYF@NmewEh~zJo$Fc zBBSCNlw-ay*X_Ej(MGuHxsW}FLs5PC1zOh-og7|g(cg(-W!ro~>&{gA#mBdZgJq?} z3+Uw!M|yb7u(}^!qu;bqKZvxg0sVFwa+2e82HAVR4&E!?<*D^Y+DzZ|^)Sx$^V?rV z@}Jbkc`U>7PIeaI(9s)|`&mwdBEK0b#qhpz=v(nfIi(9giyF%bY~oSIjj?C;OJ?%guiagpQ}yczmTOcj4fbvQ@3)#Jae zKE&6kYE9N3x^DGczpnOAajR<)4qOL#kChbeLsM1%wVqo&2d{HVScCOe&zINDf~H1W ztCNz>bJcoS@{=S`C!J8*@U)^YeXuFA+6afbK}psBmdlMFR$HI1*Gj7|!iR~K5gNxHjnEnI zd6LRtAeyo*# zdU1IF(@Oum&{M*u#rN?&95gJF2m20<#!Mx@#fxZVRk{&YsAy$cQ{@BA`P|4{*}(?o z7A9?D89Y_EH&!p&0iL=BJ$oO@pp{NvVA3LES#zE{>=pPUl&{zu+&j!f{*91tE<$At zu7~oF+u0a(95^|eA%}WwHsZ;BY{wUa( z?gjGo9FVX5PD7gsx@P-ivrj$fAHjH9b^D6!-j{(!K8QbL<*089ncd_u{o}FhSW{zcl$}>;1kX5Cx=hcI(_%X z2%r2EjVwDem}g$evt#3-MbO{C%7{i)LYG%q1pR_J&>fnKzPmHbNUUar$V>(1${C;= zmq^n4NuZ9C@+5|({#^{62@aTy*Fs+u%aIbz{f{M5^sG<@33>{sr4v!`niCG)PbmQl zBk5=H2@Rg~h1+}#?5x6}IfI^nNSleB@%Kj6l%60v9zMAsy$FZ8!u3wrvO@=)YKE*? zcEg$lR=&k1AAj3R$ab`2J^s{p$;Ze)k?S8r|3mIG`^b|6)##t0vjLu~M3LnpEXj6g z&B3J40wNL)eHs4A#;5*myAQ9!;!Z8Xc7#{?Nb@@!Y8l|+A;m#jEi>eD@RQKiY>x|`7DxXyFw%G*S|9n%#xp0V7yAJIkJvsHN? z35hwO%L4t#q4-qay1UhBg%<6zowt6U(;#TtXq9XM_NbLwI?x-<_n`cddF+jFl9l3o#zH;xGsQAOh1i!s>JO_? zTrI?vDviaJqsy2EeSGmN<(*@3< zkU?0uK4dooEq`ns?(J3H_`ulG?UUahpg(*V6=it)kuT4`-(I{XI^>fyNls}+d4f`!7O+{H_l8nYk#K_Vy<=U?p8El%`Bdr}>| zh@)%#WnN`*FqKSNvBiqIzjQtoSgH={=7}eg1ZP21W?WZ>kIhgAxQwXaE(<4?K%%!D z7S>D}g%1FKL;39r<^%nFtyGGf6SW{zBOLk|mVtCf+)p^v8fGkNg$qo?-5t=xH>xic$aPw*&WJCX6W# zf@%{lmx%QM)x!&2u#EsM7qiZ@JXY)^k39i>FyQFW;Vdm+Ce$)2#q&&VD}9#}g zTe3`AO$&SXb!f5DvllNCRy$<`y;-frs{igDv?NJ#Gr|XCtvvi%?4uTb3oX2e>LF*Suhee77jNm^->CKX zX{F`um=D!+#0ft0V2|QOPPw9S4RPcRQY6$hVAY5z^*$nS)- zBBWzNwD|YNp&W{v!)TpR?ZgSN6As96N{w--v4=aq-dOZ6T&oJaP8Mbx~IlF8lHUqYrx^(Cu*hFVbc$bEw6SebM<8}<^uFd#?mT(UZIsncVa%q z+Z|qhDi3=J>dScpEwVk!DyjI7ab|&)(OK25nrdi@vFbsGW32pCdX@*h0fd-pg|?Cs z7GV|!QL|9(&+GkavkSQcg6q{vhudiWi*3v6{StPqD}aoaf%hd!I}{GQf7{#wU~-^8 zdAMs!n|Zx2IB6DtW;uAv8y_98b@*-BThHxW|9duYTv=H*H8u$N`-DSe8U#_^@!Kck$_e7|&~a{uHR z<$UHz(r}&a!2DYmS)+tQsr?l`NHWrBbvY2~=-;W0f*qqSjYG}`Lg%plA^vJ0r23Vj zxdnZ0LO4^A(|6%Xfwc0i3cb}z$7>i%-u3V%;zl;tL@?1QOJ6G=0UiB4dt#;;gjdP# z)GKslZ`(o|)7E3xnxE!7U^CA%X$En`v^iatTupZ@tFiQj9)VOUE2x20ESqL3SwsFE zEREOLJYBGQ%+=8qPHUTK>zb{q9D44!u3>gMlY{l;G!H}tV$)AzzTjXrqqA$oxY^0+ zhV~{CmvcS&!_ldkOs76*bElfiF?$eijvfbXFS+z-@UV1_=rJ@OdkOSdg?WiR6f5+F zCJnIF#n33LPgP&>GFgHOd5jtW|2bVZ8NN}>gf$aYA<`xaZf2QgKG1;2-GN)HQ4i2i$Mu`HTIENw(y`9{4bF3fR@svlEv*NQCJP0o ziS%qq2bby<>l)XK_rKI&^QeRlSb#G-c=!)wq?=wARCyGrvWV7izS;|&0$7IQ%~da3 z!yk#wG7HgC!v(g6J7UTrP9j=5jJq8Iy$OdVh1nXfU{bEr!pyX!Cf!74A|Zs-8Y(?z zL&ds-?l|&JqGM|wSRgEj%~E8^Gf@`Qe)cW4=Cd-=_Vff{0iH$vImiO{zN}lJ3pWUn zeBWyTH9X|Kcu6DOqkaGV`R~8~{j87)-Bxw zssqdvhqM=^QCV2js41%tRsw9b#-g*k7WajEK^KNXpC9-h+L*10mWnR0kkAhQ=8Kz5 zx+h@s)M=k+xnqz1@L>3r2)`gYK_VQeTy&GOI}1OOIstW9*@a zZGMs+bw#6#4V+x<_6F@bxh@Boa`5TN%TB%0H_nosH z{&`1;pFhIRQ%yFa>?(=ZMn}VgX&E$VRT`1boQhMTWkN|DkczppY`fg+zAIds@gL9WNKIfsPEFs2s{Dx}T{iCCC z*4VF@qHxxk8?HI>k{1}7j^Bu~GuD8q7`&FN@U8Ni?JB8R^{$?oygI-`+k8y{llfqv zLe5EJGMC}J%e=>V-&t6(HtunHaVG@V7BtK0Sy+uj1HD3?o@GTX;f>vkYkUWL`RM^y zA$?i1y>t6I*B&R=$!62H74WH)a13vZwcGbO$DCc`sq-MNv}Sp77R3>bSZlW9y<@rS zWoL9SAg9OUY1(22q2dGb)~- zSvE?TAjFEZWbS{DFVqAvZ$>znxW%#fjUUrE96bw9n8xJElk2gps|}pxJ9BL8i!e>z_?mu zM|?H3wwVrS;l;;;nj5A1HpcoMLcWJEMzraR4XUFIR#O@)TSd4kd8bK)J!dmKqAk0T zhIJEfxdhw8@g0x(W4aSz3(14_f7EC8UxJ+%Z?Q9h`N>`8<<%#zNY+CUKOHFQ`!`wekh$HQJWM-sY!Of&H>Ei=Dd*N4@|nQh2rj zzqEy4rvY^kudy?Z-!MYY_m3U1=$qD^@O*gUH_!@UrmP9FX(TQAI80}=5GU=!`Y2BF zD924*?n3D4A&&pK28~13gq&z@eJsDVoUyDg{c7ENvctR!{dku=J#Cl#BF?+u z{Kw%xHm%;oWix5s%zC-ZD1#0=vUbTY8Q+t2@$mM7e{}rEvH@o!{_*%H#7C@~ItEZ% z#n2K!>MvZQ8idZFG@E}9SF=w)EsbVKt}eR*@;rFpN%6$O3s17=E+2YbS^|zjT9ofm z4-3u5$;;vI2D9puZK`Y4#XRi1Z}!MNO!{L1X38T0PwGR#)k;lIvL_epKe zx?ofCVQ0p<1jz_{^5XU8pcB?3$?NvZFWObtYKzJ9$cy&<@)*!{lsM~VPv|<@AfBD` zJ9x1%#xFj#5-3R&dit32Vfc}V&oYa!fZ3e9E>+y8P9BVZiQ4iV=TACXQ1Z3#14E^T?kY-+@r6=99x3%EDm6!*>}`(* zBPC~1@@**jL-0SaGO#sud7vKtw;X!1gI_3Kf*0la0lq|Kn;b0l^dz5h-gU01{Jh58 zqOBK3&*=K4Sn4of*t8tSeuu&2Ig^XR4TASXfZ!X@vF5 zq;s}yD%;4Q&T892EuiFc4x2;m@S>gC!go7A4-e)i2Dyk1!lO36`1h&*0oqeCG$=xO zq^~g@TGLEb0QrDEo^2$a*ozC=m^$iHk4LnagUmEWnzw^StgV8$@{xg```Tg0Q4N2j zgX1y(ceqFEX6d@av)Q>vgva~J;O{FnYw`@B*3)JMJ~&2Sj8Mt(a))Q*{e#(5Hs_%+o=p4t^ld(NE*t^!W<_?zZCI5rsQ@$E} z%h~inm6h7;h)|AuYPHET4C1U~Q;*Smoh=Q0iM_W`c^hsVUV>fWZ?{G&djtCVet06I zy!+95cXCc~!8|1nNdO~K&%b!)aq`PV$7fd}{$PY3LQM0>4sUg!G4L|CSB)yNb>XZ^~y0M+L#kWNlH)3upOXY#Tq{J^R=D;mz(0=O&BJCH0_M=#+6=mp+RG}TiJvVyR z7w!}iJ)CV>@XG==V>#CPjPQ^cOFDSkU- zwg2d=@Xr>~Em;_CQwO%Zf_mFLcXv-Ae3bCy-*emUqn^pLV3F^(V_dTO{KAy&H486x z)EALPHt#u@KM=YlQ=ehyf*Y{6EquR-J1&MHoe=T4#{wt8}W-M2|Dch%8R-z=P=u`bY{inKBaffJi8%>@B zRskz8sTv@$VWQ@XE)RnpGq5tU^RH4ld5MKzRjb&K(#}R{f7loBr(@+m2c`Yxt!=Nc zwfVcPuO#?f6i&3_Xx-gk$kd)o{(3$5q!;sF>?xZ*oz3a-+GkPeiOQZKvzD|UWJT)gL2#m{S`JoNm)~T zggeq3#w?$94PKKiJB1H#!!huW00ddSRE~AkmTKpyz-dtS**+6=vEKC-m2ZQu zJ|GDqc}}bKddhJJy?>K~4^}GAD!j?P3~ZFv+qpoEmT%o9p4T$nyS;pEO0OdiGHfer ztrC9U<4E{@k2jepz9ulspNQFsMUB_Mre=~auWzrk6+ZuBIym24A7NrlAjNO-??JDI zM`K-JCnYqtt(ObTL=C0>d-AT-i(Bb}Vugnn+ zz6k#$FRHp{b2cGYLFQAWe_XIbmXax?S>q&o=WL%@xE1=*03j}l*8>_6rAvW`O7k5y znrHJnQTA?~=A@7gk053CHf?;Xv=$nPTYy~5pMUia79Vhkq^5ZIi)wDX*|VXWwHt%? ziQQ|zA|LiEV>4ccRLU`*Njob)!j5(=lGt|I>x8H;H>(JKsn0=^+6#=TjOpvSa-Dqq zy=2eWYJpG8my9vuOqq*ja~!?ihhs4#Atnc7p6z;9E@Qat+{RMpKd>fG%0kWpo9v8UR@Of*V{j$Ly0I+aM$ zk>B=f#zu807Vpv@I;Wt%n6!xA!-uCx157>Way5C^F74p-XlqLVXZ?SU}p6AoP zh!=``22+%wF>wSl@_04T5BrHkVRu6US}3X}x;6*C1PnGk?BACJW5n^c`GE;GXCTq$ z3hG4{)*KzG`7Q8ncyqBB4*m3|ApWL+nKBoAE`R7oXn!9M?r~Pva4y0Q{sOD|XYvc} zmXz)6+?B4`Ip7xHJ+lEv>oIoUK+l5ESMYYG%SwQ+$g>3vu;M!_i)IEqNJ~?+JIbAi zv_|zCaoiY=0j(X$MBzAw(JFM8W|CCQB-HQJ4R+us?_uvKqQWm*;2-!FA}R*@xD7XqUZSCDls+7KWk5T2!}%)lVWB`QDopJ4+M)x; zWhb=Fo(!%ptSnEE#>X+zOWtb1ErQ!M-IyncpY3dzqzQ;+WUfw5Sukxex0_}DtUPxSVNS8E<|PJ6trv9zyT7nXiNel z$vRq?;>#&;^)f4S*4bXo7}K-k=&M_H5JyDPlhI73=SE1lVe{ntKqE%xzzk1+&*MD} z>#Td$7mRLXbDVOTd-jaO-Lv)9o&N4wag{*iNZt(@fpwfO?{b-15TY?V-3Z2l`)6ma zT74^|yGbb2n&m15PkP&Vwc|bLB1GybGP32oaOnDJ@-e9JdfM~fpr>m8gd?kM!7*7I z{07*J;&pwrf)F0_Lm$Xm4=iw?r|LS5irg&t&1EZy$KOoY;TjiXHA<)8cNqACSTEYG`_ zVN&1JQQyQJeBRj%O#@bFR=^_);XaHdzc7N4MW?Ouu;`2FY_*3Fv%2z+<;iS{_RDpU zp|r+HkDb3)gzvGodGOA6SAd(MhV`N#7vzU$S*ulu9ljyVMKcHzluimdLM#RO``>`o*G~#=)lL4L{1K!4}1K^S;m>{ z4B|}>pnn-}zxzCF0(Oa-v};8BEc@*+|LFLtD8DGmm*{51gZW?QGimvS>++E^^IGIg z6&zZ{u5KePlDNE=pg%ztF{-McfzQ#$O>eqi&`&5DnwhD9m z%kXID@KZTSUUvZ89@Xp&=qRia`g(GDxVJg$f4gmNs+0UMS9{65WFgjD8ul#p09paD zBKP(Tcrl}N0^mmVIv@!-ld+PQj`%eA*F}=v_c7dt=$Se)E7zb`{<3N+c?Ln za6fsmQs^Bfjj!$N30>u^bKSoMA4BO*3I`U-ZY_3W8A^2vg!m94W+Q~Q zj}SBN?N8yu@{=oi{o5&ow>=IIou6Leb?9I2$NTp5p^qsR2ru;J{eq~&3%yH!5#ivl zQziI?W_Z(v|J{C*kElkhbghG#k`>TTVFQLKR%jNnSfjzu@l86@`$gxe!wY*+ijuEzXghQ}c9}D==(HZe*J4%E6hk zn9UwPT4sg@7Gt-0Vgj+y@zOvBsj*}Ta%lX(FE+CVl-Mu z4!kI9y%@<1SK~z3ScEM?*va)g?(Z(Rs~B0qn)dfLru3fm-l!)uOvvOxN5H<$SK(4ZuoPc zUPXu{U5(936yvpqmjCoNO(cAC3sCXY2riFrj9DW^!ZQ;U>~l+bhenTgK+Az@lZ*iP zCawk%^R)h+udeoZE|sk*sVPg4SOXXEYPlA@=+$alP);VQu>w*{PN?-piI>XowDngQ zL8_qV6(_WstG#QAdpv}+Vh`QSgkWvi+OkvFX(_*OdGaxM?bA1|aYFaD1J>_d3PO+c zjv&3qy=Q;~=){>GX6g&QOMdYwxFBXCBWlo#ciY!4guW6ka8({` zIR>NX(Ga!DU%Y<@N05R2!fe2I;E!LX_H0AVlXeVjU6lKPH>aRYy|OhC^&JO57c^HgxgqqXK1;-t>14bUH;-C@W+!gwmDU)Zt@!6aLMDfNH}gf>U5>7+Z@vMH9FmY=c7aJq z==DDG*D@|puC!5kq>aoB+UO*7nTt0^iGM9CyWK_wuRxZwV$bTZH>CXCW zl=@D80Gf~fFb1WrR8MZXTDIxA51m%rCmWa*pjXi8M~nC9f}} zH&xD&T^j6bLF01O&7xPRME_bIYDd^+^!%bb;S=&nJ zzryiF`xK0}ZejR(;x8V6jP!m54PUKY3{U7Jds!Gf*=>$I5|0(QAV21+HQlK! zje6#$$w$5FYH*sE?|JH#(2g-XDP5aL+NoUaN+Cv?f8Km5--9uw$Xnc?x{)zw%+grs z+L)!XQ>p&mpYJJr<>HRyotMihfrG5sMty$Gmi#h!UGZ{aep#07T)UcdCY1enXTx{J z-tBwfXJn6iPx-lIcw~h>{ytAxxhiS__Qzow8?G@=tAn5ZNRu8Fh)>VP+93J9dgs)j z4o_G-u?6od%lAi>CAs$C|6b#GUvvrabfx&WH5Q+)_AD&Zlx=XtlzGd_%bs;icFlJf z5bi;LpuD4;fhSo)u+9v6ngqsTZpK$+!$JS97eSQ4O(mWHCnr?NKZ9g~JHl9Oqc`q02Zm<@N5NhB(AqXELgxshCkRsG8ZL9yi@IJh>+J#Zl!oKw$uA=hB zJ@zfWH{>*EiI;9I!j&a^slQTQXg}A@^6(vK<*{;S_W`?yES{M-OE?CP=NZC!ajvqL z0yNq{9T@DTkndSla5J6n6Z;K_XjQurybI71WWwn_I0${J2b?{(OJh$x9(dK2#>&-ofAqZWCg z)R+1eVTXY^N{AP4hj0jy{$&Q%MDk^qXOuwxkN3$|?_$qm1?2yjyo{4?xwXl>ZED+b z%rbU?q*gaWWw-8lK)x9|cx$pS`9F9-{;}umw|pRbJxc_YT@DrXMSLIM4DG_#^C7%&yVw7DJ$Vj*b;gqTCGb_mc6jWYU(YvG?4`m^a#T_u|?Jv|3DKrddX2fw`l8Uye!`;r+5Z{JO3dsZG3IzQ^lHdHyrMTAB}D+6-?)UM5QFZBt{sZ^d{&Cs!L+W7IA6X|M~n$FaQzhiI%rdsK@XnBA@N5lV1;GO2!Su#+wj=vlBrQ8OwVzzD$^nT#QUzNQf4O6 z>hK+JQ0DAoW6w9HMAbEFs}ilz#Y;=zQz>U@@qYPbyXK9&%jXQKn7^X~|67(P>GXM* zAD(@$S_ho*-k2|BV+Aj2EdM2lf~pdGMKEFZ_7FZvmZ&FVF=( zG9{GfU0yM_(UhQ$me}Zo81(^N%_~lGP1k7t!fOI;3ll-jX`g{N z;rETNVP`r_4+<|9BbWAb^3Tj{_8A=0fdsJ8ADjNKgqxl+x}%XhaMXGD9QQVJz&rXu z%<|AkL|+|ogT6{GTRXbW#KHr2fkLPTL;Tz{#tS@GL9C(``i;Fmg;LK5 zP(^kktmEK6-EsAke0_6W@8%Y&PeG;;T_PVE?36t zxPSwx+zMUpQ>Ci{>hy#Fo1PfdDLA}3Py<;pq5X61Oa1wvSgU}-+%Hy;*AetLMS`yb zx)GqYmN|H(phFwon*XDvpsSQ~Rfl=-s}+zPQQOB71(Yi>>tKDu%n>F^e-00YaSCRU z<|yo;C9`+a%4Pd47B&rJnNa#ngywJQw*fIDDv^Ob0IC<|A|*MbyQKzQr`%<1PKU4@RI*=`3~Vz$3dHk`mWtoAE~ z7UAplEcV|c+ZJ;ZVa_b%JGq7FKDOZHf+QbVo7OKfp56l6EEQ}|9ZzHJ(plt5!2VO} zHlxiJnBEo*OjjeO0k4~C8yy%8Og9dBJO|yHecHQQISb{O?#^mwwz8HpvNF8h994J(>$6{@{wkPTA#49ArOqPr`s?yE<49@ifJSg* zhPC<&%6{GBWhY1vbROH9f|kz`=19(th;MNh_=1$@w}D1^8NKw-g?j8Hoq>6jaI8|< zY$O~jR{HZh#?uuy(m=)XdYg;MM;8OlvKz4EzjBx>Vr#53;hb|+z zYhFfzxGZC2z|`@`96lpnJd>g7{3s*#{GmCpn-YE3cDz0x%Seyc1hk%>2ITiFlzX)YKD{)7+^e&U`s7@v;|hznq;cqiM_(R$ zGx5PQg>5Cx`r<`AkYl=LAghSPTl!oij26#3N)jb|9Q*>HOhaK!C9p>s4Et#ruHi|X z&R#szZ9n7-qV^WQy4(@p>s}Tc;CkIF8sRBd6KK5F{J1(eJl435kAx z&DPO=27Uo2GbMhm*HH|u(-#bZV&6Ggm1Qc)_0@NC>`+;B(4eHRDVEPXxjwcG(!|aC zfMKQh*1%gJyz_&GB8(-}sqBC;lIgaTS&Gd}n8?Jfp#h1O_9HR&>S-EC%qHyg{t{pilTzjYKXsu+8c2mkg zaT%nKeGAms6-cLs+{p2yhn@MP`+d&`ruW@O->w37`mS|B8AQ%+DEL1Q*}Xmq^!Ukj zI={Z)Q_qfqa?_4=1w{ouZEmalvhmC#n%pywuvgCTt37PiYIluig{fBYW47mmmzW1X zdI|OgtBR<;US_oLkfdF5?h#cEgYavBrI7wdxv9pDJT(o4UjiS&RnGg$GCID7{xA>T zgTWq2X;@7}uC0N0HC(F;PtyYVT1!h3`i>>Q)r^!*fCn5G_!1K8(yfebOfU(0&0_*| zZ9rdCGZ9@57LwzqC6#jIm1C509El@YypoiLjv5@H>3X_s<7{y7BZPF{&5#Ga-48zb z9()MW8aJ=Eax>vKq0lChLcsevS#?zlu%LtI-};3{NDM!>*DQ<;e(gEx)CCW2t%G)b z1F-J9ASVrnN^Xt!Fq8kLXsSVf{DcEs>Ih*h^uku(PEWU0f~b-Z|JEt7(+)+kdxI(#6hZ)3va>N)zsu)^-_v zI~Jxl?GO%kXYy}5`Lp-9$*w~#rJcprd)l>eOII}=?oQRiw=tiKD~mqbcetC=KY*Qj ztUo%h)wg7T+dI@9$26Pfx*^|_=(({$S>Zo4nYa5MGkCjQEcycaUt1;PE`T=JiTe5m=G=a|enfeO#ga$V-^ z;BS7UnKC1|dmDCh(5T^6L~~`gdgC_ZR9g@TV8zDg@-FKOW~v@o@VXpTk)py~M&4ze z=Ya(-Jc$N>X_%b9;DH4lqu+KWv?tq>vqIR>-RoDu$~sL5g`#f`X?s&yjFGj6QY)ml zMe7jARde?>FrE=_#Z|=TCfu*BFngk3*HsvE^%eD=Cp=LVu@%}wOoggSWlpLy>}M;Y z?_|cUCapED>WSWw(&qK_a9n4=p+Q9_z*ZwrJ)`9;L_%|4b z@zN!yd&8kkH`yaB_`;FW|MdM)POsk~)B?>suN~0}n=0^-pWD}}XSI;`oVBm=y$;vG zYmWOmyBXef#lXjcnw0XZJfp=DAMuvqQ1~WKp3R}ZOTMx)rN#jx=4WGt8iuesJ*#i4+In91(eVp&NSVIwar3%1j6@&G&`JdRWHos^r8XG%Bk-#rv zCS9;;;142pineWRZU$CbzH2HW;yT#GzC(d&to#&$sKcm&?7>pd8m z6Jn(i9gLry(IP)Hy&jxY5@d4*7J9}2+5O-= zv{@k6JvnQa9GJ8VUt^6(*!O(RJ8D5QEeSL*zH3#gelc$eg&O)+`E$1FA)#xPm$7N^ z7CIL_SDOE@^nnTIBPinW%Puh5nmgcCB;49hyNw%7ZBzUnyI z`U}}1GFJ?-pI_0z&udci&*f+Ajk2Nn9+{i>ioBuuOiyznWT=Kwz1|mIk>}Vqd44XZ z7h^pL-+U(TEAs4S2K&tML6v=6mAL{o!uD|$W}qqYRf*f6H&bO1_@nEjQys=SyT1qA z<x{V|zv01PpmptJ#c>kP?9cRsgNh)Y-k&RlK zpQcLTlhE>j%!XR9+IdgV>Pdc{$-FB-?FY^50QPgqp6}msjN0vQ=mF8^cga&%Ocbk- z=fB0*qu+3f1ZQgY&7L2JU{}hifp5_}lJQ1EPBJyS4t62$)3fC!sUKdGIM8wyt=-g4 z`!G(;E(M%T14eR|NA9_JE#1Eb-o)Tl9-1_x13uw8kW49PH1~&IyIJD%Ub3^F zxFd)fw1^qILi2trALnwFtEZ(A(1jsAaVZZo_VU*n;Pb~C{W^It>5`wQH&oSOXOI1u zYi7a@K{e?g%nEr1)8LyUz>9BlqLg!?3uj(1AN%znuQw)uaI><7TGI-YP!#l)SN%QN@Gac~%iFmLlZ%|)F zBkm;ZK$6dAQmol)7o-%HA`aCgf~qB;tNzD941sWBWGAqB#Qx>8|m4%Jz5P*)q! zj>5j8WR)IMvtGy-=1F(MgPO??Ed#`&M;oukjPTkGLj}nhSL6M(P6M=c<_2|j+F9*d z(%wAWtKrx0L(-Kn3*Qwo-$@HX>)AZyY39As5k4JY3X{xjWGl4H%md_!24vV*YP#$Zqa96;>Id*o%jz7uuta?An-du*#C0@whj{TL&;6JiC`Biy9A)dWdTfUk;`#=&P*toTd$o@FN#@Ir8 zzK?pezAba#jA-&eP-O`FJCeGjT0U<~ko9I&_Ye5x@WBmPVI0sNj;Wljc>Ul4)1=orSaBN0>mMPJb|Eg4 z^%Ec%xWjpTT8zkdTeZbM9A3JY{{&y^6+DjCTBOTY zQGURq!CpYj#GgR2TkWnc|DaK4uijxSn;`29%W%{fDsWU80yuI8V|luFMY&EWgr(gL zSl7qS_BQfSE=XUFSdVVHvWd6aHZ#^k-lEM%H%IuZWH~2__#152gk8Wi6EAK4?;S*^ zCD&fi=~2S(%NKjd^8XIXe$2MJL4%n~Re?6ssoIxmxR!&k@VL7@S2zwoWM4oFrrMu_ zkpncc5Eka^r}^d$pEd=iv|lpL30q?Dh z+IOnQA$C1cd*cEd9XYTNC_eI)^gv#Zf7_PSNLVym(pnR)-dd0l(3u_LwE^d?w-LoY zYqT=IxoS^onW#fK&)-^bsl-rau~xkeop-)t#kzcGV+!-q+AnUQnp~`U%i-FR0!~V> z_*(5(&Mbmnu&d-@H&H_H^knUK`0LM7MU<7$AgG!sbk&70p`wT5jLnt$0`W)sO` zx_K4Q8?aNx!}3l=-?@f(kHSMP%wdhy(6!wGKX+cw?mt)OZ*d6V6e)(hcG`ieZ)&@% z%v(~cS8rKfZLUqNT3x%mYH#hXDx$TBqg8B#;$ za+=aF%IS!Hqc{us^$^mFs=sJiFvP zQ*fmhSKubY%6ceI0j_*6Ux{TWuhSJ9uAJ{P0zE+L>%pCc{DZ*mraR+s*et)Hg;>KkUnt)A#$VYYk;1S<>}tXn9TYwSy?#h-cqHIvVLd zq@$4TMLH7c9;E3=clD(qKT%Lp-_ABKbP;dhXvVP*haboLI6lO20>__moW^ku$KP=< z9K$%22L&z)M;s0Vj?p-*I0|sg#4!iQeK;25Sc$_1d>EDJ0Ea8}&F;$*%kcHb%3t3m z(?WF;|2*X2OsgS`IJfvrz*UB*CJ(Iz_i2~44K0o?WkE++PW6sMgCtNbD@o z%C(eYCCh(X8kaW%G+Yd`c7Fsf)I*RU?u4J57r0+74zqk`RQCyWcE|d4dVWkti{oT0 zN?O!n8M0{MZ)9daBtHGm!6BL={~+v0=j+qSLei)%;dOe212@l$+oQg8m&VTO-zl`F}Rk zRaSctE!FOp3d;$pB2o6jgUt^=vZEPJeSC*%f{`R@OSJo&S0Ofvl>YQS$8=cT{PqSv zK@r@Ch|XQt>G$OIfaHe#$Z`B?LUiQ|T-haG*=3{tQ=>L-g==Hy#{D&@l_~Ks-iGE7 zuv%a_bZ9u{=wE8di}#L1vK;bkF1ske<=6wihJ@#?05>LS^@FRoOZOSKOZVFBK;u(b zTAbiVus;@&_MzBXy1K$rLDw%kzo}@hcxM%zTdT?~>sHYYav8s4gqGFH-g4pc>eU-9 z8|nVKs^*Q~$Y(88*!65_5!P1*2c}8S7doo{i7TSbT3rrn>3WPP9Z)NW2mHf?j|PwH z1Dp$3cM|dG+cti__KpOWgUod^WQ1c_oUFOtQkKESoM|pgtG(#d9|flw&zZL^UE+6F z+S?5qZGOWhWBVy-2(d`FfQDD*8FPRv1xX{xKL z%a;=E+W9<-%QBj2Y=guxl@gUXdBYJ?T6K0BCJ}TD$tja zxA2Lj0clo3T1CAWi>u`Yt?&>_sXwt)TbEW5(J;c5P+RJVatTZ)__PYE_E?lB!4>7z z9s3hFJkHY7n(Bf)cLO8|zgSmPd|4&ris`N?P11mGc(PAvi>a&er)`X~V$NW_@k7@< z*3lDr6B~^2@kVWaj7u4s>{UW%kHe^gtU}iy zgmf-QAxygZLyopB2Sz`i|90>5+{lKuDndCsSZb&n=sS6>ZCe*;q}H;Vj5l4|cR8{wNR6hJ;#cd@#bBP}!-8Ii2smvSsEdqMY*FrFjvcoob6t)vANb(t}PR zl;GjB)xo$>f}78Z32-J2VrlEmng-62=T75&tw6d}M0gU4|5A;5;d+E`kE45Q+qR!l zTWvKljPK+@YqiO=R$EPhTbZQ|0;9(>Ny-@)!;D?;N^UMCl;_EJV+1JPlkU!+ISP#F zB_Y1HsG(I6Bx}^W^9wwSdC-I#66`$cn^26WY#z{9)7zuG3be}!+cYh{N?JQ&EHfjo zsb4dHx}B`ms)4~|Ur(}i!g@+TKij(6;B7ztG-tK;>>L~ou6JyYdF?~63^Nvta)J_pUM+;fbn*Cxfso5bjgqbQk>9QXtv&NDIq> zm!>%^&INkbYp@s^i^xZ(rBZ%$%Up5HfowMYR+Rg!w8;tN7@@>!Y~ll-!;cx5oNmr+ zVlQ@42~Ls9;4E5L>g0Kf8MmfwRq(cD$5CmQ@g#b-wG7_ui(6L_m-wCWeQUwgQd2Peseb6$;2WgzaTdOE0 z5MxuARNw~3_bW&aW>)!>A)-@;Iqo=Y0+@YspcP)XS2TgqIf^c0jwbN4X__2mS9)mA z+^r9CIfiapZAbKE^*aq&{q_nxu|7i9h6+LYib7EDFTp)!=m>E1wa0K?k&IHWxBmAM z(?Z+i5|iQeHlk;2zcYDkzx|iU`#;K?gL`+%!}%{^x1JH!3mt!ST+q-TGLH^Y&6A<= zMLUIr4(jb0#s;?x^OyAG*#1xswJNJWlvQ#`p*0+vcS#XxUaLJeuirUs(Nho3 zi?nk&OM*PJKkG-Y+#jIww@XH|GC+P5CH!2bb$74!PJNRCB)h#iS( zU&)dGDL+KJ^q&jX4vb%YgnDcTpO-1OIF@RB<*nX_cs@I#YYo2EV>zn8<2gd$i5vs< zy<9rw+WNodLX9Iy{;F~%u$Xi7JypKhfe{`>wl=8k4_RBTa(O3v0Xlja{!Ng3a8dNm z(K*Ua4SAxOcvED^n4=E7)%!DElO4W7qwtH?snDax#F_9L8^`5hw3!V3Tx?wZD2y$7 z`q#1_8>9!QGmWzFf5KNe*-EsC0tisi4cbt2gG-ESP=-SA3ZQWsU57qfKPCWAzSvB; zZT~Oj8ICE9F(LY5^!3m;h4iiT4dK$UdNyz&eO&&y2~Y_FY1WuAJFvub*1 zPg`JfYsLnqw2g2Z+h`|>>57GH1>>06A{Vfv$hIFq#mz--dnT!V(( z1X$6Nl%5MEBJMpOign9h;Mt`5v|yzCbaLlPJe`QA*W&4|cv^SoX;VC6mC;J0#}`cU z>G6D$TVI#p!I-vTj2-(za#X=GI)5Hyn{kjjibzKwEeeeA3OTkwtZ)A9mW)G7#-SzS z(UJ)PTKj2rw+7|CQ&9`8R{@?F)7e&*?k4KCZI#9s;URl9gL#y>xPMQv#>eShXOPw^(S;fx zqq)E-^jWw%F0moXx7V5|_ehUMe>&1r)!tTS6dzT=Dzrn-j-3-i(cVd@dt_&XccC*e z6zN;yp9u|2wAX$uC&9qZosIA~TNSnvXOwqu4t7p=F(eMtW~78@5AD+Mrz5>N@Ci}j zno62FBN{uNQCzMQvK>>vK?)cLIr5-liiLjAeq>ehhSfx6h>PhjZcpHG70eZn#jBl)QHOwz?CwL4i z71<-|(&g`*(n;f`&7bB|S`)gUHQ^)K(2er;6!!=ZcX_7Z+m_(R%u}g4;=HL;4n~B= zWdVG`>vf`5BYl`ZiFBc?n0fp2(-; zfyQJC3ZOLAw<*n2usP9K6FVn+U6p3XN$CUF4ac5rEo(AT>R;D^nZkh z?=>hCp$MPQJ4%u2=KMenl4ZLF&t#v4g)kO?#FqPZ??Nu2{wnbQK&{v^rJNb3r4nB2 zS;&5IW|Cx^;cSKE$&!gPs%IAJHx|bj9GN&Wa9D7dahPxzag3gkj4wg5T0VFoR z(NjkD^%>5rt^*c6&Vy&vK5bnBC_IBp9aMWp%>TSK4J)D0ofuNPGgm=s=$v+`76jJ+Aekto0GW&Q@VQm80n%86x=`%^xkwtG``d#ZStM z3TWKC>6uIR;%6=`kxPxM7eaAVqB*W%5=I8K0ns!uYbi2_TAn)Gc5!y0?2r z39F%HqKFVt@CiyhZeY(smymcoVV~@&K(V& zBJd2GE~q2}dOmqmgjdlU$;ZH(b^e`eA0*&AUmf^bh=MOV#58WH+dx)u| zq7PKk%nzXJI|$7jj&V3<;jkTSD_aiR{a8<#KMR;-7D+LlsPF=wBG$$DbZo;-l~k;w z+4$UyM0ciyh}RyXr=kM6w^vz3=P$9!0w>w1z`nwT6h^fdD;dTQaR^a?{B{M~tVqgH zbUr<|-p-xoEj|w15l||%9s^?k{3{=SJKvhy`O^3%P@j;qIGqFJb7nIvMM@%7On;M$XFkhudqbB-<7%~2rBKZX*}}iV>)Qp{|+{Tv|6Pz_mE|6bg!2;l*N0~nRf`!*k+2E z($8lQB@Bre%R8GXJ*8WO^61JamV^Imb;+JMdA7v{)Sf#zN8*k{r^SvI&N%}ApU}m6 z=lP?tj;g`?&BV@TV3j?YQlT!%UEUxo$u0mG-8~5-qjW5 z@k@$>M`lfuiZ-Rm^d9YTk>2;)>FG$6Vqp8uMEDi~aZiZSd#PLl+uXef*x!1T5s5v> zede#Hi2T>$*l)Y&>&ymUIw3&xh85b|$M_MR<)S4NzLU^a z;1jH)J5x)dJfE$EWvE~0ReSWTtSid5ytdk)3(-4cP*-zzv{!{10NE1%rk^QFp|Ylm z^MNBQoog$@%F7kQr@3uawyZe-Czz21s=i?`!I%TOozL0a-wR*!!FF2HNdDqFxLc|y zhkaAyZt11+v(j_NqZ-djPUkOSnX3~c8@$k#me;*2&EnpbMD7fb9d(Vw(d7l);Eff~ zU4A7?N)ozvVwb6Dw_=BhKAq=q!!9Lcg=C3OXWBz?`cu9d~hptI*nL!IhHK|=T zNcw`rwM)qJYuhA;Capo><9U|8Zpd!kmNBXa0a$PXTa-qX{uly6!D{VP=st96aniX zYLhD9hA)pB5};GC_Wnw86r?#WuT1mfN!y7&rx4l1nP2emnYDdshSa|sh>$&l`l)H*7>PtHP(pEeClIkc)wPhY%cS0#tyu>uGtaM z`+UUwS)?PeiCjE`VN0ewapvto)767FT}6h1$~%JyrT)@T&wV|6?j|5 zaYbM}i#!MK5Voe1-UY8IX*oxCq`vYibfv`K^7G~CkjBE&r|0JhkjyEqs=yK02oVL? zf;8HbjW4hl9^5K{w~h{c1>L4l(E}V69)2d<2S=e^iNH3^%-_}?>s=)tF`yTWqcJ}4 z1&q(<(>N0ve641YZ*;KC^9l0IAQ=YDf!eLx%9PNHrKP6n(v*hca>z0a3%J&G17YYuS|Gjfyml zw&Scc!S<8Q(e1y%haU|u`#Q3vDuL(lL*g+&!Y)F{H_g^ei>8CSF| zTcPUMO;+`gchdj0KmNDN|1baeUoZc+0evr8zZs1IaQGc(qx@rRbe?642?;;Bvt|oPTj_c9h~-Py6BF;2c1;{|oQMP#o6B zRya+-f}hVy&IxKn)G8{zq+df?0Gx9;H&&F=eZt7#-alMQy4p;(dXRfxDkZ$ok^cle!qjhn_Hca;OOX!mg5Qyt!CoBB zN+qvApvC|TzMCZY+uhM<4}-RBptu%(1uE#I6WDKI z&(CG8K`7Zttnl-it?8^ zW-(9Ko;8J7^)@M>J)y5yjBB13DxDJV6v{bEP5D=_Q%q4I9t6&J!lK|r`E*$2#Rgj| z=}w+sz*m#EQ{Q>hXtvWWzf-nU z(r35G5hPrQJol#aj`d$+@SwDPlFpQK;9V)h_B4DHe?3wQ4HeLF>*X=L1IWCtW#Vk} z10eysL^3oNC9oLOTXbXe4p=>f>K)F>KxESEvW2dQsU{}y&l~uBWnN8DFD%ps2mWIa zc9U68qPKLKRv;m8+PDyJ()PkCy&n2Hy%AUkOQ4yY(Y>(!1z@Z3TKM8b4jW*HmY?dV zoBjQ%FJSk|!7g)|m}*A+Qq+gMq?9|8*-%dj-f(zO8+z^gNKWC3gPn-dm1<6A{{@Rh zV?JTYki}U+LKOSpoOXOv;9*F;>G}e!hPq=PP(c5=Pj$84{A&TX<40gwNl* zU5X-zoJ&-&o=V5FT0ED,}#MCbGzJS)}twe?XA9#|_l79GJ#qy%lVy-MTS?f-pc zBkX`yvMb#h_&A=H9O|j?8q_Q1v#CG{=h($6WfmVie_^87E^&JxH;6pY>*Ry7FA^{N zBE9BPK~+&`cPGQFMc zsKS4>1~H$be+Sz5wnY@}@rs?JSuSE`*jY^#+QdKm`bw59$Iy6z{^!2n_rc2)nC+k- z7mH~vWJyKO{ft$2(o>GA-O$G$m7XvXU#js$_ueJMvU8nkQQLN+mOPpi2&}6(z2riV z%5eIq^oX9z=Gc8zeYI|l612!PV*}bTyNb@1*xj1g(;Hq}=TB>mXhrn2p27>KrNn%z z|LEW&#%V8g9VbA0HhOJ=d1Y2r3vq$r;w8w~u$rx2z zrLlF?I|)_GunPAhCNb_gk4k&EUjs$#1>l_Rv0;U2Jo2!DrxsJ+X~1<;uSGThcj>&*{~;s-kqwX$?rf>`YLvjs zKMc>nznv-fQ)?_zgxs2UoYb1Jb^XBqr}l86h`Mmj_s?~Hjgs7<7-K>HT!)I zm!IZ^2J(siftQDtw$s?u2D2b_UCA6h0%TX5^@HGte_wHDJ(z>I$aNYZ&7>1*pfg6y zhOS$(r9AhNbSXgy)k&XD;;fs4gl*!^e;$2Kdhi*x6*3J^8qY=8chs!KMR9P@*gjkGeGpSE9_l8^v>W)ZOa9H3wC z4jh)Aavtv0#ZCoJxg4?;T?Ez&?Lgnz{w#k9IKF|t)xf0+VAL+>1_s!mO}=U~U+X)L z>*aLa272xp1$-R2XOe>S%q-mX<8Fn2eFfF8(xJ%HTZ)ZP{6|OP;my)jbJwIS&HCUVVd!8t5F6Dr|9B@vrXvAJxd`X+NSJGDtyr$=g=V+6$3Zvk?{I+yF z54}3L*mlF8?z`;wf?qtmT^X^$z$EDEE0PGT7=HplRZXGP?!TZoUpNSNCDY;@ugn zZ%E;;^{;V|hDINVfVb)eL%hVt)=R7OwXlWb^Yw@WN_b`pAE7V-_rR^_cjm(1sHm=p z3$F1idslJUe!P{}qfh+T$xh*F-~4O*m~ih!8x0LZ?N zahX{2@|G|2V#UaSVarPRE2*&N8__ph!!QsTg#C19EE@^WT`sFPsGMXR|7~yzsFvpn zc2@}Fb;pEEK9h%!X{2ZbwwN#;^n6fb=0buQ^)!ZSNV=#KSmB>5D72+iX0TmD9G<|v zCF!i7t8fx$9;P+4E*o3}eU+>s<67KJc-(ehF7>MVx=qwjYyzSYXXbM3?8O?y*(?8D*|bd?Aq`2?f3Aswlq5qBj6q%< zl%J_z4qMaZtLI!at?iU-++0U3FgWN=_&PLruBjJ0A=mlM+!TA9|A#HGL*aGx?Uj7{ z$##?p7yTscE`K#HR>hzG`nElQz38p5caoy$vQ80`r$PMP#g2G?gYXK8gTnW_4$hv6GVR3SV=13t^Iw#$f?al1W0vN9{%regVqMf|A;RGs}nC zq*B`v*eGi{zbR8(p08*fOgDOqoL4?{#<;U#u{!1Eh^#7jDczP0qov-}=n+^>_Bg`r z>y*F1=lK2fn*)v`mGKQL{0Tt*)dDp}t0H-!mA!SI=ENVX)sQszw8ps_rDfRP&~|ud zX{bLb%FF3E?3^6iTMhh9lbUhG@2^};d5i(X%|jkz5ca;5!&Ne6YClIyK;?vQ1A zFM{sh^QT>q0CLuffZp4UFHbgk$=!dDzjy*!b!_)){ujDk30S(+k5sbQp|zC9I+F~O5?DCmx6!I6Q5*R=V(k>g5fvDcGH{I zv`>d@JK`tr5g^&-A=!@Yit)w6^Q4y7`4At+Wdybj5SJ~=ozP#^J@p^p~X;#V%!f($}}GMSW~a_Q_fl z8mT0o(Gi1Km@%Hl?{(ZG>=#`EdZ*HHZQzaTF@+eb#yH$4EH{;*#uc@k$dhZ4OUzBtx1_qBl~ z*L7ZA=ELv?nGP0m2HdI3+n2T)^%?!0Z@Anmh+ogB-h$b1a>gxIm~k7Cn$lFW%F zaJpra*;9y?9DJ6d*^XipdKUDbe3s6#d%`(0dtNU3HmDi@4frqn6!P)AmimVqSFR~; zsPjP~XzbSx=h_S(<7}@qBl%4+bp>46wyHx? zX93BK{!(?=G=+`owwv}!?{l`YDa_E_AsOTLN*{1>W{V^plo+Csc zK*1Lo2w3Rfueubb@W>5zfjbpbP}XydELt-RuC>cjh3v%6pd+y)N4(nSV1$91EeefenH}v`?6)S*c)W?oz~2X56zmcwcpo5*%6y zpDW(aw)Rjx%k9zZm%eiNO(+plFJ-+zXhG19q_Bgx!tEFy_`@+8NiQFa5p^CVxGOiX zv=&~^#jZ{9+=|5;135znd%1|?SDuFCbH$6(+l^(jnX}6PFZ&wbtY{>dUx9>-WuO&2o+3-LHz2d1fWC!%jc^J zv4I;CRG~jy-L^S0V84=v>uO+abIevnytKV)B`G>2oY__wcs&7L_Diz)YKbOO?8%{0{y9QZ%f;%lRlB_PC z?Hha_~bsroE@K3VJL=+=hKj3hN#+`YBFzyJ#)lFF(;!X)XOV zq!Y{2m7rLEgP5CqP(Yu{@ARNernUYrT5F_wJze3<)IO>!kGkF^DN*(ptyFRwW){`5 z`&o>lh!@ay!n-NMz8mhDQK*&6W-a}%zqd-?=ihhj-POKUSJBDgW;U z%W_KXp${v$36p{LC- zMo<(4K7weKBt#1idp82*ZKiftIA*h3@9~A8 z1@|PeNm6Zlt)zg%6F+(HB*lba@P?xV>vg3`ZPE08fS59k!@Olpx$HOgY64cPVMO?W zoQDO@(--D3F6#BhG8aZR*Pv&%VPhG!L~ozP-fTKiw&4)pt5XS=XRCgPO?D>VntH(L zmzKvLl$M$i`=WRc(zd~LecRwD<5ol4pb=+g+hRj^ku?Z8NM4Vc?_+or#7K|d^P zOzGwYh`^xi{Xom@NP_&o1lsx-*tBsLwHXn9xOXA_=o|1!N?FsZ-q$y=9#Y?F@9_ftrAU2_Q&ZVm47|$m_6Hx8@M0&~eiB$XSC(^IuR1Lu2 z*&lxH@cCjH7BGxD5eXu8^dcD^frrHAVO5z#M zk71KO&|_RmeTS}|ma--xqJfGqO0p*D;r~b1_v8AwNr-r}{zR$^D8!tF?jj#@aF!{^ zGgADMf4zsC^)ykKfe>hs&BQ@I=DK8rs?yD6T0on*_T zeL9s(J@f%&A>+nS@1=tFf!2@BK93$9L6mO}R+h=E>bzhvVuq5Wnb3>xLfJH%)BGgy z%VF!z(*InW%O93eFI%<0-k>i4%+JAieJrp(VB^7Nb<*#6{AMHluJfYfC8^{= zpx~Oa#Uf@`kcW(AEqutZS1yGYG}fjE3)#!(Uo=sBZgdxoYG_?>?dAq=k)~6BUDan# z*=I*2i$dT!Xc2|MU_y_*C#@W7Vzay9YipP*|DTm*!uvVI@qPwKg|OSj$XbHOz!k>9bsr-}lS3B<63)rwq0Mc8z{l>r#hs(owM{|;a6(<>qhK+2GEIaAwaJ*lZ zJrbDZ&zLbXPL};qim6LHb`mSiNy+A%23qi|oBN=zDg{dCz`z58Kb76&{{$}qh*6N- ze2QO-WBIyxzxU~QNOjk3DW08zaY1qk@&S(xxuhjPdybeF0eSPum5AVTL$SDFYtd}= z?Oa&@<_r&PCG5^uOFjz6H>cJR(p?4{*5vpt#b}}JzfdQ2DC3f#Y$~D_j|h%yr#H|J zePiI+!oYGDPm!o!)xhB=Vvs303!>R-AGC_it;!4~@PpxQ_X6+;}CqpAB! zQr4?|BfFEK*E^xg4w?_VB<=(eBAA<8v*LtUcrwT(5l}r_3sw%dNod z|Hn-y>~h9^@DQwZqq~%5ao;lW%0TJOhhVR!>YB3;(Mx$H>h{o0`<1waCdi8nRlvEd z$?jY>@x?$~=Uvc+{;o>dS%~!CoKq)G2ra;wse0+erGfh=+F4&s@;7hdO0Zhp=|Y-Q zy$4snulewsX8iM3A7?wN|9G_)RQS1?li%2{SS(FN9E-0R+4;w-m*EflWVIG&KWyFv zTK^Q@Z)bn5X#qcwAm{tI+J40>pJmn9uf*fb&fc&28_LO%uU@W>=(JxME1##<{PAie z-gBVlu8V)X8ileOYL2s`C}F((+#5B{i`KRC4;aek?HAw+`P(7%4A$y5YIaK#b9X}? zL2EGRUc?7VD7KW=BR9=+e%Q=jyAG*CqQk-Wmo9qq>hT9w70tY?`TZ}yra z_LAJn9?HJgt0; zSLxy!GQIO!_=czhiU!*O(i~9jBE1p55$x(MUl7Aqcd5q>1pODR zjx5-`)RvECPoMc3Uguv+$8(wEl;JbT&43$)|EGb-L;v^S|6ct6I2X8TMRaAa?KA1j z%+I7w9H((C#Sy^q*O?zYHsi6+q|b5wF^=OnI_;lH_ZEL9eSq`BINqB%v}(qx&!mGm ze+S3DnVU*!zW?mqM4L%0G57T?yS7K%bb&jTomIU?nMQ=J=~Mt>rZsi}m*Ycv8sh9AJv3p-$WI`sl<6=5|lbRC9P%Fgbo zqIJl?hHe$ZGHrU5=mWmBd1?CMR_ynAnjjzI^OS)cM?5g}>@2hDWyzRlKp%gS2W~tb znt#Cno8pAx=nEv5;rfzqmv{QsOq7=Zi#^d3!~W}R_$^=Dx*no<($_-!r5GnL^GxaN z$ulg3uXV-hcpJ2f3wVY!hOkRi?T{XMH9Y1+&Me>?+6_k5dA2`vNLo3iBXsyGw?Nq= z`wh&tvx`o8epc-%sgt|a=K&_=J^lW74uJ}yv2s#=epZ%|9X{KR=Vuij0{^doR_-(T zZAtJi@X0#27UXnd%kX?|>vAi!HeM(zp0m1MA4SMW8$1Dgc z>{DkxT&$c#tL;82110_{fY_awyN3r+PQK_(EnNY-log&l@L19f-ePg)K~L0Nn(sSk zw5%%dl{%YOP4ZnRwXB}(TeYfr^%UQQRhBh{zE!K6*G%orE8<`o21o-YC&Pp>M4ZW^17F*wTt%=Uy4Y~(OL=d8h%(H z<6q9<#=H*8tF7=xh!qROQK1`})Q)wC`aMRDD547{;Op`fhsaTc{+v7{gp~e_+P_xo z#Ch|1Q;FEK&OL|rvCBbz@@6eJ@m#P&dhZw5DE>_ykO%7e$GHD)JG6YvPLv!ieV1XCxTdQ9y1ruyw#RR+vq{WyLxbrH7pL&~k7?D=>F}1t{^QbnBb>;4kBNheapJy?NxRDD4B%~F<%0GB-}`%~a9cv! z;!I(_bA+$?RW5P5du~E6QdSI~P?f0nb7Sukiy*CZ@JiD%b`Q8lN8Y2$=CmEDobI1q zX=x)l;S{#2d$NHdQBP#gb-qwJ*>J*7Tq$vZQ^gg2vY|W=tK%u`KI9{-<$IX=j5;)h z3HT3=uXLdA)-~b={}%l8?}R$plajWMbd&Fx5lfzP&zWrCClyX1zLJnD|ItGzpz~#f z*#C^vvaikqeReYOuoECZx<0Uf2)0(Hl;sl{gk{HK z4dmO|BN2xPylj8pyuR@cZv0iq9AI7PpUFa9lMTkQNo-6fm-$Lcm~USNK6Xian7d88 z!^^@?Zw`EesrHv)ZMNol>PKjR$JoSMviCsL8_8nZ79h4M7FVUKOfRiwVAVAA4tA#ko8?tAgkIgspVOi2##6jS;Cs}EtI(~ zsRXt(Q$d~f50u{EO#&z>(lT>(OW3V5RBArF6+W1p<_In2vL*yLM`@b_oL`<8Z!xl8 zbuIPhZ*@4rXmxliVp#iHjqKSjd%M+v-a|AHSTcboS^k6`zWKCLr`4M9G`!UEvskGV z)^rTpI3pLbLtAmHX4Vx`zPo5~VAhocr1v9DMLG{@4pI?m64D~1Baz;XbUe~&NEaiW zjC48DJftN^Cm_v7ir6(*-aRcYjV&`TZ|?bEXNZ_ExQASSN{vV}N&UDE-h zD~&zetqzeCMzP;`z|?Yc;I$#(Tn9}aAv*&0T4CL!663jm7t9*)P5kd^uSgG7I^qu) z!8!l?;8Eae#wj%&mGImMV+?Iso5|9y^RiVm-s6FV!o>I%o|%To6T|3p&pzK{29pmQzeT!h%Fpb9I zw*n&e|W3!%Bm zvTXxRKNIW654Ut7aFu4-VcwIh@L#1_61I1Nr73XGhpM<^WUsaL53kDWJVw`oL+}e3 zaz?ujOOfT#h_tx0JWf2;S}(>oDzRtW+tV&3l^<_SZETm6<*{|qo)R&w(Zu%NLX?Ni z`Z_*fVzoC3S51)>5m07n0#RA2z#c?lUx+9e3Xa~3Cvm9t+}MUF&tSR@{sj#Yk<&0@ zxW+6tVQ{9$?u#vt^=RRppqu`_7}t12Olgd4jA@K$Ol(YO)HZ4wM>H5*y80+r5~6I~ zAIh)Tkv`sP3TQfcYeHb=DZv^a$g$oXObp#+9f|lVT5ldK?eauzLqTYsH7#(~Y734I zX?BhewN=34FjD8r3i;C$>Ju9>pjo5HfV0`#-H~-8fBg4ccT8QNQ-hs`G8Pyc6~*ZXG!|DqJ2Gg ziG(ho2}CwcY$yMqIPYxuF#{=O{4ay?O-DdCx73h*K4c=`tv%_>EA(vEP%cIz2YG_9 ziRQJpMu6o!$9C2bQvA}_`}>Yw(KWq_x&K;CE@GzUVr+c?pOx7GNcrI_T?{=;1MC~` z3fMh&`@WJ`xj->k>j}4re1$p4_tW7chP5|1{dEiWMVB-eD@abj1UuR13Kk+Zu%@?= z^HrFjYqK}qDV1vk#@QgvOWu_Seg4+~O)t8vQ79V7rzuzbm08{Ufsn|myZEuNgxG=T zyiHqbZE2Im*X}4|^+B)zRR=lop3GgRvzIuG|64~2TujG6dr;Az>5IP;u-=c4$gxMB@7 zS9c=d@va2eT;U5Ie1MI=jdtYI#0Tiv@;lE$>O{|Kn^KBnU^7R#`Np5IIi2DDngjeh zoq58(D}Ba+?ej-MX`qE%dImQC}+SqhQT< zeB{p8q>9jM(x!t~`uKtIjnPdO$JoZZn+SC&t1-5T?Ehbr_Lb|KApJXTZ5+|`nsm^{ zHyTjCO=`|mXPy8*D|g+O(q1R(bzIR{%zg&Ssa*b!*6N5R@|YM~O(SxFu~EaZt}=n2pmaD6*Fjh-unb@ll^s5z#6+BO!;pCFsiJWP@0Lde zis1FAoi$d?Y~tZvYjMD0_02HiRZ`%0en@!yDd-8Vk>n^bzQ~Yu(-PpwcL|z~$lKSa z!3Q&%?dYKy#<640yPL=YFdGyaeEWGFTPfo;%z*AR8c$?{s+up~na@Ucd!-0yRI)G{ zMzYRxUid`!fF4etlIn=`kKQ;%zM~Ii{(BXdjpJIMG$7wC3tN|{Wb2YF(B`99eHYzH zbC5q!8rt$%-|=|8hqNvkJ*2&MOT0c!S$v7NxDl`iQtI-kVz(sd6(X*!$%BSljXbI! z^Cx!bfmdmN; zza_5-e8O^j>AXP^b^kmISRYYKfdM041GIEmMh#Dmqho}500=k9po}8-g^3ukvm@S$FX(i zOR*ESOX)J@)B-8t=W$yNC#26!9J~L6cGRKNL0rGe8c_%T<10lkttr!bmPjU!_ND1B zc_agB158nt_fq+Mg^A=2PO%WXK79LFdY4n)zs9~qJsW%AIwIxXp@`K1lx{ofcF5rsXnWpLnAxr7Bak0v<~yKivd zv%x~Nfatzc(q1#gOWbRw>tFul`aAOVcg&rV!M0rWR7dQ))Nj`ZB8Rj`=EH`lfKNxv zY;K2!CEud@eFyvVWr1`^VIK?}l}b3ODOU$<2^(Q^E@#Ivr%Lfmq&I^l-kKE}>3I{l zV49q`An_bNAsSwu3laZfYgZP=*g}4!XA%34F1>%Gdos&A7c1k47Vz^$daH(=hkm;T zJoi_MHum0qXJvT?XsrO&3p=elkwy_3Y5d32H=-KBkg16q^DHW6t4m>%C zuUa}BqhY)zx~^SHUHBij`>ET(Pisi&E=~9O{7)j5*9*fW@7MC6sVTux=+&X?I|qA#-# zwyK|-!f*TBls>ukrdz+O@>X&=cJ{aGk(<4F zKKto63H{Ye?)e`r|L?7()}{ZC*7?vQWM${AKIsUzaQip^OO0eyrRJ(|efC!EuH?qs z*DQOS9U^0G2UvZC_T3i90#La=vVK2HKrSaLLgCpU+ z6IT7PMtIvN@^Q>~mdl(V9uObC zpz*5F@;OzSoY}#Vn0x<;2+G(&xbHje%&3Lz!ufyAsJlADGiu8jnyDRukv?DL3dn6T zY)z1HZF4-LRw9ZdSx02EhT?a>FHj_x(|ojLZs^Umn& zlt*9ZPe$KzIB+Jc;p>4f!|7`k#x{hFY&o9?7QFRj%7Em z6CXyFK03;AJA&0INoxWgBC9@|?yHgKr(K?tc5~u|Q_{Wi`Mu_t3#gUs6~~PMTJ!fM z9Ciy&qB+H<*eUE(?&LEQm>+R=Adk$XT1^nU%lNVQKCAxpA0x&8gb(ltaSD9HQ*kyD zXOQS*@`$$Gio2skeymrFMtnPdY-9*At;A~Fe^?BLCW(IoLd7HC(8<=R7*tZ$B&%QJ zQvu7GX2ybkX z&70_Kvsm}~9A2fdqpckWZ$3m#I;#1---LQjvT5xF(US^e7}-ACi6 z*#$Gg!Jn>73;0ozg>&cFgM;C3n8};_U2m-Y*D0|Ah?$S^Kl&CYe{(`yDfOq7sVQj1 zoBO|g^TNMrj*9?|qK4NuAl`5S_g9_>?pDfAe*+$TLL^i^`!nG{XBwDdqTBIZ=Kt*f zO;;K)2{qkqWg0NaFBTRry~9<+T7jpuZuGHG0|N?Ddj6BZ1}$;P#>)c@$od3-Kqjr_ zy@?DWz{#XGf5o+)4a!5EGD6e*X%Oo;>+itBPf?CUWU|c{9s|Zo;*H6kFPvy1i%!Yc zwxDj*;4K5rQk_p@L}t|i$tsv!Wt03THmu^-T5X$7i8p}R>2HCphF;w5hSjK|RT!cB z<Lwr))0Q*u@39`L! zPFzZ7;>JARvWl#B#D^pKA~6TCSf%xL??fg{N&8O3~C+a&9cn7^;>w%YF>I>i-!`=g6o9NUmL^NQlSi5Hi zFGL<1pl=1(Djc9V?=0R%-u^uUk*Zt_|(`DlINgj<(Z*Our1X zg-T^!>f$D_el~O8x}CrfSNno%t;kH#ATQYkeQb7SZRG_^cZVk+}rAiR0lny%Cu^NJz-XPE$m0xUdBCIb%-& za@6T3hK&btg=C?>Hw}4=40t>4f(5_K|2C90m`O=Tw~UpI&GU`hG#^X@?=qJovj$bf zY(I|d5GqR%q617i7`MkYB1YGVIHAO_JkIP(MZR%+_c6o`Uc{AM88}~N#d}HgO_r{p zf?sg3H5+{td|EFUgs;ySF~Y$UA#9h*Z4z9-#6mxh#;Q39LQfNeUcJ`70U3nR^8YUI z>^IV{Rpp1WFE0j1NX(&XVpLiIEV4X9%_nahjNCV9-I#)Fv#E*5vC9PJ7O}lY zAIwgJ4n!j2@NSF%W8fo7DYg2j9a#9e!aK;$K?H0JX)(QvcwJu)!0l2jESBG~W(co^ zZuls^zOttjUUm2GYZL2JYQAm%c5}AMbP`${jN8DbLGM_TC}`t!enU_OTe3i@JcZ2S z)C6SrssbkP&yfN=A{Eca2-|x}iA#5?49bNwF@k3~uSJdlElT6e2w|X8K1qM{9Z6e{ z;$bTP`BKVc;=rESRI_kylbf&(%{iRkT)IDX3UEv%$Ui{L8%iTNP}FOj&!p)jRFoQL z>Zfsiyt1tZT!xxgp+!XzuV_qHHeLjdITqPBDCfFqowF)F2iMS4e^xn%TFXOUS|X&M z#dwp^1O8|F=05Y}W}WW|Ut&-;Nf$U!nb&UHl!7sz;zk@eNJa_v>xy8;aE$k0s2_|x zcPou-#2ywA4lyzVEpujtN-zx)%K^peqI?JCKsPgE-J-SFBi;?>sW#XLF30Y|r+lwf zmcpmH!e^_b(hNp^iR;nG7P^O)6A2;4G^k$SNHi+x216nlNt&i>t|sXRmg`3 zU|1{76q4bgsgN_NLxk=4&ZK4veykFwuqr_#juyfm2DT(PpcGS>Q0kJA4k;(lV28#-aq^B#DFKmEsq`Zt1rnwqwxw z_kd-k!>01*+t@(XrW7C006b}C!I+~A6<2|?_-RaN^PwcZ0eNJJl`(t| zVp4MCO*}ck@iTn&U^^g>shZI17~|m4GBdjppw^*38qe!f_ipBPSfF{51I3NKzrl>% z08|&A;veG6V+JF0pa@TF&lHoTyhrg6ShVmahVc(TzwUgc0!(0ufmNlozzUG3OnEBH zg;}oH&KKp1k@p9w7Z;ZfM&5$TPsu8gvKAIIwzd|Phgb@=R*gsH9a0(-O4AsRnyt{& zd8-C68wT7w3*g7asP2qG7ECDor!eiC!H2?ov8A`?k@JI+3btHv+pD*T&leU$O*F}) z4kp2`L492vnjzC3Fu{%sL(g*TekRpu358dO!)t6i$9gi$#(933Hy(d!_?zGvdtl^S z@FJpoYELMrc*#EGkn5uuCj7it#oIBG&IIDh zl$wsbV7KI<&H;+}qxyK^g|n}T46|YTYw&($c;%THsOQ9X(xglbDnp}@-E=vUe8bS5 z(YO%!{)|Rg2HdWwILrSeOD+5>7l0qi7 zRNj0bw`SY>Be$-Vm#EuYN-$0}E#-fR#18&doU!LH*hQFKlvl=rJy7Q1JTozWLN|NN z3XD6#O^WC-mLZ+=)UdGJ;E?|wMxsMeYUCZIi5CYWYr#tm9H z_;|7EYd|deg_OzyUhY|f6#{Z%g?ZPqq?yB98Y>hIPzJ<|-usa$kSYATn^+pMnIkzL zi8o}*ZgXiXM!%l!Yz8<$j;w`uuJ05L4$2?72fzGJcZX)HXh6=Y33eD+%uv4*PW8^` z^+43@cjV6PSwo7xgmM`NlnXl@ZCFjKsKfRbfpTGBC6I-!lCX3Ne>NgYKu zpKhM~1IFs{7`u{s9!Fgu+HM^w^ut0MVnL?O2GS`pA>;Sm;w|`fr0`9bbq#(?FqRG# zMqzdwBTO2wy5?LiV}b3no64Xq73e9OdpX15$*}?@;l$@~|DvlOC3td-_*7avIZ4>R z6#J8osu1sq4bHjz&pCBDi2?5#;JKH25X;HF{8xNx!FB>%%@{VQun?ExnuSJTRS($& zr3)z|)hHD8;2pA7@CnfKE;jE_sr`5(quVehnfYZ;v#FznMZoObi2M$o*A-=-``#97 zrZHo@t+_x#yo&88CTEF{e$65@jx=VQ;%luV4@DO%wzumRiBR%Lu|x_xG1ShW-8J zB}{*L@sG!wbm~Bg!rcE`Cp5T(QH+tUB$G{(O;u0&Ye2$OU0Z6$CYpy+P-yg3SL)g)3VVC0cKWeKBvjV}!gAze zZ51cXP)R-UXbZ>m=hZOo=NqMdxQ&mm+18T8_W*IG*a0mtbyAb2p{Fj^rD!5f*AK!~ zEb>{v>&lK-@k4eiJy87Wm5nb6+!ItZCxGKj_{LF4u^KenXqq99FWyj+1TF^cNf0<@qJDe z^#HvPKx8som{k>Jm(vSv(sxId##?ekgE0~NN61538RCb+-x1wT4Jy1S`>zrItU7ch zdvkK&T)Wa6J%(bq7UA7NJg;5JYdmqmEEg+zZ@M3a=jInNUoRG9TICoe;?QP-=lb%j`sC_=#Y*E3!F>_?1P)?ce|UIWRliT^2gY#^g_2G0Ut0rUmt zZy+$}t#XvSnl00_u;1JX%@;!n-=aZV#_@Pdn)RQoa&6o2pLsK4p zJg7N73eR!@(9orR#anT2W@2>`6I!hqCT#B^OJo5rgkvJeQ%n6trrMIaKN(ht%MCsG zJ;PrZ@w^ZoylQoQDc00e3_1~hJQZ+#Uw{SNz3dKRVf0%nQGXXA^}r624Zy%6nbMQ) z1*?z83VXyYakxxuCYxlKpy&e5v(5S+Yk|&Uz%Z|N&k=s#P1XWsJA@;-w}`DtYGuom z7^5kw>VW+XaU+pc|z3fEw=wY*i9YM&`+a-+dvp7PuGW&&Oj8FHctlUJsdp%V#@P=_$dO zkX>Jb`KOQ{4!!Q-9oHky>x`AO#0h6Z7TZET&k{YKlu_b^f1XvP--}U5o?hr@EF`E@-jO~~HoJoaJ?&Lh2=kzZC^CvVHQgeYZV4t5U z#B|;dc2Ue+9?~Gmf)$;ujzoSpm?zzfV$(dl5zwjuCW+3_370zW`hT6F6LPy8(ittd zOFH!NwZ~|I4Y03nk8Rww& zW@1LI=+WVQ-TAiew)fp6^$oBf-RTFp^WVo9`NhH_&Ya+vC=v9zEx@3rut%yMl3>P+@v96)KQ6qc0uL1DRrvlo zGxB`U-VoGh(|kL{Z!;3%rQ3>6@;7aTZ$}Tm9Bp@=ren!xHB2xe6SwzQ6pwoc^J1)U z0G3N8G)Sl|PBwoC3&9SLA}NJfyK2ZQU|CjZ^EFi_`wA;HzLd%oU(_z(V4bQJU|Ky3 z-s`C;u6;OXxUdb@uW@P-IO8a7ze>+4=L(PVUN2$J_eneM5ZbG1npcUwYbQw-M;s;Eh#c^q3uJg1>~c zI-10sOtJ}R{A?1lt%_iyq-8n>R`Nnv`;%d>{&T9etx1&Ib#2h-$ymfESI}EpEg>If zOT4^yftQyMGS%%}K>eK*m$PS|@qnT7sEo~gIJXJjAR9)V1>h*Sm`u-n5Ee1A9?WZ~ z#HbydYnjz9-3hIGIm@Od2zq1)k#Eb4c*C_D)c>uRW#p+^UqXe6`hbkF$bu;wKW`Vm zsV?yNc7qM^3&Rj!tz2}i|18=1o#f+-SL7xE=jVjQ`(iGk&5A1!zx1-h1oi2(oN0|%d6T(C_PjQ zLy*_MQ)H(Tx@aXk8~!gldM%hKnr)a3G=dv_*@ZF1i@Xim@8FeSrrX0@kGvu(F{?cD z?S3XEG>$`lGRAe%nRw+I)mGEIdjmT$UNbgQL7e2sx}9~Q5K_)k%}#Rc6c102?mak6 zfial&9-h8a+=DS5cut!FeQGdr^Tt-u|CeE8x9YL=3Dr^&GV$yGLi6khVRRQU^B)`* zV_Cr~gijUM2V)wHb=>`RzKY^ZZLD|=oqs8 zGX`vke$qP{E*MVd!?$J=_TOe%Ab$akOovY^g57A3`S8-;ifkE(TAby`@R{Twtd(0l z{6MD9jXM24ULnjoLmUe99%f4Y!9U&1ze>L?F#xMdbvhmqIfbCRU8lFX1r~3st!;_1 zDUl7+ zZ>!{F=K?p(a7qtZ8k68_FTq&E*t=9|r;dnvdo=$grB!J&2ac3>D@L3mFQ_i0lva!f zMLEC6r-l*??bTyVmBi7yf^22Py6|Uk6JHzoV9CdNq}1B)-f(0U-779&+f?SGd-Z_P zlg?j+o@Wv2a7`vHCon8XzjY$dj%@5gMcm2%D)()5pV&-NEm{f2g7HviA{(a&sDq;7 zjo;{x{CG_#uKB4H<%`~<72jR$KlM>}i)K5U`8WK3@Efy=0V5%mSbZ8?f$(!jB6r^+ z3Pl)C+_HF5_#T#GN2mc1em#9{WUkYuc zeweTu@scSSsr)EhVFJ!SJfDv01%pMms5jh*e0Y;FPYMo~de)tOHBjqt(G^qVOUhF8 z168m2;ulhle7@4K@VL0${N+kjqkO8Y?_)(7`E)bOoTtzhLy?EY?791$sz&njf;(Vv z9FH~rWPczUAN>(GL%E0a{>jh!Ov}(esDR~AyS@Bj^aVst>!bZ4w$$6IK;K`0=aG9t z5xc0Ump8UtVHZyg&}x4S*0Ku&;OYdTe4g}1r1LBdt%;JVQC8r5?HtUzDlYfJQpdR} z^?tqOQsm~qKG)t_4&DIyti4qq;l3$#seJT~-qr=UlMopgRKKRE*ITmrOUU7rH!Zlj zmTQ8ak-;8#oe=$g`PN9g&d*@gOqskPC=yAL7-`)x;%gw8?HsZSl%6(e3~6#Ju`XvC zGBDm);oW-@`54)P7WyZNhFx4eh!hfLwEw?SosC5&Hm8!AoJ2 zFFL(6__p|w{V=edhk>^)%6?n?(4LoV$|a7Fx5d9=I}ysBq|`t;`Z-{}A7Aci#um|I)MujYB;&+G@B0Wz^9;OK{MI&)rCa+~Pl2;e5 z)ffv`<9Vkh`U=5ZQn-p#F%sKnmVV}9g2}vkEo)b=*0pDq_P7eyDjMnNWo6rZ=W8e4 zZoM|C^?trmohj=(#ud3}&Cu-HVr+KOJAM}LnDZ~VdJvz4j!wnf%A{Tdt-G4D^xUTQ zsGY6!e_b079(5UJULn#vsBAutNZ-pDP4c0qXf93kw^o81b?6MB8k3;0%viP=Yx2+4 zYNa}BuBuz9S@^KCZl&qh1Eq+8W)7^1whWVy(-m_&9&ra_Mt$T%*N&Fsq8o^?mB@JL9d;>9%Q>Hb@%u&eLG5Q_Ph%=Jyk?6)KsYg}$)jkBrt1bRT7skv$nX5f*+p9l0!)%-KAZMAQWP-dCT+p69W zXEDz?oi6nYLgcYqy7~=JUz4A7y1?{k=?@3PeKkN;jfD!r2IEnq^|ugPa?4VGP5aHDnBkA+kMwnS^KK5+tB#+Ra$5N!@ zowHT2{_`;w%@f}5WP(*-C)PGqi&l5FXsOR=OF?E^0nhqJBIgj9Z8F&eWVTH}W*b!3 z_rh*kgnDIVKudsW2n4n@&m*UeS_4Q(Yrs&dqwKaEtXw|0365`fU(H$ZdWEgTtN1} zc+jBt0xeivw^DnRg66uuX<|cO>G>Gg& z{Kt)T&N>`#XHS^6RmFtvMij7yp;(yyHAQpW0i|%CbmwNbCny7!;Ka(;ZJAh4vG&(( zlkq9DbI?(45;=SB5n46b@LvI35m2Fsk0fj7T;Nh`Tdzi*xbA{=p|Fc!)c)VUxvu9! z-xK9AcwF_h%9$&Sb4(uRj;e%UbZ>p_OQG0Uk86&pwsixz)|ptfHv0mb>T&J``+8H= zg_`3E-O2Cjy4(}CnW|jd3aY-VZF0X}TjYMURvS#K>vWgaC0D&(SA^dh-Q%|vx-Zs^ zaPLMRDE2kiswXJ@Kfn6BCHLL#AM_rnf8Z^^7fH3G-c8ZRCDNNp(xD$l{YznheKmAhsJ^}F$A%zbsr#-(7)Hv2eVN{zDV^DW2@ z^jxUJZ+1l^=2AOj(R=!8FKmg<&Q_P~DH<#Fx5r5uC6!OXq64PmuS%!uALxlfi& zb6dch?Q}7iLq8hO>?VBM9=9H7%FX@8H}QP=hk4B(ne+{QvkN6O_<@#u%rwlOhrtzX=pzrvWfdfD2ZWW|fiR%bn>hAnrDd)W2&4M>ctUj-D@5-j#&NR+Kb5#u7-8R92fQ69OH+gK5>t$ z$>jhF=1Qbt@ZR9~yvwjj7&D%{T-ZYXTOo4)jc3z_cD^OWeucV_Ha@!=bDy+l+NNdNP;skR7R<#y46RhWV0_SnA-Ka1DuRwD>P`Fk?^WFn|#1!Ch zKgNGW-vU`HdhS8-x8@x=iU9CO68`et)XnGHDm_PtldB1}T8*ntw3kU5#M;0vvD;j- zW-0QPp|=Pd{iSU>;rTOJQq-|Y91gT0N+S6t(r_k|YKN!kQfJf}P@menjgT4gz*q2$ zXYfB4UOHplj%;m2P5A14+qiyrZb=EADpBLxTVf4nwL5Ox)O~o?0{aR0L-&=;fK{>t zHY1I01sE$!%Cg%DFF6JXlE)=X>EjtA&s*UsDwn>MXHfZb+tr~04$sPfGlFZbX+%9S z7W#!SZwssF7c~@U4Twu3v(>HWtJT2wVyN_)Fe=MDmm~LGmw6R^HL?#euB$`$%09zL zGY|cS@UM)JRt4QOAnt~1&b#Pb{2JsuXW;WWBg&bgnD<3x$5KT{IEgVBXS&`8L-QBm zMZ<|xpX-ywepb3w(r-vH)w(v!Z8p~B*t_##cU-%M>qvP#Z*M6sb-Q-BmVsGo^SzV$ zov{tI$HGb6F=$$RW@6XQQ*Rb_-_C znp(!vSVh;qcx{%8YdQ`NjT)}O^~!>!rmw_LhbU()H60Uonpe5hmWz?sZS}#873FzEo;^XySz#_*L>Tk!Lz{X&DB#Me3vIROUh)Ndy zBJP|%B$pAgW(Hq^IFY(TExd~QURAmXWm_d(liuoGxc6|5)@((t;#J2)c?<5s%@eIH z9#;dbawChowXAaP#nwyCo#J?d)p^dDirCvocH}JV$G!>XS-xU$ELz+$N3nCSOEzn- z(^Rpd0-W2{ebpspD}4LP@_e3av8eGnW3dxk_PwqXCMZ{xl}Ng~@&H9@9}vzXcMN*X zu;OBc`+BK-*}`X4#iig!P#Tf3Pb-XUC=#|wh*UT7-HaKFg|R^Bc}tB@`QBCa6=qmM z9a@AJIuCqpbv4#>L6_CQydfqSjJ1WeVA#U8(a>1ig>4hIhZ~G_g>`R;W^7vwjdk>l zP`hO2_>#93Z1Zk|N-Mrkz^@bS`?kTJ*vx@7T^^9Xw(6HwpZb6zsK%DAU3mcNdIwgy ztiSZQX7I=QShY%cqqn5AskX+a8lQc6epRz;e@Lm$nfobzYj*B~r{LTpLxRf(e$QBu zmmGs*rb@@e{?{?q+H;Rc^SjkkwXduU^~Ku28)#F5!;HoVE9#B#QVbZf_mu&83H=c6 zc70}@1(z5UZO;G7TN_lSEQtB`N^o*O)1@#|JrN=JOA z)SdL!MxS-f!W3vVa{jS1x8bpbJPUJrQe_j3H8GC!QpGR3&tij^4@>0e@*v2{V z8BP*n&VGtD=gS$u44y*U#VqjS+a4y}NfRi+n;UN?+{1Xj6Q7sekv#V65e!?FF}Z8iSFe6PAV^B2}N=S@2rWQtr;9Vh`*n% zjcDcg7SM7n^;F;L$QwM~S~;I;ivt$+OL2AmGvdAYEgzo`;BPtpw&Sk=e=F+a z8*B{})n+?6*PP#+;LKQHX9c~?2)i4GH?)0U zx|03d26c+&Oo(CU^u@BW319}ia6uNZ`XxJLSZZ3rwfh7C;9dZ?TdVRZ&5``1vHf{JsMR5?PG$f24pJ&9rxUzp-EG} z4daC}bDMKptukv{)ovV-;`;%dbS#bm_kQ?l|4`s+c8m9!fvZVnvFcRrNcYH&AVbrx zBh1ZaO@M_GE23{1%I5R~_X~IROsrP~JE0pKJAw^@Pq_k6H0d`Uwecp|ne2I5a z^IIy3`M5%P5?3*sq+E<_As39C_rYGHeY1|xd1S#1t)>}IE_ul33Nc+V=hKldN29u? z8nFOvQjkiL(oXmjrW(qK_#8=Bf-i;6WP~eQnqi5em1%d2_uF&ZsJ^Owcs@jZqVvN) zx9k)XBvym7TMXXjQsVq=UZrY&j8^;HuNI;G*^jS8tAm$B)s)o03Ie zgTdQX+gOWO&r;*jHmn@=O@!me`lgVcAF+icV+|o6F*2ge$^`55!Pf^DF z8{+GB@@%gROa#g(7SRXRlm40w(UW3~24D}^(ta)-S%P3S-J)y8`*I*cA#A@nu|Dlc zx;JH0V%tGJfc3Hq2tbYVO9em?om=k3&Cv}bg5c>@V;CLuXaxrqx^Bu z5Sg;e(Esd@ougJoZAu=X5;3+}0VUqaeRwC)?+!$?(wm~!twqU=?Y46hy(y*Xo{>I^ ztxohd7t=Lwn3WQ*!`J||1JjXc+n|=>R~Swf#r5e%7RPpJJHLy^tE04ABM)?m&tt7#}klzI# zL?*lrS)Jo=dmwU!%ClG<@i?AIZ=4I?#6+)0+?zUq&NL^qQyg$<8?~}=$PZ-V=^1jw z)Ox}pE~x~UCqsLUM|WKt#c+L9><8kX*`<|B4GCcRBoqPtVm5HF@;(&5z}e`l4jNUD z5yAjt8|eoUuipqw#{U>y$3BI zMm0LH1EhTFHuX~-s*xvAZ%l{WbgG^+p4uUHF-gt&;FmrQMk8D?6A`^9J5@@YzZ|0o z>At*h!;H^~O-apTgoS6KZ`b|sL~oHR>1a+r0@J1m?NrV#6?+OL z!U)k^xwJiHQ!e#o^h0XlvH(}QUDqVfa0r7E&RbulZo-qAbzY3_hW%gxNZB;8DG~g4nm?kS zt5m>At;Ra%1N;wt_lQ*)48Vs)-<|lr+S-tu+ozH=uc$QMb}!cZUU;-jxnB595_7fw zPF$C~S!?Rd!m%3@z3Qf8;@WucH4bBv3V4X<`fKFpWMg}_v_0D~3)|V!cD7>* zw&zOQa~+egy+GPt;7G&vJ<|3)4hy#PrR{vjaBMG^wwF7GVjG-XxPF1dfbEsi_DY8q z+fHfQ>5yZ4wY0q&aa4@MzVt@jYgZy;Zqm2JBlO(#)GTyv7K;C8_9@2lUCl0d=t$Rk ze~m`#*2(HA>VA1(VpE=L1*bzBEr7K`tx16x=?qr)xxHHSg>{F3|>El>-$Jv;(7&^N{RD_$iD}&llM4h@CLAQhoBv+54Q3b z{uyoc*_-d~&wc}QAN)42z47wDCQF{(JGKk_xYHO5Vf3DL&3Bnf{NkrmWBAMP+ttE) z`P}4fJy4ZVw-7nqgdXEui-R(UEbDdWfhy}7D1X(PYLok!LgUdxux#|mBUHPgS-2;r zv+bH1Dp+Z<=4{oewwf;RyutglAw`~|Z*#ZRB=*k*+jWDR=GSA0<(^h96rS&D^lhjk zMGuxEjx3p9D>Qbp!ARtXn{=EN<18WJ2~Cz+*R5KAGBCG2q=H%x@+Im~ipNxeSk&E* zcFL;T-{7y6{2x10-xd@0m@wa_1~ig_vCPK!kHCLmV19^P8Zfpu!W!+tICA?ch@%w! z@@N0K$`{gAz5q_z&ME}U4d`7$rFcky-lYz>fCQ+ej)T=}hX-T=SOA6j3L*7f+)1`f;yTsC+Sc|0sTptXIZDR|`d$ckuapVsU3i zpOR4Vqs@za$h68p9&3dyxmvUtnbaGR**DoK>WLS@>;B)zPVm{1)3AcD8E-@;NXLY5 z4BkE%oStrhPtvR4IonV^7Hmqh-Ex<_i``Ei_U|LF-0H>po0}9>^HmD6gjw0dCwnP; z;WBG?&s*C?#ieVAFf*JQ8H6pr>1}cn_pjpXFrCx#%r= z;T(=3U2|6gWBpr!#aCZxXioqWk|Q9`G(+_`Ggu9@kvw&|@JM$ueEt>}ty3Drx7?3y z+=45WttWQPmF)NtvxGRPmY)>2v$KSMp8?tl>clu|eOxeYJ*n-)Fk1YNWk_v@Wk_vj zC_~)YDNIyrhp-Mz+9!d}ze)dYaLx{>Aue^v!JQ#@Gw}AtnJunZzCnBgw&N1av0s!A z>vzw;CqS7f!-d_Vg0Ba@>agfAFfSO9Qxqq&L38KRo22+$e{DSfNvqQ}TzEl*1&yo^ zLR=Ve4wW2u$kWgVjw3~-SifbBJhK6_`3d7i+_Eq)j@gY|K7W~ zm6?oVrXMw=n(+oKZKcnMG3A%SC08kD3N5Y5aA>YepB!`${xtxUyFb|idIt1p7bBWQHT_Lka z8CyvUIf&-DC8>3TMq4UXYw^LmLfm%O>S|CVqqn;EV; zUrTXdc@_r@-R1Dj%jK(LeAb%2EzIP9LGL&k(-jv(-)B!Xe0=0vZRFz~{ULlD%*~AO zv74eISQc&<&sxH2Pf7|KZ5;X`gC5VR{6evdvAkgH< zzLQ&%g6*&rWL87)0CaWr{wM+dVIc668LF5z1duw^RMFyNS zyCVq<5CJiN&kvDB*Xi9IlHQ&60>{zYd(*9%lpQ|cwp*>`taV>G>d<=R3iI%*VE8*< zzGNZL_KZC6eT2WELTxI8-$&*^FP&{N2``=vB5OsiF!(tj$m-lcwlnjj(%Px^HoO{& zRY8XZV>hk3)Ed-493A_3@0-k?WUYOcbgb#dtEfSC>V^$(w9-mMemClG@|g7{>z$}Q zwM^Fcw2W(zL3Q%|k%;qA9V+7eCa97aFe2XDOLdecUFixKx2cApR-kx)6dN3dc*7{X zXE&m_caERdtM2=~2G?Lxq;q-(*y%FVrUDw9^zKrC(?c02S^jez@DgYb&|aRd`pI#e z_eJz2c2W)EYAgf2kHQ$nx|8^KTzErv zOMgc(@nDmJ3F~>snSFVed#A{C?1cwZZ(%1;zQlf9@pvnkEIU`gPx-W4Zb7?8R?237 zw)Iay$;hooR{sXP3v%T3-6fUvp@A)!10Dk|WITVaa-{Gyj&}J~p#{1H@QC~n_J!e1 zgnl+_Gjy`vB4v?;QKIXX1vMI%ENC^w7zaWAXo0w?EYtAabk67vqR zI6La6W2P*m`F8YYSnHOm)F*S=Wv&F*@zSNGx(WM_>MSuqi!ZvTp;Q%&Zs~nXOW7dl z9v7`Es$@cb)-9d^F0WM-at=Z-a_iB0@l5W@byFO5IsJipG0nWBmCZ07Em~JtSudWm z?#P*ORLgg{n%B*Q3e=~oeFOcWx|}rZYhKrcBksC=MDsfPd-g+&WlHLjTxK+TW%jyU zPjP>fpkZ=vJZ21T+?7yA()h|45Vr0g&&^b(X&uIRw0SCb6dUJD;nlu9m%q zXbYbz%I=bfZZLz9!-ICTG^L$2=K?!*pjsPrPFMELS6;3mJQC|TP<`3`GCW|n-a|${ z=4n!IjSq~rg5QJnVSVHiACgt)9D|34J1`$KhqfnTYow9dGqEX~)P6D#pBkS=L+j=G0@89+0@ z=YbYC=USwaT3*#CNso+u4H*Y4V_7ad0cnh^7Qzfor1wC~ajX$1gg2gBRQ=@3Hzvn3}KeR%j;Afs<#!vUt zou-`1b$wnCsAYj|n3e&ay=-RU1V86`ep@4W_-3D(rkEDPstl(N!plH)O(^r__6)wb zVlWavco6l$X1!JI$3^OIZTN zr%z$UOsvg~h$kGwfAEY+TYJpsOWDlx$a;_RDWrcFS==CofY=_2_Bh|~2a*q7qGe3_ z9Dgu%sLwR7fnOQG8LD_ZA)hhBsT16NBEMr~~nU+^X*`8Oh76D@0 zJ-Mo^>RYEYl3J-{5{JC5oUs1=hJ6(Q;}m`ncAftBt@Tjnb;9=}v^DO}VqLksEy zYHvoy1eXz(x@eEK)VaV?C*6VNKk+|Nld{h_=Zg zkFb{aMC~3S5=YrFP>EqD$o<;>jy3OG>3B>H4I@@Vcy+SU#7N_;yX=T~Fe6+zvY^H?jF zXLPGBpORFIpCkUkDb~DPs!8t3>b<$7XZ}zw+RBtkC08}WCd&Qnlt(7YdZ|}GFggh%i+sZhSC6JGN9a04 zk*WT#i@5={=uKIcYvvCRgvAlUU(Tq(t)6B)92$&EBi;tJ8@1T^&7UC_LG5p`Fh#8% zV8u9oA@h9(THq2T+S?PS)mLU$DEid$gQ8{6-})HssOxptX+6#eHL&czcR06_o%pm{ z6*|qWDVruHV&+>8eQeDDcbRS6lJlD`V&b9t*1#UPo{B!v%AhqaJk5AN7a0cMEnlxO zxQf>-ovWEpT)e7ljtSQ-_6=OV+?u2AnsfR0nN2x(x7__*!QztQWx-wInPbJjU3`7} z)mGHmQ2uHwo_CFQKzVhls5ba=*q&hVv>@&uW*bxBUunuoKF(g*xULpkGmh%`F+dg& zFUfCi8W+(S$3=hYYU?@^a(6B-%55FEdUZptwFLYd6XLoCC&&Z((BSN?VsZx}9a?ho`vC7c*vOu?kkipj{qh&4@3+0x@DNy7gSNeg!ZFF}5uKhvAN4 z|D$1r&5DtWl2WJp*a3wl795f4AUHaLBc<<4U2L#4cWJ@m3k_*KYEp4X_ObBVWP(HL zQs>LGVzH4wWrXl-@6fzWz{l**Fa}=^4MFx}bpMuKgS6kDp~wCQxH#K!>G&slwRuUT zB9*zqwF&I6E0Ws=u7v5@AATdxJAwSN+xxCettx--$9j8Ki?U4}mX20G^^x@3t$s|B zwJdkoqBQ<1<5H1xkAQ)v9#D$%J_c-9om_PZet~yjgpl=L`?=M$Uyc2f|7-s-96#tn zen{_ca_Jg_>iMfbmioqwL%T|M6wm8-|9VV6GjG?b-J&6XsxL|S{n0QVgK!2H3rRiJ59TZnO+knNrn)}D(X^N>a z=x0jVu7jeJ!CaR=FZs=!nBHGhJe|W_HUed{9B7toA+d_hN`ak07KR~Xsf(=Wokzie zFh;&Z(V*N#D6*Yy*w|Op`&lSTxr@17%viEr_wk#9^2Q~YEw_c9hVSv&^aoCpcc``Y zH+f5j>$15}cI*aMiz`$^=oqeVN#dNCg-}>^8$axeja^|Jb^X~}DW(iw(YPLn8;%Ph zkC^;PQ~YjMTWyEEBdf*PR`n9l=Y7yJaPWt!RE@-6(|O}uZMc>q7KG7G%netq%-b79 zwc80%$C%r;u$Dd0d{Z{M8KCDp4^`8Qez zBR?QJgvL_pdq;rVn&qPRQSV|soY3865Y%z3R{<8d;bz1^mL9<83*y&_lC?538McY> z@;@-YYk_t+AujJ|eAJW&_Io}N83DohKc9C58FtI{b#V+6008*ObmUJ9gZ1&wcZ>9HlA}=%6YDREDdHb~e>doXh1drao<#Je))VC6PVI~ZAb z?S64W_U!h>{d4fNfm?E3-NplnLuzbu)|>h7!%szI@OLoQKb3zZ_Pe)=7wxZa>f6LL z>_UF)0w^j|9x^8ky-uUQ36Vt8FPPwPSXofykTTOT*1H;cvYa0TLgJ&$ZLsUC?e*eT zg?`jRsLeXyjQC?f5j46p=s8M7C~biZ8sG*sH?7 zDSOgj(+2398Q-WxC&iP9hH6gqNIu`K)2-66^y{f$cykkc3CH1U_z1WtM)=Y_VPo0G z1Z9f+xbeWo6xnfO-^LS0AdF#msN2wnqO%g@3gzsR3#I3&I<2e# zS984*6eUdG@07{??uVZTZfxDg){WtfP}p>9TWNuE(Mc#{qTbU_%PZtUoSf;~D*t+; zWh1x4x2|H0$s^E)<` zLu=@3>_cyw@_9kyMyxPl>kWb}f^o(0Ttg$T|KlyJXSrr3ZM8qKg0-y-&}>EZr(I^; z&ZHIkTScc~m#FM$#YnSt-i)J8{&Qm^>@E(q=52*)x&c0``c`pyxu%^(hK6MUMmFtd zE`z9L;N8<|2N*+(ICM`{-3NVImTa&IU8GC$5He`(%wcFDe~qht!I#XFflq{q8|8oI z+Z=|h_`%47H-1M)*^gk|4n_z^_nHJ_cQLY+!Oc(KO=Ss2Qwalv32Ty zw+;<78t)PhF{7ECgOTdN;k0&`zpNtaBcNQOR&gatUId>Yt3gdwAM4W~lB6j_lx4=^ z3(1A*3!It(EACG5>r5K)*(`7;Vc*eK8v7T|)BBZJgU-SFQrT}u4rZRT&Ga*A|MEj; z(>`FNnc-Dzy^S$?!1yZu5AzZ8>GyVeLI>U=>@nyT|M@6Be?J&`^Jw~aB4S0gs;C8? z#BUKV*r%OBDa*&f^8LCRt6UA0Pjx{J{}kQ()9_&*ZDEGdTnzs*9Nqg~*eUJ37=9=$ z?^AO?QJ2%q5?xcX)9+T?9di);Sx0hCpf3B(WzftE6j)H}@4|ON-|f=(TNs-#U$LoD zj0|NHn8UPwVXRdc7k8j^zk`;a9##$cBXwv)*+Q**hj_`JVPh_DbthvUH{sYzc1}8D zV-Q|9XU-AScP8w*>1@`>?0P;nn1S-=p1mgW;{BdADK-xUtB@6+zC_T zybC=Q&?u+u-%CI|z|-brr(K2hG%cnKOquoogY1i8oXoSgA`^_pX~;h9H?S|rgwFXaVzt0lE)1*Rb2)bNPF~X=L=taHoqv)zVlW zMUCvlonID;QRf~G9V~*fe9`ZvXAJB20?c%4Vl|ir%8iKDc-{z-Br$_ z4~n_FMRNz$+fbhHzOjCIh46gTUSP94=Dz&7`~KndR4<7SIgbZXTN^fxbY#~V{S^$N z`Z(I$nsb-`FD81AZ0cWdPO?+pC6#jRQlpM)#=fc|EM0M14(*rsG_S=y~A$GV_4Wt7sH#b&{Hs}MR=*&2VV9sLqz{q!`{{L~}Hn|9GG!4l{fM{1r^hcSovcs4ufZ2IdrSeDa!R#(FEVZjccY-zA2@wEf?QO<_&r%+lPNdeP{nYneRV zn3*j*fXOP+O4~4^ zwWl?DwLJ{(h`8%sJ6$oYJ+(chJtf3|H4$D<+`p$a-b45AX^rvFn*v7jMwctTkHPFX<)bS zkMHQy>(=3y{Xk@O#>X_$c4s_rd#tXHWx8A%W0&(QU~aw=XD4i!tA^I_496$pY}tAV zWg+>5{cNgXhi=Csh#*6EsM<QKtZ+oQQB#ncqd2MFoEU&nw#W7qQFfoC) zJZfW!$P&I4xqgc^GpV|I?T(aS4%*c)=;N>!T?1o{3u+pV)oeiN*;KltZbx$&<-?&5 zfR&Ms(Sl8zwdxT47!5r`MzC!m#(3HqyM@Zb2o^B!L?YvFjX2j01a55O5s~TmQrzBg z1enPbO@fEkw{N<=V!7RdRnKNF&O@Ffueib9rC}!|?Z_5hbRQA#=`bpR_w5*pxN*Lt z7w^!trg*NYm};oR7uPsknA1z!_uIKXH}VhYh~l|LPPz`^uZE&7qvsXjyrQ3+H%2<| z3Hvh9Y>u9li!Hj=G3mNPq~9n0uixp8YU!7qx9=F=m|!e&9ubqE4>8a06{oqSwbR0t|vIXFtg3;V_UE|-xv~uWF0%;d5*~9>4 zC9{9Uo6?UB5GKefA%&Lm8d6h3D>Qf9if9IV@u{n)c3AJGGIUBMNNi-Ys0>ufcsvIq zRJ)^3(sK1FX$3{~@H4*-7~Cv>ujuSBH*TFbt()SEGJiYznLThse8QgF&y*a%CtbO_ zg6bKFS=`~@_90Em=v>tC<6QPC_P~(w|CJOIAb)`;Z^gulx~C3s$U868bp zBqUZ#>Q@p*@Du$13LL|f<%|DTIYuQ}umrYt9v|D7GyHgKY=afKe@hT`x)gb6@Q#N) z3I6|lhZ%l`JqC6rv{f*o{sE)cG5j|*MI!&a9^2F_7IdtdrwI099MJc7lt2&du`%$y z_lm9#^1n}H3MBtKMXfjYpMPUmaG^E#x;hMx<|YQ70G6Y%0G8zJFU9iuQJybR`?2-I z>POTk)yLI;z<>5HuvOugXgiQg<7jkz9nqBPqt!QAGtXbY(^4h`^vyAiiN^SV7H>1# zAJ?4J7-emPB4UHmqo^mu=S)7id8ju&7~d4r%oqh|>tH-?l$-UWHa>iPdpHglS{ZQtayq*~<>7AMLDM|UJ3{y& zTAR0H4yLAEh&evx9D2R^Ya3vRP?rtu@eNjMnkx^@KllRa{ccfnCG zif!Sbd0`ahf??j$XcUCgw%fiTS|d?hg4RZIc)^(Q#4wi!YlIl=b6x*aa6-ZYO(W(D zXfRaxZLm6i?T^PA@>XQ>z#)tnYbuUOb|%IO-USw}uQw<{xmxyaRrb-=eE7@14?h81 z&SuK>3sZKsQ%^1#o@^a_w=Af7_9^>e_C~+EX+)-qwW!CO-8NZxoc)*wMG$!w<6Qp=_p$B5YCBwy(9VEqOtr|Wc)R< zh8iYkOvM<syy31%k0@E2}>51 zSpp;(mPv*^T84xiKu`i$glVWMjI5Y5o*gMV2wzj+E%Of z>kLcH3gZeUw4N}5IU$hz_j3l+_W!Q`y8eqR%$YN1dCz;^<$0gye(pOKXRE93cATxG zaREF`S1D@mid9#GdaRiwpnu0st~BoS;E zbdJJ(&{?b0oLhU3qGs*fgok!K^qcITBj23~?iSWN6txXY_-ej}?VijPNG4czOk8xJ zRmF6F?8-y_2Vbl3^oNE1h=SQ4U6iFyV`!5L82~QWYEegp@xn!^?6og|oP z&@N@^%tX=C@ov*$cwhyvQx9^HpM>?lCou;O!DBED+$QkffkBaxbwCEfcMlkaENHa@ z>ALu<@_T(IWMWaa5{{@E3tVez`x}?&I>a->gP)Mj90;2R3W8(je6oWl9+fJ_{OOiY zD;;t+@~7oAUa4-`exlb-Yn{311>XRx#z58jjERivLZ) z!7_eM&WCn=RT-4Cz`wf9(Lxz;rrR7XiQ=bi4$&7en35#Not0KOd8wWH0FqIA^mc!yFLR?Va>KWrBUyQB86-BY?d6dru5 z)Z1F=Eg_G4TyZTN&5XGohu#Y{hGSW>b@m$b%WgS zjq-!)9+b>ScxnOuT{G#+dVRdj>C#$8gfsn26(U^T{cBo(oaR1 z?*Z2aWqT%8VRcqSb7aK}HPStkqiRZP6Ma`gldiKshZWpvhR0l6$9HY#p%voT3jYty z5rs~iwVV-G{V{Qmwr<_LwqKa*GTfg_vuqhSb~f+b8SRd)dsjN0J;s;ns{`U>BsiF& z>!@Xo6r%T!tfTeC3~ucH=sJrqpc%KHd<*$#0SB^}tKcl2SraH+ zIjj!PU0mvAM&}eU;=}Jp^si397jQ5)K0xc=D0%&Bw6hb_lvhGGuBFAK14G4_`onh( z9FZQj536HF{|x8a-!JvP;;6y8{h0J(5t}nvYqKl5*E6Z^E8(nL8r=ELeQ|YrD|EJw z<+c{b2H1&ohtyiS`lq+AuEW?6BVV1~9`%u@`b|v)CRddA%`@tRL!N0>jYrs6Y4VgsSq`B5RwLZ=t zQ^!ux22$&ykgw5J7UM4UdYvDJ?6#rqn7V)XM%HWx$KBAnH+?nIIONwG>Mr>rwXxu8 zZ=%gkIof7daRob?@I1w?;rnX8f_fIzQ-lNFPrN4wb31z)9lqPjRdo!Qq+qYyZ4T8s8b zHfvN(ntLz$nFW1pYfn!wFBY$TgQ+GNnFyYm5#ODF?bg@(ca0}JIxS{nQA)r-w%8_wW9k` z|38PHLTk?J)M^hQzoOI=S5xi8yL?2`#c(?RnN7K9kB1~XSZu}_67z5j;`?VejjfHs zw*7||s12lfGJT7O@l*J&{c1RTf{H1p8lX|Qq1gA~`a5m+!!?YVUn{>oIa7`-9o?ct*wgBwYSs@Mf$?$+Kaf;fJ7WKp@QxeCx~WO724mG|m#U`JGvNrW zH7yQS9?Ml#ELP{s%UP^<9xfjOWo>#VsKKI!U}_!e?LeeQjl}k}q7%9Ht8cuAbsdaHa^!r>Y@gJ&fIASs80~-I(4h+M^KdCnFz7hb)rK{1A((Ir<)toj;#}tI(Mv zCn%cLP}PRbZH^5ZCg}Wcf?Xii64|2&5_W*$^y#F&%UGts=6_m|(c?q15`pSy)9a`m6TqT6LG5$9j;DwJnj%*4ljj%%Ix8Ig)qlf^@{0 z_W%4n*&Xfq#ODUKVzQ5VPaO1Nv_Y>!9ULitU*_O~*nic#WL%wBw;?aNE;4^6V;n0r zaH!!t(e-S~{sfhw4hoWD`PvjW-o15;G6gRJ5<&hI2V! z(p3R9N-`vqYhE&^%Fdi)jmVFUe{IX1QEsGvp^P!X7*bd0$XN+Az zpuT<7HMDMmJQqa1*SiMQscJT?tI3TCyoR2bSl5KJX!N=j9swLPBkp(2NJ`wVs>#Oo zZr9+tQ8g4HQ*$-Q|2yL-t)A=4ZR$r>(-^4HVn5&J7`(sKU5fSNO8-vh66HhZca~`C zPUJ2Ld|FA0>T3Q(?jp?YWF3)h^kz5NMjuFB&efhIx&JP6oK7a|NC`&5JJwO&4|YZd z)G$kHF~&=S>T;|(l_Tn04K?5cnvpb+lp`eLPUD(Oy|4w$-kt1p^5P`gQC7pUS#4$6 zzLEHS;;G?vLr@FJ!5Fj#)?ZpZBsi*WaP8FLS3(=b(yF*0`p})4RRpL;XoffjF7wFK zZSHyINFJi~^@48qaNsAXu2z)un8TRSH0P6Lr>ZSMAzK8P&UA zzSGv^`HJG{nYBibqi_q533|arbJp#-CStJwMS9fa9eHEt&8VjMnmLW1gEw%Oo^*qwl5;%j3)caHg{og!lgUiiv& z;Cag09$xosqg?Mb9_RcX*FysfebnsPb_>nZCS@p6vH3fX1 zvfpvdZ27&s()xf^-Q`kmKpx}<*c;QVLxOvHG4EUSvZwODkKguR$45M_df7u6;S$Ar zzkTghtW9kAKW!STPPSS>4a^xK8iwf9Sk3Cp3WeH|>kD$oAh?m!}No&&aEN`$4AaqsON zZ?yv(ySnzl+s6hacH;c}F6dNP{IDV&jX#t_)k;X8kw6z?1O>!@Xe6~2XZojVPSGRpHw=r%MpRXDOJWiDW&Y{!H*c|^G zB~Lk!!!{-sT($+-M!~bH=r)S=U*X@~`dDI034J4OpY8a5={J>1QLUUj=|O2!!C>En zGH${kFqt4)2`j_%_$VLwQX+noB6urUK(pSRHYDt@L#6MDlPT3jL3F3Bw|8 zM>*x+`olecgx_O<%26p~IYtV*;WtJWqeX#|rUcekq?u`rS%@{|kTqMACQ4lJ-HO(V zUsP;Ks%|)(3l+|m*zSR!{iQ2b2~}-Zt5cuSyqtU=gZ#v;w1n3KLB16Hr^JRzqvB-S zGRZ9KQu2NeY-x&a5uRc?;^eo&+zrMsA-KOc8EjTNOQJ^oO-i@M+{WB~AByk3yD4%k z@giL5Wev%}5aDl)0reH+us@x}1XI9;9L+FL3W{hOaC`Z^{bB13V$)oNvt|Nm89`K# zA4kf|dk!j4O~$##Ih~=}Ytw^$GbW~Cy*F_tGdgun7IcvwHUZC<-5J_; zjTr-#q%BcU_MFS6!!L360{jtRUP{1qesztVg4k@fx=W+2&Hq;iJ2`ElVtfZ(DJyCY ztqaLpN|cUwXl(Ac8#oH9>!-G{@nNjb~mp^$aAPOmBK%ks9UJL zKr3FxnIAGd5uBX;pkxBh{+IqeQfCnlT+{f*bYuk0L#|Gi&=qEeH7DJ%rna8ht3e3*mL!kE$DFZo<*HZ1ZH!bKebRt37C z5&XqK_z^tC^#;Wh&G;*bV?^>ChKcX=0q>pO5l|i#Pv$wo$N#Z}P-#q>Nnj_kX7U<; z4J6>q0nONJi1^dUP~cGGX;@QNXh~21$${|Kr~W&4Vxf4lO@&fX=0pVFat6NLJ9pe9 z-|>62_nYArP)wu@ic(~U5-MKfk6k+1HxPags(JqkZ;-L^ceu0jfHGSs@dv7V!A1xa zMg%*@wNg7s5AIpFcwGQ2F$y#CD>Mr_Ymnunj?=G8Zq~pvScsN!$Y(0!GUEda!A7YI z)NjPPnX3Y)omY!D%eOXE<;Gy8Wkjj^p^o>{wiW3q#if{|48S4kDPx0_OjTWT5OM#j z73d~d9*5u`21WoQP^!{Y8o{j|l9s@`i}DFepR7z;`j`=|>3sh`5s!#!vLV~0)e&t- z9L~AN&zk^Tq(*K){ljL+O6vihDgAEXG?y~U^IJ;x z<#GY=X%%bz@Lz&!mV=iPM_RkXFAb=Jq)4oj{f~Lb0WNIwH?bxMyqf>&_FF9L=Hv#mb+M<>*O+WTk{Ykt-WH86I%JF_E(?-G5&IWFxosrM`r$EGhC-$# zu%65s9_^MC|<1jYpG;LRN6Ni3My_X*Loy30sO=T9AkXn z)EWBjD&=wK7HBA6Tlub_lt0x1yvo3zMxsEu`7!>j(krgWy*Q)Ylmlgu2cVb28g*js zg>=j~H_OSpJ_4hdLO@$~4HjzP-()7({ETCQmam{qa`0Qmq-puxUhk($T)KsPZ1oO>*fvUPu*( z%{g^+xJ!Rp#>dOEDKM#cd*!Mzt(OvyYfNZWMu*TDdgiJTHKE9I2$#cWz(_j>_==T? zj6c&l?4<1PpXrAelo_R#Eny2V-$(VxJ6`ee4S2^UBRgen-wc@*Hmwk{o26>;y*v zVwPC{I|AcqBWp@r&GhC>Zza0dO#`A1TJfy9xTR8GzHvl5x#GVFEgW-Iqt_?;uq%KP==b-kKA~^*Lc1e zx{Yq=k&vbi<#>$2s6lzK? z&+P@{Nl7_tQw3Jo&ord?PF}VGU$yI$6`6iG(}pX|ie3tR5*)|M9AX3D%~bhKYfMc8 zaxEg~=afFuXXQ9bC6J5Cx0>aANSa#;#48tDg>QpvDYlv&;fH0TmLd|`;cBM(8MDms zfW#v%5M9N4&PdI$s~GVkml^0U=IVzo@@~D&mF*=9VXkZ=oxZUL=t0JkN|My_@ew#l6< z|LKN+D}Qe-9L7UG`Fn$+V~%VoeAjnZ@JGZvR#-A4J|k|rL063+<}El=#F;G46b)J# zx%lJ#=w3X=Zn_h-tQT)2;`pmLJ_pBNHAJ^i4byKoF{h;i)9FGvnS$xC;%KLYSY!nmp3eQUy8yQ1H!Qjyrva1Jx zs^G!cq5xw{6_C=gb&3|g9+tA{a`=Dx&SA|KUpohJ%jg4Y@$Wa3!n@t`;+U(Cm0!G^ zB+h3RG7mBRL-~RvqeT$+0U(9!m66fmJ82Jh# zS<`=9DU%)dAK&RNS!^ELg0Y|G@!`mmd=-eVfpB|Y!WXtOHQFy%{&mv9^;3nlrC9=J z>Imk@d&91;lQxt^c>NBp>BL(Y1BRGygS;2#gt}b{i#_yj%SokjU1-nRf9V z7pw%l;j1|Qj@I;v|F}#24|h3u`!02^4CoHfT{N;H0wdPqJ|BXill*vjjwQH{+ts&j zl!39mw+@IwGgC$R&kJvD44T*PzQlXYYo5JbJ2%7cNUQP0f3`i3{o8=PFTuBF+jE!p z^rl-kU>{?7${%HUvV9xYqGY+>+q)D>D}T&>62DdAbJ6Y6zG8h8=XBVXV?TOJ=KakJ zMC;7m_JZ@#y87=-F&Zx+mV|e^O3=s|MZB%`#N{{Rw_4)r?XJS;P z@n4F}KfjgdpWhnvC)o_jWo82g6Z$4%DF>ym&84&Hor>>L-~HFS(|q$Bu-45=f1cyx zC3tON~??j`!HIpRfFpILbB|M_A4l`5XRNu$HJ zfz2nU97kLM+SAnU2Mff|q=Mh`a`;@YdYm>u8omSJGwA1SZ(q09n2 zFMjX2LB9h{A`aYS49H`~cp^fb@aZ+%WwiVdLfT9y4MaIv=nz3?lw+#3P*_(U=BoY1 zT;T&-oanenS@_HSN-u9pDSf1Luk#2A%NmZ*g-nEv5B^cqO_JP(QqYEwghuP5t#@L-G{&M%UPta7YHp|y>m>vTa!~QS zOxk_Htw4edGRBD~F3<{3KwiAY^^~}QuRwoM0?(u}fnnu91u|ADV70)$U@nK*-V87h zL$8zhAnS7YhICT08Wvn-c}`?eN9ycE#CsJyqJGKsuzTyJgsQJ9)uLK$hMhe!54!T! zOXX2b7Cbu-+v}yvD&|!va2N%yx)m7_7Vz1Bd4nNcapcEF@=UD9i6KFUH%~3EK>VaF z8ms&zXmQk5GLXA?0qZwv4JqQ9Hd0_@F&jNEulGCQVX(?p8jGmiGRK>^QUz4nV!I?6lfaqhq&pUZ2&JF^6#g-BX%5+zcLS)Y@tsmz|(Y zh-r11kac|?bADkmW84CSvpKi{+LX|32U>|g3^o!l%j*yPlavnRnoO&|94?lqU+{-- zgjZl|p^$cX8Tsb>ntexelLMNrN|f*jEZ3<Ug$72#Rk337HH74EN9J$tIt-jGgupWHO{)Q-kI=vU^G47c6vT~GV0?G1Cv86 zGtBr2ezNG#!z(s#C7#V{4$}MVu0YM5)(FTdpGsLoI^@1^of@zXDYTQN#AQ&n<#1tbAW>3|O_Wr3rQ{8k6n7=& zZFN58PXSIKrKk}97Zwec_^}CU?wkkTJVoC+f8!f0siKK((U7k0IDkxTuIT|8WI9uJG`MpZz2zRC+S<6s0G(I$QAstwoeEDlSNTvGS+}+HnIr&A-7me`!v5c7vi)J(_4==*}cJ`M1i)@A6 zbTQ*={N$;OC=gE*N}Ti1;y1Uxbjgd>wZ4q7-f?Hp4%sPEyx!Rq>CG)Zb(fZn^yk3= zj+C{ZiigT|k;Cb{0xgw0h~Ya57>&+Ioae(}Q(2&!Wu~5jie9dw>hZH5bhDfn5xGd| zlwOf&QvAr=;&Lea$x&A8*PG^zh`|!d3l}?n1OWrXCBV23cQ=PfFPjxQJZ7tUX zBflh7;1}k+9^`mo96u`Z8ce9jT#zx7=w1pWkY9wjx5-y5jyIo7GerDYd!r$5Kh+R4?*yanAu~~m>2$ZfROLOy}Q^86D ze94dUNBcsdT10IRLY=F&gw3j5kp-+KvwtA$7=RZPE6ITd4Rq}y_fHXz43Ld@TIM6w z1&9@&MRubZ8WkA_Y8=a*{h>ei$a#L-G16ywoy{d=#eU#q%%nd9p1masTahJp)(u1j z6|DI}x;ZYBMVH(@#|j)x8?{q8C->-q3*$ zT6^wD8KI*`fh!z}hWmj>X*m=$I5^lFxzJ>&mh!-u3eIugT1OkNIIrl^A#2S5ZssFp zku&Jr?4W7=MZx=_m4J>Mt(HeAjx9og=Rxnm>V!TTtcEek6L^MXsKP{=mGFD zV8u@OTs1O0h+_-mq`aPw2~g?o+y@Z|aVwrFf~s7I%wWdYY`PqJDID>(owr8$K9)W^ zdP3XQut(A!P4q28F0xlpiT~4Y@GZgiR`}5t%?`CVL!IiF-MMopm4;SY(1~uZmp*0=It}0(mi;Kj3$FLCnQlK)##S?O{iTYw zAIev}gS8cJiTJ}Jp34H0%Xv98IUIDB`55Cyl-!DK+S+Kn9LkipB`fVuyZuCzhoTAO zJ!b zxfIUn`*C&Tu0$`NIS#R7nyJ;RRLyyEu1O)H)P;|mg8QH_l`W}8ri#zC8K5;$2!v{3 z@et&v=z#|E59ph08{2@fDUO^aGY6|9nf}kRhD}8$i(n0vf3=D++{tnkiDP0mze;~R z72`@GYH%RDalpK)&0)dYVU6Th9SE<5N09iBKCfimd5F0)4=RP7K=I9_;QJtt-@B zD$RRKhx+-9@qRW#8_4!~RsvIoY`eL5Gf4xi*#d?lZQx*KtR=3c8SyP+MeUZs*oW9T z>dsRfpFS@q4C60jJXQl zk_mot1$0+6c8~L8Nnr;bjC+5fXL$)MEz)TDj3teh&)Dx)X;wm^v6!u8GvfUVo#~E3 zSTDnoaY$E16tkb=i3~Ur<`ObAXci(&N%9(D0erG<-Vy8I@ir8~BTjBNVdz!W-+|*n zF%?V$$QD3(G_MJPVCDS7JIsXY2eOvfkrk$Yg?55h@=;`0{MB_HEEAV2-$xWf-@_C{ zcgIE#I&~bn3mh`=__((!mHznx+B`BzQXc&nrBi=R+X}tY@cp;=8>wnsGIhHhC*GmRM54d+4(+o(*&} z(eu05XyT+|q7}%l8V3F<%xTdH;MZsHY)5vGrX7u;Bm7amotjSjSddFw_%5c z-l;yr$C##~w@kjtm>RY`kgpF64t}|V-nPsdWD0E|b*HZI=$rTFa{_UiI$t=-lr;HvtUC;4k2FIy6b}5-M$;PjH9j){`@2XR zV5&7~Ts2>xyae>frc$IVyh>(HQiIW>0Vv+vWjvc7Wy&p zOOz0D_h7ey0e_?+f;5U2?)r5UGP^9k>0bE#bPAi+%?H(<1)^T3t!9krruh2Hq1>KS zun(nUG{3v&yz~$})baJoYY(nYH(d(vlcKya-Lsj@P)Oy$blN zSoee@G1a7UsfMQj7K%sF{Q(~<#$4DYBsImG>LrKaAHfM;@GcsYOAAXgOA;I$;yQbJ zlZ?71BRo7tQm9MN*|QOcAbppVid-nBq`3A$X22TD|kPlLhZ zn&2IGSOw(Vi_8RAl^a!5QmTom;=>o|87Y6W+{Nsvk&+BwIk+mmiiP(k9V)NO;lKI1 ze}Y$)GeNEq#u|03WgDB$!x}RRV-c^kIJ_mH6>9HdUrdd*R%QA&{MLX07#dCOm*5q<+D4yqkPA4f zB@>(!pMf=HfdN`Di=onLP5{@d(*KE~@YEWI{02;$jpTXK)u_7X%aPBc$TZ7>MPayE z>e081o0ij(+T6H5}R&B*X4MpLyZ*g0B>my_Q!da3H*M= zKFaYLCR)M&NqY-n^QMX?Ix>ZoR zRf@^|l(nveO1#3Ps-G)-i=16Tv?yED^|W$Tpx&8*`^Kw0v3_N9^!Rvx%y_$a#$^f? zK=J2Im+I_7eE-DtJMy1TiVK4ObJS@$6Mj$&lc{WrhxMt1UW6Z7@`HVrbvZ@8pwc_S zMtSLX7aa*EBI?1lgRh=H6jcA3AFuTPrki8$%N4p<75tl{napWFT;q4Q)Lug5SUZAE zbd9lrO!yC95LuN$Pyz2e7SFFlUjh3SuXIyHCPPq)PYx)n-j#jxW5t-(H9;`22ez)W z_+r3&9EB~i?+&js2xqXG&JeJ=HjNd}x2nCo#$%|bT8H^ZL2(L&i@oJpZUQfxMt*zV{R#{eugzxWc1_w7&mQ`f|lptEv#m%xoVWE zJDD3LZfvmxSFR)efDE+wrOj!$MxRf4ZAmFuu8rS?wuuoYo~cDc@r&CRZDbHZBu<90 z;^kJ$x?=f$TCq&#s%1@D@kBdeB9(Z0WlhA3E|1q+;YlyituX`paGQ@*b0gR@I zkreLIiS@TQ)RkQ<#C0s#lW@5f3yPE73BBdq~DHs5S;vc?QijhJ|;$?QlF z2S!5Y%0%9s8HWFTUm05{e&5Op#QcBq@>IJ@eEg3h%Ch}v4D1yZ_RnFXMD`~6aQU|~ z(Q?lrZ}kAit)nNs_cFr++>L9gtDLjpavrC$|k~e49rxN z0H27}&jjG6kOdYrL%SeaT!BbN`U%U9RJxvt5)-7&C&bTeL%!bb%>#|*Uayv#KhEl4SCfp-_4qazb z2^=Bzv?c-%^N`Kt*j?gr>`1BIv25qOJfQcXdchh;h*w&t!Vi~=BbT=-CL6|ojMj|j zhSzzHANMuteAVlAfO~7C_=h$VasEu)U2;ZBXYU(fO~ESvI^Q>h@kKu4D{{FO*0@c& zIfyZSAf?A!eAOl3{_N)a;>~&RZWpk6pCIP9>znpq>{{j{l?YEeWenY%i0mIJUCxb9 zH|~`d!nX^2nQ^#yU-MpAeTlv!PqMZnk1?aDE*@UG%h$MWgU_~ZC0c$KW(>B?etYYB zEA62^Fs)57$uREQz#T;h@`b?uMay4cRSUIh2ciIutVAEFnXL%)IGC}I1Z-H5q^?7@ z+RrKHWkHV}j8Vh$K9}`M6mqWbJ>bey!G9y*Q-RN1e>2`eqm*6MEWZ=RGR;2+al2}M`-ms$2>1*5xN|_3G2rB6@eMrc$P4Ip zj1UL6xPX&ih&ME(Rohdv)Q&A}YtuE?BjD{c+7TZafwj0|qG9Y|JS%z4BliB=*Vs)_ zZvH73JQgv6u3A;{glR17pq;P8x-W&^4e#*kYOHQ}sHi0cQyZ%yWUswmFa=>OQ)Z$I`o85+3==iB; zcg3nVu+i>4=)0uLNuFTdGV+G2j}IJl)F_$mm@WTA&8NyWZx_v5Y;sRK;NKY&x184O?(TQQ_!K?!kGVpXvANT-}XF?7~|VfqfNJ8Rcz4)cX;?r`_+N+ zDDUgt3LOs*pE4L#v%|xHH~;l+osJpv9(XAZNwZ4deDv>95Ga$c5ByzfuCj-|DJR8l z&gRKKef45FG{sGu@LZYUgY%{do7@NIrJ0^{KL(3V8DQrPJN?+6x20pNFM)4EsNGt0QF??Sa#KS(XewRdrhwn_`D=_Tom zVc}cL4$nTK6+e>CUI`y~^eDW=EKjaoe6*Zu-770gA}i8I2qMhZf2TBlF7XZMsxx-dM>g&skmTXGEI!cbgM<@9bnr1?gZF$kMO;AIH!UP{Eb`ZZ}aZ##hK&CbC zr|$}UkMVj|GUk|IOwFH?c0;*aqf(ux`|9gwK16tjuU)Loo%=odG4=8~b*A4@JG1eg zGONI4)0>(u3SjwEWB#R@nGWl=JA4TGK*LV|-Z#G(gO3e%;H0 zxvDvfVuaAbG(B7Yw$z$6_V?e0KgUd*Av|-~4Bv37`2Iyxa0D_j3Ssk zh6~1zf$GGVs9!^)ao>(#^KQF*j?RlatY-Id;2^vxDdB_65OkigM^Z(uIR;}NM#7i5 zc?>cx7E1=EboSKmcxEclaEeL05m}EGUUg0d^84QdtWcCpHp%7CE5}K7>c=DE(qDDz z{HMXp7YB8MmY*EC{WxI{N}&Q20As9D&^76tXB^s1XB>Y6ibA2}&&_mbeeATEMX$jJ zZA9ySZF&4~6BI-xNhMgD2p7$oI>W!ZX$4CwFvqk42HI6IN$0F{R`<>_q(YaV;%T4M zUZCjXCZfdFw-qkL7XFd^c65|44(Mg6f(;IY-yC4l_e-Bz2X&BLN*3hh(4OnZq?^`P zbD6VIO^2kL1;?a*;ESi8IwbWMu;z)dTxTGXM@Qbe3N?o;Gmh#9mi(r5R4{UER6r?P z&6mOd&!mqEuy?-=Ri19#HNApxPkO0TD{Oa86i%sAsoa& zI0Xz9oM14MJ*sH^=@FZ2rk;#)=+-4WE7#5R?S>~a;(g%GCBq6_d`eb+04h=OtLKlN zaJq!QCv{eURWWnEKMOHTnsKAL2PWSIp2T$2$l;!?PEKf1N1e+PS$?aWRiimo4x560 z?d};K+~A1vu{j%x`VfEZE26&TzRWXbCs*}0a9?&Baor=t11+rAE+h-w;bgJ2Pv10{ z{6$*IZj4&Ic-CUXk>}gp|c0Vz5R0Z=4Ha6E0OD`cr04@ z1L0ZZJ0arkVsI~o{!(&M(7dS)n)hqvGOaDz=>-1<%Dr znWy)ITdh+ss%u+*b=os3N ztQ!OmHCwMYy0Cf}9ZCyYHnrkC+-V!dD^pqJIkw)042jF3e})DH4>~iTrO5IJms8}< zijg1{*-@O)ggNN@a2vL1q#hw|Yqkrvw=TnOBxKH6=mJh^vN_^~B|xfnhJSHGg>lYS zdpY#mP$Y8@_rTG=yh^K~@38uyw^<{IUesok^dW~$@#nFcO;doDxdFI?pWd6otx5}0#2JOp%^R^-hRI?R6(A3Vn*jM zMLiSeQeJdL^ceOob)RBrIoe>ApqY{ipSKZpd*BYeSNoaqno}z5qkcL(q=Jn-69}t;@CO6rKge-3=6(}k?~0zWd{{U@Op|Mm>zoR~ zy)H&bY)XV~?qgUzp}oUCN}{p%85LAzfXI@4?+Uir$y%G2vxeuP?E1WPnejRqLs!xp z($~yZ=@WP)74dAw$iSJ~tvUr;J&b)9(_^jaD5imR;aY)RGg$4HqJx7ojYYfmV^%O6%L<;x9X>H;gbe_72lmCN=gN4D`Rr zurrCVD6u|&Iy;hs`gHb2WJ=}BoVQA$5~z0SB@x|4P3bRvC)P#za@IvP-3NZn!{vN~$p+W1k_DYhp_CJi zyaKHlr`7aqo`WZSV+eZLC8+tPgWYcsDtI8Q$DGI?PRCgCv4r<9Sm%A&nNkr>-YlUpivEp^F-dKq>OtXb;ha}f@$GY`dN zvhC2J3dWft@BY*+!wGOxT3G{Y`vjlJ8w3LCBmAEX4cj~UX)TVgDiv9jv3m9=Onm7W z8UGz#cJqz~1p2cfUiPU{E|?@+Y)o36a}=y2cJy!TA~FcMK2l@99BL3XzDariYG5ZS z#*%)LbdoOtr>D__sKiZcWA7QJrG)EZ68x0~zUs! z4m=$5@`;D?CUX3nVc%Ex2K1(e-MPBx)Neu4Ng5!*lXv+Ntn z+_P%ziYcyHtzh2t<_FsH&2i#XJq>{%MUnKWYO7g^p!Qe?r1_ppKZc$eTq6s;0@$L_M8@ST_T*pk(W=SDZt2t7kQ-4cVbFdcCn@}>fj+Elnp zD-PV?f`z+gh~KqMSd%UcY0`^hTX~EoqZ8uAzh4}`hB3mQW!ff{CV(v=Veyg;zM6H8 zrlj>tVC|H0EO0-iTtL)qr~1` z19CB+28w<)Jh{Wfrx3;H4sQl7Gfw;ljD=9a4fg<%nt}0FA?ZLW58)T^My)LBV4n%Sq^Ds0 za_3duPbo5jSgQlY?2u^xR*c}Zf2(3R?YA~wb3MiR34x~y?34CeTjgK(D`LTCr1{CJ zoMNj(f$Ud{zqtr~K-iAM#NuAdlMJ})&%-md*w+NtcS1@Ff!mFRmeLKG>oAR9r@x73D6Vp^eLeNi?%! z9C#5v$7hi5v;tS+aiypxF7r7*llcTzbewUi_$aQlKJXZhXSMmakAE0;VWCxn+@pgy zONFz{O)JVY)6X<;nMEzdWnk_Sv^ZC2DTfug3?&}IJak69jQS-s0gi$n;k8@T7fj;n zW@Z8-e(s_yd(>;STKsEAI%@gE`~q2STGTT9_}qCEP8{46;+|a=Y5ZOURKGr*$MXD!QKM^JdjLxSD%* z<;iO~n!_3*a~L8+Kh9eQ$-*0y zDgO8KC$(}Jw)WM-Fe4fdN@w)ihFJEkXpjVQA@! z!WCo-h8I*~edI_`0x3n>;5y&yxx8OtGgzd+{4bC{f;M@x6nG&-iA3ukq*lWacrREt zp_8+H6?4;t81cmp#`vbxs^3tevp`kUykP~|f@-YtK4bj8@51W7kEGA41_#Icn!t8W zZDqT3(#m?Op(V{)h*vopZ1waTSntb;(?j$V1e4&8u%c!gh!y3w_ke4klRE( z<jo-p~SjN4%YY*;~OotKc3 zjkxc}*ggZBgT;!T;=Gfg1vws8!ex@tnvoVN2D-EMnFWalqsreY44ruj>Ad@cYy6DE>L331*YKua*E3R zl6Z9QQDAb#74q35#oUg6eL?Sq1p>@mlrF3#YnMDfv)9A(qvmwPwOeY!m>eVSx-ftd zI#6DUaj~_>-s37j6secKo$ZNDm*aCY8ROhemNf_l?b?dHMo1&37$+|J)SvhwW>gxT; z&_P^s#Fx6x>x=g;Q4^CK$H%+ly|wZ-i*56h@g8%}mbGTYniBKy+Y!dC01}?C3Q4k6lhgJNlxx~ly7Q*nF$N24&yDcQV)ix7 z#Txcf_{fcN#Fh!W&YA4!8f2VC{B+efdZqhu59s}mLwltQ;pcsonPaB_%*k6iTtY)HAeML zS?Cn5MY){cb-!;P{8o%$_=||M~ z-}T6#Q##`yBNseiWP<7N*$xu_2YKpGPgK`W!<_Cd8zkPiWo=@rwB}*K2f)c-xVM5q z9MG^=ik{@jog~-r!KO94@Q%^LaBud<`Pd-7*iPr_C|d$3E=AQ)x%RBq)W*mYCW(Wk z%TT^bgVI7WvP9vlT|77t^AlT`j*HmB1~8WSC$c#-y3-c=QBTb8B3skYqjpFmXxg}ml-unA09xeZ%k0Mp^(3nwmYdPEc z0_6G?_}FxeKY@6oQS9qj5hNr-SKGs|z0Bh8+X{m;mU$Ga^XB#DrU-&7Uwj@&GFrP4 z5+NNJK=b-ktUZmw&%`fV&FkG*?L1>P$#d5T@h@$rpqFMtBXNux2n}Rr#NdsgG^%Fh z_*yZ3deuCv*%9I+t&w9H(+6FAENg_X4`<|c#qvh@?dU1U1}hL3wvjiBN~qwU$CgpN z(4s_1HCa?&r{13V?cg8A(8{AKcY;@yL747p0r)IJiIrkBtzyJ4T_+q#$ojtE+BLV< zZtre&-6OZkq2gW0qA&m*G#`D82@U~{pTi8!LJ7|Z{KoUGgh`zeu)@~gF3ok_E6!?J zi`DZA1C^*+wYG>x76reyXf0Ubfq_`OwkQhqJFmmM9#7!TMth!z>-_#A-UPNsiVw94 z=+kA2C+8lMQj9hsU!2)i9jtduga6dK#wPTIJ`BAC445*`h!yK+)*6Mq`#slwX)f3X zcniv4V6HY`&Erp_d6LVXd3^~KKuoUA(C1fa4Pq2yI*#?;Z$qW8oEJ!D<3hW^U|a2IPuvF zrj6%;=`so_z#7jGZ?&*Ntr*{%?wkyq<^l9F#@HXuld~X9VnLgEBeX2g)8u~U1}5vU z#%vO|wGaEk49`3REyG5K*{6qXO4g03P4&BMwCQwk1$}S}?_al2a0%O_JqO6!G0?UU zYqMDKBUoGuk#TZ&s}gJikNU}$`Zl}-@zRI!wlUl6$`V^HSTR0Cwr5;q(lcQ7GI96) z@Vgf_#q5BkHuoO% zg%d5RVPuu32Q4Lkkg^ZZ6&icDP)| z*f(1o)`5D|6#yUF*v}%84a6nh6}3x~_*;x{YcRs)piZC2eg$mU@DUQOET|T9fy+{1 ztbTV@y6~E zw>UQs%;Ag?u}(d_@@}Jeyp-XR#wxP9Wz+TsglC)JIG-gT^;R$u( zZ>2f;DQMC0q6P7uxroa3wnqGm#d6LS*)Qp~r9j=)PpZwOwjV2|qaLHgzjZ{8J0c&K zARkvKALjv!I9-tgMkCz@-;yI%jFr#%Jz_~ZSOKx(>2^AM0@gEx1xdwxs8ObhPhF%o zLD);6RK>9u-@)t%c15xNMn#j_3*QGYDVxAC#_VJF@%t3}RASl%G5f&e zV7i2^eY*y?`c&SvzEv`ElMtD6frD-4kll%F#tNy@S^zLa zSaoec8;0fy>VK$c=u>0 ztJeuVUf}GHWz{h1bDR;m0^l=&y|p`9{QhEuY3tJpynDmWqh1w7Q{+iTtIq8WrMtcbPw6|-AFa37op#`b^UR`- zfA)pnU@!IXHM@qGM~a1*MeO4LVeHKVqo}g>;aYl2XX_A_PQubl60#8JB!FR2n+_C9 zRD$Rj0f&Yt(*ZO=P=hks0h9nbhJ?{9qG%i^fM_}qH98nZ9d$;>x0}VuLZAdj6h_}_ zI?$Dbq`&7>2c3C;zxVsTKa#HH)~#Dr_nv$1InQ~{*sU8OMdEwyi^IrheGY6`%^8Ru zkCLosLuo*uN&2l}e=YeaH|2!K^DISH%!F0#9M-6INv`ZmGmQpguVPA~4Qeppv?KG-uvmY{=jP8kPVbb~yq>>qwsi-!Ny zmu3x_**#np^CDjpt~Y73u1;069CtGGQOjyoQK!f|9|^mgvIeYL2#had;jAO23e2+$ zA+@z#7}X}o*PL_(x6etLgEYzVJO40+b-i4T*KxKnQbCM)JQvR-v7g4`-UBoOlb8JU7WXxz$Z(;@_YvJUEj3hr9JXWlI?4P130|&}5on?*=|thgmB;bCFFX zXIR_ULffCEXje6z&@S;NcqyfSKXE@A=spEPKXeZPp+rv)nFAUY>o))EpA3?a5L#!e6*5@ z_R%{_mwxJ2P)=T&mC-iK`QSugaVS#gQZ77t50g)$!hJ*1oRsfkZ%gkwvv8ZlX2 z$67G5%d}M!JoH|s2;(3NTscc+tzu6Z;jP2W{Dh|t@4wg+mO6{BccKR`|J^oNsj06g zO1Y<1H<_lK^Ytik3rmsX{;KED=JSa8IpGQ4o90VepR=d54ck1IVV~;6iW5?QqZITG zh3g%Eop2K-eD7J^H|%uZ_()T^88KA}-APKUZ6v<_=#H6+)Eq7SDP+Lvw*WX-ZZdhA zs2}OO)sxj7i={8}TkY&AR*^Bf2Iw#~5sHq|0Ur8vMDurG4x@J&)vmQfSX4Djp{>5t z$xIpLRZnKU+~i0fzLBXGIhJUh1^r-nL@_Vj*d7YHkA}aVbi~&jrN}!Ud<<$q+jKs- z`nt9W8UVcB=YuP-{arA=&xv(AtU}Nt8cy#+&1BajyvcLeR$smIQ5&>urq9%-1vegD zXTJ^^Y>D=#Fwe<_h6{mjf|e)4d&wr1KY^W)Q3+(u`QRk*SKa}1-Hq9YWSl;SBN1?FFoI>$K4)aW(T@z^J7fM~9H%RA-jFT5 z(rLqYys@Y0*zaL2H}>N(V?2j>PKTb!o3#g7=+j5xOA6U)M5+bZK!&YfBY;V{!|?xY z{~Fa4FWoV8!w#1ZYfX_Y({mI|F!{i%9L6tgGZuP>v`3oGVPs25e1`laX+q*Nap2~( z;C&N^q*{uCbd8i!z+VJ^cIwL;=+^|c-<{5Ea3)^^uT-zijD4q*bh{kL<(59urqZQZ zU8D~dV}zp*Lyv%z+X((q+=JFAdg-r-i~2>QnB8pJ#sE4(4 zWIbixjPyroU-L)lj9^WkBdDLOUZ{9TDy87_o= z_wLzIu>LJyw^4bfT40>$`bep|BTYH-?@wrvzU>^@KsH#WMt2CK=n$=9mkXYUCP?GY z>KY0>%@6537lWq;bq$DXFtx6E17&F)c^HwXcxR?1Dh>$Ux8W;C%VB@f_~8FVn`RRd)C8T#x2u%E!#1FU^%cgH{nO?Ko}1m}kvbz@!i%YF;6% z3!NV!eU16!zk@L$?aQsMRu9&ec;9rNG@(8zyk6sKNK?mH_jh- zjBn3-p{~eRD$twQD;VFgkw?WOMQAJoKWPGw0Wmec~@}aXp(hqVs?s zEIXMoh%qo@M)Jrmr^dqqxuMVA<_P-g9mPN%N;~LV{TizkCVPBI=31bUvI+A>R^6ds zW8Z7*_sZ?IJxO&A-RZsZ%?65V@VHwN5#JFw><-U;k$7jnM9{p6qdHp*+VMv>MN{2u zD_;G^{VxD#GF!R&CHJazY`R^lb^l)0jXsgM+i~nl^?%fqk64^s&ziM)=zANnR#~&U zxR`31Z40-L$=vLv7P4S_mF5ox3)_m7nKz+hbqQEN9HYRKKy$KIX_pnX#UuL6B;Ag> zs6A9u@#^AL#l`ge#dv2+eCG9*b$GtQJ&re?R~FcwhL*X2NHj zhrSvQ>!}sE-5lS!wS>`|ZCkxMx{aBf;VZ@}&x#D};kT=6r?;E2R@a^c536J{wi8yX z#xc69cx_|b>dn<{)^&M8@oLr_4|Iz(-y+Gc&=rZw_aGm6`!(m=&k{;qLH?>;zZ>Sz z!Du8qteeT) z(Vh2-@mLp?J850_a@U>WM=s;!sE+i4R(r%LvUQRc#et`gvX1v(cZhHJBhjPcJD$J{ z8IK$ruqeULP>UYz_}O9x>$#a&BEK8R5Wj{-`Nh=S*2c}&4~sX)x5CrhrZ{3t2tlm@zOT&eLt9QOs$;Iiv-DG(rW4GErHX=^H z>XFwTStu02Ll7x(osep{Y65dUi0m&7k(LZ+o$%JTN93<CbPP_(&!_4V$QMd}Q?_)P9<=m&yk#RsIdk0oVE9?O;}1V@uRKz?bnl)~ewr zO7Qim#+)(>(f&0Ywe#z4DrFOXDcAS}STVs(H4A4Gy67p+yZ6eaCZM=%`C!(u>^cFC zuyA?n)+p=u!1q3GYnHbhOJaE-U*}xnwex$OkAZ*B`hoVY_9*{`s3`yDs0sbgUdLOr z6#)ev{(jJnkKH4^dZq`z;jajuTGvYJji-LoKZ3LV+mmk{esa7|o5ugqe?0rS;Hi)S zkxsv3RsLI<6nmT4GdagIu|?|`rn>hi`Al4YUpHb4|pxR zs8lJ?UDO}!QoZ|NCF(Lz9USUH-{eNOvwkDb;@iS=!@FA=T0Svua1~L!6i46Gc7~qr zDeu33(fPeE-Sh8Xb>#p0RnLLz>VPZ!UC#wqhY}Cw$lT2~AwiEft$bNCzSO0z|Ltk$ zJ5Iy1XnftWikX8s`y%lFGa%Lfw{IG4&2*CYA`|mE-UX}nKg+2PeHZvu@An?P|8_=w zz+gES90xni9H9%(*&F;(<{N;qU{1)#uzGnMR+qlO57(#;wO9wtGJR1-tiXCUi6p@D zy!HG>dZUGcJ9A|FkQJ*qSv^bbU%~27vou6j+5hskUxbX9L-7kMy?hCS`1xO#Fq7}~ zwt{=}SKj3cXYifg`&>-cV(&KBO11Xnj`doJ(=t;=wzCsC=;-{!OjlH9yf-@23>M(o zu*`UE%f@nCKJDHSBU}}@$X_|Pd5fU*_l+=0x%vNNtAMYK7)worf(-mz+jv!mB zYdN0$z5nCMb;D1$A)weQ;0*#|u z0sS>zwC zJkt5kz@0%2uxpGo3LJ{UC2eXH?z`O`jsM;5NL(9Hq3JyhTk7_w?8w)w^3UcGW$T~7 znk?#?bHOhMOI#8Dk=i`rV<0xp1)B#kUjei6lUwg!07l;rWDQn4&w|BAcZ{umZC8nl zul_hY4irn} zC&Ohd)h)jUDx(_t7)uScitGeqx_>3R%W(|(yYoHgDzO6e=^#VCb)5?q52krst{Fm{ zyiBI63*)KQ)fXtaszD$7F0dQ;9WAm|72sR0yuM4+^mZtAWWsp{)VfpQ z_TY)Q?*jLtMVsL@M@`6sd84MeS1r5nMl{ylMaZ=@mnp$a`X+Y|*6;L1+|YgvR;$y9 z*>1Ei8e5sWI<#8EeOaXl=(ScU1CrzpZ@4vcmDZ?~))=pcuV=lOCw*Yo6}nxU&E)OX zATDXlH*-CrF(FEwdQMfF!mp5~A99$<6cdWd8wgM&AI7&VDeE3HL}jJ!!4QCGhwnc9H@6BBY7U z>iWmGXOgehL8M>9o!|oks^mY%hCQj4|#M_NHxgBNm%Z@|| z39WnNH*Gxr-;{m1%_rNJ9BzxgV?oI`h#RS$&!eUwL_}TF5PR zmekH?()>PWiNV7bEHAB{Uv`vo#(U+xHse}VL9GMq?7gF%uq>68&1c#RO*$shbsTSg zYiZ%`G!Jt*pV2uHKRTZn*(mNGu~Hc6l~o#ng{J|WMPd(dUbmNwYhzP>Z%@9YR}cNyMh80O!tD6orxufsnbr0B9@MFB zVzMs!wBmUnbkqf9CChQe{W{fj2DzFj9*1eCwiAo_u~NOjuA6gZ9be}d>D#up@oL>h zV`glJ4v2-QQ_I>^X3qLk;Mz5nSwu{HPAc)76zJ2 zEXXu=Kc1{C1^$r6(xejdtRzeCccwh}0yKBvG1Z7C?`0mD)%uMRVfX^LfLM!I`cvSc zYcI%oaiMhHE0!YXa$pVizXEOxY|G|2#5ja9IB#4(cO^dmJ^5u-{v|cX=Q}Q`*+0rJ zPaTCXoi2!_8PLdS*7zx~@?DBsotsT4x5~l*Q1B9RFdf7HPoR67vU#j^Gx8!mV7Ue^ zMK7dC5BIP@fv08DS=h(33DHf_t*O%IFXtUaEf_;?mi6eIBY>#fo*nNDe@kgG=3wxO z63gDR@X6n@Khe`&azeH@E1u0+n4NX`!hGa-p9gEd9caHh7J7F@xVY*ivdMs+7RQ)< zTcbtQI_6DcP$oVD^^Joas2-%{k;L>*cLh*I{r^rX$vr z-pojFvVVgAe8ZttCowLH*1{Guba_`iGDGvdp;h$N?G7Fqz2lOPV=`&PxR);OJ+?GH z|MFHmPuQ9dc$ReLCsk&)TdyTg9U`e93X(d0RD7MRw7A7H@Wt(g= ziKX~R`~6>ONvx|MwO=ahPR(RqfJx$ z^fzn#@%-|Hh|EhJ;p1+UVZBIL`;qT%riaHI zziDa>#znR#GHy2fCI>j5w%Y?8ZdrXCT)XP?|DY9DvZGYllvBNeg^&e1-Z(GOu;E^3Y*d1va{tG zIb#XcW%P0 zi0lYxRfcSuEm9?qay4B^SDAztwUmUY|LEtJy~ru|ENs#@aJ@Q-dB2VP-EF>wp;m+jN` z%cckR%aiV=ZMqIu6|y-C6Eqn+Te`4%t~D>KOqEun6&+|*y}2HH%ZK;6Dw8T-GGi46 z?IIO;mvEV7JCk<4{PWRy@X^utOO{60l^v-DPw3O78dnN%#EqqP#dzh5QQut+dC#_wWuxvRuEmcbC{#RD7ZwlUV*JIzvbEgx>Fq1M)Pg2p4Up3R}vnaT4|LgqL=ZmvLnAUqkr9{Lcg7k$VUcHv3FaTj9IWPtFkrz zLU!+THgjjoyDej>7i8x7EYQZk!niX);{G0NzSS+EOx|n2_e{*MZlN!HtP3UJ6|1+C zWv;q~?37337;~!B+C@i>Ab!t4wG5Y`clw5M2GJSfZPUR8y8-3w)Xr3?t{!u$yw_kj zqJzv%me|w$LV5-R-t_qfrv0`9Jmy;oBa1xfyQ zYuS_RE!SWxOUv$n-CaFAg2OebeOBanq7`YXjWg@SLwM@CVmQP*i5@dNy@ ziQoo)3CMAk?}U;Op)dGuALU$m>pIEV99TkoVO35a{$jdUXg;lyBQ{VZ|7b*^jA@&J zH?m)mUElawwrK6^@}CM}hcj!X7q9PyPP46zBtb4#8hdSX5EYpLOZe-3w3m)OEs~r5 z3K&_zHuuUgZj0*-g$cNBh4*r-oNmx$M1RkYJle zGc5SOw739oB^x?Kij>+#K41=#Qks)2S!-#1mv(Taf9@1Do;`rjA|BhF5B#5%5#!O~$>ftBI(I0&||OX^!x1aD7NSMco+z-g)B9 z`!;xg=)NpnU72@cM`{)$HMtEPW3qG|BeUGnl8UITMc$Y!yJW9eB$~3ec+J?JS+Q2U z6D38rreh+0E8KH&bV|ib;3}>fQjO zNOK#1#SXpI&1_r9DZg76UI@hdP2iBw3m1ZO2eM%y2<7HFMOY=qW_v^?8}>;sfQ^lN zQ;et|(NOPT0^hhzz;jt8U-w@`?G*c!ui>{mhW}Vm){s6H(eP7X-Icu}k8{VAbH|i( z40N}6;itfTS8UFw#Ymj>C}%zH2;lkNghh9>x>RD-txBzp%DF~&L_L#n?8+-{CWZOE zSel9J7vlO?MH*9bU`o&pUGAsAfBOxs%G`ZL3!Xr3*7Uz)J2kjZHwnFEjd$GYacxOe~ zlu>9!wiWy$28*ic+u(ge>U~ku(%{>(BjTP(EAVC`{_NY}k|ArQNl1!>4Dx;#oYqJ8 znkRl2wDsML)?@yj4y~`Zxj5I!q|CsW8=u{G@wpZ@YjOu!lg2N>3I%pxlVzMI9eTk0PpottLfMjX-lW%dt1KBgdlVkc&SgEGT3XcJF0mbS?sYwCaNZb7{Nh73=o z!vOz9{UeQ~tXSz_eO-^}#IE16ImcU68C{QXoj9(XWlRmf%`JmO+R<2w@{j%PqI5); zz5|(Sz>*la;-28+AMC;N{GDssH17_>&JjI7)J>W4(=~9}m#pp{tdQ8~&) zmOA2)1;dSL8Q5km503DS=yfkXD#w^~UI*}6hp}a|bU96y#8o$omf<6LqB@K9>C8Hj z$8V)sC91MWKi|G#r1=|dLdB?4s~B zSmI8HWapy9WiA!?Dv!calMfEn!}!&SbdKc`D|pc|+&(<9lV+|Y&lnHQg>l!pR6GN8 zGRADMFfSxaADltEvCo>ZQh1n-cyPpkBZN|7?xZ74z)e}DBc1K_9yUIT`dMxK(@iDTerFcBvu=Ingx1EiN|T#Ol+4x7#eI)cnZ8Y`uX zqW#7QjA>c*+hplxrPa4VQ%RBb^x#?Y=nX8FvF>xLtjT6u$s&xlvE4IaHx)~N3@p6r zgf3*2R>B7w3O?M=9iY8)r`=#MraA_C^p+LM3g8;hkSAqRoKsVM;jV?rz=UBm z#*iA?qn&po3kR;+N|=wF?>XWRe*hZJk~1qN3|lAvXvy8 z7YTSu;2z;AHoqe`p{{zgTfp`~Z13$kB3DkQEJJ_5FKhjS{L*wLzsgPlZnSs{Z(*v@vtTEU zhfYAN`(&vS_k9b$Z=PM;+fi(1K820=Q@k1S-MrZoj!&4^Algt5~U-3Y$ap1ty2alpfRXf&YjOV5V(%6I>A1UB4l zsDptfYrz{JEy^M_o^8S`CkLJn5Ke-kMiA|4o1kb`R;e8R@$ImLkxl5PBOa_gRN#Ub zB}8;@D_y=e;Cc1x;~UiJ<4#-UIMXP2q25Fu+^wY}*6#8=l0M=za!eH(g?N!YFoZ}w z7sl{W;HwW}&U)uGMg(abHky@2GBhi(%q>Ubf4+xCxx**JchD$x&uZINnuNH>N77?Y z=OTYqj8gN8A^UL6$x_!Dl~OA!+OHk9jaBl^p;ch*OvV_d+3id42^(O|JpVxSuqL60 zb)FcVxNgjOuIxnqi7=O6-cT?4 z7*D)KwVsm7X8BWlv;491HhX&I276R~v;3L!0JhBeJ6jT9SN+Nmp;4cr*mq*_EyHRo zyc!PIxp7cz3)h)2TxYpb=SQgXPybfuv7hTq_fTDzey)q`VBxxMAN+o}u0*P9#1}Zn00zf2;Cgy9Jht45hXoP#dxZ;g8nVZY6^>1N4e3 zXT`lMJj~>X9_y1YJ2XIK5e6d%dj2BW=pkm}fBERE()yEFRa`*Edy9;oW;t=rv%?Yp z*HE|ND6%KOHbLJikw+E~+uU|55Yn{8gRiC=+=)pgK6!5OpTWt=T6b@V+(dc%3UleY z<&5g21stxt_hqHe9mN`fDI5N;@D9%h>w=R>1}|onTL3TGhG^m0 z4c`L~WfRT?ej6|gw^5^10Eb6oO{pOwD{j{)8K!l z{TcZ^8}Uklr9$6bvT1cIENq|2llH$M*V@`q!iTduX6C{Scs%65Gzqp{^w(l9JlY#~ z%46++MaG!}$YA$ZFiTv(^9laHfN7UWyTj|2MLS(PY53YP())Nff|rh^4Ihh^@^Ean zax8iH7%zP$e~No#_@-vI3>@`jfIUknc}d)3Xlrh6qQ4tn4com?4x%}tASE!)PMXk?SIF-x5u%S ziTh$J^9S>GW;giULcvQP0jmSfHz{A``Zuossxid%?;f#_nEsJ@23~qT7955O)BhYn z42}%74Kw|REf!)hGBn1+Pr1W)3wZfsGjH!SSmp>^lNbzPW=oZhcfq@4o9E?$pyeUG z>wp%SC8!QD$VSbepRDLWd_&p{FZr)SK~Knyxs$dn;v=n-A02Sbbk(`4T*1Jvg0U7B zu|GQIT%a)Uv^>V$G*;{X7#LYG__rauU_`9;T&BshaWlokWaG|XVuq#PtS)4f#_T_u zA&og&(U?a;V@?wk4&C`aOvI>X1#Vn90+N)p<}7j*g4rb0e-SEnMob%b1CZdUOHMK;GfXz{5oAb`N^J_kX5}Q z*V^ipU&@byN92n(AiHdk*#OC=jC*_89hHZTPufc>pR3g5{MJ4>Uz4I9;OE6w9MrYs`b%=?p~wk zpFzHlv1TsGgM|?>F(zJk_W5cLB>SDGWMmTP@UAImvQ$$^|Mx+XO?n?IIJErMT>c5TIHU~Q8Q~r&BHZ5M8Dbl*2vIU!p~`G>wYMn zaw#C^GG~bgmi0Tt9aGEK6o!9)L%%@!{f}DE&IfH_zXnrcl}2rfxZH4C7@emE?~CU7*RzceVNS>D^Yu9B7U|jEJ3Y(B zvan~U#7Iw~c9J)88;kEg$+QQ5AGfvoL${9fsbDvA6Td4D2D*}l(xfMOpbJidx1H~0 zfGCL?MwG-0k=q1Y`aMB1}51o|PKg?vr$8$4OTRi?@*WW;pWkjL8Ew&l>w)ZfnHF{8@wFcPmSwnh0Xs|jO3AvhfK~We?6aif z`@;GZ56c46&V)kDMzG&e980Ryq4YO!;K{duhjknNS0T!S*cW1a#O*<{Hx&GSkjkFM z`WA0)1m!%pg~Fu@eZ=#vu{|eiZTGdRveL17Lhf}_Mk_MbgY6BiRPsq&YNMFr6KLV< z*%<#1*HyAJc7oGT)w%q+c(9|~hYVHh&1_Z#q&*8SIuPG}Ef?+A@L=H{+$U=d`*4?6 z{VX%b(dcJm=3Hi2VqGB41@EV2RJ3~9Lq>#+PM(VyoW zLJWHb&y<+Qy*6$r*fH3+xfowDukiLZl|PF?ESBY4m}JWD1we!*d>gnUX!5A0rcEM! z5_iDg(sy|#AHF-4aKf{#q@ZmC_=%S%6uESs3qg61ogOs}vNC0|U|svN!+&Cb$%WvL zgN(ItmD6gFAj4!9dj z{$8@Mm0L=|HcI@!T|f2==z{!EBfr1#E-zOev>c- zD=8!F2vJd?lBfapTkbLfZ01dE|Fhr|z^$p>nz#TyIk#~p?DS%ASwG?FSC^a%Jl5-* z2mQPu_JpNm72X9uz{Mx6b*|dxaQN69YK>)8@hV2VNjUHNF`+x*yz^QTGx`xzD&{}+pxxY0x>zSmRQzCHPp_(NkH@wzHP(sx781_H$_diu6@PPt9(@s z-;&L0T!lFleeBv05GyHZ=(9u5t5U9BRHp(*&K^( z1^i?cMncR!MA9Qi6y*pMga6&9p2B%GQ&QpUkDVORnGT-^554hxAFb{q;oIQ79K4;j z>?kp+fU>w#t^#n=HiUxz7-G|KhSex>LR!2{o7vEi=mbVX(exr9vHYnV!%7U|oEhtA zuyn_kJCG4GssOzm*wI+%7{pc`LJo43U~ePM5)tee#pY{2IU!3>56cWe?!8u5iF$tg zC}v3QX~MUG>sR3?RdO#69o3>0 z+(EhuT%p-K?$+rF1>X+c;Hix{%1U(~kv-3gNJ1^vn#6%U7TUPU{cYgTRX#1HgLviP zBMf-2B7VUM-vyJ6yF7B$0HhdGr3Nc1d54I{`T*rsN0wh2V}%~83%Us64;+Ho2^oW| z<$s0#NESEgNP+8>W^f{d*P4g)-tBzVRe)#~=E^R2?%G7x9xw?oCegWFG?v61)JS{e z#3oi+3AP_5#VRJ&jyjMf6?E}JbK9$~QB7>Ru{{CY@!CUK;0$7{F$c%VyrF(YoP+hU z(_jP29h=$fV??!(*fjP)(m_^=N91z1R}H-CVP>C$?@V!$hJL$9cbSBYMh@R$c@v`+ zrVrn16z;{OP4WHDyWRaCcN+`#uCWIuAx72f8QV1O0Egc82YJ8eZARrcFvk+c;>fpw ztg9Cjz$~$89NI!9{wTB45CMrccKU9#?~_3$?ay9V*HivE+_$2b31K_?{JE}6%@u+H ztN2lfi;5b!zlo7L!5CtfA}h4vh6#ms zEwC*7SC8u;i+OdD)O^VN!{DlU%K88}rZm9Hs4AY3)!B9ORg>PcyybzKl?Pn4 zS<>%1Sw&8saF-lh*~I5$Npln)iZ9)Dh-)2c+2GmN_eUUev|yUhB1c*@=0KYN@RUHR zWkd6`N`LF5)=V+&f);19ZES|J;HIRd%VgzK5d5De8G~ zf2Ew_yZ;by&Om>v-(1<0FWkR}*~9IfB*k|U;@B=#x~=Gs#32$Z+*}%nPxS zX5ioVLj4i`DDbP8!RC-pCHBTj;|JzoZz=X-rPKYnZ_gRNdfHpei?Pyo{d6{5mPLKq z0UoRIaOuDF^N7Y#?u3%Q{^!0gWQfUt%EwAq`qz?2bccLo9(1U6PsRe-mF+zuFBr+Y zD5mk%tH*u~&4eu~AzOW{r0Q1*rdA6OEDJ^w`{iGTGJ#FfO1t`ErO|_%fqtPn$yPE6 z9I2UW!OK>HvdJ3hlAH^Mh@z5MN$MkOQ>mn9WJOPg^@(^*=Fi7WJZo(XuFy)W`?4YV z(cbH9+FAKz)o5=U;*&Qc$}Cp;`np>v^voIliW9FBLaL~Q_=`SQBF|%`F@p@gaJFy& zYu8xm57*tc5ncv*=OpQK$Sad@b4ivI)6EgPjZ#iQM$R7$dOy;HpLvDVb$a-zqwv%_ z`-p2b*_(knX`Wd$^be))eb+swg<7;3x((G{tJHogYCqe>jm?HE&s3u22a&Bl+)A>H z#7d=Y^v=t5^xT0t^ybIl%d!WfP)C1{TX^5Y-fCPp6Lms=3y{rX(hZDE_f4gA@!f>)eZwi~Ws zCOn{m-tG)>q86(P9p?O@qo@U(rL|>hq2prZ`#gjG3%S6oBx^e3|5W`|OOj7BiS2xK z0_w)h^KIZvkfZ(aH}<~?_Do_sURBsq>HOEh&Pj%jSI5OFk|4(SpQYRXqcjWKjTzUx z6C_-9nSGKJ06FLcV5>(L5PFMA*I^!F{V|NEPjB+{!4pu$`Yp`VY_^Kq1Gbcf-v&Ml zu+r9k4sm#3W5E7L0hI~TN7{m8HjfsbP8CM0!TxQ))2eDFtT8>O^QB7WY5djV&v3*b zv$LX*Q8!LzGxeSt$2G61+?Z%M8YvcxFR+_0@$7OPe~IDjI@2YdG2}1QG3kC^*?j2B zGMhBQAIj-JUN)aAxXZ!~FtEup?d3nfzqg=lelnHE^Mry@hzFZh(!ExX-DNZyV7&?d z(OI)66cj^tmkGypIL_w9d5#6#8zX@YHc587!C5wc0oaP*MVH)jz$Gf#9r}DWhr@AB zpwSTnIWQ748e^V>FaBnTpS-E#?Drap)5j&Gxk@lHNZSEsbK)q` zHN5|q5SyX~k6ZZcM>snLp6Tz0_us`?W+JlNTnPbzRp7N>8N%;EF9S_!8=g!v-Ho`x zR0Hk55Q-BgAOe|i>M9#A#N!>=%UQ|BjfmrOm;uhl+6uH+PO=Tl#~x)tx%`>t zja94({Sq1x#wz4QFrV_S=Z4gXqx>!W7L!9yLn90YGeYWB^qU%bTKTnv)T@`Ge-odL z$_%+xMQ5#{$u73)(Ka3{0=qX-WKE%9H13T)h%H^nXk)9Ui%jZa@DejAbj8q6k*spkY6R-LywMTSJ*RxPLvy;K zd~DL*0smEYVAPxh4{xhNjx@$(JF59BdwCAa3$`OmjEqSyjx2x4q3JPs)a8G0RJNnn zhz5br+2y$6vthj_FV?>jjowrXZ5TY^m=hAvr?w6;S$BIwla_jkkqvgRp(@0Ms)TKG z7l*^Dg!9InqUI_YPcTP%tnEtg-ef2ASdQZ|Sz) z7tyZ`S}yVYw!1^Ye-3WDkDWFl|L%D^?*5@WYU*USx0yv{>#0Gj%k;qVb#0!XgLQo<7(c{j zap=jRV9XHo3RqBN*f+v|uYb9N;mRY+iE-RfUVvY{&t1N|{FBQ}6tolMb{#cM_wfz616ULJp8$1o@{BTSIXX7n8IF?S_^4 zhzl%x2l+>sWKLAdLrUPAR~$Nc@L<`I(Xc($d3IurdFeWsK|K$;)R*U}=OrLMY3iE} z9kTOL{;qnZUQR@gGce+l-?;3^Zeve5W>TDOxxQ^}f#>|@&!9s;%Eb3;t^rZ<=(PN3 zaVSgU)pgjf4CW4I>DtF3E(?+!b|A=kpcTuG>W)yfMrVjhd^|i>bf`O8NW-&-f_tv> z(68==d_^0ODVKhqxX!F&2GokRNX`$J91}inCgch-_Yr3)e%D<0%C@R!JWO%~BCF{A zm@#JOduBT|B0Ketx#a(Q$>Hy2Qb|9M;o*_y%-y0z)(Tby`yk5C13QXF7zvFu6wJG> z!90@b%-dp+<}=g0d64JhujiTPkEeUhMoTL_oa;qL%<*u09oHFf?7M~V-mL3I@=dlT z=Q?NWx(^|-XX9$i|8Y&4a*byA8uRsE;hMBnm$4eBh*3Fzq%dlcYT^i)uY$DGExwcx z|3|y7pO>Qr?d5+w#+W(eJzj}5*HehF7Y9~eD$-56JHpG()}MUJV7wF&JF@-9gwHRl z)&7g&b$vMJ5!0^2_%|HEtUbWHR;(K-aVnj6?mG3tJHa#_3cd{A32epq?xf#b!x%6? zGex$o0mfy*vylFSx8810UHt@;Xr5+yE1&mTwjmX4z@brxX z6-sU>7P+Cg*gWqK7ilJ(>a`2tLPYyt8=$xvSokh)i&R6CBbocFA!C~gaY4ZoCaisR z2CDsc15Z@;Rq~MJTa8~P#)@&}h2;@kgfYbx(^gduO;mUqtdSbeo^rEOE%G_Uc<`^| zG+PwXSAU*c#20{_-5Cl#dGuwBJ<`Ewu72#O5uO>|X%wJ|VKnDq?Fdl{DjOvr4NMhxpa!T{R<|5^=Gn}(WGu@+$Kcvqc6-_10D znFK3b=_2D{pbx+{H#JWrJ!H#}8;mKmwSI`~oIO6Kfz7n|fRE_sT>%gAH;01EzzjrC z(boM##NQSQUhYS)Z`L4gav}Db2GiQun>vwYhq1vz*B$OAg z*oPeUW6n1nogKSQ`KCi%w>W3G4SFQc*F0i zxj+1tYQTn_?+w4FTaVLw2n;gGZp0U!mAC9?UeRAxfvZguqHbCBXYyrJd3bLAxwh!H=p8(WmS=mp zm;U9^HdxA;8ot3MsOyp-V|NU2;NYz<*ES%hJdV?`-wynUp5)f_(=1Xqqr`_&rMKiTj$veUXtaxtR<`y6A@W zAGY(w(wh8urv|MXkJeGdw5H**XIVK13>b@8MJ_{!yoDAQAzwM=m*XtXW#vl{mq|xe z*y|drsm96^BaO|`RAc=(d1O0}Sk^ey8t9{1o88RBLqI(nS(gx5M3$>v?hl0V^|d8KbwIa}_|yvaKb zwoU6LwK~N)$G8k*wG~#=iQ*`kodDa?o>1`KKDLgj->v&(1&bK&h0M}^)=yh(dW4rt zkMZtoBYa~Fd{6n3dufD7ds=0WDdvFQvr5cTtMiECl<(I9lTssa4LYB?mlQ`$0Jxt@LU`&h=PV4L7;Sgf-6JvO1j+ycE~rA!Esc)XR@@irJ~ zPDOk}uBU5k{Lj5Oz8dICSox_Jk4HJIGEgq70@~C8Jhwg+ygKlA*|=X*H_2L%AAj&< z5qFu7AZ`P`g0oBk`Y;rnB+snRbY-;J4n)>}Y2;Q1c;TS<`LNHO1xJ)O*Lr)Wq)9?nxDz#f{~L`iMG=N?u>1YuN2DDvW)U`ALnq z72@QCH`pfvLZz-d++Wi9J*FW&P_3%Ms9^5JF8hTf_Cq;Nwb-NM05Lf?t;)RxV zu9qBNw4ZJvrt4W=p7Q8g@Ysg%#*QJLV(vDuIX)mv5FyiK_U&yRZVy{M z6g(VSe5sy4wn7gUmE}w!;_<+~8OznN^?I+dPj8F&KLy6+MhD;H&SkwiS#Liyug6yn z-OD{G+%~?BNuQxGXixX)gvU$tb;NhD2yK`=+=jP8Z26l)gppbhjTX@T*=ksKj|~MM z{J-9xttXZlz3>061rG??hKPE0*1JY+jkb=>eyX?N?TGrAhS)mz(nhN43o(-8-xdT7 z=5=t6);!hw<69JuZ18IQE&OO$dbT3J2PA8U+oF-#Nv)3F4#xD$T#~JfVj9C+!utN= z-NLKQ)#RH+4{So@5weLW68tr{PDrp21~@oGOwvtY689J;)FY3yh6q{u1F{a9wLJKZ9P(`9rfcHMzoX5HWsQ;H$Yk zC$N^!L9f)-Q=dc>+vQ4>yU&#iNo@6M8i0$~KUSPnK3aSUazt0Bsb`4m`xuQ^iVU}V zR9Jzt<~??<_PpWa75e;-?>ba|!MF~q=YRI_(-QrmnP-oy>)2Z#HEtgJHy_`m{eomG zTi+$zsa-6b7hX8ogQp_t)CSFR8)j3ILgxRJoB3me=bFdEa?Yk(IwD(Hys14y-+S1G zZVy*~y8JlM|2^>ijvL3$juA`B^8_8N8jFC%4+SG-cDB)zS z#5Bp(4+WnNG$OD{{~*^vF9LgeLsO$W zlU0iUfPtL=UI1ZgdJc;Byy zwIkN@6?h0%u$dC9s)3KM>276hJAixm*d0E)t^?eU@Iae{vw^eMzAFnK-QPj1l62L* zKuU(U?!xu2U7H~|#==t1oDF<&?N#7j?p$~_P zPXaGFS@PEVBBvO7{?}{V8fu+Bn7oU?yGFbE6q*kuY zR<6Cnw@)5vqjn@=U6Cn$aRza62WASH(&uNW?pu6d*OeaV(fbkVg1esy_VkfYg|zM{ z_**6`tyQCSrB~H>=e*@?V9_=5g=;WYM)ny*Rg)UN+_QnCYlZN#B3C=C&FbUYIv_DQ zHg}1WN~#WMp%Huo&+|nuld8llYRKCktwFYvVOdgwctx@rs9d|6Ps&>=;OCH4HgM~2 z`mD(63ZumS2@Kg3=_K-a7(M%4-v#6PyT#{Q|A8EB)vnPq*^JB%&H@%_Fk(kb?{xvW z19S#56bMtKy=PI%*5DeA{H7|V|fa5ACO~| zrPJCMd?(Z-9@@;eZhV~0Bz$}_t38l`{0n!2nUDJ|u*kOK+E0oiP9htR=|!-)c;%)I zW7?9yd8r*P9Vh9bXMOKuCm!0&WM+D)rb&47{z_I_3{=-9utO7GG#WWueyQJbI!2`0 zKQ7{b+X*I9%Jzd?4^%(6BI3)ImW9j4N!_q2{NOW+8-X*5E5jEg7O98T(uMq<| z5?0$LwZJzRJmA1d*LNI8d`h7ZSITC`{pMbL;|S?oryy3#i_6BqW;@V5ME}p$WA~d5*D2e=zzbyT+* zj{Hy5xAR>Z*WZhL$k?)e^K2mLz$*_1uV?T}Rw;J&g_iXjHnpX@nq5}|NmBoF&8~D; z1XzRh!;ELWflKd&?N`#AS|Q)1c4>t#iwv&OLXoq&GEYdXh=LE)(lN~LB5Xkan$R63 z^1!PiHx)dl(Nbn7L2&_tH0$rV0Mv{$HQF{|%^`z*~(MjxdL{_Tka_27h|Ep7UOBv&`jotjjJ zctA0_!47oV3_M*Xo~1lQcN)!**Ho&|X&DAKV1F`iut3WddV(@E9vyIvh-(*;Z9VX7 zO){H=Ke)0W7jB>f$Vc-iP?t)y_Ts0(Uu@VH(?B^Y_F&w_zJe@)?yGIIw$)yJ_Ti1V z_A2np#9L3eCpF!9ah6n5OZ%(^_?V7E$TGp|zs^16Jhb!cS%)eVON9PS*Ftb)tNa?o z!uA9Y4c&{q1=xCHXaRbl22cGv*drS^Z$rOq+)ye###=Y8x00q^yb<+9mV%+aabwCt z-m+beZQd@As8adknV#S?Lt1|x{|j&Cc6oHwc6m&*3U(7(L#Vw#s&IC^F}^`Vaj5$V z*+TnEF+zW&2-yg&e-Xc6>Y)mitgX6`KoK6>;lr9FrJdcd&MsUJE+5>ujujF&+XXHo zsyz`gx|xtRJ&1Nxo*(vul^Ea8rxRY2;@smpl5HbAVqkxO6-A8WNm-FT)|@kTzl#tV zYUv|HN0cep5ZLUn#qTs_MtJ#-S;(Li>r;s~#A~@RPr+a8>Ml`<4j1pL-rQZ1*k*M7 z;t?V5akD(ay<^vByS8t3&;2~%nS|c96hV#X!Rd0mfz8E#(=JDhH>%*yL}P-x64=KW zrmDI{cbR3*7sU*)8*EZ9cw}@_qv74Wf#V~OY!Uis*^vVHBvhF|-lvQ!(4=Yx)YJC^ z^`XYMdVf&YR<^n9C_9bMl8|K>S1KYQ;t9VNidg~A6qoqgB9x9*Z z%-l>KwA`|HvzVlcLEuiS}j zstnL#D1}vV*sy)=I)zEyuGFf`v8_+t#4A;VSO!`Le9_@ycHuOl11(|@DQ;1RS z3BG&%m&^n!``!HvWXql4Ks_rnlb3mmU7oSw7SJ28Q@%Pxpnqk1xV$I$=Jnb>4O*q? z0xJ`c2z1q_vO%QhVsmHvR=NJBo^dKpa<9?=vA$CtXQRxR$NHv-bwEi05u2_Y^93%_ z71ma|1K(SrFgA|!&Guw&$!z=DbK?z+6vwx5$Xled>BU-EW6FJesXa*>;k65%u}1W~ z2d-1TY8sb+f>i zCB|T4nwsVI&ZtRQL?_W^k@VifI)`=s=RJeQ_V)k(rX$~WzH`3q{oehJzR~?^Uzj~l z=3eGyuiL6HrL_D$3U;8VDMHOj%&9HpWVTtDf|4zxC5&7$2_?_mX~R>SD3m;Tr;S_^ zijvjd646#jZ6=^3YqW$x$-1p-leXn>)cq(I`eLCAbtD1rgk}Gcgmqgra-D#>)H`+H zfZkiT5Owi)>vaE8N6$swt^2>v1>CLkK1bF=^Hjz^uS}?XYEx| zw(*2r*op|@keZG~^bxJ=`>>C~UYFJs?%F!r@*{Zk3^Z6HaD#VUVO$(EVWjgD8x~>S zx#J$U)58hb_M5py@Mg~)ug$#yU%9opCGfgPI;)JHw1h%{S1iuihc~s_jew+_qt3)Q zOwbPIa66GS?e9%DbJ^aN8=1-?J)1ziB+0#m!oQr{5ApxelN#^Mm2m|o_EHmP4mh6y zJRA)f{LFa+tOoq1P6TJ51d&19AdLa4IMdJeOlCeZ;=z7@U+zX5Z7M z?Q`uD;U(QDGV7kt#@oB&y8ug}ofG0RJ#Vyk>>|s0t+*E+swfsfIygCGX>3{#n`7{C z?iWA2@ijc*n@-nki#$zrdimQ}!+3E`ivx5@kGTOe)wb6xv}vjlXZ!ZrjJ2G#$@hkzjhPHxMPMzkE6JWAe%!1Fh4>H1 z^vuG5>yOVQvI@kos)D^gFJ_D|#*Wo?O7yQ+tS0;K6B76?GKOT{L?P1bSKGn&qQNu<@i?uBzOYjw)tp)tgWBq#gv_gSM zUgYzVF8pfN>4{l-`0Cw{NMszmu<6AwW#1A{%$n!oX7Gq)LMI{~y(`4d z>)Z_56QcXu0oh5UGmSFbbE zdC;Q>^&(!oCc+~Fc%5QVvz?_Cj288vX^)J_*hMST;r@K!*fZXniL|fa!-LTHdC#%ID2k&IT|AS8+-un<1TQdBy~zAekd$H{*iVs$Q`7-`xG4S#>c1Y)`# z-|@R8)fP+V${pvx%VN47-4Sx|hWpkq$)PQdukj^sS_7QEoe{iJ9=V}W)v<@WER`Bo zWj{fh)pa^>A0itwZ?ERK3Klr5rjD!OJ0mp8jxr4}b4#-Q58DWj1!h}*N!a6xe?bw= z08`Z&Y_O^_V_Xew>IoOR;&yy3*%IFd&tr<2t-1u-^{}wXWdfB;QLf^I$6pJnR`gir zAL+GN=3D1?FbX4RCY^X|&?a1HB(0B-Y9sO~LpFRnBlZ?UW4*!;(p9R_iBm_*e=MeW zu;AgoPI1ha+kdz1Ys^!c5LCTdSSJ4AI%Mmoi7H@y=t*65NKJy6D1TvdF@53Ju#Ceu zLduM&?Rumvsp3$}$!$rENm!2y=7UzYHM>CR0*wxD(GA6lx$6qN^Qdy1#A;Hnb1>>R z+P;~blSV--RFP2Kt z=5_ejV6Mf#M)PAX9aC-#s`iZ!a2g7T0)BBM7=7xDdbD38(3f6w-}EeSaq{~#s8bk& zTtU^#C-SE8;574MKmf-zz)DgByp%7#_kHnbccoroFciL1s4*x_#)5APStnWiKhp^d4We~_A4dY(YtRJvc`3VY|Tl;LuBV_ zO+oS(s5C0APX3=C!x|wcFd}Y*5qk(&?} z<}z;QOeQCdzfG+M31lpgv_jOZS zaZu6uBp=oo1`QGe^flPns*0J#18IgG`-LUSa!qh96T$Z zO*3LbA_~^O#Dt_?bmG_nv;88pmCeGTZPd?^YxF!}#H*D&yr$i7zc+Xc5KS$fZ)Oc@ z;brM@J&ktAJ!v2lx+H4RjwnLp3p7>;-~N-^e`riijXf%xnGyuv!Z>vR{#C1e@$Y!G zhH!;hN>?Vv0S_c<#x>@5so-+pE(Q%O0uS7jTrSO@zj~W)5@;;-Y90PnF~$gC3Or%Y z_xqs#lZ$KTPaaL*y0~sWo6O#)5Caw9sl=ac3QPPPDdTQAl?S!Z?Z|II0I7R52`AqCd)mm{He)l?Hs zpdY+qu*a@^XW-4#$G!)?PeOqW&4*71MWR0bC#OemsV9HNdb7FVvHB%Z zikvBqaw%H>NPPpe9^mZPRNVy2;;cucXdV2P#=k{5>m&6mq)C>&+i>T{yhz?nETKKj z6IutnqUd%hR99D7mRnX?Fau^A`jWMq)9upq<;0o7U8g}GfaRL}-`f9d4Rrijn$F+o zKG{7Ft#b{8*DAc9km`IoOTQ`KX7kyN9Q^66&OxLA;5i=mrG6e7cue$9?l}XBWc}2S;fbISCqyLx z$2NSml9@J#yxbahTT_5#4??5h#5Q=m<6$Rn)QLJqwvx{`G){eC9_*lbg~By;8#6Vu z3DUoqIP|fIoh6pGv7@QI*OP!X-UpuwT(nuXX*a?$OeywW)58q^Z6lkA=4 z`lV07&%YvJuH^FO|$okFHIX=Z)eZD+Jy&Mo{G_TG(SM@A)5Mr|~T` z_Ic)Rd()>U2Ct0j-XKQXg zMX|4P;FALI5_jGmKPXYMACy1_d~sO0Ge(@h0-JOSJN#WUolKluoJFaD%lQH{4X{V) zzWhjgWDX-omD)kx6@U>RF%wOKbpiDDxUYFSo}qWg3d!Q8c4ji2i$jma*?qT1g1UN; zT`WFxLy@AN-sSW@bq;=h$vZ50ADAVw*Nr)fX!NGn=Q8n#s|q>qMDg~u{n8TiP2lIK zS^5{8&YZ-RkCoX=;Gv4&o(CT!iiC*mOB%x=hvA&Qzz-o;k7J!bx&KEZ&q?25U&?y* zhzkIpy*YgR6x`yR7{sal98#E#i;2iIfJ>*dDPqDi$0PNE%@Q*%GYtOVwwep=e|;_$ zQjFhTKO=3|r3!mtz3ngLMg%TNLTL&->4n-@JQHg3%Vc9LDBFIW@I4D`8mEbquhZQv z$3aU|h*#i0dgBK#GpEkI%xuo(nBM}lap2P`bNn5AT#$o}3wC+{F^zhnUP^Ph$;qPg zy4K|}C~|F(<|!bn{Ny>yWY#r5mz}If|MMX!Nx&@8&R2-FH6oz+%XMU>Y)XWu)T>G2{u^fWxgvq=N{Q=N zWqS@Z)@;}_YHYAFtx6HATB@YFnJVFkB$S$fW6TCD6Bnw)FKZ}@`8lh`xd>8`ZgB_Z z^G5goiaQo;ba-o&a?N)lmERP}Psd?+(4%K~2lb;8PqclsARSSVSwk2+!Pu5@uq-56 zS|k4QnsGgB?M6#qf_Iq}32oT76xD3DkRmQ_v0&D|)aiwfx-ALCBFiR=8P|x~J}rM^ zikRBM33}{6qVaHxKzc;aJ%Z9$lz1h*)5W*JhgbnwDtunR3x+{_pp9(JD4&NsFAiTn zAk9un$Brg?(aVn!7v6T)og=;%JFchVBwV>?R;z7Qk~yE5 zVG;M+a5E-_?YhyuO0;2?1;vf-N1%hLb$HXz$0S=)lrAC7OvGD2`w+&k3ExjPrpe+T z+lZFRcdXm6&VCxP;j7@IpPk!QUy8pBY(CZ@W}Z|s5%}`YabD-jab6kIEaxF`H5pTq zqXl1)zF>xvVCQ0Co;bS=df&Kpbav7C4Tfqm9$uI zMI3~#UU(Rvl90N{|HcCe}-AUb$rXVhpVP&q%{o5h_cjG{zyq`RUoG2nx^pgri(ZU2eszn53rIJ^9_B~)uLhS3If$I3U|9pnqONy; z*b^({<}AT;&X(?+i)c?fJ5iV^K62dx-r8*JK;}CA^}xPP2Mcn7`dgvz&%%@GZ0Ktz zi64SbK{tYL<55YdQbH>_sep8oT89|px?flI>-FBMu zO8U`XG@>%mY-HeD$k)Wa0no$@-PflEIF|=EbF`T}_Y&1Y{F*OvXr*7S^M^OQ*h;Jz zbPpKJZ4ji@d}XrO-f~o$UT71DYmn~ffInbcK}(JqtNB^Ku9NX?lr)4{iLCGS?nnE0 zNQT+U>)_Y3h_5x#iCXhH_-HM&!3QuTrZdId_EdZs&32MFtDX2LJ8VRe@rWz3(^`mq zNp-9-Nxa;?0rTj6>fv^?OgEEW@^Sb9`9h%8P@y&LkeTfSMOG7yt?S6yy`TlMrPz`% z#}fm4x(YxWvIe4*e{^^DBW^7)g+tetqI4Nf5M+!sL_K=zzv(}V?}f*KEQ(2tI9lzr zj^3}?(@r-l6oXt0BwF8LuoAln9`U0$2lM(mO7$4*|qtOpzETbfEhIX_hj^x7QPF zs$F|??IiR|H*u1<^i3KiWb}x=z(vQ)rO9FkVoT5(@2k^R`fjt~w)Cl>)uy}g0DNgD z_WlS}jWN9xKC*cba9S!A+!0nqQzSGJ<4+M7z@H)yM&jQ=`GsZ)TvQH$9^^WH3+!l$n%2>#X7CPnPIK|DJZVroq< zrxIYdc#ga>q=;E^-JPd0uKQP0TzYz{vyq3?Yrl8N5MNC9R;u6{%OnaJAT@7z_mPz8oHeU2xzhkU9jUU%m0$M`RsK1KY-?y!J;ffWJA0)ZK2ies<) zz32Z&@0SNu2V%tR0mQGrPNSkPPsDitr`=ocSM5JqUvxuT;{$6C{~C55hZq0~L`?E4 zx8U?p9|tk(UoyHLW+@}ShxoZmF)M1c&|jDfA0KMOO447*v9HZrWv_?~hSy_t8%14F z0ME!_=p6310S81J`fs0M<5>qEKhYP>C(i+J-KJL(RbD>j|C0vf!`-2}tyo2>F zE`Bk*^j@-_>vd(m^Ay+mMQ>QT%5|=HUgnB+AEdv)jA2C&VaE0a9t)7??1lE9=PVHV z)808-{V#L2;{VLqKd$@KXscPw8B^h%GkW&Uy#3&Qa+m{5OfWwuhB5H!Y~U+sK9_*= z%pAr|a3ERyMY9?-4A0#0!u%X)$sjM+r=oGNtBdcwlzzD$nwg_dCSfOCZT{!?8gPVU zTvWdnvByimmuOo*7Z!*!#bwuaAi{^n;v>fXPD7S%>EtVwbo_E14E#&n1XiR+v|hp; z5EJ*quW)8*f3AT}V=Qh(*>4xHitzVKrFU)IHg$YDc=0)jS@qE8177GtaJh|#+fQwK3XtX47(Lp32U?t35j0DM9P>SI zOocQa+6N^6!|W~#$ayu#Nz$+Q6}UUe|K3u^9XR!HGZVYm@j9^R)!;Okjr*l^+`r0} zybaI=H9q^~%fK;DZ_8**dSR}8Ke(ty;Be+7Ht7}oOY;&g?UzpJw%VDv$&kaxf_Hez z{Ic|}?#HJ*?#H3ciyJg;rugSKg5+6zUD|*5jt_92-bS90;F-mKCsya&^WIdlcpLLU zHkjhVeUhqNDU`{2VJp&Ty%cy;v6Na_3_P9g@p*cZf|l64V|xkwjTP)cU;xBbsI)#- zuW2gpkJhQ<{I4-_zHOCO?1JE5)$>l2nrlF5pJx8H67=?D>N~d13G;O!D4&5?>?;88AAs&-j~Q_GF!{x15bbo`hV%tV4oDa< zNB`*WfM$~(n4WD7Ux!(O^?Vumv08CoeU z!VCqqbH^{R;I#TLLXB_(UyP_mFN1dO25yZxhJD#YDHb#ILK_P__tMlmjMZ63xfV!xV|vc)TXV?cixq(-Mf)vRDI{uUfl{pB!3u6HJRc^8l@|G%30VcrXjAxM;g*vOc77D*y!&tMS&+GX{BNdd{A@FIEz-0NC~6vA9{oe3)YMOuC*Lp!&lOn1>gWYn^mRhB#S?V{#p_e-?!pFWk=bsTO#JmM{z@&)T?P11W zrQe2TrK-~+&%vYZ9-quUC|00k4m-y(!PP41m}%lH=x#b1!>0Tuo#N?0VIDJ*hS^c$ zIZDrMztbz_lI5EF<(ld38k)DABF@3fppa=Fr-;98n+z^wG}=DcHpP_(ud+S*n=3Ex zg(h+d*--xAPJ~~3-$ug=tK@ckHCHoJoO*+vVGSwb_t&5^T*+2ap6XJ>v$79!s@vE? zr9=szXeWM`2(I1EI&j%4EnWY!OmR}Vk8nV>urwNRSvo&P#DoWLkgZL!Ly1|0mKb_f z)GUoo6o$LEbt!AYl4^_P8wDKg=i&WQ=^T8Xv{axywV8Ew=iC5&j!5ecYo?3I`skE8G5nk8Y{5oc@E+^WcE}g z0^hXh#ei1Qi%6C^im75}3uzvJ+V9k}zs~+PS1*3oLNUc*Wjs9AMVfy(z|a&1t0=<% z7jXnHw~T94(Kn`gb#s1bV_auJ&#!|v$<0DP)G!+2$Omf3Gx-<|NiriejElT0kmjqG z2l#3pMo>)B9dIwOM*Y`k3&l9uW>9~>z5%_1(*&=p6;WRe7I~v91UY?R!>jP&2YkBd z8Ct#kW)*H8Hrjx*?Ma#{W{vWu=K!uofRm+2r~#Lra1kHzNQ()&jO0;Rkq}wrEmezo zxEGLr{!YH7opv8##dF2;Z|WN6!>7=z_P4Ep&X1nw;?z!f1L}-oW3W?nmR7ga6yCVw zdE));DAeKnFflLJ?Ue#8id>xE$5c6M%7R1RWMKKwAFqV)#-ogH}E zM5E6Ym%K$cAfyL2zZlqEO$h}TUvt5)L!o?JQe1d-ffi>`aiMAfv_4ae_8W)|{tWmS z%mvs)Cof#^1NaZL-yYq>G3@62g=`!zXo2hgpnped4yl(~dB{HNYo)2t`3s4+MBcG~ zFxR54R%$iMIXz=U+a$C#B2s9APGRZUl5Y_?#@m)6tqg^rCi=8A!rSV-rD?Z0>qTh@ zJ&;7!182%MX?KE6nwp65F07OK;78k%$v3stUkEFg26%?#p{SwL^8fcQwJVoiOoRs* zt9Rabj0pS#`@w}rB-`3j>BTIPSu-&YgNGET+#Jclqs;h6*kr~>JGIC8*!DO3b^6^A zs|xbT+o^%AP*n5rB+ClNsc40jD}6=4d0m576Y`%;|Eblj(N>Tpq6bwqtZd=|-{1PV zpDQDlu8^cRtdBWnzyr;Q@eS)r#~7p%hL5Hxpc41()DMg zEaIEcU$%6q@H`{FCbvyP+X~xGl&Vph2p?s^_)GpPr@PMd3Po8CfAl^EWpR$_S1es) zk-879#^LW~XCj`9L~63^4<{Tccsl8dz~5gxqfs{jsd*@wh`+ybCb$rv$b1wu4HNUY ztD)bVl!iO~mYJ?3rorFk@vrEke*IV%Kp>$`7kuk87+PUA_ObvhLwK>t8OZ6L#07i!5(L z3il-9l(EOIb(eOMHKGEkBBT)Q5vlD+afp?9t$VYaQX`cwr<6$Lb*f;i&l#?DKiye{ zz8Jj`y+XSwK?@yPqH?Q}6~HvBqbXYUyV2_#Yx6RDc5V#I^%0kYM^=@51wPd;O8MN5 z2!B}Rm!Ks*gPV8b73mFVQ@xw8B)xvHyNijR*ye3t7JORTl*RVGksS+Dy8eSzn*KbB1c&=CqPm$%zyz*)vu?HHf8u>fUNPRlSfVdJ0tynog zIcRFJi~;^7QF3&E;&RPNsNDd~Ew)se$@-$dg9~+l02<+yx^P%ru`ycFgDAef0{_QY zXcXb5KA;t~(wqIEW?Pa!tUW`_Of)P(p?@+4dh-UsS0JCLTJcedv`!dCkr4@NIF4+% z03&0>$PeK+8oH6X2C~N$J&0Nl`7ptYb~kZK;HL<*u}E=C(g^Px2m1?>JEwx`Crl`b zpmJJ_IO9Vvd?st)ADbYP1Sg@bo;BH!;+sqIXg;4iNAM0ckZ@6XWTUtI*C-boCJL2x zj4`M(OqR;~3*mr3L9$I$tGi;Tp?7W($Jw97#br%j13^)(VJkpr{tmkg4xI4DdpMLOj z-Frh8)X;5NQBU`u$NlFI$ljZtoQUuH-H;yj_gfOd9f+3ONN98P14h1^=5X%wVZfEf1uKH-`L`0-B#v|xKz6miV zU)a=T!4muz6Otv)U%F_&U2`n>)~m1x}(0=mKp8XZlC9>@6~6Tuo@`O zoaqce-jW%P`s~c<&N%e4stg(llHvhaz|-X8_XxT?(K&Kw#ynu;3=9!>4_ z5Zt6%c#j-SmBYv1=o6mWsDcSh{E2H6HTsNM*8mSgI3a`wu#G*q-@i+OS5Dl~!_cL$ zN#-EzxPCKBH?7WIlE>R0`^}wHI8x=3M^6xfiGR*XQ0U2MK#*WSlHkmqMH>NGf~jN+ zO19#+9lsawdkH@qemn3h4c4N?b-8*M(m*egpV@ir**rUBd74pin&V zH>4av^z7%lTFAbaQkhO04af*Q1(C$=!cfK@cRM3+d%{`>G_|K`=6kTQV*UO zk|F3tK+lWPVf>EZcMQLGqxlVlOAt4SB6dKpAVkxUhIydV_)7mBPv{!>G9^B&2n)ao zh~t)O_7}Ly^U#0+Z?T+5%3=$@d|e z&o5o1X=QP!V1=p)dT88Avs}~ZaTkr;Dc?R4PZ&HXT`#YYI~0$7G8OtKGo^5N-&sH6^;E$J{?j?e z^{6yiPrQI&KaV>CeY1yVp@eh?C^c3O4-1Fh|0Tf+-$6D-+o{p2X0`!Nyk&j!idP!t zosom`jL=MY=foe}5}J_!%t&DFo%#3?UaIfR$IXG$LOrm4M)QPAKVuHGd^Iy3cIakg zVIJnqP&h2`!f&3D;T-4U4$=EB3>4#8kDDD?e4DW#CJ{rqfnjfH->|n-!6e=@dZm-* ztagB++VU=V85)k4!kIhc|H&DJ(NQlI1N@<4L6BnQKKBezUzGEc=K=mf2PR8ljB+&h z{D2DbOp3bT+o|!@cB-^_IR_WKF*+Yb4IKR9@cWdNKA?&fmF#gXq8O;_nDhVdHDW_r z#-2KYKx*8e>p`LD0>W}0gUvGksV1p#L89PxhULu8FlQ@I{O3BxXwE(&<lDD#_{*2m#*=uE5ve?-#EJR)iF zdl30hg>FU%C2S{MAAYwAT-`(hk1NMleLE_I2^4Jmo^;+&LdMzppEhuTKX=A9E1dg^yFX( zixR>^pwYPG5R)hwEu~h@nH9FQ3=lmj0NNb%ed7B(?3^#vQ``rVApsX@B7dv?upJ8p zUK?d->kjW>rub*{uR0)=A=Xb-9M^I*E}(^VmB;xyICvxtKnz9rt%NRC0P6I@weHV* z6|+)j+=AvB^=}47SY~Am0U1|TrT5sD2AJ@TJ(dN`q}cQ*dzFc8Icn0hkoH@ENzn{{ zF3^4pfRs>?m>Pcz8nI^hQK5bavz(aVn_n)aBqTvkYfc)xxh5#=tF6BI!N{j3gyhqh z%)q@O5C_N4ywo0ra^DrFm`V8t`)9x$%odG!xREqq#mov}M;@@y4VJFi%NXO%y4|1} z_e$f;JgA*L%XUM13+n@0NK1NcuO%%5kq}rOn&vTlCB++hL&1X6kP0t`wRtEFJ(%Mo z9vVPIorID`s-?9B1t7K#eIk`9%y!ak;hh9S-X56yjlA+k)Fji&*5=uP5gg1>I^OQR zkhKgk4mcL}d+2}d0QjhorW%W9%DV#3>66gMn}qL{FTz}Z((BWc{b+68pGSN6L+^#< zkD&*Cw1>2T+C0Q_Z9JHhAdGW)Td5pqwX(UBK~!DMXuD|x@EDJ=Bp{xnjql`_RyyN|eFfS#A1ejHw95rfE&$9EdRJBBpq&Mb@t=1n6*K6wy5-t$g5J^)1r z@Q$tG*~4K>DI+@;Id$i2I=23h)CljHekJc zlhr~EbI=N#cs5oz+jOJeNBm&GQx7ZL{t{?l88(7`*mq||eZ;pAWgw7t2565A$YS2W z*KG$S=3Q~(*ZYW%LQ?@0hn?t;QrM))Yww7Kj);%=SG;p_Lag9xCtZ=Megj4`1$QpA z8jwmEr13(dLEMa#w@)AONxT#M87I|2x>jD6L;C>r80F`Kch+px-PwC&boPA2rTyN0 zSG&PW{dhHX@*8&KO#mfrlO_h)=-d=3gl^~zh6VvT@xGRehz0tCnP3)d4)_w0RfgDg zfPO~M0;I1Ak66GWJZ_)<@r|{>el%kEFxlRhgVHLBjcqCd^eHD=EEYarkhWp|DH>l% z9?^Z&eq@MX9Q8Cu?&+39{g7lF3_-s(3(eQkgsAx(Tec&nA+h3p% zX*a?0m_rGzXKkJr%HBPRzu1U#q#E6;h^r-(gJP9e9=k3H@j3!IXiX2Bh2!ge#5T;i z_v{>i+;X;Xdp*304p(9I^+H~OvQx_{JA-*;X8@k5^w1u-X|KgtzQDOASz483Na)x^ z|C%;qWuYxd)GEAr;R|`5bD3Z_%HvC^wW6Omge7^ai+t@GaoV{sc!H&QF3Dr{mC`F_ z-+W4!NUzW=0&0#dB~5>3S^?z2HfaPF5Z?}g$FR&x;r%yuuXnYf4V*xi?0)OncbD!akkkwKN-NqyaO{+#%?$dUwN^AvU^HiVLAO zFAde^RZ6As&P{t(>kI~ek9D>_M_On$l)`2K(eGowEo}jJ6r8(P`11V8uXoSy+%1GZj99nII`NitDg(hj4?32+O13g`?im_jdG>^xzPEq5)QC z!DSzJ7FoI8mpHE1lh~CAA&iZ1p(@}(NAR;r%@Ks>5O)gttd2JIXZ2IQf;BJnD#km@ zrO)O-VrDGOyA{SJX-v@ZiZYa;Svp9}OUv7vG_JP=KasPBxB%kJ72IIk+JCMc3w`ZBWGeD(OYwR+{L; zja8Cv88dByGc5NttmIF)anhJw^=kI2=^+XJ73bC6*b9rD zFeVj}U=II!c~UP7a?u~xdu_tuKe!1eBKkRTHBQ?WSi%>4hf&U%&m)Cy?WZI?d@|W?K{In@r{AIaQi~HPQyOexbd1{sr z4oxGboUM$gfyA^jvWC1lP0uk3tAx6RkAOcAY1hH$PlqGOMSlaFk!VNyU1`vwjKF0ZfPO~csUc97-7-yQuy-!zD&}fTDp(fqVwloL?W6Qnl23sAh2!v3;HSo~T>6%0 zV>J#wHWV0KNq%O}9zYrvHQp4(g&`Ypi2@(S4^| zpQe5KQ9p}&m*hk&^by`42GlpSJWG9_K^mF|x#SOlQ!5D6NnBNaSQmWi1m@rf`{A54+a@eHd1NdFu`h~ zCEm^hEs>}}97Ps=_UVY4(1-;xz9dqsXiHy!5ivJ$QzOcpA$QEm0T zQU$0?I{)xNKk^Q>NDN+o5iN)toq-!FVm;z=CR~Y7n#hWdIMY|9gVFJ*3CCAaAO2Uo zZ{he5%Ut>EhGEl*yKOxp?4UJ$K_I@sbdJ7!8h8gI?l@pK=0vhr54N*&z*`13a}1Fg z=+5)rA$?K~`e2WT<&yQkM(o6`O3^UEdxURCUqG9v^MJO|2lFgpY=R~Z)@^`i)u3iS zmSTgP&+?GqU6FEvK7$wI;Pslsi_+uKjNwoimzddiBwru@wscJE1`SjqUDD<+O!uXz zU?JH@nreHQO(|AxQG+z}}%3EpT3bKt>wUue7SDy;2r6_S4> zx;K{(Fpy02U!!}AF(R4~_&m0>@HD@$Dr@HLrOX>mpLB4XCY^)*L8r4E)=MlnZ-m?I z)X~3Xdir;loZbyMxyUz?N z1TJ1meU) zCV`pDmti;XH4kJi;Gd1SFM8H(7;9JcjxS(cSl0rqtASt=@g`DE6MViY_qlv)Ax1&4bpbJ{)`&f*kx6(h#LcO~h0EY!1P+ zw`C4Vghi9fB*w`R(Fmdu&tEO7n@9_`9B|^`LJe;Ju?+E9-RZB$+(GV`A0ioAB*os1 zkoZl2C%ATLYI%zrewS-Pz%gZTbDv$HZsEm1E{i!40p6TG(uZ>;Zlx4)=_o?Qr3F7; znPGo^Lf7L@GNF+@D|#N0Jzrpk$Tv<1AP(e2`$pVtQWW-~uAv&%g%wQrSD0r#VX>jW zXVhW?ENMvQaAtBvy%nD9YmxGnoRv#1pycdi+Q~J!hnR8nv@H1!2Cn+=&k;AiUOJm% z6ff|Rib%hAkj`Jo3#`i*b`{W>?qUan6Pb9oQv*6cf~Q&Un$tZz;?{XAjc58Hi^)FI zACo*6|4vReWm6>XTMY5XJ|RDMb{poC=Jpb}Pa3SR264K)CGfcQZzT@7BuH*W&s>Gg zWkCpW#x>`e1l&W>Hfb~DD_*T&GDB3DX-<#d3o`&8hiWo7uI2KZ?Xr!28Kcw_UiyT~Y7O;ji za0-i!Z$k3@U~wbTyOCx@MX?gn?^onbUeA~~lnZs^U1q;tm|RD$C7FQ(1U9t&$cQ41gw27_^P0(xSvFX#oe_ z%|xcWN)kBom0u+-M2R(+L+S~n(hWRPi#Wx8CHVX!?mtTA?4Ns_LOmi{w-JBm)GQ{*F=ovaJm%mlE2p$HU{4488(*b+G#s9hDFo@9=^kiZR11X zRS!`Yo^PHQ?5Y1lr&iThuSBFaoJ$oyJ-@kBT4;y}j0{4aFO{qXrBeFZQfYoxDdwS6 z5`y6;2k>iA;&PV;zVJOskn!KAc6n)p5%4O&GQh{-ytH(qT|@Tt-+nml2+g)6}#QKG|2`mu`=cam#(u8C|s9CVdyd zy72FuE1fJ4ehVnNTk$sOA9LtV_1ncC;%c~kibIey98&C49a8RNAY~yhJ3330_{>3m zYf_^fa$jXLYeZDPx!&87I12n$U%K;v;nRORz#-qthO95KvR5MU#tZ2e!^)p6u_lAV zLll7bzmU%(PrqGkLi1oTQ$E-!5)6X=h@njdx~#=v-xPpH=EB4_KLRp1?gMJd}%`qG+3-(|g<> zdSY$&kJdvM&!X?iXAbvDOCLyOWAQFM^+Zpc@Ej|i`G4AN&7Syg?GAW;D4zO%+JU?E zZ|!z?JkhZ`wD^J-@hv$!;*r`4++xBa=zpxEuRYv5V5SkWW{gq(7LWVao^cr}p>nXN z=SZ*gtZAf82>fwNzvBMu+pJmfc6`Zfm8#Llp;L9%6f0DVr=K7*z)tz)WgH>S3GlRj=Bag*8H`6Pf_}? z`vp(8TxLfZ**9)QSpmivXfUDWJbXhQB3vwjiGa;;leKj9W8M;w ztHs*OwQGkF)e<^m@b+x!x({DuKu%-0$#`>-cj~aF!_e2oF2Y->HSK_5x34@uuYu-_ z%~yb@Fw#g6FJK;TO8sY@0TCas?ZM1?Af(OfqUp8T4nYW)3^&L z2C)v`*!W>Sajnc&19}+n3O?aqGX@rwQKsPpNwa(J@=o(9(r=X^u`gnUJv*$2h zIoK=LQGZ{I)_TXh5B>Rap(ro1Vn6gf3d<_2{|L>^qtPBit*m=9?0ymL;J*d4;wywV z(tN88TIf5|Znt9{o*7XasP_YFLh$_4Bd^$RD`D^DZ|V8~wSxoewU?2%be&7P?C*VZ z=lh_L;!;6Zg$jD7rLQ?Cci;F=oZE`Oc<x0vLXgV_oy{~eN_GwqtWm-?XV_glpcE(a7wV^Jjkc$3hiw!~ zkZOnBn+6!It==0&kouw(SwEof5!a>P{!0kW$LuukT6yQ>bG+3bv+QwS_pC27m8k@Z zgFx*X(x8)zH64cU;FD#LfZbM2rjpb3-Zz~BM)o6gIX)+-1KU8-ms*3~#sKdL0R?L5 zdn$>-Iu{7rn>Se(Wg zRx`tH6~^z)({A<*S-XO^kS;@e_ki15jx*B#v6}sgy}z5rjVEzN`Y)>EuHsHh)8nZv z{h&dxdnldX4_!7(PPV158nZC$&gswW*|)}9w^pt@mTl>JS$=L6o+}-FZiQSI3))Tg z2b1}F9bZvyU?xS_u%cb9fD#9Vfc=5{b^C|i_hYW!4Jwh}mx}bZpdE5Lu|G}-KH=4b z$?)h$*R^%cu)A`IAd7dMDZd92x;t>#gs&_a8r=ox3-DjA_1=c3S?uk*wFFI{K`q&h z!|Ktaox&K&Dh2SYK#$!U08g}YJvvwzUkTGV#-89hUS`>ur|PxS(xgT6utOebs%M}( zz+!HKVV^I_&~aPP5`4pT+`=@jETo$$jZv>c`m*FREu%$oG7Qi@El2SlGwD%D(XnyC z8%+x(Mbt)t`VSmPnwmzJ6@hVi{S3y;B*1^nvuZOvxt$I0CGts@=}@d^oQL$9|#e=}QQrxS_-DN0CkpQp@ROl5$WZJ(r$&`&h6FXD4Kh9{P^M z?xoWEK{PuFL6lo8ZB9QS=M#}9ozh|V184EKm}xrF=JlCRaNwv62c}3Ic7jdL)BE-g zp3aFjMag@a@QHB}VKLtK2T9l`)(~(j3Dcq0TLw|GmR4i)GCCp861N{wv~l;qh|JRU z3u}Opt3cdR18A#C!2coY-FLM2Iq;s>1vo`d$0JQrKl(1Kpr9E`8*<-lDgtltlr+}N zRq9}+?%z3<$Bu$LAy-(7*lHg4LC<+t z@tg`~DzQs%dFYL$QX%3Z47m>@>g$oTBhn^0cL;Uw1|5;M$hivCwXQiLZIyF-klVEE zh_qeKl_IwpxfkTzi^yf5mzU(+7UUj8&L-!cL+&BuO66P*-jIqnydvk;AU7MiGC8*j zIW>Dk+AZgndyYu2DN~{00>3J-%i_p0C`OrW^n)ZQSI`*&;W1Jj<|EW>1P(XWY_h5A zNbcl8bad}}54mS}{&l_g!zTOZ^+v1&c_g&nLpZ_zzTPhl{Ofve8TkKR@9pw#x_7+? z=uD5UcaMC&?_KW>U>Bd(v8S*`*$VL6$f5~eLb|`|R2$PP^~MF22c%2MY5UU~LycCP z$jqLlg=xp=*^dU1ZZg&K_Xg^w9c;1V2`tvp_nf@c8vB@l~g#! z<8A{!c}ChaiDrBVQNt;>WfJYHA@}ogZY%2EMcpPjw;gq@YleV1QOg&Q+q7&5m=on* zLT)p1PslkNavA7lrJO58?m^_1$+=gMdkDEDa;^+-NW~k{<=k%MW+OLm5?sSLk;Nr?*4RFOa6*mnpIu@;<2cfrTb< zn97y#)1k2;R`jr{^8&BH%KE^1ldV*~?m^5hpBiYNiW9k0QkZ^~&uZVc`cqPrSyOYl zel=na1oA4tKz(-l7`Y+O6xp?*8oeEsj!HCO-)*#SkR_y z^N(Z+>JV)f2+0}6XZ;Lt?rWf-J2>0{Njd4>+SmT2cBhmn`hrVN_|A@Qnx#$HMFGPlh{xE7NOoNW$MK~@ZpAQR zeuU%w6FA;iPMT|?^~-=wJSox6BA9K&PGcq!CXh>(zWd?%Z%B#RysY%n2Se@-IiCd@ zflAI{KYt5+B3DqNZ4G7=-sv!7L+-z$G!f}sq@7564C%;i1pYA%b3$MB6sX-{_heX> z;wC8(8`RM9BdEdwia_7iNYZK+R+-9^z)m)%b$yDsN+a$qh^&q5sl%Dsqbs}vT_!<#d&`{G z)dk)24<1398G-*(vXYglzNJU%_V=%NQXxERA9h=ZkxsUB{UPlz>}ow2eNFw4`#5;A z4(N=L2H{Q{#gs9gREbZIL}M)yWD6?NC{u}BMkbtu_i2y=9F4<6DoiNn5PIq@Mdo+VG?zL1XH1!oP}f!m+Sl zU~KYJA4{()6p32Y><8Q~Y*ZT~G5_N$#~LFl`IF%|H3Y%Kk4IsyP7c9OT@p!|ApOT$ zgEulnqvEl;bP_C{{Zdj&hn>nO|M}p4DPeLtvtLSlx~=}L$eM^qnfDW7p&jnT-kIVl zgjNWpJqDVSi8zVyZ7>{zn}IMfq5_V97NdPJgxKCpPxiw1APIQOW&uq?PZC^KcytEv z|1(3Oo8v95MQK0iX(o%x{qB~}Lis;YZu<}A-;5~aUNmS89sqc?nLX8L|J4XDzbmun zx5)i%?vR4t$7DE$%q(J!|^>Yq+7a+iC*ugfO;e;Ga$`P6gddGdtvV zBc6#8Blfrj%s#Aj@C>}crg^n_=E>fUZ{_c*gAXE{NO(w)Ph*HdS*fa2<3yesA}!dN zj)$OKpggWRp*}g{-ZQ}OpM{vlI@jyi5sXQ4oaz5^j;iuZ|KH}Q@vmc!5;TXokgx3c zUU@uL2>5KoeSV0YX`6p9GEaruYyAM2#RGGVE z!mPfJ^Fg;i`o_!;x$7w}*W1=o{)Ak=c^SQ%^6%Vj&ty@)8hJ0TjFIb!{vYkXfa-VO z&C~N6;2)gHqW6WM?ghE8hwyGDE1)q6mIPF~5#wa!aZs@$$9U1i6cs$cY^^}Y5yU9DfGRFk4adU8gHUB%`=13;=zeD-JLh=Z8?8u-iF-& zdr#iBcF6rbo#4Bx=6zE;?9xVe2wHp%%9~kxhue$uKQs}rj(BPG<$ncb?ak5GT%fk2 zd}f-rv-jj_-s*^ow|d*#kw12~Z|{m6#@DdG54=2~10S;FzZF(=oHJ;#%D}t$IE6EC zaUk~mn?wGtHI0NrK-!6(N``GG9x>0L+o zA@_Z9iQnB4@B0(+{y*W}>|#HB|9u~9LYnZasTq}s9}y^QfVGTXww9SB@P8p)&#BP$ zj4bnc*JO*y_|J7FTc({w>7l{r@`vwHXz(P(Bor)A zIpC#mphW6v1BYpAfa^Hm)0)-rr63_%$IK!3OOjz)pL1NJ88CIoV-^CTZvfoZL($mD zHx1csgvhwcRp{jP;g{{=nNQli<0zN>R{%!FFujg#3S&96G}y{Tuy%|W)F+v$VR$ts zzZU9~7TCuRq1N!9hSuw#bHThG4M`yP9zD@I@U?UdKHlcw z&fV=f0BbjBzQGSjAj=Q3%YuCnUHXx|k`6Wvb0 z2r-i(v4elRZwh{quC4aNN!h+}N&24#yZTZTPr_dd;{&Ne{sH8xg-gOzmj#&JuzT4s zboQox*;F_G(+-VheL8>Dt0|>$W!=@8VrmH6&O=>W2=TTRuGLm=YPHoXY20BXi>)P+ zVlFJ{`WqKGobW=ilc*a7`1cb8m1~)#@k1=Puw|0MZ(5jNLZ!90ZMlY-euid0fsMvk zpZ;eUzD{J1?;q^y9R^lQQNeT5*Qb9L!X{h}S*&9d-|n@o$pUZP6H*P|eG$STNFaR$ z?P9&K8!4@@N6ypN)+kTGkA00ldOmSV3NVkj%ZG~q+ZphI3LAFZ{ubI$-xex`82!rh z`F(oG?7Brp@uX4y8{gbyK~xo*pO1!EL_1fuMevs+yfdS8g)Lc?en+2-skyAU>_;u4 z_*)UTLfGUdbxN1+!N=3R=_jqX6u11?=^A(ovGiRH8k8j`mcFlpd|cdgtz7yQN~g(k zkiQ2R;PHHl=Y{jENc<`(J&-hOfC(+?vT?*`1O<^zG7!M{f#)X>W<_Vzx@O4z+yM4| z;hR?I58rpH-Xv2Xm(~!+74RQAy_T*tIhPJ7^4I_~-LHwA!cEam(hHM;)h#C|Yvo*) zt_Ri-O)}(OIKb+!buZ}se+YXI_$aHafBbo-r;$m633UpD6w0K4*kCe&p+pVEf`D!) zx&ycxh$uy25K!!agqDD^QkG(20&xwBiGr`L>$({NN)a8!T`{aWDa>=HB=h^8`%D7v z`~E+FKA$k>+;iJ=%em*Cd+xcEa{SzoAN z2gA~YK;OymFNqytSjr3-CX?h6mMn;6Yf(=)#STnM@uu*UR)kTyBw%vv#GaIKxZ837 zdBmeUH9U2`DULzE+f&p+Vt=)e-A66Vz~8_7sfAdBT1dg)tq6Y-VOM&q1=>9~v%wmj z`=Ye}J+kVlV7s%)Hb~5tZpOPE^)hah zsSeSZgGeD6D--fSxs|xGwcJNF@Fr1TIaooS@fcB&D^A-2?XWW)V^=; zxMVcaKKwhj)0K_8_c4Ojl#l+9b6YG+Y<^R2r*r`4hm+x_scQ*IaWO5TSm+;&TD^)| zO**PK&9l6GB^I(WxSk0*LfE_Lc4H*q9+BD$J(+O`-glJClrHIUy6i0{|B|r$fF3(P zT3&v%yj+x52Hg*&T%3v5?Ntc-_A3O~FAXMt$LgxIyNpA{DwB!){HYJYjvk&L!%}L< zHmubnY_m9op_zEAE`ADmgbYi%&~1=Ig-X>m*L=L;QK^ll`>~d&fuL*HZywt9Q5lWU z-KG|koHEcU4AFX%i&ITvNS#YkdP0{ts?L7RBMiZ+6bq9?k!6J<88z~TMj8o-A*ygTeO?`LnST^MOjQwaLx6(-Dd>{CKq zpX@ZzPRq75B>fATPov`vQwqM~I}STJd>;FfH_+2L2yX`L1Wc*_5wRiuJ|5>&>;a9A zwH*EkXD8j^?<4+Nla7~G$6=gzFD*stw}I`5=6V2dOcZ{Dm%M}Lw3COI@zh&+_*NcX zfp9uQp&Grw^;UBDdLG`3$6p;GJ%=2=9BcN6;BN{O?SQ@WLegW1xiy-@LV{UCfzpIk zD=#F?`|@tuccA4&YjnPg`dO|~Gs15%$)o2V zfM1J#<)?s0@%S`vLQ(_t)bfs%}EnC%R}nki>pFxc;H8#R^&h zuG?S8^?nWYCT)i}WG7~K*WEO`Bf-6xO#+`yfgsI31&7;%G%Hmc{v}8=QN!V%f;9Vd z9R5D2!0d}v??k<51m&YnL*)^KHXjBoucz0B^kCE<1A*<0wyuHt27SGn_jOVi&C|Uc zjw6bl@?MSaR{_IGVzjS1v0{xe$t^4KJz)2&^mS5?x_AyPwA(`(c^+TxH1<#~A^qBD z4Zh~5-eY+RPp1ZPC&JRB?K6?rL!RY@loEB% z;IVFj9f8pio&QMD%@;=S+REXXJkB7*mq(%T1X)gy)W4(AEz;{W+KD?&K0cdT0b>o|@Kqj8V}z_`Lek|A$i@&eV5-XT+z~omBHiy} zicV=oh%}|Ix#)bz$j^tMtG0+0s!C`$Zx!=hIYDUU#DiVZeK-TNLQ^XqR6##AmF#z+ zIeG@?2MfqI23m1CAgLJ30X?Tu6EbYb$XOf}g^=+#UV|)=gV9yez!G zCwx)(&pq&hu$9M9pvNB!KZZGr@8`VtKGGdbCmqaVpiK?S=Lfd7uM5F-poRS!vU%A& z#KCumq*bUJe0}h<0@5)FOKBdIh3T|WXwZG66k<*Uzts&x}*qg!U4DNpLJoDJ=fMsqxjO_v}bKneC16bz3Mx5X8yMY5Q#TXolHMMLW z^~qvjd9=cEjK-(TkBI|60BkS3dgi0l`{*1Wd_v~HQ$yD|@D!qeAIX#=V8l;kj&vJx z=;pwqqm}?NpB)*pfh))yI4hb)rkF#<9!h_tUmLAK@6cHAa(NZehlo$fWyJC_$oCug zKb6r_I^I`BESb|v!Rws16?5h~r){AVYqYVz@cewMI@lS=&3(nC-|S85t1fHOD227k`5z6Y&>LP5`6!G zv)&x+eK@{yF!r0em|m47@DQZOx5OX(2P>%1HX#1xKtHb86B-PaT%R|QpE(If*xUCUVMjg@jFazr_P(ul zRg-8<#OqXiZ+TVJPncrso5%EJ5q^U%ksdh3tR;RoJGWCM;$5xMICo z9f}F$Lo>Gr>ufxHHseLc0F4F0L(;AAshEd`BopE+GtEHjMv_BPUtl?oCt+b4l2QRL;W85K01|*LjqVQ6A`>zH>$iWb z6sj7O!lXvrhrr*DA1Q?c2=n6)zWrd=4IRFPX2P$i-_EFXcm?nvlh^D*U;F?#Lzct9 z11|y_jI#BhoaM0Ghr)d9|9}qxO$XYi9KKF#0G@%m*_L94mWOZ>j}_5uvt*!TH*TXE z9c#=v8$;4zgquuj%!>iT;sKx5&4mjc5fVnD+m)FLvRqj#@P+J=Y-H zt;v=~T?Ommmy5nkKrU9)dM{wAK{jCeN-A}5^vkH!fq-iePNfzJP=9pfeJ1f507psW%1!{uOW@U?bowfL8-H1O5T<(|}U} ze*^d!8$4u;DJXpva>2Ii7|TF-6T;UbPA1^b0gnZo4fqt`;edw${t$3F;1Ph|1DpZa z3b+>VAi#Nm-vs;=;AFu2LsTY}9h7#5RFKTz!yKBsyI~nz#m1&}O1jQt?6x%WH%WF- zKYpmMdjb2AAYKHsVZDC=^I~&tP{O4mq}KTlyJOdf%q$N31fiZ|1J1N#tlNF1ed z%rhO@7?gekf1hD$0n`HMZd3O2LFr$B?lUa{I52iy1dmYepQwyMKKzEt4Uk*xJ0F{^)0jdCWr|A%&7XjU2Y5_!Y z&lFSkD?!-w8y&@_MSz|HG|6-b(35~Bn_2)Z1vJ5w{c2G96Cj6a5g;cZgXs{U`G9US zwE%h$(6gpGW-|t*nSkZlP5neC@!e})P^#=)iWa9em}oD77LjVvt7OSfFW2GRD|_5&S0^LFPLgJinuBI z7TzZd!eU?O=$cQxj5TRqQOCxjAkO0wS`}Jhi1P5&IY!4ojHeng2wxPcC~h_P13tD> z&GA>kr)V7tN~2KQ3KPi#H!;PypftR5V9#tB+DWse)JNw!1NjIW*l9t?eF!l+Ugcvu zt+T|pK(_$5u_I$H;+;oX#@K|Od^;fD;6ADS?JV8df0gIZ8Q#o)Uk_B`E*_2AYMf7e zHmMQ*8%kQvO-l1c54FSYBpJdY09y_aFq^8B%UgIv$p1%$xvbOrAVr_~}3)`oBIC z^4`9eL}AY>qQL47nlz4HcM4vU-^t-^9G(bR6-`wbPDQGf zk`bv=kZVvH1AV-_>j+AD&>eJ_H7rcBrCe?XuY+74Bab7)eR&)iPDLr*b?X)W45duu zbt~d^P-C@}`EO8)@LgnzV>e0^r$cA0VyJ%uoXiS{HxSmG00#^Ex+eIV~rxrtXO^8YR|8=IZ=4`;d0YArMmDz(*BFB&i zbWX-#R=>L)i>Zq zLUB;=kvE}4<>z>rZu|JSpw73({(0-bSZy#?DrqT=6Gnc~@Q3k#zpB;h+}m(_7&n6S zwxY&X7o_|}orj(9cvh*X5D!;gfnD065N<6gYex6WDWxyCv-4xRi)6)lZ*61iK;>(; z*i6Nx*fFX?g}1RaR#Y;(^be5`V zzxt}RZo?7yNjo$EBX2a9;~2q?SLE1@6?h*lKJ4$^n%FEAh53JlxN4KjssPK4DV}K4EthY+-*Z zptnw5@+P#d79-MEkpYJW9>$6NLF|gUZ2pcUBi=vxqD$Z5f<>mSZ53=E_ZL#w$6bx; z#)L@bv+&wOZpj7uUv~nfHMXw933&g5+u=jT0BgXo^e(Fk7?x03pQb+tI}WYGpTM9hy1<|7VEa)Qp=THIB)h;jUtq+`q!YW31yfq#6jTf6LsPye)>) zY)-0pXvb7l{>&V%%Ycn)Kw8lSKNz(LpE;rLTeTfAMW!O?jGf= z?fZPK+pfIye7_eAMNBp9u)Q4?im;7^t!!_Lp;A2D2f7QglkIb`ZzU`eBPMR2$oC`N z@|al>67wJ2Xed_TK9gyx&Ho&3_XJ?QNiUN6=Hm3T^WBiIZA84$;fHUzXOjZ3-h2x? zd%O?XVVE0`Mu1~wLuauTluW>RfY$>y1Gf1$B*`y<2Bf|p>ahmNr(dw)hi1#xmOEGO z@5chf9SMg7vot9E5x3jA@0I1w1*gQ0p5A(UBN8#s;xV%kdUrqoPqFzYi2>ysm`C+Np6gNWYsbi0hGT=4)I(QmRS51Od$3FJRD7r(KjJr+=oua8O@W>F-xRSLV z-I$ekXAR;ra_`3@yoo7=fvCmZzs`7Y7nmi(f8sT?Gy$%nB@Z7T^f=`;EZJV z{G%aXyUp*$h$X2gD1Arwr@)Kp_D70?`(VTDIfFC!F_05{kkU87Ga=s3!~QP|`{rIj zxn=%|et59cSuDb@vr$8uvovnScGRBDeLmN0%q%_Z5)bP#^h1hPxUnE5EUU^Zx;$_Ns&gSQ-!NZ*-o6HHFR&Z=Hr!2el+kW;eb*TI+87 zDXs}1%v~6imf?0mx13P`U3B+)KZ1w%=PN}f;79Vdg0B^BGAF}l#mYxsC($#ju}9A} z1#lDpX4H^Yz<~7END|G-hBEY{9=6X@kfUoU&A_jbg5%gv(FzohK5AG8ub9J3FAkjI z7IS)?U+DgGt12Eobp_kicmY23ax~{Xt)ei7`%fkR8uX{f=ul-1hL=9kH_(!(R0=qS znoB1^0ldjUV@jJ#y2@Cu!b}wU^1no=Z-_$J?g+epo#;;W+fU>{kzT~0QyD*OztynV z9F|*ilsx!4b6sprKJ53(@k&Sj0(kS8ldr`8GxJmNe`)?r@HDbK-^Ets&js`ZpeOP7 zIR2L9(|vKsD&_#ZO>99pX`LvH+BhIR03T8P7Jb5;2&ei|eFD;Sd;xunjNx`FZYy_V z=X+VkrPO_KHABU6*ZgD`PhOiLliE)VO<1$D9_y4J#d59geX9h+c4~fqu&Vjlh z#LGhxq9Id@FgAEduV~0}gnWq*Dl?IX;hitwB^}_WJQs>_f~QG}rg<76#}GoJ(B@A@ z-QEJ`>%sN|lPPo}6p+a3K#rS&xZ8T-5>^q7n}YA6xEp)orh>Y*CoW+tqj6KCahG-_ zqF1P-G*B1!#3gJ&G;Ufn?i}DGq1pVsLA?i9Jg+ZdcL9@Iov?|(8X?8XF>S!8gx<)< zh8`LNJc>noVI)G7Jg+`TO{-YE+2-$qwhEUABqMNZ6!!r)0B`Jxodk@>`cNzo$-fLO%HkNCzQ{jfO^xW`oyG z>oammBwl}R?@k~T*$FO zpiSzGnB#$!bgairF9asn=>uT5plwPzKEPT}CoVS3u3XTE^0eQhlx)y#ZQoCm>HR@B z_0WF+y)UQ#5T*M-PXc`)Pk$NoSWdru16|}HKTe}q0Vx=cnA0e>f2%1VwPR;WP_#Dl z15yj<{JZ?yK))Pb6aC76A@6S}cH6&@_iF5re2Co)I?t``-=Kd158@Q#-#kV@I@Oc< zCs0rD)IUX28<6@~lwQ(t0xk0vPfal8ACUI-r2ZMHU*oBNj;7Wl^%l^3^Do(in!dun zWD~xG>NW}V4fvALygossU)}v(ZP$Q3$#c7g+^81{(29?OKA6Y$gZ@WO_ebe^&>!rf zOQ7G!>Cz4KyQ1`xjs|?oM9>M6^QZJz`-K~_HU)D$A<`ZHM1ziJr zNkfuz}TSRJIPs^PKU5xh1X&xg0twVR8HiO#6 z^#ZoG<|wtLhk6Fo%Tel?DD@(!YF_Uu)cXwfvo?QKw9R*;&HoO1GN*3={S?vL0!Z6E z*5BtLzeGb;76qUOr#L?%M7Gkv{0|xUT(q@4gc`gN((!~yQJd~-Bio7wJl5uKSpPxgbt#-@!TQhZbv9bB4^c1DI@tVl%0_KV zAqmlti1`mlq2XB84fIZE6>R=2oC^}&&#`-eJqYZ#;1-rSn&>46X?D*=*uUruKYB;( zXi`ABL@C@rx%C#Ygs`lC2|;E_T@L?6ma`+hAn_Bw?Mgt{i`ot_{_~ZdT4PHJo7qJ&TDP0 zA(sVKj7mvIRH;{`xx?m2Dt*)8yE_ddn3oNSF%UaYOg?w#V|EysMKRk39~l=W56Lf<|T zUsP(TwC7%o)|$7?6BcFu#aiT>Qfa69WKuaOww?%!&6AZ%F*YLG(V%knqbm8Yo= z)%MtC`ZB>ptxhd2x9*m3cWcQljFj`4G^eYv_F21pH{(7N(j#no7x@r+);_RFPB{zr zWl?%hzZ?l5UOvu@c?gZ@fV3ayUAXNRq7<|rR`~26lyNN$-O9vWF8Dj5cTnjJ%nToE zBqs0aO_9W%0WB8v3~KFs<0@77-nh&%$L8J4UI@Siv4Gi|0 zz&e1f0JfTAVPN}!JqauqI+lEXx`uW-ZmrXpHyla9NvP~MFCe|ll$>Xe1($n{on?2Y z(X2N`s#sF0(vptX1?g6U!i$~KCcLbSU4JZmaw#{#k_9_f(L_2tD|CjX_43)VXgUT> z3HAC?tYz!j=LK{EYlq*6$EPu9EC?G9Y#Fej9CL6V7ECg7th*P}Io92a$sFtM#W;?2 z_o9kp-M!d}bL3;JyBGZ&>+Z$hIM&^ZS2)()i{EpsyB9BTth*PRIo92aUvR9u7eB!X z{=WxfHt=5j5VR^jCgb1}qYC3Y67|MGW1GQ~;IW>ueSqiFJ+}YMvF<*u=2&+hS8}Yo zk6+@LA7g`N!3K_XkCfG@O^|AXQAG2NNy}i1s;|q0%}UH<27k)9-)zQveGBJHxS1i00=$_7%rEfZYu29LIhM(fr)UE^zGMz-|Nf4adF% zwglL>96N{8i?>m_mt!8#%0c^qW1je;QICF-lZp2X$)Lyp?Vf+`xVB%KNKnB;;sn_$;;nG-JOv5A|h$u4vHJ{Fd1 z#5vqTP>I9IH-v-IkK|Lagl@5II0Ahu-U(64ci0pdfn~yG`6ipf_Z$389WJDicLARD z_HyVfPN_?6bZQ-uUhaY~6i8(uoC%TTG@bl{(?iPIGWUOAHOr(Ak?xj4@_EK!E1)>o z*zQWF`2C>k6JVdEKrf5XFn$FdOdd~{r5t`m zxzIpDD@z{ApnXD)L8%|glWR=20=BlXXvwF75 zpmZJ@a5={Wo?{z4zsWhyMBZcPQp_2_lkinT`B&q_Ba)17L;Wcy(nv6P&Y_#?kz@+n zkMB6xnS~bUlCsg0=p8$S)7adFRE7AKjrf+ysQnD!ii5DZK&wz2PDfdpC^eGIM;=<3 zN$U{jezg5%q!D+7q`6%zryoeB@o{RIdZO&Z)K|=5s(zg}a;kd+|C>|orZ(V`*F@C!I;XP1 z;*)0Xub8>dh%|2Y@m(>^(mcd`6WqqZTRI2Wbxt%G*mX`cfO-M*x#NcUycYQoHU-t;1V@=#bX zk=G^Yz)@OQ@*zgIZv$#SvO4IJcJpz``9GgULCk~zyh_aqYT(O+Qhy!BoPeITvHV@M zd-sgU$2$LGXgHq{DKi@Z5kkB1ArNEJvXe!|qZjqFHtmdgTq8xrjLl zzJhXThZ^;X!=x=pkrxf2JwrbQg8TF5+V@@SPMsT}`|~dC*Pb}6J|t@%K&_}gZ;<5E zwv(?VR2L>ae|$CUtjULl%JKY>L`MaE2hN;aa|_#6Pv3!+!;2XtWKM1BUfp&Uo??$L zVbUYWa~HG0^VyS;Oq6po;-&=fqRtw%Lv>!hEmb`&kISQ9%_V(3_O{)&_gpS14rW^H zxbdAS&|7;q<2(P^m1a?HRaXibMvMaGL2adKi)JgVcj4D@JWe#l$}H~Lm2PXpwY;<^ zBA4?v&NFwgZXXrCl7n|{gI#i>Bh$IinQ&NnGW&UbMqiiykn-bx8_%*>A;l%&Rz*rh z%z-oQHLbL|{{#sj%wHUYbxD9$Y219`t#x6p&975PxUWgvQs!`bu`2yXKF@Beo+e4_ zx&*XLH394Mp7TA+a$P&{uLz5?b$wWw310Y!ikY zaMU{{6l<%0o-;drS`jP(<7O>)heECP7SYoC?F^>4{kD=4pFW=YhqQm_=SI9+;ra(l zZB%SyuxuJ#tliOq)KiLPFRu-SLPafcIhR1ywHlT1l^IP(Z@s+5?ma^3726b}nB)k( z*P5I-*3sZ8aoj_%$;2GT+)|ouN89e{BwIXc-)V(-d)F>u{|_I)Pm)i(bM35MrbyEI zPJIX7HiQRT?h_BOC23`+eyGquyL7O zgZ5v6`N5>IkQW^A(M9K&ls1k3uEE`rHvzTQcJbTOvVXBM=sx1>Wq--wUB;J>Y-SIq zX*b_hTrx!%s>ss8dy8n%Y=&>b%Hqj&c)b-n@oll&;8xn_&)?+Y&+g6#;P~}*d=7kN z9>(czjPu<=>9t_&j<_1Ups_@GO(=gpwkGz``uf(J5@XM+tL^phxa)A+Rp*Y{s~Ut1 zF#~>yGW@j}^#@zyV`v;#8EUae!)1of$Se9sc&UnfLBTT=Y0C zxb-`BY`xZE%&?fK#yRjt-OYQ?v1~_L4YdevgJAzm60QUpiFVD9Zn2i&1_`tu(|Gs@ z?3JTbPnSl2e#&FmiT5F2skU!`&#c`-L7-Nd((0_soQv!#6f{%b+9Qq;nhAELl zmx4P?dJdfnZZ#!ws5uCKXRjB@)_p>51mabCYKdyPbx_>y4G^rQ>sxi_TO|< zl;HR-XY{VKBx!In{f%h2fN*LxiWBUVeRmMt(Meu5Uozfr6-3z8 z{Vhh^w2ST3YdgI8LdNv?nmD0CvB~K8wB0sMxfLf_UDPXNcR@QBSw?sqYyJhCsYg8r zVoxhUi+zdd8_8eRJck&HX(iuD@Jt9lvSTsQsOLz!&d0Zq7F)($9Ixxa>Eur+m!vl- z?`Z4JK+r&5OS1kzOR}Wu%t11=FynlAy)D zzTUZf-RoU^@cMeU)1n_LuPX_yixik^+Z06OT?=o-)uYn8C=1Y6{y@Mj{gMZ*(X zAMJ_#WaLEPQR9igBi89fO1z%fr!EUay->gFv<0!x)t!c$@QZ3MgEek|5dk-#y1=2u4A7{akRR6t3Bd>;GI4-lY_B= z+2bw2*!KQ-g(~&-zK0>VVWt`mr5}cqQt2c3KUx6)M^2R8Y)GjlFYzg^h@=hDY$skA z;IbV3K8rq+y%5qkk))5qvNtW4U7j(=!7H;ctM`KAt~JF~OVV&~FQ+LUP$r-lQvx6h zAcd(Hpn-t)nGyk|1A4=x2Sm3mcbJj@k>BI3rer{|fMTnu)g@^NU>#tRWd;Re&?Ce* zqf^}5S?|%JcRNcRjoTZh9g|v!Ft)n(!<}FQV%~J-X0TBT<#cs#J*`}i^V;uZb z#RxIA35T#EmD9@db@&7;z*xz%_P^zH-}eHB-YGa)?Db8rgBpu6q)jfqvQ`qP!TJL*-{uxF`wf&2Rf++=4vK;g> z{d*0cw+gYatmrIhc_EgxqD#!1CulE;I9)w-ZRa9m&Y@OCY`Z6~R)9A=`1`A!Rr`eS zSV#ZWy+Vpd=?&-Uc189hm-t@zuEgLgzFelMz$>Fqy?NF9)b|r+do=KmrI;sV*5XC0 zTD)jAt5$bG$QCa>IBqkKX-6ZIJ7YLB;xTbCkM6rd9-{Os4dTd74~Jc9rLZJ<>7Zof4m*6i3pCq8=;p zsYTIqi$mmZ?gXSmSRVvP#2-a^(QJcHvT|73rQD=d>0i>{PTv}MG*$LxEBgK;pFF}E9iD?7eyO!< z3!5^kpW6lmk^KJ09^n$Qkfr~nIJ1+Z`vh25Tvqk#(@2bAD)>6pD2hGbfQ3b z1w3QpJi$O~dOL6VAkHaB125NEl70c#6meqv7yOPxzf5N8jB!J*ugJt%FG7z%(yt_? z;Re>%?Poe@&c7I;(6v|zBq@f6f5yYtM80NoMy(xR(y}n-MyB=if4{8GfK)%@EQ~3~Bk-vH;$dp_$hu#WHbhqvvZ@I*PRZNF5W9W`U+S2wPLg z8Db3XRN;ifA5mXj2)*$A=*y)+IXC%>FcQGep9vt}GFhKbudb%y^eYiwHL0!Wr8Kl6 zUJT20Nz$L-TY$?sph)mKfG?M&3%>*SgD4yNb@3Lo zoBt-!FO_wU_nRIfox<1cU$%FL&g!(f#oIePN*?}kyXd7@-PGbv9jL9?k;r)z;pUI} zY!$1|FT(6vk6(FA?n^?uOqZlTV~^D(dC)S%Y30`lBxx(FXOr$J@w=A(B2rEnqtE_f%pI3mKnb?u_4hWI`&ur`mMT%;<9JX*7sv zsl{xkw@XrDeuShj{>Qsn5u>HJOy#!@=E-vXvT1(l*9cZnzQR)dREKO9s+kVFgi_F`UkOQoa79;}4*L>np~}FX#afgVn@iYBz|^1>aoPr8q_OJ7X{!StrjJ$)H!Mrj!HeQmNf4Wsv z;C{CiH$%{Gq8Tv-&~9<*M8|Br*Sc@-zdFRWhLE<@iZGYdj9*HS@yk~8CF$GN>F_* zC8+Ay0h{tG*0*YpvYn}WYoD);_aqeUVLR_etc*x@N)y5dZ>}}Bs8n%YQ;S-Cou-b` zQYrp;5ihwCcd2Aq7#*b3JK2C6FYtH!qcz?WyL?)0QtOJu*o&H5rq}Lair#yeDuYS? zJaIIj7#&wyHj!S>*4Cv!`x@U+5h%#72#m@XD`WGO7x3Z_-a@$$>2*TFmr$S6*eC7( zm$jDqCRSB|w8p+=G`i?*0(#M4AjbUfUTen5p*$z{U~G}({}f{03_dXqqc9gdgyu8- z8aox>Spp<9lK7!{3}2r;uneiE@g#Wl_`W_E&z;cI42X{B72LX@i=Pm6No}-ZE+vja zyD2|jtB9VS`qiRe`VhACGOcilU-~O->0@a{YD>%YOGof(OoXSjwG9P+0PE}STc~Gg z7A=mxv)+Z)mcN{4MBlP7-q)cP_=MN$EYiqta0H~e;M`0q!1slvPw@5h$})NHr`$4N zg+_U+kheTbZpAEdIj^*jb<_WI-GVdCH?>A^rutsrMgKp};i4Ua^Ec^(_XOv!Qqu{+ znc~~{I{iOjm(p4D*!CB7u9~M)@anMORG89y$9KxV2k@Kb8(w2`ek-Nd+nhsv_rFFV zr+99keMnxaUv%EFP?@t9{(ny6>|*Qle{@c3vN(ktgCp*O&Z~4LIc!eBjQ5x`Z)sA& zce~Fp>deXXqxQUWw()rBxK*b(pMKb>%YDNz*Ff*p_wvMe^-S4#X3m#$;xUT%+Xr~W ze6nAC-`;jH*(>IxdFDI)eUFS!{I7VL8{&yZNb^?P1nInB%vqJ(6 zY$dPNyPZPjJ09Opv_sz08n0F34UBllCivMtEA0)@3EP~enAUhmOdjbN+v9wAt|DiI zM>+Do^W_^~w@>pNXw~cT2W-V@1~eJo*EcQ~bXM1dNzJ;OzDpPIGNX5_JeJ_uu_`7;l@;T;_%v?FdFC$?^XJdI>=g4amzJHFzp$u&&&&Ds z3ZG7B>b^U7f@Wr(ubf-&K5Ttxp=eC;9(ID$=48Q^LE*{s{p$jqqkq?BMUSjUkK`;A z^K<4Zyu+OkdpwpEN_@w5d!lF0%SEt6e%N|mt2!g+8vl*49$yQ;(R)z-WhY+3<~6}x zJ)GgvS+Z)H#;I~#S#0)wdEqPeNZwAn=&`IUa{s*O%3|e|=N0m6vu59tYP^3s?pdUv z_>|7-h_q+;&M;N(#TS+JhWB%p;|vOE+ue(oU#?&5Y_5mD{sIgBcjhj3*Q}WBCa)3j zsp*^jZK)ffqF@^1`|eu}&R9j07yguByWt!6&Eb`CNc|#KK+3tuy%=pFpr@7al%6v$ z&-XvyP@k09@_fU0Sys?GOc-9BYAEA8R5eZI$XTv&Dsp~XG|H3j?6+FT$!*G6te{ud zZ~uxlsm;EpF8t+cg;AX;o`27-K7V+T(Q$QN1n0B^yjSKC=U5t{S|3HN_w>|S__mD0 zdf)vQtnP!0=nEzbV|=T>rB~S#e6M}ibwW=qn%jS6|9ZR{1s;T(jCeCaPw)6l+8+r@fim8s6*2hJSIi|HNrU`HO zjHyq?E0pV%F|DzRA~t@QSU~3>f_Jy$Yj!4g`-C5wbDYiW1C7#ob>^+^ek*d^gWXw< z=?<|*>-!JOS$Wz0V|}Jm>8xaJRv~9pQxj_%eQ~3ZV{J-4jJw=-PRA~6xNrN#q?%d% zGn#tij9%n<-L|3fLz9sLOW zVXLr5k4U~qY0;PyG4(1dxGQ3aS;{6=GrjpCdMT`LG+dpPbgsm=vFJrx+?f)e0l#Ye z3N!F~wmY6R8aF1Z7r&3HjfvB0W7PP$F@_@=D={mD$BOTzkB{$_O#gJTK)T~nygB&m z&b6#=xm)cNEZQmG2-8`9>DzXtCpmqFbNfWhlYDhfn+NrW-Ntr&qnKroZ^>qh9?DPt zvN-4pW6p`UY9=eLu2W27X6vl}%BDtxOs6=FNUOM^y_$fhLbE0cWfRGV0a?dKuq#$> z++)`^;U#IT+rI(ZX{YkYZnjr6&W{K^YS$nR$u5`B+B$avxSI(7RuR1JO;k0{L7q!r zG#DLaCzK9-oz5BW=xt7SG-1DLarQR$&bO4(c$SKwLENNr#FgC*&$9`R;<7%-DIV|8 zM{q0Eh5t1X4gOcc>wV0^$u0VYx{fuICb#IaG#zU+lUsUcJX$&i^lQ-1&~Gd54dB(; zj7MEU#)zelE){EHF#?^-Bk+kGJH+MC5|=o53t}FN^ez}~5Jx*ET*IpnC$4m@BN+j; zh$A1gkNMV!3dkk2-k)xdckAjRxXr7w>TsU`UyZqkGJ9g3ZV&l}l#)jXnQ|p^R=SO; z9D2+jl#CfX26LL)fMhf|*R#?H+(8hA#5)pPlbsqz5-gp5i9A&LXQv7LAtL=05iG=Q z1!vhr1$uD|bW!A+;@@3U-6s69F42+chNmygnSq@u^bGoqjx!+Vf)1bGA zz=On0)Fcnk_dFHZ^EOG!PAI>yZcr*6Qtd#hGW51On#$c(%2TOo=)FTK4e}n+{S=Pv zNf(QBPybiCEjOfl=Z18D|F3j&dAc!pVLKHyTiK;_OyXbmA|NA5rZ01cRTcwUuRGQs zL8I@dH+NU@c&Z)rExW?H-^H5&+Dx~qMvnOikEz~4wci+y{awtlzl(X_4Kd53G3hm| zM2BX8FhuPwzwdqc!noB@evdfH=#1brZ-c#~In%*T&`iS(k_Lu%hO{dj1H{2JTts!}CABOJ< znY#Z5>JK3$pZPmGl~L-p8>r181*g7@-GZEU;|soD{i3H!M~jvwR)^m z9eq)4QRgUkCPqbX{-#rtwDS&zlTQgf2Ya+KhhldT^d2qWs^pPUa#s6ZFJxBvCgDo z53GTbkK>*fY#0%muI&qZ*{cdGm3Dof#ct@?~`b-iG7>M^F}KRK2Lv3?30-8WLHX4o0gn?tV; zIHz+Yq0FhNy@LoYkFLEBW_iB>IiXk^AR83C^5s^QXM(d(x!wQEsg@y??f*>WM5^)sAE{=A zb#7R?5cWRv$pH5j`N^5htJ@XpQx(CNXS_rgH zZL{Dv3!ch^DzQpYrL0m_wYBf@-|8$VeY~`i-DX|vKD=Uf{aJk3c9nScyi$EO)4^X^ zwWawwUnA|2R9A!&zL=SScgl2*_IBv44lU-n7WfLzSx~k@X(^rWEJ7XTmx_>$p?#_r z^At@#I4kX{^H!7}!K*$o-qU@_2T5(Hz3n}xX`x{Gsl8Wg*9rQLFJ@|-^PSHfvG`QT zLyMKsif>8uP5lP46*OO#(wn_zXO@F*b(%|s3Rr4YC@WMI35eI$eycwpGW%`T%lMY& z8@?qK-;(C@eS6hub)1K`0XnmK3+hSr?d7F*k-roc*bUZ&qAArk^PF{|62Et!qwm44 zx0G6-$VqbC7c*6sCTOQMj`_T$FG>we@C9%Ju<}V5sY*lLM$1wBiZ?-| zT}8fc_jh9T3~HAeX!M#cJFD&LbJP~fP@iqb?W$(EjaEi<-s63#ea)l5y+g(lzmZ;kFFPO^YLC#BV|a&E`DfqV;;VXyZ_!~MU*CpYx{ z9exS+>k8*AH#9t!j|`gvD!q`UyC~*Y+9i_9`Dmpb3H=E^Tlvve*BYfq@U0OFe4lTR z+z_hsG}aEvRGc?vs+;Z^)2I_6zyEj2IM2yiV~(zAP|n7Ndv3j`6Z1b-D9_I9FUK@s zMiB2H$xzi{D;KV&U>+JX%j&eA!nU%dh5nUBAxGDMnR6m0Q+a-O>wPM5SpK>D@KW*2 zOkG2aQSj=FiVpAKW7k~c;+u|L6UN0g)n2oWi^c!0k$9J{qh+aJR(T7|3hyJ(xwe?& z?-Z`ugkgq*vna-*vL3-(ZZhYE&+jkc69_Fq zuPv%PpTLeFSmrDm;H8!sgf_tUcL*w_M>Ik6mly9HlqsJ3ADzOxyY(K8Unh<(@QpZ^ zi#JofW=ntYPFSzK5)n{)+W(gEU2xe6e3??ri9bI-Gq!0#rmpFsOik0nnX0BinW}Sw zPm5ck^sUfQ6vIMMD4XcRey6*4;Gqn!%6<#2D|z+OU>2#oOVdvq1kHi=zqgYZ9C`A?}ZA{yf` zhkSLrpm8U!^-gfzKYFH@tqb4?dZJs{I zkJ^xrvX{H$m1+QLA~bl}bAo-ja(S|%+R(ThBW6ZTEVO|!N!m#bvvoF~OR%*l_1&Yf zC1P1VZ@FnjQH#QSc{z>!q88C&^9f57KI~bog)M@OQrbFP`V0J55N69bRuFyNx{dL; z9j8<(a*~>qIm4SEO*HA2t1UFD)Ly^zN~dMH(x+86&Or{)fy6GqygX)w0_7xYW;UQU zWmMiBfYz2#jC2i^B?zDa-s`a|%{1#A>5hL&Yd#c&q$woH zfPXdiL96$6q=CkqI6=0tT<_? zWJ=dAR`9;fw2(8V>6-9MtuXZA;rZuO7?D{Rk+Xbb-XAnv zJa<*6^%{q3o9ZxTCpGMAy-Rr!Z_0tkT4qe>{f$@y{b9odpR2s6!<9e5x3>I!Sfhwd zMID0D;1KW$r{6AguiHu#ULIjHvtIQnX%0x+BZ$#2iR=>wT_7bCWnS#`7Jk+Kq7$-!~B7 z_yJ1SU+C>sj7%Ut8UF#SwG*2@XjLV~dsy%o^6n#O`|?bS@KzNq`qk%^b*uI>ee(-Z~muL)wx6)cZNdHGZXWD z;a!xbIs#6Te|bH^o}+O-rcTfO=%-m#lm7`TcCsWO$p{*d6DAm#WM&D-0jIODLpj}k zy4KTv*I#L*ymX{*@h*0^EB!95=~H0`xPza2sT%4OS-ycd@Ck75<`2ai9?8 zUW_OX(60SdXG)D=Caa`fY?4)Rpr$Wzxtl?`HzJtFU^Z^Cr#4t{_C))$cz!w>k9z$0 z+jGKWzTV(wf}k!IjPRv6@&*2eLSt=Cro0-xi7{2dKDMS{W$xQxGgPn~fmRJ)ozhXk znrs#9ucZmz0qI*<70!XS+11S>SE}z!V?(FD46Th=@MG;U`)|#}X?-V-ATL%o5a~X$ zra4X;2AA|*DQ3|-w^fbzF|(lcRIThd=_iXUOZdCD19W}5A+Sp+E%UNas~YVP|Yj7Ki4Y^ z{{v!bJXOq=yUwm?mMK+%W&)X_JMV}b2CofZ!=*O z=ADAyz*Bf%qKY*d71`SxX7pdr8m(dmwcH2B*{iDUgPN&rF4tGFYt{=|!x_90kb6;^ ziu3J{tX1r^@iO>om34Yh*?wLdgERNkToLtb7SKB4Db!K$K8*8$Q`Ta)VD4L5b^^1d zX9o%C45x=*SgmzpPG3(2yJl4Ql0<#ht)3?KfgUHewgs4Be*Ljf>oqZyR)`BgQxDpQ zc}NC#A-2I`J)y`M>^XuuVMeM30g5%Xxsh@z<*?A;#=E_kd+<8W1^BXA zBCZ2rcnMab`m3GbPc<%ty zl%m?JMT5-eHQoxuaCam@k9t;X`*z>lz5JZ#cq6gFx8 zZs0i8d#LCk=-bg&6Q&|BTddfNj!cv2^!St+_LzEqJNP zYBT9F!+`S!6u!^bd%&#i^ZETA-@m@%d)}9G-sk-~=e*82ulsq~mhNU#b#5*-+|8s; z@Fbg1its*umkJs$z93|+;c#9m@M~&q39S@iglGpgg>!Q$F&-t-9z>p6+wfNGF1+Tj z^ec>Ywv{y^PDv_8GNM_~8#OKFcg&cBt&VCbSzuFh+nc1}m}6=%%J$oWxyd?|MkVW0a}|c2l91~}9(GCvuA2PO;Itnct%%(zrDD!^g32K} ziD(JI%H9cX&brl5BMF#;Qq03rb?qpH-HuhV8eW7>)ISgWKDF-*^E6l18rH~WWUUNA z?2sYOA3HbeNME4)zAV1(+s1`i`FANh&Td?z&xhp^o_GDu=9CuC|FyiQE(`p-Z@yDn zWHG<9!!{W<8?dFrv-^!s=>bd8OjAtM2qqe{Fb$9daqfHC5mT7q}cY3sGQPvvm842ch%_pQ8^G`@QmgU~a z)HBkI$cVPwF>D{R=!}#T`8viXt}~kYIy(pR8Sn9~aJWk?y^K#Ahi8%Q(!W^?40MGz zSWl_Bm-SCaN>1eI(pKvdq~t_qpnZM9pW`{7TFnYats8CG9V+FBUUg8>ahlyBePch? zsJ4!~!Z4Xxqf*PHZy46SFyVY7dY8*-SvtBx@|ju8JZgTARnc*YtC7CZ@07l`GgnxS z=Cwb?e%sg)S0R0GMxD${5(sBb;EJq;AZd{AzQ9}pRsY4x>UPQ^WuDId=XYoW}8U;^e^YkE6mKDk|uH#*7cZ{fyROHmgeU{ zhIj2^tYVPc<+z;d+v??o{Rp@y{W%*Z}fL=n=P9eEnN$-?#%7K#n<^XQNBaw(&c#sfF{ghpE&@@QJg;%IRKE(?kQM0_P#AnGsd_C9a3`gS-+yYOBc$tB*+RK10r7~5dY-2MN-G6zEXf%aa z(OvZzG|JsCJVxu>M1EIaZ+DhUrcd-sH}8OV;w_s$EoHpicwjmHYNapDSuVV_{zYgF zh}TGm#Qu@%8IJ4L49p4N8am=L>?lu8&vOuU2xm$CK-69%5KsoRMwKJ$sH)}#H^Hy`73vD{+y4m!@kpNE_yu@8iRY1Cq{iKnh<+^R=RT=O!9Sm5(dBf3s21T~{*4Z3f1EhTSQ^ zp|Sn&SHwE7z7Epf>b^jr&Nl7h8AMWIGlsiqe2tA<>R47#Q&<%TS@CI-B!`<$!QxeJ zd5nupOStKF@E)gv)z>Ni1mtHe#9NFtM!3&N=E!9Q^e%Bn$re~GcrxL^Ol6c%88Y98 zc+Zd(%tBm5@C_N$WcYU6fbZ8ofiLYGeK7}Ld_ex9aN~<+`HN$3`eMT17ei40;-)Vq z!#13tn1cO*2IP8#{RkSW8F(Tb6D$u!zA!_$`rtol4p4~GUDe>1xHJ}X z7DfPi>X?~HIw2j!hlK9dL@IQ0mN1bay z+qas%)jhlgbAoU>t{PZUXB&@ML1U?g(e(c2YU!Guy#rp{=jMPSs+RinPU)I?FJ@(U zb)O5>iJoXdV_i41cijB+x_Kbz!YI~&hx3{v({7Q=jixfqO62bc1q_-3?>VJDoO=b7 zKUl`n1hke3B@0fZ%kgJW4wXf6uVB^y{I1pJEC;waA-+HXPp@OX<4zV)Ce++2;BX!! z){O5h@Z|5BKb1;$$W%+w4|Gk|74^(aX% zXUh@Qz}5-CzXXzj10yD2HJD&onlQ}0+%elRtKhVhd<^((e6J&%tD<=xlsCbjoxR!p zYBQu6k%Yf{Z4vG7cc{YozVN``aAx}wGT!e{YMT0_KvTE#p-SlNkk7b2t1zq9wxFHX z{8tRorL^Yfg4Wt6sRdf~NuGllR~X|y-x!|8x<{nNdUp173b~MK)Y+oJ2c87R=`f#Z zU}qgB%jrHwEH%Ob$Uq0}bN_vfWI)BPostLqP)y56QjLgaGQAol1gMaITY(ZWJNgu?dzUY4bD;f`M3UMB4 zSXzt}XE-Lcf4ODlTWsRzk1PBFq^KIxKLcZe$$&1|Ss|rh{?E$&FKPJv1K=j#Pdotr zQHS3L%`wO^Bez1zMh?+_0DNABWY1ms$jXO*_sH)a{_>G8A3h;DbCVvCDQc39g1$m; zS%&!|IPQ=FeZ2&94deS##);y4hv-td$c7+Q6g_f_|G2RY!xgLDN=Y=7`L zVk22CF0tHpFJ`L*BUfJsJFU=cID{1fu!68>IwBMGK33g#)%PsqK(9Jqvkh;@y4gy2 zusMDX$$*xp#;N+ashM%uBjqaQ^DgK8RMwINt$T%IzGFc_C1S>ojhr6015stih;0%B ziX+At?@;!sdWnL;YSNeCn&=|iaQIHbZ~JTMT=sgha~(%GFW0UizBELm>t^qhBG6v% zq7=f7QJy&B9o!G~Rs}R^dKp9h221Q-0d(SzMqmX-U&T+uqvytS$Vs z4qV}*Xqy=pzT-IGWUFYQw+LpU{Mc#d8+B>Qwh-2_ptT@fzlq)=x!=3yarYcI#Fr|> zMN*>uYs_*4g95syXRz1$BC$i(mc}LDErf=w{#Dk_3 zc1ydMy<)SAIC=U?6u#2Y;}r8`%Jb%)@%C6je~*Cov+p$RJ6fE}-o{R)FTG?tbDlUE z8rM`G-3ygs*glmw3U+#E0gUC$ZYD9U=%`;Gk&M|=ubJTW8)iMZlz|*hiq;ElrX0N# zeT?bIVpJU$U@1PLI^3rYpVb?FEy2e|B(zNLa;|%M!SoVUhljB~N%E3h@bvFPhW7H( z>0J!cURla!aIUnX^Nm^A?(=J#A)|)RO4E~x*yAeCNw&*;djNO0@cVJcrm5Q#E8(xP z1@@;o&@cpsb%(gI7eQ0b#i2hF(gUesJuuJLuVIpEz1+l;Em@%PnA-Hx*+h|B_lhxS zvnSn~iHGPp0iB-O^StCfeBRH7$<$&P(Pc~+_5EAY1JE%q1{bvzC2Dn)qR~-Gv$Px1 zP;h$_7rWVH?gH^g3*B$})e&)`4reZcy9h62M(L%LSU2IhLLgphgqxiZ4StG?&|lzz z)pQl+Ss=pyJ57x{HbQ~B`+ytl*jzwv6r&XV*c%v{N=~@;q>2AL0=_ z@|vup8kAx9=8Y6zo?VZb77D(ENs6+D|xZ74!8tbepN`v@S`7}F?kSO=$^xam32J{SoN*q^XNr+gZG2t4g; z`w^L4hgdqv#eld$SyUkoXYeKyQtQ5ufXO(7Y zP%Dq1-p!^?zzP5>ot_gWHhr8Y?X5AeFi$pTO#f7!0B=i-b<^ht(dT@;T>kRRE~iCZ zr-60o-zB@e8X%9eKloa&0#;u1bpt`%snWqbOZ^Rdffqb1#H==1BpGhA&1lzM#qF+@eW!cGr;d7D&;HhrUk z`UGtfwjCHwI_-W$W}`OQ4oeYg6O#7%*_ATy z;4^Sd9j7Byke9#vgRhBfc}}{AI_L<PWLiQ0xgoB!U=EuSjX6Q(I~(-wWynSt-)n>NrB`M7(rj@d$)%j+vHWYS ztRV^0%ig`&R$rZyAk=t%(M(hpZ0s_KqZ$bQcHs4noCv-($@Q0xnGx)1XcD~RfNNIJ z;*=xLasH|3W@h3hH{(rm9n9viTK8jz21u98d9n3*XDZIK?3ah4>n$xanf@IDN@9WH?eck?gd~rzjG_1{tSZAcoV>7lHOugF9DoC4G z8%Y)w9{=T(}-#dNu9_SwIBPH?solx2Q6rMqwng~alP8B$lG(( z@Ii-)C(iN*iPO_Ak~u9Nlpu#>PD>KhgEA*b(ghCE08o68EnXYsJwtRaUrYNhS3{DR zNs`1O&{#bbw=mj;83F6mU!=Ihe~}Uz5Gkq;G+-~SH3|={GK|mXWA1L^Aq`&Q7QuVReUj(Sg+BLn)0__#2;;LXZ@ zzr`X(z-w%LFLUiA_SlTD)7rK$+kf#n*D-%M&yIh|8s?z&d)kaJyV~Qz+?*ko@M-L{ zxC~e=4&e{^N8u}x{Xso;82_n!aMn zym}zGtDj3|MZNoFKTEsT!E1hcM>v}*%F@<(13~splENM}^PtC%V&(~YLULFd3)}H6 zhZR!vW7?f$D+0?9jED#E)Q+#`=YkSTPAAD{5p(M#_dJ?$?P{Mv{g;k^MVLI=7Xiz$ zP}E0FHK1uw0IrzBs@?G1z4r4^h0z)SsQ%LYQ>f&W-x5^M9@f8fQJMj0asbU-K$4pa z=nfM!W`ahx(MfZwJ2+V9U}nTR0?3ZBK7;D*j*lbaJkMQrszb0KI_UMEheWm<1tjbK z0}?sqx5P8eAX+qSo_k~%X?3BS6;wW6RSR43-L@I9u6ofn9lwl!t`a<#KS!y7C$R_f ztDPv9^&}Onaw$5V;TEhlOvPEHYhG{Hc-J{DK}W~=GJ3gAZCsV1*lt>*YfiK4y(tc_ zti993CEG8RQhJo3%9d*9NuJcsrl;By*DQq`gUv`pg$EEC)`L>a;pXv`T#)^Cp95eB<8O8LwzBsiKa*HApFfmFI6;7*LsuMO1 zdfNLIR*-6D{09tLm(^u0P%H?iv^RuW8{fKc%=t#*K`)W!g_$)gs&t!37A)YQZ0UBI z$=K9k9>{xz(`wUMd<8PxwO4GmwO1C{Qk~3r17@p{9?0R0ZgmvsH;pk4Yuq&6_4b)dU;QQe%nlVYb@KYE_XOikVDlr1tH=u@i+l`!IZI=wNw9u2pem=D*QZ+53 zXk{2L%K?P=Qbbw-mq}JQ(_p`YFX*oa4_!~h>JCY|eu-Qo)>dr)tqbj>4^N>wx%Fi> zZ5x%0Jm&eb1;>n*QCW}McV7-?u&R2}OV^jy*}`Exg{V}BL)BC~#2aF-v?8KG$PN!$ zY3%N}2*>?69>`GAqBLS^MMK>! zqM|0Y&ME5aY3A71lY^17*pBg>tE_>!C7OWNGe3%*7WB&RHmhmGuSm7a`d88f#z=DL@r4Q*@LsEuuY(39-lMv&(`U;{2S$)= zL*=2h;t)mj#2O0xNy-!z-LI|-H&seZF6OoA9|d1+rf>XUY2sfK$ma))<;(S*NU%Jj4zkoS^v7i!6%Ui#yrF+rRXv)>Lodxd4`Y7@r8()_p*7CxKHwq(E~gE3wRZbX#J zYr(u8#Z+O^7aq(tn750py@59mQ>^qoixlFY3j**lH@jIJA&<!CzhxcJ$ zz~Q4BKQ@plO3(&MkZnuvAkHXo0N$dT*kmQF#}#}?V;{0UzYSxFtyR}!CyTTZh-}Rs zRP9xmJ_>$@s3)9TJ2A|o@E(zLCQW^uo%g?4NS4+dwpTRog zmd0*f=&J7V&PSw*boQ>X@Dx@~sqXn~9q+}H1#U@S%#4flhRs2|07L?#*m9sMYttOl z#njOk;qAB+CGpK;AqV)Yt>e6kRz29>e)HtB4EjlQI(h?Zx*Hr_ffw-0BpsH-n4ZAY z&i(LicBC&}lIbenl-A6b#=H0@!kW7SVFASyVInN45obJ1Y;cV6?fHa9d?_Ze0oJ+b zZS?gn-%u*`^~q26BfdhpG|bfC=nkw4(zmX3?T3DMg9*EAosCCtbYefK20+pn3_T}I zC`USMdSy8FEnz0!?tXO>lRDKyxUyum(Z{k&@@u8X^ep1_mP?NbX{A|BlorCDrCW4O z@uhvP2H6MuPFU@nm69_OU2)q`!^w5FC{GIf;=_Ia{Dg%kbdouZlWxp|Onl5%3=eB1>!S>ul< z$djiqY12H+t+#ucDzkh7-{h3*V>-KJMANIAxVP|4n}KUtN@!;^)rTq-A}pQrfN?9HJ$%U7 zF6o&uzJFe9!wB7vb_AwHe;?S4$YTm)hOh4&qCnIFV-hW5oGBE4O;P)OpdLND$8iS! zzFR-r+2gfv8N7!yrd~_wXZwjlMq~iSx3TOHBz+ZYHSWZ&io8QkM059beZnMLeGa6= zsb{p17t$f;PP|7Pq}Q^)K+%!KzqozB!y@jN%z4z_alX0da}aC6B8Kk%bwLjf;8Gd! zGpvTbKCid3v(~oqBAX5x!E*@hqDQG`qzjSz3)tJY+um-WQa{~(sPbUTz({Fv7Sw(V8tD{@~{JE-K(1FoxwKviUAt-Z1^>)+miTZg&# z7u*frdjInM4%Br$tx8_Yp~_{7W#MQO)T^)gP^Cc?duG1_I5!p;qNoN&|1)s8>#&Wq z^%=ff5V2tZv9GC3|0=id47q)eI$60iDuqcKcM&ZlWo4T#tSW3*>&}?Pe+GV!9#o4c zSMkq4L)Wvm2se$)Wr#k8K04pvI2Rn>-+(sn2_*VxEGv*=LE7qb+q{P=1;U|)hn$Gl zb)6Z1s4_=P^f}Syw9@WhZiGxd!xy~x=XLuX>0*2#hv-tB*i($kZo5eM`cKS4!N3MT z{rrbCEGG1@aYii zLOuh><#oS2(xt&V``<@t1!fY27>Ts%e*d?4Y^&Wlxy z+N)?YU<5ii=VGCmwJ6fnDcu)o1)^9?2aJ4y3DNXo9mjCJLo(W8TrX^5CS^*<9rGb|lYmMTFW+2`wK`bJpEZl&B6?-=eiIPR-_w`xS?Tx(fX zfi*m9S0%f>z-r9e))?zrhSmK$cww7ii4*Q1-$6aRQ5fT?z{kD`cIy33$EkqZr|6DZ ze*!vdMR&sbBs5aml#~+{ooFITQc9_3zxw< z>6w;+U>y(9vU#X@TL_j_OrC=UW6YVT@!t9ix^#^6wj-N!*bm^$ku%VWD#SX*g0S~pr6?v zoJkSqo^?9{9cqYQSzNA*$VDy2ELYK zWorh469z6yien4J<>E3(Va)i-WasebBX;X|MedYiG|uY}z63lB&U*p%F`Efqk|aNO zS)+$s=ci>hK(=uh@)@~Q25}%({G`;6q#2O$H+%`fE{ui z$F9Th3x#(z`h3S>DW`(*|J6CqaW}6$tLd^YKH7ckA$U*vI7EhIHKCRIth8ZlO;5Bw zCqeBQ)#bcx7&N?2wE-)#1{ShP`5Es%9ym6NIOSbELKJHWgKrZT!6VwC)wj*L7xFF9 z$EmK8{oS~;QUhxgt-jXwJV&{B4t~h^!sJ?MGqe-;c-p0K^L-NEKr+B0cd|)$P~o4; zo(x9yrO~=#u2&20!~*zTo7)ue@QxU6sc+^XQ+-al+Z={HXg7?lg|70do2WE4wbRXE z9;DP?z{YW>6oFOsvb*Ce-66C!`&c8BxTR51tE^Sks%tg1+FEWm|9m_2Eb}owmtlOa z#QvRMsEpziA9Fs%YXX0SFU0JSHtYA=IQa5!l~(AMDta~9sWRhAz8XOk|8H*rtH=T+g=&iL#JO8wg+ENBIJlv=QpL%>?SpTH-FPearngd1hok3| zhsl1Q-qR5V%n!Xi*|!E3X=7RT4+Fue*9BLH+f9FSP?r4F=3RBcO<=al4G}Y)_#BU zuAWhgUiT0Dg2(!{hfj9F&SfG8yVMw_+BItx+wmT}oYEmLQnji*&dLVjpTWsP2Pgn< zU~66Ujz{w97qC@^$b#**_*Txdqv~Z_Y}*dp(L2@K8^~V&rg!Wvg>Q@EbB+5!g-@*z zrc+elP*er7vm_fR-@F8|R|dmQ>Ec~N#)GCqD$Sp2|AUWoGX0tv`zTc^ldsKIf`)Q7=?YvtiC^kGM|7I zg{@r*4HN00$(oX^c3yTK+Qgv5OIzo_cCU}$6o``RL z9TrLF)r;Zh^lmt^XNfpA50@KOnyQ2E^CPhU)#k4DtJ> zC@**0`xZU?6+a4$3o^;!=YE}YJ1Ce_f#-ZLud2$Sv{Qj+ea!ezJ|n%~dm=0k(rcU3 z*4(0wIMc9-FXdnfb_&)o*5`Yn_^MbnC%|aQ_fE>NBgEQVaya}HFNT&zdth?*j_F~q~NqC<{*wGdP=CyRm_U5=&escuk&fiD4(Fd#jPvIIS5@Ib2czC z0DB6@ih>-BkGbcV@%vY?)y(s;NKbTJa(oz==53bl&?;jRG+c_80L~=tR>OW9?0)xlDBjvy!Ohf)6fPY9szzc zd{1PJ_jH=rnvbPDEOxi@$8b!o)hB$C;C*cqbL*Ba#cMzPI*k+h=2_2(aL`5waaEnWZk z^RAv5LMUpyS+roi>C#W}-QM<7I9jD|S zOI5o0)F^n2ZRx80^Kfsgq>=M!Oreoo0ItI;Kk=Hj{u{KUe9fSgYw|a*QOjcnScH6S za#|bG&d671Oa=d5UQo5|5@ewhg}P>{y>d@Y%7W6rvjQzV1)R?8?X2>p!v;5OIJb$x1ymHdsI?=6a=R{TV0UvFCY>!aXc(m zdmZEf4s)AY1#X$vZSf-OB^f?DK2scq`JGl){KP-haTxSJ|es}Vq`N# zGuQeO@aqOevUoE^sr?(r_`(?{{9;2s%Y0#N&ppV&$gv_fOkP@|f;^Oy~OUR(V`!kcO^>+Z~9nnEcDNlcw8yQ?%b&I z{*t*rHtNZ54SzDM_+=xaIPex#+Q+bdn*rOZttD9{kax7PDM?sAp8$2EgEumVxTKi1 zS`-2&7;MmRf$QYt6vbc)D=6d?ioAxk3?8@P@GW8GXXNY4r3^WV12wm z;7g*d)zU(Ne(#fi7ssLXLDFxun}Rhy zUGh;NzUvJ2MhW-?TCe54sXKh35bc@2ucS&;g9c(ubvgP6`Shq%M6`^6<Z$r6h}XZ_j58(Gt+Lw&&}i8peHj%~p8 zpCo>w67p=?RU;PnzmsV8kMOc4i%5C*NtDwf=Y1Y|zeiq+c=@YQhYUTu;Dp!pzvP}T z5i}An7=HFCKT+q2{n-?Y6`e&a~ z-ADXvN~rD{x$cpu)qDM+x<}*s?f#qV&dYVz7)K!GHKhD}-T7MLWi*Fms~NO`s)4?B+OR_`p3;*!L@QPIA|5+GQR5ko-G6>a=?!)b5C+6~X)IchI|DJtui)8G z3G{5JgilbyS2s$qh!?-o{A^vre)cJ~&G4U1xw&mLsP*K*wh6=aq#w170&VkvTVouK z6yyKcHi}x_G#tE8I3tJ;12-^_VMnzs17U|aNR7!}1o)B|=Cz0%_Hw`;6E~$ms)#2A z1I*a4LznJ%rYmk>{H6Pb|Hl(VXq|AyV-yL}_UlI2?-FEZuCK8j^YhF>8+)ElRMsvM znX%lV&lY3sz=Q6Y>x#*S2}+3#>+-}ApY$xv%Wypr&(w!*lHGU~Mu~Hn7{+3R1P@-UX zFWqI~?f}mF3t6FDx+nMZLi)uFB!mwA>sT4m6=EWy7g5ZX2Hf$Go=3G@NzfVV*kLIte16E1iMoF zq%bCN4&=gNPQEZ)G!*y|aXif-l+}W#jmEya;^e%tn8Z9gah`33nTWWl@ax%24i>Z2 zOo`p|1T=o!pH&h&ky-_@;Ef*z*7-v%u?IG(#2u^6tkDb#c%}TjuB6(g1z)DtFDE-!}?RcPArT^Bx%mWPE3Kl1D7_=Gx04d zhrYIrT~a0#d>!O^@}6pimQR3w=8V)3!zA_u%DO8dCzb-iAlc?L#C#k0)z#3|5lGO# z4UEQJXW+#k(pZh_7rsO7Pf&z8tXK!e9vPdDc(y67cm4TX6kF5h?_|6>F$+?jn#P{M z3s)I|V!S0Vdc;Ja7y+SHt(9_w9f%-ME0tRFCnUGzBeHM)*wc_y)Jn6=w7MmTY3R{a zCiB?985GU_==5YK|;bMF<$AwspecKuM_fWrKgHQ2A03(c=&}|u zx*_TVYvw$xdy`S_SPs!E9?2JtaBL1fXUsae+22@v>vC|N1l1WXtFbsN5cCuo^RnLP{Njk|M{6}zc@9nrU zi~k5N>`f~y0Pb}L4ZTW{aE$$f3D0Ntl2$Z9nJo4L%c!;=G%iJ4@G2XyLSN`U5B%Yk zd7fC?azr|WR}u43Aj3!4KzOuw)2}uyU3aXJ?kjD3*3EFkmfH=lYYz`^!`12Kl67Gs zq&~L_Rr1I+6)q{!7cAY>8T=A)?Ncz0+5?pS3(z!E+2|J;JX0goU`!cG@=~i2aUtLiG@vw zIz!)zeIliq<|^L3TbiqqwWhWUm=N<)&eJI!+t-L4fLBYc-Liz0zr5%Zn# z;@3oTHgB|=x&klz3C_$xIG1f6CT_QlaPye={P0aIgT3or)T%LpINU;`3=xIkJGWu7 zApUZ_u~3dyhS^T@`ock4xfQf>RGTh67uF9X_ahvvk*xvLUQJs$AdbZtSwAp@y@bI< zHz>JW^U1(ejNc8DRgkyj3coB_T10nCN|=<}-G7R!h3yPkL2h+LT6fr@-R08L0;Q8~ znj+n7n7nLl7UqaOGnMG)r-dljFxOB@tz-m-EGZd!v*N~^#{YP;V(`sS3X@b0n=vX~ z5ML}xB-&n&$Trtr#_Ti@90m)6&(IRu0m@N_x~e@(O4tGG-u{ihUXSgVAVFnz8QoE%=nm7{W=CYWss*Ap;H|b}m{{F$U2*j~hP3 z>QE~!faS)LUdoSA#4Ih@YTM|JD=}Z;Sk|M5f9H#_&ma%sVxf0&0&6@O*mjjQIz<{^ zCj;eI+2qNPzp@dQ_Wgy6SNCBrE7(D_?JwMe>nvQyw%-No;ti8AQ<+0$iQZ7o$wsLt&Z{~70_?D8ZpZE{=o`e&e~09QRUCPR zlI7-x$$Ls-yphml4EG>1ogCv0dw4-gH_SaUEzBJ@`yY+1_cLkA^BPb^n+I4k_%bgm zw}>)1xkU;2C65S%&L{PQap}~MmHu;pJH$)uFauWQlL2rkjl;2`kW}*J!%X6>d(&Q0 z!2US(#R>Z^N=FWlslBE4>)_6Q{?;-vtX*LmbI>Aw7<_s_eXFAVmV=hj3e$(dr=TS$ zX^8VP97dC=wehHbW(3nYrTo*&244 z-{U%fqYoR`4d6Tp4Cq5RMspLn&8(Asn%&OYxS8AzJbR5j!oJJ?oz-!}IRnfH=!dD@f(S zd|p02qxdvo$v2tr|kKH^MdD#diuxu;6!}!Fl^j0}+ zZ0WpY)3OrKnvtX#!7Ay4S&Em&0M((W|5o{X@g=Er2Is8AeEU?_vBv7J=-p+T#>naC zOX2|Yd|>%Na6Dogll?)8{1s>o*HKPb)bo2cWt#hf*hv9vC9Rm5d7XhryECT_(4Lvq z7ElDVGg@D8g}h=So^iiQF1>CG;`QjG6xjQH#oniMS+QGiWlE@teX8zBx*A=x;;B0@ zhg&<(%@yQb*CvYzf6$mVenz#bg_dofd{r))8}`ywOtSc( zMPXVA%%ZrFMSV(f|7YtfqtmRNHD%GaT04JRmQl$YoMZxbhLM1#GSlO zy8}bd*Gu;BOcLS3(}UlcXD;}RdgxeZNf~`PuB0a0*;!mxF3oHBMMK>M-CY2Yb17utuj^6^lo4N#IR7{0<6yIe{GhovOx{trbQNL-kA*0D3QFTDGK!4|@DwYOkP^NxWZDq$T{}bmP+d*!0tlTq@Jq z4eu4&`+-K>ulnc8*jOvgH-Ak13EHDfnlJF6S`}8F3PjNEv-<{NV zTeCNw9#cmp31YdlS)eh*`rqcR2j3YW9bN(KfBJ*B_dGCI!e;Y)%rc=70UPzkV-atB zIdp%-ALkoDr2Ms4tgv<@XIRIu;?0?Li+_Jz`mVE16ER5uPIZ>z?d2-8Qz0x z^HyoRp4N4RxE20#w5rx3W@91gPdx=_mxz8QDZ#s@d6<7->bN=7u1kK|AKZGKpAt0@ z9Bf3F=ew_#l{^RA-RH3D%5xHjgU6x3p)`AC?E0>8X>1KBLS6G{NhuI_3f`1k@MJx$ z_cyrR5UupBpK4iO@&g}CvjI^v?396Eo}`lZjwcJ%$=8M`xi#mWkma#+5)^4V?2v+p zuL=dW_v8@^0`#g73!e|7&5B@A@Lw(c!ELawfc$b>(M+<4-7uL0$Ff|nz;O`8co(9_{Qnv#7EWjB5AN)vts+H#i&OBY?IrVf^b) zH?olFR@)wP8?hi@gzN7hs$QNOY_gqZj*uwZ^{tdS37RwTeKXk}iS8HGs zeV)W2+6!UlFRm-aM91{bRV?KD=D1Z=Hnr!)!rymWA7&@Pi)kD?4!p^@`a)~xqw}}h zt~L&HQ(nsDLHxe`{;!!VTUH0d!{b5rKm|OIfiIW&ZSuY$+fLXfNWWK2RJ*i1lh}%V0n1xmRqrm(C#g#}c&%UBc8Ub&4)h_jpDEC{~ zr!h`vyTT{dH$DhjAg+9|sPyry#{X;XqrmxYq966;H|P2la;eMfrM3EcsR$k|tm&cj zT4?*PZw>QDaoU<$h|Q4+s=?Kx@#iyi_hIl*&r#_Vb27LNTKQRSRsA`Icy?Zwv*=Xt z8Bk@0=3LQOz?%N+k|3N4K6y+mu z9Oi`OL+nbLSJ)(dp>KEQ71G{dj4x)Z#-E@L^WVY>rX=i(pz+_S`Vf08E|Lsk@VYZ~ z2Go9IL9+OsMTI{8y+pXuTSnjK{W%;{bH0*nGJr`uS9=uuiN0syYbjpbM}e0Ds(S0y zX)EHa1T~vD#dqpc4UHbTy@r{l__ls}<}=OS+nej8k)Q@C!acK*k$p=-m^8P4dguEY zOfvc$X~)ols^oUIeYc*T*FrJ}^)z9|VuNsFzi!UG%46UX*5T z!pu!&;cIL<#*9KTyMzLT-@rzie&L(jw%{|gQ)ied)J{Cw>5flH9;w=^N(67NB>Yf# zMh&)_`ZHjYfVZ_rB?IEbK6hEc84EQ2KXP~b{{CsG-40(Dnk{mEjp=(YVUk5WiAe23 zqfl%5!fPwh_*bh`chocb2p!V1kSeh@q{um>J&M=@HSyIcX-=W$%k ztD6J|=Tji2g0Uc7yxXTA{9eiRBFu#ZC$$oTy6^fVu|RN~cWg2;wX?-fyec{MqL+G0 ziMgfSnOL~A>P^hNO&E(G1#b6+T3Ba#9wQA>=Jie8_AOT5-<;~9@qw9T1~}ae_s|#_ z8X+fx#v3&YGd=$QS+fUj)QqV)Dn$u`gRL2=A4a!azjX0oioApQD7lwrD(cg4)GOta zDdJ`?&0q<=>gpU=Mx6@A^$w-ReWKpC8t>6O7T#MSI*|^a&|{~t>#};!si3l#+K0+f zesU4dSBi_gYRqS=5sl#mj@`jktM+R5Xlm&lX7@*d%zzSn>8aq?J@od!d*~fI?mz26 zpH)x10o5lLEoe3B8#5mt`P}77>Mx8(s*RP`)bX`*&|9~EqN>kDEdMazixOC-{>1#F zUgNw}4;q($x%flx0n<2D;>W@7udzwVV#rU`hrMSaMGiZjyt4S2DkgQKTaTSXH@Yh~ z?}~j|N@m{Q%qNfWjB;?lU~i3Ui>R7+Wz>YZSJdNM8t2}sZmV4qFI&GXeUwdK`tTC( zZ=UF%1S^M0O313>z=>2|V}*I%XxP!u@n9wKY{wp(Gd*x~x?SU+P;@(rHpS1g&Fo;+7L45wg4z9o!zexp{UGh5&OOiXQtbLB@NfVe ziB}IEo)Ktg7230_^6*EC!^QHd?55OB=}q4)hJK}qc%zT8Q{xn0_jx6>&uVC6>E0+R zUR52M>>Jyzg2gL#T&^ddEv`1zL8*%R$-YGF&Pn-L^g`w{>b$p&Q}rnyyK^elg5W)O-QZ%UytQhd&EHDD;hu7=ponTt7T|I;_N?lbnw6FH;>gu*c*aWD~qsd=B5Y zLep|ly7Tb22H0FdQt*IB0o(WxJc|48oN66}r-tB}d}!4RfQNno&x8;>iu>8gcTW8y z;F&JNQ+=J8beo%CBE6A-IW);nJlkwQwDr0ZBkd9F)R)tgi>nn9&0x^@2knyJRr}v# z7eG6WQG@R?yV;!|1yX#JI$t8n;$CU7Nbv@Sxh<&G2f=06(QCxpF$&`C5Sf!~ynpZq zfBG=hbCgJ4w0w0qVsyd|x`9b$eAUjQ*r}Eo7mG+Jr<}iW-s`re-s#a`mDBhYEVKJ= zU($ucwx`a&A=5v@`rIy(mW*=q^+Wr0ZpVI|n_WmZFH?n`RRTYryF7#Wyb`NKR}ge{ig`ylwqHTp8u%b-Gz>Pt@U41GZ@e_;t)`XiK1 zWe-98-QpKrQ#bvFAhshCmMR?ahnR?HH$l$SFyjdFr6P;iV&C+eMGeM;N^VnLZeIp# zPpDlvN73u$RnK9BsKjp#Q+(Un2@eN?EBZ0!idE@}rAEwfQ+#XA(GGN92j};s6>3az zb~9p^(w>6V@Sv!u`p4q+u7ub~w3V5mo_y>Y>;w@XP5`cET0aOr`gSIEXaOHOKr z9v&rfwXnGdH}SSvS;N;JL1ZJU59|scN46e@ExuDxgSu4{<(65t6ZMSpgcH~oCje~vI#e_)*TN1!^^RS-Z zFm}NvHZ`pMNYCjayr&+B<8DQcTag2_G(VoAsZoo=r>>o=i)!R*)Lu5@4CZzCZ=2af zzJ>!0niHn+k7E@bWjN+=*n_X3u}5``O+4A53x9aVy><~1RZvSg$H&gu4jz$M*!0=< zGm;^adY^po43QeYDCfA>!A`vwX$R~_dg}Cbws$*JY{ZNc(t)Cxy;{TvpTi!I>WYr^ z9JIT7RQhDZ(cI@j5vQT6o8%9QGym-C}`H^p-kp`VR_W8EJHlT?ws72)1KG$xP__^zc z(bjv7MjK;#1{n5?lmah>5QJf3ask2fm_+IKNr?iRJ_Em7VEsU2m@s}7=AU!n|kVm*~=mE5vuTeLHH2AUO~5_6|l_4?`5G1zuyQS;@2nW;Dy>H%*L-IRN?oU z@F9LD7(c|f%tn%P>K>l+aM4WJE@H+RX~O*Hz%UkYAEUlH_7CFQ5(7%?Iu4r9?@$(w9=nMS* zYGUHVIR36_MO@;Ri3eM@ByEP~dJ8}A%0UIig%~ZqU39&O;$4tUt#VF$CB>fHkM(9D zWLF%|Q~ZmTk!rHHWyY$+BoRB;#=Z>-Q^`J9pi=zqI-BNomFI)t6=`TE z`H&S2?f$sVRq4>UJ_?@e^UCLs`-p-%gEdia{V=fg2z0UxqcaQQ!Myq^ zk7t!fV6?+9EPhxfw-cw_PKdpBGfc!E8J(a|$oIIGpCKoMm*t|ElPrh3Gx9V1P%+G- z6=C@O@w4zK!&q~UeKo^!yh5o`sWlp{P8Sw7EIfReJ|qvzcrTyO>?X=CZlGTyHj^$jVIQe2k8L z_~A=9KF9F|jxTZi8^>2TF5~zb#}ynMIKIL0EspQlk52kn9Yo9;#;VfDXASc>?y7LG zxMvxie734qa+A3VW&?9SLsy(4Y^2;UxEN|9T+-v)CQY6)>GsS?Q_Mng@zl)B+bmOr ztR*Q-@yfi_%L~>B>sRJ&C|LWbkhJ~|VZq7`8;c)ZnJ*;e3oABlSh-%H!Dv^qZ-$DEW2!i?n`mjCF1Z9Pi8DZ|1I z%kx&@N&XzXKD~J5qs#Gy4a-;4qhvfq8DjCul{ekadKBNg`9aPD_uNQEA)$03O<4Qb z%3^?-e6&*9eZ~>xC67S3W9#;_>2w4I5TI`jb3&2&6qWvuT#mugf5=5`BNVM&yE@c5CF5Pq63ch!bj`NDlez4Akc;0i6ZQf^=!v*vMTO+K^e-dXqL&b>n@UVc{+ z5ahnB>2l}Lm*jlH%96a5xTHqai4V-0A($-_lS*_CuU`JhdI1-V?!E=nb8(fNR08OW z@^Fb}ES68}i{w*Y(fXl#`9jACLa|v+Dz=19>7i3b=rlQWni4uq#YukUw$OcM=yZGN zWEm=Gup|o=1+WA`SYMQeL~~}zPkyK{q|uu{lc-~mmK1tN$2cC%UtYZCAsofR^8EY| zMxcgy#giW@$S(<@+lr0rfe;(kGt(E(64tL?{@6-kWpVM^V)=eU!J3t8H*S!x^H=7r z%^ynCQl`~wAGt$Vy_V1quuKpf1vf4W@^4&*nmd$-nLv28VdMJ2R2@^aJSqP!Bqo(G zMfo>fI&QjNedGF(yy6?zN#^v$Hy;y+ZvK~xp)5mZX3?YhD<3YPSx2rkFd6NeWS)%1 z!Cc3|`yP7%hGuPsp3r|gtDxDC&&Qcz#xrAarmJN6o?$?X%Ws$m&y#W1DT)|6fB)Ar z@>$6+19Z<0aA4XMi~(b3+a5{Lks2etQo9= z?zdKK-%V#Mcq%&6iYmi3SguZy%+d1;Z#w02(adr?6a4fX?f0{AxnCQq?~QY)o&Rs) zLWN|w@Jaga|4VQ&)DFPpYDI`1X~5YZV3@-=e}A1}4&pp85IR%FS8$K&FpW6(;rXkB z>2#)l2XOvp9K-x^@c#d>_a@*`6vMRf3c5;*{#BAc1K$XQb5NAm zUxcfr@PV;XIEp2O!(R+vBZXsS+Cz)})slbWWZ56I=>LG^Z=7O=8I_3$$r(VI9)F9lG6 z6yGSqC!u%>e@YGyM+FnzAk#Dt5UmlU_-d${Xst}s#7K0AKL>eIKO;KyI@-{apO?gZ zGPc8)_=d>-zJY!|l&?Tpeqs;*IzK7D+r@G+cAtvk&6mSz-k@-rHwe*gluxtF zH%_k4*)l|Ri21h4;qNQn7u(GrK_*-f!@rdI{DgLq{$6q7Pvd#z{de*E3H`+Kd0})9 zJ?a{NZ@3qZ@8SEO#b<1g*d9Cz2~y7@JrX2+Z|SLzYx&SUMLvSWxBcJbtNS30ZEuNHezU8o3i0uO&W=hGO_hS?&l~?(02rM@w>pCAk7SF6&{0 zEVu3&J;XCUOp+_{)7}WtUb(OJ=t0UCk9nWM8)4xPw94s^=Oj9oAJItut-M4dSWMr{ zLPdVEM=6}=Bs!Fn_`j2BnkXqenk9?;eP#adWx9|_{G&K2oZ;s#h`$dkRDv{*5d2c6 zlVtwOGR z|I3VzB=|wlWznAjll-OpkUzE0+5ENh6vvi@5+6-z6h2Q5zuLd94WBQEd;972@$Zzw zX^V{HULS7mNnaYji)C65eo8;MXMFdU@~f2cOZFPc+cJL3c!EF5{erPJv3@a~i{Z!L ztjncv{j7nq9uy+<=4bX{DV;lHx#)jNNuK1NBm3)N2arFu^F-K&m*psbg+1{?u91)N zK%|euKA?E(LL@k%|My0USKJeCgxnvt2a*5M9)GFb(`t_5H!{5_rx61J(FJn(zEv6r zN%=B~{`^bxY(`1GuPFDt;=I^SQ!*vFn|tIGi1~U> zrg`=_Pja4@=^s#jqF<0{Z@ylZ>2F~dQ9AP@B)&Ige{cOAm*em0@%QRmO1GiM|9vr? z{<0l`Xd>^Ppi-zLeL6t7O_cFQ{djS`_hXyzyao6YV3@-t>I0qy4U< z{jZ|~uA>95ql2!awKDB3PoL|;gRi4QuA}>2NB8SR)0&5#wXm<7d@!N{PMU;u5J76F zFym zCiz5r^;5ab#@d(L*w%Y&>q!VBVmtH4Jf8$-g97h#{r!Loz65!V=b45Yf;DS-u$zFktb4Hulz(fK&{y6w3)8n+N zOgeVc_c|A0Q>>->q)DEuLOn}~PaKtyP~b%@dRAJZXZgALdX`&aEm$stobn1URw`m;1aD`z=|cv6KbWrG1e!u_DwVOB}MtAOT{CO6}jd4mV%`V^$Uth3k&q( zAz5xYHGo)D{L&=_Wy7f6y%Dnt3$6Mo#YM=l$Z8-?V#sGDMN3d*>(Uj4r7VAW84mQ& zN)j0kPLPNELS`+=$;&Uv&%x1VVFAuBb5`UQm9x^Nx#Yj3cxhQ#&QgpJ9lHof`0Baq7=}slX@{JCvP@OIf`tI5 zwyL~i9qS|e&%J3KtYT)Q+2uCibAV&!XHSe+$1uE!`8+gZ9UCa(FNkuzAH;`QE};OQ zGwxa^QY7CD9O6YMddeRO2^MfKXJ`A-O90@Q-RkN6iAu>SSYBey$z8Z`LD7Px6fJ!( z<;*6^x(J-)l0DcCoYJRI)m!-9nCP!z{ecTI9t&J4#~lxx^h0r`0jGXSva*5q2NcT> zoTfX%i-3p8cq#C3$f3A4;LwX0_i^9@fYY-JICLaF2Z58VNY6*W^?)Sv6!5{wokko< z;2}R^Cqz?Zbkd$*yjYLsSGC@3uM@hHh%vOKpK zy{Vv3W}&f1MloP8ya13>nu}Ksu3|{UT5geeN^6D69v`=bZ-um)F zDONrrm5S|_&F#@5dwlUau^m#ITL+x#pZe{Ci`HSkUTV)?IRtacr1^#BnEQ}kEFiVd z8sJ0Gf=Ev92c@g1#OX0QO99GWUW9y?<>%#;$E(;>WQNqJ%E0t|^c`K5)q<%PXGO7RlKJ%uc?PU!+hC$iflGyphf9D!l=Y?qeviIhcv6vR?><~ zGD@sVOYvS$!lpM*#QyQ1*hazuv1P*= z;U5V2DIoer4_ptL%5gnxfIsQG8j$+t`!ZcrSVAw_2^M-)Z#F*0%*V&rr}1(7ahjsH z<3o61_R?DI`}pu_#7FQEyrU<)f)C9ed??<)2lqMxLXH-}jw)WpmMq0slv50|8}wTO!` zrH`o@bEl=v8_CiVr7`zNIY`RY%(Ze_&uBr zIx(_B;BCOkzZ5v*C443DIh;oHe;D{&8Gj1+O)~x>@Y`jXyMfagtrBuR0R9eVgnWU0 z4%`S_jlb`Jf5{mIvQ0XGeUG;4}^v z0N*a-4X{P00Vn=t@OMBCm1`aF78!pIcr0>8{=0!6kjwH{;KSfY{zrhnD9daD?oI1k z;0HNciv_cP)U0Fgi{-+(H2fQ6{5Rl@NQ?5>1^ic8j$eaXjfIlYVi-5Pw@*%e8v05sz@+!`;7M2z*Es#4)3Cs={S0(5` z2+t{5US5c`X|A+r&9&yj&dFPWS)P@ZE-fi7yhr3(SX_ja5Z23O7Lk_v-EwO$qF}`m zkwRifvlj}xsyMe&^jNU8RGiq$upAOSN-K(%6=DrTIT8Er!dxtr5CJQoF$*Or|LR}z zhXKp~K$4hiDbrLewq$t;tN|DpB`hx&#w6B(3t`hN&m(HgLMndllJcAaGH}W8#4XqAXSFcuQs!yp*sxG02U1+u-M#@GiTmt9sT@>GQ**}FW)`;?icPFoAc1!XYaD+^t=1u#=~Xm z{OX+4+kP>{Ji7AHibqy#Xnyq5M?TpQ`&jfN>90pV@#reey_ZUFx})D;171sc`@i10 z=e3vLzH{GquYI&{UE}z=4>vBmKYKBS#x}%eGuAs{(~0;4A#&*^lxht z^r(v$1X|d_2Y)XL9>oamMStWFvm0rjjLeEC`rOg zqRf{d&BJQN&u>(e$`@BZQTtTyrv(A&p2qmC5phAp$%o#W`5HUS96pWUIYqn8_@oi~ zYw+XAgfSxeW)@6knNw}>@rXVgyQDmgx9JzFICZn;sG^azvINe?o#S%(ZoWa-sx@j4 zYQO5UJmfFBO5c9`^L(}DE^uw5mN$i%AyeF4=*37ES-e5|T*}C~nFxxl2Xq`p{Qc_{pBLFeOSQr<^hbh8@FlCr3Ol?pn zs;8?9)HoN%**FJ>a}2m{xE|Y^8Vwa+0VlvI;b;rK-)HqV+U>y0}0iWIvb;Lm$ zdw^5T@>E(x$lK&S!yaKep8Ysq5#hvS@b7JixWY1YIp;HYi1jHhthxi2{l zKMNrjSPF0}|32@puz-)kth`ZCr_c&IF{Z!~&swet5(Ip^rx<_R0oUU1OD>v^=B>Qs zPhliklCI$=@)8GeQ3_Hj{)*cbV{v224t9!7<#uy_=OX!H8DGbn6`v?lgdGU^JGYMi zM4?sgQO;AHV!J_^K{cwjsI3~E7&DS5p5cn!kPykQ67D8?FigaW6B zhQgQ7k81(NwL2j3xj(`_4WRcSKN><2`~Uo7i)ZY2oQ?dd;+YMOtphGvE`*0a4f73v%#_3 z0pZvk$TJ+f6A+Hwg*?Hry8+=a4@y%Oeqx7dIW4cnFrigyRa&)H-CwO&k5n7~v{L`4 z@&8o#zXbkyUV5{;(Hh+-^Ldo{G+;B}A;5P4_xiD_Qn*fh&(P_MUq=I+0JzDAaqE3p z)ddaXE^0snZU$TgxLCv1mJjAUkv^>IXXN8&EpWg` z2AH}VU%X1bKVdo4hT`SHmidJGDt*8WtjzrP|7)|q}boQ)< z&9n$Oy*@(t^-q02>8$KsKpMlo03>tG1BlvWgZnGQ{cEy|yidOosrdFR0!49393zzH z;8dId?YfHmbUqdXM_NmVGsDri*4uF$-ss_Z{GcPp3kpHSD^&PYsx%5gqeLbsKlD&C zG+t7E&4M-SON#7lm}N9oc#E|fO$Q~JbXh6{tEJkTCuO*0k3)-z6n5Fe67 zX;ONW2F0cQ`9CU?UK;8-^mx3DBwC&v;&T|cITV9~>5CmI#=-REkS`8$ImqQ;mvPui z#E%d&4*BFTqHsuyL(AqcPjJ}V<&Z9i`GLC?Zay5cam_<@Lit5pvEHcse?}t@VmOtF z>iK$_^hWWK2Qi#6K`bPfG&ms7D^r!)H=;(LplHy8z*>Wo#OXw3uN}FN&goGtIiDSmj znKDz4?H~P;rAtO8B;ef*+8?5C-RcVp?4~1+ zb=O;e-unDKKWanXxZZmHJwIw&UcTP#%j?&>jr}`*lvnECz4J`%jq*x<-n>wo^ZNB} zcN9*1l&-h!Q8@YaZhsU`ez9=gHtF?C?Bz#iF~m2qm!G$PkzB9tdiOD}pSPcpE$H?0 z_BBe^>xc0|OoP((`q9|#P1oz^)gR^QkNgnyf8?R}H@t07n#XcV^2_K92zvvo=xj!7 zq;aA5gSkTbr%6Js7J`CGic0X3Q5jy(0mM5tW#tR-))1z{vYg!I(02}Rc+N8+xJa8bjrArE>;uI_|ugtH+8wWZ0`HOM7=%tn}C@ASgLQ*dZKhscJ zg6;qEikv0bOGZqnM|^>zYz21H#T=C}2^Wv-uJJ*v6@^6$E#)#teqnJ>w&gf@<3K8g zL?ebwqoQy5QnWve)PL^=j>kxCdJ%A%^a#HPI6_38zW_(S7J1eJr+!I%j{>K*LlU+D zr#Xw<7U0wm$bTnr>X(GS4xIWP;k$uT-z0oLaO!`w7uNus_D~4_3^?^SO6v#UH2%;T zSsQQ~PbiHp;MCtqj{jE*aeN_s0C4J$l%HY1$)+HD0&wcr8gOO;r?HCU-vwM658_!7 zaI!y052e7#jv<*g;AG1X{uppN_a*!p;MhVI@i&3f_7(ZR4SXQ>{wUoKfJZ@x8tinO z1Rf1P^8X&VLB{_HJO;R^-@i%kD-qrYxL)=L=y{3?Ffp-mYrgbaUk=`@Sy)(3ubVKI z^pkY%O8MycTC5vsU%4kX&iX6z*@|3iQ7x{ipDK z8~evcHg*N>p~=uE=mUU*-?NDkF2UdXRCyHaF1YD%PVmr^@v)6v1YQXE0G#(}_QkvL zel)A#J#pYa1PZL)AKxE^`@N@1_8%}X(ho0jUh|}!{^R^VvOr+J)mE|kC#%@VXQXHk zY^@TJlko5TP`e96D-9I?c(iYSv}Fx^xPJ@x1*ac4={pX+aUYy&_Y-9*5qcHB%7gF4 z|3TbP*1#Ik;`^XS{_oGtNi7SH|NGWxT((a-wePjgM# zeXjBE&C?sds;g`Hf8U=&@03O>f>+x_tid>Fd(eJA-Q{?9&H1{Yde^y#V<4!&fahqr zHYC=-*mew5I&9L{oTo4=hLZCTY<6Hn<69a)ddC}=G%_|uKVZW0<@k?_TR!0qeCAHL zBNs6jFq2;~d(pRy`TMS9_xV(@HqAqw>#-HHU z@;`HVSQ8p~J^qZq^5C-;A+LesD}D>OanUGZ-VF&GA?ZU!BBVw^x)!N$+y{aass4=A zPazkdAU7W%S8pSCuOXK^klU@u^+x3WA(WyDrCEtmm7#RSDCGjy;+M-_^1p*E2)KnM z1kPbTLAZamM{~wOr@p0cd&RrwN7Vh)gn=-kYdmhbla+4~}W9_jxV(m#_vq!AO3{T#k~!fwQO zushjUd}DkBzG#quh(@NzIf)Tt`wuvD8qupPVk;0cO5g8lQd|3{x1Cos+NJi1k!h zx?7op-`{2c9J8Es5ECc&_x~!EX%Uo$ja9L-B*-^V$9UC}^sY)!?S5bhQnd(nC%J zc-q-h>IAl#!E^=B4)!y*m@5R&B=!zlkNiY}2m1NlvX?SglHeH#9@6uTY$aOG@9P=A zX}~6PVd@L0+zZ^h{G+O=z@~Ck7p16Wk`pVZg}P9Qbpbt(k@e%@N;wbmjNbrYr#XL* zUTl#&6jQpj(36%uub3}m8nn%)|K4kaf^@v&CbmuEp!Bx=evS5cH@A4=m-Xj8DfRozqkKDO#8;mR)Q*v{A8a6-i;qY z68j3-%nw6{1K4=joO;DQ-Ei+uS~+b%J|O=9$R~yA8|)`_xCY!`}gqlxIKwfXwp-%jw}E`&@jk%QN{&x%Uz6 z?LXrAm3HEg7TNaV^E+~4xESQohv{K(|Ngjb?Qi++yu#ks?3mA=`u6&9`)WMnpmjfB z1__IIS19X#qB-629maOpzVmsE(btXl_;DST#@9bk8ywnC7aloKA00Eqo6Y~g|7hSp z8u*U}{-c5aXyE_L8lYcIR+`qCnw(=DEGiaoQj36FmzEU0S#;dl(ds*@%GB?4(5QY* zv8KMzPbp(-Jx=4fo{iG>5`3P4o-0^P_@J6ZhtJ{Kk4bZfA3N z6lo4#fnQjU=M4%wXW;DGnem1lme1AdFVzkmufg5u`?{R%*=;}crC+ONL;UPQyRnRZ zsa)9<&+Bv<_!VkqXq?WCeLuD34E+K#Hb;(4Qd0i=nYNhdw)oGSo7!2F8utw}InOv) zbQSLA3dvZfGg@{Z@Q=PJ?IYc%vu`#Za%*gQ@V<{blValiXAVpoWhVMhrMO1_x#g ziWXY@*-_`Cj%s(@>=VwP+Hm`kVP`%*73cERS^9iKfjX-&|4dO~!A^4u?$y^NkZszGqb#T(knWEL7vJXD*6<4_fW` zuLE>P@5va(4ukJDwP5o9N}a``!z`aU-{??g=y6Ae0lC-WCOS(4@lJ*O1C=%wk`=Nq z#2jMc?0sfLnuVm-TkaEfrn!L`=@KhDa?N9)#rVg!t9&Q zlWS*ld9zPui21OqyKAaB@?h4Kc{h!KZf3w$z`ccX>5x_X;cVE$8u0cZ!_5iPXGRV)t;RiO?VTYr^k%j<`@#db&51=FcKz5D zlx;Jmn1g0n>NDYU#M#xMx3H+A&TXv|EDZNcj4|U^?jOW$JQk&6Sl2P!oN)w>{8&Rg zDD8(`;g<)S;~^3EfZ`Si(sMb|s&BV1EyK;s zfw(nW)vPFD8(9>$aiGQ5QMmCFjxO9owF6JmN~;&+n#odMDDF0UcTZUqpK? z+n1b`JcHYu3`u%OA7B|$bi~=&&KV5mq^u#i5tehgxZ`yO?xVf@dVBYriQ{}tqtZRD z_1(vv6WUKW^IMps%k;B9kEwpXAYYYYgRiJUecRAuE#wd*BiJUh@su+Eh@*v zE74hcOSpw^wx>*pp8Oyz^@%qc%jk z_x3C5Q-krHnwD7XmA$24Ki_L({hm~?f81|lr=g=T;Pl({)_whFj|}tY4m7x zKOLWD<_tEB|BH(QCvb5J%ntz>;JfUfRci^ZkG32F5AN$S5bp`+-&@q_nv7`638w;@ zv!X3fT9jsjL&4?&zINb2mivH>Y4{}j_}52m%*%0qKQaWksmScR8h3vkrL z*_lCSTA%7@)*gI13g<``qeZ7PIMfPF(w0=*QL5)~3kBYp$x>$OEH$a&4Xj1Ohoiq+ zr%$Ex86Ay_&M7tL(-~q3n$aN+HP1Ic6ZTqaX44px4I`hz{@|SfZr;iz?n%AW{H*S! zRN*umc4O1nh$kW#?)*eN^@q5BlSK>mV7J=F+`NrT%$w$JUaiA6gMEM-+eh=b_&UVC zBW!NiFX2ot*ztpIjXWF|zdzO8%tqlX5M51>75?5XUN{jd6r-XK+l9%o>0Vj3XBnn#e5NsGw1FY24FI!|Vp!Qli<8 z9Qv@q;clhAuiFQ=gYZop=86Q|o1hu#Y^Ixx^F8Yh1ZKhhxcH$jm#n<#qaf~xm0sQm zk+-#(8|y#XH0=vm362N9)iY6luhNg$U^62$i*gcS37NUg5|XWO1o^Cr;0(c;xH0C^ zyIQ_W;budo;?AR3q!;JGSK~%Q+8EQcjx*7wceUA$n@0;>3WGX512d{)`Vr?3ds)L4 z)G5^wrA6t)p$|@JV+kqyQu759mtQ!TxBKdkV+=Gb#s=mY?nYO0%E2{@(i|*pO`di7 znneZ~bMISgQJT1zAd|`wr1H30J)xbdj@R<=@_vlc{`{U;6T@w@%^q&_TdA%y?t|id zImP4pu{&&5c-HrBt1T?MBRnkY_(lA}5pMfd;;t*fbXSDOwZ=0Y^O?~!9{oDkX@pgC z+_}POf}ekSBK&T3`lctquf%yX{PeK4(Epuu<1NZL<+w9vvWhT9ZZujV}?E7!c9=eai?}#LJm+%7;%N#KyG&m#+OCiu<}IT zs4Hk;L&-|>xJtUUm_-h|`d|6pec$%yEzy?KZWjO1MUIO`e>tHIjC-WSI|^?7J0jpocXxW|M!)?Hehe#mtWCHl}gzMZvKShL$!mZ{?x zX7BEDI#OVde&`(4UXWFod03ZQw709(nV%UwEX15YD}SaS&avEANfu_0vnbjRC3~$Jr5@CnN@2o}AXwbWK>k7$(KE9diBUN`j@zWG)(R z(GHG|RU(BuAcKQ!&d!S|L|C?v3^DBP>%zDjk-qK6=0mRAuZ*{xxX4s{I#)YujbVfK zbak|*WO0~3seC)obH=29WaP{rwCK5zPR?P|9di|TkFyAdAp5?~2U_3mTd-Knia9>)+QD=ffH#62;fi`p88P}#ajkJ8| zENk1>9mc8!HVb+Zk&nTN&nzq!6<@OC2381xPH6SG@IJMuGU4(`(X)ESPuO%J zedZj2mino4uSNTCJ_BBOG7nDlA*=RcCnt7QU%jtI;54px) zKH=8Q4zyb%!PB9^9C^q!=`!(*ynGtBn+{AvI9mBQziR+ zW*l**x=tNXI~?lCK0$VFvU=1Fxti1dqf||C#fmm#{@!-uQr4ucpO(ex7w57Yerx{9 zeLlh9&?=4s9(H}zbycS?x7;{WWr{T)c74>9VB$^V(~mfRruzt;c^xUR8scCjraEk> zQGz^b7&D^V9+g)#bhz>?ZheYMbr^Z_F}9w)MVbo&+Tw6mrafVs0$*X7)ZWaZ{GfGM z#d#iAqDP{P9l^Lk5VMdNX6zUSDn?xSd0btvVZ%|%&pOy%%1Pf2s;8B`ay_F3H%Zs1 zO-=4CHsTOE$nMAO$clS&)3Ij%(7h#Ik2{?{b53hP2^OW|zNqj#vi1Loc8l*;MHR#T zx$!BiVE{Yf=L_p>OM)Js+Y=hy@4+>~eVL$u-JK^@iT{x%^J)C+wYQ8r_gzk!Qx zbk~9UDFIehu7I$o!L=Lic%S3ZI>28Ou&#H%1?-bP+Gq`68>C)N;Ng1&R1;#K2Xw%( zMC)|iZJxFTxA;zNZHxB{pPy>HC|bO*m73gu(OeJa20q|hHAZH^D)<84?_6;nDeTm4?DkfvB8ms?XX88gB7pPYEN*C?NXVz zcn$8@B3WAEpDV7z#>Sfj`5sTQBWV}H*!quTseT7I^NYeu*l^(+ZgNL+3eBQbs#??3 zvHYGE+bWZTnH0^#E2!1Hts7W~cw?n_9O6ZkusFq;I4cLs$x+2kYHf}e8>?&Jh6pXO8Y6D7pMv$l0v9vTeO>(K6wLmarjTtaM|Y>) zOcFcM<4(2d&34PD*wxa*JO@p+t6)X)k;0Dgp1)@byq8Z6gqtR}$` zbJ?6n>Az#cjefxe*$3+VDqgMs8n?!6nVy#sje6GcN1Q7<2V%J+k?q=g>|L~IaGPBqsP8{iN%g-!U|w8cE^zB@VR5b z^HZC?zS^yvJ39Tab9V>RC&BNVw#Ge=xQ8%HJ#z%HY|I4?bW4oBE!v! z#BWer4*hLrq5XknTg`{vTHEcpG;_c}5^oA#vmbLB?QQgN3CsZ3wDv(( zKMud?kpNp~Jod-nmj`z{+>1wSY$RY9+!Qz^+)Vi8VQiWCfsIvQd`a2I1`8&eyK)XI zVvg_JdebLPwbO1HhLLNl^Gno6Z2ckJH&57y&UL8i8qw!|_|(8>Rfiq>E*9J*7@26O zkEjR{Yrg{)7TqLz%rzQ!5LOp$$NKvt4{;`6q1770`mwr*MUBRuT_i*QZ&ze(x8&!= zzpH!Q4^_07N zJ;CO}ySF~Dy29R84RlEF*{z3e z7sFu`cn{;nl!)vtrU?~Ff}BgJyWIp4{}u5604eD99jsMt(aJ8s$A z{JmRSWq_addG%(xhx~iDre3r88(=A!KAX<~evOgIck`I6U`v?Af0N(F(HZdrd@PFE zfQ`Ah$6M3LZ9e2mxfEp@Zb`8mb~d+-%;dIxLoTO#xFvo-lqpDDTO4*i^j7yT-M@&`W27%5 z?9hpD-=Lmpz4164tufBN^ZL8hfV6*9189TW07rWZD`?%D9bwtHTcG`yQ{`DY)J&_V z+cmG7cJn@UmbTNl_^ESJyV5itz2{Ts$hJ6G*vfARAKHd>Sz27)5tpZv=*2C8yEJGA zpLLMk`K8;q+iw%%wyXyAsdIcwl?cbS*hKhf3)z&PIv;LPiEu3}JB%vM_c~~I(0}7G z=U+Rjft_@ZZan6!@9?Yj-+C4}ze&@cnx2`dY)_rW+Eb0b?WvhQ?Wq}>_PPpnd+Kym zd#XvwYv9pwYK}W*WI_ftJUG#UboVxy{=N-UbjNkUUv`I zUbn2itF`5Ox7+?sS8FHVrQ7<~u2vV{)pr5kr9E`gE!e+z+wG&W_H=c(9_Z@6^mbQw zhi0SCrr{ZJnQ`e1x48T7KIztO$8GL4s;AUX9(I1`9FlJA2;g9oBzC*hS5oSuK@XE@ z&t?6AL7Doj0W)D4+UZOId)rs0w(4+;ucx#o6}PbBesoxSoG!iFb^da{3>K?vU{N#c zr_={$#bW>I4$GG5aYeBvf}}^YbC{{y^<1~!)Q8&0W2}MdpV|VgO};|Acna=sa8JX{ zKzpcwdk^EaKi-$6bB66}Ii@jLr&FtFc3+O)xZ7{DqTP)B3ZKo(eh9=m2_yZkMrVFo zP%PCQ-`wczau)xQk8wrL%KK}JVz)%scE111@btrOD5`m#261#Y(7lzl;` z6Pk@3p0a0CnIjV~JXYM4ec`4!y4^SplzTXQ6leUiFVv0?x#-KQHxF($wk}M1HZ`=_ zA9tz;yvlD5d{wbI=v4u87p2HHH98MEX|6U@`ENVoo}V=E2V?8EH$9uGX)?C@0SZl6 z^C_N9H9CT;zH~RuPB1B3-d5oLS*x<;7(qt%zyluP;sc7q?l19^$$oYYJA+br{^?{6 zyt@lq!ENJ`r%!9?l@B)bYEH(RCYab$jo3TU*B>wq#U2;FmS(Rq8DTT^&N+*|n)gQ3 z7mNKz^MMvFD6lDD8;dhKj@p7m_<=33b`M55qvJi?#D3-%|5_=3p;3Xg+)(5*s<+gj zSFwL5Y6Q7}Mn*f$_1q1<&4Jr!q*OKgZ$)hWko)mIhuoowTr!LOzB$=M>$Op){%Cn* z*Hi>!B{8UKdyrj?PDA7-GIcdS)Y zORcIlH2`g6OvtmTKCr>9NmRx)_#Nm&?(&c$pxyOB+b$lEG!Q1D&o7#qJBh9^9$==K4U( zvHHCaeSDzoVcgBDz$o18DALp)bN$_2_OO0{!67KhRwtMaIisA0hhPy-FjU2wtp}Gn zI7XjA_@sR{|L3@k{Yp13m!L2r>95CYc_CwB}TF0P8;}tWz4W)`f?>Owt zY~i+PqIa6}AJ*d}SE0zbpulOapvYf+8$u&mnStb;Tjt*kyJtIAN4A%8g%&*VAy0sus`3*zl1}EH(}$8Fp3+tK(+3 zU^2p5(L%$@mS4;))f-{`5xM_icqCq2uWL?i*d@%C9Ny+$z-woH=A+xpt5hq z2!EIKdz^U)g za}L2bGEy7apXm*0tBr;=t8E6Y-3WZmYMh>x`P$90e|B4AnZmA>DaC3!&*8@T4hs{d zh_4>%v^t$Ggc%L~h~;ay88r6o7<(EG0-eN_VV?mq(pKw{%9@8$AHFFqqK_npZoRfn zr`?2Pv-2LUn)A8R&{fy$wT;rQJb~tEfTMZd)+M-H+M!SP!~I&VJC`N#_r3EJ`V+ zGu$!WMAjR%)?uc28>Owsn#p~T8;Aa!Etocg{s(>73et#Y6kZuny8h9UMfMcEEs z8PaB38q$(d|VWvj0lM6BTP`)BjQx2vfDQ0)f)M) z{0(dJ0_`zzT+`4vq1o{8syO8-f7E_|_~`HkNT^|F-o+wCo85pJesW+_wnIpJHCO5% zuN1N2qcWxbaVz@A%}sGdI~MKCRU}efdR&2?*sL8z_@yReNE&?GjAbku`<|<+p+dS#qV4c(4yjnq@8OF7~jvWIakf?!uuuN2i+?DL6qZf;cxHhSAT9ze)W#(okeGq zzF(2-9g94!@4K0gZ4axruQ|7#*>|otRKJ0-*yGyQy|aj2Y_b})=ISjrD-gD6HMe=iS_gVnZUDp(^1#9%Qlm>ew-=V^nvU3OHvyjVHU@7z0MpfV$yu;s0w_` zxvvWCoEtXnwB}W#MO}-vv~z7oTBORPXxeGvCu~XO&ocdX^H{sta%0pX=k|8v-i4OI zmJcJMaLPI!X;?1pK5+4_8{aBg-PsM9hu&N7&~&^82YR-*P4*AMcxe zANI0YV~;b1xVg9iCN{jYIoI+?>Nj8Pv{)k}!eOOYB6Rt*%F<(B#HiR!YhPO9yt_NR zCTwHGCf#Nh$2$f-h|zWSQP+^m!8Mp+9Q__lt_$7@zquY)DfZh53*K_b`AM6uwvXjB zb{jvgpIRGY;jwZKwR7Wnq%d_0Z&|NHK4wH72yychSzK#V@Rko;p_is^O{w*>e4$I( z%nXmEmLX zl&AW}`87qvr8-L27TC30qlb-YivPkkEY-1S?LxaV?Dh)hUBUbpIyK(Xc`tHwShVR( zMsl6UH4rwzA*Ww^XJoMM6nysRJg!g=@5p|?Ei6xr^SLg$?sL3f;o~`1v7;h_Pp)gq zs0A19ZFWq2zxA%rO}r!J{m^ax(CiIspFxQka&g02=UoC|+*)-DuTfpp2(;fh`3j3o zbwsW0=hnoZQS&X4YlrTl^cAi?Te*Z(N9bB-SZ(E*O3G;;=*s_nXV^ED+bWam-pWY3 zz~l7$SU2zB-gn;B7WP;i-+K80ZpU1=!SO_2f&C13wx7VBh!EJa0Rp=j@QZMPwZJL* z3v4U=0tO0f3|t0W|H-&BI#OU0z_$WCKfo_)kicGsoLs=Aa2w&CgIfr>uLDw?2O#Sr z@U4JEdmX12*fhA?;O>vYUZ>$|*v~PD2f54P3gL2w2&@e5LAY&jB%=uFujnOnInrD> zOki&!d>CXV!z~AWcI;KT-n3stJoQk4CBT)z)x-T0Ze%R>1L1bT9fTwPnYwG^--@yy z=#{QlW-klIyhCN$-ah!2MTv$Nu-uRYX@t2xz1Ec?b(h+fm^ox7ZSd z*S*IY#wwNUu18`aBU4+~R`0;C5|HoXqVJR|8u;E@ZCLqZCH2b3#9le}iZ6Vv)#?^sjk?80Ku^;r zq32UCUWZ;h=TOA&Kb4ZntWxiQS}+n)Xy zr4ESU$#vs1QZFblMwKJ{&37MnE4CXdvoH8&W?oP%%CFehqVxmio8ItZ3-7nHBKyLt zL=VsDT;D}nhK{FdqoPH7Bm;yQn85*GXgd z`L1)7(JSR%f-xOoJ+0%LF3Pt?ZXHc%9f5zML8Yw0i`Qsyf~dg_Vm{{eXz*b%k28Ac z2Q!nD6{smv4(k)V5~y_wG+NO4>fy zqwP1|S(4>{O)r`x_M!qYeL>V&zL>Xe2k9?Y%(vUoTYqA1di0lmO-^sPCa2^7B&Q=p z-TKSAeGj@dztcMvX}n64$E&_wykqt|)Z&xtCd)0_4}PY1vK>mFeO;F>c}K>6_WTNM zRI-@wryYjMJh|snjfbTDSmEvYzjjjHDn}om_IIQm{Z4XSoY=SQojiJE`0C`k*o++* z0Zw)Dj*xd4Mv}o9`JkJ`@R_SQ_(WywgwKbaijlly>S`KoA~Vjx=lxCrJ{?tI7&#Tu zhDxkJI=QHjjXd6rrxFCCN59sYT-OKh&Xa_fkj4)OlIsG+96Sf=n**%D+tyuZ?}{x7 zvHd@T{!oR!5Cr-V+WkYk5?j~kFKGX-4h)3#aj;6VJ`g|R>YU@9dv1#q*ibk%+&_DT zU+w@b{+ZOF^x$k|I7c`H4xxt;zaH#B5Bd^F-5B<{;O!;t z9*u_VeB5o=qW0O6(a-Ipr;#F|lQj7R(eWPF@M~hI< z;|l5IM;~a32y!(0qlPl7yeX+PYi8`9x_he7663SQ&FiY`dxp0UNPr~^_wSPP)z{5U_QVNIG-J>%*z!x% z+V{5zK`q#I_79qAN^PyP2^TerJ1Qi;2_j#v%;%4sX`$sOui;4)d9r05EqHjx1N*5( z`_}KQh&T|3d>AkB_ThjNMUBN~e1rBq7I|B?U+TSs<=#62ehc^iYmXl&_xMPJ-?~4! zE<$XFeJ@e3%(f-h>BL?cfY9{)tl?3N`EjsaoR|-Gz>bN#g1gnwKl;Ld68gqu^o@b= zn*#d3sNaC@hILHOgCa}1ZTABcI!2*3Lx6Yol{Tbsc6^OA{g4)-h zM$JoWokOk@-7I#BdeBh$6Vi$ddtuLyzR7jNGrC>B zdIU*c-B3_JdjwG)jq=^D??92f~`HFhDesW6v7#96D1T$aWFzrjq}m?CQIGij1W_|>rT%=Xzt0id9X0Dp@n l&M+ z%l7;TYzDAQPxQUXb(z4XNh#c$e=o`5HY=kkWg|lV7kO_U7R8nQ4_EaLqPE}y;!@o$ z+KNj98c8$>f|dd%s4=@q8Zf5CB}7dIx7Y|qW0DyJH7YSdF*C#@6IDyB9Ih{&&`7uIYS7gP1tP3}G?Y^>$m=*0NX)a$Ian!_MZ!vT;b!lTs8=ioI(y z*D~4zDKuzbYSFe1q`-bS@_4njTZ)NgLlOHE#k$%1uV%j5`MwL^4@d0ZDVF7KU02%` zJF(1VGb8q|T{)Mo%UBnwDGt}5)`FAuR+p_qsp`P^ub{aoAN`_3L0h5?2V#EOf%ZO+ z_InjDk2ZXVwLn=1N@dy=Xu~~>uI_Ef*|xHDTUku^HvDye_foz3<51r$Zq*1D_q+DJRDXy&A8uWPbp}1^`f3Yi z#SUdBD7g@jHP4507}Heqk;$~0cPN|NHQ--=zRF9VcT3|Rd!d0eIbCTEK;EZ*8H;&@ z`eh3G;Ry80QuN8|fqwaS;3UK?#oGBj;+{g>N*Jyua5K7a?=YMexCgp$I~cCHjhDtBXXA<0eJN&2s{72GEv)W;Y$NW> z-!7$rR?S@b28+AgW?fy&+VgxkjT>s0j8&wc=uo~!zNSE((>S7DaI%fon)bZTb#M(! zc?2otW4}bf%j~T(XbPs(U(f5L1K$E2>{~0BvK-z<4(E>jLp{EQW{R?Dx%Gd}>z-e- z=r0j*jwbA@cPOv6>A+n^^bV>E5BgUPFCD_$?yk2#`d{9Dj=kLzZ-=qBx8m&?U2nhj zzr3B$^>$zO_RDxXr0eaa|I6E!yWV~bZ(k_rEO*-f^0wx#w*tQH)Tvz1nZy(>GEr}5S8NAKpy{QTIj@MdbOsllD8u@+;+T>&@= zFt=P|eH!pffF}V~0Y`#HS}WpOO;Rr{;!%P{fTLSAR&Z%r;$%CNVXb%aXwL&TuvLdI z=-C%&JqQKNE!VRzJP9}$unL&I@EBlCs}5g4JihP<;FcERX7pC@ZrTn-#_gW5M>}VA zKQHrR%T`tAtp&%~YbW^?#f)!@xs$rbKdm9Z*FL#Z~0FQ3X6 zPAucB4(bcL36*I7tkxCh(?;S7aaRl$6ng^dVX&0AHAKrtpj!vNVB z6a;9vuvLvRhic}86Rp9ZGd!8f)uF6F=|3r_zE}pH^b-2xX7H7d<9{6b+2fYM(7y2g8YH>g6W>U)@XkUm< ze;uO^Sgm%iMc%pxDTlYv%E=WHPr?^kSMNqG@~FjuEtWOcSNn75<;_GbcGfE2RiB!! z`qXySr>?6$^Esl+BDo-4XA=70qHf5U*}(wynOtinwqNTzFXWEacLmv_qPV z570ro484$2?vhYL7_GOEW;k>RclYJ{F&<{3Z*Ra{{t%4;!22-Yh3<3z&S3TO5FN7qzL!cuI);(HjrX1 zrJ$L3DN+pdX1 z10#OTcLcz;Y->pa#b-pSl>7#U-~ZjXuU>Bkkfq4m>9Ypp zl1}U>VE^IU8;~ivqQzEYUAT#;vmxf3k5*m3G)ZwwY{t5QSbGK|?iAvJ1ivgvam3s9 z2mXk!Q~v10_5t=|U+FsJ<&D(1SWWi?uGEKl$$?xFsJ4TW(R(7=l^s4#I)7p_=GY&= zH;hN0Ttjm*_>f(gv#aoA;=Tm&(OPM!wq0@iN^?jz{o4SXgB^0xOz#cA*}jaGwv`%b zsD>*fPLo1>;q{fpSpSFO+#Kb?S=%B1XRNZV3Zz5-45VANrCT~4>1OycR@+tw(xI0I z(yiXuEu9AG#-kiBp77I}3tAoot)l|8t_{#;4bZwW01ph%`d}BW4>DRwSN0&I^+86f z;lI%8>P7?6THo=@v_9J{9nt#t4o-?VL3);nWlx}GzUlDKfR7?v-Qk}B=OFxL2M6sw z?c|~TktP%2hY&u|F|jNab7|>Hv_JBaD==E_&})H-gv*m)F35Y4(-I< z4_q;D-pt4@+`YhU=`cxd?d3is3DUcl#+Jy=BT%Ba9U`^=C>=)bok?jBo7M(R^N_08I(2>+!V=j{ML3Q z6=|RoxAje?_u7>tz%)|&5R5k_p%!{0{SsT}8?mU1B^5#7EwDqvZN?Lc`E?(3VHeSl zpF!WQ0FUuI^zCOb|LzBGvJi3qt?py5teGHu3e!K1n_gmn8 z1g^902)7rwe*ovNJHosN%s1`b>yGbMcRPNe?kd~;bywI`cYkQ7y8BJHy89SusO~le z>h68ORCgN!b+@~HVp-lDb%)z-(qE7Nx4NK}a~UYjMY%is5#g2s_p5GoLAWg7maw|e zSg9vr)f6*<%Vc!{9C{Mro&)a5cH+^gHV88hm|1t!g{E6wJo*cDac`h5(z@!x5x~q$ z?(7vK+NtCsO6%`OLj!e_7^sT@sEdR<>Y^9wBAMzUumaiH92yVm`1Y<WHPBppy^X{EKXEVMMRTGo;6+ysF4Gidtkhzz)M1v? z7g|>t3Nuz23-_)vfnN;*w;BxYzXy2#kizS$dlp*P^ePNbsgj?qpI9~^dGP*r<&SOk zwf_BpzL;m$Y1)>H zZQxsCTW$ceGJv_iEhm6^C4d><_F@3DEP#n_TTr`Ixig59((`Cm+Ov}6E}T;E zPPwU>LMv5p61CdHH?LZ(Fo6F;hU{dwboVF@RdH;U#GA3Ny=D>TzZw}1Sioy z^#tqcYbxdZEe>-p=Y&`J1rFLY9Gj72|J z9fdypIwW368;Mcu=cxtY)*`onP zGl=Buv4F-fh~#XCuvHy*hn#I@a(25iwB@O5G?x( zjDdN?*phhdcaYJ(M?ZZG^C9Uco&@|2`rq{&+saTK=GBbM9LuVKNwq5lc5;T#OviZF zRP{)@wu;t{2%pH#9c>1Hn*FcxmhwbjC!KPI>koEyJ9*BXa zhvSo=qu?mkfY=e>hwNrfmvEDJlCFnhhqGAY7TVjv_-{Vy{r_9Jr=i^1<_Ekz#!Rm9 z_Z^b@iL+J%Qa`~D0G8BJIupds9!>&$L-n6kqWya5SxV%Y@N_by=;|DWsVxWHO? z7TQBtkle!K-ey>#dFSc~-^jHM=^yml#mDw5>{lGQ^Nqx{4YNP!vupMsEly)t@r6%R zI*)AgOe_?+x1Cge($wOC zJGi3Io#Dmth3(2B+(W~OaK+rt?pxt3^CWijmQEU#6@veKLd08Q~H2Ufl?OIPVP^p&h;lHwV6yKd9&Jd7`FTV-Ks* z<81wGu~H6eOyGJT+{SKq#e3S6Exyn7THNBGP>+HhJ2?Bp)t@VSaJ!$gFU8G4zPA>? zn%C(bt> zfgI$;+UYnPA!>_t?<9F;N3>O_00v;Y#1P9{A8NHW%IOO4; zqQm7b?~z=k%xvR_>AZAzz6xhE`SEeCcM_FvwYaxE7`Hdcq6yhAtTw_|7VJA3U_CNI zjP>yBhFei$+qbyw%5Dkz)1Y5W4-xyj*5ih$NzAu$mL1}5by#+#{2DA&Rl&|=)j`f4 zTMe6+*}I{^D9PsHV8O*!n?2b!dF-c^9-K*<9JEjE<$fW%G?yFR&pS(`Tac&ZSL+?+ znJz9m1opB9a;PaUbQkxW%+7QrrQ2S2I{7$T?!(i5xXcN**E4gY>6XVvqMrU$+>(Ti z(WoBY)e9XW?pN4Wr?+O`D_+m}TshjxPx$!Y3odS)RAYNx5TA~;r_7r((sOfWMRx9<;NwBk#B32%(lsn`X-0!>p>D~uxl~&xB@!K0LNXK2>*kiC_ z`gvI`F|2*cwf?3_^OSP{bS_k5MrkOgz4iEj5pJ@ch_n;la`Lgdn4@?% ziQbLNOW-H!Zf!KKay^o;8aH|9-lz#ZtJkrlMK(`b!@7)J&ZI?pZ{DKR0F<|AhpW1d z=i*`05qJIYXhqz5_41CYgHM}UYqF>Ja3wV)#Px8RTs>S|LxRJ`Al!+GnE^{ixam9H zba=|5pz_>B7LOaZtbXwE0&XFRCfo~>re9SB_s~s2yUpV3Vqe_YxmTo{+b3nUX}x#@ zeJZTQNLGv|U5+@^s>shJWe&L<@m#`yn?bmDPIsV=_#Ez8NPn{_W|P3)Me9yKDPQ`- zER;^#n2p1B(ws4a0^sPdkaoddi~xj^u;aep6_kHkq~@U zoe3*=LtE%BH7Biv-6XHIQvSMr7p%7VPd@GtgT>Rh+bm$7eN+l5u97*&hnYpGT1&K( zvu;owI7u|V#4c7TeLGB6J?=mAJ1gZkWzM!i9pT`L|DEw+#<4ozgMBNX7Qe!c>92Zk zsyulsDCjh-a8;m&-&e)#(^#o?t1}Q@>^!ZOI6{iwSGN{$(bKB;FA8&gYt&t|LH{4- z1myg15%um}=#^i}y`_Yv$=V%>p*1(MzLdiyy*;R!LSd50u4AEIQixq!)A`Pai(qqA zAKG)E=PB4L>#gCvXwhY-)vpBDxNY!;7KUt453{gSGpFYU^{5c((n<--BYSO7k2#KF z9)GAh3lv@Iq6m<4QGlWwS!d-hl-m@YmH(>vDLN~EsrV^6E1y<~qRw{~{TGT(38&RF z-KhG5KfJ6kXoLF4ZWJErMq#-l12=*BQKw;T_O$wuBfMs>>tLhiMJ?<@Oy)NyYHA?+ z!Y&>xBPAjYzEI}47)W~&;nT1xC5UI``6$Ck)T#-$2hYk&6alNsS$UzNvG>NBc2=H? z`0PevQXqC#1v4hm^6@u2XkLkkK&m)~gMqR75^ z2keNLao6`t*-^*Ac2zJ+`H!Y5oe|u^S^23Z&K^=J2nm?81w1q#>BQk#K_BSGF37@K z#C=t1XvpbrXps7Exnb435<)tLRBw!GFB#gB*LHmxe`}LbTk|#~f&6JYW?|wvI(6vf zMop+Tz!oeQHP)NCP!O%r!LZ}_l))IVBYjq$2kY2aVZr^SHGGwER^Hd7hrP$nluvg{ zIlU`oLj8QC{7qBPtxeiT)F=l(LF>GA@KEB{=hYmV>&m8i&eJVHX=A4)M6yousXHl4 zbIZ_A+n_#~b~9om><>)lALvoejd;&1h&!g!{P3<@`GL0{O?Xr_PaX*SCWY?Xv~;JM z@1iBG;S^{|ZZbOiHHVD0diYTh)qL#BHB$rS4Pq8I4XnIp<$p4(I8@q%`eAr)Ow*&P zX|mS&Ot;#3vRj$IzAJsdrp$$I)FN8&u6jIjS4xiMtZ{`Ujp>$m_xgPAt~Y+bjn~_G zcc)_WT`A8sg6h#)m+huT3;xT&PfVM(t|9Xi^Zne|bq$YvLaQlk6CK{2jCEb8l(W#k zI4LHV6Lut5%9%}XCu24S{@JFj$+!)S(34I5B<^`m`pAt{CX};;p-+6K48Sg_frZZ^ z?Ju{)5OTpqGw9 z{HnXC{Jep+fy5g+%a_;f&CZ&kHhAW)H{ZvbXal_2*#;UfwSm8UI%^P{C%90u==Ygo zWaXnB9I|b2R-Sp7`0-gEYdNvL;E|n)G~)$TC)bDDb|xCDJ&oJbLMn&aAOm_wfk&Tg z(_4IKzt6A}i(aSk_q5NHP<4oKQXT~xsRqnRoQ85YCw!(Dj*xEwZI+m&i@rS{ZaAP5 zUkTx&CV9;kmpC*fT09}^UViM?giAU} zdgYa#chX7r2Z_!T4Y%q14=f4ZrnCFkH+FqJt>Mq;#ebE%)7gDyS=N;@p?)4x9+mH= zbAIrhbn;i5dNCRwd!<(=jYC*nJ{zEMaW@*@xr4^;U!KtQ<+O$`@#VF5(Ad4!g|3td z^>dNZ#b`X7_*o6r;_ebG7hq13ISbiU13gVEQ#B$tHnoN?(!w^(y}-soBH*^eMj8AnjA=81qn%iN zd*0}*2O3u%`OX=qxnAR{JpNX1 zbZ*D|GIz!a`H{v#jKsIdX9#GcnuvylH=^rWD>sId^4ySUl@!<`GoTH~=xd8Rmao)UBK2cZk{Y-;!en+Fa*+jTttBjh;HS}V z?p_J#y94hkX$HPZbv0pASi-@abrXK-Q^@i66BUU!_0tA-tFO*kkaAJ#@2v9&>-A24 zIBZ0sJ#t~2K~LI=JosqA7@dbXYQ=|It^v=pCOy{*eJjUx40QqT#Y25=r})MJ&Soq! z6$KS(v!=6I$JmfFz}O%SAgi>PCurp!%%*ZNr}A_0Wt}%Fg;3kdE_JXWU3wwy#uv z-F8Zyr{%rCX#M;~8cV@h@>N$H&BSYwVm?dZ(o$YEQbFnqSvwMcle)E1h_XbL)|pH@ zDtCy+2KDg=gH5+in{L-h_xaFQce}lb2b^9P4qlGGU+cV`zH>}c|M;O>`qM~1uI>qN zpk?@)*2#_es%E;^WYLtp$Y#A-nG-Z<$+|kf{ZXRZ(q_wYiy_g*s|R2&MtAPy!L*xZ zd(utQjN9MqK7K#x_C2Cck-E><-Al5oTS}trI(a{F^Ajo(4}-6W5mQr!qJ5rh;i4V@ zjWa-@rtE~gB|zhQb-9>{9KSFVQK=Vq%bTe9^bRVz)BAW=N9=uk$A*swj*-KkV z&qoxU07beF^!uxnf41n}n**DDG0@D$0I#@#fTyd-VUAkg!)a2@c7_HcC zzKdffu4QPq?+pTFFGxt))u+3+T<~2f=SccujSJFE9CsAjE zWh2wElHI6&7?)?D5AgftIxF{v4Id5G0h(3bgLU2*jK?bF_ss!Y@Zirn4#tBwfkm0< zF*Qk85rVItyh9dzjL~v?{y!t{R{mR?By`bDE5#XklLC1Jr<$YT-DULE&fL3~bj1J2 zed!&!cdz+Acjf*ha>uH|a`$Wh;t!L(H{366B^^Eo%K);ELS&QJr{tEyRx9eLCpdu^ zZ~{FgvaU;`_<@#@;>m+#ol?u@KHjRgRVnGMWRdoS+^oz9q#MQ31tDFPG6%6%#NOD9%1+eLipFP21`Cds5}>sa+O)=*Kz3AS>TPV`1iMEQ1rsC+P>Wn&&b(KLhjy{ ze{9mYLUH@=5pV;v3e%`~CNL__$WL@h)Cu*A(Vitu&@m)wog|rj4qK(Sd;9G+JtNKk0r7xqHNO)-&?(yHYQ0TB0Q{Mr4E5FoUek!b3#ke8H6j-)%zRsU&-< zuwf0`XlCKK^6Pf8scW{LkUx~3cM7mMZ}J>hdYs6fPSVD4rJ=*=^uj;VXUf6WOjk)G z=M>Vz!+BeY)AowFf_lwad8sr=s8TNaOz<-|$SOEb$QvZVrFZ(2t3DlkBay}?K7o@~ zl|KR9(cvtzbEKw);LX|6lzN`~r>jc&1GKMeVE>U1fdwir9~+TGgTWTN-GJ?hi7mngV>I2V!wo7FJb3Pq?Zn3Bkk1rodCts&LBD zsPa{BOnrQi!P`fLQ+vGK18>z%Jv8mJ^L(6ULZ9d(HP9`jRVnvX;{P`s?2Gk+m3$rM zp;L+jbsFu{i!RR>PUFK4Taq)*wb7|{`uXc;eG{-3qr&RrKn~t@OdNdH8B!x%lgjm} z5iW~IkKLPKaP!~zIB4Z5p6oD_J!bW=In^i*at#rWdum<9o}Lela_vg&U2{g>ta#B9 z4IP{<+G+I0i&3sKvRk2XbhBf$$c={Y2V0yIU#q12Xg_NC;SEc5;u24_`jvyj&c%84 zf}mZBy|kKyrDd=hhE)M;*%>*q5mM?0Q&iLa25})qCci&K`nhfQ4Fi|f;6pF`Yb(vK zXQ8jIUHY^Knsq^UYrW>2dcka6x&`gyTsjgOtu@TP-)D+dg`J?mu8Dk8A>;mF*G_tAiYyL-s?qarX&kGen^;0rMD@aXW6!x?l2#H^R~scu8OH zRNnH1s+*A3(6;;w)il8$yBV?Mm8e7cKT%8dRL|X;fIT=^F04}iB5;5nGhlvs!m)YW-sfh1Z07Q<}zFi(pAO zrD+`gd)HK{`Ee;tvDj1chhl6eGa=^zJGFjp9EIZ#lOGD5sLkvtj`Wzs-k4j18cQ+~ z%E`0Y30aGTCRJ=2Hy4|LY!N^J|j`>-ckJg>efgnG!=$eRK`UKeLZU()XA zP(EnZ?(ivp=+LI_h8HcWo5St;1CEL^%oExds8_+88QNF#4qDhTbwTce&lhMHm@7D2 z-hz`0v@eiVIKOWg)9#@6TCjUdv;7%4Mj@&5jQoQfY(G(iyZFB%)nU; zhYf3xH?!19U2S5>lZrPY1hw>#F#tRME*3?JmoNF4WnH}%+QsJ3hU=~YY*o0hTC#R zepw!AG(aCj*7^)s4HWFUYFMbgp`Rr6)*%L`PY`pnfwxRTeSpr`O63A1B+7}X=C+@a zXUiQ}9Ztx;LmX_AhCs&&+ZaCg!A<2CR5xcr52=^k2WK%z59pRmeFgRu;Ts}cG*>jB z{WU%GT+%`#e18UAdrYZ5GS?mmJ&ezF?EnJVO`8>xoj!2~^U17a74cQi(v*;lHHK9E-=F_MO3Mopg&9ux9?iyPrc!Dc! z9F;T{Hs>{$X!JkWk-1n9$p;|(-q}bdo9RHFv+omIl=5b3G19_scH^?_hd5ub_N^N; zII3exF$wP<1RZP82Jn*84tvwvNMa>R!=+0)lt|2A*)@947}tFd`{mWq9kDsws6_A* zVbKv+p{GlyepA^PmrQmfPsnrScH ze#l_}z8uEph5s;F*ry!ou#0BI1j{*~iRO@Nftc2I1H3)xyn{pyJa9lKiC)KS>%#BD zK8)$#p|AWAPYa&ic!nPCJyRpva*mao%eAo4iZddq5ra`O_}bJIX}1K;m|AasiCPkR zsSZ1QjFPV@I#HmVLAH#?{|JAr|I%_aUxZ*yqP}FL9+bTaHeIo2`fjh?Rmvvp$Di?p z6yM7v^;BqfxDw5FE%s+WW8T?l_FvgLSu}bLo_pYL#_gn*f&Y|Qoz#=<<<}0RH5|_- z-d2YlY|`i)UsfTT8+xV=cXCDWnia(tIb0#hAt^RdvrW5=WPDCK*5N2mYuKK7N_EEM ztMhrzI~sLDd%XRyfiUHsTyEH*ja=#eO&EJRah6Bx(kJ6O3p~CgVVsht7F@tF%y^ZQ zhWM>;@C8FbLkVaIw^l%J8RaZ5J^HFw`a|g?ChyhhgRw z%rPFDizstQob3!wmB8m>-5^t@Yj@($m#NI#TDW0UztBzPa#8g-?^O3-E;svuT<#3& z`IdbX_Hl^bA=O$}??6rex;+Xs_VkX-8X3r)NAA%XH(>J|dbk$;oqz8t4gtA?4lR6 zkZzW2fA9Uh7VEEG+=xDU3GzjaL}i>-J*9qA+-dC4AJLbn4*02Zs}p0m#_Hu&YJ7|- zu1cK@k63OsE~d;ii1nXya-mY`Sjj#@21|2>C&=u>I}9}aESK6PpgNryh=1!isAh!vizEZ>;R z-TSLt&I{U|hc|N1|C-~d9JO0$9ny(aFPgx=uIRw23C`p(NS6`9dIa1MpOeKUz=zI0 zhAHYOahW{4v>LORf6QztCw-eyeCxoc!e;0e2a5yVty1!usa`ng1FQ~Q56(hEZ+UZ%4^OEd9T+9@1%{$r<_|}JU3SbE@S|ZWflk=1+X`=L?*DTy-X-uROIh+owcz zU}obShbZ=PJA62C9Kr^v72$lY8Z$Zk54U??DDz~x`X%S7-)Hwr)oiC#O}kyUUBBJ# z3T0z)4t#`|XIR9~uzyG=4U+NR2-dFt^J?3+<#P9bqU93tIF4*$K0Hj|55C@&%k}-k zM(*17Ty8qzD)3Kyt|pbod9`E8Y}n5kZ{#>FyvHqv<*HqdiQxFacFf>Rzm$3bBYoN0#Sz)3~QdMw-~${2~Ju1Xl~{5 zfct2(ikkJ7zN30v@yFx5Q&ti1DF+W?HN8<&`vZAp`*$Dec_ZPK?VRj`%yJ4o-!7=S z(2?+XbWUz!7+vfIb;bDeYTrKhGVCq*j$bjJc-y{~3+nhVe_Ag~J3j7$I=P=8^EZZ> zJmG?RC4l)0!(0L8(*gc8ry1tciDsNaLr;Zo=l$R`Tn53Tm)>tCdR+HhP)m5hW0cOe z6I=rN3IOxcNCp=Go(fnaJqJ1N6h__!^$Eb=$oJO~`~+YJi`TXi>;OET!FyDK#{-UM zFyBIOd;`O* z{=)Kd1I__#lnyewasY2)?+;|}Zvy-#d;c%2v~L1->FE8(SnavSUr-k_xPZZn0cSJV z%JR-H)&L&H${Eb!hao>Z%YQ1P%MLgP z^`e))Vd-;FFV%X%6CySJo${+jpB9i`v+@-Co^X$UUe-x}IifI~X;HI|PZ~73+U6=! z*9gI*G?y+yR~zL$uU?te7u;rr{Kv+y&K7JX%+^x?))NVfvER zcK#)TbYj>t`k#`#UftrLkX>A_7CI{A6^#i81xU)1lPlz<2q(dsVy{bdatb|j7;K+= zHFg6F^T>;EVasAc|M08|`LV{=@O{Q>`^E-vGlA1H+#A@T!VF}|QwbIi#nx3|P-lFK>8jrflLDu>Y zHLib=zY-3=43Y55@N1+ngR*a6r~dnBP0aw?dQ}%=gBSM|b1=6$inEF!hx%tvV-2Wi z)>%xWG*<>-=G0j*Cs+I-1iBs6)t~V1#y`zQgOc6Em)g$BZW;3;pM9vr6&~Okeg%w9 zV+W>R0J9XB@meot$UXtg^T15j?*OJ(05cDmEBaZO6-r#ez@3vH0S10(9grY#Zi}mo ziC@oc@a1wp{hZ6ywd8WSvFo{eC*thsVV@OxcW_vl!}8TiE3}9_YmedDSN5qh`py@$ zmVDKr&sP_W&sQ_%*RYm>pVWSRmhDqh=I&Ex;&~X)EIf1Y%*FECs%#M zF(cCg3;MZgqQm0KRg>87MJI));x}InMf$J|%(4q|)q9;**LtdR&fZx>0^X{U{dapbd|xBOQ-S z>xVH>7MnEnnMM5l&t(2o9uD1my!E)8gVpjQ%}CK50sWBtQX}bxrH!x+6=bT5H_>cx z#IbW)&1Jv;3u$BLzY4F5@HOrlEtjC)w$}cM|L9J)MA4+(h+e zu@5|*ZV`1Z_<-hv;hYju3KPUhp#CFkypX8c+@RFTwQ7Z=MSNURrvIcJQE#Y= z=ihr~N5s%$$>LB@+XC9lVncSm8(}K`LKR95Wds$+i_0^Di{*?S#c`S76ecFA6U^FM zr!_r`A8{^6e#?RVC^kura#K0^3BAN^iPfO8A4f2#oMLo^VDD)Me10C#z;6R2v3C-C zRD;iBl2{)vH2UeiJdSkU`zNF@6uWOY_><86;{Dt}KDm8`N~K>LXTMR?_(RxX^2opy zVHd|0k>XRn_VMBq$7sIRTKlK!rRSUBpP0cKYZ%~X0AE7u<>>TQGvG%7?_jXO+7s|Y zfS+Kn$r=oJ8vKCb1T}g%ofoJ7K@}JG=5k}cgupdsJ-2e)dhRof*>;Rqjmv!a9F@z~ z%d2zkfnO|sVGmCP%JR8-Ahc3BfxRAcg_f1|KQ+|W<_f>pToZK7hLl}TZBEozYvK+y zzPV1R={%_pKlYfDPZxxppCb)Jj!D`(9@{(p{b?Ygtt0ci}%f*hH^fh?*YAlPKQ~+2njZ;sd9SMGe z#qS1e=LvodutE9>?+;^eE?}MXSH!Pj`K@8_7@Q?|lfl1Y@RkLv*myxcwZWuX}#R_c* zq&y$?i=^;2N>K`$T&xU}kdHz7C*Z{lp1|Pc&G4nh;BkO?X#(ULY~`VhBXfU?ZxD~m zOTS0WI9N#qmTDeKKAyn?8T;gUsw*<=nTY<{)FXX$4 z;Wr|kR$75{M;M$7STCuFKLdC*G^`rwCwz4uzWNFv9W)W(D-ah_`HH{^OT5s(WoLO4 z>c^O0K=|$K`3R3Qrz5;0`&ooz%uge{Gy4gIr<4Ab3-RA$aqjLL`3wC4_rZh5p{BgudRVg;4Lag4z3= z0Q*)#i1&FR*!zND@-7w(-lYQk

(@GJ*3h7f1`rRnqwd>WRN~{}XZ^Ntn<=8K8w4 zZUMhlBU_rFR{{@yK{bb6g-)14U-i9;GY%9A2QC=5Q-*0xkPsRmORUk5ERo}v1!6~J zl`rfAN#80JUFD)G(jha&KKUeJIBEX3x(ULVMy&Spc&+pa^e;Z;Y2;vnG{8$qOj7}(Fv35bBVbLhZW9;>3cJ~@pb5GrgOq~)?V1g#5GBCrDJH$RA+g`k%>euwgKvN_ z6~uJc4LPX^>zsTMlr;wuq7M?p9rb zvEZtjQzD2#TXu-1!mFzLK*-jfTYGJ-P>#0Dz)t3%U4x5B%N#8IwL>pLGi58NgH^ZlLId2Oo(usR(d+wOw*`It|ep<16=nPne@@DhU7I*W|Vn{Vb zQ^b({shIU#xaCPLUYe(O_1Y!EEAMI5E0E;kvz%5h;fBr?$9mOiPR!zLpQjsl^(d@7&F1A%s?BV zeljjEbh;vz>S9%84ZJ|pd^t0Z_B5`*|1Q?gopjq#FWtgebn&M0-nRa=t8lmQts9%T zm8q+sD_oVjis=e9Z)@N7DPvnr9!M#*rs6@nNXs<17*>X`M-sG?JW!L@T8%WlC8U79 z6P{;--i$2p?NjZBPu1V^XO!Qy`{jgS$6V-vgFmok2+)MNaPRc~n&4t1^^%x-#oqe` z(AO-{dD9AYGW>g9fxm3SxVjqbu`EBW{@XFic3M5|h{bP};~raD!`ckoM2KB!!yh1p3JfA_pvjbujWs@h&S@#M=PJbo7SMqKA}8{a=SIA^1ilR*MY$v z)^VAan8c*!YtSP@b+J?6+m%AIahv;%mvH|tTB@P@EkzFEO0FsJ;3@Ik26Zmyhs)I} zxeD;39PRoWq}N-blP_YF9GC4)7cpiM>X*(g$});?U`IG~5oAc*8hWax26Eqz(V-ZV zE8sjSPff-+S}`7+TI^Hv=L25FU|MS&!js-ZjjylkbLmjyrggEG8l#Pu8luOZ`#ySf z_0Q3xs=tXIfnBkU%lYVOmuyJ6Yu$izhZ=XR8+<9Den2R8q;Y2K0A$42j4{T4KE0kB zYZ2{6L+_QGG==(>vCzh#d36 z?{cmwt`_K}?jd{8dDv^bwoq88i_xN1ZCOaSk6PfxmM_%=PS^OaRl>sAV!J%5(O|U? zo-H0#*0xfcc$J@hC-u1B<~pe+Y{^sa-{S9$&bIEo5&lOrI^e(ER32_Cx@O7hZA+;4 z#qLo}F?-Zt3*QKTiFIun;$8%tf;_Lb2`5z*k0hK|Im=14fo_bA;%j*8Q!g8FlaB7f zLfS)5Nn<_5t9;}$H*ijy%TNtIQ_y&*HD`k#$1i7rAG<*@S7ok=v(Wr56kM0@tLLoi zY(aJ4J&O2(Ffj;T1G3^0+Ud{;SMWsu?SUPdOPFbI<0I?n`6Y-8@WiS9(tmW^c!&RjdD8IYW5`5{}k8eHQ-*E6E_Pp9NTcqkcY3q1S>EY zi5bF0b(165I?$cgFn8Hg?u*z-=ZBxN4sk!_Cavbr^8J#@LsIpp>gm{|hN?%Bq#@dU z2>V+u)K`UD9@Hav>#h~_@3Vfl0%@&j^*)>=2WA+hK9|Fff?lM7%d|-$+DKhw2w{E0 zHMo0{ubzU;eiF~;*uS|f_p0OJYm`Dkb+#;wvG`MJ_chm zUXS}8m6O2>q~VDXzmabdHp5Td$&P!Cnv1k+B*eBD=-xYr_r7a9X6yyegd9e~LyqfN z^h>3)!QNLVWv?3jssE$A?u$nW{qg3m_-)WXl;VC}lH(1}0Lh6PwnjVge()#2IDjD{jj$|Uds4}E(i9XRu*h1AM3lPum@ zF?Q=r$5G{Gb6=qfXKCSG*GO>>C53rE#C|jR;r;OW?_~}4sj*(GX52$=$<$*V)<|D< zgrn_imWLGCyf&AROnks``Ldkt(Td^Bf8IdPpybW-W*e1@ICY3~C0cNQiwz|%&Qc>! zs3$$pj)~++ctAC0gSUD|n78K+!E*wqr#V~CqFzOG&)%mjZlyH3>X2e?7^UL8^U!jB zZ^{m=W4tt^zQmCY<;xD<3Hivg+!3aK~hCgJWTg%eddGl&dz;xc}Q#`{(f!f|I^m#>WjB(}bN{ zD%po@|D_jpmAT4$L-M!~(6jjSjoiY=;BOb?%*=F)EJ(@A&r< zLr|Li^~7sDh`PlM01M3@LW*4!QZ>>^=mMP1*vmswvG-(n>qa=Iw^*!$AT9k`jXxII z4Li&l4s4$4Egz7IQ$n!Rpe@i9=nMKK+g<&zuLNtazU=Zaw!>%@N#vUs7#C zc@kN9T&z5OS$QU)JQGl!r&)QPy&RVc+2AEA&mt?8%mLb?aAsq6&A3!O?um5bM*|-L z{Ir^Ayivg3Sj^tABPIkf@ioJ{VqRo1Hhc%JMD5Wv*3@8@*HVTb3cL*b&>C(VeKXjy z)EbFgzJ<@pfp^py`bu&*tFt#d63TIl9&`TzNCP_bX4+d7#1l%NR&JQ`L+KMdmxrf$ zAnFPK-{M~%k;g?u=5bT-zXAWb`1j!dWBh*|p2vNQ|0>kmc+?;1eQ%#hfZq(P7o?#$ zpp;F`JpS#Us;+zg9pgQ-t=n+Ou`A}b9P#QllHhD!PuZWqyFSzH82Y`0H2oN z_X^z)cl8}gQ({d;oW$bt-N|>vowACEyN%^gXArB(NlU_8?6`ABBdb69j?>u_Bg+m= z3Ap3r!Dw-uT48&!9m;Ro{r;;H*m$7xBsHV+xX+^VxOV*ig#Y*PzX$&nqktQc$Nh-^ zk@h@p3;wSHo;EU%dkN1q;F`zfaeW+l+-$t_=otLtd3kIex8~$Vj@nPKC0N}zLbxjQ zv(Gc!*2K(k>-tR1e9iNNt)D;N$GZM`y_IyCX$?|(k72qf%>sm$nMOeKwjkFzHQj8< zPv4Ni4-1M)llq3NUyvq^FlixgeCqhjsZBqbuFIH`QKcR+PhD_oe$w+BUZ_$XRe#F- zVu9g>M12;V^XduJ7V za#w*bBTXyqRMS~Xomj1!wY0W4*$$)`JG|ixeuBZ_fOSTP#|B^KCzOX7PKVvLGEF#e zJ%F1Ep7bLP7X_YZjvcs2;O>Le`q3Q7uo@GfIHZWzQVQ3caKO=sjeq2VszRncp$ubr zs*q`qu+)Q^xu{G?)cLXJRWD9MoPb4S-30TP25`{%EJY9Eg0Wk7LNTy+S75j9D+YHk zdH5^9;gHu)C`}9wpAe7z=Mb^Rb7moZ{}!;dkoq@ql;(SuW)ryaHyM0|!Eb_#^Un+y zj+mLp?zDzav-{&l(;JFjEb+AAR`hGijr1H3`7{1o2RJxbidn0iMy__xDa8H?VdRLl zkLLMGADxwDyAM;~J$Ja)g_g=7Ex!&c>=Q|q@^cDm5c;^s*dF2$&dpWIj{^6RhWL)g zxNXqXXz-0x;B-ckmAAW5qZtCeH3c{q(xo-Lx;z)@3XyIiaPeAtw?6Jyz`YCH7~odu z2-h69#OoFoWL3&Gn2sjsv>3HbaS!0V`N*pQxO|P|;p)EELIW1dHGaRGYmCl@7A_W=HqCHR zS7$cbT;Hhq>n|_FsaP(7uav)SI)ktfxIYvIK;`L721d%5Y{?DAm~c&CGzjg?-=(pN-@>lGq+nm&A z;uD}Xsf@>tjXcGG)3R;i|m_dz@3 zgRNb`8ICl!P=YbuDYk(rZuAkGE7YZPp2Rp$YY0Y3lbdkf*~2w%&h}=EruJ`gW;n_< z(7M&fUH>7WUXJ_64JPZNpqqf!osrx5e24r~NvVnUI@k z{8T98E6o)%4rw{JS`|j;s-?pl!BzTDg9-II#9MrR&Cdll2dfLZ#Dw8T<*$_}XTEwZ z^SDr<^no5?7SmH7MT+Crqw)y_Jk+wx<)zDOmzS>Cs$PqOmxAbjt=LgnyTS+F+3x6J zv#!WkVO@TGnI0#G^VPq{ksLC@oDa)!d&V4kS9ANte?a9>}gx3LzQXK5Ra^W# zW~wEbFS4XsQ?xj}rU|U7-#4q}LsGHVx{UTHXotcoM&bmO(bAz19afF>hvfHbtEL`X*z`kyzM~icc)pB#a&6SQ5qSf+Z*bT}| zFTqL43gvI@!Xo-V-|oe_QK9@5XJl&AZ};)<0;lsTl+P>76-Qs#gg$OJQy=%AuZ>6V zJ=pH=-CNOjF6E3qcU?@ToxAkqt;;5)Hz1^EGL7NK*J+i4WBGrM`i%5+?AB;#H=exbDwlbuhdKYnjT;*Gjf@j0?Bc8K(UjKmSo_`Fy z{k%M`8g1=)JddL~r(IO+DX&OqYRx>E>z}gE0lj@ zSI$2({cxOk{*76i0`gQgTI4%sjqiT6NH$vJ^~Pvdlrz&Aj+n38gaw>^G-ARLvj+Fj zD&PyryC59)faU|UyfG{_EO6d8G&L+mQxuk}#iPTcFLE;Zc#!IZUOaPs>3aVu`90vy zwK#=Ka-d%xEa{R5FV4^7hMn5TMY!@fqA}uQo*Q&n%Z)cIDdCP8zP@!ZU&#u_=$R>8~c`{a_ zhVj88^tNi1bAvw|kK4sB!~U4~5lT3xjZTGP(nkON$jV`E_BD*n9u1xHFt=Tl>Y|IfyF&7v-9s(ysgkvIXScnzwFPxW$-X zW5vW&oiql%?aN-sxJE+3q`%~#87)iL$hcJog14tqd)!f?+9}Bri zBkcx$3V2MClsIb~lVtL+M?5ire0P8(3FSZg%HWVhG@n0;1^Do8*-wRp=Z zO_gPgbr{1u+d^j$)))$au`o=Z=2_*JpcxvHd<^y@Y4jGf%5wC2E%t|eN-xGQ2F`s~ z{*(<_=#4zC5&soOcuqpU*!CJ^AGG02^ocEpaqBQAkE`?W9KR}$+qMbg1o12JzX$)j zH|B8{@ucI40B+1?q&doS|5-q1@NpyPQJwg*$CRuQEmHGUBSyU7YFDywFQP)3%XZCl z;Gwz7mpREiECJA|rK47$6 z%tRh3IghBif3tkr?#yR%w|qi=F`vYny)=~9OUP>$(X;Zu<(0DXHckKMyke2p{m5(c zf6eR5|JQl(_n2YR>G@9}om;TmK1;BW{Yl%eoMPj+n#-lx6rr<7D-d{7vBu@ z)f^oUzKG=VFMPtWpWv#IJ!Pi=QTr_=Iow=W+MriO1cR8PLNtmgccO^yJ<=&Qb>1 z{=+=(pTK#+D^UN+K0HKx<-20fOC^1AdT}rHf6rnNa66XS+NGHk?d*lP6qd?_ z&^Cm&v-E_c^w?A89hlP-X#TGUWO2imDgBRh&1U~a^cxfF`i}iqS_i&FFlT*={cEk? zxkc;1++gcdxzNkw|GQkQXH56x1;5dY-G69TjHmpXk<6equKpr&xnPM%(bbu>it<9U1A3WZ zh8vdtz=QzvY_mc1GQA9OoPAP4F>@ARhI2amTsAWvoEJ+D^HA{#wqn?MlDrqk`eSoW_8{A;mGL3qe-FLj38FZt6X)bo8P zMEpYaYa2QDVj+I0U4O}Ki)-N|+Is|V02)4f@qqd;?p|)rI^^+1_y0D$2OrPd`(A>L z8YdSVWbb_`2j>GMuD~9ANei1mL3Z4c6L>-A4adzdUf{f(5Q6>4@29+(*so@9t zz5Gb+r3b--(TT5w`Vj2(8F2>Hf`47jtN@4;fLw9QRxK(QsgK^97sQge}=B6P@(MuM%cNnx6ZJWqKiw*ljTmK*S-aJ04BI_Tn z+gmydSy%%^>7)q+0@_)Cpdf*Uh7c8SMO5fcC!`y)G)dUhd2ApHDvl9wL{J9_D$6(~ z$da%~R1_SSCs7$8xI`I89Q2tE9k@4S>Gyl;-tGis@cq5d=l#5YyauXkxphySI=9wS z=bSQ89~ijq*(ut_2iIv6Up#8Tnan~rwXX(fLkJlMy{{i&NBj1YWn9D1N|rz(Crn7I z3FD9rEni4sNs)1zi)5Mn20Wu3oQ-om@C3XL9dKbo9nLi9rww*&nr`A26hb`jo`J6G z7~QBASYDIqO)_g5XBqZ$KO0^vJR;sInX*_yaYGo7rAjWu@*3E%ah3>J-x>!!l7rr9 zz`)I%2;C(@l3?7?J;K=Z3;#}edCJd?<1k0M*-fa$RFNf^8)})(bVQ7lpm(KX3Dd#h zUgKuN2-Z*zYe)drC~;HGNoi`i6X%0&Rx4>L4}u?|KmUX}dKJ>gZeFWCzgiHIKXq?* z`^#%;q`bXRS}zfK7S67rcsSzU;WT>cSRu~k9^_)pCRbJA+(ok?^`LgIalhwQuTmM! zt4LaqwAHnW-Jm-`^M!Dr$t`t;Mk2bLw9h^9n`GK^L-(` zL)xOM2E0|wn#~sBqJ9Z`Huwcf?R#`CG;N@D_-q}?#*SA%3kihEHpjP8%xdkkC#4hp zW?OX6hVJ|XmQ^o{NuBa4?}B@zH2nvdH5_Jf!!4Ex3dHRkq8bpVH)(+77zN8Z?+;>6EYtr3#I+paOh6p2Kzx)# z)Bxg*P1@lpmf%hU2VpooUnb52Sinn z);Ww_=-&&g3ZubuJ1oX@RTaYGcNX|CqP{)ZL@BNtj?^~{>86K(wIa?uNfPp7Y$(#_l-@1AWN014)p_r@M0}pqBX)#BO0cO*5*_K6dJB+tV>r{cfR+p z-w>p_yJSuLO;e(e23cmKZFk~SLSGkVocDcY1|<8pLbBOq!psrX`g8{5Vg(9^wvx<- z+zPer@)`dyE<;6W$1rDpAhs!I{~@M(!Cx_060>~bPwo1;UdGYi6Q&n0&~G`;@>%R< z?_(FZZGohA@0k|D|Kl!wUAQs&dy~Zld_RXFAwBqo(6_+K*e5muPJ}V|`$ZXq%`vYt z1Df@W!f$(XGYmNts`GAyw!JkcG*NpRR@?!l8WIJw1si{7m)DAS#_-x~_s&OnEDyiz zeF))uczBcdY$5a|gn=X#rFs@?-YtvnOw>2-#kwXvao}lVzS*Nv8*}p(Hq^qf2Kr5jxU>*Z*?W@Pkd($KV6 zy&-h{pu9Jv1Qxb_UY=@4uk{3*^i;#wZ(bDqrwHV~(-66S(Bi1|arwR1XXW=vLFI{r6i+2d^kQZ#FNYTRX2%ZEY2 z7rl*}p-Vn@k>0lHshO+vs|Kx`yY9(VCsswo;iScMYV~Gtv&N$*tVU1hV=Qf^QS!3) z-b+)_x?e9m2wANu8EMPpaOwqPe*K=Npfs!Dq&X#=;)1kb`yB%ZQ^X76*Di- z6&a4*Of_a-;@=cqj;tAM?6;xcrU87WWk(&S)vO)!EkpbIDWjBi!u@htVCUgz{`K>w z)sDV=hu9(Rf=1oo8cmCV)q1C1JnN)z48pfvtm5HlgwtRZn$r6soP5#9!;uJ&!dOQ0 z_+haGQVXxWwU((JrhR8Hi_guksAj@Y)7#!*EySBnYfxjmkV$r%CDXwt01y z+0dGdMeaAifi%?dwZG0}dF%+KcH+Jb=|_2w-z{I#A%3Xvnh%RLeE%M@pLl0FC!K(m zz(!3Dw`*YIk~>&sLUJS-k~_)ZUPA9U!H|8=8M2WQhxW7)oZ>qgM`vn4)zO*SN@2q& z?ATTK9hITpFp5+57wA;n+Bh;G1LBT7LHtP1>@K$=p>ZM({C)8J$3R!ebO@(lEYTT@ zw(MpHVPA1PPQVJ89+Fz4S)DiZLaCJIDwW2&ek}hxazvvauJokUP`Dq$vpl8JBo@?s z5UYzxiZs*X$~UDo&zb=$wgqk#+?aCk2L`KHzZ+C+CF0c|R4}5&QwUeUJp*?D{o**B z343MO^2Oa14U!=$iJ#DX3VU;O!e~e`ItDq`|}8UPu%HuFG`@lO!qYAk-v#-@r0vp#SZ1`u5#HOS+rYzl`dk8=)%xU;n3*@A&Flilo3w;( zJToZJ2DGu&kW^!ygPofosYa4J#0%HP?uqM*)HgfR(R)cYt2!t1IaJCXezlaf9@z_i?MBk#hg}EwFG2?7uo#7} zw2_CxlvB6EVh~`mqfIxI^K*=)nQZtF>(WfEV{Nt0GQ>Kobt|keTu@GzPr1i~gR~Xj z>(8Fjb5^X+K9C-o>=XC-+*rY;3Z@!5eg7+uO%UjG{E+yiZ>r@`^W(50uW6Zz9Un5Zdn_JXzK|8_2Ln$L#QXCfa&#w@E zo+RY43s|fgxVYK+?38e<0G~<}phq3ts7eTG4B9ahw75R!-qWy2oK}o{V1sq z-e>W~8K=bO+JQCN=Em93sDgVDZY$jO*`-qJY=h-Xab4#ioD));#Tg-&933Rs(KGfKTocBI@fb6k)P z)`j!=t5>F~QUhB^>PnJum2Dw)h~qCuqJ7AciH9ItL6V8==qExM8|^E_UB0DELisP< zredalR@QUfljA920R(9$o{>EQvn7$PeXB{X5?w^*m#@?(AZGh-oQr-ckF~X?3t1BX8T%2 z{uR7kWv2H_z;=kQwh^7^G?#jlNukrjL1pX)xSY^3HV5uB!awyYW1a8^hL^E;eHojm zD`Q{7b;9)vE@MC7c^+ta%gfwm6!b{rAi=E5=n$jZ5b)G`dmA><;X)2b6 z_X!5^JastzN;5=27kd+GR?pA)(=a2X#npNXFMSEFdwT33aNP~+i#X%Q`50REA@NO| zZpY(JHH_u%*R9~nRt~e#i7~iziuAA%C$UT1KU zRe=uiWsHD_#I>E&M`SJBQxC3Xe;824NTiygOlD|CB5Rb z)foR^tZ8<9ihIc*v$V9?@rv_PuLt2OTa^PiV}CzXcM<$0D&^iz;$aiaaab!sq5=DD zlA*;OBt>i0;C#_dN5p(5&~&|Jq==?a0owGFAik3Y`DE;*dBhK&MF1>C8no zEZ!=_!kQCoJ`J3S76thipD46fPieNs!g`i0DcUciKfaD%QnW*SMA}r>TWQ4!n91IT zmN)avye!XT^@ziE8Cq~+2hC)M#MX{(nSvv?ma#gxowt;+kAH*=IqLN^;`wmzz!AOH z)~Ht+VKE2eKcwxAOZ@U4?c(=bsyq@c>~D}9pm+5(=>LaZ(}^}3!y%mMQ189B0V_0X z`h`ijuU4oW&Bqm-&w29Dx~4ZK^yq=lEtyCwGS31$xutRF6;Ec;IkD%iHrF9TAiW>t zL~cOp=WWq^MW@AS@*v(5Z&Lauoj4ERDe>r=vZU@r=*3fSjcNDOXg1LdDKE6kv;7u6 z+uwF%+9dS131#dP_!Hqj4L=@!%Wde3pwCMPKRmIF{Q>SY!bGpFSfRPWv72WjYE0~a zT^CN5v<}E$ASG2<10ND^2GvNambBZeUA=JLu?e| zU8v0^SvhY?pXRxUH(WRlxal>cOvkYzFd^mmg%wsSWZt0RRxCjB?P5xrg>Jj?iFJXF8#^?bYdonpi8koY0DVONhnCU`so@%+Q11V^0QT?HFqoq-* zj||$dcACagE%n~I=E>tv?%DHD)2fwh#6ykAcWBSQ%iL>q&G$;ll>;TA^1Er^<0q|} za_RF`Q)V^%IB=ZQyBaourQWl*O`SH)ICaox@1NJ}wXiD@a$YM;v4ortX5fd^>o(MS zd$;PgguxzNuu0XfO;WY%FVuSVtzXmAElJqH1T_bpw=k2WYKC@CxB+ z3m=`=s@SuAUI;lK%7kZ$7ZIAYeoqjzJ@xg>bLO(~Nt`027+2HTZa;pu+n=B9-oS#D zeeGO6CVFA>G67noqqYXY?l{?hU_O{-V3k+T~C zNjEm?_`p4Tx@oi;G*VxeMsDw~X|&Ay|AaX_v9drrheMrW;|H?@KAqM=@Dt zp8-R{w5m*f{vF7ZQl3HS-(%3dVb=Z97?ZswCUb;9JGQUm=={SY48+OL2UwfMoe{?L z8hyTz#Z$h!YeoqE9JG(~iQnVgFp}r_pT=;UZ>V6)vlp#$ARD6QvLWr_Nj^jRur8+= zl1?h9FF!jO>n*sXDOjh$r!fw9H=3z`U)i@$U)6@8AztYdU+wDIx4YI*-}blRgdT19 zW3=Is)P|ov{`CK@4X?)u&6REViI)Fe8!nWLPxCfh_Ukr$ZCaeVCM{N7(VsajrtAN_ z*`lGFWvy!5j1kt{M-oEIr-U@zP}4_J{k(sg@L4(T?xmYupPS-o+%+YrT^k*K`u+2& z;K`Pt_TUTp^FiS6MYlL&4AHiMGtr8Bx1{67;ae>G#SNVc@5O9a@%TRV2K^QdZgbIY z2*Y{kOOOG@Jw>~H;@iHUYIbDEKGg=@7Ubd2V(?6bXVpF}o{ifVpV=Tib{|$USiR6H zCc*MJ)*`T_i*|QQ;}EU`AI&CTnlvXJs}X8HD-Ojdsp*#{MQy_F0Cy~O8V*JKQ!m^c zwFB0AeB!ds6X2tf&BMp}ss!gJU2Y|1Qyg|*XuEg%(v*}PabY}Vn(wwFpWLouBkoW! z;X$n5?k{8e=9RH0;IBmdhPha?z&#B&F++v5YGjW(Xt9f8fCRn5j>@`F1t%@!N`jI0 zN=JH~K9H6ir$gHF9k(4>a#tA}5BD_OG`M@=M!;Q3AKG6LbfV8=*n4%;hn@(WKCX^# z`cP^zr%z5tH+?9TtQq;lc^xO}`YG5@sxFSsdS`XGKoOG8qIDbg#~mgmjN-mxs#OvvAsnv0jAV2)7DuC)^Uaar;7glv|B* zBRS0$D1Wdirj>2b!PcbXQtsWqknGw>mv|ryf|!EoXOUHIM6*c2m{q z;_)5$(nP1&E-Irwb`wgZ_`t5)jywQ7SHX=ZeBol@u3q>3pzPQWil4kqJg10*YRFCE zh7rR-*j$DN4^A+{;tqJ1h+#%p3U&+4bXSA{w@)P0tZ_806>e#ALz8L*|jiQaJ7d-FwFtAno)Csc-kf+3k~eHZQk zBl$1=8T0^1aK~DLW@>P5GWfE*FZf*97ks_GjGaRHE%2$VdPj84L2)|H`p<%oM=4uD zi3weX0XPv>P=zJjKjiEOKrybSUENJbxeiP$m2+K1=hSFlU& zdA`Z+Ou>$g#hw=5!Kq4+XTmpCJViiCt#2z*Qob?r6ctk5^cj#c@|&}T^p+Yaulbq_ zgFLa&?2q)YGqevmC|<;^@lE3WZQtQe6E>o)5qIDCPQs#5bWI5HT0PIT;amc{YFye3 z4&x4J1ZY}zumj$89y&isOFt-naU|`?hkq$!AN|$O2d+k4Kj3>==GlUkL^ZyA$)ynR z!ObR;?3!Vs6Zb3S_~Wg|@YZgeOm1Q<;qeBlv5D7v+_#C`S|V98Gdx6Ku2pMgCF&*SQ|72%$kZ%NXd>>?X;Zpx(hx5M58 zlEld!cFAPO#{E2WTSDRd}g#m*zY|d%B`yd93h#Hw(rknEaONSi-MET&R*Ik(>oh&Tm7Jl z5&h*hGrU2I^RWb2Zfq9^N&fS({ocKz|9ot}_phS=d~CmW2ksD(&&T$Aw~4S1jBni~ zUf?~1zU~iP-`!aQ`TCFjyb2R~%OjqQOWe+7DJOwvG?bTe5b-on*|3n#(M*>8(A|T^4y<|7N!otMxXn03 z;TVK(6Qg<9fN+|44s!sVpY_Fgj|#uqN;TOI&mimJm&G=p12m5E+;^JzN{~ACl$|!z zB^#@;a&pF0nIdel4Jx!-$cKmFcvz>VLN z`{_6JKs|o{dq4f&bbu||@BMH;{U#icbzAgk%~Qec*jf_`OYu7EG;2r(adu7ol+SN3 z{<2ub&l3)cNgc$kB79E%h;R9G1xr-Mt?vCbmz}Z7CjOknJ*0PD0KpR~-``TN^KD-FN$KY}nr7Gv=kuz*`YBv}4J^^d>B-QpD z`u<$>{bjHgWQd(PGhH$~c))wIRTxgKrr8GTlrC82G?^?@d5NUE{RqDP6dub!tQfIL zJT?QdJj5pQ*mT5l8WSwHAO;N@$nCO(hoSQj#ar9hnPbt~^1(AQ*zQ7W8xQ#=u6?nw zOUy#5)i(VKoif4m5=Qy0wh73a$RX0ZV;VnGgUa@x&bqWc7v?PeOY|7i`ryAPtmt>o9yHH z!`Fs7dmh=zuxHC{a*%SSYoM=iSm6aG(x~;$>kB!;L*>VNKtA#^5|C z{!gIa|8x-g4E)@PZXh`9-OA6xQyLN-S}S&_hBHnfWv=j%cJbIUg*{ zvYxdb6pvpv*v{4T&WMIa%s%myZ=5B(IUG{-k?t)6qgT3N?PEoY(K$oXu`Lhi$C@GK zde-r0+z7DPp_}=Yb+aN%E$jLacgh;BWe=37Ft;9qRmspM*vdTrj%Mh}ZBz73v!$d+ zW|$0pFq%L6Vg8hV&xj+rKAR6VY?@1181%fL3l(_;l9jN5uZdcK zbxZx=2EYx38w@u;d6o2}pcBlnObYQI}yO`lyH3a*$bIomkv(x*jk zsROcTTcsG}S&{6P9!aKC^^K`C|F5a}TuRWJK=lc*NwksM4^K!yNOMqxEH=(=kq>9{ z&0H3GL(Q7S4=xT(3~FqUN};)ZP>khyN};*k%np(i2i`zlzP1q1=fW?maZc9^NetY= zf@QOgIwerU|)VebZx7l39vDBjkMQVwRnwGir*V^U(THXysSx) z_{~m&&b5ts{@hiyST#EA=%B*Qh0M?d%eJ|8*y**q_-e;>q*_{(A_9kSi~23S<$$-3 zH^|a=#sS!>n-m=h&O{pU`g5Dsa-wE0a*oHYD;%<`2fQ^GzK}eylU3_|+e3Gz92B2v zn-2MC4=nAdiT9RX>#eB{f+VDx%NW+84OPJr&nX5x$3-bY7P>X0LGoBxVsZnOee%L; zOB~8>ys&y|NK0hMkjqbAo(;$gP(JCB9>803fWe@dX5@BVNQ12D8SxR=b92;~5U%y+ z;ikM9({x``jP{;$J*zFOc^k)XQrk0-q?wG=2XJCIV_GnBO-3#iVLQFnJEdCAJ6le{ z9V&jDaerG}FN+>`^_&rBwbk!QFz%RADurlDrIpDaA4Mn?AywKDALU1&IB$4Wtc#VV9JKSc5u<$3$r?VvV?~ z^o;m}w6-QW!(e%B@fi_Dk26fUa`=K&wYWOh-%6Smj?7?jq9B7MP-yrqriowQeT9;KlFRm>5$bbl}@D4Js>{uR@_KD1DuUY&8G|T1H+$6|&usOm+XdKRAqtmcDht4hL=JSv&9*Ua>suo8( znI{~p=Am~p&}95wuzn~0rG4AtK8~s>WV8HdQy;6g`E%)K!?r1d8sC$Co=wu(p;#Af znvPIvAB4VwZ9T{l^c@Izn;bvj7B7RP4mUzGL)sBRaeOX-g=I(rgL_@?2(c`~J<#uX zV=lQZ3>K?~J929dEj})JDx;lki~fN-cp#^rB%~b2?}_I0OXm!A&|yPAt)o3o63UG5 z)i={9a}J|bj)!s|m(FdK-!M83+m8cx0W!p%%Hh@usnhg*9?tgFkkM?k=WT$52u3eR zh(sGzqhFV9O42q)dxVIXqtJf4yFKgB;x^cB`-eCUSe!GxB{iG3@6oin?1MwvZD;q~ zisz>sZQ`4k+nujVi`2o82*s|>cI%?Zlv}d|(XV@ z9T$eGNX}R_I{IiI%j?o5QyS#&n#7g9gqk!#B$$XbIsga%!AYq4cY>K z;)hZBA9T@KgQubl?U&9Z$y(|%w1e-kfA5Bq+BF_u4bO`9l&Xz7-RF$=R(b=r?i;VWf#diDR#rEvoi>tEFFFu={m}kscoM+G3 zokwyzi=9VXRt6a<gp7nJUhH&Y=7)wy|r_o~^$D`k$z0@J3{=uqG z**N85qX%V>zUM#EX?`6#wo;0^Cpa@?CceLwVGiqudu8gxxv)7f6jm-^)f{WUFMZTU z*wMTgEz2{|y`te6_-4rjMT;-Gyeky4*t4|*;t~*ZfhPcKzS>f0?if0mFZ9H#n#7#0 z?a~Zw+L2ipOCB1aWz*oKeLFA;0?KR+-doYNJ)=xItf5h`NnFyk4Y4B_Z-XGc-z47K zwH~$t-`2dCAwR#PYYUzq<>PUaIJRq3#{1GSC3bTc8}_O+SF;g0QnC$L8#m#unDrU2 zVm={Qqq=IL$%AL9H(RDa;@@C-3N3tS*Y1J!d)7$9H2W~y2xIG`U&nZ_8rSQlpBsBM zugRFg@e;b;-BTv%hZ-zyymPtpRY|A$FVuqIdOQDs64Nw98;YOrd<11WNGq1d&vq_H zd{H2Nrn3a`fsEdF#?rwva}XrYOzqNm$B=Og~HHvQ6}B8qSB3_;ZNbdMf~4z7Uau8x(V)I zNFNUWApA(UuKrq9i0A5PExU;D`$)^g^LW&~N&Hubu?L1{I}8ejDm?oNG78(Jp_&+K z?XY)AX>WH#$}N2Cb4W{ktDi#O4?23|&4v)U4;}4@KOevT7~$k#jwgT zr&QWF=al0e?;l!HGob||oVBMweIK@85g5KrKYx%6a*DG9&Z z`R`tn3E^t~TWh)*;lup5-gFbfYx(an(`bZG@ZXP3qY!T3zh6M^;l9pD&aIp8^I+BE z6GJ*1xIYZ5pMPM6StHfo;}b{tVtIQ&nzc#X)P5sYg)B_|?$5SEQ%LQPC4*R6+85XiWR@6V(-CFmHkx}I}iT{Jm1|*&4OM~v0%7RxL1*9-*y$t3Bx|W zQNwy6tq)v3xPfp{aL?mAJOQ_6@djyBY)FkJjy0>}2IV#_Bz?0W@YYE}qz;zO|ck*L1hzV=ru3V@}sWFFFtFFbOvKPT`HbIPm|x{f$+& zaDJyD&OzffbPk$9C!xY~#HG?c*Cx*CN~=qTT}HYg$GF5Vu~sL3d3lsY{LwbHoRxf{ zW<&p{g3X3cYhMR=?K&q3mi;s~R?INMlNtTLW0))|c@q*+EBo;uu~PFz0u zKD_TN<*Wl`-u$*~@28s=!5VS~H)^g5R!%hZutVAgJ3KPa z`EQ&yk6{cWn0*XtHtOFMENVtMA9vg}!5oM8=OzFLeHY0Xl9tC0T!twPW5FkNv=-`( zcfUnj@BpWZ>b}6r%_aHoYq*)?1*{b5%~3N)L9VR>9LVY^2CD^_Rjmqxjh=+ept$c> zu?@q4rLbXG#&G(QiZw)(jJ36?(WulQZl)GBnA4foLlTV621nv_u~VGfbxM)S9LZ(D zI>moFyy}?`^O{1zBN%>w69Gy!4gKm0J_w%E|S5KeL?Gz)ice zoIMPe4f;@BC%|8FM>(_2Dra+UhmSn^%*cI%*OH9XdvpE$VHT$qjiKYX&O=|&>YsRD zmILf-IOzSCNc_{O4Z||^_=cEU(9Y?s*@&-b%u|B9(+RG^hMF3kA-D&uP6O1fhw za!J%qvA8SY&>+a>f>V*HhAsqYm_*}LfUJnNiO!B{rT(4J-ywU_gKE?x`yN$8Ka2R~ z(VlxxW2TIym07fB)@hjzF9doG^yh)|3-_S!z|DaZ?ki```^%XNG@!cB9JL8{bcw&L zhZO4Hy2zq#8!QaT7IoXikD)<8=SOwo-rBSyuUO03FX#ty-vjU5>)73!G{7$S|dl&IG`MyXM zXIvgvEEq%L&Mq?+*=@b6`RQ} zSz@gg`Ucc8AHgg?t93GVfKPZ547ITQx5{F$l1@M^ZXcRqS%e*80>;coJh*oX`C_bD zwjZq2nppfc8%g$R+%GNZi*=bkIRU@ANkaNtnu~p*a~Pd`OzN9_L#B2Z_K;a@!{AI6?pz+6IT-prgEM1hYBsTvpyRVq!+GB|oS!`5aLxF4`}_K~-})d1^e zxQ|ydfNx$aX5$>BR&n^A4bZE2shn-RT){?tp=K%XuVtNc)a-$m zX{^**JmCNQ1M4vfIyy4sPg`m4CnZ&(Uqr+9R-2e{xe6H3c%IdsfKqPaXD(^@3L{`4 zksT$NG@qJkeiY{^BYv$o7+;7nai7kiwRoLF@>Sy|L4vRrHqJDbNX%EaSoT3@p0qe3 zW7)6-%#fJbAv=umA2RY=ZDD6f^4e~j)jF=2^dLxcEk@YqUDrZ$KrL=wPQ@(Mh4P=M zDrYAj@SmT*=j>AxW7_BaV~adj*NT6~`8nyL4TUaRytCfPxGq|*lXTI9G4VFiM>{x& z^wHk4Haq;fXx~8>4XwfC;b-sBXhCn1i~ul?j@t)2pR!Fc%(s>*t4|!)(QI8?bAu=L zE6ik&kBkQUBxEK@SYRH<36J_rf6tMxthS)$W_&N7_yES&TJZ^fc6uA?@ZH{Wb_9;- zm{wB{yWTUD5xAD0|I@rlIOGEd()N?Fh!Mk(X7AD=Z8XxtfLU)~w$MiQ&PanXqHC+Q z7T@J7?C1%v1mHz$5yB%u}=X;Qkx#3>@J+8|ODZF`>)qtQBtzw1I&nXMr)soLSE0^}D6@H8?S2 zj!As{E8%?WLhu1gQv1eMN!gKAi-ciopnrW9cLu<>zOv{iabnwdi2WpvZzJ0Y=fqTB z6>d_zWA<78OV;X}#5~`cAla5a_2c=)1hHwA5jHML?wRjAD<0?+aK3m}tmr%kn@Ft);wa`_#~xK+b!HE2X+x6I@2eP#z=Cw$~+e{A~duyy7vkpMVq)vy325hsD6)t)9?M> zhdn!Z&ZZvkl6551DYj_^*+nY3=UmKwZ-ysR(8`YKvswPFWOj(_^JoW1dJ zIs5rbzuottXzf39>3qz&u|v_?x4^a^i>m@}FUNY;y4azKHQMyXs@2d%!0p6+S%-L- zbTF-Pn2G5Y$PV!{Sark7a(MzyoC&W#Ufhb67mY3kVXyaL(E%B$p7V4l=4o1?w}}Qx zUVUy*)>D z_I}()P%eFpHuDvG8PEUfrPQ<;KuSvUP zY}p^2l99fbOADS8i~4Zu`YqlQ(1QLwIHf|bJeq|{iV(@4~M_l0!c0){J49>4Gb z^cv~uP&|E6c^a!cb>ZnK{`3YseOh@sNO@|*Q&VUV zT2={{12+S%5&g9VPL1$txa|nfg&zlZ4BJ;dPSy<C~@JK~gNm;{^F_5S-YBv`wXSM!qi z1K+U{9-olhz|jkVaRm~9-ql=oz|t^0QwyzA`33+3*ZQH|%o5C&X}BAqr$(MJZU~-a z<4I!U4S^@=v1@TdLWj7*#}s{S1L^K!UDNKX#j2k6JN*Ou9g>3Ti_t|ATd=n8zG*@* zO5&|b9iQ(p-q;?lV6Q$1yOHoegfGB<7XC`OH!9Vv^Pvi+Kc!|=H>m^bex%blY^@2( z49Xb1HqJsjb4gsF?A~j|>DZaGqy4d08in^f;Mve#_@MW)2O4j0^~=QCVyGrgCuuSV zxdr2NYf4e8wWJ6)@>WL7gasllfjPT<>l7Dw8YIVxIew#hqh_OaBi6B&;F*c2+Zyar zXf<+>+ruOobt-S?{0jC2TpJvfE$=O(QTAcJ51$7)4(!0=us*Zu(W`4<2`d?UHIkC? ziT$BrX0T}l&`DP6IZd0KZ*&(jO&dk)< zeK!bw>#6*UJ&q@`wxl+8D*tAkVvZzhOV%R=y4KinJp|dfK75Agjjt%%MTo*zBtDBI zhIe*rOV)}nw2@Zn2uB6$1@}a51v|a4g8cx$2Cfs~mc{sX&I-0FuYyhOtY9Y4fxef2 z&m)OX2G)T^*oo8g<$3l6S@|~m0%yU(Li{*O*zbS8Q{Zq{Nj?VmD$c>)+4pp3YV6!>37f0FifS4 zhC2$ga|{F|FDE-h&XH}G{bja17GHdeVMcw#R34ELg~0_e?V+#21f_FQ$JZ4DrQ=!UDq-^Bo8j#b+DR4e{AG#b@8#7iQ-t1M`Wd74a*W%NC!VyF5M{o!fw!*c%h$8tpwqjS|@*JQhLn~TA*^5y|Jl@I418G)L zk@B0#x&C5D5ivzFx)WIGkKY`J~}3v==(#+#B?T+eZm`3Y8%lkX~AxUe{<ygUyrCym2L|s~v?_6Ln$&*pdSyAG$ z(HHiU-BwUiyd01HaaU1c_ELLEfh|90Vtg?xS+O8{Y01h3_LcU$oCPJ0qMTyKg81wO z^2e4NOHNTyce`M=Toa@A)gviudG=D5ANhhpXK_y6GGH#Zs!{RT@_$Ce^5=5dh`cz$Lb=M!M(suJ%^sr(gLPz>_QTJN{$-z!U1@oIEngTscL~LOwtgXQ88Dyr5h&&VK)i^Yg5sP7#d(D;v`LIvXkBva z35-GA{fNduX9;>W@9i#|$v-lh{Nti2i;s%b!u&;czy5y|lDlCVx?FcvF>Ymn1Y>fQ zF@z5Zwqa~C@EN=jDBU#{nfzAz`BCMEiyfs&OLa8=RFl`W6o z$(RK4{ojn<%5fDe%~v`SO?}<-TG0wS?oKR_pLKWAKwf{VNbu$@<3d~qQv>0>mO0?jd9G5a@T$w17oT}6#r!vG`nbpb6$F-NE2WU46)x&sNDfQ}i1MaIGu@cnKtC_R5{ag0 z>P{F2>6PNFWRtTXl{&b;KrGW1`iC&0l7DC`a@lQxX+>GG@-&R>3K4j!KTSdJiZq1; zSEMNv;Ay;nFUaGSq;OJ?aIzAXQN~nKkexL4S0ht)w!a>{mGG9zX~8E(XNld>qYY7O z0}+a{^ZXTFQDVzmSd_DblI3y9;a?SWx1Ouo4*#I}*-rnga&>dZ5R#p<%wGb=v%JDU zb4AdiZ0ClYWkC@fZ1 zcQ$J5@|d)=xTG+DnJuu4ymH+@FuGR_OP8W$ z|Ga+$W}zb6^1z3Zzgu9O@~=3r9_jq)3QE7q-?OvJtuCxjQF;PhAF^fD3qm=6p8wPNqsr?!@{(Pt(sEZZH6LnUfwn{udGoOlWI=?lq5LDULKlA& z0I*7>Tr@EG$tbV5Q%(Q-HFtonfd%FjbPc2i=o(0&MonEQ-X3q47grdud#is>zLte5aTyO23s>S1iXW-?QHtLiJ}eNiK1#f=;`dYh{)!(B z9~w?8fTZ!NAFF^7A@KLcV{}coQ&lLoM{D>(C z1mGFu*S{p9(O)|MW#W-{iTsSY`7aYED)B%~<#eJf{fQIn<@^c-y7S8jbjM``ke@z3 z{tWzAoY@Fg`;`Hv&eT^{2Ih!g*&lqVyAI5h+M zOQ#=k;^o`O$3%v1!~2nIc|PBa5|1meMqHqur<-S+=a}y@-)+9%{L;>4+I!3k%#+Ns%r~1; z&11}C&Ew2z=JDqK(`QT{KHY4#nl0w(<{9QBbFw+byvsb-{D66$d8hea^L=K!*==5B zUTw}c=a?6oOU$|Et>#zE+suD8ziF;E?>7I%{D%3g`5)#V%-@?E%#G&H%m>Yf%!kc2 z<~`=O%vI*?=2y)J%(dn^bG`W;^SkEH&0m;Ln*VP8(tOH%+T3J5WB%6MZ2r#tv-ubE z|CoO=|I2*d9B2Ofj@%uN9WU-Ywd19oeNfNx9ZBZbcb?hNxZ|rG+jriz>w}%DT}iu= zcgf$5cpfY%sbB#Zxx{Yej3V3Oe8%qmFM%0t0()@1+?dOb3#<|M@B07vcjg;E&N!hq zw;&(WM9;>h@Nsy1bgaxOa%MZ0(=3_lELg_mZ6~w)7pY0z!DJ4Nv;DC6WB$b$P^D7j zhRfTl%=GC|WU3s-B0y=J%97v;6aoOpIf|1_AjSwC^u6FFdtu8G?mxwQwZbkH?1WwYcXhh|{i}U?ua}Ny9}Frw6CXiU zx^x|3O51{h!lHbZn`g5-ZFwcm{G1||2R1mPRYsmOe<@~g@Xc>pXv+ehn{(ALmxR4MEG?zX8F`A%v-oclCr2 z8=!-ZmHh^UG7h1a`sB~oh7iP_{0#_CatIOXii%%D(BoU^*)zWZ;TaAgNO1AFw+>qC%x=>dIBpKC*) zUV429axXokzqO_(gb4v0sFz+Jg4|2%^~dhKHU#RW*M}hY(qsBNc^~uBp&JM4rPqfb z_tFpbr=GYr4%ADp4?*swpX#%C%eWE;e=og01i6=frvLfauW=v<)Jv}qLGGnr>X&6* z69Vt0*M}hY(yy>SzcvKwrPqfb_tIwl6EF3IFp;+he=og01i6>~pzm|*wINV1y*>oF zm;R)G>D09$P%phc1i6>CUe%(yYk>ul%g^*;n1YKIV9CM2kaK3Qz*JpgD*|g86K^1e z)((ifu+p@d!2PB9ns{mC7b8~=Un(rfUz!KL062;{u44IMA#lWwWEmR3$SVOl94*R& zoPqz$l>?-WLywg}Rt}rI?7ndW01*x z#h6AMgX+MTb{vd{p5JbEU_7Cf$Mqq|W7;R7EWIa$IROYXrd=O`Jf?jf%G}q6Kx5kV zA;@Fe=}=aGZ3r}`T_1uxrZrzhhwfU?n09>#@|gC||40WK)2tQ=x`VR7XC5q`VizXt?ep01R(G+?fMYpG0k@s9l9aVn09>#@|dO#yRtpV5d34> z^&!Y(T4>mn?V%e2jcM11AdhLi!4T`&qPii_n09>#@|YHT6@#G z869~~CYMj+C-DLK_Gk&y1x->viBW_6QpI;G{-cV&T=9z(zd-R9DL(N^=zY85W8uW( z4=MgU#lK(i?@|0Yia$&7?@;_q#h;=07R8^c_)`==UGXO={zS#URq=08{4~WMtN3FS zKUMLQ6+cPwX)mq|x=npE_a`X+tpR^DPrpU&_eUx5M8zM${qbtqPg5uGcp7$w1UF4R zOz~--Nb#ZE9~bbAN}Tv&x}b6DSniJr_y!(NRr~!RJf5tU{S-AZ{B%JnYT^Uyf|3+J zSxtOwU64ufZ&v)#il3A_m(!z^c%q@UvNq3yQ!o z_GgxNTKTr(#YzhCX-QuDik%o(^jPz7F0HaRLrRj8awYVfk`nCsDND-fn51n`07oWTByH}eW}lWoiV8%4^hWVGkxBc9(QfG#1Y2GPONeE!`1565raFCa*kF~xl42Eh zj)X01tt4zB+eM7|)Dm>-$xhf|Z;U7XQf~paiD53iv%j;UdN{$OQ~A5A<05_b9%+& zoz1!RupMhJk!yI^`_BtuurmVdqpZ2`kavSYA1MphpjM5aHsm{H!4rKLFIl21HOjGBK7JW^HmZ0Jn72G zuKGbLp&xMR!y?U0pcoF7;SD%17qnNUneSteE?7J@=RS9gP-<0);!%!#$ZI@j)IU|K zZ;&OHvfOKk6;?M>7G4$INtN)IM;RN&&P~m+Eq?{?J+2?HjpffTZ%rS@c8q#d2)&Ux z5@#`%sB#mOy#!^Rb+1s`th=~;H!q=IvP$Dd9Y(8Gk$1D;?tw%Tt4uu0zTC!|6TfM_ zzl!BgUDRq#VbzIWvJj6@!E>Sn(Ck+B)6|@Y#VU60m~;N}ZOrk_Q@x=+kw=|Tmsm|XWp<``ATm_;~j6WM@QD5o7T^XEU=3OkDQ zZ9@lB{a7OEH}XdYBmT&8|F~CBUfF%=cK{{Kygcy%yv`G6ahk#CKfNAuQ1)~?#k*cLQe z)E#Y?>RtwvL}rjZH+kPOR!WJg=G7pUsJE69y7!@={P|_~HSbk1YV%uEZa13E7Wq>> zC6n$ckSCE1IK&DPRibsTT>2K3mT3J)f~oILEM+LYQtp4a!H(#;MYU?waDpk9r_xcY z`x84i?ZbKEHW}FSh&_QAJ2$_)_5N2-&9eLPLf)~Q`>cC02=I#WuDw_89rNV(@Qi@H zD#NVe9bJ5dIi`KkYS!`!_s?1YAK;z4P^(pcWs84+ZuNEC>4T~DV zs@bC~DiH{(S(H)T8(G4hRzDA~*Ny51cAduK6}WalShMggGb|U}&04v1 zH47WaKkimkVlFXpMr-Gs7c(1Xs)D(O~r}JO!$I7wB1F zG;|58I7%utKnp=gEHcIh32XT4oMuRL%+J(J){@62YdM}mkg(dS3yz$@@r;_LewV)A z4|1E|A$xz~UepijFX-cZrmlj=RO%D+(KJF-8Z=Cyw@Se05PD-mQC)ogFZ>0aMJ2qC z#J)77`)8T(Vj0*lRrF12CPd4z@#<{=Cd8@lBX5XM&QVei;W4&oKA_x)wmX~+Sc?v8 zWaHMVY1S4h<=0<_xvg;hcL&tRzClaAml@twvsigTm4zg-C5Ksw+<6~5EEtzO;#)` z+$#Ni#O(A@ZybR6VZN%>ltZx?e=M6~EFns61x_JyKFw8vnmkPN@~F5LQx;|fCDts= zYc<(1(!R%pd93=rP!^fRs$s1)GV2Opi&^#LXDBiF8$SOzzNui7=K~6Wy}}6Q{e)7P z<^XvW>Utf2eTIU|V#I<}emn_l$YCmV;8;g9`2~Fxt0o(sKw>UDdk=!>#;xb0u;)Dj z9bHKyLwii*4-{jwBUyF2nL%cXR?m}m0y@-&YZ{-~;W=XoZq7Sezj=sAHrdCn0^<=88Dh8kh+ zM+vK*V5iW)K;-Wx|EYEM|3%xI$46aV{p06;KC@*e%S>jHp@L*IY9K)fpcyM|g#<*! zN?0Tm?GR-PD4Sb+)Yj|?dss?PS`9mb%P3+{w4!KH(Hiy9So}5}s#I{nR7RuS_`c7% zpUFaP`#itppSiDl=Pu`-d+yopx%V@Rj-q+~EIr;mJ^w4&L`T~hgQ^2S03j^xZ&;;; z%~op;n!l{Uo)#`uhmF_r2pHqaBy8CJplfxX`5^Cy`!I(hgnN%~^Gl`BdoCl=7F>h>Mv(7p)u=b@CLZB&aH1}b(pV@c z_g!c{!2dzxEH%DtT1Qdv>)kP^M<-A|#|&(Tivm&c9j7qh?-45Q){saGjFdJea{CsLPPvc;%|8lzsJ82u$) zHV_P#Ra?5LeTDs;Hw;HBnA}@*qPQ*_z#ng2nq9&w)iN$*10cn%R+nbh#B(SX+CdEi z1qkyN`Omyv&;57iI@AO#p%+&UF?Rn~(BN&R zw;9V1ns}0;h41ioY8X{b`A;!+J>I?YU-U^c$m@R6Y~th#=qQf5Kt7eVzJp$nfMb3o z_zYZxr|`jjwg{TF}+V&K=6M?>t4fI>>(qWb7t#awNl8< zuyLW?u(fi+;)Q82R@g?Zd#SnD<6~sC*ZT~Qs*82~SB%cMfk$dKVn%4-JKA$%Mv6?# zNKHUp7CK0VpY=!wn}OgqF3dKxpNvc{w8yN%!62|-gTQ3N8fO`mEXqM&l9-LW;C>N` z#vo0D>0&7wd7}Cm*`j+JdGcQdSvkF^hR$6edN~?YfIh97ft{ka8o7pjP&OI4(!j{G z+UbEFhq91GMiG@2o+4ui%|~)$QBOhvKVxxigv|gaV`#xkQz~v8V^l%~;2h`$4S4S5 zo2jAH!3JYPWSIhq9M`-q^y13+jX$J$;9!Me4MdR;yKyTu(hQ|$QAKT&$bgwuDVt_% z$X4o_w}QJdpRk~ofqWShRrf*_GcN(18RIBaxXOl&u&y)+nz!1CK4DBX@B}m&*YI{S zjEUy?Jcp@Pj>;-0osRi+gUM*_@6nt&m{9^k+2DDx#86-!sc&063tI+-*VEj{gLLB^ z#)iUGWN0PBxWlTc=QqRXga1?CRh-={K?Ar= zH(*|1_VJdgf!I0B=hfZhokeBzDH%VfhG~A59mhw{X1j4gdyTX3=hDu37@{DZnfSU= zaLhi+H7$*TmEgOM%E@kZ5$7so(rQei&*+qFo&%JO<|gzRsiC;3lT4BC0Y4Ha1p-Js z6v)7Aom2>Oj+&rIsAnT}9f7`J#`P5MN72w&j3*;_;hzwwEg&Fl>M77)&+k6yFF^|Q zMbei7XgAr9|0r4v7Y&|6rX5uEplZ|-Pir&MXT~8gfjkO`0@4Ri&wpWg$k@!tG5~xm zQe&3ORHDAKWgv3|$n6jrdyQm>0%NbWkBnL{PGc`swAU*bKhP)oKrp}tN{P;b_S8gy zVf-Jp$bT7a)_*hc-&zU`r?U6`WE?bTT3<3+n5ja9$aw4v;(=N)m5me_VpO&sB6Fbt zZ{Dsv_z#ln2gR_iH>>4PK!Cw3R1xRIme~SIUPb2~P|IWF4r(2x@F0X#dSV1iI;pP{ z$ch#Rp%(~CFw^uj|EMPoR#|+Q$%bW4=1&c?7?^kyv(08bYiF?$zlij5{K>GvFf!f( zx4Ha41uwY2i%`a6anfXQKm|a#{!i6U%Y>q{c{TnmoX;- zcH>CEiCB?fowj(1H9Cg9s;0uP9K}3>v79k@OvIq^Csoy6S9j4+W;#eH)N0y{&oHs^ z! zr=B(7&)8#jST8ea-k8h-)tD64!8=-v8;JSBab*E=wk!YiFszwlRE|AJCLFt1 z4)c5pjXiW(bq<9NeLx2n>;0EwZo{Nev*OSn$XskRfCkMXi>(QnnimPtBB|#8poa+2 zLQ7{FR8`Z0R8px@Ik!oz1h)xSYFLU;6ZYRyJx~!qLh}*olHwe0=K?DM=QB9jq^hJH z8r(}>O?3d`lH!HBCU#?`ab=Tys(V!X)RBG|9-J@$l8KYM-OBscIxp`H@ZX~Ec zdtA)%dQa=+nDJxF^wQvt2OHf;MdPJV_CpO=y80cMj<*`b5H?#@V+V{gs;fmXm{W{; zCWa}RG)l~K8Lcx#e=%?5nzo|rIH98J^awYCyuY9jTgj%edJHsUP4lDYxRd*-<)x{? zMM8B(enMGi8l;}N;Q&Hdr8$rF0_GaAnN=`lX#tiadmgNL$Cu&NdXFu@jK=A-z*%m)mDQffZHMj`X8qbW}e`0!?mt!N>0J{Gm>q@vNrez$yf zCEbV(8$$!_v4#O>9u&w-?NJKe&N)Z+L1?Ob@SiB9<|BsfWnkih+A|xsiGo+ObF1e2Q**xG+0=FU3aBQRBR-I%edpwp=?0t(@Ux_WLxvX+~1(HH^VN z6Yhld`5}~127buU|H1+Qhy$u#yRMF=en8nzQEcTO$ZVmqXqbUui!V7vER^I_sfkmQ zvPutS|3?0!BDgcz=miS)cpGnqv~UbqJsR}M-X_7d@0hBUqYa}08`k_Sa%?He;gH!1 z$oOzbQ)I19_EAG|IW<15Ic*!*g)o78iWe{@*p$V8G$i4sYLNc>U=yN1a@}5KjFVz=F(#YGvbLiip=a6q9S%6Tj0)(x&8wleu3hhn+ z@$3x@yapFX8`vc0rRy9wclwLZn1gPIGb!xG(eS$G7m>Hds6DufY?;tJawxn+9YNwf zsl8OcwK}7U*g2Ko5XEL!r9`DqwqX-^QSVUbHdO3 zR5p`0(CTPesT%NUYzSIm0>g!D;Ady-q8+O6#7y>%Y^Ji*H_0}bqDYWy1V1a;ET=TK zd;u_wDmX>74YP8pF0!=Wq7P}_!L?-j0Ua-Dq}GoNmPfWr!LR$Wo)toF^!Fjr#fXU& zt%>JIUZmmeLIEh!v2`+t_ArHR5z%9NKx}3tCb$&n z1QMH@Q~T@*ZTsIax73Kybkze zK4?(^hJBMlw^}(fgneY&h6Zel;=eWu-7YRRo2D#akR8{y2m~|)%4Ss?S;~e{Ma<#N zuY?&tiEPmIshouk3CFEdw<&dqGYpPB@;?1VUS@5{PTPPkE zcEdD+C1_Gq8fRqrUu+A+O<`L|A;|a9cS>^J?P_1-+}6wrRS{X*T2QGc_H!6iQdrZo zP&c?o8WdDYgDF)#8=#OIOsP^0rSLWH)Y~wsx8dVB=-5KGO0bJ9)X4u~Q}TbC-vP+{879B^)U14F6~svo#QdRIv{e70324Z(kVa z!t$`0Sr0LvgO&iU@uYBQFDwoC$h>jQHQv$5f5RjVn%-Ipm8RC6_W|(P!!^esC7f{` zPa15C+I}PYE|Lo9yS878?JG1`S8>}}&^R%|N9faUfM+E^$+tnq75XW^1|sCr=KPp$ z_d0SDk<+MqT~uP*>u5fmyf9RXXNaLvJcqo0?Ad2WjX^x@dunMc73&TF6OMVdfwV)B zp*FOiPcJI7Ji%^IJAv%)VaFY!(BhsA;LAgEG|*_BE-I?+_Y^aBQ0O6LLbJj&_hFNS zH>vtao!3&LY@eEWOemikM5oAh44#E-n!t{0_kan7qVL)uQ?(@(o0?4pE-J%`0~bOs z@TJT7gD*qSY9FeR{0~g}Focvqor!%rZ8#My7Zcca3b`CA&~^YwgUKfNglr4XUE1!z z4xi?T=f`klAojyOoIA>Vo^e(igK+y$CkMsuu$y|)4p|4g3&;1v*<#oSWg(xJLsW-- zxdrG2?9fkk2MXcSNvt$FbM(uHX^H<9)mTI%Q?d8Arh+4p*WP+L6*Y}Miwns>>>%T4rKPzsc%nI<`#uVP73|Zq9sW>u;aw34Swb_!HKY8`EXt2=5&qZOEBAon%HmE z#9j_!*VqmB#4hxn7#xG)9hw)6lF@@Z{&}bN@NMg1^>~vlM;0gq{N)%DEI;-Nv(b;K zta%*S$6EXozGmdcY0^kg2rsJg)+AI8i{YZM9|{>0kR29Njl!wclbiC!(?IM~E*N*% zK#b4xfdXtNd&GF4_(8H?Cr&5(bqOXu6}nB}LUp9Lg;g9qo`pIY5C7R-U~3mDMNqdKTm-h5_QMeJu_zdh#Hs?)Fn;JeF2inn zmiD{3Gliy|6(4gD<6=H8{f^maQ9z z^N-aS`)Mt2PfM(W{j|DdGDfISjfJ_J@|TK^;t(^}-m*qUFtY$4J9;#-KGV%%FjAJF zAj0a8hUGI}F~ks9?O@SPr}Nq*)CKO8s2_ZHmipd?dY(}d3+T;iNu;iIeGUEt5C|S< zui0<`+}O;sw&3(*CI5$w9zVycm9|!JZy5YANkQzvZSdZ$@2?HitPb{&_oWVm4sjIe zTUzz|v(CM(HNY>qoz3>XE z%JauM_X=`B@?!t-u&*Kq59A4*dks0P7{Unozr&d3Sn__VbI|$x9O^@lqYB$%AKP;$N(5-}3$#Sh7Gn^1vcg6xM2ZlDE) zmw$cv4YJ^lNyv?*3vSR=BIdOqea9qKffIm0KFGA1>BTzQn15tge9&d=`3ivP@WH#6 zm7%88RwNMD1r>0IWhJC2`B}=aqr8Vd(s3L1${ePpha+{tVhKrAjr;WI5NA+^E|`mU zthmTFbj;Ck-bTlvQsvzRIy-!ZF6Gdwien)piI@Y-?$wDzSl@e?QF4jyY>}pN?Sp_$ zR3#Rz1+_*U?+5JE<3=q`108p(Ds5ghGhXgJqffSr9kpx*Cb+O`D09p{&ElPO)@dh@ z<8m1m2;rp)Yhp;9ri07;Vk0k-e$98=zAY9l$A%|rm;kaMN zHlrGDLL?l*?AWCLLrp{-JGNt>A?i=tfjV~SL41y|VRUvWZqO>ww%GlSPgvph0ldoR}t#DC-kaQ(Gatn!d|1O=x7B4VE1a7(ePJ zrui}mVaI-I9FvEA1UGga$G0vBJ(IG1KV)1Bxdu}#^i1}EA;QER&xz;RHyn=Ls)0qN zaO}dVeFM8)&8BTo`I{8Ippo?s3tGqam*CQ4r!VJhjyJ>;<#(Q4J}+n$UXXEtB)&fh6*%63Wael>CO5{!TbMLrBnS~G z&OGycCcfXXRi5zcJ3YeEok@DQ0Ebkt+!9rmpvvH`D$8`0MpVI(@(Ltb6kz+vq)Z#8iDR;_ z#Qt-{6+u^otg46@tDjr}kBhM;&?q&-+Ix@*eF=wVf#pIrc-gM(#j)i0dvE3;4FdU^ zz#x{mPrZ-SaScljaIKvIh1Kj4)V32~si)cB;ArX)Po*NlDlwbmd|(kRex3ps=wUe; zhMNQB4-&9j2b~?4JXr&DVvj+R1fXC+grJuPq!$Ya#Z-sbEqeu)DhU5493p2nMktah6EBl06Gw2Bv-GeV+Uspt zqkWOO)zRflD9l?cB@kMp=OUe4EcD_WsD4>$bkWO&!q1#}IEp@$5*TXXlbee(Rcd16 zbuqHQU^$XROevdz2+(1L&biCn!U)-AZk8OA6jLk5Lpygd3A2!z!2kWoVAan#0(^q~ zicl_ZqR{=SLbkR>d6B8O<|ypq@s6BP0#b0Nxs^LBGGE~T^v-c!t!e-#c84AT5%ZVv z^3Tsb84nrg`fdubHxzdq5JiIK83QdsffIcXIj^@i7kI&&G+?-)5K8X69&Q5>Zu3LG zjpwjTMf}ombapR=9u)1@ISrEQtON$lTSQKGc5!bZjq7_>!9akM_3NW4FAgkP1pb0k z(#68-oHJwuUq)i5#%6Pzs(|agl2?=4l|@GM*)a!1JHqKKv*w^_@FqE9cizNRY&&j2 z#9)xZwbUHR>}Y~{6&c~kxkXo5Y}8jgPtL_yP1f~|3YbaGDr^!c-CLjmE~DU94bq*o zU{q87oI6z?2yf_aXK}KX%3i4M}5rScGe2%seoZC+z)PrQKbJDZBz*7sTga=U821 z^f}us`ZV8S(r84Lakly$ zA;9l8w_y&*>CFXtd1heI0?^Cz2w;I56f4Fu4$A>5uXM+A_VyI)IeRU^-ffkSv**B- z1h$>?^qCW5($M#-g3AqJVt7gL5?rCz*2=+O2RIF{%-!(zWFAm51U;`Yv*P{06N7x$ zlBDt~RJR@~iJjBY7Ke-~3Kmo4 zs|h;}fl@fIM+{w!a(*B=U%hngYf#%_=jQvMc(Sgc6)ays%m_4K4>Gg_7H2*i5?JhZ zb04~P{@xmv+u2&yNW!9yHSynq3$t;6gslQ3+8n?L-j5_C-1%3D(?QpB+m|-hpQPgx z)8oY-!96vWoPQNq*x5KaM?7YeVUrw{@mx0k57ASc^l60o!F|H+;N%m%9Dg;p0zmh0 z^C3z2Kh?(m35b`!Bl3MZxgh^w|H1QI78;8uJrWi}bTVwU?tvn8jb3&n1NftQgg;^` z+2T~22*}`6o0umd;Sog2Wb5%b4r07*KuBW(C)ttlnLE=tvG2^_Ue0QS=~aruHrzi# z;ee2y*jZfIMnvl#XeW8r7!{Xuaz+#zhs3pEr2%|H zNYI-9k?t&;d%*$-g}AbL2lQ+F$TEyrud{^(_{@jT7RYw5v2Nr@bLdjGQ8UPOvGn4* zk`v{rz{cx&!e3Krc)U|ZS9A^K5iVFfTv(;+BIZ4;lxl6%>QkhlD=dYi zio#$7o$;{hLc=@|Cf8U!x*uCDi$e9h4f*_C&&c{uf*f2w#)g&X2EK~p8V@nZIhKZL z-aC!Tk$!+H_hnp@6B3q@>_)5#Q_h>QV_>Tqv3AnXo|bC z2b2J$Yzj4~jFBTK*hKRy5a@j)cK&n`=EA|Cy}G%UXal~1Q+0D~;j{aC7H>h*i1PZ#&H%xFN;zRX;H56vGroL;Y# zKCgI8k^v9nICclU0x^j7+X-`L^z6m~I3&OEAjUH)FoJ8FS}y~!1=bk8-!Qpw7qoul?xo~pEcj!Te78{r z+D*P&O&$3d1@8xGT*kMG=C{v_54u|dSX_rt2<^TI$!Y#?L4^Oqx@QmIGjEB)SFjtQ zd`U0fTq+y6n{YLGe`E?Z+6*&NLaz5EoW%tz`NsY~uulBo365f#zE9PL(*AG(OH_;N zeO>s4ipGA6;1*$Pt`DsF@rv1AdEeZ{YpWwyKHLMyvb?P`k(ks1VFRi5@mhFl>Y#B- z?rRd?Q@N$gzHZQga&mpH2I4X-xXt{?GTSSkLeMU=y+_=cy@SIRS03=rP{~sew6zEH zQm@KB2V~30xfbZDSFd!S%38{wsZky?qfD(|!)oR2OJ)80o<0r$xwBcQxvryi7J_;~ z8l9-Zt4X1eLtHz*6{t;~15}m2A*?73f{&+ZxGz)#C*sh0txDo#7l0UVKBQ2X&4mv| z##4AL7^mF2iH)jP9hfagMQox0Ak4Wgg%b|B4S`UCMF1kSmR>neIdB^ulWvCK141w{ z+m)FLhCA2Xhxvt}L9nLUY`Bk@l;lserhy@b<+O&yIdG8RGwEET29r)2 zWZ2$Da=!UEkC%sbP_y-ZPrAU|BZUS*e@Pm|Tl@5hK~TOTxNT*qX=AxC+J8I+@5AV_ zfu!a%b11i)23hbtB~4QmF@-Bpx|fR?$u>NB7|m@H(r90DZPFEnv3m$5U29b5Aqfkg zNa90eU}=lGgn0q(3UQSmq4{(g_#^7ybt*@MONGnQN{+bMXv;egb}u(7;Dl>27^K4~fv3_BHg zk*i`H7bIBH4lrK7ZDt;0@TVHP+YBc!)ls8j>=sIDN3sWrkXyrfbUd_*8njr#0T*y) zzI7C_6_Y4Q;$Lj5kwd^t(maZdt)~e`!9UTN&aFNw8{xGJ83pzw^EG5gvAMEOpSWEU z5u9;Y@O&)z5iI!aywPoK+ceeP34RUIxKpFYM`&0)1w_Q&RW?5u?cLP1KEwC_+Q{nscKwDJi``kbSu~j8=jv-qUANU~mX$0@n zo$XX9J^nk&|Jl0#^UAPjw~=1msVcz>&Z4O^3+`nu`&&2CL+ucJd@lN3d*u^U0lWBJLPV}X;p}lVmytD{-#Y zLP_7^KPM%9!{e!Pt-gk}PLw3_PnBrjC~gi3?>XHiouE!$?MCx@+tvCeWXiX_-XTaR ztftBP=(M)#aQO~7-!V~?+_vv%kUEDJjLbJ+cCt^-jaxThdG51>t+~^nS>;hk2mibM z!VBCm>Wv}_X9_Sntj-}9Qs}Q;CD70QW+s*E<@wUM}NgkEN{&1T7mnZ+(5j~p_rjdH* zV0f2d(LSutK0W%-)3Y9ZrctQcT7HWdw0u9xVgj0+rkjwIF7(9aQ&mWTvP(aqEA~kfFfIv>%W8M zJVbN*?@&t_KbxC-4)kGHH>4l}AlXLuZhwL^D< z>cDBWuMR#dH+)vQ-7Y<8L}6efT(t{M8JNxw>g3ll!T^_5)2N4*;BFEA;?~m1`Jv?j zIiuYJk!p&5svLTnRvaL1cfo}rUWfb&I9Dz`)w!8&di&B-pZpR+1Z5HKfd6InYZmaow!jri&V(}# zrq=+NUNSKWxOcZ0PM*r6))MOmxPbr$?|#xa3*IgF6Uqd&!lK2N@wV0}Lvo0O&5h?T zMLXu~8g(t;tz+S>fQ|{tWi9G4jq(#B?cHx`>^=wLn?#{?Mjb}?^bw63Hf0SIEcc7% z!@NdsXjtACJ;eP!NMpRs{f2U&3c9XX`DWLN9}d*o>kfXMrRv-3&RcyRmE})5{mC2H z+PFTEf!M8ja=*d;o~q>;+>7DS!POp{C_L_WMd^0Gt08;$%&ubwy4L?40o0dKXqATS z_vj3S@_R7HAv_0T6p+P*<87WkGSIR?hc7=cYkR) zxsbc*^lQk06XzZg4cGk@rZR&<8>~L%P|1B-A4PA$2&?S5r{&;c0y~fxr5uYw^p;7$;FyBuEt*5WK7gXoz2MkVvdjni}IFIgn zuv64D?8cj5F^n8)Yl1onZt6Kt)Dd>PpbF*kf(NoJHUC8eVuoC4wRLwQ3B3#o@JZyn74?zXj zg-}tWA%S`&s_gi?naj=bstc0TaT={Z)U*8|>r0S-vivUXW%MNiF0jO+??y-FkP|m< zAGwkmC?i|3X&rHEK1slghG&ljl0Ms??!!zLs3x zRElQFiZSqNAT^Ji`7OBOzDUDApak<_jprxSJn9nUKy~%Hxq;>h;APTt#K+R6FMxTk zv@oG|ijpV`kV&+2q@RlQ=5h`L?bcJs8etA{9tu?ncS}Bru2})GgrWeEd{XaJ78>In zyBDIt2ny+=HxG^-jWC6D2p$~lW$oAe`S2RqRi4}ay-J^pio>+&VR0LHmdQmmPmN)Yd5k=D3a5`3F1|_QtPX_>t-`#;*GV{p zXBqSm+1l2jE~73ZS2tK=*b#l>;m2LNlrKz$t9b5{N$0J>G{;kDt<^x-y=R^HUp!4l z^(b&f9ju2O^E&tNp1ckZb=BiU#q%pFdmEdC13#hpTN+?h;_@OtALH31hfyit!fiK+ zQoijO%b2%a;pHLT2qK-pE}#>QTd!f+DWb=-UNh=l=5Ta|UizGUiaZ>E)Yst^y{B)> zR+*T(4cm7WOj68mZQtFm8O|4)$kU=<(Bap0oGgT&o#ux0MGhL-7UWXn^_JbOcU!r)GQ75=l|OA-%HYU zvICFvu=*+w_rT!S5BDf}3<#P4xKz1*sqpY4`emVQaEh*{s~r?Q`wO54oz=K8_a7jv z!Se@rr7yDzZOg@I%Jj|@grIBI$nrh_@TM@p_N51sZO}FNp&%seUc}a}$72XMBSOvp zmIj^}u!IJ9ZivlscB9qBueKyt%%}y!#lm%?+}?$9qXJZr%s}8|ayvXH_fiW-0TUauZ`|o#%DvFF3>W&JyO&*ah>4GE_Edo#)e2jI7piU!dmF)&4PfPKLu~xVhXd$+GprZBqU&4bYB#UC9Bo8&09+ay2d44_?5x$#j*!;JbOW3uV(0*ZoNoN@dJDo)5{kLv@%CJow%e$Z5*d0t7u#*4B zZfvyc;l@6^2K4gJZft|z!-JaOituKm0c<=DFUdq9))pp|Jfff;;8&{ni3;0`03wec z!QhKrs3P)#{aJZ^!dwW=Dp80A%gFXSnF{8|kuvn6oTMe=d`z9D(7ik(P>)ne{t28G z9C;*#6F!3Ku-3ZKXs}Bm;jKthLvbPvhoanepoV^i!aY_4_%1AIL7~$ANy*n> zyuVUN+cL>Fa)Z>iO*#UFR|U^PU{_)16jT^|`ky>m0$-AUVys3KRPt1d&uciR_5>c! zgz;$-`qbPT!%Bb-Ps}<#46YQJlU#a+%z?_t_H-*ZpJDP1?c|xLB8BgAp}0Y<8*zO4 z&&N;6^HgmiV)A=gridlxqYY4&UJjThPF1p%-EZ+GtLBCBo>lT_PuKci~L}(b6sSdjKQ>aEGgpFmKDHe)-n_P+i$|>|K z87T8j?I9R${)T5%W9D*#sJZ-XoIWDS!RaHCJaXX_Dt`!0ACW+bdQf)_q2KLwfQ7>6 zx535J^?Ns_mrnTTLiL^ zAxS*i#m2|}H&m1Fd}!%+lP`zCMFfgYrmG4t0o+A&LRvtQAXHF{J3GiLOqP#yQF;7+MS&8|mJ zrDjlDrkJKaf0uB;8@DQ#klbL~mdR!05%jWQ*pJGmw*Y;OAJ?Zc0f;p;(`YE8$zN z(Lxizi`jW$npq5RQ__3Acd?;217zl5>$rl=V|MU4U{j`iPlCsh@a>Y6AOjC3XVk#F zO6iB32Z8f!a|xWNg2yvNc06Z1TUbvi=Szd|R!*`yw*7)sg9YD4^0%_25GpK!dod6 zSreZ>Ne_hMC!CY~`1@eZxSaESaY&_npF%HWXQm96Ma5H!^V`>kQpU>;NGU?DiB=Rb z@RX^;FEVxbMWznF$n@y{l68`zlT@4#AEcCPj2}#U5Q!e|8nc$s^PG?k5{)I1u*mV_ zd*F2}wY{YfVD26PoLK4iGNV{`IP^C$DM|!8K*}%D6B~>mhiWQ)PIAfnthW#o%#lTw z<7$S?<}FNwsQsIp))pqDGxD=8Wnb1LZl)Agbm1XCgv~XFLfV&?a;Up-I^huk-iE2S zf_4qWkTWeYdtwZ_@tRgoPn1yuB{5~8HdHF1U`Ye6>2aIq0P2(q2}n<=z<3KOw9$f$ zy9RwSwW|EYb$uSefSZDElBe8@x&Ql{s-RJ0Dp9(X*$kA7D3YU* zyW-&o@TzAy1%HJE|NRmkbe!ks({%iC(~1eBT3PcdYT9h2)ksL;C{21#2esV{0P&LLHrgiJh4Eqf>30 z=)~KFr&=~6x%^ZUUVwl5s#E1#sR7SPlx%~d6p2S?(uqjjt2-*`MElZL4^<&q`Rd2j zbi94dYt9s!mWa|6n(#v46;NwaE3Ql>Nx{kH1%sUAz&xl)4C~ zY~nIu{ZnWuxRvIjFa>5H>ryD>WUD#|`>zD^`$<8(;Ky|0cbCSeT!Z9C@jJ%T@!u83 z*B6T)Gv$~(vWmqKf<7jG)0AWAx-VFXjL_0$-@-JZM{o)S!#3p|ZPD)6rmVJXQr^|p z?tUb4;?RrAG0iV1bAaV`g}-(D>Cb;Jj@FdlQ$zlET6_UD=8sp84-jAM=SPJ!EMIKO zQOg%=xoe@Do+7}Bt489(g(9)~JTct63?uDhSuficg={pXd?xer=)x3uzP`&N$Qy4p z#965ccONzadjzdsa2m+AuXsaKzD8~wZxR+~E57YLIts@dDSs2oEv4(cLtAcgc|R2o zYPL_JR0IC`>O?P(8W`4NOenOR4>BxV9}H5Ldqd`snxyWFIYK^?Dyb>zdn1QPFW3mM zi0*5zk1ud>pJL;TqBo1`dOi8W4`+(TofYIA~;WAE1YIS|kX8 z{nV&L;`|USXg7s+NzSuK980PF#j%vy{|v{HiyI{DRGEVpzBNq6d%1$PmXwdnMK9oK z$^j_6EUQD48|>-h+Fvjibe4KP{sS$olXgLzexP~qVVyjp6U|hEaEmbM@0G%k)*P`o z%!P4t?~;*ohz6*BoD7sI#ZV`?vmH9wsgs9v(lr7+o*ZoHc;Q1z9RcyOgHnH_QGS`^ zR$hh%exsC-WIIb0)XBekN_iQfHJdtt8CY6m5809QwdLP{Bxn?u%73nNu`R$SY7<)`3CpS=yE}T|7I2=i9a;6;(Qi~Hg7Oklh(Pupq1N+$r zPqF^Pv43FU$)BJXv3j)1Xr2S~q(&$fx+*>(9iCtiv_8L0osCEI4pHh1yzcQJ3c=)X zfoPffWn^$dB&W_+e3QKUzX#+$OB)r#Z{^M6TXUTw$a?e^3{+18&atWp3I?2`o`riD z;BLU3Nlr%QvBEPCzOKQyNR@^}1EUJDwyB4q9<0K{d}6A*tZ?zo;H^uuOE#fFmUEG& zC1I6WW-BX7S-#>KV5%mivNIqnEqWsqrKR!W8>w+J9x&TZH{n|Bf(_brwFP`PHU2I* zJCZxV^`{M?f@L)K$Ph}cN6yK)n~$W%2Uj773*}p>5nY$VaR$xmQGJ!FfN26T-9<=D z%2|TT${ts$zA2ca&#qH9aAAOxK{>9}b)2)MZV-JJPf0bos3hGrpP@X|J(=Y&p-cHY;v+N$7;cgNGD5F0MT=$O;-la!p|0jGNhHiI2=Xk62 z#5Htb)i?_XkpMt;JvKrm2HC*)Mtmf#yvNvZ_9;qzRhk1m{E(w}29inqOuOD4LJZz4 zB-k<`BpBfw*cQm0ZB!uGG8MN0vEzu?l!fN64RClQKKuv2n9R=;!yYSp@e~qm@FRC1 zD22P>+0(WfzBItn@MOE;d}%GEBGLk9kulUna`KNzN+|U>-SpC|sz*=Aq!FbqRL(P6 z>%d+qdmn`PC!_Lx5BJFi0A@QMN4(d3WYnWi2I7HnNaXqiV5x*NJoOv+*};BKBGPFR zr6ma_d=qps5#}7oZIa|B6ssk2V2|9#eXT%71Wm@)G;BLF_}+ZGK;R9q#D-Ebi=) zNNvUI4uIt5;2qR-dB>V-unuVvyd?cRrKO4}`1ll<@#(DNse-e#QqjcWCKS{$g8&oI zCRCWY1~w2J!q~-WVk5w=GE6LZ8djQ<2)-8NJ^&N{_)Fl|TfuEk#+$YpHT)km7HqDx zJUtL{?e#Py3qlcSjUd7lRfdClxE*RbX$X#+!BK{sC&PxJ4|4MXbaVTf*2e~*W{^i< zknkTr);J^&Rr*qzzKNVR82TWtp6}=XIu}M{TL3_A{>9~J4lKdq<95TWUNmHv8wSI2 zwZTuCpn(MvbGPt*=#gJg+V_RKg`wA}g%qs7RDh7n)FoC9H$Bq|p|=9E{kl&pSApPh zqcseU89ABKvLEUsI=fsL5@0!wTz3O@+ofFzj=LNiI5%v8B9C4^`T*e&YgNwKaAXN5D*I(Q zrTv5!tX&Xa7%{g;m|if@Msn8D3IBrloKtihRa^;rL0Bg5Q~}TnqZhseUpCDRji9ud ztiL1zSkh)A$3e?dlegNa97?-g_Iny`1JVw94AD$T-b7NdL!~XyP{SX>&r(akHjTg8 z;BS7VEfPw`H@}#mlV6g}6}U?hJQ>JajXwjyNhj8py<4Klr`;nfZMn4?;npghWb?9H z3+mQ%jpPdCz`?GULa9>JT}29$GbE`9;hnGN$(x4r)Hlh87+p--H<1=({Wfx{XS0fg0U7aNW=cq ztOP&|`5w48vy05t!V)sUp+|ctb1jlI%EY!upMS;(oLD?7!7kLprS}?*`uikl4?s)! zfXv5{{DI6TG@Sp!-aI;b=09%sQS7C;>h*NSgfSH1#$$@uc~k~OrtK2+coUyX)7<7! zGaXBnhIsauODOHBF5nTc?E}l3HV%9c$$0V^Nbm}?RttM8o-~`GPV-t&?-QsQ^MD$d zFB>zK(w-OW)`LueU014T3Bu2?#65X(FGPZ9i$RJ-l=c!Vw+|`pWkCV-EPT`>d&nWx zL&Hte($I3d0wnm|U`Aj@GpOe`WV*52N+(9We@7VR_zVB%j*^Yw&&!$Et`;0?hd4 zN8^iO#y9UKUqAS-cg3?2N4?_Fc+pLmLl&<}!{}^o*El+x+P0$5!=p2WfQP_-&j#~2 z&T66llto$x9UbkCFNTPGDK);@1iQciR|7a-Hl-cIV`@44y&hJ<(~hyU&~rCwWQb1W zUoM?Ruj0=5Q*mjhftT?t|M;_K3ps~%7^#z=!r$ZYz@OX-4z~Crb+moy1*HZxj) zJ~;;rI?4MZQ0p=r>N0v%n^k25=WyXu!_o?IRs%PT9s!?$fDgi3WEhwjk_t)mW1{$2 z+vIePveeq4Ttf7Ym0o;0dJ1kk{bpmL3Ngd|36<^sf|FQe3x#(=Q*E}l{)D1~g|3A; z4umTn5|3$c%jpg zZ#%v}&4jU~_Dz$hKsF;>z{?aT;a+5Piicd6AW0+F_mTL?bt%QBq{puq0Y-+J7pY4k z%Wx|b^5Khw#sbLr<$v!i47;WkvOgAa#9?}MuwdUJNjVpaUXChp&OuWxo`tTB_%GnC z*S5?8?6K$^?&Uz+=EUcPVxc4PD*#~V16FbPzs?^2wa2dr)BB-6PE63=OCv)Ru7dHa`Ucs+zZ-)>SoBQl;9IW zXzu-m&>+aPEBODr`s{Akf_Cqr-Gf#;aZgz}(C)wKMH2)3S?`^H&XF4bR73dd`ET7KmM;1ir!EdpAggU zRsInP@W~1A$qDeu3BqwX3F@S;PVj^g3IP%*gkg!kETfliRcqSU8lXW9HG@k4m%qp* zz5Fjnh^fo*jR5Io=>Owh@EjckW&$Lme&j*&{vQ^*9o~E#;33zJ{eB3{(Sll6fp3(# z%}|^baLulDpdG47U(fP>t6AkIIsw1d`yFbiTL0e(6u`)a7fy83#xHcuzb0x5r~ND2 z=v>9ZSwk$9b9`48(l<(Z-E2J{KOo}B1~$7`A_4M5QUKU}U&jLu>Z_kox& z!V+1F!=gLiT-?Fn|I6R;>aMSYhT{C!`10TYh|@|mLO*ZnmtS^VW%vkkhZkhI4qgwZuSEf_Lo0a#qr1q7n-eItw- zT#EONL6x**u=LodUo7&@G6+%szRQqn!j~}kzZ9(P0>n!VEuy2-jDZCe6g%Ri%u1Pb z*YUm8H8g4%sFet4hIYs+=CsK^vJN&Oo$wq_JLX<08(oahnnBRS^@Fw|+h<6K@*iGc0iodVD`Ffdslax^!KNu9 z8NEc&OQs#2xeu&&SmOz|!GFgijt&@_^Kc;Q!`E=9X2zeg)7Vz=4S>OZ22`K;E1KLh6}Iv0zuTF+cDu$VP0nE&$=QmuVi?^P7u_ z`S`WBRitKht-F0Af8m9j`^I4Ojihcwf{zg1fWkBi)*^9Iuo?*zo*KQV%k}!L=$;Ecx<&s#%+|lmkkHr z+L|lE3HUtuel6TazKp$xe0T;F>zDerAQ>Jre%Q_TYoi8H_&!7wz#KqQg`2FL;8v~g zSv=kbVn-F816RR#Ps$vy@htWWzKb9@IGxb$6>&ZwQQZ6$rM(pvgGY{8Q12YR%bm?{ zFXGdzxI8S7c|V5UdWd{@1{4p;`C7pXF#1QDG~PmPA#!@4cjOrg-$$UOakj@LaahUF zk022^JWtpBodllwj_?Tw$Lwjy41Uy(p9}83rR+Us)HCq7vjw~$=iH4`CRxT6majwGc;QZ|8d)(=LD(W;e$gg6=0g!@JrnVNYO}g;@f})P zjFgWy`@Z2P=SoW8G@Q|SHue~Qe{%vC&W>O8jC`1R@n4XeL%Dl2ET?JyOLNo&4gLuD?B#PDaI;g_M4seEuWdfQ~7j|ESli$@dNYuc{j45JONSi(~L7ztg`bU8e{6 zgVnSKcM9w3|NoJ8p!h!~cmJ;pu~b>)M&a5GP>W2+vy|pNPBo@< z4jJx0i@<^&cW1{z~HK(y(Iw8#Ul!BO(yWz^pRzx7qCiUuOlTw`Jqh^W(b z%N0yS*S-c`z?ito!UTYSkaA%$$U zA9E;cBK$UEfX_DQOS7hR!j~R7IXL%mO<=cn*R0Q)xEM9-d)FM4`#6S`D4H6Khy75i zw*{!2BY{|(!DEfQ`_u1MYRqFmkM8;&C`hp`cU&0SAhqeHlm z`=_p_J@IQWap??nZG3r1rR>JUHmOujp#Ja982UU4=rtwh^TCc91tuOrtdhCh!4Y%adJ< z`%b)zzc7r4b10o(UFVv(GXP@8^UJ))j(|Z7L5}JAhH`KQ2);FlFCR3V;fzI=+|UA9 z1z+XFlLkTBqg`!}@$ki4AsZPe{Y%UbJM}Gvt<5aY$-EV}&}3NVU^MJoPSls*8nw(( zzTupijzX}YwI+)Yw9~yj&4s2PPV~HNLK4M~8$o_~_mW$S7r&8c*AHasKA_vZ0#Uc0 z{1BKJ-R}?v@Au-rHl7if__clU-%l?bi;!i;T3Ca4K_SoLpZ#d3I36fpGIP>+ zXxsJ~hx>y=<0|+kTv+O#2sn8)6TF-;4?_j8xYkaAcv%_GeH8m$q;_v{7R}wwsEg+A zkp@h(b3~N;=YXVuR@p#PZ=Hc{AtUg+F@Ei+b3d!`0tYm>4H}f?eauM|3HO=zsq~4h z?Oy~~phzrY0HHF1CL}J8RmMq+ct#AobiGLL;zZZj+C#{HyJ){iY-2zZw@aw5|8^+P z+|H;3FYvE0>IMZ_PS-swNkzr;oU4L<#tHT&s#NlSD~t-ARC0qAMwL$3{NNn_SBE!& zq!&O#59g&2s5dU&03y*P9$vbs9t72k8!4Z;S(ePaT z5Gx@5eY&$f-__Yuy*g__u1ibzAGC&LV)z$x|2N%X>scaf-qFb`Iys;dd}X0jO`rGI-avrL z74O>~26147Q4N+Jz*iYXys*IZEV@n-oQMeq#b<2z=3|S()v^F)5*F^S8p&ct7`~tC z|04MBCj6({eW5Xb;=3^aSuf0gZebq5P^lMAn5Vn`>wjK=&VNIEe>r3B=sIr#wCzy{ za2$^X*iQikhQzWFI2#fKv*M$^c~5E#J}N8be+^q^?({a%HRvJ_I7%Bd0bK?66v0sf zCfQ#=OSILESDAYBxdYX@cvwMu=cQO9*4?au)Czr6D_FX$C%ptlat=#u zRD!Vtrs(EZ2@PH}rke)4tnz@qR$^J@0e(BWi?Iae0a;x03}j(9Ccgd|nE0=WFMw!+ zf8uWys#F_-$w|nF^G2uZjUm} z*K54M@Jn$0F1JXaw%2%d)_58(+y66Nul^sncasGJdTjY0B*m=3RBjd7AIxkG(MJym;aH2 zauPT#!H=j?wtGAmvICQI%<`TTF4YERm3x0@_-Vrq#U=2xQ88!)1@`GGPt&}}vB~kL zq2#wv#y}jWpQemq@P{2j4%`h|Gc>aH+H3J2YjPODhW`S`MU)4Qivk&V15X=bQ4iwq z1jD{01|0s2=83Ol!R~qSi{8*wfCliX1`g}d-=KNz82vaW(c*a29GDgW7;h!A`IhTYl-{>!q zvJBu4l9uIuL4p6nN-%#*3suafDxuwsBneNzL)1OLHhNNb_FMRxzo1+^!GWN(^6eTH zD4tNBlhe4+{LHH<>syii0gg_|?s>N}@+QBAUBT<{mBz$ZK=KD%DBI#oaZ(1p(!HD# zCnajmjQ}Bd1}1WBO6x}qE-r&w;99U)!@|ZJ%O8H{Q#J%~$YElZ(%-@1xif+B87+T< zvYjIl^n%+&WM$Z_b(bXuA}h28U-9B9%E&boRLu;znFwuLkM|Ikf1KlDuTcxC%Lrl} z!a^^*PR1_|3Y=k_ljMz%LVS1N;&h`j?;XmJXc$$l18s0lB8P%w)Z6Xu=6o37-A{67 zAPf|gmEo1nN^}E0mBsuN4l^d>I5vj3Lk}%FYRw2}J;jvF3NlET4S=StFk4nn{%W8^ zD2BJf;**?UsZyqrQIM#~L5!%<>pwXG$hZ)8I4fp}24#73uvfr5W?h&24y=irC7U$z27j2mXm{$|yn(?U3W80(x?nu|*`B&K}`59#iNn<7#2Q7ms7kcgB~oGk((3 zD##eG{*zUZG38$~IR>z&Y)k;pzVwV)8kQLrOBaTlfs60mdU?hT7W6PAZEq@o$=3Pe_IDtbF6#BgO+FGn1jAew?<~cbc`FNf?zU##V3CECI`XV*v zd1%)QXy*h2v^o=WHDi?=4rQzo)ZzLrj8_c{yK6=Hvc5-)mj^T{%2KhBtvQ1YTquPgAyc|vaB%b{Y6wfcn+@Bb|b`VD2Z8SVQf-?5$Re2US^JkX-;#u%d6g~-u z4gV*?CWAMSKQp*T@7v|bdCqRz4ka<=hQm6tI0IdSYxp1In*B=fUo5HnKk!I}oNmsJ zmy)!m?G#J>GJY_D5bF&a{AW_}QgA*eW#IB@dp%vuK{zHwb>YQ_01_@*=)%UOu(>!# zu~K)u)oS;q(qEyIUM`kgvv;XVLQUXvRb;78Mp#A}Z{j8QRL)s?fmA{4)-*@FX&Vl- z*CT<5#0YJA*fyZ`3s(udmHE=6$^?L50vyv_&R0t7jW+m0+L>zz)c8D9Y6Q*OB?py* z`-DG>n}^Y0RLkkk?YP@n&v8gxSdM_v_PUgou3qkfSEU@@J0vCWv|%9hS+Ho)ZPK{phZ>*d&=u9*aS_*DMyQktUUF|qV zux(REX%LsVNZC`1o_4>VPJ>Rs0LNa}c z_ap1D5t4r{G=c9MUXNU+LGO>;r~oG-3XJdu+KHFM$~WNsvq{Xap~7*LNdw*o!#({4 z%_~o3`rr$IBeO3xqDsjYoXtDpcPJSMg=Oe$ zeGUf?pr)*QCh7mO_4*|c$tnOoX@}3n93}*5T3@!~uecNp0S)pOi)jHqa2N6;G|?lx zfUQ=HCtuH!{|YX`f8Y}ggdfo&dORDFzFBQgDWmleuRA}7oIi_V7^qc)6x7CfFrg(V z>$}yBxE|TW=&4sNdoj(oJEmNRe9FW-gAycTme`3qol)lEfbglXnc!BVKGZ^!SLfc^e91gE3{FYZj78p|@RNuV0{5;oHXxTdQWn*E>>W97PJU_UXg8{WiOgBx`m98$ zeYwNp1vU5vm!C3g@%=whrK80=L_SQze+xiv^0mqad=E1d79W-a?eurHSVZzShcwr~ za@;C?;$zR~)6t43A&8e^5ihN!jsr~y9YR=9+g|17HDdC9FCN|t6r^#OWF`;^t*h*P zz*3#~787&6%>SYWH9}=p=(*#;P!!&A4>hY1vF<|bm83;CQp02uHF49$%$J8$5&NS< zl`<`wsMftS0G5>pu$l{ASb3nJ0c5)JK>iE_{Q%`mDEu@tNO22C`;<-fn_t88j4D%b zx^u)Ge`<>c7oL;$x{iV^YAORS8#bklmGw6A-iU(-qdD__OtY>v3=Ik2-z-OSe(-e* zgd4Wg7VI&3CyIk7 zG6#h60C?{VJwMI~lFN>SDHCQOZ~GM>%(}Op+L_2%?4IQc7Pb4aqohWx3L&tUcSnio z<%Cx*Gg3o#w zrTc3o{Ls@9`N~Nb*JpOmaxCa92L}T$$7_UE+%_9&7*7f%8rux_vL?Jo69Zw=_)lsg zC={O3j&LP3e@=AaQLGVAfWy7fb37%Rpq0#y7l?1v*WC`vdUpev3icR}jy`++Cn|WN z7dca8$eK%k9xv${4+A-ytbyX(nXja)Ggx)q16h!96?acqj2>0k*%7unJKY-=Zs+Rm zdTHsuXcu;>rKPF8`*c`y2+Nx!$t?*0jf!?~o3AXWS=H>G7#C7_i>T+pOtF1~=L!`B zgJSyz&y^}rRdn18=e}DZ51#u!QOLiOGM=r2s#O^7QD{0! zSQCdwf)zSHuAFF)*nXD)Tnj*ma^7(|hiT4+P!!q?UkRvJVI4FO#oU=0 zfp$(-XCW6RfavV%%#t!Xk*hJm=>khjqB%HNkMLjl52Fh#U4gBFWgeA7ZQi8Y1f8j;S%j}7d==t?#O?9`a{H{WU5pe0z-gFzlHSIhe zm?|!Bl;s_!;9an}P6;2x=`rBE3D2E`?}8@aV1qwV6OW|^mum99SCjWrJy3-v@1+v7 z9E4SXn&E~s9#Y+@A5x7*8oq5w;956diq~f@`L>M-tmfP3HP(1~pq0G_T4fECcvwnv zOr8;5GXQh+^BgRc!za$KF7SP|pxlN?wrqsPJEQ^b5X&0zA-S2{v_L3SV6C@;%@BqfEd-N83|cWwH6bVa6RS&04mx&VBU0{&XiU;U|xS6P-)u( z=6kLK{##21X{ausLHLZZhGw<)Q@r&RxU_Cm=4yj6!X`k;0579{2)JJO2)tP(|b3gU;#f& zF9CiG|DGSv>t*}|L)Zh_-x9~DAp95p{q|vriwTr#rJV|XXn>y}Tq`I9yvpD2p)(qe zau&u%P_7`I(RlpTdK7$upIb$_s30Gs!=S!KhrxP+VNm{HyZ-Wu9{uzgA29}N7Yn~n zFTr*Uw$s>Ab{2#O`S^GCH2#V`DfKA!6eIkf*XwUM*hhd5fB(3e2E3Q)dvth90PgQ! z%#Qr>2g@_Aj!dv_X5shg0p%@>?&$haj{;|g%U-X9Qyza2?zFdu1* zV9IU5CHa%{C!1SyvsbOSW7!R>+uB!T-I3?aS6IS(SbJk|iCj%i8Z+lHIyuN%pdi#o4RxZfn0Qd-bZNt*h5$FTJyM z)tc-@YZg1~YZt9*Z?oT>y?n*uWp}hMU!0BL7DU83OIEFJU$MMUoR*V6C1-j;&J?p~ zS~azxU|Q}Jv3OpFSX^IRC@!8pxpn$tbE{a=x@JkCSiNGom}kx{$TsI^Pd1C@{KDKR zg;S=BbtR4B?8PhEmN2q~Vy-!Va!y{Zd73EAEiVzxx!HLIlb0@TTQr?~LrUiOL9J5? zmQJ3!bjkN9@Bat=KcWF^RjqXfYHIqkWeYQRE>J6j{c|iKpIDYDqa*|88DR7XGksq^ z#nQ!9)nZ9eV-X?v$S#?llWWeIJe_4+d2(~|rsw1blSe{PX4xI(cXX^+wFVZFGkI#x z-wILxPVPRqE>FGJ? zGt-x+-<5uU`a|hYrT;u9XX@0cGpF7^bLP^eOP4Rbf9XR@pIZK-<@Yat=>Gfff9j!! z9((Muryl$HQ%@C@(xQ4=)JThFbJkL7Eu+>NT3o~x+i3ATT0EbYl=3B&w6v6#Hc+XY zO7*nNO3Ui04gY7;@)A{fDJ^fH<&CtWj<2j2D(BLwa$40$t7g-xIkdWnRyWe>CR$TP zYiem-6|HNeb@OO_Ev=ueYAB@*<+P!aHr8tz=W??fk|^=f6prv!l&|8bRfm~S0cdQ5 z781Th%~xn?MJQhq#$V0kEF3N1f~YE>vf>(Q(_KSBV8uaF!xvtms%j>54&i^KAy5A8oo*gB0MMfXe_RFR0(KhJ`klGIExifmq2(T&{!3xV$}*%((zRh{M0Dw z2NU%SrDltkH%HK{2p;R%Kn`!=d5enX=y^X~!dp1vM+%mmNqDQkxSpxwtr2`CD~ozn z9M>rDH7d&V6Uz~Y@PLo3HYNUl;Z`JTB8jK z4TD-ZUaJd_h}1_#$7q9KN@*w!qdFQ+@in4cC>O@*_>j=hurQrY7p{v4508jQ%}Fz- zS<=>|ZBOe?+mp68&6z(V-;#fC{`UOt{JjMhJZ*T^v~6$eZrf|`v~RcX-MoEs_vXEi zKKkgMNB2JJe02EmqX*Z_*^a_mnPCNG>JE)=W-}!L}1LN>C{YfOU%wW)h2r^>~!%@@5SQuqvBy14*lomt=VK_rj zbI5JXB|Ha&#)+)GIBP7ino-?U95J9g*Bndg7zWU*Pz%df*a4veq$${;)EvR+vlwc= z8Uy_V(xH@&A!~rG0=6`k6sD4rbcKISemJqllad6IpG0PkB{n0e0G?2Y-yynz)J-OJ z`Gg9E3X(0I)MXGs4H_k5Ndai2k&;YO0)f?F05r@BjS8cp4^~&rSYlD|Y9$Y_i;ZEiSiiRY3^Q#DsAi^84OFYNgmo;L zkxHyVohK?fzoJ#>tSNx_?}%_S42lF?K_b(qn(Hw5HP(?xI?y7VC7M_mBj#vgjv+IW z$qd#y<|u-nYY;f53sla5F~*X5W(=7>meh?W^E1etY;so~bW;&Q79|jC5~&zV7NwHA zOw0mshDDoVuZbzNnDGQ?sX1FLv1Os$ShcXy%+64N%M4JPIVyd9ZLmy%LC{!Piir#00;-!aKA`b9(wM`n zR8N}H0=zL<7#7naE1SzW8^d~oA~%aM4Je$M{1(1u+^Bw}Fvm1YnQCZ0>rt#b(7Nkl z>=aq)C3O)*$*E#E=r3woWk#&z3I)&t7c7@q2CZRKYY^iLjI2+v#uTnIW4^#Z3e(9< zmXV{_UO}?b^SBa}0F*<^f+|NF&E)?r6E>Tz#|Ww_!d0ocs!*;fjI-)6=FTLcTi1tD}&R5?n3Pl9CWIgVkZdd`B^- z3Yf_dvte<^V6ZfFJ1v(L&Sl}7Uw9KC`6_}hs{)kga`1@*&VrAT;ybQ+Twk!LNxqJ? zvw$@Q=E?sg*2$_0RthU%C6r2Wqe9>u_#Xu}9LgF~VT9IQ;joFtW-#(?tXPvmis>jH zI>MyPSwgr1aLeU@TMa2G_0Kt%G4WK?5rV0Qd;H*Cgc;Hzcj37LPyx^k)9W04RF5dr% zhw*+8d}8KRWE4&t( zsF;{opcWAggXqmxLLx{M(VL5jMjfsq`l4b#vc9NwT6i3ff}QF5+YJC ztBhze)HeW9PSlaAXcVtPmV#4FG^%i@rKpBzBGgg9sSQ+GG%Hv|J<*I&j{#0SRd7gA zLy%5mkWM4jOi-tx_-qoJnFtfWx+69-AsdmoM3bt<7xor41qsd%)MbT$3L91{(Zq)* z5WN-Roq}p%|Fxww*O zvcmH~84agVt3eqJr$|~{LlSb6rT_vd!qs6!EUpW1SPUs5)cCEN;@Mz6!q;mqo)auJ zH;B`O_DaYBWhMnP3GAx^wL=^~WPSjGKJABK*X744fu0o;EdhrLGInEuEO4l3qa>hS zeF+Gv)B+K)IMwLX;fTPV6{{-^QpQfsU%ZqVZ5(<_Db%9ad@00H>MCsr)P+4?06AcX zL}D6aQeZFW&yv7lCVqZJFEI|8ZAd{&kieLtc?p#LrC{NTv6V5)WXNT(OeG83%0L!c zkl6+)V?48lD`QQGN=aFuDfMNnDV40CL6!yWuq@bcWw1j(PF=A0EI&kF7UTyT*+8WY zf%Yncq!Bs{1!c4SV*)9I9r{^C3+9ARC3;&WiJg=P4sF$eQa03eL--E>2~x)X*iYF8 zf~*v=!AKNIv2XTgl|xcCq!4VQHPa%Bh`v17OxRTiaA1&1o0bRVDz70*w-U<(>eZJA zH>s5x_Dp)TYPQ@y8G^L8FKnEf4f+%_>Rh1-WQar4s z3av8c5tPZNK8meR6L99j# z=CO&Rx-KxzS2L?)y|OxB^Q4-|#d>9RP%ij>{5)3&<*J4_q3Tc&gu)foRYT9r!U?=Y z{#mAap5MYrH59H7k0AOQNa~L;0U3uiK^v=qT$wt|gEf#VDI$rOYtRJBpjQ)|h2ebi zvr)sk3{wkyQ2|IDi3y3v+M$L?p-={^5wK@{4Qf{=samEDR;sRu;AUbXBB))dqAobg z)S-5Ku?``10fQ9lpw&DbeiFAX$OgP${z~hD>aD8@G(lZ`V6>?V3`C?Zs6#l+0;Qla z#m4H`K*ZVtjx@jV!$HVtIhZKigk&5^Mg$tmi9G2%4-9(d2F27xA~wL(mD!;IO`sT30~@~BXwwk1G5GWRlpD%OOjdjzN(F7K zAvkfs;TOQE2*}&Nh`;$x|*gZ7{S)C2dD~&Q6{IJnRoLwC- z60Gr6qJZOO?7?)}P_#Q-r-GKU$UMwV2^ei=2kFcK9i^Ynfyj#e%t3px^(vXeBxPNA zPI-Vber(C#8Rx(xCWYtXYj~Mj!ts5Xb73u$bbvHrzZ;A77ir23&}qsealD!XWHKW- zo`_hXYj`#(G+}9-phW5koyy+?9Q>TI5JrL1NEGHpc+o;8XeIzMhlFWEu*Pn}_ot5^ zV??BhgtE1t*aVwb44`Q~iC}6G=jDQDMD+7u^Zp2Y>HY}h_eZd9^G7g?_#@MT5hy`1 z<9UIOM&<>qh0M<2lxQscgAgLjFH;IQfr~C6Q%O2wCfuJjE|66- zmReG2NgA!0M3WTSDJF1~Ksz8Y=i{Q_sU=)t46AD_>PmtC&XGiuI7H#VbBv*(9QVEY z8>Lt4SUMw>=`9vi6Jm{58`KOO5&$5Jhv`^b+4IRzu0s;N(ih>nPfO~xlf;P<2E7&;@F&M+&@ z>=zn}LtVO{zVZk>e{}v>S~s4~&!BU%>0Nm=-mfyoW;`6#Xp2Nd6G24{)v;y+l^MA- z8hEj>@NdK8M{QZxmy3s_vGIhPi55?%dI%dEYhbL#(vEa0uojL6)#yOuE9Rz{OdR#` zkZM9o4v^z$V-9OVKoTbc2Y$HG$*8Lh4ALf=3esa4X08&2g5fMvG%z*>@POfu!h(CA zR^?J7%EDO>-y0pr?8L~Lr^LuqmcmqKOhmsRaJf;~9e@S~Gz5SKT9{5}`iYDMkw!Dj zAA5A-fWP2h{P#?I@WDjTNZv3p7Y7En*F6EEVr=U%aFZ-(<=)5RQ6zErnMb<=M;F@kJ7{2y3(s(ndM~Vefth z_xXTw1KG}4_5e#CMIC;)ujj~-BQ05?ata1?q6bY3ayS%AOk74=SXm#Mn{))?*l&oJ3B(QH)DeikfjRBoK-`RlSsm}EsRy0LKs*HS=3pFZY6-+6u^wm( z#8rSV3&bOUza|Jr+!2WD;aaoMtMp3(aYnx?7zdrYK%CLX$+03Mqu)%S0UK`P`9Z9j zmS8sGZGkwe#vKr8r3f!0(E9Ld+4xU7&iIPlmZBT2YI~1J4!Xz#mTx z#G!%Wu|_4^5Cm0S&rMnY&Wc_uM1GJQ;04#<)CJozjK7Ecfku?z!jC zRQ_hHDlM`WTV~vN0kEgN>&$W5}Ho9%`Ew{AIZK$tr_}9F9S1w<^vUOo| z^TJViXus_n*00~N!hY+m_R)FJzzyS!WW0~ltQXY(ZQYQKZ2#JC6w6jjSg}>bC>66) z>ivAQu5sh#Y_~+?6R2wS7sYY<-i}4Es z7>g(36jV9U*CHlwxm4EEY<)ZiP--DBZRV z^G6${+qbhc$36HUOLN>q58*V-&T%_-U~&N z7fg$5c>W*%zIO;9JFMv(}fgvXMwIuhDOLdFyAcx>-+q(szlL={6+ z@kEFrLOKy}_!(&CUhL3 z__qD83B8HZ9hCl&(nxlhiLU49&pG->wg$j|#v=J2VDZ0$H(oOd95OC({)uyE7UD#f z8wvXi8W=m?NJb3wGrSCR5$ja;sx)ans>M}WE!H`N9}>K(OKOj1bUKnZagNya^9img z;kyWVlJer@F{(e3&d^6#C0K$z%|iB|H4|fuq#NOHQbm^5eVh!Fq1exdhO%rM7Q_@` z+GKxNqf*e++7yI9&>k_dh(hYi35fDk{cfH}G9wV#kHQ`X`C_6-IyE4(D<3EVuM>$# zVq=q*hGOBY;zcsnROj>Egy=Zk+iXo3pJqf)d!^v@P!*PMn!o3fBm3Um>-o|N6jlUpOvN$?m0;RgtN@bIV19vazymUfCZUrrdi#|vSLXG%q)2V^Zu%Sh-0F&aP%z!{J{}5 zX%+nNk3Q$fF~GtR4&(jZ7yeb?@Hv0D?L0?r?dQnAS$~>wKm+gf-2C6A+LYpNhdmR0 zUqa2;r766zY`ioqJ1-W-y9DfdL)bCWyrbEjOG^3$o( zv5n%}w(PWAvdk*lU!=C) zY&~Sv7B48?Up!P?QSw;H-%7Ge?wzOsc%O^5M!~R(@BRUNxuc{;Joi{!tZET~xiI`pN3|sxMWG zHI+4Y)$FeMZOx^cm&dt*&lz-MqT>b$jc6TlaNc%&dZ0&9gdZJu~aw zS?6cz>T~Mr>Q~kOxc+ecpX%lMgobGia~tk%c&y>I253Mt(MV1=Txy7E%x$b|T;907 z@rA};H-6SgXQ#|AoIQ8;>e)MHzcl;Tv;RJOWcHXj`EzRL+%{+PoTujW%sDyd%Q>34 z;@rZy4Re>xy>IT%=Kf-?Ywo$Zv}sIJZc}+vYm=j?yXpC+H=F*{^ktJUFKJ%xJlnjR z=dGEyZQh=FznJ&?d4HSdofk2G{QQFXHS-tGcg%lq{+{`-&Hvr}Pv&2muU%kRkh`FC z!Mp{_7IZGyxnSRdHx~S1!QU2qw?NxGwmGM{sJXHE*5-B1+nb+ib~gXA`A^N~ng^S8 z3sV-F7g`rKE?lzk?uA%_? zV+8BZLOw>NEA-NkX0(I!i)ydu?;Pi^kI`gL8|b}mxk|4EX=q>=8tARN3T_`IW8{0wP~wpY?_q_1u5fV5YFA=Gzm`Jgoh>5aBl9h!|j!TiZr)C>)Ln`tC|qYie0 zVCw|?N-)iK_@6K`0Xpv?4db|yW=8+!HPtYqXQ;tynbBimcqPq@{@VP}Mm^f-KNeb) zPeujlor5)TZ(pT1+Q^yp5*zXZ1z4vjy@p@K`k;ZYCK*}h4fgHPMmV}tjBeeVW?gTz z4Og`5SL^6baCTJwKlVS&>T&c%BY?>&1sav1NgoG*p)(d!Q@`M>l{nDYKnf1fN znKMU5;xm0dE}oFDaLw|=uQ=}A4|)FJyZ8(QRrLdv@$*F>{4x-p4}|9e;RS!F{t96? z7}b7;2zIWlW;de#npJ;A^fi$C1mTMap@C0wjN~s!GU+}>XhQf=ApIdiR{NPi_<=us zmS<~9<}lsPwU92nyYTKrx7>x7jcDvyh?hBNSh$P>olbu`Bmf(o2e88C_mvw&9&?9( zU*09aaoy*8^RQ=DCZg{vcMf?I*=+dX4UqDCi~kMq?0=K@G2l4+{oZna`ZsyBlMvUa zJZ2uvP!G%d?WjD)c10lXo$tvj3FNWSm+^A#6U;;N<)gJ&^X4LCo9{e?%(x~aB+OHK z+6)AhSxI6?%!QMOy=RQnZoFinp-%c;CvBFe9mC!z7FjzEz?Wcqr}Yl`{-fA2z&>Kr z05(f|?zv40dx>}oFW(^>fSs5R@V@pAdFk+hi=8XziDh!gv1PKJ5wamml*kV`6YUeF z?y@`Nk|R7dGyyEw;74{6Ptj#woGgpO%jCsxGS=`biyg=Y%bw!PyYK8c#!OSZ7a;DC zR#JJ+U*?XA&Y9u@`J*AHyz=O=bDpOdO2jUp=u`K}^M+rLBTM}3JsEq1N*PPt?78F|(lJWV=* z45zFgGCF?h703oFJ^740^{r>*_uhm8&LK0m=lBkq!S@~TO8RHz>Yiuig%~w-L&(C? zZ`e;CzekPaVf?gzm>PDE0aZkI!RW-#`Yw*zX7Pgj7% z!;K_5PkDEVZSrGpDf%r4WN1cw;%09$T`G@L)E)r)hW+3r^1VmFXA?B=yF6$hoSgEW zBCp5}FEO6-o*`}Wo3Jgk*D_=g&k~>3xmR9tY_GgpQA_N-06znnpO-_AmKdLxwMP}~ z?Eq6xyH}Ksozq)xli%?Zc@p5wUNdEyKRLWdeyoRK>-HX^*Tmr(UYtbAo(ZrwJEcYMXEPL>Jk3s|QPG;i(gw+YCvWqjSQ~z#Y z0!)_Yu)+p_YcCDXt&oZ&#?hyjwLRPXeim|dyP%eeRC`1F3WAgXW@w_cr1U2l7nEcc^}DSFidEIPF?$fwCq zR}Rp@E}QnEn#GL3OEo$53LAySsruL;rSEC^;T$>a z2re$k(MQ;viSg(tvWZFSA{lB|m-W53EJ;V+3P~F1>nLNjDwc2tC_BCXK}0aQ8KIr0 zr&q}JJuBq-Ftaodvb8R%R-fMK-A8!O0dMb*dNsUjr*|h=A#VcOCZJ{MakIMfo(|b_ zStXh62fSzW`wn)$Z(t%Iy{hd!hv4h^zFO1l#Y{b41#OMxe0 zMAbd1M8{nA+fwMWO7ie!Ry_7aBq9&-p1)p>#Q3ha{D*8{gYfGB6Om=i9*R7Azr1u% zv~QDdQtH>a6arIy%(y`Q43db}3Z56(@Zv^tk^K1Om%TcSb`qNl4o+h&srv#sg69VV zZSqq<6fYr}A>~PeCwovWWjUuKHg-@WErJ~`lCz-7SiJ^pWb-Z+41cj~J>su1R0LS? zWGWIwrz3$5Bv#5_z9o2;K}yih2at*_-$teho)OY4cMTWGuX?pk!Lw_)S^kDeUdPIL zqDMq2Ls}z0GE^&{L6xB`0INKv0j8bMrAlI+lF%^sWnzLUtX^&Vtnf$%|vEWA}As~~U05I`dErwvxgdNfP4 zTFU?#096fM89rhG%oN2%4DV{lKppzWOuGe_Tj~6^`2F@ z(MbmeM7?EuoRlJI6T?nhtYf4Oxq2{Fnhdd62h$^6c7#E#qo8IsEqw+u`onAFBf|pb zjn9VslkOV%kkUY=AthT=Nm3iUsg~^+y)7Pm!Pl{RLulrAA6YO4>5nnjHq1~A2`5GO zav53|H1JFzdI1J8a&J85(F7B9u>p+YWtyA;)a>&k#bc|MI(B2Zrj}COo8_+tw9a%# zvOB>>ChV46=Sg&@ojm;e^Hf|R&Gk+of?eYl$NA(_KD~37m$V4(G&_Uuwtm}phvCbE ze0Kjy4A+i_tQwcPgFlc9`8~y)xJI_4yN_(bDi`w`bI|WnIF3FFHg2#HBW*2e-Ozfx zl`)s}TL6hTsgg?i$qinkSZ>f43mF3^S!OqNBX{I*dW}HFNwprLQeV`o1sBc2fwL*w zmG9QuNq2YG%h15jZp26^5bj00v{GL0GhmkKvQ9kFX_|1ND1>-$V3az?Ycz9%@1#9T!k>ESOT`zO++e5UNpHuFb$q0?&t|7 zX#_pXuq+gOn*>)#fru7bBR}zGN1684a8jAU%;i108Tr}gJ!OK_?LC3j*c6OIhrBj& z$XlVue2oc0#1f42m69o)6|O_x)F@GElW!W_D2dBRx_GHmto^5Nt=J~?OPXJJP1II8 z%~eF|q!sc*z5|!PyVxnIE=P4fkDOaB*z|GGz~eKFpaT2E&SLv1g% zz#NCYERI4Hg`zA}f0~iy#%D^zxLAI8gps1+0gG{2@3%NWz0he9+wL-`bB>=xvp&Gn zpYXOYCeqL?YN^xlC$F&kqJwxMh0uOV&@|d#uRUb@#Cz%>oj@GNC0mb>rE$F?-#sWg zKk^c6>^i+eQP0c1L0q-z^J?1qUXj}eiK)f)JSJx|u!TN`*XI#31@Y ziGH`C}j++j;|s$o4smdcgxR&|)Ar{zJP(M=rpSyNmSE)W{!;kBg~h$_L= zSsLfU(j+9>{feA6;Biv%YFV|Lv9STnQa8g{SFY_?S6g83RmGit{UV8sb~$XF>w47@ zr&$dLecA5k13P9K$%ptkIQ`*J_d?qi zd8SX0EZ76Bkz0mEsBhu$TtL%(#Pqd`O%MhW&X5IZoBZk!%(<_{&SvU0a@8@GtxrTY z8q7sJe>p-tPh$*!k4pm#mVFCJ@022?d}+UI9&B=w3AbF(k`Na)MY{B+IM2gh%|kb@B7cU&G?4B}^mrma@w#^7 zJ%G0pZ+Ef_BM^}!YKrfRb%r}%k}vpbr5?bZmp>YKJrL$Y16yx05@$h|dsDLWr`|BK zUk>pS(cA$Wev0H=cD*eBct|ZhFTX#azD#5#lwOt}9+HZGVg2HR=jC?>UQ~!39e4qu zzp5j?m*vi(=j9g%UY6G=;SA@?^4&whI$o0h?4!mm7{u?+;u-?hs03%Fk7LmL4(Fgx zVnArZp=bA_A{puuNg?vQIGHR!I0G+F@3Kd*M%W|YJv2j`u4uv<<4P^tfU*@=2s^GBgB!&{8;ix6N4@3(j{=L`W+ zP)1h%1Yb`3EyTZ4E(fX!gC7a@`#(oV$LjKyXyY!9mx6q2Fs>-Hu`(F~za@7*@82#B@0j znJa93<#XRdfrd%Z9&#Ppldy#>=*WyWA8!HP?rpimg!6Kqu8GzAS30lA&ti*gNhfZS zew#eOr|-E z2JW$<7wo=gh5X*g?p7vQhvixM>7%#Foda~jM`y#uPtF#3I#>2%*wAlA?XO|{dQCA5 zrrO&-4z*0R2zfMaU1yUfyUa>6h%Ek+ETu;^LYbTrdJGb8$ZCY>w9aopMaEgz-L zQ1@Xn!94lgVDCYn{D$v#`R4-;=L)Q?4p_tbR><9#ElyS*^WTw2V0xW|*w3H!)4cs` zh=XM0xiTCy!b?@ovWWOIWxH;y(Eq-)0P`jNCqK23WBKuoLH6 zkM75yy$64&kklz8Ll{ZD)}-nqMy(I8}JFBax!gq>NW?1>2$)){t-r<2hB z&9rOfsk5JW*L=Fdlc3@QoZ5CK~?6LCrx&& zfXM?Zd(ft#Y$RNXuY!mUCl!#CHR|8ELZlccD#@~JrMzZ9Ag^E<;zB=pO1^i5#h#VV z52-F10MS5OF@w~|v=%i;l(1v~pZm3oOG<3G^J6bAf7aVbifrJ^eEi$asLkFv`bWJc z{bui6J+a?d)3R7U^%eQHffna<8$PmtsZn#kgZ$osCoQ(4_y z{DxkRMwxdAC&s(|eEtH%Sb+o$EGspVcKPstUyO5@2&SK9MGsuQT8v<)e2Taoq~{+U zRLnSwbEuJ>o0xx=(!Cmy=v%`HyZS-|bX}}xcVQ%)fh|H8!XwXUiOC*Lwj;h7FA1GS zcA;A{Hzw|P#Fock81%{E*ga)F4FDUho|B7)Uxw(^6w>FDLoXAP%C+YX|KLMBYmcxo z#r&RvtOGI`Az4}=4q&Y$xCD$W#!H=1Z0LCpW6BX!x=g81cL_x%m1hRVUF#5%(7>${ zjxnw{fq8?Mw{eq^V&f(Tdyj6*d=foiZ5EySG_{b3!5 zd_F+3bbSZphrP^e;**amT*Y0(6;J0cQqTpdcl&|w$cm7@J#wD6z!_otbUVIW+1o)h zZucfV92(CJSe&5@xLtpvDJ7pHhXLH$5d5RuU zsE0}S9}uL6VRFKY{KY!5QXV&$p-fC^Sn{Wym{_4K`k{eEWk!575gQ9Sev>81n&=u| zfs{V=-s2XE?UYzfP3f+<%usulEA>(*7uvE?zGYx+1-0AqqFSPoJG-`py*1X*mb0QM`A*e9*0sS#XjdNK+?aybe9t(HsY%2cton0>P z9U+*5Kl1jUW!r>A%$RJ;U`GpfY-DC*>55}BfeK@;Hk6=Setnr3(IOu_>UD{aXvk?Y z?rDw2^|#_jG^#$nBHGbyB_~J^#jwATg2Nc4b^^~)rE(kA$!%2POZxgjFsA0I_zkiKxE?I0UC>a_9U z#B(^Qw$QQFI?m_K`Jj}owK~huBMtl$;<#slntIB)Z36>Pv5|@|5!a~GCsu8`b zBZSE{!gZod_IY3JrUO1Bd072;xpSbr((zk6*Uv{s+aJ-4JFRPvc7Io{vm5POG-0Q- zneivy?tdE^Xe!5v3GLrNh5qB%d@PIEqS2iezR8YV;la0|_3KT-&wAlfAQNf#Ysq)I zM?}p5jP5&fF{!L{*$kG_hbADkWPNNP#SZQ7RtFDjj zeFuep8a2Tg-lEzPzTv)gg1hz-DGhHS6T&wIi;Rw0cB578dZRd|jqi(J8S1D{3GHAC{h61; z9{&7EX38G=IVxdx*(s5<4F?{U^lI+38tXgi{=JuUHD)VTe8XaQ8UA@tvTcCx<;+P&Dc5C1YKJxZMBA&IQR`;!jh&y~KBlMBP95d=#NnsV zKzWss+}>g+x)4S`UCgRlElWP`i6a-eNUlGGhG5IaN2>8x6{*2rb)?|Zx`m5T_^uxg zVG6?4SSP5|%Q$!AWcComM;XLX-s z;VkI^Yv_p@r{{L_1-Nt;3w`E}E+$|K?GO$Wu$9?U_!6X+B-ZFcH5pISUbK&sqLa5< z3~n|XmQ-UdFkx6RV5r=Jp@r?!9sw_mlPJe5XW#8cIJ5Q?_kngo#|!od$6YBA9hSTW zhK~-u;Mit8r!;xfA=H3{RM}wd1_{e(^-()~0NS)e}6H#R@)#cwlS(D5;i0u9_$W5ieQiWS&|XC%fn*W5eV;x8U%8Q;iEyGXK>UOX9! z!YS@B6l8~IFU$81O_qcgizF4Z2G8Eh_+|-7c=@eLt-G)}qdC-))R>CDsS1Sy)=MXQ z%JU>U1YLSLgpH(|c=`l)LJ{oSTQ*1sZ6tk~wAl{tHc3my!QTmVJ+$7?Q;&O@FNua} zOz|%5$Gb0bL}glf;*)d4qtiu1=t-3vt-lJbjIt{7PEXgO&@`*iRgDQ`@ zxa@-aZolbmMUQ&W`qz`%{!r)?%<4O(J^i7ysPvB?k8_g=pLn$!6Hv{=SE>o`+l7Ie zRm5sgyHX|27y==D@Z#8%7XR|#E{q)yTK|61EKQfX&ayg>C#Z`fi~ot%Pd#S{Ct(ui zqNqD;Z`&;nt{=WGd#{GN5~VYrk0=}C3UxBG@1@n7A@Ga#Wsc}%s4Rj?yc97g{PX7y zy*t*??1Wic+DbKjr*EHP6DB5 zG-5^+OAivUQ`#u0r43T8t+w1C_1eoFxR2kDkNdhtGF2EGMl!K!vs*OOP3%NNOx#B! zFlFzKL@4w%A2zs>ws@)Qtz@&iz|r}t#jwws{V|s%V4JAHb}`PC;&wPXQ&c9+2a$-y z!f`zguBJFsbe|Ch>yrmZEElxeq6?v+A;^z6sRQt@M$`}`BqRY-SVmHLO7%fa3C(^V zv^mh$g6??RacGY+?QOAW)b4TDq@e-xEQ|wSIQ&EM#H0(MB=v%p(&A`W>IF5KbRmRl zi*>GWH+drTLKx9rz&)R0p)cMNf|R-#zA$meS)ceI+ADNT3eG&nkEGgJVjU7Z5=)TS zO*@fdn=MVvU@8ZN{^>kdzuI9r=wGdzP^(Xkh`;&FKO8M%dx+!+*wRX8g<+#L?Bhia zZDyz|Bvb3MBw14043>ks5^DPDW1sl*&$5%rL^j?exHBD(I5B%*%^uMwIxHz0t)U;U zcAUp}!^8dr*B*o2&>_D!V8(p1-rzfU!0~|fvy&e~1C#2FW?8XXntmb*1$m+Z{er zN#95QKA1ioV}2J_H8<*28RotWjMH7#tdF0Bm%bY(znGObg}IH1m5#0JV=R>&8HrmQ zQ5G$_85@U;jty4NnJ1O*#Dw(^q2aDn$FIs;Ak>lpu}3?I&ps4WcRUs?4?Smr$c@vAmyAicpzt_ZiKQ>{5oemd!b zhK|S7LW?ypZ}NoZLYOAx0!L5@TK&b(ed0b$dq3l5;^zIe3M)GZWzjvhEz;I&6lPHr z_T$ghP*_z!VauVgih#n7Sj(WWc+-r&9|sh60~A)LC`_G^9#B~7H3~Cr{NGa;6}v5L zzDafbP*K*Oy!uyz%5fhj?lAY0(15WKUNWYqUn_c=j-FI|P*p;2IQVhLHT}f`CpJ?} z2pN9?R}70IT#;^ePGCU~thnG_=RQk*impLJFYr(tQ&ch(H5Q8coHiMiPH@YQrJE~y z4{ntx&I{@~`s`!^>zg@J_duAL+RwjA?lC(#69?xp4tCre9AGrP!RGSf=aL2}-DUm3 zUmljU!pu|iu=eoDKO5FaKGS3z15I}MAqz%)rb#Y3zEJX~=MDNy<6WP4g$*Q4dofm9 zD>Zr3M3&cG<}(>wJvbYJ1`M-}L~~-T!)qt*NH-hWI@dXzZHCVd3R&k*DsTmc4-&hQ zVX`TojhHUOkCpV1vBsiCL$%PR)Q*vML3>vJ(@BsSQuGk-wgW}xX0$6}>za_(^m z7*IAut(NzD-S$N1r;ZT1T7J$ewkJ9*-(&;68;%aKqoqS!$qG+>9fdWZTF`?#BB)1o z8Yw%mYoURJIq(w(ovv(U#D*f~sbJM4~@4xi}m==kaa7QzxE2{w?L{BsB&VCIU7J z*?arGIJ;@vkFCN7+cerf7E_%xdi3=8rj7Ou?cHU&+mCN6Qqm&Werd=ib>eJ+r#op| znlktl3#3a*kdmcvS4%rFg}GMAU;EUOdm9_dTG}&Es>{dY{1P+rCL$ITzl_z^gI=y~ zyq!;Nmn_n*GAgySLj&PWMv@8ilHu0&_u8Eb<9igwqXLX`3WNWSRkO58?(vzV-=hcI zd`aQXQzVcGEL=sGd)vD5-fuUMT(6$&{;s3dH$C39)0+m@aCBcwd#7`i{8OI>d@z2k zzLxe(DHpMy3@fYoqE&MDTYeXB6rjI=AMJHoGr`}-1k$?=l-08o`D@TE*UC3vR^h(J ze0kgDF6S*a(*LezzI@;1f>#&9;Psa*kuB{9yj3lsE>BL(2WBbSt)z#1+IdD&qsKzE zXs5jWs3V6W6D~nB0yTX}aPx-YNf#U30{ycZdq$lvZG1AP(=F6 zpg_*LaBMyf;;84#6E3&BnjH|w&cx~9U7j0s9~4MoZpRH2A>({E_@|l>7fXErmmg2DoCx7? zsjyV(9G<6cxv(7?7=Z>_Z#w0W7Y^#3Z{Q#@*>yxsPT!>;SAN`k;E_+arBodMb_1Q& z{E)>^9?>$kJY-Po(N5R4z}IIT>Jx8cZ0XGLFm>$>=p{?&Lzv>4%I%G zOB@d|A7O#P(em>6Tk_3|f|N90$$`8Xe-CTL(_fsxR@$v6p`T+S}$O)fuvK9p?7`f;UP ziBXuf%ocg=TU4AUuN^q#4I#v6mj67$;M8*yj`hq>2k3{U&Nk{qv+N$BlGdDR@AY!x zBK%d0savcYSOG0=zqFvpx<8=E%){hjh(MUnq?_wLg=wGQuZGa>LpZ{H*{daS*iLrg zl7jJ`5Ou<-SX11|$nwzCkYu-Eh5ReXtaG`sD2yHImcPS=gKl~3Ww*g6AM zkied5PkXNO0EA`}oeqL8dvmpIrToF*3%KaB%C@%^UM^t;Ab%QU=gmyrSq~`$*qy0( zX}8=vV(KB|lcX^cCyvMlFPl02M{^rx70^wuDdaZOP0Zm_O@~1ed>af6_ zfnvfDM)@`FL*U{r20qCJ#ihT5iOte8*H-e4o?>Fh(*Gs-?h&n1m;OUckt$5LJSmmy zhQ(J~w~5=>U5dYNeR^x_R&i^oJZJblXREx!*Xx7^zFvr(k+=faq}UQG*0opG4;0|e z$=$;$=_Ux*F}P@(ahpjhl@|=V*P5M??&$PdcX)cWJ0!i*Ev~!II|rANLx^d~Aum4Q zirLqF&wbvxMBKU;cVAlYw}L#1D=K^CZ9~Sbw6k?El7EE>;U)RaVF;t##C%B}JHmuww=!RnlSkZZUy?&d#=vf&Ssedp zfjw_{xojVZ!#SMT#qK5z6`AGV9Ycr_xJri)ny{YmlDvP|f(6D)@?*ot&OrkgZpMj; zCA3@*N+U;@l{0f?4Za0ewDcQAa_MWF{$P2u_&%yElbVr^RhCM(HG-=DgpIXJgw!oD zvs4YcoX6XbfBOy_mkc)@S&cbU7K6KPykVC$|<(eH5B=qVtHEx3zq?kHn%t(m3PA;mt-z#w`BG6??% zQRWYx?x#E-o*&6b>Ta2)(6~hINB=?1imbKA1 zV_=S$L}!LQLA0$rd6wNqDa7f^Ur&gr{Gnma&BDXO(;X~Fn`B;PvRlx7-|Q3DdR8)) zX!jAUj}Fk1Y`=;4*`CeV)>2a$@S-O&R=E?#d$){)@Q5kRHEfFN^Yi$RQTaM-kv_oYis4p|__;e7 z;O>wO{B;uhtGHJZ;$ZuNk6MicLcDuc(Prn{V10yo{H!Y)C+X-OLw=p#0W#RVo!H~} zP0Amz6^_=vhuvJvnLQ3JLw}Mp#h>|)fG{B^I8)>aeU9o3mlNg^azb4C9F4!lI`hw7 z)C~09rTzQa8|-F(Yv5$=0k5ia;#s$2@mk)5>%14$RO8|y!c>Tx3voHuSoi?{2|iiF zL|=!gQZOGI_L+W?Q#Mq9RzB zK$Hm(*Z|c&dl#T=A7So{m$?F9#QVv#Q)re+xyJpI7dw+Yco}yA8)?U6fii1 zvn#)E!59+9U+EZqvPB6@lug**nZfE>iSw4M5I5c)=EqM77b<7XeE4ZpIQ7axixF#D zyvO9AD#wRSsPe~s{f-%^vMD?ctl7h(1hEUum>Yvt@B7;5i2FW;RZn3@)jPtr!Pws- zHd5f*^nKGHNgKQEgImJA&75eaR*s$Tv+t%*9vaO9Vpt&g*^VFPZf5K%T5K=6ngnJ8@} z8go3T0owRZ#pT46hl@nGE&v0ktLzMl0*f%&gM-brBV(G~QD@G$#kFPLX4{6BYCCQg zal@b^!MaYLPm5)=__^hMeG|#_wc5R$IkY(sexcPE1 z>q$^;#gCL)B%3_{+AhOMFTs2op>C5PvE?PB-15ZyoN{-njA(5mpf z*3$iTEvixb8EQRYAv8GsL`NCf7T!M06S^Kw<}Wx=5dVqiwV!t@wO0d8dUPTn@}59+ zTK_g^Yr9KJ&qP_uuuxGKPDvF|`P@mo>#O0XkI-tkL92x9^1LSf6Etyc&=z+WL1g!A zv=Ks)9E2(P38t`B$wY}wid!}C20ZhOrl-scms_y9yMV6t3VHcSGD*~LO+L7PNR2+_D9g!T=twBacsAC8oFb) z6A2OxlcQV!@zmq?a(kIwcBj4U=FeD4L`gl-(tESh(3>KPl2Huxs#w zJQ~Yoj+~3bh)xSxy?lLK2_Lked!&?beib!2mnAaqRgRrQ*$Cq=jKwAcS2^Gq1sPLg zJ&M(MLo-WTqlav+8?{+O0!xY)6xV9UpueGyg7;(^1?A98GjOkQZY1)f8?MqW^cX>> zzCbO3!>(_8{h>ze$2v@L=b?yn^J5kVkulK|)YkQjvZQ&tbtq@aHJlaIDEv<=5X~#o z-W~X=I@|l<&5p@MY7&>bu`znsR=rV{MDJ0F=-@I9M}*=A?IfnbWSl9D^wnxQ6@fcZYVskM&Le6CBU4%QL zYda=~pwGoWXRS}pEDBd=HHZmvrj60#tiwWFX#WWzGYBT-ZmlOeY_5R`VOeHdAluI0p?ud6@sT8-wcct> zInRXTbE53mYN7Dg+~*C+aza)t_Hg6@4E%hxovqS}dWh271MxM&Gh;_k0jdZjz8rTa zvJ_}Hbo_fl3QZWLQvkq>oS8h==1K9~msM75gcQ!D>aY2@^DjnUk%Wn+@W(el7AzC^ z$h*-hwlKq&5ubbQ3oZ|8$9nG6V`VqxE(Va95sc#C7O`!w_9nzcdEk(6$#iLAIy!FD zKX}(%haB8eqrKUiD}T1GMw^8DZeGjT|{KicTZ zHd)V24K%q;7jnIM0D)jLu_cx3JFZZ?+7Ssa>$9&3U$_#p@-(C^T`ozbNg{u3hNaLBP6#rOZTJ(IB0)-SJ7s?lnDCgQy@x)cRpsx^1}v@dRR zkcSXGOSFpq0?d@_pyrR9_jn5+X8g{j8;>(F=#P7YC^UrhWhwhSbOOfJ0hi)T(p3 ztUgPSNCRg*0`Q^>QTCxV2W7B%uXYmz8Ga=nFGsZSk??Z+&D{UlAkFP{Y`6sqMf^~;J4*A zP=PsFt&_EfdYXZ#r7W$jX>9`psw>)-Y9dfs22}DoDmy5)MAcS{mT2m)=o{0(Hu-bd z5eWW6S})S_NSptC+ShJRM9VMH&iB*TU&7ZZm!D|0==MQWEkUo^gy0N9<94m0x6n%% zcxk;I>InY2;61)l*($$wo#UpLe%Lv{o!NZ&I?vVl36(RBA{C#P8oA4x3ca+UAl`>T zRqYNuCn%hpuZzdO5D@S@QGbp})MMVm)S3QgBpy#p?$A3oR&kv4&W&Q`@SUonz-F!s zq5k8pwG2`q4c%X|ZH{T-jPk59E~k=&oz!H0h2QRZv71S|>zmz%&tL53oCn;(=SGNS z)D<5N8Wei66gLH%>U~-VtO3|Vg2Q-$PR)45;$UZU{I*h?+;P)bB<5NpcF2dDB8fg% zR}fS=Fwo$Ko{>}`dnKA7s5dkO;p705&v!!o0wjdf7K)5ac(kMAkis%fN1E$~|A@363b~$e4_SJhhUSNgmK1&}1Uxr-}JfwBct zR&aSjBnZ7YSBA^2teEMoa8kIzdD14T7Orw7h1aQOJzQG(cE;5fQ1jem?|TKnz}{Lr zdrAB0z$71sb$No9TT`UM2;)lHz|`S41C2K6zo~M=llP4efw?T-{H_j{MaqO=ZP~X2 z8#u^VWXeU?wom3Hl0CMgM{MJU0K#)cDnurw5lHcCq@eY{6fQ&^QQHk?@Q~t*Ta)bF zF4>^$c~aW5X8VdHJn@zE>#j`1?{@w7WMu-uS6Jnu74ZK=?yqNFCB33m!{xo%Rgtp-q73GS(UZ8 z_`~a5RzvSiwIzDWNnul>DYlOEmT3Rv5ha!qDtHt37&6hflJ;w5aZn6Mf++$v=jz-H z*`iF6#>*3>SADIqN05{0yUkft#4O=aRokfkCFi_8+OLTO?hB+1(OUdtJQ1(0AU1=P&S@GXO zQxA?AhRmd%B!K7Q;2N+LCwdOztj>fz`x^rs%>#8C!6CsJ)j{oxfyXj(J!;EA=qBz& zRH9x$U3-uN&A%sTB&+?&IE3*&qba>j)bAL*s0quUhij>&&8YM=j z``B;HZImub|0eIL_N>)*-_F5YlC0j2G;VBs z$(!ygXU3<;m!xCl(b#ci{Q1gENB~S_)U6L{5A+8iY(x`Vp7$j!aNDDQ5qaQ?KF!|4 z#u^mL)u)XF6XBq?4{9<~**u5wBEH=q0s|W!vop^&ZQX5yLSi5%+-J`=Mhh`(cC_ro zeV!xkB2|fl^qQUoaTnh{s4awrgMnw_mM1c@{Y2BvI8*Q^3i(GExsM_=Ts_Bzg}6b_4lvVrbg{3 z2h2;fjnPY14VBw!ZTG-v?_Z>CV4P5;X7tP2j(!ehdK_iKDFDg@b_>cxrFp7<7-kGh zs85^S%Zak~lb*D;MC4i6;|R&x+bG{ok}a15*cV{VgL+P8ipL<^JWEH(+Wwv!SE!+~ zpPmdW%OWcQ9Z-mi8kEe{lD%DUlMSqxhGleqaK4dr+${yN*yezK=Ti~C_8HDzA*0^# zgg4X9;ZVdgf{pzw%2o*W&!WN*C{+#{`zYR}DWXri9Npkm9+}@YI|Yj0@gGJLnoj|G zG3p4+@A^#~R$M`W*h+h4wbvw_i}vxNngE5WKE6QqhT?8D`~NFJ!4A}FRY*P66Mpv) z)|_41x3@Vv#hfnj)o!r*_(~pHfMl(Ag+tL=t_4^gK9UJN7&SrX1}5-s z)xzV0nPsKBJtzXvEz<;@*fn z75(1i{6AMLIDN39r&<(XVA&I(h`NpJDJ>2>f}@+C)PB+*^ze3<=XD(OS)enTf*D5c zjrR%?WTZj`Aa2)dO9y63qzVyz9=ngO5*l{HJPFPL3`Yjl-yz^Fg0WVa$T~oXFj)4p z?VQXw7Gz{C51UU={5GkFQN=ik7Pnnm$_W9SMg#XA=R!Q9HxfN#AuDm9 zgJtawWJC?F!*0Wchew;n3ujCU3Avlb-#lx~60&(EzKzRb*%|Yo31SR}MtVQGZWwMZ znN%{ov4cB*=+4WD&v8Xk*nj~D`Ne~u` zT*Ea>_%!q5S71)b=v{!*oB;>Bs0+f^od6ka8;bq>0+C(6Lu9FVh7g(16|2JhXPVhq zxS;qEnN{f1p6CmL9W&4ay9a*Z*yw2mp5A_;HhIK$s;{2 z85H5@a_tY@>bn-4EX0w#dEB$n_$Hi9_(|^&a#GT>5IJ}|%1g_&NYAr40)|8w;_+5j zhKPO^Y@&k*u+A;A{lzKOJ(Uoq*YDQ<>{XNEm>oHy|B}PQ| z!c0jKza5zO;+%De5*+<()Pz|!!kR-Y|EX|m^b{2WAN>s#0wL$wZiQv7$#mT~Jh|8F z*SetW11jx#ZrnrK%7L`dGOaMm+Ss_(XbE!}jpyG(YFmiXS{2xvVE1_3$j!@&U@mRB z=I%X#5Dp8|zx#Z$YczPVH(2iwko}zgT`IHjXVvJppZ0j)kL5W+&$BsH3dI1~^V?`b z!*ZyWhuao@_ujNz8xIW3e-d&;4Q-@+AbSiyTCQdHEp9U$qt9OJakdd|sX#8hVkc0{ zAB2vex>TSesP3!4^-ffGxDuz3PG=1M$sqh3i$`@n9z@P3gUC6@sD*?BWRL-^&2!K@ zgT{))z3i6wm$yqSe_Pj@cl4g1^N)g?cSirfDzS>R^HaR~u)xGiy=iar9-P>};u-A} zjxEP@%AlvSN4wM=>qVd)q32e|S!CAWmAQs`nQustO^sgJjAu&&L}qAjSo)Nmd8K;E zs8@Pf|8dCELBPi*dn9dJHxJr{S;d6;9&5udseKN*K(JCv)wzuk;HY~zG(k9Pt`ZN0U!ceay~;t2R_Zsg*!F&kc`aO(Q8N45 zSwduRG<95_!CHcixL^F)$1)No{_ELo88xE~lYViQtS<=RVFwHcISdkL5geo{#VWrd zR(WPZnE7ClWI0%e$v(dM6C4Kq!LZs#i!o_r?g0j7Zv#D0-pz7E*#JD2Ma7U(%>>hV zE=N!d7<&_e*(bvAlnAChg)j=y$0CQ{co-3*b3##GukG)qk=Pn-9&GcL!8UKz+noB? zGVPVy=tnm9yi-t#)T;y6&eDsbW=f~w4&UP?%l!!y^r{@YRnBc2Y48x z3WvD-oba8B9Qvx-D#V>@jlKotB-5GJXp8Me{eH|UN1|_`It;_5d2m>?vXM%594-SU*<&D=dTI`BKtjPua|H(pl#=Ts%|%GO7vnQ|vHSKY$3>@Bst&)PX9tL7a?m zd`Ib!%`DFz9#Xn+bAx--*%fPE#P$WtjB*B=Eru*eduO#q9~FnibK#|XD`@vR8gwjIgnA1hc&e0qeMQj?6Dx9IBOkta7ItLw&nH` z7-V6p!aaloAzmHBrxZ_@rjLn}i}9xL26c=fy*N&qF={AS(0qqMRSXI0n1o_dsgmZx zMnpr@@L!-`Ml%k_bz0&e#n-_$C#XsSSr#h4#u9!5NCBitx;k`7-@x75?JS{lQ9?qe zV1bI$+2H8YXf*-zIPOk}YL7mJcTT~t^RMp;`Mxl086h)^6Pb(BO@T+2Vt$$H&UCw`IxhfiMCz zFrBH}80)pFt`_FV4UZ`0VP0T=H-k2C`Xx?Dfb9GJZVvry=$~prLVkQ0;Sjv%rDU?N zgfbn!V!=9b>Pif5!0bSR?A8gNpDmD`B^@mVpf{q=W6cpHcE~J3w}xiI$vf=e)ay)> z^zyklVFz`BOPZ>4U#4R1sRIuNTmKaZyc2<77)ev~z=`;c1@7bm2=yPInFjAbYT+NpuD zU>*%}V8Tvd01it<;`TA} znnEUq$*T%^QlULT6?|}!g#mn^M9=3`=_%i5-U@Bqz$pk~5(gsn0R;To_o?^N^i$HO zK6dMX6tk@|L8gGxPs*^v!fxCeNvk)Z!P0`dphLL$Ti#{^f{VXRvh|<_-Uj^x@0Yfh zTc)_aeQjkd*^r1>PwgCR5raN3I^)A{`z}rYtp3AW!3DcpDsPUlxl{|-p0*P7j5|kjP@!u+ zVY|`SSoTusOXb*ABXdI}4IEKXrb1feG|485k_7?;vmk%qWh7f6g3A9J3Z5N6@;#*} z9!H{LAmJi5xgLhd>Z@&1eKkd+`gsl@8Y1zr{D(!(3~rYa6{<#Jm^tDi^?0&`zY8HG zokT4E9D=y8wW5rGfy}3IO!YbPt1jJ8mNq4Z^f;8*45X(?l%GvDz>rVSMXe>`POarM zRUk=Ob?N_-K%xZL^iH<8Nbn_l3X&}GEicWO{`bmJSFr#ypjyDWp)wud79t*P1{Tl1 ze;(&Z0~&@!obq&8gc%`7e=I;*HWhURXHS*x#l~_y*oxU*L4QtHu*fM*$GB2;QJU27 zcWDq`Plq&m3>Wf&EXe|j4GfHW#?I(q;S{nu_`!Ts5VMwyau-=#PV8wr^!H#3e0BJp z(is%-;jd9b=kc7v{YsH3s7zS)R?r(u>35`x4x%OcL|ru6uGxtG6@k`SDtS z>#DhkmE%r)=0ea|-T1)55yeBtdcJk~w_mr0A=FVfz z_Ql#`?>XBa)Q){{50|I+I6m>-xbVQFp``+H=x1*cbIjN|IjxdTIX+rc^62w(!f%iX#8;q;^D~nWC zsmJXKPA+Rs?rc7SBr`%CEEVHp2Q*lnc zd(@xCw>5Uh(GKkkV@|3fTz4~DH=j`N=D%1t`g}{G!iiQuU8W!50O>h5cgY9~WyH>F zaNj&DT%V1Vk@-i4#`;_Vi&UuO_{PrLy%~D>f8ube0?xO;PTK}aR*R_mzl{1jn*B^n z00xrw*jZ;nf)V>s;d+t5gnN1*?uT);-XD5vAC8LRLxB`2Hg2t8s3t+==Mr|6Rv4Uu z9gfS@BW$Kf{+|y!&nI>%!P39jCXV)W@Bdg?onj z=U)Q`tb6TjXwLn389MtV`dxX}&vy!Z7CX|(2}fGKiR?BTAS7b*v$zV~e#28g!FQ65 z&jYp2Iqr_k#U^B~4>E-$m{~kAGD$lPE=e9ppE!&!68C=JF^9RMHQL^RBrG?J)9%+PT1PhY zA|~T-_fFpw{7%(>lkv&gff#%Wj2I6%>p{Lu_IjlO?dU+SR@?8y3Ao+sf}!JyK3WTe zeJE$WbcgtcrVWtn1`dwb;tPV^B0i{DU@|pf6J8DatAN)qw^c6yPC?mNWHz8Z+Lz-S zC3^ku+!(`Ud5dr|I*F@;{W3#Orcd-%Wa3Z_cV`wIu8F=6SJ{1atL)wcdr^?DHQI}6 zKML|2iZ|KPl2NKyMU>&zRMfT4)Yv{mzHu$u35E=p;7#IKs z4yDmtm*7Q?OMPsMMYraLtrp(ZR+jzHyaefu&Y)l%Ukf2PZam1*@oU3|@v9?471Q`t zVaxc8@T~DGBeN819uL`~Wf6liRZfsL$-9+S+`HsmiUA?B@)jT@M^2Qgu_JUOvzb~ zJk~E!rdH!C)ek7GxOY`AR9rV^4S(&%tUG?`E(#}I%FfF~&cpJ?g-7Jw5l+wZL{gQU zyo~U!yrPI*8J3?F7D)5D=UMQI^POQne|jWeNy{G--jhEyGC`T5ypEz?mh+UHYJ9GG ztnxbUm#Z_C92Bc+^=Ksr#j0A9uH>L9Rclj~*J}`7Geoh?%@1(-Ln1kNud0btUPo~+ zuQw?-5CCChtMryl9o8GQs4Pdb4WM`)_QIMwy1GkU+7>!Ryez5Zv z=5r^7oyw70iYu&4~uXP2!C6`CNS7IImuf; zr)uwV3WSImH10Q7cEgSo1n6`D zLK3Jde8Iv`k8Mtz_ceqquPoM4iqhR&4f+3!<4WbC2<6MsX3IOxHX3vg(Dh;kwH}yzG;= z7H6ghT^V18)e~L7Nz4XvkZVPrw4S76^64;73}bN{I8Al)$!HVviO z+PvO-Aemau zl+<#Zt*SOh!WSQ7QXjS{CnXzt*TP89NuW}xz$V4$Nt0Q&h-ac))1+VD3i@r})SiO{ z(6)^MP1``1T*Bh`iLfUDAY2%UB9A-%SAJ8t{ zi22t;zLfIG`7WP~CG>G4OZ5tJD#S@hNOHZ_((eqFgy@+Ts`c74zsg33S0nV+KbX;* zy7ttR2lNcAb2$%}?FdwaEJz-?4eg4puB~~HrXwN)GPv3Ta~eUmUi%O>5R=0{Tg{+OOg=8Z z-Vd!?Lu64@7+-`dQ;w53NOeD{J>DG?;q)tdE~({BI13sZUauYQ;XFgp3-h(s?!y7s zw|BW06n9*&6V}79brS3}IszT0#Pe)I{H1*DD$FCqQ4#fihw}z-5FCC|r6tt7^u66~ z0fkNlBSl0LW4S9|nh1LBf=C*I4RhS{VB(|>*M6b1Ij#a_d!ZZrug&$L<^Y*ytnGuc zi_HuZI5w^xPwTb&dT{>3NMUSMA3Rcs)EW(Qz5;oe)`YAl(fR)7v{1hGPr$%eFW6Z( ziNSIDO4z}*A_@()FQd)DBo8UlDDQs#Zio5aaII|Wv@i%nyLZk=j?AtH|G(1;q)vdE zTAs%~%IaLNrS}(l=G>UYMky4pXhvql2>I;P+wiT3Bk`fwe98efY8Fl^s{>7)7GZZr zQBaHuTUG~hJug6wu;=!i8{3&A-LEC~L#`Zb5l+e1_VrLXTu_>)F8KCs(x+DIIDKD0 zhR+FkghZN3aZ>Mp7%VcMvo%g$9pXHPdwCt3%0U8FDhbNjzL^@Eqwim{^Xn*RWFP zfN(5<$L39AMy&jdn)< zXpmT_IBj4rswx7=6%8Q9OJ^u*>j#XH2O2<36Mj!|8rz@-7K50x|HZ%>)$Cs}M*e0H z$KoGpVe{0T_$0ZT0mQm!7suXH_aJAo+6_ot`wM3Ffcgz`*8RWVz7H9#+>;nd9|Tw#HmD zTc#dHnRUy|TylzkI>mXToiK3bCCr56um*{TY;sXRKBAJR8bF5bn{8%G)wfUxa!&)u zu#P(^&LMn&ywU)2hifYQjH;_qbTZcrNa|Z}7}!f{9#WC38bF5o#|i9N^>-*dd8#pS z0@>+BK-%d=Bp%L`?`tsP)cpqbvib%RlNTGrNtYHH*ehx!8k$_#05URIV_*l>&w)|$ zT?0r)`NNcIE3od3K}KDupj0!dtpLF%byKNa^60{4X0}BA5j6)%)&BNJfuYzVw;rQVH8DPN@0{*p|P7pQSa z{~Z`O^<&V4$rGgC8`(y60`Nj^bPzSaWUQGCOCibXmLL-se8^kGTxRZv~ zIiP?%-T*RNm?^M*Y7>ox7{t?1K#-^K^@bQ^&c~1N?3nr=C?R~*00X}|hKMQQT-lfTv3?LN~+(x!l9gTd*iwqzO z`sPsonu(&50~tUTW{U=PSiOJ}l5jjA_pQ|-UjRaq?HJr7T8)534W}SdnjUP4wG{$L za@s_@kj2em1N!-v|9ETDD*Q@Z3K zm;8fo-Y3WoV2T6+5ocM+FZ5Kv0y(q+WckjKJo~wN1Vf#?*Z?Axy9}&JJp=?W2I7!!8$e`R35uxRK!x>F z4KBG_K%7=J899^78^l??^DNJPs)|TOJV`*-sAp(#7f~7VfPq7Wi^&O7= zQk9S^?U?|nNifr7B_h{~Sgz};rdu%2UPi98nL(WORSyVkueud+Bw*m3L$JuC2lxvS z(4a<85!yE(YHjm_0^6frL}K!t1IUKc`9}7n`a67*9OwYDF_=dvdIIBs{O16&Y0(iH zut$&&`Njd{hr_CA0`Vdra*qSZV^{rV_K-fpnq!d1cdnu}Dg(tL=QxNHSTu>T->QZ9 zRyYRPtV||I4-i7GaS-Q;zT+G_u11kcjX}2b>B#TLx5ya|;%u!tMa}VhK*$>oAWv4b zQYr-{Eboi|*{fj8A)p@%MxQW%zt~9mpMDLD!~fs^aOlcL;dNcmqyy=F+CRK^4zNcb zUq1EDsdqkDGvaafX2-#Tu#3PJN+_<@BQ{@WW zH*JXB(pw1PzgW0F2 q6>zuV0$Wdq;ims}A>P98UU2^|zZ5)E+VB26btY(Q{Qd8{c>fm;(0Z5v literal 0 HcmV?d00001 From cf1c131f738d66c7648885e5096668ddd11b886a Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 1 Jun 2019 16:01:25 +1000 Subject: [PATCH 0415/1788] extmod: Add network-level class binding to cyw43 driver. --- extmod/network_cyw43.c | 460 +++++++++++++++++++++++++++++++++++++++++ extmod/network_cyw43.h | 31 +++ 2 files changed, 491 insertions(+) create mode 100644 extmod/network_cyw43.c create mode 100644 extmod/network_cyw43.h diff --git a/extmod/network_cyw43.c b/extmod/network_cyw43.c new file mode 100644 index 0000000000..fe73b07153 --- /dev/null +++ b/extmod/network_cyw43.c @@ -0,0 +1,460 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2019 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/runtime.h" +#include "py/objstr.h" +#include "py/mphal.h" + +#if MICROPY_PY_NETWORK_CYW43 + +#include "lwip/netif.h" +#include "drivers/cyw43/cyw43.h" +#include "extmod/network_cyw43.h" +#include "modnetwork.h" + +typedef struct _network_cyw43_obj_t { + mp_obj_base_t base; + cyw43_t *cyw; + int itf; +} network_cyw43_obj_t; + +STATIC const network_cyw43_obj_t network_cyw43_wl0 = { { &mp_network_cyw43_type }, &cyw43_state, 0 }; +STATIC const network_cyw43_obj_t network_cyw43_wl1 = { { &mp_network_cyw43_type }, &cyw43_state, 1 }; + +STATIC void network_cyw43_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + network_cyw43_obj_t *self = MP_OBJ_TO_PTR(self_in); + struct netif *netif = &self->cyw->netif[self->itf]; + int status = cyw43_tcpip_link_status(self->cyw, self->itf); + const char *status_str; + if (status == CYW43_LINK_DOWN) { + status_str = "down"; + } else if (status == CYW43_LINK_JOIN || status == CYW43_LINK_NOIP) { + status_str = "join"; + } else if (status == CYW43_LINK_UP) { + status_str = "up"; + } else if (status == CYW43_LINK_NONET) { + status_str = "nonet"; + } else if (status == CYW43_LINK_BADAUTH) { + status_str = "badauth"; + } else { + status_str = "fail"; + } + mp_printf(print, "", + self->itf == 0 ? "STA" : "AP", + status_str, + netif->ip_addr.addr & 0xff, + netif->ip_addr.addr >> 8 & 0xff, + netif->ip_addr.addr >> 16 & 0xff, + netif->ip_addr.addr >> 24 + ); +} + +STATIC mp_obj_t network_cyw43_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); + if (n_args == 0 || mp_obj_get_int(args[0]) == 0) { + return MP_OBJ_FROM_PTR(&network_cyw43_wl0); + } else { + return MP_OBJ_FROM_PTR(&network_cyw43_wl1); + } +} + +STATIC mp_obj_t network_cyw43_send_ethernet(mp_obj_t self_in, mp_obj_t buf_in) { + network_cyw43_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_buffer_info_t buf; + mp_get_buffer_raise(buf_in, &buf, MP_BUFFER_READ); + int ret = cyw43_send_ethernet(self->cyw, self->itf, buf.len, buf.buf, false); + if (ret) { + mp_raise_OSError(-ret); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(network_cyw43_send_ethernet_obj, network_cyw43_send_ethernet); + +STATIC mp_obj_t network_cyw43_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t buf_in) { + network_cyw43_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_buffer_info_t buf; + mp_get_buffer_raise(buf_in, &buf, MP_BUFFER_READ | MP_BUFFER_WRITE); + cyw43_ioctl(self->cyw, mp_obj_get_int(cmd_in), buf.len, buf.buf, self->itf); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(network_cyw43_ioctl_obj, network_cyw43_ioctl); + +/*******************************************************************************/ +// network API + +STATIC mp_obj_t network_cyw43_deinit(mp_obj_t self_in) { + network_cyw43_obj_t *self = MP_OBJ_TO_PTR(self_in); + cyw43_deinit(self->cyw); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_cyw43_deinit_obj, network_cyw43_deinit); + +STATIC mp_obj_t network_cyw43_active(size_t n_args, const mp_obj_t *args) { + network_cyw43_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args == 1) { + return mp_obj_new_bool(cyw43_tcpip_link_status(self->cyw, self->itf)); + } else { + cyw43_wifi_set_up(self->cyw, self->itf, mp_obj_is_true(args[1])); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_cyw43_active_obj, 1, 2, network_cyw43_active); + +STATIC int network_cyw43_scan_cb(void *env, const cyw43_ev_scan_result_t *res) { + mp_obj_t list = MP_OBJ_FROM_PTR(env); + + // Search for existing BSSID to remove duplicates + bool found = false; + size_t len; + mp_obj_t *items; + mp_obj_get_array(list, &len, &items); + for (size_t i = 0; i < len; ++i) { + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(items[i]); + if (memcmp(res->bssid, ((mp_obj_str_t*)MP_OBJ_TO_PTR(t->items[1]))->data, sizeof(res->bssid)) == 0) { + if (res->rssi > MP_OBJ_SMALL_INT_VALUE(t->items[3])) { + t->items[3] = MP_OBJ_NEW_SMALL_INT(res->rssi); + } + t->items[5] = MP_OBJ_NEW_SMALL_INT(MP_OBJ_SMALL_INT_VALUE(t->items[5]) + 1); + found = true; + break; + } + } + + // Add to list of results if wanted + if (!found) { + mp_obj_t tuple[6] = { + mp_obj_new_bytes(res->ssid, res->ssid_len), + mp_obj_new_bytes(res->bssid, sizeof(res->bssid)), + MP_OBJ_NEW_SMALL_INT(res->channel), + MP_OBJ_NEW_SMALL_INT(res->rssi), + MP_OBJ_NEW_SMALL_INT(res->auth_mode), + //mp_const_false, // hidden + MP_OBJ_NEW_SMALL_INT(1), // N + }; + mp_obj_list_append(list, mp_obj_new_tuple(6, tuple)); + } + + return 0; // continue scan +} + +STATIC mp_obj_t network_cyw43_scan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_passive, ARG_essid, ARG_bssid }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_passive, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_essid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_bssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + }; + + network_cyw43_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); + + cyw43_wifi_scan_options_t opts; + opts.scan_type = args[ARG_passive].u_bool ? 1 : 0; + if (args[ARG_essid].u_obj == mp_const_none) { + opts.ssid_len = 0; + } else { + mp_buffer_info_t ssid; + mp_get_buffer_raise(args[ARG_essid].u_obj, &ssid, MP_BUFFER_READ); + opts.ssid_len = MIN(ssid.len, sizeof(opts.ssid)); + memcpy(opts.ssid, ssid.buf, opts.ssid_len); + } + if (args[ARG_bssid].u_obj == mp_const_none) { + memset(opts.bssid, 0xff, sizeof(opts.bssid)); + } else { + mp_buffer_info_t bssid; + mp_get_buffer_raise(args[ARG_bssid].u_obj, &bssid, MP_BUFFER_READ); + memcpy(opts.bssid, bssid.buf, sizeof(opts.bssid)); + } + + mp_obj_t res = mp_obj_new_list(0, NULL); + int scan_res = cyw43_wifi_scan(self->cyw, &opts, MP_OBJ_TO_PTR(res), network_cyw43_scan_cb); + + if (scan_res < 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "STA must be active")); + } + + // Wait for scan to finish, with a 10s timeout + uint32_t start = mp_hal_ticks_ms(); + while (cyw43_wifi_scan_active(self->cyw) && mp_hal_ticks_ms() - start < 10000) { + MICROPY_EVENT_POLL_HOOK + } + + return res; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(network_cyw43_scan_obj, 1, network_cyw43_scan); + +STATIC mp_obj_t network_cyw43_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_essid, ARG_key, ARG_auth, ARG_bssid, ARG_channel }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_essid, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_key, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_auth, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_bssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_channel, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + }; + + network_cyw43_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); + + mp_buffer_info_t ssid; + mp_get_buffer_raise(args[ARG_essid].u_obj, &ssid, MP_BUFFER_READ); + mp_buffer_info_t key; + key.buf = NULL; + if (args[ARG_key].u_obj != mp_const_none) { + mp_get_buffer_raise(args[ARG_key].u_obj, &key, MP_BUFFER_READ); + } + mp_buffer_info_t bssid; + bssid.buf = NULL; + if (args[ARG_bssid].u_obj != mp_const_none) { + mp_get_buffer_raise(args[ARG_bssid].u_obj, &bssid, MP_BUFFER_READ); + if (bssid.len != 6) { + mp_raise_ValueError(NULL); + } + } + int ret = cyw43_wifi_join(self->cyw, ssid.len, ssid.buf, key.len, key.buf, args[ARG_auth].u_int, bssid.buf, args[ARG_channel].u_int); + if (ret != 0) { + mp_raise_OSError(ret); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(network_cyw43_connect_obj, 1, network_cyw43_connect); + +STATIC mp_obj_t network_cyw43_disconnect(mp_obj_t self_in) { + network_cyw43_obj_t *self = MP_OBJ_TO_PTR(self_in); + cyw43_wifi_leave(self->cyw, self->itf); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_cyw43_disconnect_obj, network_cyw43_disconnect); + +STATIC mp_obj_t network_cyw43_isconnected(mp_obj_t self_in) { + network_cyw43_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bool(cyw43_tcpip_link_status(self->cyw, self->itf) == 3); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_cyw43_isconnected_obj, network_cyw43_isconnected); + +STATIC mp_obj_t network_cyw43_ifconfig(size_t n_args, const mp_obj_t *args) { + network_cyw43_obj_t *self = MP_OBJ_TO_PTR(args[0]); + return mod_network_nic_ifconfig(&self->cyw->netif[self->itf], n_args - 1, args + 1); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_cyw43_ifconfig_obj, 1, 2, network_cyw43_ifconfig); + +STATIC mp_obj_t network_cyw43_status(size_t n_args, const mp_obj_t *args) { + network_cyw43_obj_t *self = MP_OBJ_TO_PTR(args[0]); + (void)self; + + if (n_args == 1) { + // no arguments: return link status + return MP_OBJ_NEW_SMALL_INT(cyw43_tcpip_link_status(self->cyw, self->itf)); + } + + // one argument: return status based on query parameter + switch (mp_obj_str_get_qstr(args[1])) { + case MP_QSTR_stations: { + // return list of connected stations + if (self->itf != CYW43_ITF_AP) { + mp_raise_ValueError("AP required"); + } + int num_stas; + uint8_t macs[32 * 6]; + cyw43_wifi_ap_get_stas(self->cyw, &num_stas, macs); + mp_obj_t list = mp_obj_new_list(num_stas, NULL); + for (int i = 0; i < num_stas; ++i) { + mp_obj_t tuple[1] = { + mp_obj_new_bytes(&macs[i * 6], 6), + }; + ((mp_obj_list_t*)MP_OBJ_TO_PTR(list))->items[i] = mp_obj_new_tuple(1, tuple); + } + return list; + } + } + + mp_raise_ValueError("unknown status param"); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_cyw43_status_obj, 1, 2, network_cyw43_status); + +static inline uint32_t nw_get_le32(const uint8_t *buf) { + return buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24; +} + +static inline void nw_put_le32(uint8_t *buf, uint32_t x) { + buf[0] = x; + buf[1] = x >> 8; + buf[2] = x >> 16; + buf[3] = x >> 24; +} + +STATIC mp_obj_t network_cyw43_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + network_cyw43_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_antenna: { + uint8_t buf[4]; + cyw43_ioctl(self->cyw, CYW43_IOCTL_GET_ANTDIV, 4, buf, self->itf); + return MP_OBJ_NEW_SMALL_INT(nw_get_le32(buf)); + } + case MP_QSTR_channel: { + uint8_t buf[4]; + cyw43_ioctl(self->cyw, CYW43_IOCTL_GET_CHANNEL, 4, buf, self->itf); + return MP_OBJ_NEW_SMALL_INT(nw_get_le32(buf)); + } + case MP_QSTR_essid: { + if (self->itf == CYW43_ITF_STA) { + uint8_t buf[36]; + cyw43_ioctl(self->cyw, CYW43_IOCTL_GET_SSID, 36, buf, self->itf); + return mp_obj_new_str((const char*)buf + 4, nw_get_le32(buf)); + } else { + size_t len; + const uint8_t *buf; + cyw43_wifi_ap_get_ssid(self->cyw, &len, &buf); + return mp_obj_new_str((const char*)buf, len); + } + } + case MP_QSTR_mac: { + uint8_t buf[6]; + cyw43_wifi_get_mac(self->cyw, self->itf, buf); + return mp_obj_new_bytes(buf, 6); + } + case MP_QSTR_txpower: { + uint8_t buf[13]; + memcpy(buf, "qtxpower\x00\x00\x00\x00\x00", 13); + cyw43_ioctl(self->cyw, CYW43_IOCTL_GET_VAR, 13, buf, self->itf); + return MP_OBJ_NEW_SMALL_INT(nw_get_le32(buf) / 4); + } + 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"); + } + + for (size_t i = 0; i < kwargs->alloc; ++i) { + if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) { + mp_map_elem_t *e = &kwargs->table[i]; + switch (mp_obj_str_get_qstr(e->key)) { + case MP_QSTR_antenna: { + uint8_t buf[4]; + nw_put_le32(buf, mp_obj_get_int(e->value)); + cyw43_ioctl(self->cyw, CYW43_IOCTL_SET_ANTDIV, 4, buf, self->itf); + break; + } + case MP_QSTR_channel: { + cyw43_wifi_ap_set_channel(self->cyw, mp_obj_get_int(e->value)); + break; + } + case MP_QSTR_essid: { + size_t len; + const char *str = mp_obj_str_get_data(e->value, &len); + cyw43_wifi_ap_set_ssid(self->cyw, len, (const uint8_t*)str); + break; + } + case MP_QSTR_monitor: { + mp_int_t value = mp_obj_get_int(e->value); + uint8_t buf[9 + 4]; + memcpy(buf, "allmulti\x00", 9); + nw_put_le32(buf + 9, value); + cyw43_ioctl(self->cyw, CYW43_IOCTL_SET_VAR, 9 + 4, buf, self->itf); + nw_put_le32(buf, value); + cyw43_ioctl(self->cyw, CYW43_IOCTL_SET_MONITOR, 4, buf, self->itf); + if (value) { + self->cyw->trace_flags |= CYW43_TRACE_MAC; + } else { + self->cyw->trace_flags &= ~CYW43_TRACE_MAC; + } + break; + } + case MP_QSTR_password: { + size_t len; + const char *str = mp_obj_str_get_data(e->value, &len); + cyw43_wifi_ap_set_password(self->cyw, len, (const uint8_t*)str); + break; + } + case MP_QSTR_pm: { + cyw43_wifi_pm(self->cyw, mp_obj_get_int(e->value)); + break; + } + case MP_QSTR_trace: { + self->cyw->trace_flags = mp_obj_get_int(e->value); + break; + } + case MP_QSTR_txpower: { + mp_int_t dbm = mp_obj_get_int(e->value); + uint8_t buf[9 + 4]; + memcpy(buf, "qtxpower\x00", 9); + nw_put_le32(buf + 9, dbm * 4); + cyw43_ioctl(self->cyw, CYW43_IOCTL_SET_VAR, 9 + 4, buf, self->itf); + break; + } + default: + mp_raise_ValueError("unknown config param"); + } + } + } + + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(network_cyw43_config_obj, 1, network_cyw43_config); + +/*******************************************************************************/ +// class bindings + +STATIC const mp_rom_map_elem_t network_cyw43_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_send_ethernet), MP_ROM_PTR(&network_cyw43_send_ethernet_obj) }, + { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&network_cyw43_ioctl_obj) }, + + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&network_cyw43_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&network_cyw43_active_obj) }, + { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&network_cyw43_scan_obj) }, + { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&network_cyw43_connect_obj) }, + { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&network_cyw43_disconnect_obj) }, + { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&network_cyw43_isconnected_obj) }, + { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&network_cyw43_ifconfig_obj) }, + { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&network_cyw43_status_obj) }, + { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&network_cyw43_config_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(network_cyw43_locals_dict, network_cyw43_locals_dict_table); + +const mp_obj_type_t mp_network_cyw43_type = { + { &mp_type_type }, + .name = MP_QSTR_CYW43, + .print = network_cyw43_print, + .make_new = network_cyw43_make_new, + .locals_dict = (mp_obj_dict_t*)&network_cyw43_locals_dict, +}; + +#endif // MICROPY_PY_NETWORK_CYW43 diff --git a/extmod/network_cyw43.h b/extmod/network_cyw43.h new file mode 100644 index 0000000000..4228bf6e8f --- /dev/null +++ b/extmod/network_cyw43.h @@ -0,0 +1,31 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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_NETWORK_CYW43_H +#define MICROPY_INCLUDED_EXTMOD_NETWORK_CYW43_H + +extern const mp_obj_type_t mp_network_cyw43_type; + +#endif // MICROPY_INCLUDED_EXTMOD_NETWORK_CYW43_H From 345e9864aac03693eec6cddd09a0dcd47df9c453 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 1 Jun 2019 16:06:25 +1000 Subject: [PATCH 0416/1788] stm32/modpyb: Add pyb.country() function to set the country. To be used for peripherals (like radio) that must be location aware. --- ports/stm32/factoryreset.c | 1 + ports/stm32/modpyb.c | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/ports/stm32/factoryreset.c b/ports/stm32/factoryreset.c index 6b0c289a78..24e0ff88cf 100644 --- a/ports/stm32/factoryreset.c +++ b/ports/stm32/factoryreset.c @@ -35,6 +35,7 @@ static const char fresh_boot_py[] = "\r\n" "import machine\r\n" "import pyb\r\n" +"pyb.country('US') # ISO 3166-1 Alpha-2 code, eg US, GB, DE, AU\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" diff --git a/ports/stm32/modpyb.c b/ports/stm32/modpyb.c index 85c6ee1381..c3e60caebb 100644 --- a/ports/stm32/modpyb.c +++ b/ports/stm32/modpyb.c @@ -56,6 +56,8 @@ #include "extmod/vfs.h" #include "extmod/utime_mphal.h" +char pyb_country_code[2]; + STATIC mp_obj_t pyb_fault_debug(mp_obj_t value) { pyb_hard_fault_debug = mp_obj_is_true(value); return mp_const_none; @@ -112,6 +114,22 @@ STATIC mp_obj_t pyb_repl_uart(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_repl_uart_obj, 0, 1, pyb_repl_uart); +STATIC mp_obj_t pyb_country(size_t n_args, const mp_obj_t *args) { + if (n_args == 0) { + return mp_obj_new_str(pyb_country_code, 2); + } else { + size_t len; + const char *str = mp_obj_str_get_data(args[0], &len); + if (len != 2) { + mp_raise_ValueError(NULL); + } + pyb_country_code[0] = str[0]; + pyb_country_code[1] = str[1]; + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_country_obj, 0, 1, pyb_country); + STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_pyb) }, @@ -139,6 +157,7 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { #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) }, + { MP_ROM_QSTR(MP_QSTR_country), MP_ROM_PTR(&pyb_country_obj) }, #if MICROPY_HW_ENABLE_USB { MP_ROM_QSTR(MP_QSTR_usb_mode), MP_ROM_PTR(&pyb_usb_mode_obj) }, From 10e173aaeadd589653fda89da34766322b77059d Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 1 Jun 2019 16:08:11 +1000 Subject: [PATCH 0417/1788] stm32/extint: Add extint_set() function for internal C access to EXTI. --- ports/stm32/extint.c | 50 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/ports/stm32/extint.c b/ports/stm32/extint.c index 59b20d5bd9..1f147d42dc 100644 --- a/ports/stm32/extint.c +++ b/ports/stm32/extint.c @@ -297,6 +297,53 @@ void extint_register_pin(const pin_obj_t *pin, uint32_t mode, bool hard_irq, mp_ } } +void extint_set(const pin_obj_t *pin, uint32_t mode) { + uint32_t line = pin->pin; + + mp_obj_t *cb = &MP_STATE_PORT(pyb_extint_callback)[line]; + + extint_disable(line); + + *cb = MP_OBJ_SENTINEL; + + pyb_extint_mode[line] = (mode & 0x00010000) ? // GPIO_MODE_IT == 0x00010000 + EXTI_Mode_Interrupt : EXTI_Mode_Event; + + { + // Configure and enable the callback + + pyb_extint_hard_irq[line] = 1; + pyb_extint_callback_arg[line] = MP_OBJ_FROM_PTR(pin); + + // Route the GPIO to EXTI + __HAL_RCC_SYSCFG_CLK_ENABLE(); + SYSCFG->EXTICR[line >> 2] = + (SYSCFG->EXTICR[line >> 2] & ~(0x0f << (4 * (line & 0x03)))) + | ((uint32_t)(GPIO_GET_INDEX(pin->gpio)) << (4 * (line & 0x03))); + + // Enable or disable the rising detector + if ((mode & GPIO_MODE_IT_RISING) == GPIO_MODE_IT_RISING) { + EXTI_RTSR |= 1 << line; + } else { + EXTI_RTSR &= ~(1 << line); + } + + // Enable or disable the falling detector + if ((mode & GPIO_MODE_IT_FALLING) == GPIO_MODE_IT_FALLING) { + EXTI_FTSR |= 1 << line; + } else { + EXTI_FTSR &= ~(1 << line); + } + + // Configure the NVIC + NVIC_SetPriority(IRQn_NONNEG(nvic_irq_channel[line]), IRQ_PRI_EXTINT); + HAL_NVIC_EnableIRQ(nvic_irq_channel[line]); + + // Enable the interrupt + extint_enable(line); + } +} + void extint_enable(uint line) { if (line >= EXTI_NUM_VECTORS) { return; @@ -552,6 +599,9 @@ const mp_obj_type_t extint_type = { void extint_init0(void) { for (int i = 0; i < PYB_EXTI_NUM_VECTORS; i++) { + if (MP_STATE_PORT(pyb_extint_callback)[i] == MP_OBJ_SENTINEL) { + continue; + } MP_STATE_PORT(pyb_extint_callback)[i] = mp_const_none; pyb_extint_mode[i] = EXTI_Mode_Interrupt; } From 370a8116c4348a849c2dafb2c90fa5ba12b8c5dc Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 1 Jun 2019 16:08:40 +1000 Subject: [PATCH 0418/1788] stm32/mphalport: Add support for having MAC in OTP region. --- ports/stm32/mphalport.c | 32 ++++++++++++++++++++++++++++++++ ports/stm32/mphalport.h | 1 + 2 files changed, 33 insertions(+) diff --git a/ports/stm32/mphalport.c b/ports/stm32/mphalport.c index c770b62d2e..f4ae7293c8 100644 --- a/ports/stm32/mphalport.c +++ b/ports/stm32/mphalport.c @@ -151,7 +151,30 @@ void mp_hal_pin_config_speed(mp_hal_pin_obj_t pin_obj, uint32_t speed) { gpio->OSPEEDR = (gpio->OSPEEDR & ~(3 << (2 * pin))) | (speed << (2 * pin)); } +/*******************************************************************************/ +// MAC address + +typedef struct _pyb_otp_t { + uint16_t series; + uint16_t rev; + uint8_t mac[6]; +} pyb_otp_t; + +#if defined(STM32F722xx) || defined(STM32F723xx) || defined(STM32F732xx) || defined(STM32F733xx) +#define OTP_ADDR (0x1ff079e0) +#else +#define OTP_ADDR (0x1ff0f3c0) +#endif +#define OTP ((pyb_otp_t*)OTP_ADDR) + MP_WEAK void mp_hal_get_mac(int idx, uint8_t buf[6]) { + // Check if OTP region has a valid MAC address, and use it if it does + if (OTP->series == 0x00d1 && OTP->mac[0] == 'H' && OTP->mac[1] == 'J' && OTP->mac[2] == '0') { + memcpy(buf, OTP->mac, 6); + buf[5] += idx; + return; + } + // Generate a random locally administered MAC address (LAA) uint8_t *id = (uint8_t *)MP_HAL_UNIQUE_ID_ADDRESS; buf[0] = 0x02; // LAA range @@ -161,3 +184,12 @@ MP_WEAK void mp_hal_get_mac(int idx, uint8_t buf[6]) { buf[4] = id[2]; buf[5] = (id[0] << 2) | idx; } + +void mp_hal_get_mac_ascii(int idx, size_t chr_off, size_t chr_len, char *dest) { + static const char hexchr[16] = "0123456789ABCDEF"; + uint8_t mac[6]; + mp_hal_get_mac(idx, mac); + for (; chr_len; ++chr_off, --chr_len) { + *dest++ = hexchr[mac[chr_off >> 1] >> (4 * (1 - (chr_off & 1))) & 0xf]; + } +} diff --git a/ports/stm32/mphalport.h b/ports/stm32/mphalport.h index d828bb9dd4..0c163fbf85 100644 --- a/ports/stm32/mphalport.h +++ b/ports/stm32/mphalport.h @@ -88,3 +88,4 @@ enum { }; void mp_hal_get_mac(int idx, uint8_t buf[6]); +void mp_hal_get_mac_ascii(int idx, size_t chr_off, size_t chr_len, char *dest); From 12ed6f91eeb1d338713b8ec189f6b0110a27dff0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 1 Jun 2019 16:09:03 +1000 Subject: [PATCH 0419/1788] stm32: Add low-level SDIO interface for cyw43 driver. --- ports/stm32/sdio.c | 353 +++++++++++++++++++++++++++++++++++++++++++++ ports/stm32/sdio.h | 38 +++++ 2 files changed, 391 insertions(+) create mode 100644 ports/stm32/sdio.c create mode 100644 ports/stm32/sdio.h diff --git a/ports/stm32/sdio.c b/ports/stm32/sdio.c new file mode 100644 index 0000000000..df4aec25e2 --- /dev/null +++ b/ports/stm32/sdio.c @@ -0,0 +1,353 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2019 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 "pendsv.h" +#include "sdio.h" + +#if MICROPY_PY_NETWORK_CYW43 + +#define DEFAULT_MASK (0) + +enum { + SDMMC_IRQ_STATE_DONE, + SDMMC_IRQ_STATE_CMD_DONE, + SDMMC_IRQ_STATE_CMD_DATA_PENDING, +}; + +static volatile int sdmmc_irq_state; +static volatile uint32_t sdmmc_block_size_log2; +static volatile bool sdmmc_write; +static volatile bool sdmmc_dma; +static volatile uint32_t sdmmc_error; +static volatile uint8_t *sdmmc_buf_cur; +static volatile uint8_t *sdmmc_buf_top; + +void sdio_init(uint32_t irq_pri) { + // configure IO pins + mp_hal_pin_config(pin_C8, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, 12); + mp_hal_pin_config(pin_C9, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, 12); + mp_hal_pin_config(pin_C10, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, 12); + mp_hal_pin_config(pin_C11, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, 12); + mp_hal_pin_config(pin_C12, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 12); // CLK doesn't need pull-up + mp_hal_pin_config(pin_D2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, 12); + + __HAL_RCC_SDMMC1_CLK_ENABLE(); // enable SDIO peripheral + + SDMMC_TypeDef *SDIO = SDMMC1; + SDIO->CLKCR = SDMMC_CLKCR_HWFC_EN | SDMMC_CLKCR_PWRSAV | 118; // 1-bit, 400kHz + mp_hal_delay_us(10); + SDIO->POWER = 3; // the card is clocked + mp_hal_delay_us(10); + SDIO->DCTRL = 1 << 10; // RWMOD is SDIO_CK + SDIO->CLKCR |= SDMMC_CLKCR_CLKEN; + mp_hal_delay_us(10); + + __HAL_RCC_DMA2_CLK_ENABLE(); // enable DMA2 peripheral + + NVIC_SetPriority(SDMMC1_IRQn, irq_pri); + + SDIO->MASK = 0; + HAL_NVIC_EnableIRQ(SDMMC1_IRQn); +} + +void sdio_deinit(void) { + RCC->APB2ENR &= ~RCC_APB2ENR_SDMMC1EN; // disable SDIO peripheral + RCC->AHB1ENR &= ~RCC_AHB1ENR_DMA2EN; // disable DMA2 peripheral +} + +void sdio_enable_high_speed_4bit(void) { + SDMMC_TypeDef *SDIO = SDMMC1; + SDIO->POWER = 0; // power off + mp_hal_delay_us(10); + SDIO->CLKCR = SDMMC_CLKCR_HWFC_EN | SDMMC_CLKCR_WIDBUS_0 | SDMMC_CLKCR_BYPASS /*| SDMMC_CLKCR_PWRSAV*/; // 4-bit, 48MHz + mp_hal_delay_us(10); + SDIO->POWER = 3; // the card is clocked + mp_hal_delay_us(10); + SDIO->DCTRL = 1 << 11 | 1 << 10; // SDIOEN, RWMOD is SDIO_CK + SDIO->CLKCR |= SDMMC_CLKCR_CLKEN; + SDIO->MASK = DEFAULT_MASK; + mp_hal_delay_us(10); +} + +void SDMMC1_IRQHandler(void) { + if (SDMMC1->STA & SDMMC_STA_CMDREND) { + SDMMC1->ICR = SDMMC_ICR_CMDRENDC; + uint32_t r1 = SDMMC1->RESP1; + if (SDMMC1->RESPCMD == 53 && r1 & 0x800) { + printf("bad RESP1: %lu %lx\n", SDMMC1->RESPCMD, r1); + sdmmc_error = 0xffffffff; + SDMMC1->MASK &= SDMMC_MASK_SDIOITIE; + sdmmc_irq_state = SDMMC_IRQ_STATE_DONE; + return; + } + if (sdmmc_buf_cur >= sdmmc_buf_top) { + // data transfer finished, so we are done + SDMMC1->MASK &= SDMMC_MASK_SDIOITIE; + sdmmc_irq_state = SDMMC_IRQ_STATE_DONE; + return; + } + if (sdmmc_write) { + SDMMC1->DCTRL = (sdmmc_block_size_log2 << 4) | 1 | (1 << 11) | (!sdmmc_write << 1) | (sdmmc_dma << 3) | (0 << 10); + if (!sdmmc_dma) { + SDMMC1->MASK |= SDMMC_MASK_TXFIFOHEIE; + } + } + sdmmc_irq_state = SDMMC_IRQ_STATE_CMD_DONE; + } else if (SDMMC1->STA & SDMMC_STA_DATAEND) { + // data transfer complete + // note: it's possible to get DATAEND before CMDREND + SDMMC1->ICR = SDMMC_ICR_DATAENDC; + // check if there is some remaining data in RXFIFO + if (!sdmmc_dma) { + while (SDMMC1->STA & SDMMC_STA_RXDAVL) { + *(uint32_t*)sdmmc_buf_cur = SDMMC1->FIFO; + sdmmc_buf_cur += 4; + } + } + if (sdmmc_irq_state == SDMMC_IRQ_STATE_CMD_DONE) { + // command and data finished, so we are done + SDMMC1->MASK &= SDMMC_MASK_SDIOITIE; + sdmmc_irq_state = SDMMC_IRQ_STATE_DONE; + } + } else if (SDMMC1->STA & SDMMC_STA_TXFIFOHE) { + if (!sdmmc_dma && sdmmc_write) { + // write up to 8 words to fifo + for (size_t i = 8; i && sdmmc_buf_cur < sdmmc_buf_top; --i) { + SDMMC1->FIFO = *(uint32_t*)sdmmc_buf_cur; + sdmmc_buf_cur += 4; + } + if (sdmmc_buf_cur >= sdmmc_buf_top) { + // finished, disable IRQ + SDMMC1->MASK &= ~SDMMC_MASK_TXFIFOHEIE; + } + } + } else if (SDMMC1->STA & SDMMC_STA_RXFIFOHF) { + if (!sdmmc_dma && !sdmmc_write) { + // read up to 8 words from fifo + for (size_t i = 8; i && sdmmc_buf_cur < sdmmc_buf_top; --i) { + *(uint32_t*)sdmmc_buf_cur = SDMMC1->FIFO; + sdmmc_buf_cur += 4; + } + } + } else if (SDMMC1->STA & SDMMC_STA_SDIOIT) { + SDMMC1->MASK &= ~SDMMC_MASK_SDIOITIE; + SDMMC1->ICR = SDMMC_ICR_SDIOITC; + + #if MICROPY_PY_NETWORK_CYW43 + extern void (*cyw43_poll)(void); + if (cyw43_poll) { + pendsv_schedule_dispatch(PENDSV_DISPATCH_CYW43, cyw43_poll); + } + #endif + } else if (SDMMC1->STA & 0x3f) { + // an error + sdmmc_error = SDMMC1->STA; + SDMMC1->ICR = SDMMC_STATIC_FLAGS; + SDMMC1->MASK &= SDMMC_MASK_SDIOITIE; + sdmmc_irq_state = SDMMC_IRQ_STATE_DONE; + } +} + +int sdio_transfer(uint32_t cmd, uint32_t arg, uint32_t *resp) { + // Wait for any outstanding TX to complete + while (SDMMC1->STA & SDMMC_STA_TXACT) { + } + + DMA2_Stream3->CR = 0; // ensure DMA is reset + SDMMC1->ICR = SDMMC_STATIC_FLAGS; // clear interrupts + SDMMC1->ARG = arg; + SDMMC1->CMD = cmd | SDMMC_CMD_WAITRESP_0 | SDMMC_CMD_CPSMEN; + + sdmmc_irq_state = SDMMC_IRQ_STATE_CMD_DATA_PENDING; + sdmmc_error = 0; + sdmmc_buf_cur = NULL; + sdmmc_buf_top = NULL; + SDMMC1->MASK = (SDMMC1->MASK & SDMMC_MASK_SDIOITIE) | SDMMC_MASK_CMDRENDIE | 0x3f; + + uint32_t start = mp_hal_ticks_ms(); + for (;;) { + __WFI(); + if (sdmmc_irq_state == SDMMC_IRQ_STATE_DONE) { + break; + } + if (mp_hal_ticks_ms() - start > 1000) { + SDMMC1->MASK = DEFAULT_MASK; + printf("sdio_transfer timeout STA=0x%08x\n", (uint)SDMMC1->STA); + return -MP_ETIMEDOUT; + } + } + + SDMMC1->MASK &= SDMMC_MASK_SDIOITIE; + + if (sdmmc_error == SDMMC_STA_CCRCFAIL && cmd == 5) { + // Errata: CMD CRC error is incorrectly generated for CMD 5 + return 0; + } else if (sdmmc_error) { + return -(0x1000000 | sdmmc_error); + } + + uint32_t rcmd = SDMMC1->RESPCMD; + if (rcmd != cmd) { + printf("sdio_transfer: cmd=%lu rcmd=%lu\n", cmd, rcmd); + return -MP_EIO; + } + if (resp != NULL) { + *resp = SDMMC1->RESP1; + } + return 0; +} + +int sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t len, uint8_t *buf) { + // Wait for any outstanding TX to complete + while (SDMMC1->STA & SDMMC_STA_TXACT) { + } + + // for SDIO_BYTE_MODE the SDIO chuck of data must be a single block of the length of buf + int block_size_log2 = 0; + if (block_size == 4) { + block_size_log2 = 2; + } else if (block_size == 8) { + block_size_log2 = 3; + } else if (block_size == 16) { + block_size_log2 = 4; + } else if (block_size == 32) { + block_size_log2 = 5; + } else if (block_size == 64) { + block_size_log2 = 6; + } else if (block_size == 128) { + block_size_log2 = 7; + } else if (block_size == 256) { + block_size_log2 = 8; + } else { + printf("sdio_transfer_cmd53: invalid block_size %lu", block_size); + return -MP_EINVAL; + } + + bool dma = (len > 16); + + SDMMC1->ICR = SDMMC_STATIC_FLAGS; // clear interrupts + SDMMC1->MASK &= SDMMC_MASK_SDIOITIE; + + SDMMC1->DTIMER = 0x2000000; // about 700ms running at 48MHz + SDMMC1->DLEN = (len + block_size - 1) & ~(block_size - 1); + + DMA2_Stream3->CR = 0; + + if (dma) { + // prepare DMA so it's ready when the DPSM starts its transfer + + // enable DMA2 peripheral in case it was turned off by someone else + RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN; + + if (write) { + // make sure cache is flushed to RAM so the DMA can read the correct data + MP_HAL_CLEAN_DCACHE(buf, len); + } else { + // make sure cache is flushed and invalidated so when DMA updates the RAM + // from reading the peripheral the CPU then reads the new data + MP_HAL_CLEANINVALIDATE_DCACHE(buf, len); + } + + DMA2->LIFCR = 0x3f << 22; + DMA2_Stream3->FCR = 0x07; // ? + DMA2_Stream3->PAR = (uint32_t)&SDMMC1->FIFO; + if ((uint32_t)buf & 3) { + printf("sdio_transfer_cmd53: buf=%p is not aligned for DMA\n", buf); + return -MP_EINVAL; + } + DMA2_Stream3->M0AR = (uint32_t)buf; + DMA2_Stream3->NDTR = ((len + block_size - 1) & ~(block_size - 1)) / 4; + DMA2_Stream3->CR = 4 << 25 // channel 4 + | 1 << 23 // MBURST INCR4 + | 1 << 21 // PBURST INCR4 + | 3 << 16 // PL very high + | 2 << 13 // MSIZE word + | 2 << 11 // PSIZE word + | 1 << 10 // MINC enabled + | 0 << 9 // PINC disabled + | write << 6 // DIR mem-to-periph + | 1 << 5 // PFCTRL periph is flow controller + | 1 << 0 // EN + ; + } + + // for reading, need to initialise the DPSM before starting the CPSM + // so that the DPSM is ready to receive when the device sends data + // (and in case we get a long-running unrelated IRQ here on the host just + // after writing to CMD to initiate the command) + if (!write) { + SDMMC1->DCTRL = (block_size_log2 << 4) | 1 | (1 << 11) | (!write << 1) | (dma << 3); + } + + SDMMC1->ARG = arg; + SDMMC1->CMD = 53 | SDMMC_CMD_WAITRESP_0 | SDMMC_CMD_CPSMEN; + + sdmmc_irq_state = SDMMC_IRQ_STATE_CMD_DATA_PENDING; + sdmmc_block_size_log2 = block_size_log2; + sdmmc_write = write; + sdmmc_dma = dma; + sdmmc_error = 0; + sdmmc_buf_cur = (uint8_t*)buf; + sdmmc_buf_top = (uint8_t*)buf + len; + SDMMC1->MASK = (SDMMC1->MASK & SDMMC_MASK_SDIOITIE) | SDMMC_MASK_CMDRENDIE | SDMMC_MASK_DATAENDIE | SDMMC_MASK_RXFIFOHFIE | 0x3f; + + // wait to complete transfer + uint32_t start = mp_hal_ticks_ms(); + for (;;) { + __WFI(); + if (sdmmc_irq_state == SDMMC_IRQ_STATE_DONE) { + break; + } + if (mp_hal_ticks_ms() - start > 200) { + SDMMC1->MASK &= SDMMC_MASK_SDIOITIE; + printf("sdio_transfer_cmd53: timeout wr=%d len=%u dma=%u buf_idx=%u STA=%08x SDMMC=%08x:%08x DMA=%08x:%08x:%08x RCC=%08x\n", write, (uint)len, (uint)dma, sdmmc_buf_cur - buf, (uint)SDMMC1->STA, (uint)SDMMC1->DCOUNT, (uint)SDMMC1->FIFOCNT, (uint)DMA2->LISR, (uint)DMA2->HISR, (uint)DMA2_Stream3->NDTR, (uint)RCC->AHB1ENR); + return -MP_ETIMEDOUT; + } + } + + SDMMC1->MASK &= SDMMC_MASK_SDIOITIE; + + if (sdmmc_error) { + printf("sdio_transfer_cmd53: error=%08lx wr=%d len=%u dma=%u buf_idx=%u STA=%08x SDMMC=%08x:%08x DMA=%08x:%08x:%08x RCC=%08x\n", sdmmc_error, write, (uint)len, (uint)dma, sdmmc_buf_cur - buf, (uint)SDMMC1->STA, (uint)SDMMC1->DCOUNT, (uint)SDMMC1->FIFOCNT, (uint)DMA2->LISR, (uint)DMA2->HISR, (uint)DMA2_Stream3->NDTR, (uint)RCC->AHB1ENR); + return -(0x1000000 | sdmmc_error); + } + + if (!sdmmc_dma) { + if (sdmmc_buf_cur != sdmmc_buf_top) { + printf("sdio_transfer_cmd53: didn't transfer correct length: cur=%p top=%p\n", sdmmc_buf_cur, sdmmc_buf_top); + return -MP_EIO; + } + } + + return 0; +} + +#endif diff --git a/ports/stm32/sdio.h b/ports/stm32/sdio.h new file mode 100644 index 0000000000..e7115e6f80 --- /dev/null +++ b/ports/stm32/sdio.h @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2019 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_SDIO_H +#define MICROPY_INCLUDED_STM32_SDIO_H + +#include +#include + +void sdio_init(uint32_t irq_pri); +void sdio_deinit(void); +void sdio_enable_high_speed_4bit(void); +int sdio_transfer(uint32_t cmd, uint32_t arg, uint32_t *resp); +int sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t len, uint8_t *buf); + +#endif // MICROPY_INCLUDED_STM32_SDIO_H From 8b7409c295ff243699ed6fa6bab1e18659b064cd Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 1 Jun 2019 16:11:03 +1000 Subject: [PATCH 0420/1788] stm32: Integrate in the cyw43 driver and network.WLAN class. Enable it by setting MICROPY_PY_NETWORK_CYW43=1 at the Makefile level. --- ports/stm32/Makefile | 9 +++++++++ ports/stm32/extint.c | 10 ++++++++++ ports/stm32/main.c | 12 ++++++++++++ ports/stm32/modnetwork.c | 21 +++++++++++++++++++++ ports/stm32/pendsv.h | 3 +++ 5 files changed, 55 insertions(+) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 943acd4943..6a44ff30b3 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -116,6 +116,7 @@ SRC_LIB = $(addprefix lib/,\ mp-readline/readline.c \ netutils/netutils.c \ netutils/trace.c \ + netutils/dhcpserver.c \ timeutils/timeutils.c \ utils/pyexec.c \ utils/interrupt_char.c \ @@ -351,6 +352,14 @@ SRC_USBDEV = $(addprefix $(USBDEV_DIR)/,\ class/src/usbd_msc_data.c \ ) +ifeq ($(MICROPY_PY_NETWORK_CYW43),1) +CFLAGS_MOD += -DMICROPY_PY_NETWORK_CYW43=1 +SRC_C += sdio.c +EXTMOD_SRC_C += extmod/network_cyw43.c +DRIVERS_SRC_C += drivers/cyw43/cyw43_ctrl.c drivers/cyw43/cyw43_lwip.c +LIBS += $(TOP)/drivers/cyw43/libcyw43.a +endif + ifneq ($(MICROPY_PY_WIZNET5K),0) WIZNET5K_DIR=drivers/wiznet5k INC += -I$(TOP)/$(WIZNET5K_DIR) diff --git a/ports/stm32/extint.c b/ports/stm32/extint.c index 1f147d42dc..4a67d1824f 100644 --- a/ports/stm32/extint.c +++ b/ports/stm32/extint.c @@ -31,6 +31,7 @@ #include "py/runtime.h" #include "py/gc.h" #include "py/mphal.h" +#include "pendsv.h" #include "pin.h" #include "extint.h" #include "irq.h" @@ -613,6 +614,15 @@ void Handle_EXTI_Irq(uint32_t line) { __HAL_GPIO_EXTI_CLEAR_FLAG(1 << line); if (line < EXTI_NUM_VECTORS) { mp_obj_t *cb = &MP_STATE_PORT(pyb_extint_callback)[line]; + #if MICROPY_PY_NETWORK_CYW43 && defined(pyb_pin_WL_HOST_WAKE) + if (pyb_extint_callback_arg[line] == MP_OBJ_FROM_PTR(pyb_pin_WL_HOST_WAKE)) { + extern void (*cyw43_poll)(void); + if (cyw43_poll) { + pendsv_schedule_dispatch(PENDSV_DISPATCH_CYW43, cyw43_poll); + } + return; + } + #endif if (*cb != mp_const_none) { // If it's a soft IRQ handler then just schedule callback for later if (!pyb_extint_hard_irq[line]) { diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 02449a1b80..5bb425ddf3 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -39,6 +39,7 @@ #if MICROPY_PY_LWIP #include "lwip/init.h" +#include "drivers/cyw43/cyw43.h" #endif #include "systick.h" @@ -481,6 +482,17 @@ void stm32_main(uint32_t reset_mode) { systick_enable_dispatch(SYSTICK_DISPATCH_LWIP, mod_network_lwip_poll_wrapper); #endif + #if MICROPY_PY_NETWORK_CYW43 + { + cyw43_init(&cyw43_state); + uint8_t buf[8]; + memcpy(&buf[0], "PYBD", 4); + mp_hal_get_mac_ascii(MP_HAL_MAC_WLAN0, 8, 4, (char*)&buf[4]); + cyw43_wifi_ap_set_ssid(&cyw43_state, 8, buf); + cyw43_wifi_ap_set_password(&cyw43_state, 8, (const uint8_t*)"pybd0123"); + } + #endif + #if defined(MICROPY_HW_UART_REPL) // Set up a UART REPL using a statically allocated object pyb_uart_repl_obj.base.type = &pyb_uart_type; diff --git a/ports/stm32/modnetwork.c b/ports/stm32/modnetwork.c index ea43f75573..9d97ad4a0e 100644 --- a/ports/stm32/modnetwork.c +++ b/ports/stm32/modnetwork.c @@ -44,6 +44,8 @@ #include "lwip/timeouts.h" #include "lwip/dns.h" #include "lwip/dhcp.h" +#include "extmod/network_cyw43.h" +#include "drivers/cyw43/cyw43.h" // Poll lwIP every 128ms #define LWIP_TICK(tick) (((tick) & ~(SYSTICK_DISPATCH_NUM_SLOTS - 1) & 0x7f) == 0) @@ -70,6 +72,16 @@ void mod_network_lwip_poll_wrapper(uint32_t ticks_ms) { if (LWIP_TICK(ticks_ms)) { pendsv_schedule_dispatch(PENDSV_DISPATCH_LWIP, pyb_lwip_poll); } + + #if MICROPY_PY_NETWORK_CYW43 + if (cyw43_poll) { + if (cyw43_sleep != 0) { + if (--cyw43_sleep == 0) { + pendsv_schedule_dispatch(PENDSV_DISPATCH_CYW43, cyw43_poll); + } + } + } + #endif } #endif @@ -119,6 +131,9 @@ STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = { #if defined(MICROPY_HW_ETH_MDC) { MP_ROM_QSTR(MP_QSTR_LAN), MP_ROM_PTR(&network_lan_type) }, #endif + #if MICROPY_PY_NETWORK_CYW43 + { MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&mp_network_cyw43_type) }, + #endif #if MICROPY_PY_WIZNET5K { MP_ROM_QSTR(MP_QSTR_WIZNET5K), MP_ROM_PTR(&mod_network_nic_type_wiznet5k) }, @@ -128,6 +143,12 @@ STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = { #endif { MP_ROM_QSTR(MP_QSTR_route), MP_ROM_PTR(&network_route_obj) }, + + // Constants + #if MICROPY_PY_NETWORK_CYW43 + { MP_ROM_QSTR(MP_QSTR_STA_IF), MP_ROM_INT(CYW43_ITF_STA)}, + { MP_ROM_QSTR(MP_QSTR_AP_IF), MP_ROM_INT(CYW43_ITF_AP)}, + #endif }; STATIC MP_DEFINE_CONST_DICT(mp_module_network_globals, mp_module_network_globals_table); diff --git a/ports/stm32/pendsv.h b/ports/stm32/pendsv.h index 18ae1d63e9..6cbfe8b2ec 100644 --- a/ports/stm32/pendsv.h +++ b/ports/stm32/pendsv.h @@ -29,6 +29,9 @@ enum { #if MICROPY_PY_NETWORK && MICROPY_PY_LWIP PENDSV_DISPATCH_LWIP, + #if MICROPY_PY_NETWORK_CYW43 + PENDSV_DISPATCH_CYW43, + #endif #endif PENDSV_DISPATCH_MAX }; From 62fe47aa3a96056e03e4dffdf50a924f0cac1f06 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 1 Jun 2019 16:12:10 +1000 Subject: [PATCH 0421/1788] stm32/boards/PYBD_SFx: Enable CYW43 WLAN driver. --- ports/stm32/boards/PYBD_SF2/f722_qspi.ld | 9 +++++++++ ports/stm32/boards/PYBD_SF2/mpconfigboard.mk | 4 ++++ ports/stm32/boards/PYBD_SF3/mpconfigboard.mk | 1 + ports/stm32/boards/PYBD_SF6/f767.ld | 3 +++ ports/stm32/boards/PYBD_SF6/mpconfigboard.mk | 1 + 5 files changed, 18 insertions(+) diff --git a/ports/stm32/boards/PYBD_SF2/f722_qspi.ld b/ports/stm32/boards/PYBD_SF2/f722_qspi.ld index 8cafb0abe6..49b46bce50 100644 --- a/ports/stm32/boards/PYBD_SF2/f722_qspi.ld +++ b/ports/stm32/boards/PYBD_SF2/f722_qspi.ld @@ -7,6 +7,8 @@ FLASH_APP .text FLASH_APP .data + FLASH_EXT .big_const + RAM .data RAM .bss RAM .heap @@ -43,6 +45,13 @@ ENTRY(Reset_Handler) /* Define output sections */ SECTIONS { + .text_ext : + { + . = ALIGN(512); + *(.big_const*) + . = ALIGN(4); + } >FLASH_EXT + .isr_vector : { . = ALIGN(4); diff --git a/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk b/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk index 87e3970656..98103e1405 100644 --- a/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk +++ b/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk @@ -5,6 +5,10 @@ MICROPY_FLOAT_IMPL = single AF_FILE = boards/stm32f722_af.csv LD_FILES = boards/PYBD_SF2/f722_qspi.ld TEXT0_ADDR = 0x08008000 +TEXT1_ADDR = 0x90000000 +TEXT0_SECTIONS = .isr_vector .text .data +TEXT1_SECTIONS = .text_ext # MicroPython settings MICROPY_PY_LWIP = 1 +MICROPY_PY_NETWORK_CYW43 = 1 diff --git a/ports/stm32/boards/PYBD_SF3/mpconfigboard.mk b/ports/stm32/boards/PYBD_SF3/mpconfigboard.mk index 6104ed2475..924a0f3d55 100644 --- a/ports/stm32/boards/PYBD_SF3/mpconfigboard.mk +++ b/ports/stm32/boards/PYBD_SF3/mpconfigboard.mk @@ -11,3 +11,4 @@ TEXT1_SECTIONS = .text_ext # MicroPython settings MICROPY_PY_LWIP = 1 +MICROPY_PY_NETWORK_CYW43 = 1 diff --git a/ports/stm32/boards/PYBD_SF6/f767.ld b/ports/stm32/boards/PYBD_SF6/f767.ld index d910438a7e..7f13eb45fe 100644 --- a/ports/stm32/boards/PYBD_SF6/f767.ld +++ b/ports/stm32/boards/PYBD_SF6/f767.ld @@ -5,6 +5,7 @@ FLASH_APP .isr_vector FLASH_APP .text + FLASH_APP .big_const FLASH_APP .data RAM .data @@ -55,6 +56,8 @@ SECTIONS . = ALIGN(4); *(.text*) *(.rodata*) + . = ALIGN(512); + *(.big_const*) . = ALIGN(4); _etext = .; } >FLASH_APP diff --git a/ports/stm32/boards/PYBD_SF6/mpconfigboard.mk b/ports/stm32/boards/PYBD_SF6/mpconfigboard.mk index 0288b9142c..5018123272 100644 --- a/ports/stm32/boards/PYBD_SF6/mpconfigboard.mk +++ b/ports/stm32/boards/PYBD_SF6/mpconfigboard.mk @@ -8,3 +8,4 @@ TEXT0_ADDR = 0x08008000 # MicroPython settings MICROPY_PY_LWIP = 1 +MICROPY_PY_NETWORK_CYW43 = 1 From ce8262a164d33d222de55677523593806404176e Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 3 Jun 2019 17:06:35 +1000 Subject: [PATCH 0422/1788] stm32/modnetwork: Replace generic netif NIC polling with specific code. It doesn't work to tie the polling of an underlying NIC driver (eg to check the NIC for pending Ethernet frames) with its associated lwIP netif. This is because most NICs are implemented with IRQs and don't need polling, because there can be multiple lwIP netif's per NIC driver, and because it restricts the use of the netif->state variable. Instead the NIC should have its own specific way of processing incoming Ethernet frame. This patch removes this generic NIC polling feature, and for the only driver that uses it (Wiznet5k) replaces it with an explicit call to the poll function (which could eventually be improved by using a proper external interrupt). --- ports/stm32/eth.c | 1 - ports/stm32/modnetwork.c | 14 +++++--------- ports/stm32/modnetwork.h | 7 ++----- ports/stm32/network_wiznet5k.c | 17 +++++++++-------- 4 files changed, 16 insertions(+), 23 deletions(-) diff --git a/ports/stm32/eth.c b/ports/stm32/eth.c index 665495c174..6a1ef99afa 100644 --- a/ports/stm32/eth.c +++ b/ports/stm32/eth.c @@ -107,7 +107,6 @@ typedef struct _eth_dma_t { } eth_dma_t; typedef struct _eth_t { - mod_network_nic_type_t base; uint32_t trace_flags; struct netif netif; struct dhcp dhcp_struct; diff --git a/ports/stm32/modnetwork.c b/ports/stm32/modnetwork.c index 9d97ad4a0e..460f47257b 100644 --- a/ports/stm32/modnetwork.c +++ b/ports/stm32/modnetwork.c @@ -55,15 +55,11 @@ u32_t sys_now(void) { } STATIC 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; - if (nic->poll_callback) { - nic->poll_callback(nic, netif); - } - } - } + #if MICROPY_PY_WIZNET5K + // Poll the NIC for incoming data + wiznet5k_poll(); + #endif + // Run the lwIP internal updates sys_check_timeouts(); } diff --git a/ports/stm32/modnetwork.h b/ports/stm32/modnetwork.h index 41a0017dab..0b6d0c4a7f 100644 --- a/ports/stm32/modnetwork.h +++ b/ports/stm32/modnetwork.h @@ -39,17 +39,14 @@ struct netif; -typedef struct _mod_network_nic_type_t { - mp_obj_base_t base; - void (*poll_callback)(void *data, struct netif *netif); -} mod_network_nic_type_t; - extern const mp_obj_type_t network_lan_type; extern const mp_obj_type_t mod_network_nic_type_wiznet5k; void mod_network_lwip_poll_wrapper(uint32_t ticks_ms); mp_obj_t mod_network_nic_ifconfig(struct netif *netif, size_t n_args, const mp_obj_t *args); +void wiznet5k_poll(void); + #else struct _mod_network_socket_obj_t; diff --git a/ports/stm32/network_wiznet5k.c b/ports/stm32/network_wiznet5k.c index 3bbe639acc..796b5551a7 100644 --- a/ports/stm32/network_wiznet5k.c +++ b/ports/stm32/network_wiznet5k.c @@ -48,7 +48,7 @@ // Wiznet5k Ethernet driver in MACRAW mode typedef struct _wiznet5k_obj_t { - mod_network_nic_type_t base; + mp_obj_base_t base; mp_uint_t cris_state; const spi_t *spi; mp_hal_pin_obj_t cs; @@ -63,7 +63,6 @@ typedef struct _wiznet5k_obj_t { 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(); @@ -176,7 +175,7 @@ STATIC uint16_t wiznet5k_recv_ethernet(wiznet5k_obj_t *self) { 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); + printf("wiznet5k_poll: fatal error len=%u ret=%d\n", len, ret); netif_set_link_down(&self->netif); netif_set_down(&self->netif); return 0; @@ -237,8 +236,11 @@ STATIC void wiznet5k_lwip_init(wiznet5k_obj_t *self) { self->netif.flags &= ~NETIF_FLAG_UP; } -STATIC void wiznet5k_lwip_poll(void *self_in, struct netif *netif) { - wiznet5k_obj_t *self = self_in; +void wiznet5k_poll(void) { + wiznet5k_obj_t *self = &wiznet5k_obj; + if (!(self->netif.flags & NETIF_FLAG_LINK_UP)) { + return; + } uint16_t len; while ((len = wiznet5k_recv_ethernet(self)) > 0) { if (self->trace_flags & TRACE_ETH_RX) { @@ -267,7 +269,7 @@ STATIC mp_obj_t wiznet5k_make_new(const mp_obj_type_t *type, size_t n_args, size 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.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(); @@ -275,8 +277,7 @@ 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.base.type = &mod_network_nic_type_wiznet5k; - wiznet5k_obj.base.poll_callback = wiznet5k_lwip_poll; + wiznet5k_obj.base.type = &mod_network_nic_type_wiznet5k; wiznet5k_obj.cris_state = 0; wiznet5k_obj.spi = spi; wiznet5k_obj.cs = cs; From faf3d3e9e93a71b3947bf563e4ffe13cbd053cb8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 4 Jun 2019 22:13:32 +1000 Subject: [PATCH 0423/1788] tools/mpy-tool.py: Fix linking qstrs in native code, and multiple files. Fixes errors in the tool when 1) linking qstrs in native ARM-M code; 2) freezing multiple files some of which use native code and some which don't. Fixes issue #4829. --- tools/mpy-tool.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index c8216bb603..db6fe23833 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -4,7 +4,7 @@ # # The MIT License (MIT) # -# Copyright (c) 2016 Damien P. George +# Copyright (c) 2016-2019 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 @@ -479,18 +479,23 @@ class RawCodeNative(RawCode): def _link_qstr(self, pc, kind, qst): if kind == 0: + # Generic 16-bit link print(' %s & 0xff, %s >> 8,' % (qst, qst)) else: - if kind == 2: + # Architecture-specific link + is_obj = kind == 2 + if is_obj: qst = '((uintptr_t)MP_OBJ_NEW_QSTR(%s))' % qst if config.native_arch in (MP_NATIVE_ARCH_X86, MP_NATIVE_ARCH_X64): print(' %s & 0xff, %s >> 8, 0, 0,' % (qst, qst)) elif MP_NATIVE_ARCH_ARMV6M <= config.native_arch <= MP_NATIVE_ARCH_ARMV7EMDP: if is_obj: - self._asm_thumb_rewrite_mov(i, qst) - self._asm_thumb_rewrite_mov(i + 4, '(%s >> 16)' % qst) + # qstr object, movw and movt + self._asm_thumb_rewrite_mov(pc, qst) + self._asm_thumb_rewrite_mov(pc + 4, '(%s >> 16)' % qst) else: - self._asm_thumb_rewrite_mov(i, qst) + # qstr number, movw instruction + self._asm_thumb_rewrite_mov(pc, qst) else: assert 0 @@ -663,7 +668,7 @@ def read_raw_code(f, qstr_win): # load qstr link table n_qstr_link = read_uint(f) for _ in range(n_qstr_link): - off = read_uint(f, qstr_win) + off = read_uint(f) qst = read_qstr(f, qstr_win) qstr_links.append((off >> 2, off & 3, qst)) @@ -714,7 +719,12 @@ def read_mpy(filename): qw_size = read_uint(f) config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE = (feature_byte & 1) != 0 config.MICROPY_PY_BUILTINS_STR_UNICODE = (feature_byte & 2) != 0 - config.native_arch = feature_byte >> 2 + mpy_native_arch = feature_byte >> 2 + if mpy_native_arch != MP_NATIVE_ARCH_NONE: + if config.native_arch == MP_NATIVE_ARCH_NONE: + config.native_arch = mpy_native_arch + elif config.native_arch != mpy_native_arch: + raise Exception('native architecture mismatch') config.mp_small_int_bits = header[3] qstr_win = QStrWindow(qw_size) return read_raw_code(f, qstr_win) @@ -838,6 +848,7 @@ def main(): 'mpz':config.MICROPY_LONGINT_IMPL_MPZ, }[args.mlongint_impl] config.MPZ_DIG_SIZE = args.mmpz_dig_size + config.native_arch = MP_NATIVE_ARCH_NONE # set config values for qstrs, and get the existing base set of qstrs if args.qstr_header: From 7cf26ca4bd84134b9fbddaf032370e91326edb64 Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Tue, 4 Jun 2019 20:14:41 +0300 Subject: [PATCH 0424/1788] py/obj: Optimise small-int comparison to 0 in mp_obj_is_true. Instead of converting to a small-int at runtime this can be done at compile time, then we only have a simple comparison during runtime. This reduces code size on some ports (e.g -4 on qemu-arm, -52 on unix nanbox), and for others at least doesn't increase code size. --- py/obj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/obj.c b/py/obj.c index 122f0ea624..1797ee56be 100644 --- a/py/obj.c +++ b/py/obj.c @@ -113,7 +113,7 @@ bool mp_obj_is_true(mp_obj_t arg) { } else if (arg == mp_const_none) { return 0; } else if (mp_obj_is_small_int(arg)) { - if (MP_OBJ_SMALL_INT_VALUE(arg) == 0) { + if (arg == MP_OBJ_NEW_SMALL_INT(0)) { return 0; } else { return 1; From cd6b115815f8b618b27e2f49a7611de95983f6f4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 5 Jun 2019 14:23:12 +1000 Subject: [PATCH 0425/1788] extmod: Factor out makefile rules from py.mk to new extmod.mk file. To logically separate extmod related rules out, and prevent py.mk from growing too large. --- extmod/extmod.mk | 121 +++++++++++++++++++++++++++++++++++++++++++++++ py/py.mk | 113 ++----------------------------------------- 2 files changed, 124 insertions(+), 110 deletions(-) create mode 100644 extmod/extmod.mk diff --git a/extmod/extmod.mk b/extmod/extmod.mk new file mode 100644 index 0000000000..2143058f8f --- /dev/null +++ b/extmod/extmod.mk @@ -0,0 +1,121 @@ +# This makefile fragment provides rules to build 3rd-party components for extmod modules + +# this sets the config file for FatFs +CFLAGS_MOD += -DFFCONF_H=\"lib/oofatfs/ffconf.h\" + +################################################################################ +# ussl + +ifeq ($(MICROPY_PY_USSL),1) +CFLAGS_MOD += -DMICROPY_PY_USSL=1 +ifeq ($(MICROPY_SSL_AXTLS),1) +CFLAGS_MOD += -DMICROPY_SSL_AXTLS=1 -I$(TOP)/lib/axtls/ssl -I$(TOP)/lib/axtls/crypto -I$(TOP)/extmod/axtls-include +AXTLS_DIR = lib/axtls +$(BUILD)/$(AXTLS_DIR)/%.o: CFLAGS += -Wno-all -Wno-unused-parameter -Wno-uninitialized -Wno-sign-compare -Wno-old-style-definition $(AXTLS_DEFS_EXTRA) +SRC_MOD += $(addprefix $(AXTLS_DIR)/,\ + ssl/asn1.c \ + ssl/loader.c \ + ssl/tls1.c \ + ssl/tls1_svr.c \ + ssl/tls1_clnt.c \ + ssl/x509.c \ + crypto/aes.c \ + crypto/bigint.c \ + crypto/crypto_misc.c \ + crypto/hmac.c \ + crypto/md5.c \ + crypto/rsa.c \ + crypto/sha1.c \ + ) +else ifeq ($(MICROPY_SSL_MBEDTLS),1) +# Can be overridden by ports which have "builtin" mbedTLS +MICROPY_SSL_MBEDTLS_INCLUDE ?= $(TOP)/lib/mbedtls/include +CFLAGS_MOD += -DMICROPY_SSL_MBEDTLS=1 -I$(MICROPY_SSL_MBEDTLS_INCLUDE) +LDFLAGS_MOD += -L$(TOP)/lib/mbedtls/library -lmbedx509 -lmbedtls -lmbedcrypto +endif +endif + +################################################################################ +# lwip + +ifeq ($(MICROPY_PY_LWIP),1) +# A port should add an include path where lwipopts.h can be found (eg extmod/lwip-include) +LWIP_DIR = lib/lwip/src +INC += -I$(TOP)/$(LWIP_DIR)/include +CFLAGS_MOD += -DMICROPY_PY_LWIP=1 +$(BUILD)/$(LWIP_DIR)/core/ipv4/dhcp.o: CFLAGS_MOD += -Wno-address +SRC_MOD += extmod/modlwip.c lib/netutils/netutils.c +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 \ + ) +ifeq ($(MICROPY_PY_LWIP_SLIP),1) +CFLAGS_MOD += -DMICROPY_PY_LWIP_SLIP=1 +SRC_MOD += $(LWIP_DIR)/netif/slipif.c +endif +endif + +################################################################################ +# btree + +ifeq ($(MICROPY_PY_BTREE),1) +BTREE_DIR = lib/berkeley-db-1.xx +BTREE_DEFS = -D__DBINTERFACE_PRIVATE=1 -Dmpool_error=printf -Dabort=abort_ "-Dvirt_fd_t=void*" $(BTREE_DEFS_EXTRA) +INC += -I$(TOP)/$(BTREE_DIR)/PORT/include +SRC_MOD += extmod/modbtree.c +SRC_MOD += $(addprefix $(BTREE_DIR)/,\ + btree/bt_close.c \ + btree/bt_conv.c \ + btree/bt_debug.c \ + btree/bt_delete.c \ + btree/bt_get.c \ + btree/bt_open.c \ + btree/bt_overflow.c \ + btree/bt_page.c \ + btree/bt_put.c \ + btree/bt_search.c \ + btree/bt_seq.c \ + btree/bt_split.c \ + btree/bt_utils.c \ + mpool/mpool.c \ + ) +CFLAGS_MOD += -DMICROPY_PY_BTREE=1 +# we need to suppress certain warnings to get berkeley-db to compile cleanly +# and we have separate BTREE_DEFS so the definitions don't interfere with other source code +$(BUILD)/$(BTREE_DIR)/%.o: CFLAGS += -Wno-old-style-definition -Wno-sign-compare -Wno-unused-parameter $(BTREE_DEFS) +$(BUILD)/extmod/modbtree.o: CFLAGS += $(BTREE_DEFS) +endif + diff --git a/py/py.mk b/py/py.mk index 3d8d849e2b..e649297e68 100644 --- a/py/py.mk +++ b/py/py.mk @@ -19,116 +19,6 @@ QSTR_GLOBAL_DEPENDENCIES += $(PY_SRC)/mpconfig.h mpconfigport.h # some code is performance bottleneck and compiled with other optimization options CSUPEROPT = -O3 -# this sets the config file for FatFs -CFLAGS_MOD += -DFFCONF_H=\"lib/oofatfs/ffconf.h\" - -ifeq ($(MICROPY_PY_USSL),1) -CFLAGS_MOD += -DMICROPY_PY_USSL=1 -ifeq ($(MICROPY_SSL_AXTLS),1) -CFLAGS_MOD += -DMICROPY_SSL_AXTLS=1 -I$(TOP)/lib/axtls/ssl -I$(TOP)/lib/axtls/crypto -I$(TOP)/extmod/axtls-include -AXTLS_DIR = lib/axtls -$(BUILD)/$(AXTLS_DIR)/%.o: CFLAGS += -Wno-all -Wno-unused-parameter -Wno-uninitialized -Wno-sign-compare -Wno-old-style-definition $(AXTLS_DEFS_EXTRA) -SRC_MOD += $(addprefix $(AXTLS_DIR)/,\ - ssl/asn1.c \ - ssl/loader.c \ - ssl/tls1.c \ - ssl/tls1_svr.c \ - ssl/tls1_clnt.c \ - ssl/x509.c \ - crypto/aes.c \ - crypto/bigint.c \ - crypto/crypto_misc.c \ - crypto/hmac.c \ - crypto/md5.c \ - crypto/rsa.c \ - crypto/sha1.c \ - ) -else ifeq ($(MICROPY_SSL_MBEDTLS),1) -# Can be overridden by ports which have "builtin" mbedTLS -MICROPY_SSL_MBEDTLS_INCLUDE ?= $(TOP)/lib/mbedtls/include -CFLAGS_MOD += -DMICROPY_SSL_MBEDTLS=1 -I$(MICROPY_SSL_MBEDTLS_INCLUDE) -LDFLAGS_MOD += -L$(TOP)/lib/mbedtls/library -lmbedx509 -lmbedtls -lmbedcrypto -endif -endif - -ifeq ($(MICROPY_PY_LWIP),1) -# A port should add an include path where lwipopts.h can be found (eg extmod/lwip-include) -LWIP_DIR = lib/lwip/src -INC += -I$(TOP)/$(LWIP_DIR)/include -CFLAGS_MOD += -DMICROPY_PY_LWIP=1 -$(BUILD)/$(LWIP_DIR)/core/ipv4/dhcp.o: CFLAGS_MOD += -Wno-address -SRC_MOD += extmod/modlwip.c lib/netutils/netutils.c -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 \ - ) -ifeq ($(MICROPY_PY_LWIP_SLIP),1) -CFLAGS_MOD += -DMICROPY_PY_LWIP_SLIP=1 -SRC_MOD += $(LWIP_DIR)/netif/slipif.c -endif -endif - -ifeq ($(MICROPY_PY_BTREE),1) -BTREE_DIR = lib/berkeley-db-1.xx -BTREE_DEFS = -D__DBINTERFACE_PRIVATE=1 -Dmpool_error=printf -Dabort=abort_ "-Dvirt_fd_t=void*" $(BTREE_DEFS_EXTRA) -INC += -I$(TOP)/$(BTREE_DIR)/PORT/include -SRC_MOD += extmod/modbtree.c -SRC_MOD += $(addprefix $(BTREE_DIR)/,\ -btree/bt_close.c \ -btree/bt_conv.c \ -btree/bt_debug.c \ -btree/bt_delete.c \ -btree/bt_get.c \ -btree/bt_open.c \ -btree/bt_overflow.c \ -btree/bt_page.c \ -btree/bt_put.c \ -btree/bt_search.c \ -btree/bt_seq.c \ -btree/bt_split.c \ -btree/bt_utils.c \ -mpool/mpool.c \ - ) -CFLAGS_MOD += -DMICROPY_PY_BTREE=1 -# we need to suppress certain warnings to get berkeley-db to compile cleanly -# and we have separate BTREE_DEFS so the definitions don't interfere with other source code -$(BUILD)/$(BTREE_DIR)/%.o: CFLAGS += -Wno-old-style-definition -Wno-sign-compare -Wno-unused-parameter $(BTREE_DEFS) -$(BUILD)/extmod/modbtree.o: CFLAGS += $(BTREE_DEFS) -endif - # External modules written in C. ifneq ($(USER_C_MODULES),) # pre-define USERMOD variables as expanded so that variables are immediate @@ -365,3 +255,6 @@ $(PY_BUILD)/vm.o: CFLAGS += $(CSUPEROPT) # http://hg.python.org/cpython/file/b127046831e2/Python/ceval.c#l828 # http://www.emulators.com/docs/nx25_nostradamus.htm #-fno-crossjumping + +# Include rules for extmod related code +include $(TOP)/extmod/extmod.mk From 399417adbae831ba660cfcad3d75e2d5dab756ef Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 5 Jun 2019 15:21:40 +1000 Subject: [PATCH 0426/1788] lib: Add new submodule for mbedtls, currently at v2.17.0. From upstream source: https://github.com/ARMmbed/mbedtls.git --- .gitmodules | 3 +++ lib/mbedtls | 1 + 2 files changed, 4 insertions(+) create mode 160000 lib/mbedtls diff --git a/.gitmodules b/.gitmodules index c986704caa..216a3b909c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -18,3 +18,6 @@ [submodule "lib/nrfx"] path = lib/nrfx url = https://github.com/NordicSemiconductor/nrfx.git +[submodule "lib/mbedtls"] + path = lib/mbedtls + url = https://github.com/ARMmbed/mbedtls.git diff --git a/lib/mbedtls b/lib/mbedtls new file mode 160000 index 0000000000..3f8d78411a --- /dev/null +++ b/lib/mbedtls @@ -0,0 +1 @@ +Subproject commit 3f8d78411a26e833db18d9fbde0e2f0baeda87f0 From 678ec182cd4d9b800ed22a98f0a1eb00b5e85aa6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 5 Jun 2019 15:22:21 +1000 Subject: [PATCH 0427/1788] extmod/extmod.mk: Integrate mbedTLS so it is built from source. Setting MICROPY_PY_USSL and MICROPY_SSL_MBEDTLS at the Makefile-level will now build mbedTLS from source and include it in the build, with the ussl module using this TLS library. Extra settings like MBEDTLS_CONFIG_FILE may need to be provided by a given port. If a port wants to use its own mbedTLS library then it should not set MICROPY_SSL_MBEDTLS at the Makefile-level but rather set it at the C level, and provide the library as part of the build in its own way (see eg esp32 port). --- extmod/extmod.mk | 79 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 75 insertions(+), 4 deletions(-) diff --git a/extmod/extmod.mk b/extmod/extmod.mk index 2143058f8f..909952cc28 100644 --- a/extmod/extmod.mk +++ b/extmod/extmod.mk @@ -28,10 +28,81 @@ SRC_MOD += $(addprefix $(AXTLS_DIR)/,\ crypto/sha1.c \ ) else ifeq ($(MICROPY_SSL_MBEDTLS),1) -# Can be overridden by ports which have "builtin" mbedTLS -MICROPY_SSL_MBEDTLS_INCLUDE ?= $(TOP)/lib/mbedtls/include -CFLAGS_MOD += -DMICROPY_SSL_MBEDTLS=1 -I$(MICROPY_SSL_MBEDTLS_INCLUDE) -LDFLAGS_MOD += -L$(TOP)/lib/mbedtls/library -lmbedx509 -lmbedtls -lmbedcrypto +MBEDTLS_DIR = lib/mbedtls +CFLAGS_MOD += -DMICROPY_SSL_MBEDTLS=1 -I$(TOP)/$(MBEDTLS_DIR)/include +SRC_MOD += $(addprefix $(MBEDTLS_DIR)/library/,\ + aes.c \ + aesni.c \ + arc4.c \ + asn1parse.c \ + asn1write.c \ + base64.c \ + bignum.c \ + blowfish.c \ + camellia.c \ + ccm.c \ + certs.c \ + chacha20.c \ + chachapoly.c \ + cipher.c \ + cipher_wrap.c \ + cmac.c \ + ctr_drbg.c \ + debug.c \ + des.c \ + dhm.c \ + ecdh.c \ + ecdsa.c \ + ecjpake.c \ + ecp.c \ + ecp_curves.c \ + entropy.c \ + entropy_poll.c \ + error.c \ + gcm.c \ + havege.c \ + hmac_drbg.c \ + md2.c \ + md4.c \ + md5.c \ + md.c \ + md_wrap.c \ + oid.c \ + padlock.c \ + pem.c \ + pk.c \ + pkcs11.c \ + pkcs12.c \ + pkcs5.c \ + pkparse.c \ + pk_wrap.c \ + pkwrite.c \ + platform.c \ + platform_util.c \ + poly1305.c \ + ripemd160.c \ + rsa.c \ + rsa_internal.c \ + sha1.c \ + sha256.c \ + sha512.c \ + ssl_cache.c \ + ssl_ciphersuites.c \ + ssl_cli.c \ + ssl_cookie.c \ + ssl_srv.c \ + ssl_ticket.c \ + ssl_tls.c \ + timing.c \ + x509.c \ + x509_create.c \ + x509_crl.c \ + x509_crt.c \ + x509_csr.c \ + x509write_crt.c \ + x509write_csr.c \ + xtea.c \ + ) endif endif From 9d72f07b6de35c5901f93da7c95e00969caec6d6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 5 Jun 2019 15:28:30 +1000 Subject: [PATCH 0428/1788] unix/mpconfigport.mk: Update comment about TLS implementations. As long as the submodule is checked out, mbedTLS is now fully integrated into the unix build if MICROPY_SSL_MBEDTLS=1. --- ports/unix/mpconfigport.mk | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ports/unix/mpconfigport.mk b/ports/unix/mpconfigport.mk index f0aa955c0c..3a66d997b2 100644 --- a/ports/unix/mpconfigport.mk +++ b/ports/unix/mpconfigport.mk @@ -25,13 +25,11 @@ MICROPY_PY_FFI = 1 # ussl module requires one of the TLS libraries below MICROPY_PY_USSL = 1 -# axTLS has minimal size and fully integrated with MicroPython, but -# implements only a subset of modern TLS functionality, so may have -# problems with some servers. +# axTLS has minimal size but implements only a subset of modern TLS +# functionality, so may have problems with some servers. MICROPY_SSL_AXTLS = 1 # mbedTLS is more up to date and complete implementation, but also -# more bloated. Configuring and building of mbedTLS should be done -# outside of MicroPython, it can just link with mbedTLS library. +# more bloated. MICROPY_SSL_MBEDTLS = 0 # jni module requires JVM/JNI From ef7357d4abc5701865aa4d75d2e5488c3cc70160 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 5 Jun 2019 15:33:15 +1000 Subject: [PATCH 0429/1788] extmod/modussl_mbedtls: Allow to build with object representation D. --- 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 94863be57a..6759f11fa5 100644 --- a/extmod/modussl_mbedtls.c +++ b/extmod/modussl_mbedtls.c @@ -334,7 +334,7 @@ STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_ { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { 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} }, + { MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, { MP_QSTR_do_handshake, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, }; From fed4c23590e354394b275c073c46e3ad079877c3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 5 Jun 2019 15:35:23 +1000 Subject: [PATCH 0430/1788] stm32: Integrate optional mbedTLS component for ussl module. To use it a board should define MICROPY_PY_USSL=1 and MICROPY_SSL_MBEDTLS=1 at the Makefile level. With the provided configuration it adds about 64k to the build. --- ports/stm32/Makefile | 5 ++ ports/stm32/mbedtls/mbedtls_config.h | 93 +++++++++++++++++++++++++++ ports/stm32/mbedtls/mbedtls_port.c | 96 ++++++++++++++++++++++++++++ ports/stm32/mpconfigport.h | 15 +++++ 4 files changed, 209 insertions(+) create mode 100644 ports/stm32/mbedtls/mbedtls_config.h create mode 100644 ports/stm32/mbedtls/mbedtls_port.c diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 6a44ff30b3..1216cd13bd 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -396,6 +396,11 @@ SRC_MOD += $(addprefix $(CC3000_DIR)/src/,\ ) endif +ifeq ($(MICROPY_SSL_MBEDTLS),1) +CFLAGS_MOD += -DMBEDTLS_CONFIG_FILE='"mbedtls/mbedtls_config.h"' +SRC_MOD += mbedtls/mbedtls_port.c +endif + OBJ = OBJ += $(PY_O) OBJ += $(addprefix $(BUILD)/, $(SRC_LIB:.c=.o)) diff --git a/ports/stm32/mbedtls/mbedtls_config.h b/ports/stm32/mbedtls/mbedtls_config.h new file mode 100644 index 0000000000..4820140766 --- /dev/null +++ b/ports/stm32/mbedtls/mbedtls_config.h @@ -0,0 +1,93 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2019 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_MBEDTLS_CONFIG_H +#define MICROPY_INCLUDED_MBEDTLS_CONFIG_H + +// Set mbedtls configuration +#define MBEDTLS_PLATFORM_MEMORY +#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS +#define MBEDTLS_DEPRECATED_REMOVED +#define MBEDTLS_ENTROPY_HARDWARE_ALT +#define MBEDTLS_AES_ROM_TABLES +#define MBEDTLS_CIPHER_MODE_CBC +#define MBEDTLS_ECP_DP_SECP192R1_ENABLED +#define MBEDTLS_ECP_DP_SECP224R1_ENABLED +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#define MBEDTLS_ECP_DP_SECP384R1_ENABLED +#define MBEDTLS_ECP_DP_SECP521R1_ENABLED +#define MBEDTLS_ECP_DP_SECP192K1_ENABLED +#define MBEDTLS_ECP_DP_SECP224K1_ENABLED +#define MBEDTLS_ECP_DP_SECP256K1_ENABLED +#define MBEDTLS_ECP_DP_BP256R1_ENABLED +#define MBEDTLS_ECP_DP_BP384R1_ENABLED +#define MBEDTLS_ECP_DP_BP512R1_ENABLED +#define MBEDTLS_ECP_DP_CURVE25519_ENABLED +#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED +#define MBEDTLS_NO_PLATFORM_ENTROPY +#define MBEDTLS_PKCS1_V15 +#define MBEDTLS_SHA256_SMALLER +#define MBEDTLS_SSL_PROTO_TLS1 +#define MBEDTLS_SSL_PROTO_TLS1_1 +#define MBEDTLS_SSL_PROTO_TLS1_2 +#define MBEDTLS_SSL_SERVER_NAME_INDICATION + +// Enable mbedtls modules +#define MBEDTLS_AES_C +#define MBEDTLS_ASN1_PARSE_C +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_CIPHER_C +#define MBEDTLS_CTR_DRBG_C +//#define MBEDTLS_ECP_C +#define MBEDTLS_ENTROPY_C +#define MBEDTLS_MD_C +#define MBEDTLS_MD5_C +#define MBEDTLS_OID_C +#define MBEDTLS_PKCS5_C +#define MBEDTLS_PK_C +#define MBEDTLS_PK_PARSE_C +#define MBEDTLS_PLATFORM_C +#define MBEDTLS_RSA_C +#define MBEDTLS_SHA1_C +#define MBEDTLS_SHA256_C +#define MBEDTLS_SHA512_C +#define MBEDTLS_SSL_CLI_C +#define MBEDTLS_SSL_SRV_C +#define MBEDTLS_SSL_TLS_C +#define MBEDTLS_X509_CRT_PARSE_C +#define MBEDTLS_X509_USE_C + +// Memory allocation hooks +#include +#include +void *m_calloc_mbedtls(size_t nmemb, size_t size); +void m_free_mbedtls(void *ptr); +#define MBEDTLS_PLATFORM_STD_CALLOC m_calloc_mbedtls +#define MBEDTLS_PLATFORM_STD_FREE m_free_mbedtls +#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf + +#include "mbedtls/check_config.h" + +#endif /* MICROPY_INCLUDED_MBEDTLS_CONFIG_H */ diff --git a/ports/stm32/mbedtls/mbedtls_port.c b/ports/stm32/mbedtls/mbedtls_port.c new file mode 100644 index 0000000000..efb8d2c2a4 --- /dev/null +++ b/ports/stm32/mbedtls/mbedtls_port.c @@ -0,0 +1,96 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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/gc.h" +#include "rng.h" +#include "mbedtls_config.h" + +#define DEBUG (0) + +#if DEBUG +static size_t count_links(uint32_t *nb) { + void **p = MP_STATE_PORT(mbedtls_memory); + size_t n = 0; + *nb = 0; + while (p != NULL) { + ++n; + *nb += gc_nbytes(p); + p = (void**)p[1]; + } + return n; +} +#endif + +void *m_calloc_mbedtls(size_t nmemb, size_t size) { + void **ptr = m_malloc0(nmemb * size + 2 * sizeof(uintptr_t)); + #if DEBUG + uint32_t nb; + size_t n = count_links(&nb); + printf("mbed_alloc(%u, %u) -> (%u;%u) %p\n", nmemb, size, n, (uint)nb, ptr); + #endif + if (MP_STATE_PORT(mbedtls_memory) != NULL) { + MP_STATE_PORT(mbedtls_memory)[0] = ptr; + } + ptr[0] = NULL; + ptr[1] = MP_STATE_PORT(mbedtls_memory); + MP_STATE_PORT(mbedtls_memory) = ptr; + return &ptr[2]; +} + +void m_free_mbedtls(void *ptr_in) { + void **ptr = &((void**)ptr_in)[-2]; + #if DEBUG + uint32_t nb; + size_t n = count_links(&nb); + printf("mbed_free(%p, [%p, %p], nbytes=%u, links=%u;%u)\n", ptr, ptr[0], ptr[1], gc_nbytes(ptr), n, (uint)nb); + #endif + if (ptr[1] != NULL) { + ((void**)ptr[1])[0] = ptr[0]; + } + if (ptr[0] != NULL) { + ((void**)ptr[0])[1] = ptr[1]; + } else { + MP_STATE_PORT(mbedtls_memory) = ptr[1]; + } + m_free(ptr); +} + +int mbedtls_hardware_poll(void *data, unsigned char *output, size_t len, size_t *olen) { + uint32_t val; + int n = 0; + *olen = len; + while (len--) { + if (!n) { + val = rng_get(); + n = 4; + } + *output++ = val; + val >>= 8; + --n; + } + return 0; +} diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 5a1687c07b..d802300637 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -224,6 +224,12 @@ extern const struct _mp_obj_module_t mp_module_onewire; #define SOCKET_BUILTIN_MODULE_WEAK_LINKS #endif +#if MICROPY_PY_USSL +#define SSL_BUILTIN_MODULE_WEAK_LINKS { MP_ROM_QSTR(MP_QSTR_ssl), MP_ROM_PTR(&mp_module_ussl) }, +#else +#define SSL_BUILTIN_MODULE_WEAK_LINKS +#endif + #if MICROPY_PY_NETWORK #define NETWORK_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_network), MP_ROM_PTR(&mp_module_network) }, #else @@ -254,6 +260,7 @@ extern const struct _mp_obj_module_t mp_module_onewire; { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mp_module_utime) }, \ { MP_ROM_QSTR(MP_QSTR_select), MP_ROM_PTR(&mp_module_uselect) }, \ SOCKET_BUILTIN_MODULE_WEAK_LINKS \ + SSL_BUILTIN_MODULE_WEAK_LINKS \ { MP_ROM_QSTR(MP_QSTR_struct), MP_ROM_PTR(&mp_module_ustruct) }, \ { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&machine_module) }, \ { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mp_module_uerrno) }, \ @@ -267,6 +274,12 @@ extern const struct _mp_obj_module_t mp_module_onewire; #define MP_STATE_PORT MP_STATE_VM +#if MICROPY_SSL_MBEDTLS +#define MICROPY_PORT_ROOT_POINTER_MBEDTLS void **mbedtls_memory; +#else +#define MICROPY_PORT_ROOT_POINTER_MBEDTLS +#endif + #define MICROPY_PORT_ROOT_POINTERS \ const char *readline_hist[8]; \ \ @@ -295,6 +308,8 @@ extern const struct _mp_obj_module_t mp_module_onewire; \ /* list of registered NICs */ \ mp_obj_list_t mod_network_nic_list; \ + \ + MICROPY_PORT_ROOT_POINTER_MBEDTLS // type definitions for the specific machine From fd839221fda6f53c794ecabe6d5eb05125307818 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 5 Jun 2019 15:38:01 +1000 Subject: [PATCH 0431/1788] stm32/boards/PYBD_SFx: Enable ussl module using mbedTLS. --- ports/stm32/boards/PYBD_SF2/mpconfigboard.mk | 2 ++ ports/stm32/boards/PYBD_SF3/mpconfigboard.mk | 2 ++ ports/stm32/boards/PYBD_SF6/mpconfigboard.mk | 2 ++ 3 files changed, 6 insertions(+) diff --git a/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk b/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk index 98103e1405..489d2f893a 100644 --- a/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk +++ b/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk @@ -12,3 +12,5 @@ TEXT1_SECTIONS = .text_ext # MicroPython settings MICROPY_PY_LWIP = 1 MICROPY_PY_NETWORK_CYW43 = 1 +MICROPY_PY_USSL = 1 +MICROPY_SSL_MBEDTLS = 1 diff --git a/ports/stm32/boards/PYBD_SF3/mpconfigboard.mk b/ports/stm32/boards/PYBD_SF3/mpconfigboard.mk index 924a0f3d55..368adcf39a 100644 --- a/ports/stm32/boards/PYBD_SF3/mpconfigboard.mk +++ b/ports/stm32/boards/PYBD_SF3/mpconfigboard.mk @@ -12,3 +12,5 @@ TEXT1_SECTIONS = .text_ext # MicroPython settings MICROPY_PY_LWIP = 1 MICROPY_PY_NETWORK_CYW43 = 1 +MICROPY_PY_USSL = 1 +MICROPY_SSL_MBEDTLS = 1 diff --git a/ports/stm32/boards/PYBD_SF6/mpconfigboard.mk b/ports/stm32/boards/PYBD_SF6/mpconfigboard.mk index 5018123272..97c854ae77 100644 --- a/ports/stm32/boards/PYBD_SF6/mpconfigboard.mk +++ b/ports/stm32/boards/PYBD_SF6/mpconfigboard.mk @@ -9,3 +9,5 @@ TEXT0_ADDR = 0x08008000 # MicroPython settings MICROPY_PY_LWIP = 1 MICROPY_PY_NETWORK_CYW43 = 1 +MICROPY_PY_USSL = 1 +MICROPY_SSL_MBEDTLS = 1 From 49388e339ecea9595c0e82244cc3d60a7cb5e333 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 5 Jun 2019 16:13:34 +1000 Subject: [PATCH 0432/1788] extmod/extmod.mk: Include mdns app source in lwIP build. --- extmod/extmod.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/extmod/extmod.mk b/extmod/extmod.mk index 909952cc28..05d0be3b16 100644 --- a/extmod/extmod.mk +++ b/extmod/extmod.mk @@ -117,6 +117,7 @@ CFLAGS_MOD += -DMICROPY_PY_LWIP=1 $(BUILD)/$(LWIP_DIR)/core/ipv4/dhcp.o: CFLAGS_MOD += -Wno-address SRC_MOD += extmod/modlwip.c lib/netutils/netutils.c SRC_MOD += $(addprefix $(LWIP_DIR)/,\ + apps/mdns/mdns.c \ core/def.c \ core/dns.c \ core/inet_chksum.c \ From 9e4b3681fd82e9a520a93e09ae5ab4dd2e5c88ca Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 5 Jun 2019 16:14:09 +1000 Subject: [PATCH 0433/1788] stm32: Support optional lwIP mDNS responder. --- ports/stm32/main.c | 4 ++++ ports/stm32/modnetwork.c | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 5bb425ddf3..3852ff9b04 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -39,6 +39,7 @@ #if MICROPY_PY_LWIP #include "lwip/init.h" +#include "lwip/apps/mdns.h" #include "drivers/cyw43/cyw43.h" #endif @@ -479,6 +480,9 @@ void stm32_main(uint32_t reset_mode) { // 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(); + #if LWIP_MDNS_RESPONDER + mdns_resp_init(); + #endif systick_enable_dispatch(SYSTICK_DISPATCH_LWIP, mod_network_lwip_poll_wrapper); #endif diff --git a/ports/stm32/modnetwork.c b/ports/stm32/modnetwork.c index 460f47257b..80e5a5a162 100644 --- a/ports/stm32/modnetwork.c +++ b/ports/stm32/modnetwork.c @@ -44,6 +44,7 @@ #include "lwip/timeouts.h" #include "lwip/dns.h" #include "lwip/dhcp.h" +#include "lwip/apps/mdns.h" #include "extmod/network_cyw43.h" #include "drivers/cyw43/cyw43.h" @@ -188,6 +189,10 @@ mp_obj_t mod_network_nic_ifconfig(struct netif *netif, size_t n_args, const mp_o mp_hal_delay_ms(100); } + #if LWIP_MDNS_RESPONDER + mdns_resp_netif_settings_changed(netif); + #endif + return mp_const_none; } else { // Release and stop any existing DHCP @@ -202,6 +207,9 @@ mp_obj_t mod_network_nic_ifconfig(struct netif *netif, size_t n_args, const mp_o ip_addr_t dns; netutils_parse_ipv4_addr(items[3], (uint8_t*)&dns, NETUTILS_BIG); dns_setserver(0, &dns); + #if LWIP_MDNS_RESPONDER + mdns_resp_netif_settings_changed(netif); + #endif return mp_const_none; } } From 62f004ba424920a01e60c7a9a064b8ec9cd69c12 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 5 Jun 2019 16:14:45 +1000 Subject: [PATCH 0434/1788] stm32/lwip_inc: Update to enable mDNS, TCP listen backlog, faster DHCP. --- ports/stm32/lwip_inc/lwipopts.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ports/stm32/lwip_inc/lwipopts.h b/ports/stm32/lwip_inc/lwipopts.h index 64ff104f71..8f54c83112 100644 --- a/ports/stm32/lwip_inc/lwipopts.h +++ b/ports/stm32/lwip_inc/lwipopts.h @@ -3,6 +3,11 @@ #include +// This protection is not needed, instead we execute all lwIP code at PendSV priority +#define SYS_ARCH_DECL_PROTECT(lev) do { } while (0) +#define SYS_ARCH_PROTECT(lev) do { } while (0) +#define SYS_ARCH_UNPROTECT(lev) do { } while (0) + #define NO_SYS 1 #define SYS_LIGHTWEIGHT_PROT 1 #define MEM_ALIGNMENT 4 @@ -20,10 +25,17 @@ #define LWIP_IPV6 0 #define LWIP_DHCP 1 #define LWIP_DHCP_CHECK_LINK_UP 1 +#define DHCP_DOES_ARP_CHECK 0 // to speed DHCP up #define LWIP_DNS 1 +#define LWIP_DNS_SUPPORT_MDNS_QUERIES 1 +#define LWIP_MDNS_RESPONDER 1 #define LWIP_IGMP 1 +#define LWIP_NUM_NETIF_CLIENT_DATA 1 // mDNS responder requires 1 +#define MEMP_NUM_UDP_PCB 5 // mDNS responder requires 1 + #define SO_REUSE 1 +#define TCP_LISTEN_BACKLOG 1 extern uint32_t rng_get(void); #define LWIP_RAND() rng_get() From 9d3031cc9d888321b122d7e92491ba045727ac32 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 11 Jun 2019 11:36:39 +1000 Subject: [PATCH 0435/1788] tools/mpy-tool.py: Fix linking of qstr objects in native ARM Thumb code. Previously, when linking qstr objects in native code for ARM Thumb, the index into the machine code was being incremented by 4, not 8. It should be 8 to account for the size of the two machine instructions movw and movt. This patch makes sure the index into the machine code is incremented by the correct amount for all variations of qstr linking. See issue #4829. --- tools/mpy-tool.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index db6fe23833..a97af7737f 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -481,6 +481,7 @@ class RawCodeNative(RawCode): if kind == 0: # Generic 16-bit link print(' %s & 0xff, %s >> 8,' % (qst, qst)) + return 2 else: # Architecture-specific link is_obj = kind == 2 @@ -488,14 +489,17 @@ class RawCodeNative(RawCode): qst = '((uintptr_t)MP_OBJ_NEW_QSTR(%s))' % qst if config.native_arch in (MP_NATIVE_ARCH_X86, MP_NATIVE_ARCH_X64): print(' %s & 0xff, %s >> 8, 0, 0,' % (qst, qst)) + return 4 elif MP_NATIVE_ARCH_ARMV6M <= config.native_arch <= MP_NATIVE_ARCH_ARMV7EMDP: if is_obj: # qstr object, movw and movt self._asm_thumb_rewrite_mov(pc, qst) self._asm_thumb_rewrite_mov(pc + 4, '(%s >> 16)' % qst) + return 8 else: # qstr number, movw instruction self._asm_thumb_rewrite_mov(pc, qst) + return 4 else: assert 0 @@ -523,8 +527,7 @@ class RawCodeNative(RawCode): # link qstr qi_off, qi_kind, qi_val = self.qstr_links[qi] qst = global_qstrs[qi_val].qstr_id - self._link_qstr(i, qi_kind, qst) - i += 4 + i += self._link_qstr(i, qi_kind, qst) qi += 1 else: # copy machine code (max 16 bytes) From 518aa571ab064ba8feb0b503f91fba0a62ad22b0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 11 Jun 2019 14:38:56 +1000 Subject: [PATCH 0436/1788] stm32/usbd_msc: Rework USBD MSC code to support multiple logical units. SCSI can support multiple logical units over the one interface (in this case over USBD MSC) and here the MSC code is reworked to support this feature. At this point only one LU is used and the behaviour is mostly unchanged from before, except the INQUIRY result is different (it will report "Flash" for both flash and SD card). --- ports/stm32/Makefile | 2 +- ports/stm32/usb.c | 12 +- ports/stm32/usbd_msc_interface.c | 263 +++++++++++++++ ...sbd_msc_storage.h => usbd_msc_interface.h} | 11 +- ports/stm32/usbd_msc_storage.c | 306 ------------------ 5 files changed, 279 insertions(+), 315 deletions(-) create mode 100644 ports/stm32/usbd_msc_interface.c rename ports/stm32/{usbd_msc_storage.h => usbd_msc_interface.h} (82%) delete mode 100644 ports/stm32/usbd_msc_storage.c diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 1216cd13bd..12edbcc7f7 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -222,7 +222,7 @@ SRC_C = \ usbd_desc.c \ usbd_cdc_interface.c \ usbd_hid_interface.c \ - usbd_msc_storage.c \ + usbd_msc_interface.c \ mphalport.c \ mpthreadport.c \ irq.c \ diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index ace090f804..8a0591a49b 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -31,7 +31,7 @@ #include "usbd_desc.h" #include "usbd_cdc_msc_hid.h" #include "usbd_cdc_interface.h" -#include "usbd_msc_storage.h" +#include "usbd_msc_interface.h" #include "usbd_hid_interface.h" #include "py/objstr.h" @@ -40,6 +40,8 @@ #include "py/mperrno.h" #include "py/mphal.h" #include "bufhelper.h" +#include "storage.h" +#include "sdcard.h" #include "usb.h" #if MICROPY_HW_ENABLE_USB @@ -143,16 +145,20 @@ bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, uint8_t mode, USBD_HID_ModeInf return false; } + // Configure the MSC interface + const void *lu[1]; switch (pyb_usb_storage_medium) { #if MICROPY_HW_ENABLE_SDCARD case PYB_USB_STORAGE_MEDIUM_SDCARD: - USBD_MSC_RegisterStorage(&usb_dev->usbd_cdc_msc_hid_state, (USBD_StorageTypeDef*)&USBD_SDCARD_STORAGE_fops); + lu[0] = &pyb_sdcard_type; break; #endif default: - USBD_MSC_RegisterStorage(&usb_dev->usbd_cdc_msc_hid_state, (USBD_StorageTypeDef*)&USBD_FLASH_STORAGE_fops); + lu[0] = &pyb_flash_type; break; } + usbd_msc_init_lu(1, lu); + USBD_MSC_RegisterStorage(&usb_dev->usbd_cdc_msc_hid_state, (USBD_StorageTypeDef*)&usbd_msc_fops); // start the USB device USBD_LL_Init(usbd, (mode & USBD_MODE_HIGH_SPEED) != 0); diff --git a/ports/stm32/usbd_msc_interface.c b/ports/stm32/usbd_msc_interface.c new file mode 100644 index 0000000000..493dece1f9 --- /dev/null +++ b/ports/stm32/usbd_msc_interface.c @@ -0,0 +1,263 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2019 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 "usbd_cdc_msc_hid.h" +#include "usbd_msc_interface.h" + +#include "extmod/vfs.h" +#include "storage.h" +#include "sdcard.h" + +#define USBD_MSC_MAX_LUN (2) + +// This flag is needed to support removal of the medium, so that the USB drive +// can be unmounted and won't be remounted automatically. +#define FLAGS_STARTED (0x01) + +#define FLAGS_READONLY (0x02) + +STATIC const void *usbd_msc_lu_data[USBD_MSC_MAX_LUN]; +STATIC uint8_t usbd_msc_lu_num; +STATIC uint16_t usbd_msc_lu_flags; + +static inline void lu_flag_set(uint8_t lun, uint8_t flag) { + usbd_msc_lu_flags |= flag << (lun * 2); +} + +static inline void lu_flag_clr(uint8_t lun, uint8_t flag) { + usbd_msc_lu_flags &= ~(flag << (lun * 2)); +} + +static inline bool lu_flag_is_set(uint8_t lun, uint8_t flag) { + return usbd_msc_lu_flags & (flag << (lun * 2)); +} + +STATIC const int8_t usbd_msc_inquiry_data[36] = { + 0x00, // peripheral qualifier; peripheral device type + 0x80, // 0x00 for a fixed drive, 0x80 for a removable drive + 0x02, // version + 0x02, // response data format + (STANDARD_INQUIRY_DATA_LEN - 5), // additional length + 0x00, // various flags + 0x00, // various flags + 0x00, // various flags + 'M', 'i', 'c', 'r', 'o', 'P', 'y', ' ', // Manufacturer : 8 bytes + 'p', 'y', 'b', 'o', 'a', 'r', 'd', ' ', // Product : 16 Bytes + 'F', 'l', 'a', 's', 'h', ' ', ' ', ' ', + '1', '.', '0' ,'0', // Version : 4 Bytes +}; + +// Set the logical units that will be exposed over MSC +void usbd_msc_init_lu(size_t lu_n, const void *lu_data) { + usbd_msc_lu_num = MIN(lu_n, USBD_MSC_MAX_LUN); + memcpy(usbd_msc_lu_data, lu_data, sizeof(void*) * usbd_msc_lu_num); + usbd_msc_lu_flags = 0; +} + +// Helper function to perform an ioctl on a logical unit +STATIC int lu_ioctl(uint8_t lun, int op, uint32_t *data) { + if (lun >= usbd_msc_lu_num) { + return -1; + } + const void *lu = usbd_msc_lu_data[lun]; + + if (lu == &pyb_flash_type) { + switch (op) { + case BP_IOCTL_INIT: + storage_init(); + *data = 0; + return 0; + case BP_IOCTL_SYNC: + storage_flush(); + return 0; + case BP_IOCTL_SEC_SIZE: + *data = storage_get_block_size(); + return 0; + case BP_IOCTL_SEC_COUNT: + *data = storage_get_block_count(); + return 0; + default: + return -1; + } + } else if (lu == &pyb_sdcard_type + #if MICROPY_HW_ENABLE_MMCARD + || lu == &pyb_mmcard_type + #endif + ) { + switch (op) { + case BP_IOCTL_INIT: + if (!sdcard_power_on()) { + return -1; + } + *data = 0; + return 0; + case BP_IOCTL_SYNC: + return 0; + case BP_IOCTL_SEC_SIZE: + *data = SDCARD_BLOCK_SIZE; + return 0; + case BP_IOCTL_SEC_COUNT: + *data = sdcard_get_capacity_in_bytes() / (uint64_t)SDCARD_BLOCK_SIZE; + return 0; + default: + return -1; + } + } else { + return -1; + } +} + +// Initialise all logical units (it's only ever called once, with lun_in=0) +STATIC int8_t usbd_msc_Init(uint8_t lun_in) { + if (lun_in != 0) { + return 0; + } + for (int lun = 0; lun < usbd_msc_lu_num; ++lun) { + uint32_t data = 0; + int res = lu_ioctl(lun, BP_IOCTL_INIT, &data); + if (res != 0) { + lu_flag_clr(lun, FLAGS_STARTED); + } else { + lu_flag_set(lun, FLAGS_STARTED); + if (data) { + lu_flag_set(lun, FLAGS_READONLY); + } + } + } + return 0; +} + +// Get storage capacity of a logical unit +STATIC int8_t usbd_msc_GetCapacity(uint8_t lun, uint32_t *block_num, uint16_t *block_size) { + uint32_t block_size_u32 = 0; + int res = lu_ioctl(lun, BP_IOCTL_SEC_SIZE, &block_size_u32); + if (res != 0) { + return -1; + } + *block_size = block_size_u32; + return lu_ioctl(lun, BP_IOCTL_SEC_COUNT, block_num); +} + +// Check if a logical unit is ready +STATIC int8_t usbd_msc_IsReady(uint8_t lun) { + if (lun >= usbd_msc_lu_num) { + return -1; + } + return lu_flag_is_set(lun, FLAGS_STARTED) ? 0 : -1; +} + +// Check if a logical unit is write protected +STATIC int8_t usbd_msc_IsWriteProtected(uint8_t lun) { + if (lun >= usbd_msc_lu_num) { + return -1; + } + return lu_flag_is_set(lun, FLAGS_READONLY) ? 1 : 0; +} + +// Start or stop a logical unit +STATIC int8_t usbd_msc_StartStopUnit(uint8_t lun, uint8_t started) { + if (lun >= usbd_msc_lu_num) { + return -1; + } + if (started) { + lu_flag_set(lun, FLAGS_STARTED); + } else { + lu_flag_clr(lun, FLAGS_STARTED); + } + return 0; +} + +// Prepare a logical unit for possible removal +STATIC int8_t usbd_msc_PreventAllowMediumRemoval(uint8_t lun, uint8_t param) { + uint32_t dummy; + // Sync the logical unit so the device can be unplugged/turned off + return lu_ioctl(lun, BP_IOCTL_SYNC, &dummy); +} + +// Read data from a logical unit +STATIC int8_t usbd_msc_Read(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) { + if (lun >= usbd_msc_lu_num) { + return -1; + } + const void *lu = usbd_msc_lu_data[lun]; + + if (lu == &pyb_flash_type) { + storage_read_blocks(buf, blk_addr, blk_len); + return 0; + } else if (lu == &pyb_sdcard_type + #if MICROPY_HW_ENABLE_MMCARD + || lu == &pyb_mmcard_type + #endif + ) { + if (sdcard_read_blocks(buf, blk_addr, blk_len) == 0) { + return 0; + } + } + return -1; +} + +// Write data to a logical unit +STATIC int8_t usbd_msc_Write(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) { + if (lun >= usbd_msc_lu_num) { + return -1; + } + const void *lu = usbd_msc_lu_data[lun]; + + if (lu == &pyb_flash_type) { + storage_write_blocks(buf, blk_addr, blk_len); + return 0; + } else if (lu == &pyb_sdcard_type + #if MICROPY_HW_ENABLE_MMCARD + || lu == &pyb_mmcard_type + #endif + ) { + if (sdcard_write_blocks(buf, blk_addr, blk_len) == 0) { + return 0; + } + } + return -1; +} + +// Get the number of attached logical units +STATIC int8_t usbd_msc_GetMaxLun(void) { + return usbd_msc_lu_num - 1; +} + +// Table of operations for the SCSI layer to call +const USBD_StorageTypeDef usbd_msc_fops = { + usbd_msc_Init, + usbd_msc_GetCapacity, + usbd_msc_IsReady, + usbd_msc_IsWriteProtected, + usbd_msc_StartStopUnit, + usbd_msc_PreventAllowMediumRemoval, + usbd_msc_Read, + usbd_msc_Write, + usbd_msc_GetMaxLun, + (int8_t *)usbd_msc_inquiry_data, +}; diff --git a/ports/stm32/usbd_msc_storage.h b/ports/stm32/usbd_msc_interface.h similarity index 82% rename from ports/stm32/usbd_msc_storage.h rename to ports/stm32/usbd_msc_interface.h index 669f7df581..9d25a72a3a 100644 --- a/ports/stm32/usbd_msc_storage.h +++ b/ports/stm32/usbd_msc_interface.h @@ -23,10 +23,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STM32_USBD_MSC_STORAGE_H -#define MICROPY_INCLUDED_STM32_USBD_MSC_STORAGE_H +#ifndef MICROPY_INCLUDED_STM32_USBD_MSC_INTERFACE_H +#define MICROPY_INCLUDED_STM32_USBD_MSC_INTERFACE_H -extern const USBD_StorageTypeDef USBD_FLASH_STORAGE_fops; -extern const USBD_StorageTypeDef USBD_SDCARD_STORAGE_fops; +extern const USBD_StorageTypeDef usbd_msc_fops; -#endif // MICROPY_INCLUDED_STM32_USBD_MSC_STORAGE_H +void usbd_msc_init_lu(size_t lu_n, const void *lu_data); + +#endif // MICROPY_INCLUDED_STM32_USBD_MSC_INTERFACE_H diff --git a/ports/stm32/usbd_msc_storage.c b/ports/stm32/usbd_msc_storage.c deleted file mode 100644 index 01d15f6e75..0000000000 --- a/ports/stm32/usbd_msc_storage.c +++ /dev/null @@ -1,306 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - */ - -/** - ****************************************************************************** - * @file usbd_storage_msd.c - * @author MCD application Team - * @version V1.1.0 - * @date 19-March-2012 - * @brief This file provides the disk operations functions. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT 2012 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. - * - * Heavily modified by dpgeorge for MicroPython. - * - ****************************************************************************** - */ - -#include - -#include "usbd_cdc_msc_hid.h" -#include "usbd_msc_storage.h" - -#include "py/mpstate.h" -#include "storage.h" -#include "sdcard.h" - -// These are needed to support removal of the medium, so that the USB drive -// can be unmounted, and won't be remounted automatically. -static uint8_t flash_started = 0; - -#if MICROPY_HW_ENABLE_SDCARD -static uint8_t sdcard_started = 0; -#endif - -/******************************************************************************/ -// Callback functions for when the internal flash is the mass storage device - -static const int8_t FLASH_STORAGE_Inquirydata[] = { // 36 bytes - // LUN 0 - 0x00, - 0x80, // 0x00 for a fixed drive, 0x80 for a removable drive - 0x02, - 0x02, - (STANDARD_INQUIRY_DATA_LEN - 5), - 0x00, - 0x00, - 0x00, - 'u', 'P', 'y', ' ', ' ', ' ', ' ', ' ', // Manufacturer : 8 bytes - 'm', 'i', 'c', 'r', 'o', 'S', 'D', ' ', // Product : 16 Bytes - 'F', 'l', 'a', 's', 'h', ' ', ' ', ' ', - '1', '.', '0' ,'0', // Version : 4 Bytes -}; - -/** - * @brief Initialize the storage medium - * @param lun : logical unit number - * @retval Status - */ -int8_t FLASH_STORAGE_Init(uint8_t lun) { - storage_init(); - flash_started = 1; - return 0; -} - -/** - * @brief return medium capacity and block size - * @param lun : logical unit number - * @param block_num : number of physical block - * @param block_size : size of a physical block - * @retval Status - */ -int8_t FLASH_STORAGE_GetCapacity(uint8_t lun, uint32_t *block_num, uint16_t *block_size) { - *block_size = storage_get_block_size(); - *block_num = storage_get_block_count(); - return 0; -} - -/** - * @brief check whether the medium is ready - * @param lun : logical unit number - * @retval Status - */ -int8_t FLASH_STORAGE_IsReady(uint8_t lun) { - if (flash_started) { - return 0; - } - return -1; -} - -/** - * @brief check whether the medium is write-protected - * @param lun : logical unit number - * @retval Status - */ -int8_t FLASH_STORAGE_IsWriteProtected(uint8_t lun) { - return 0; -} - -// Remove the lun -int8_t FLASH_STORAGE_StartStopUnit(uint8_t lun, uint8_t started) { - flash_started = started; - return 0; -} - -int8_t FLASH_STORAGE_PreventAllowMediumRemoval(uint8_t lun, uint8_t param) { - // sync the flash so that the cache is cleared and the device can be unplugged/turned off - storage_flush(); - return 0; -} - -/** - * @brief Read data from the medium - * @param lun : logical unit number - * @param buf : Pointer to the buffer to save data - * @param blk_addr : address of 1st block to be read - * @param blk_len : nmber of blocks to be read - * @retval Status - */ -int8_t FLASH_STORAGE_Read(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) { - storage_read_blocks(buf, blk_addr, blk_len); - return 0; -} - -/** - * @brief Write data to the medium - * @param lun : logical unit number - * @param buf : Pointer to the buffer to write from - * @param blk_addr : address of 1st block to be written - * @param blk_len : nmber of blocks to be read - * @retval Status - */ -int8_t FLASH_STORAGE_Write (uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) { - storage_write_blocks(buf, blk_addr, blk_len); - return 0; -} - -/** - * @brief Return number of supported logical unit - * @param None - * @retval number of logical unit - */ -int8_t FLASH_STORAGE_GetMaxLun(void) { - return 0; -} - -const USBD_StorageTypeDef USBD_FLASH_STORAGE_fops = { - FLASH_STORAGE_Init, - FLASH_STORAGE_GetCapacity, - FLASH_STORAGE_IsReady, - FLASH_STORAGE_IsWriteProtected, - FLASH_STORAGE_StartStopUnit, - FLASH_STORAGE_PreventAllowMediumRemoval, - FLASH_STORAGE_Read, - FLASH_STORAGE_Write, - FLASH_STORAGE_GetMaxLun, - (int8_t *)FLASH_STORAGE_Inquirydata, -}; - -/******************************************************************************/ -// Callback functions for when the SD card is the mass storage device - -#if MICROPY_HW_ENABLE_SDCARD - -static const int8_t SDCARD_STORAGE_Inquirydata[] = { // 36 bytes - // LUN 0 - 0x00, - 0x80, // 0x00 for a fixed drive, 0x80 for a removable drive - 0x02, - 0x02, - (STANDARD_INQUIRY_DATA_LEN - 5), - 0x00, - 0x00, - 0x00, - 'u', 'P', 'y', ' ', ' ', ' ', ' ', ' ', // Manufacturer : 8 bytes - 'm', 'i', 'c', 'r', 'o', 'S', 'D', ' ', // Product : 16 Bytes - 'S', 'D', ' ', 'c', 'a', 'r', 'd', ' ', - '1', '.', '0' ,'0', // Version : 4 Bytes -}; - -/** - * @brief Initialize the storage medium - * @param lun : logical unit number - * @retval Status - */ -int8_t SDCARD_STORAGE_Init(uint8_t lun) { - if (!sdcard_power_on()) { - return -1; - } - sdcard_started = 1; - return 0; - -} - -/** - * @brief return medium capacity and block size - * @param lun : logical unit number - * @param block_num : number of physical block - * @param block_size : size of a physical block - * @retval Status - */ -int8_t SDCARD_STORAGE_GetCapacity(uint8_t lun, uint32_t *block_num, uint16_t *block_size) { - *block_size = SDCARD_BLOCK_SIZE; - *block_num = sdcard_get_capacity_in_bytes() / SDCARD_BLOCK_SIZE; - return 0; -} - -/** - * @brief check whether the medium is ready - * @param lun : logical unit number - * @retval Status - */ -int8_t SDCARD_STORAGE_IsReady(uint8_t lun) { - if (sdcard_started) { - return 0; - } - return -1; -} - -/** - * @brief check whether the medium is write-protected - * @param lun : logical unit number - * @retval Status - */ -int8_t SDCARD_STORAGE_IsWriteProtected(uint8_t lun) { - return 0; -} - -// Remove the lun -int8_t SDCARD_STORAGE_StartStopUnit(uint8_t lun, uint8_t started) { - sdcard_started = started; - return 0; -} - -int8_t SDCARD_STORAGE_PreventAllowMediumRemoval(uint8_t lun, uint8_t param) { - return 0; -} - -/** - * @brief Read data from the medium - * @param lun : logical unit number - * @param buf : Pointer to the buffer to save data - * @param blk_addr : address of 1st block to be read - * @param blk_len : nmber of blocks to be read - * @retval Status - */ -int8_t SDCARD_STORAGE_Read(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) { - if (sdcard_read_blocks(buf, blk_addr, blk_len) != 0) { - return -1; - } - return 0; -} - -/** - * @brief Write data to the medium - * @param lun : logical unit number - * @param buf : Pointer to the buffer to write from - * @param blk_addr : address of 1st block to be written - * @param blk_len : nmber of blocks to be read - * @retval Status - */ -int8_t SDCARD_STORAGE_Write(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) { - if (sdcard_write_blocks(buf, blk_addr, blk_len) != 0) { - return -1; - } - return 0; -} - -/** - * @brief Return number of supported logical unit - * @param None - * @retval number of logical unit - */ -int8_t SDCARD_STORAGE_GetMaxLun(void) { - return 0; -} - -const USBD_StorageTypeDef USBD_SDCARD_STORAGE_fops = { - SDCARD_STORAGE_Init, - SDCARD_STORAGE_GetCapacity, - SDCARD_STORAGE_IsReady, - SDCARD_STORAGE_IsWriteProtected, - SDCARD_STORAGE_StartStopUnit, - SDCARD_STORAGE_PreventAllowMediumRemoval, - SDCARD_STORAGE_Read, - SDCARD_STORAGE_Write, - SDCARD_STORAGE_GetMaxLun, - (int8_t *)SDCARD_STORAGE_Inquirydata, -}; - -#endif // MICROPY_HW_ENABLE_SDCARD From 829aa58c5ca5dc9681b642c27c9a6906957ca643 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 11 Jun 2019 15:23:22 +1000 Subject: [PATCH 0437/1788] stm32/usbd_msc: Provide custom irquiry processing by MSC interface. So the MSC interface can customise the inquiry response based on the attached logical units. --- ports/stm32/usbd_msc_interface.c | 59 ++++++++++++++++++- .../stm32/usbdev/class/inc/usbd_cdc_msc_hid.h | 2 +- ports/stm32/usbdev/class/src/usbd_msc_scsi.c | 28 ++------- 3 files changed, 64 insertions(+), 25 deletions(-) diff --git a/ports/stm32/usbd_msc_interface.c b/ports/stm32/usbd_msc_interface.c index 493dece1f9..6a81d14f63 100644 --- a/ports/stm32/usbd_msc_interface.c +++ b/ports/stm32/usbd_msc_interface.c @@ -57,6 +57,21 @@ static inline bool lu_flag_is_set(uint8_t lun, uint8_t flag) { return usbd_msc_lu_flags & (flag << (lun * 2)); } +STATIC const uint8_t usbd_msc_vpd00[6] = { + 0x00, // peripheral qualifier; peripheral device type + 0x00, // page code + 0x00, // reserved + 2, // page length (additional bytes beyond this entry) + 0x00, // page 0x00 supported + 0x83, // page 0x83 supported +}; + +STATIC const uint8_t usbd_msc_vpd83[4] = { + 0x00, // peripheral qualifier; peripheral device type + 0x83, // page code + 0x00, 0x00, // page length (additional bytes beyond this entry) +}; + STATIC const int8_t usbd_msc_inquiry_data[36] = { 0x00, // peripheral qualifier; peripheral device type 0x80, // 0x00 for a fixed drive, 0x80 for a removable drive @@ -152,6 +167,48 @@ STATIC int8_t usbd_msc_Init(uint8_t lun_in) { return 0; } +// Process SCSI INQUIRY command for the logical unit +STATIC int usbd_msc_Inquiry(uint8_t lun, const uint8_t *params, uint8_t *data_out) { + if (params[1] & 1) { + // EVPD set - return vital product data parameters + uint8_t page_code = params[2]; + switch (page_code) { + case 0x00: // Supported VPD pages + memcpy(data_out, usbd_msc_vpd00, sizeof(usbd_msc_vpd00)); + return sizeof(usbd_msc_vpd00); + case 0x83: // Device identification + memcpy(data_out, usbd_msc_vpd83, sizeof(usbd_msc_vpd83)); + return sizeof(usbd_msc_vpd83); + default: // Unsupported + return -1; + } + } + + // A standard inquiry + + if (lun >= usbd_msc_lu_num) { + return -1; + } + const void *lu = usbd_msc_lu_data[lun]; + + uint8_t alloc_len = params[3] << 8 | params[4]; + int len = MIN(sizeof(usbd_msc_inquiry_data), alloc_len); + memcpy(data_out, usbd_msc_inquiry_data, len); + + if (len == sizeof(usbd_msc_inquiry_data)) { + if (lu == &pyb_sdcard_type) { + memcpy(data_out + 24, "SDCard", sizeof("SDCard") - 1); + } + #if MICROPY_HW_ENABLE_MMCARD + else if (lu == &pyb_mmcard_type) { + memcpy(data_out + 24, "MMCard", sizeof("MMCard") - 1); + } + #endif + } + + return len; +} + // Get storage capacity of a logical unit STATIC int8_t usbd_msc_GetCapacity(uint8_t lun, uint32_t *block_num, uint16_t *block_size) { uint32_t block_size_u32 = 0; @@ -251,6 +308,7 @@ STATIC int8_t usbd_msc_GetMaxLun(void) { // Table of operations for the SCSI layer to call const USBD_StorageTypeDef usbd_msc_fops = { usbd_msc_Init, + usbd_msc_Inquiry, usbd_msc_GetCapacity, usbd_msc_IsReady, usbd_msc_IsWriteProtected, @@ -259,5 +317,4 @@ const USBD_StorageTypeDef usbd_msc_fops = { usbd_msc_Read, usbd_msc_Write, usbd_msc_GetMaxLun, - (int8_t *)usbd_msc_inquiry_data, }; 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 d46f763d1d..eaa39f1878 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h @@ -61,6 +61,7 @@ typedef struct { typedef struct _USBD_STORAGE { int8_t (* Init) (uint8_t lun); + int (* Inquiry) (uint8_t lun, const uint8_t *params, uint8_t *data_out); int8_t (* GetCapacity) (uint8_t lun, uint32_t *block_num, uint16_t *block_size); int8_t (* IsReady) (uint8_t lun); int8_t (* IsWriteProtected) (uint8_t lun); @@ -69,7 +70,6 @@ typedef struct _USBD_STORAGE { int8_t (* Read) (uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len); int8_t (* Write)(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len); int8_t (* GetMaxLun)(void); - int8_t *pInquiry; } USBD_StorageTypeDef; typedef struct { diff --git a/ports/stm32/usbdev/class/src/usbd_msc_scsi.c b/ports/stm32/usbdev/class/src/usbd_msc_scsi.c index 9da9033771..8651b3ca87 100644 --- a/ports/stm32/usbdev/class/src/usbd_msc_scsi.c +++ b/ports/stm32/usbdev/class/src/usbd_msc_scsi.c @@ -225,33 +225,15 @@ static int8_t SCSI_TestUnitReady(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t */ 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*/ + int res = hmsc->bdev_ops->Inquiry(lun, params, hmsc->bot_data); + if (res < 0) { - 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]; + SCSI_SenseCode(pdev, lun, ILLEGAL_REQUEST, INVALID_CDB); + return -1; } + hmsc->bot_data_length = res; return 0; } From 38bcc99a586d7d6e5f51fcb330a12c4c42007162 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 11 Jun 2019 15:35:15 +1000 Subject: [PATCH 0438/1788] stm32/usbd_msc: Provide Mode Sense response data in MSC interface. Eventually these responses could be filled in by a function to make their contents dynamic, depending on the attached logical units. But for now they are fixed, and this patch fixes the MODE SENSE(6) responses so it is the correct length with the correct header. --- ports/stm32/Makefile | 1 - ports/stm32/usbd_msc_interface.c | 18 +++ .../stm32/usbdev/class/inc/usbd_cdc_msc_hid.h | 3 + ports/stm32/usbdev/class/inc/usbd_msc_data.h | 104 -------------- ports/stm32/usbdev/class/src/usbd_msc_data.c | 134 ------------------ ports/stm32/usbdev/class/src/usbd_msc_scsi.c | 9 +- 6 files changed, 25 insertions(+), 244 deletions(-) delete mode 100644 ports/stm32/usbdev/class/inc/usbd_msc_data.h delete mode 100644 ports/stm32/usbdev/class/src/usbd_msc_data.c diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 12edbcc7f7..4c9a2342ca 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -349,7 +349,6 @@ SRC_USBDEV = $(addprefix $(USBDEV_DIR)/,\ class/src/usbd_cdc_msc_hid.c \ class/src/usbd_msc_bot.c \ class/src/usbd_msc_scsi.c \ - class/src/usbd_msc_data.c \ ) ifeq ($(MICROPY_PY_NETWORK_CYW43),1) diff --git a/ports/stm32/usbd_msc_interface.c b/ports/stm32/usbd_msc_interface.c index 6a81d14f63..0148fc7c6c 100644 --- a/ports/stm32/usbd_msc_interface.c +++ b/ports/stm32/usbd_msc_interface.c @@ -57,6 +57,24 @@ static inline bool lu_flag_is_set(uint8_t lun, uint8_t flag) { return usbd_msc_lu_flags & (flag << (lun * 2)); } +// Sent in response to MODE SENSE(6) command +const uint8_t USBD_MSC_Mode_Sense6_Data[4] = { + 0x03, // mode data length + 0x00, // medium type + 0x00, // bit 7: write protect + 0x00, // block descriptor length +}; + +// Sent in response to MODE SENSE(10) command +const uint8_t USBD_MSC_Mode_Sense10_Data[8] = { + 0x00, 0x06, // mode data length + 0x00, // medium type + 0x00, // bit 7: write protect + 0x00, + 0x00, + 0x00, 0x00, // block descriptor length +}; + STATIC const uint8_t usbd_msc_vpd00[6] = { 0x00, // peripheral qualifier; peripheral device type 0x00, // page code 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 eaa39f1878..c41908d25b 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h @@ -131,6 +131,9 @@ typedef struct _usbd_cdc_msc_hid_state_t { usbd_hid_state_t *hid; } usbd_cdc_msc_hid_state_t; +extern const uint8_t USBD_MSC_Mode_Sense6_Data[4]; +extern const uint8_t USBD_MSC_Mode_Sense10_Data[8]; + #define USBD_HID_MOUSE_MAX_PACKET (4) #define USBD_HID_MOUSE_REPORT_DESC_SIZE (74) diff --git a/ports/stm32/usbdev/class/inc/usbd_msc_data.h b/ports/stm32/usbdev/class/inc/usbd_msc_data.h deleted file mode 100644 index afd39e4f09..0000000000 --- a/ports/stm32/usbdev/class/inc/usbd_msc_data.h +++ /dev/null @@ -1,104 +0,0 @@ -/** - ****************************************************************************** - * @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/src/usbd_msc_data.c b/ports/stm32/usbdev/class/src/usbd_msc_data.c deleted file mode 100644 index 96740a3a4f..0000000000 --- a/ports/stm32/usbdev/class/src/usbd_msc_data.c +++ /dev/null @@ -1,134 +0,0 @@ -/** - ****************************************************************************** - * @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 8651b3ca87..26556bb48e 100644 --- a/ports/stm32/usbdev/class/src/usbd_msc_scsi.c +++ b/ports/stm32/usbdev/class/src/usbd_msc_scsi.c @@ -28,7 +28,6 @@ /* Includes ------------------------------------------------------------------*/ #include "usbd_msc_bot.h" #include "usbd_msc_scsi.h" -#include "usbd_msc_data.h" #include "usbd_cdc_msc_hid.h" @@ -328,13 +327,13 @@ static int8_t SCSI_ReadFormatCapacity(USBD_HandleTypeDef *pdev, uint8_t lun, ui 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 ; + uint16_t len = sizeof(USBD_MSC_Mode_Sense6_Data); hmsc->bot_data_length = len; while (len) { len--; - hmsc->bot_data[len] = MSC_Mode_Sense6_data[len]; + hmsc->bot_data[len] = USBD_MSC_Mode_Sense6_Data[len]; } return 0; } @@ -348,7 +347,7 @@ static int8_t SCSI_ModeSense6 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t * */ static int8_t SCSI_ModeSense10 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) { - uint16_t len = 8; + uint16_t len = sizeof(USBD_MSC_Mode_Sense10_Data); USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; hmsc->bot_data_length = len; @@ -356,7 +355,7 @@ static int8_t SCSI_ModeSense10 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t while (len) { len--; - hmsc->bot_data[len] = MSC_Mode_Sense10_data[len]; + hmsc->bot_data[len] = USBD_MSC_Mode_Sense10_Data[len]; } return 0; } From 9e68eec8eac1188eab0bc059560b877928783978 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 11 Jun 2019 15:50:21 +1000 Subject: [PATCH 0439/1788] stm32/usb: Use ARG_xxx enums to access kw args in pyb_usb_mode. --- ports/stm32/usb.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index 8a0591a49b..1582654115 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -226,6 +226,7 @@ usbd_cdc_itf_t *usb_vcp_get(int idx) { */ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_mode, ARG_vid, ARG_pid, ARG_hid, ARG_high_speed }; static const mp_arg_t allowed_args[] = { { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, { MP_QSTR_vid, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = USBD_VID} }, @@ -269,14 +270,14 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * pyb_usb_flags |= PYB_USB_FLAG_USB_MODE_CALLED; // check if user wants to disable the USB - if (args[0].u_obj == mp_const_none) { + if (args[ARG_mode].u_obj == mp_const_none) { // disable usb pyb_usb_dev_deinit(); return mp_const_none; } // get mode string - const char *mode_str = mp_obj_str_get_str(args[0].u_obj); + const char *mode_str = mp_obj_str_get_str(args[ARG_mode].u_obj); #if defined(USE_HOST_MODE) @@ -295,50 +296,50 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * // get the VID, PID and USB mode // note: PID=-1 means select PID based on mode // note: we support CDC as a synonym for VCP for backward compatibility - uint16_t vid = args[1].u_int; - uint16_t pid = args[2].u_int; + uint16_t vid = args[ARG_vid].u_int; + uint16_t pid = args[ARG_pid].u_int; uint8_t mode; if (strcmp(mode_str, "CDC+MSC") == 0 || strcmp(mode_str, "VCP+MSC") == 0) { - if (args[2].u_int == -1) { + if (pid == -1) { pid = USBD_PID_CDC_MSC; } mode = USBD_MODE_CDC_MSC; #if MICROPY_HW_USB_CDC_NUM >= 2 } else if (strcmp(mode_str, "VCP+VCP") == 0) { - if (args[2].u_int == -1) { + if (pid == -1) { pid = USBD_PID_CDC2; } mode = USBD_MODE_CDC2; } else if (strcmp(mode_str, "VCP+VCP+MSC") == 0) { - if (args[2].u_int == -1) { + if (pid == -1) { pid = USBD_PID_CDC2_MSC; } mode = USBD_MODE_CDC2_MSC; #endif #if MICROPY_HW_USB_CDC_NUM >= 3 } else if (strcmp(mode_str, "3xVCP") == 0) { - if (args[2].u_int == -1) { + if (pid == -1) { pid = USBD_PID_CDC3; } mode = USBD_MODE_CDC3; } else if (strcmp(mode_str, "3xVCP+MSC") == 0) { - if (args[2].u_int == -1) { + if (pid == -1) { pid = USBD_PID_CDC3_MSC; } mode = USBD_MODE_CDC3_MSC; #endif } else if (strcmp(mode_str, "CDC+HID") == 0 || strcmp(mode_str, "VCP+HID") == 0) { - if (args[2].u_int == -1) { + if (pid == -1) { pid = USBD_PID_CDC_HID; } mode = USBD_MODE_CDC_HID; } else if (strcmp(mode_str, "CDC") == 0 || strcmp(mode_str, "VCP") == 0) { - if (args[2].u_int == -1) { + if (pid == -1) { pid = USBD_PID_CDC; } mode = USBD_MODE_CDC; } else if (strcmp(mode_str, "MSC") == 0) { - if (args[2].u_int == -1) { + if (pid == -1) { pid = USBD_PID_MSC; } mode = USBD_MODE_MSC; @@ -350,7 +351,7 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * USBD_HID_ModeInfoTypeDef hid_info; if (mode & USBD_MODE_IFACE_HID) { mp_obj_t *items; - mp_obj_get_array_fixed_n(args[3].u_obj, 5, &items); + mp_obj_get_array_fixed_n(args[ARG_hid].u_obj, 5, &items); hid_info.subclass = mp_obj_get_int(items[0]); hid_info.protocol = mp_obj_get_int(items[1]); hid_info.max_packet_len = mp_obj_get_int(items[2]); @@ -365,7 +366,7 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * } #if USBD_SUPPORT_HS_MODE - if (args[4].u_bool) { + if (args[ARG_high_speed].u_bool) { mode |= USBD_MODE_HIGH_SPEED; } #endif From 53200247b779358ffa03e1b7a8d1e9964befc234 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 11 Jun 2019 16:10:52 +1000 Subject: [PATCH 0440/1788] stm32/usb: Add "msc" kw-arg to pyb.usb_mode to select MSC logical units. With this the user can select multiple logical units to expose over USB MSC at once, eg: pyb.usb_mode('VCP+MSC', msc=(pyb.Flash(), pyb.SDCard())). The default behaviour is the original behaviour of just one unit at a time. --- ports/stm32/main.c | 2 +- ports/stm32/usb.c | 57 ++++++++++++++++++++++++-------- ports/stm32/usb.h | 2 +- ports/stm32/usbd_msc_interface.c | 2 -- ports/stm32/usbd_msc_interface.h | 2 ++ 5 files changed, 47 insertions(+), 18 deletions(-) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 3852ff9b04..44e29921b1 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -645,7 +645,7 @@ soft_reset: #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); + pyb_usb_dev_init(USBD_VID, USBD_PID_CDC_MSC, USBD_MODE_CDC_MSC, 0, NULL, NULL); } #endif diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index 1582654115..3e432fc8e5 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -120,7 +120,7 @@ void pyb_usb_init0(void) { pyb_usb_vcp_init0(); } -bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, uint8_t mode, USBD_HID_ModeInfoTypeDef *hid_info) { +bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, uint8_t mode, size_t msc_n, const void *msc_unit, USBD_HID_ModeInfoTypeDef *hid_info) { usb_device_t *usb_dev = &usb_device; if (!usb_dev->enabled) { // only init USB once in the device's power-lifetime @@ -146,18 +146,22 @@ bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, uint8_t mode, USBD_HID_ModeInf } // Configure the MSC interface - const void *lu[1]; - switch (pyb_usb_storage_medium) { - #if MICROPY_HW_ENABLE_SDCARD - case PYB_USB_STORAGE_MEDIUM_SDCARD: - lu[0] = &pyb_sdcard_type; - break; - #endif - default: - lu[0] = &pyb_flash_type; - break; + const void *msc_unit_default[1]; + if (msc_n == 0) { + msc_n = 1; + msc_unit = msc_unit_default; + switch (pyb_usb_storage_medium) { + #if MICROPY_HW_ENABLE_SDCARD + case PYB_USB_STORAGE_MEDIUM_SDCARD: + msc_unit_default[0] = &pyb_sdcard_type; + break; + #endif + default: + msc_unit_default[0] = &pyb_flash_type; + break; + } } - usbd_msc_init_lu(1, lu); + usbd_msc_init_lu(msc_n, msc_unit); USBD_MSC_RegisterStorage(&usb_dev->usbd_cdc_msc_hid_state, (USBD_StorageTypeDef*)&usbd_msc_fops); // start the USB device @@ -226,11 +230,12 @@ usbd_cdc_itf_t *usb_vcp_get(int idx) { */ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_mode, ARG_vid, ARG_pid, ARG_hid, ARG_high_speed }; + enum { ARG_mode, ARG_vid, ARG_pid, ARG_msc, ARG_hid, ARG_high_speed }; static const mp_arg_t allowed_args[] = { { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, { 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_msc, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_empty_tuple_obj)} }, { MP_QSTR_hid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&pyb_usb_hid_mouse_obj)} }, #if USBD_SUPPORT_HS_MODE { MP_QSTR_high_speed, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, @@ -347,6 +352,30 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * goto bad_mode; } + // Get MSC logical units + size_t msc_n = 0; + const void *msc_unit[USBD_MSC_MAX_LUN]; + if (mode & USBD_MODE_IFACE_MSC) { + mp_obj_t *items; + mp_obj_get_array(args[ARG_msc].u_obj, &msc_n, &items); + if (msc_n > USBD_MSC_MAX_LUN) { + mp_raise_ValueError("too many logical units"); + } + for (size_t i = 0; i < msc_n; ++i) { + mp_obj_type_t *type = mp_obj_get_type(items[i]); + if (type == &pyb_flash_type + || type == &pyb_sdcard_type + #if MICROPY_HW_ENABLE_MMCARD + || type == &pyb_mmcard_type + #endif + ) { + msc_unit[i] = type; + } else { + mp_raise_ValueError("unsupported logical unit"); + } + } + } + // get hid info if user selected such a mode USBD_HID_ModeInfoTypeDef hid_info; if (mode & USBD_MODE_IFACE_HID) { @@ -372,7 +401,7 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * #endif // init the USB device - if (!pyb_usb_dev_init(vid, pid, mode, &hid_info)) { + if (!pyb_usb_dev_init(vid, pid, mode, msc_n, msc_unit, &hid_info)) { goto bad_mode; } diff --git a/ports/stm32/usb.h b/ports/stm32/usb.h index 0aa50f9e77..b1c8b476a7 100644 --- a/ports/stm32/usb.h +++ b/ports/stm32/usb.h @@ -66,7 +66,7 @@ MP_DECLARE_CONST_FUN_OBJ_0(pyb_have_cdc_obj); // deprecated MP_DECLARE_CONST_FUN_OBJ_1(pyb_hid_send_report_obj); // deprecated void pyb_usb_init0(void); -bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, uint8_t mode, USBD_HID_ModeInfoTypeDef *hid_info); +bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, uint8_t mode, size_t msc_n, const void *msc_unit, USBD_HID_ModeInfoTypeDef *hid_info); void pyb_usb_dev_deinit(void); bool usb_vcp_is_enabled(void); int usb_vcp_recv_byte(uint8_t *c); // if a byte is available, return 1 and put the byte in *c, else return 0 diff --git a/ports/stm32/usbd_msc_interface.c b/ports/stm32/usbd_msc_interface.c index 0148fc7c6c..1f9f68ed88 100644 --- a/ports/stm32/usbd_msc_interface.c +++ b/ports/stm32/usbd_msc_interface.c @@ -33,8 +33,6 @@ #include "storage.h" #include "sdcard.h" -#define USBD_MSC_MAX_LUN (2) - // This flag is needed to support removal of the medium, so that the USB drive // can be unmounted and won't be remounted automatically. #define FLAGS_STARTED (0x01) diff --git a/ports/stm32/usbd_msc_interface.h b/ports/stm32/usbd_msc_interface.h index 9d25a72a3a..411c707cab 100644 --- a/ports/stm32/usbd_msc_interface.h +++ b/ports/stm32/usbd_msc_interface.h @@ -26,6 +26,8 @@ #ifndef MICROPY_INCLUDED_STM32_USBD_MSC_INTERFACE_H #define MICROPY_INCLUDED_STM32_USBD_MSC_INTERFACE_H +#define USBD_MSC_MAX_LUN (2) + extern const USBD_StorageTypeDef usbd_msc_fops; void usbd_msc_init_lu(size_t lu_n, const void *lu_data); From 8b18cfedee441413d6b53a3d7c083a1e3a1a47e6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 11 Jun 2019 21:01:14 +1000 Subject: [PATCH 0441/1788] stm32/usbd_msc: Allow to compile when USB enabled and SD card disabled. --- ports/stm32/usb.c | 2 ++ ports/stm32/usbd_msc_interface.c | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index 3e432fc8e5..2807d512be 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -364,7 +364,9 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * for (size_t i = 0; i < msc_n; ++i) { mp_obj_type_t *type = mp_obj_get_type(items[i]); if (type == &pyb_flash_type + #if MICROPY_HW_ENABLE_SDCARD || type == &pyb_sdcard_type + #endif #if MICROPY_HW_ENABLE_MMCARD || type == &pyb_mmcard_type #endif diff --git a/ports/stm32/usbd_msc_interface.c b/ports/stm32/usbd_msc_interface.c index 1f9f68ed88..aa2b381a09 100644 --- a/ports/stm32/usbd_msc_interface.c +++ b/ports/stm32/usbd_msc_interface.c @@ -135,6 +135,7 @@ STATIC int lu_ioctl(uint8_t lun, int op, uint32_t *data) { default: return -1; } + #if MICROPY_HW_ENABLE_SDCARD } else if (lu == &pyb_sdcard_type #if MICROPY_HW_ENABLE_MMCARD || lu == &pyb_mmcard_type @@ -158,6 +159,7 @@ STATIC int lu_ioctl(uint8_t lun, int op, uint32_t *data) { default: return -1; } + #endif } else { return -1; } @@ -205,12 +207,13 @@ STATIC int usbd_msc_Inquiry(uint8_t lun, const uint8_t *params, uint8_t *data_ou if (lun >= usbd_msc_lu_num) { return -1; } - const void *lu = usbd_msc_lu_data[lun]; uint8_t alloc_len = params[3] << 8 | params[4]; int len = MIN(sizeof(usbd_msc_inquiry_data), alloc_len); memcpy(data_out, usbd_msc_inquiry_data, len); + #if MICROPY_HW_ENABLE_SDCARD + const void *lu = usbd_msc_lu_data[lun]; if (len == sizeof(usbd_msc_inquiry_data)) { if (lu == &pyb_sdcard_type) { memcpy(data_out + 24, "SDCard", sizeof("SDCard") - 1); @@ -221,6 +224,7 @@ STATIC int usbd_msc_Inquiry(uint8_t lun, const uint8_t *params, uint8_t *data_ou } #endif } + #endif return len; } @@ -282,6 +286,7 @@ STATIC int8_t usbd_msc_Read(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16 if (lu == &pyb_flash_type) { storage_read_blocks(buf, blk_addr, blk_len); return 0; + #if MICROPY_HW_ENABLE_SDCARD } else if (lu == &pyb_sdcard_type #if MICROPY_HW_ENABLE_MMCARD || lu == &pyb_mmcard_type @@ -290,6 +295,7 @@ STATIC int8_t usbd_msc_Read(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16 if (sdcard_read_blocks(buf, blk_addr, blk_len) == 0) { return 0; } + #endif } return -1; } @@ -304,6 +310,7 @@ STATIC int8_t usbd_msc_Write(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint1 if (lu == &pyb_flash_type) { storage_write_blocks(buf, blk_addr, blk_len); return 0; + #if MICROPY_HW_ENABLE_SDCARD } else if (lu == &pyb_sdcard_type #if MICROPY_HW_ENABLE_MMCARD || lu == &pyb_mmcard_type @@ -312,6 +319,7 @@ STATIC int8_t usbd_msc_Write(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint1 if (sdcard_write_blocks(buf, blk_addr, blk_len) == 0) { return 0; } + #endif } return -1; } From 14cf91f70467aa928f3e17223f108ace0864b4fe Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Wed, 15 May 2019 00:43:38 +1000 Subject: [PATCH 0442/1788] stm32: In link script, define start of stack separately from heap end. Previously the end of the heap was the start (lowest address) of the stack. With the changes in this commit these addresses are now independent, allowing a board to place the heap and stack in separate locations. --- ports/stm32/boards/PYBD_SF2/f722_qspi.ld | 8 ++++---- ports/stm32/boards/PYBD_SF6/f767.ld | 8 ++++---- ports/stm32/boards/STM32F769DISC/f769_qspi.ld | 6 ++++-- ports/stm32/boards/stm32f091xc.ld | 8 ++++---- ports/stm32/boards/stm32f401xd.ld | 10 +++++----- ports/stm32/boards/stm32f401xe.ld | 8 ++++---- ports/stm32/boards/stm32f405.ld | 8 ++++---- ports/stm32/boards/stm32f411.ld | 8 ++++---- ports/stm32/boards/stm32f413xg.ld | 8 ++++---- ports/stm32/boards/stm32f413xh.ld | 8 ++++---- ports/stm32/boards/stm32f429.ld | 8 ++++---- ports/stm32/boards/stm32f439.ld | 6 ++++-- ports/stm32/boards/stm32f722.ld | 8 ++++---- ports/stm32/boards/stm32f746.ld | 10 +++++----- ports/stm32/boards/stm32f767.ld | 8 ++++---- ports/stm32/boards/stm32f769.ld | 8 ++++---- ports/stm32/boards/stm32h743.ld | 8 ++++---- ports/stm32/boards/stm32l432.ld | 8 ++++---- ports/stm32/boards/stm32l476xe.ld | 8 ++++---- ports/stm32/boards/stm32l476xg.ld | 8 ++++---- ports/stm32/boards/stm32l496xg.ld | 8 ++++---- ports/stm32/gccollect.h | 1 + ports/stm32/main.c | 2 +- ports/stm32/modmachine.c | 1 + ports/stm32/pybthread.c | 4 ++-- ports/stm32/stm32_it.c | 2 +- 26 files changed, 92 insertions(+), 86 deletions(-) diff --git a/ports/stm32/boards/PYBD_SF2/f722_qspi.ld b/ports/stm32/boards/PYBD_SF2/f722_qspi.ld index 49b46bce50..e9d6fa3c39 100644 --- a/ports/stm32/boards/PYBD_SF2/f722_qspi.ld +++ b/ports/stm32/boards/PYBD_SF2/f722_qspi.ld @@ -29,16 +29,16 @@ MEMORY _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. */ +/* Define 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); +_sstack = _estack - 16K; /* 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 = _ram_end - 16K; /* 16k stack */ +_heap_end = _sstack; ENTRY(Reset_Handler) diff --git a/ports/stm32/boards/PYBD_SF6/f767.ld b/ports/stm32/boards/PYBD_SF6/f767.ld index 7f13eb45fe..2a474fba07 100644 --- a/ports/stm32/boards/PYBD_SF6/f767.ld +++ b/ports/stm32/boards/PYBD_SF6/f767.ld @@ -28,16 +28,16 @@ MEMORY _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. */ +/* Define 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); +_sstack = _estack - 24K; /* 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 = _ram_end - 24K; /* 24k stack */ +_heap_end = _sstack; ENTRY(Reset_Handler) diff --git a/ports/stm32/boards/STM32F769DISC/f769_qspi.ld b/ports/stm32/boards/STM32F769DISC/f769_qspi.ld index eb2cf783eb..362fab3305 100644 --- a/ports/stm32/boards/STM32F769DISC/f769_qspi.ld +++ b/ports/stm32/boards/STM32F769DISC/f769_qspi.ld @@ -27,14 +27,16 @@ MEMORY _minimum_stack_size = 2K; _minimum_heap_size = 16K; -/* Define tho top end of the stack */ +/* Define 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); +_sstack = _estack - 32K; /* tunable */ /* 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 = 0x20078000; /* tunable */ +_heap_end = _sstack; ENTRY(Reset_Handler) diff --git a/ports/stm32/boards/stm32f091xc.ld b/ports/stm32/boards/stm32f091xc.ld index 73b8442957..5e1e9e7bd3 100644 --- a/ports/stm32/boards/stm32f091xc.ld +++ b/ports/stm32/boards/stm32f091xc.ld @@ -14,13 +14,13 @@ MEMORY _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. */ +/* Define the stack. The stack is full descending so begins just above last byte above last byte + of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */ _estack = ORIGIN(RAM) + LENGTH(RAM); +_sstack = _estack - 6K; /* tunable */ /* 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 */ +_heap_end = _sstack; diff --git a/ports/stm32/boards/stm32f401xd.ld b/ports/stm32/boards/stm32f401xd.ld index 7c0e790185..50cb3c571b 100644 --- a/ports/stm32/boards/stm32f401xd.ld +++ b/ports/stm32/boards/stm32f401xd.ld @@ -14,15 +14,15 @@ MEMORY /* produce a link error if there is not this amount of RAM for these sections */ _minimum_stack_size = 2K; -_minimum_heap_size = 16K; +_minimum_heap_size = 16K; /* tunable */ -/* 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. */ +/* Define 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); +_sstack = _estack - 16K; /* 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 = 0x20014000; /* tunable */ +_heap_end = _sstack; diff --git a/ports/stm32/boards/stm32f401xe.ld b/ports/stm32/boards/stm32f401xe.ld index e76bbad1c2..78e0dc1cba 100644 --- a/ports/stm32/boards/stm32f401xe.ld +++ b/ports/stm32/boards/stm32f401xe.ld @@ -16,13 +16,13 @@ MEMORY _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. */ +/* Define 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); +_sstack = _estack - 16K; /* tunable */ /* 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 = 0x20014000; /* tunable */ +_heap_end = _sstack; diff --git a/ports/stm32/boards/stm32f405.ld b/ports/stm32/boards/stm32f405.ld index 0375491f65..13133e8c6d 100644 --- a/ports/stm32/boards/stm32f405.ld +++ b/ports/stm32/boards/stm32f405.ld @@ -17,13 +17,13 @@ MEMORY _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. */ +/* Define 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); +_sstack = _estack - 16K; /* tunable */ /* 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 = 0x2001c000; /* tunable */ +_heap_end = _sstack; diff --git a/ports/stm32/boards/stm32f411.ld b/ports/stm32/boards/stm32f411.ld index 9e3e6bc154..8ae5f6929c 100644 --- a/ports/stm32/boards/stm32f411.ld +++ b/ports/stm32/boards/stm32f411.ld @@ -16,13 +16,13 @@ MEMORY _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. */ +/* Define 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); +_sstack = _estack - 16K; /* tunable */ /* 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 = 0x2001c000; /* tunable */ +_heap_end = _sstack; diff --git a/ports/stm32/boards/stm32f413xg.ld b/ports/stm32/boards/stm32f413xg.ld index cac313bc67..c2719b834f 100644 --- a/ports/stm32/boards/stm32f413xg.ld +++ b/ports/stm32/boards/stm32f413xg.ld @@ -19,13 +19,13 @@ MEMORY _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. */ +/* Define 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); +_sstack = _estack - 16K; /* tunable */ /* 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 = _ram_end - 16K; /* 240K, tunable */ +_heap_end = _sstack; diff --git a/ports/stm32/boards/stm32f413xh.ld b/ports/stm32/boards/stm32f413xh.ld index f6dc430e32..017dbbac17 100644 --- a/ports/stm32/boards/stm32f413xh.ld +++ b/ports/stm32/boards/stm32f413xh.ld @@ -19,13 +19,13 @@ MEMORY _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. */ +/* Define 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); +_sstack = _estack - 16K; /* tunable */ /* 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 = _ram_end - 16K; /* 240K, tunable */ +_heap_end = _sstack; diff --git a/ports/stm32/boards/stm32f429.ld b/ports/stm32/boards/stm32f429.ld index d91f625ef6..35d0736eef 100644 --- a/ports/stm32/boards/stm32f429.ld +++ b/ports/stm32/boards/stm32f429.ld @@ -17,13 +17,13 @@ MEMORY _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. */ +/* Define 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); +_sstack = _estack - 16K; /* tunable */ /* 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 = 0x2002c000; /* tunable */ +_heap_end = _sstack; diff --git a/ports/stm32/boards/stm32f439.ld b/ports/stm32/boards/stm32f439.ld index 16c606eccc..2b51c3a371 100644 --- a/ports/stm32/boards/stm32f439.ld +++ b/ports/stm32/boards/stm32f439.ld @@ -18,11 +18,13 @@ MEMORY _minimum_stack_size = 2K; _minimum_heap_size = 16K; -/* top end of the stack */ +/* Define 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); +_sstack = _estack - 16K; /* tunable */ /* 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 = 0x2002c000; /* tunable */ +_heap_end = _sstack; diff --git a/ports/stm32/boards/stm32f722.ld b/ports/stm32/boards/stm32f722.ld index f2a1d85117..8986c68d52 100644 --- a/ports/stm32/boards/stm32f722.ld +++ b/ports/stm32/boards/stm32f722.ld @@ -15,13 +15,13 @@ MEMORY _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. */ +/* Define 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); +_sstack = _estack - 32K; /* tunable */ /* 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 */ +_heap_end = _sstack; diff --git a/ports/stm32/boards/stm32f746.ld b/ports/stm32/boards/stm32f746.ld index b5864453dd..330dd97141 100644 --- a/ports/stm32/boards/stm32f746.ld +++ b/ports/stm32/boards/stm32f746.ld @@ -1,5 +1,5 @@ /* - GNU linker script for STM32F405 + GNU linker script for STM32F746 */ /* Specify the memory areas */ @@ -17,13 +17,13 @@ MEMORY _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. */ +/* Define 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); +_sstack = _estack - 16K; /* tunable */ /* 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 = 0x2004c000; /* tunable */ +_heap_end = _sstack; diff --git a/ports/stm32/boards/stm32f767.ld b/ports/stm32/boards/stm32f767.ld index c05fd8021b..47e992c2dd 100644 --- a/ports/stm32/boards/stm32f767.ld +++ b/ports/stm32/boards/stm32f767.ld @@ -18,13 +18,13 @@ MEMORY _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. */ +/* Define 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); +_sstack = _estack - 32K; /* tunable */ /* 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 = 0x20078000; /* tunable */ +_heap_end = _sstack; diff --git a/ports/stm32/boards/stm32f769.ld b/ports/stm32/boards/stm32f769.ld index d6da439435..41bb321a37 100644 --- a/ports/stm32/boards/stm32f769.ld +++ b/ports/stm32/boards/stm32f769.ld @@ -17,13 +17,13 @@ MEMORY _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. */ +/* Define 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); +_sstack = _estack - 32K; /* tunable */ /* 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 = 0x20078000; /* tunable */ +_heap_end = _sstack; diff --git a/ports/stm32/boards/stm32h743.ld b/ports/stm32/boards/stm32h743.ld index ca429edb7b..0f1c2b777e 100644 --- a/ports/stm32/boards/stm32h743.ld +++ b/ports/stm32/boards/stm32h743.ld @@ -17,13 +17,13 @@ MEMORY _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. */ +/* Define 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); +_sstack = _estack - 16K; /* tunable */ /* 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 */ +_heap_end = _sstack; diff --git a/ports/stm32/boards/stm32l432.ld b/ports/stm32/boards/stm32l432.ld index 70956c95be..40515e75b3 100644 --- a/ports/stm32/boards/stm32l432.ld +++ b/ports/stm32/boards/stm32l432.ld @@ -15,13 +15,13 @@ MEMORY _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. */ +/* Define 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); +_sstack = _estack - 6K; /* tunable */ /* 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 = 0x2000A800; /* room for a 6k stack */ +_heap_end = _sstack; diff --git a/ports/stm32/boards/stm32l476xe.ld b/ports/stm32/boards/stm32l476xe.ld index 31929517d7..330ec96e67 100644 --- a/ports/stm32/boards/stm32l476xe.ld +++ b/ports/stm32/boards/stm32l476xe.ld @@ -18,10 +18,10 @@ MEMORY _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. */ +/* Define 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); +_sstack = _estack - 16K; /* tunable */ /* RAM extents for the garbage collector */ _ram_fs_cache_start = ORIGIN(FS_CACHE); @@ -29,7 +29,7 @@ _ram_fs_cache_end = ORIGIN(FS_CACHE) + LENGTH(FS_CACHE); _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); _heap_start = _ebss; /* heap starts just after statically allocated memory */ -_heap_end = 0x20014000; /* tunable */ +_heap_end = _sstack; _flash_fs_start = ORIGIN(FLASH_FS); _flash_fs_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); diff --git a/ports/stm32/boards/stm32l476xg.ld b/ports/stm32/boards/stm32l476xg.ld index 59c5d90b69..7983fb39a1 100644 --- a/ports/stm32/boards/stm32l476xg.ld +++ b/ports/stm32/boards/stm32l476xg.ld @@ -18,10 +18,10 @@ MEMORY _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. */ +/* Define 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); +_sstack = _estack - 16K; /* tunable */ /* RAM extents for the garbage collector */ _ram_fs_cache_start = ORIGIN(FS_CACHE); @@ -29,7 +29,7 @@ _ram_fs_cache_end = ORIGIN(FS_CACHE) + LENGTH(FS_CACHE); _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); _heap_start = _ebss; /* heap starts just after statically allocated memory */ -_heap_end = 0x20014000; /* tunable */ +_heap_end = _sstack; _flash_fs_start = ORIGIN(FLASH_FS); _flash_fs_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); diff --git a/ports/stm32/boards/stm32l496xg.ld b/ports/stm32/boards/stm32l496xg.ld index b420873199..e1ceb50707 100644 --- a/ports/stm32/boards/stm32l496xg.ld +++ b/ports/stm32/boards/stm32l496xg.ld @@ -18,10 +18,10 @@ MEMORY _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. */ +/* Define 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); +_sstack = _estack - 206K; /* tunable */ /* RAM extents for the garbage collector */ _ram_fs_cache_start = ORIGIN(FS_CACHE); @@ -29,7 +29,7 @@ _ram_fs_cache_end = ORIGIN(FS_CACHE) + 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 */ +_heap_end = _sstack; _flash_fs_start = ORIGIN(FLASH_FS); _flash_fs_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); diff --git a/ports/stm32/gccollect.h b/ports/stm32/gccollect.h index 25a74a306a..4992a96897 100644 --- a/ports/stm32/gccollect.h +++ b/ports/stm32/gccollect.h @@ -37,6 +37,7 @@ extern uint32_t _sbss; extern uint32_t _ebss; extern uint32_t _heap_start; extern uint32_t _heap_end; +extern uint32_t _sstack; extern uint32_t _estack; extern uint32_t _ram_end; diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 44e29921b1..523034e097 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -536,7 +536,7 @@ soft_reset: // to recover from limit hit. (Limit is measured in bytes.) // Note: stack control relies on main thread being initialised above mp_stack_set_top(&_estack); - mp_stack_set_limit((char*)&_estack - (char*)&_heap_end - 1024); + mp_stack_set_limit((char*)&_estack - (char*)&_sstack - 1024); // GC init gc_init(MICROPY_HEAP_START, MICROPY_HEAP_END); diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index eca8322eac..cf615ea6aa 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -174,6 +174,7 @@ STATIC mp_obj_t machine_info(size_t n_args, const mp_obj_t *args) { printf("_edata=%p\n", &_edata); printf("_sbss=%p\n", &_sbss); printf("_ebss=%p\n", &_ebss); + printf("_sstack=%p\n", &_sstack); printf("_estack=%p\n", &_estack); printf("_ram_start=%p\n", &_ram_start); printf("_heap_start=%p\n", &_heap_start); diff --git a/ports/stm32/pybthread.c b/ports/stm32/pybthread.c index 6baf88f66b..d6e9a3f515 100644 --- a/ports/stm32/pybthread.c +++ b/ports/stm32/pybthread.c @@ -70,8 +70,8 @@ void pyb_thread_init(pyb_thread_t *thread) { thread->sp = NULL; // will be set when this thread switches out thread->local_state = 0; // will be set by mp_thread_init thread->arg = NULL; - thread->stack = &_heap_end; - thread->stack_len = ((uint32_t)&_estack - (uint32_t)&_heap_end) / sizeof(uint32_t); + thread->stack = &_sstack; + thread->stack_len = ((uint32_t)&_estack - (uint32_t)&_sstack) / sizeof(uint32_t); thread->all_next = NULL; thread->run_prev = thread; thread->run_next = thread; diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index 078b143bbd..0c5263e053 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -181,7 +181,7 @@ void HardFault_C_Handler(ExceptionRegisters_t *regs) { if ((void*)&_ram_start <= (void*)regs && (void*)regs < (void*)&_ram_end) { mp_hal_stdout_tx_str("Stack:\r\n"); uint32_t *stack_top = &_estack; - if ((void*)regs < (void*)&_heap_end) { + if ((void*)regs < (void*)&_sstack) { // stack not in static stack area so limit the amount we print stack_top = (uint32_t*)regs + 32; } From 637aa9784dc96301cfa5c4ccdd0ab1ae7bad5744 Mon Sep 17 00:00:00 2001 From: "Paul m. p. P" Date: Fri, 14 Jun 2019 22:22:03 +0200 Subject: [PATCH 0443/1788] esp8266/uart: Fix invalid ringbuf name when event driven REPL enabled. --- 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 cf9e8f61b2..61715f5ce1 100644 --- a/ports/esp8266/uart.c +++ b/ports/esp8266/uart.c @@ -301,7 +301,7 @@ void uart_task_handler(os_event_t *evt) { } int c, ret = 0; - while ((c = ringbuf_get(&input_buf)) >= 0) { + while ((c = ringbuf_get(&stdin_ringbuf)) >= 0) { if (c == mp_interrupt_char) { mp_keyboard_interrupt(); } From 1a51fc9ddf889c6a81e0156e6d438e4228479874 Mon Sep 17 00:00:00 2001 From: Nicko van Someren Date: Sun, 16 Jun 2019 11:57:54 -0600 Subject: [PATCH 0444/1788] esp32/machine_sdcard: Fix bug in SPI slot number selection. And fix minor typo in docs when referring to SDCard class. --- docs/library/machine.SDCard.rst | 2 +- ports/esp32/machine_sdcard.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/library/machine.SDCard.rst b/docs/library/machine.SDCard.rst index 34bb2e48bf..8398624c15 100644 --- a/docs/library/machine.SDCard.rst +++ b/docs/library/machine.SDCard.rst @@ -30,7 +30,7 @@ vary from platform to platform. The class implements the block protocol defined by :class:`uos.AbstractBlockDev`. This allows the mounting of an SD card to be as simple as:: - uos.mount(storage.SDCard(), "/sd") + uos.mount(machine.SDCard(), "/sd") The constrcutor takes the following paramters: diff --git a/ports/esp32/machine_sdcard.c b/ports/esp32/machine_sdcard.c index 633d4031d6..1400c56f35 100644 --- a/ports/esp32/machine_sdcard.c +++ b/ports/esp32/machine_sdcard.c @@ -203,7 +203,6 @@ STATIC mp_obj_t machine_sdcard_make_new(const mp_obj_type_t *type, size_t n_args if (is_spi) { self->host.slot = slot_num ? HSPI_HOST : VSPI_HOST; - slot_num -= 2; } DEBUG_printf(" Calling host.init()"); From 3ee3995be1c6c461110d7908498777241e08a76a Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 17 Jun 2019 18:27:29 +1000 Subject: [PATCH 0445/1788] esp32: Update to use ESP IDF v3.3-beta3. This updates ESP IDF to use v3.3-beta3. And also adjusts README.md to point to stable docs which provide a link to download the correct toolchain for this IDF version, namely 1.22.0-80-g6c4433a-5.2.0 --- ports/esp32/Makefile | 26 ++++++++++++++++++-------- ports/esp32/README.md | 6 +++--- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 98ad196c1d..67e2f52415 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -27,7 +27,7 @@ SDKCONFIG ?= boards/sdkconfig SDKCONFIG_H = $(BUILD)/sdkconfig.h # the git hash of the currently supported ESP IDF version -ESPIDF_SUPHASH := 5c88c5996dbde6208e3bec05abc21ff6cd822d26 +ESPIDF_SUPHASH := 6b3da6b1882f3b72e904cc90be67e9c4e3f369a9 # paths to ESP IDF and its components ifeq ($(ESPIDF),) @@ -78,7 +78,10 @@ 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)/efuse/include +INC_ESPCOMP += -I$(ESPCOMP)/efuse/esp32/include INC_ESPCOMP += -I$(ESPCOMP)/esp32/include +INC_ESPCOMP += -I$(ESPCOMP)/espcoredump/include INC_ESPCOMP += -I$(ESPCOMP)/soc/include INC_ESPCOMP += -I$(ESPCOMP)/soc/esp32/include INC_ESPCOMP += -I$(ESPCOMP)/ethernet/include @@ -134,7 +137,7 @@ LDFLAGS += -u call_user_start_cpu0 -u uxTopUsedPriority -u ld_include_panic_high 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 $(BUILD)/esp32.common.ld +LDFLAGS += -T $(BUILD)/esp32.project.ld LDFLAGS += -T esp32.rom.ld LDFLAGS += -T esp32.rom.libgcc.ld LDFLAGS += -T esp32.peripherals.ld @@ -269,6 +272,12 @@ ESPIDF_DRIVER_O = $(addprefix $(ESPCOMP)/driver/,\ rtc_module.o \ ) +ESPIDF_EFUSE_O = $(addprefix $(ESPCOMP)/efuse/,\ + esp32/esp_efuse_table.o \ + src/esp_efuse_api.o \ + src/esp_efuse_utility.o \ + ) + $(BUILD)/$(ESPCOMP)/esp32/dport_access.o: CFLAGS += -Wno-array-bounds ESPIDF_ESP32_O = $(addprefix $(ESPCOMP)/esp32/,\ brownout.o \ @@ -276,6 +285,7 @@ ESPIDF_ESP32_O = $(addprefix $(ESPCOMP)/esp32/,\ coexist.o \ dbg_stubs.o \ dport_panic_highint_hdl.o \ + esp_adapter.o \ esp_err_to_name.o \ esp_himem.o \ panic.o \ @@ -291,7 +301,6 @@ ESPIDF_ESP32_O = $(addprefix $(ESPCOMP)/esp32/,\ task_wdt.o \ cache_err_int.o \ clk.o \ - core_dump.o \ cpu_start.o \ gdbstub.o \ crosscore_int.o \ @@ -310,7 +319,6 @@ ESPIDF_ESP32_O = $(addprefix $(ESPCOMP)/esp32/,\ intr_alloc.o \ dport_access.o \ wifi_init.o \ - wifi_os_adapter.o \ sleep_modes.o \ spiram.o \ spiram_psram.o \ @@ -685,6 +693,7 @@ ESPIDF_SDMMC_O = $(addprefix $(ESPCOMP)/sdmmc/,\ OBJ_ESPIDF = OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NEWLIB_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_DRIVER_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_EFUSE_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_ESP32_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_ESP_RINGBUF_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_HEAP_O)) @@ -716,6 +725,7 @@ $(OBJ_ESPIDF): $(SDKCONFIG_H) LIB_ESPIDF = LIB_ESPIDF += driver +LIB_ESPIDF += efuse LIB_ESPIDF += esp32 LIB_ESPIDF += esp_ringbuf LIB_ESPIDF += heap @@ -757,6 +767,7 @@ $(BUILD_ESPIDF_LIB)/$(1)/lib$(1).a: $(addprefix $$(BUILD)/,$(2)) endef $(eval $(call gen_espidf_lib_rule,driver,$(ESPIDF_DRIVER_O))) +$(eval $(call gen_espidf_lib_rule,efuse,$(ESPIDF_EFUSE_O))) $(eval $(call gen_espidf_lib_rule,esp32,$(ESPIDF_ESP32_O))) $(eval $(call gen_espidf_lib_rule,esp_ringbuf,$(ESPIDF_ESP_RINGBUF_O))) $(eval $(call gen_espidf_lib_rule,heap,$(ESPIDF_HEAP_O))) @@ -804,7 +815,7 @@ $(eval $(foreach lib,$(LIB_ESPIDF),$(eval $(call gen_sections_info_rule,$(BUILD_ $(LDGEN_SECTION_INFOS): $(LDGEN_SECTIONS_INFO) $(ESPIDF)/make/ldgen.mk $(Q)printf "$(foreach info,$(LDGEN_SECTIONS_INFO),$(info)\n)" > $@ -$(BUILD)/esp32.common.ld: $(ESPCOMP)/esp32/ld/esp32.common.ld.in $(LDGEN_FRAGMENTS) $(SDKCONFIG) $(LDGEN_SECTION_INFOS) +$(BUILD)/esp32.project.ld: $(ESPCOMP)/esp32/ld/esp32.project.ld.in $(LDGEN_FRAGMENTS) $(SDKCONFIG) $(LDGEN_SECTION_INFOS) $(ECHO) "GEN $@" $(Q)$(PYTHON) $(ESPIDF)/tools/ldgen/ldgen.py \ --input $< \ @@ -864,7 +875,7 @@ $(BUILD)/application.bin: $(BUILD)/application.elf $(ECHO) "Create $@" $(Q)$(ESPTOOL) --chip esp32 elf2image --flash_mode $(FLASH_MODE) --flash_freq $(FLASH_FREQ) --flash_size $(FLASH_SIZE) $< -$(BUILD)/application.elf: $(OBJ) $(LIB) $(BUILD)/esp32_out.ld $(BUILD)/esp32.common.ld +$(BUILD)/application.elf: $(OBJ) $(LIB) $(BUILD)/esp32_out.ld $(BUILD)/esp32.project.ld $(ECHO) "LINK $@" $(Q)$(LD) $(LDFLAGS) -o $@ $(APP_LD_ARGS) $(Q)$(SIZE) $@ @@ -891,7 +902,7 @@ $(BUILD)/%.o: %.cpp BOOTLOADER_LIB_DIR = $(BUILD)/bootloader BOOTLOADER_LIB_ALL = -$(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 +$(BUILD)/bootloader/$(ESPCOMP)/%.o: CFLAGS += -DBOOTLOADER_BUILD=1 -I$(ESPCOMP)/bootloader_support/include_priv -I$(ESPCOMP)/bootloader_support/include -I$(ESPCOMP)/micro-ecc/micro-ecc -I$(ESPCOMP)/efuse/include -I$(ESPCOMP)/esp32 -Wno-error=format # libbootloader_support.a BOOTLOADER_LIB_ALL += bootloader_support @@ -903,7 +914,6 @@ BOOTLOADER_LIB_BOOTLOADER_SUPPORT_OBJ = $(addprefix $(BUILD)/bootloader/$(ESPCOM 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 \ diff --git a/ports/esp32/README.md b/ports/esp32/README.md index cd3d5af198..12144d822d 100644 --- a/ports/esp32/README.md +++ b/ports/esp32/README.md @@ -37,9 +37,9 @@ git hash of this version can be found by running `make` without a configured 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) + * [Linux installation](https://docs.espressif.com/projects/esp-idf/en/stable/get-started/linux-setup.html) + * [MacOS installation](https://docs.espressif.com/projects/esp-idf/en/stable/get-started/macos-setup.html) + * [Windows installation](https://docs.espressif.com/projects/esp-idf/en/stable/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) From 34c04d2319cdfae01ed7bf7f9e341d69b86d751a Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 17 Jun 2019 23:19:34 +1000 Subject: [PATCH 0446/1788] py/nlrthumb: Save and restore VFP registers s16-s21 when CPU has them. These s16-s21 registers are used by gcc so need to be saved. Future versions of gcc (beyond v9.1.0), or other compilers, may eventually need additional registers saved/restored. See issue #4844. --- py/nlr.h | 9 ++++++++- py/nlrthumb.c | 10 ++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/py/nlr.h b/py/nlr.h index 90595a12d3..8ce5cf0f4c 100644 --- a/py/nlr.h +++ b/py/nlr.h @@ -54,7 +54,14 @@ #endif #elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__) #define MICROPY_NLR_THUMB (1) - #define MICROPY_NLR_NUM_REGS (10) + #if defined(__SOFTFP__) + #define MICROPY_NLR_NUM_REGS (10) + #else + // With hardware FP registers s16-s31 are callee save so in principle + // should be saved and restored by the NLR code. gcc only uses s16-s21 + // so only save/restore those as an optimisation. + #define MICROPY_NLR_NUM_REGS (10 + 6) + #endif #elif defined(__xtensa__) #define MICROPY_NLR_XTENSA (1) #define MICROPY_NLR_NUM_REGS (10) diff --git a/py/nlrthumb.c b/py/nlrthumb.c index 99061e62cd..32fa6b1176 100644 --- a/py/nlrthumb.c +++ b/py/nlrthumb.c @@ -63,6 +63,11 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { "str r10, [r0, #36] \n" // store r10 into nlr_buf "str r11, [r0, #40] \n" // store r11 into nlr_buf "str r13, [r0, #44] \n" // store r13=sp into nlr_buf + #if MICROPY_NLR_NUM_REGS == 16 + "vstr d8, [r0, #48] \n" // store s16-s17 into nlr_buf + "vstr d9, [r0, #56] \n" // store s18-s19 into nlr_buf + "vstr d10, [r0, #64] \n" // store s20-s21 into nlr_buf + #endif "str lr, [r0, #8] \n" // store lr into nlr_buf #endif @@ -116,6 +121,11 @@ NORETURN void nlr_jump(void *val) { "ldr r10, [r0, #36] \n" // load r10 from nlr_buf "ldr r11, [r0, #40] \n" // load r11 from nlr_buf "ldr r13, [r0, #44] \n" // load r13=sp from nlr_buf + #if MICROPY_NLR_NUM_REGS == 16 + "vldr d8, [r0, #48] \n" // load s16-s17 from nlr_buf + "vldr d9, [r0, #56] \n" // load s18-s19 from nlr_buf + "vldr d10, [r0, #64] \n" // load s20-s21 from nlr_buf + #endif "ldr lr, [r0, #8] \n" // load lr from nlr_buf #endif "movs r0, #1 \n" // return 1, non-local return From b80bccccffea7aab68d4af9580664f77fecc45b2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 12 Jun 2019 18:03:18 +1000 Subject: [PATCH 0447/1788] esp32/modnetwork: Still try to reconnect to WLAN even with AUTH_FAIL. WIFI_REASON_AUTH_FAIL does not necessarily mean the password is wrong, and a wrong password may not lead to a WIFI_REASON_AUTH_FAIL error code. So to improve reliability connecting to a WLAN always reconnect regardless of the error. --- ports/esp32/modnetwork.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index b93715b6e6..8462576058 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -159,8 +159,8 @@ static esp_err_t event_handler(void *ctx, system_event_t *event) { message = "\nno AP found"; break; case WIFI_REASON_AUTH_FAIL: + // Password may be wrong, or it just failed to connect; try to reconnect. message = "\nauthentication failed"; - wifi_sta_connect_requested = false; break; default: // Let other errors through and try to reconnect. From 5da60ff9cba990f239bdac2cd7ecdb2f84df4d63 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 24 Jun 2019 17:48:28 +1000 Subject: [PATCH 0448/1788] stm32/boards: Enable ussl module via mbedtls for boards with network. --- ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk | 2 ++ ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk | 2 ++ ports/stm32/boards/STM32F769DISC/mpconfigboard.mk | 2 ++ ports/stm32/boards/STM32F7DISC/mpconfigboard.mk | 2 ++ 4 files changed, 8 insertions(+) diff --git a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk index e542d1c998..47b4432893 100644 --- a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk @@ -7,3 +7,5 @@ TEXT1_ADDR = 0x08020000 # MicroPython settings MICROPY_PY_LWIP = 1 +MICROPY_PY_USSL = 1 +MICROPY_SSL_MBEDTLS = 1 diff --git a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk index c3f12998c3..0fdc1a6dcd 100644 --- a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk @@ -8,3 +8,5 @@ TEXT1_ADDR = 0x08020000 # MicroPython settings MICROPY_PY_LWIP = 1 +MICROPY_PY_USSL = 1 +MICROPY_SSL_MBEDTLS = 1 diff --git a/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk index 49b318d30b..04f208c5b7 100644 --- a/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk @@ -39,3 +39,5 @@ endif # MicroPython settings MICROPY_PY_LWIP = 1 +MICROPY_PY_USSL = 1 +MICROPY_SSL_MBEDTLS = 1 diff --git a/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk index 4f88a139e7..8b54dc84e1 100644 --- a/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk @@ -7,3 +7,5 @@ TEXT1_ADDR = 0x08020000 # MicroPython settings MICROPY_PY_LWIP = 1 +MICROPY_PY_USSL = 1 +MICROPY_SSL_MBEDTLS = 1 From 205c6d0dc94ef1ca11d7bcef2090ef49c2015e48 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 24 Jun 2019 21:59:58 +1000 Subject: [PATCH 0449/1788] stm32/Makefile: Print info messages about use of mboot/QSPI flash. --- ports/stm32/Makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 4c9a2342ca..31597e88a5 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -513,6 +513,12 @@ $(BUILD)/firmware.elf: $(OBJ) $(ECHO) "LINK $@" $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LDFLAGS_MOD) $(LIBS) $(Q)$(SIZE) $@ +ifneq ($(TEXT0_ADDR),0x08000000) + $(ECHO) "INFO: this build requires mboot to be installed first" +endif +ifeq ($(TEXT1_ADDR),0x90000000) + $(ECHO) "INFO: this build places firmware in external QSPI flash" +endif PLLVALUES = boards/pllvalues.py MAKE_PINS = boards/make-pins.py From 04c7cdb668cc7ee391ef5fe000f825389197f7e2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 22 Jun 2019 21:26:03 +1000 Subject: [PATCH 0450/1788] stm32: Enter bootloader via a system reset. Entering a bootloader (ST system bootloader, or custom mboot) from software by directly branching to it is not reliable, and the reliability of it working can depend on the peripherals that were enabled by the application code. It's also not possible to branch to a bootloader if the WDT is enabled (unless the bootloader has specific provisions to feed the WDT). This patch changes the way a bootloader is entered from software by first doing a complete system reset, then branching to the desired bootloader early on in the start-up process. The top two words of RAM (of the stack) are reserved to store flags indicating that the bootloader should be entered after a reset. --- ports/stm32/Makefile | 1 + ports/stm32/boards/PYBD_SF2/f722_qspi.ld | 2 +- ports/stm32/boards/PYBD_SF6/f767.ld | 2 +- ports/stm32/boards/STM32F769DISC/f769_qspi.ld | 2 +- ports/stm32/boards/stm32f091xc.ld | 2 +- ports/stm32/boards/stm32f401xd.ld | 2 +- ports/stm32/boards/stm32f401xe.ld | 2 +- ports/stm32/boards/stm32f405.ld | 2 +- ports/stm32/boards/stm32f411.ld | 2 +- ports/stm32/boards/stm32f413xg.ld | 2 +- ports/stm32/boards/stm32f413xh.ld | 2 +- ports/stm32/boards/stm32f429.ld | 2 +- ports/stm32/boards/stm32f439.ld | 2 +- ports/stm32/boards/stm32f722.ld | 2 +- ports/stm32/boards/stm32f746.ld | 2 +- ports/stm32/boards/stm32f767.ld | 2 +- ports/stm32/boards/stm32f769.ld | 2 +- ports/stm32/boards/stm32h743.ld | 2 +- ports/stm32/boards/stm32l432.ld | 2 +- ports/stm32/boards/stm32l476xe.ld | 2 +- ports/stm32/boards/stm32l476xg.ld | 2 +- ports/stm32/boards/stm32l496xg.ld | 2 +- ports/stm32/main.c | 4 ++ ports/stm32/modmachine.c | 34 ++---------- ports/stm32/powerctrl.c | 54 +++++++++++++++++++ ports/stm32/powerctrl.h | 4 ++ ports/stm32/stm32_it.c | 3 +- 27 files changed, 91 insertions(+), 51 deletions(-) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 31597e88a5..153ea44626 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -92,6 +92,7 @@ CFLAGS += -fsingle-precision-constant -Wdouble-promotion endif LDFLAGS = -nostdlib -L $(LD_DIR) $(addprefix -T,$(LD_FILES)) -Map=$(@:.elf=.map) --cref +LDFLAGS += --defsym=_estack_reserve=8 LIBS = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) # Remove uncalled code from the final image. diff --git a/ports/stm32/boards/PYBD_SF2/f722_qspi.ld b/ports/stm32/boards/PYBD_SF2/f722_qspi.ld index e9d6fa3c39..b6d3e08e30 100644 --- a/ports/stm32/boards/PYBD_SF2/f722_qspi.ld +++ b/ports/stm32/boards/PYBD_SF2/f722_qspi.ld @@ -31,7 +31,7 @@ _minimum_heap_size = 16K; /* Define 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); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 16K; /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/PYBD_SF6/f767.ld b/ports/stm32/boards/PYBD_SF6/f767.ld index 2a474fba07..1dd4c11ed9 100644 --- a/ports/stm32/boards/PYBD_SF6/f767.ld +++ b/ports/stm32/boards/PYBD_SF6/f767.ld @@ -30,7 +30,7 @@ _minimum_heap_size = 16K; /* Define 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); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 24K; /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/STM32F769DISC/f769_qspi.ld b/ports/stm32/boards/STM32F769DISC/f769_qspi.ld index 362fab3305..9a0bd56fb3 100644 --- a/ports/stm32/boards/STM32F769DISC/f769_qspi.ld +++ b/ports/stm32/boards/STM32F769DISC/f769_qspi.ld @@ -29,7 +29,7 @@ _minimum_heap_size = 16K; /* Define 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); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 32K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32f091xc.ld b/ports/stm32/boards/stm32f091xc.ld index 5e1e9e7bd3..5bcc4c7275 100644 --- a/ports/stm32/boards/stm32f091xc.ld +++ b/ports/stm32/boards/stm32f091xc.ld @@ -16,7 +16,7 @@ _minimum_heap_size = 16K; /* Define the stack. The stack is full descending so begins just above last byte above last byte of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 6K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32f401xd.ld b/ports/stm32/boards/stm32f401xd.ld index 50cb3c571b..f4146abc6d 100644 --- a/ports/stm32/boards/stm32f401xd.ld +++ b/ports/stm32/boards/stm32f401xd.ld @@ -18,7 +18,7 @@ _minimum_heap_size = 16K; /* tunable */ /* Define 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); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 16K; /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32f401xe.ld b/ports/stm32/boards/stm32f401xe.ld index 78e0dc1cba..e7bd8edfed 100644 --- a/ports/stm32/boards/stm32f401xe.ld +++ b/ports/stm32/boards/stm32f401xe.ld @@ -18,7 +18,7 @@ _minimum_heap_size = 16K; /* Define 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); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 16K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32f405.ld b/ports/stm32/boards/stm32f405.ld index 13133e8c6d..b6f5d30578 100644 --- a/ports/stm32/boards/stm32f405.ld +++ b/ports/stm32/boards/stm32f405.ld @@ -19,7 +19,7 @@ _minimum_heap_size = 16K; /* Define 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); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 16K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32f411.ld b/ports/stm32/boards/stm32f411.ld index 8ae5f6929c..50633118eb 100644 --- a/ports/stm32/boards/stm32f411.ld +++ b/ports/stm32/boards/stm32f411.ld @@ -18,7 +18,7 @@ _minimum_heap_size = 16K; /* Define 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); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 16K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32f413xg.ld b/ports/stm32/boards/stm32f413xg.ld index c2719b834f..96d6dc5fb0 100644 --- a/ports/stm32/boards/stm32f413xg.ld +++ b/ports/stm32/boards/stm32f413xg.ld @@ -21,7 +21,7 @@ _minimum_heap_size = 16K; /* Define 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); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 16K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32f413xh.ld b/ports/stm32/boards/stm32f413xh.ld index 017dbbac17..0b28730de5 100644 --- a/ports/stm32/boards/stm32f413xh.ld +++ b/ports/stm32/boards/stm32f413xh.ld @@ -21,7 +21,7 @@ _minimum_heap_size = 16K; /* Define 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); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 16K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32f429.ld b/ports/stm32/boards/stm32f429.ld index 35d0736eef..beeaa4df21 100644 --- a/ports/stm32/boards/stm32f429.ld +++ b/ports/stm32/boards/stm32f429.ld @@ -19,7 +19,7 @@ _minimum_heap_size = 16K; /* Define 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); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 16K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32f439.ld b/ports/stm32/boards/stm32f439.ld index 2b51c3a371..e847646b35 100644 --- a/ports/stm32/boards/stm32f439.ld +++ b/ports/stm32/boards/stm32f439.ld @@ -20,7 +20,7 @@ _minimum_heap_size = 16K; /* Define 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); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 16K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32f722.ld b/ports/stm32/boards/stm32f722.ld index 8986c68d52..ab41f0ea90 100644 --- a/ports/stm32/boards/stm32f722.ld +++ b/ports/stm32/boards/stm32f722.ld @@ -17,7 +17,7 @@ _minimum_heap_size = 16K; /* Define 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); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 32K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32f746.ld b/ports/stm32/boards/stm32f746.ld index 330dd97141..0f1de26964 100644 --- a/ports/stm32/boards/stm32f746.ld +++ b/ports/stm32/boards/stm32f746.ld @@ -19,7 +19,7 @@ _minimum_heap_size = 16K; /* Define 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); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 16K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32f767.ld b/ports/stm32/boards/stm32f767.ld index 47e992c2dd..9410b9fa6b 100644 --- a/ports/stm32/boards/stm32f767.ld +++ b/ports/stm32/boards/stm32f767.ld @@ -20,7 +20,7 @@ _minimum_heap_size = 16K; /* Define 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); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 32K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32f769.ld b/ports/stm32/boards/stm32f769.ld index 41bb321a37..ebc6d033d9 100644 --- a/ports/stm32/boards/stm32f769.ld +++ b/ports/stm32/boards/stm32f769.ld @@ -19,7 +19,7 @@ _minimum_heap_size = 16K; /* Define 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); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 32K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32h743.ld b/ports/stm32/boards/stm32h743.ld index 0f1c2b777e..69738ab8b9 100644 --- a/ports/stm32/boards/stm32h743.ld +++ b/ports/stm32/boards/stm32h743.ld @@ -19,7 +19,7 @@ _minimum_heap_size = 16K; /* Define 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); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 16K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32l432.ld b/ports/stm32/boards/stm32l432.ld index 40515e75b3..5558b13c89 100644 --- a/ports/stm32/boards/stm32l432.ld +++ b/ports/stm32/boards/stm32l432.ld @@ -17,7 +17,7 @@ _minimum_heap_size = 16K; /* Define 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); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 6K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32l476xe.ld b/ports/stm32/boards/stm32l476xe.ld index 330ec96e67..e4bcda1f16 100644 --- a/ports/stm32/boards/stm32l476xe.ld +++ b/ports/stm32/boards/stm32l476xe.ld @@ -20,7 +20,7 @@ _minimum_heap_size = 16K; /* Define 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); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 16K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32l476xg.ld b/ports/stm32/boards/stm32l476xg.ld index 7983fb39a1..9fe83c74a4 100644 --- a/ports/stm32/boards/stm32l476xg.ld +++ b/ports/stm32/boards/stm32l476xg.ld @@ -20,7 +20,7 @@ _minimum_heap_size = 16K; /* Define 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); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 16K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32l496xg.ld b/ports/stm32/boards/stm32l496xg.ld index e1ceb50707..c339903422 100644 --- a/ports/stm32/boards/stm32l496xg.ld +++ b/ports/stm32/boards/stm32l496xg.ld @@ -20,7 +20,7 @@ _minimum_heap_size = 16K; /* Define 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); +_estack = ORIGIN(RAM) + LENGTH(RAM) + LENGTH(SRAM2) - _estack_reserve; _sstack = _estack - 206K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 523034e097..2dcc09ae7a 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -45,6 +45,7 @@ #include "systick.h" #include "pendsv.h" +#include "powerctrl.h" #include "pybthread.h" #include "gccollect.h" #include "factoryreset.h" @@ -368,6 +369,9 @@ STATIC uint update_reset_mode(uint reset_mode) { #endif void stm32_main(uint32_t reset_mode) { + // Check if bootloader should be entered instead of main application + powerctrl_check_enter_bootloader(); + // Enable caches and prefetch buffers #if defined(STM32F4) diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index cf615ea6aa..a4ee47470b 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -237,7 +237,7 @@ MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id); // Resets the pyboard in a manner similar to pushing the external RESET button. STATIC mp_obj_t machine_reset(void) { - NVIC_SystemReset(); + powerctrl_mcu_reset(); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset); @@ -248,15 +248,6 @@ STATIC mp_obj_t machine_soft_reset(void) { } MP_DEFINE_CONST_FUN_OBJ_0(machine_soft_reset_obj, machine_soft_reset); -__attribute__((naked)) void branch_to_bootloader(uint32_t r0, uint32_t addr) { - __asm volatile ( - "ldr r2, [r1, #0]\n" // get address of stack pointer - "msr msp, r2\n" // get stack pointer - "ldr r2, [r1, #4]\n" // get address of destination - "bx r2\n" // branch to bootloader - ); -} - // Activate the bootloader without BOOT* pins. STATIC NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args) { #if MICROPY_HW_ENABLE_USB @@ -266,24 +257,10 @@ STATIC NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args) storage_flush(); #endif - #if __DCACHE_PRESENT == 1 - // Flush and disable caches before turning off peripherals (eg SDRAM) - SCB_DisableICache(); - SCB_DisableDCache(); - #endif - - HAL_RCC_DeInit(); - HAL_DeInit(); - - #if (__MPU_PRESENT == 1) - // MPU must be disabled for bootloader to function correctly - HAL_MPU_Disable(); - #endif - #if MICROPY_HW_USES_BOOTLOADER if (n_args == 0 || !mp_obj_is_true(args[0])) { // By default, with no args given, we enter the custom bootloader (mboot) - branch_to_bootloader(0x70ad0000, 0x08000000); + powerctrl_enter_bootloader(0x70ad0000, 0x08000000); } if (n_args == 1 && mp_obj_is_str_or_bytes(args[0])) { @@ -292,15 +269,14 @@ STATIC NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args) const char *data = mp_obj_str_get_data(args[0], &len); void *mboot_region = (void*)*((volatile uint32_t*)0x08000000); memmove(mboot_region, data, len); - branch_to_bootloader(0x70ad0080, 0x08000000); + powerctrl_enter_bootloader(0x70ad0080, 0x08000000); } #endif #if defined(STM32F7) || defined(STM32H7) - branch_to_bootloader(0, 0x1ff00000); + powerctrl_enter_bootloader(0, 0x1ff00000); #else - __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH(); - branch_to_bootloader(0, 0x00000000); + powerctrl_enter_bootloader(0, 0x00000000); #endif while (1); diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c index c3792be3ed..2ad2426005 100644 --- a/ports/stm32/powerctrl.c +++ b/ports/stm32/powerctrl.c @@ -30,6 +30,60 @@ #include "rtc.h" #include "genhdr/pllfreqtable.h" +#if defined(STM32H7) +#define RCC_SR RSR +#define RCC_SR_SFTRSTF RCC_RSR_SFTRSTF +#define RCC_SR_RMVF RCC_RSR_RMVF +#else +#define RCC_SR CSR +#define RCC_SR_SFTRSTF RCC_CSR_SFTRSTF +#define RCC_SR_RMVF RCC_CSR_RMVF +#endif + +// Location in RAM of bootloader state (just after the top of the stack) +extern uint32_t _estack[]; +#define BL_STATE ((uint32_t*)&_estack) + +NORETURN void powerctrl_mcu_reset(void) { + BL_STATE[1] = 1; // invalidate bootloader address + #if __DCACHE_PRESENT == 1 + SCB_CleanDCache(); + #endif + NVIC_SystemReset(); +} + +NORETURN void powerctrl_enter_bootloader(uint32_t r0, uint32_t bl_addr) { + BL_STATE[0] = r0; + BL_STATE[1] = bl_addr; + #if __DCACHE_PRESENT == 1 + SCB_CleanDCache(); + #endif + NVIC_SystemReset(); +} + +static __attribute__((naked)) void branch_to_bootloader(uint32_t r0, uint32_t bl_addr) { + __asm volatile ( + "ldr r2, [r1, #0]\n" // get address of stack pointer + "msr msp, r2\n" // get stack pointer + "ldr r2, [r1, #4]\n" // get address of destination + "bx r2\n" // branch to bootloader + ); +} + +void powerctrl_check_enter_bootloader(void) { + uint32_t bl_addr = BL_STATE[1]; + BL_STATE[1] = 1; // invalidate bootloader address + if ((bl_addr & 0xfff) == 0 && (RCC->RCC_SR & RCC_SR_SFTRSTF)) { + // Reset by NVIC_SystemReset with bootloader data set -> branch to bootloader + RCC->RCC_SR = RCC_SR_RMVF; + #if defined(STM32F0) || defined(STM32F4) || defined(STM32L4) + __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH(); + #endif + uint32_t r0 = BL_STATE[0]; + branch_to_bootloader(r0, bl_addr); + } +} + #if !defined(STM32F0) // Assumes that PLL is used as the SYSCLK source diff --git a/ports/stm32/powerctrl.h b/ports/stm32/powerctrl.h index b26cab391c..6eb0342287 100644 --- a/ports/stm32/powerctrl.h +++ b/ports/stm32/powerctrl.h @@ -28,6 +28,10 @@ #include +NORETURN void powerctrl_mcu_reset(void); +NORETURN void powerctrl_enter_bootloader(uint32_t r0, uint32_t bl_addr); +void powerctrl_check_enter_bootloader(void); + int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk_mhz, bool need_pllsai); int powerctrl_set_sysclk(uint32_t sysclk, uint32_t ahb, uint32_t apb1, uint32_t apb2); void powerctrl_enter_stop_mode(void); diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index 0c5263e053..a3740d59cd 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -72,6 +72,7 @@ #include "stm32_it.h" #include "pendsv.h" #include "irq.h" +#include "powerctrl.h" #include "pybthread.h" #include "gccollect.h" #include "extint.h" @@ -144,7 +145,7 @@ int pyb_hard_fault_debug = 0; void HardFault_C_Handler(ExceptionRegisters_t *regs) { if (!pyb_hard_fault_debug) { - NVIC_SystemReset(); + powerctrl_mcu_reset(); } #if MICROPY_HW_ENABLE_USB From 89ebb3325b6572f61531d2f434dfb6969027c7be Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 25 Jun 2019 13:39:06 +1000 Subject: [PATCH 0451/1788] stm32/boards/pllvalues.py: Support HSx_VALUE defined without uint32_t. --- ports/stm32/boards/pllvalues.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/stm32/boards/pllvalues.py b/ports/stm32/boards/pllvalues.py index a628dea8a9..4a85b5478a 100644 --- a/ports/stm32/boards/pllvalues.py +++ b/ports/stm32/boards/pllvalues.py @@ -137,7 +137,7 @@ def print_table(hse, valid_plls): def search_header_for_hsx_values(filename, vals): regex_inc = re.compile(r'#include "(boards/[A-Za-z0-9_./]+)"') - regex_def = re.compile(r'#define +(HSE_VALUE|HSI_VALUE) +\(\(uint32_t\)([0-9]+)\)') + regex_def = re.compile(r'#define +(HSE_VALUE|HSI_VALUE) +\((\(uint32_t\))?([0-9]+)\)') with open(filename) as f: for line in f: line = line.strip() @@ -149,7 +149,7 @@ def search_header_for_hsx_values(filename, vals): m = regex_def.match(line) if m: # Found HSE_VALUE or HSI_VALUE - val = int(m.group(2)) // 1000000 + val = int(m.group(3)) // 1000000 if m.group(1) == 'HSE_VALUE': vals[0] = val else: From f96f53cd978558dde93d136a22c7bd9a42cc6588 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 25 Jun 2019 13:40:26 +1000 Subject: [PATCH 0452/1788] stm32/boards: Add stm32??xx_hal_conf_base.h files with common settings. These are intended to be used by all boards, to reduce the size of a board's configuration. --- ports/stm32/boards/stm32f0xx_hal_conf_base.h | 90 +++++++++++++++++ ports/stm32/boards/stm32f4xx_hal_conf_base.h | 101 +++++++++++++++++++ ports/stm32/boards/stm32f7xx_hal_conf_base.h | 99 ++++++++++++++++++ ports/stm32/boards/stm32h7xx_hal_conf_base.h | 96 ++++++++++++++++++ ports/stm32/boards/stm32l4xx_hal_conf_base.h | 99 ++++++++++++++++++ 5 files changed, 485 insertions(+) create mode 100644 ports/stm32/boards/stm32f0xx_hal_conf_base.h create mode 100644 ports/stm32/boards/stm32f4xx_hal_conf_base.h create mode 100644 ports/stm32/boards/stm32f7xx_hal_conf_base.h create mode 100644 ports/stm32/boards/stm32h7xx_hal_conf_base.h create mode 100644 ports/stm32/boards/stm32l4xx_hal_conf_base.h diff --git a/ports/stm32/boards/stm32f0xx_hal_conf_base.h b/ports/stm32/boards/stm32f0xx_hal_conf_base.h new file mode 100644 index 0000000000..9cb7761ac2 --- /dev/null +++ b/ports/stm32/boards/stm32f0xx_hal_conf_base.h @@ -0,0 +1,90 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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_STM32F0XX_HAL_CONF_BASE_H +#define MICROPY_INCLUDED_STM32F0XX_HAL_CONF_BASE_H + +// Include various HAL modules for convenience +#include "stm32f0xx_hal_dma.h" +#include "stm32f0xx_hal_adc.h" +#include "stm32f0xx_hal_can.h" +#include "stm32f0xx_hal_cortex.h" +#include "stm32f0xx_hal_crc.h" +#include "stm32f0xx_hal_dac.h" +#include "stm32f0xx_hal_flash.h" +#include "stm32f0xx_hal_gpio.h" +#include "stm32f0xx_hal_i2c.h" +#include "stm32f0xx_hal_i2s.h" +#include "stm32f0xx_hal_iwdg.h" +#include "stm32f0xx_hal_pcd.h" +#include "stm32f0xx_hal_pwr.h" +#include "stm32f0xx_hal_rcc.h" +#include "stm32f0xx_hal_rtc.h" +#include "stm32f0xx_hal_spi.h" +#include "stm32f0xx_hal_tim.h" +#include "stm32f0xx_hal_uart.h" +#include "stm32f0xx_hal_usart.h" +#include "stm32f0xx_hal_wwdg.h" + +// Enable various HAL modules +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_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_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_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +#define HAL_USART_MODULE_ENABLED +#define HAL_WWDG_MODULE_ENABLED + +// Oscillator values in Hz +#define HSI_VALUE (8000000) +#define HSI48_VALUE (48000000) +#define LSI_VALUE (40000) + +// SysTick has the highest priority +#define TICK_INT_PRIORITY (0x00) + +// Miscellaneous HAL settings +#define PREFETCH_ENABLE 1 +#define USE_RTOS 0 +#define USE_SPI_CRC 1 + +// HAL parameter assertions are disabled +#define assert_param(expr) ((void)0) + +#endif // MICROPY_INCLUDED_STM32F0XX_HAL_CONF_BASE_H diff --git a/ports/stm32/boards/stm32f4xx_hal_conf_base.h b/ports/stm32/boards/stm32f4xx_hal_conf_base.h new file mode 100644 index 0000000000..cdae0c5629 --- /dev/null +++ b/ports/stm32/boards/stm32f4xx_hal_conf_base.h @@ -0,0 +1,101 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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_STM32F4XX_HAL_CONF_BASE_H +#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_BASE_H + +// Include various HAL modules for convenience +#include "stm32f4xx_hal_dma.h" +#include "stm32f4xx_hal_adc.h" +#include "stm32f4xx_hal_can.h" +#include "stm32f4xx_hal_cortex.h" +#include "stm32f4xx_hal_crc.h" +#include "stm32f4xx_hal_dac.h" +#include "stm32f4xx_hal_dcmi.h" +#include "stm32f4xx_hal_eth.h" +#include "stm32f4xx_hal_flash.h" +#include "stm32f4xx_hal_gpio.h" +#include "stm32f4xx_hal_hash.h" +#include "stm32f4xx_hal_hcd.h" +#include "stm32f4xx_hal_i2c.h" +#include "stm32f4xx_hal_i2s.h" +#include "stm32f4xx_hal_iwdg.h" +#include "stm32f4xx_hal_pcd.h" +#include "stm32f4xx_hal_pwr.h" +#include "stm32f4xx_hal_rcc.h" +#include "stm32f4xx_hal_rtc.h" +#include "stm32f4xx_hal_sd.h" +#include "stm32f4xx_hal_sdram.h" +#include "stm32f4xx_hal_spi.h" +#include "stm32f4xx_hal_tim.h" +#include "stm32f4xx_hal_uart.h" +#include "stm32f4xx_hal_usart.h" +#include "stm32f4xx_hal_wwdg.h" + +// Enable various HAL modules +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_CRC_MODULE_ENABLED +#define HAL_DAC_MODULE_ENABLED +#define HAL_DCMI_MODULE_ENABLED +#define HAL_DMA_MODULE_ENABLED +#define HAL_ETH_MODULE_ENABLED +#define HAL_FLASH_MODULE_ENABLED +#define HAL_GPIO_MODULE_ENABLED +#define HAL_HASH_MODULE_ENABLED +#define HAL_HCD_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +#define HAL_I2S_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_SD_MODULE_ENABLED +#define HAL_SDRAM_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +#define HAL_USART_MODULE_ENABLED +#define HAL_WWDG_MODULE_ENABLED + +// Oscillator values in Hz +#define HSI_VALUE (16000000) +#define LSI_VALUE (40000) + +// SysTick has the highest priority +#define TICK_INT_PRIORITY (0x00) + +// Miscellaneous HAL settings +#define DATA_CACHE_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define PREFETCH_ENABLE 1 +#define USE_RTOS 0 + +// HAL parameter assertions are disabled +#define assert_param(expr) ((void)0) + +#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_BASE_H diff --git a/ports/stm32/boards/stm32f7xx_hal_conf_base.h b/ports/stm32/boards/stm32f7xx_hal_conf_base.h new file mode 100644 index 0000000000..05ab10fea0 --- /dev/null +++ b/ports/stm32/boards/stm32f7xx_hal_conf_base.h @@ -0,0 +1,99 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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_STM32F7XX_HAL_CONF_BASE_H +#define MICROPY_INCLUDED_STM32F7XX_HAL_CONF_BASE_H + +// Include various HAL modules for convenience +#include "stm32f7xx_hal_dma.h" +#include "stm32f7xx_hal_adc.h" +#include "stm32f7xx_hal_can.h" +#include "stm32f7xx_hal_cortex.h" +#include "stm32f7xx_hal_crc.h" +#include "stm32f7xx_hal_dac.h" +#include "stm32f7xx_hal_dcmi.h" +#include "stm32f7xx_hal_flash.h" +#include "stm32f7xx_hal_gpio.h" +#include "stm32f7xx_hal_hash.h" +#include "stm32f7xx_hal_hcd.h" +#include "stm32f7xx_hal_i2c.h" +#include "stm32f7xx_hal_i2s.h" +#include "stm32f7xx_hal_iwdg.h" +#include "stm32f7xx_hal_mmc.h" +#include "stm32f7xx_hal_pcd.h" +#include "stm32f7xx_hal_pwr.h" +#include "stm32f7xx_hal_rcc.h" +#include "stm32f7xx_hal_rtc.h" +#include "stm32f7xx_hal_sd.h" +#include "stm32f7xx_hal_sdram.h" +#include "stm32f7xx_hal_spi.h" +#include "stm32f7xx_hal_tim.h" +#include "stm32f7xx_hal_uart.h" +#include "stm32f7xx_hal_usart.h" +#include "stm32f7xx_hal_wwdg.h" + +// Enable various HAL modules +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_CRC_MODULE_ENABLED +#define HAL_DAC_MODULE_ENABLED +#define HAL_DCMI_MODULE_ENABLED +#define HAL_DMA_MODULE_ENABLED +#define HAL_FLASH_MODULE_ENABLED +#define HAL_GPIO_MODULE_ENABLED +#define HAL_HASH_MODULE_ENABLED +#define HAL_HCD_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +#define HAL_I2S_MODULE_ENABLED +#define HAL_IWDG_MODULE_ENABLED +#define HAL_MMC_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +#define HAL_SD_MODULE_ENABLED +#define HAL_SDRAM_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +#define HAL_USART_MODULE_ENABLED +#define HAL_WWDG_MODULE_ENABLED + +// Oscillator values in Hz +#define HSI_VALUE (16000000) +#define LSI_VALUE (32000) + +// SysTick has the highest priority +#define TICK_INT_PRIORITY (0x00) + +// Miscellaneous HAL settings +#define ART_ACCLERATOR_ENABLE 1 +#define USE_RTOS 0 + +// HAL parameter assertions are disabled +#define assert_param(expr) ((void)0) + +#endif // MICROPY_INCLUDED_STM32F7XX_HAL_CONF_BASE_H diff --git a/ports/stm32/boards/stm32h7xx_hal_conf_base.h b/ports/stm32/boards/stm32h7xx_hal_conf_base.h new file mode 100644 index 0000000000..334c6df4bd --- /dev/null +++ b/ports/stm32/boards/stm32h7xx_hal_conf_base.h @@ -0,0 +1,96 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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_STM32H7XX_HAL_CONF_BASE_H +#define MICROPY_INCLUDED_STM32H7XX_HAL_CONF_BASE_H + +// Include various HAL modules for convenience +#include "stm32h7xx_hal_dma.h" +#include "stm32h7xx_hal_adc.h" +#include "stm32h7xx_hal_cortex.h" +#include "stm32h7xx_hal_crc.h" +#include "stm32h7xx_hal_dac.h" +#include "stm32h7xx_hal_dcmi.h" +#include "stm32h7xx_hal_flash.h" +#include "stm32h7xx_hal_gpio.h" +#include "stm32h7xx_hal_hash.h" +#include "stm32h7xx_hal_hcd.h" +#include "stm32h7xx_hal_i2c.h" +#include "stm32h7xx_hal_i2s.h" +#include "stm32h7xx_hal_iwdg.h" +#include "stm32h7xx_hal_pcd.h" +#include "stm32h7xx_hal_pwr.h" +#include "stm32h7xx_hal_rcc.h" +#include "stm32h7xx_hal_rtc.h" +#include "stm32h7xx_hal_sd.h" +#include "stm32h7xx_hal_sdram.h" +#include "stm32h7xx_hal_spi.h" +#include "stm32h7xx_hal_tim.h" +#include "stm32h7xx_hal_uart.h" +#include "stm32h7xx_hal_usart.h" +#include "stm32h7xx_hal_wwdg.h" + +// Enable various HAL modules +#define HAL_ADC_MODULE_ENABLED +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_CRC_MODULE_ENABLED +#define HAL_DAC_MODULE_ENABLED +#define HAL_DCMI_MODULE_ENABLED +#define HAL_DMA_MODULE_ENABLED +#define HAL_FLASH_MODULE_ENABLED +#define HAL_GPIO_MODULE_ENABLED +#define HAL_HASH_MODULE_ENABLED +#define HAL_HCD_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +#define HAL_I2S_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_SD_MODULE_ENABLED +#define HAL_SDRAM_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +#define HAL_USART_MODULE_ENABLED +#define HAL_WWDG_MODULE_ENABLED + +// Oscillator values in Hz +#define CSI_VALUE (4000000) +#define HSI_VALUE (64000000) + +// SysTick has the highest priority +#define TICK_INT_PRIORITY (0x00) + +// Miscellaneous HAL settings +#define USE_RTOS 0 +#define USE_SD_TRANSCEIVER 0 +#define USE_SPI_CRC 1 + +// HAL parameter assertions are disabled +#define assert_param(expr) ((void)0) + +#endif // MICROPY_INCLUDED_STM32H7XX_HAL_CONF_BASE_H diff --git a/ports/stm32/boards/stm32l4xx_hal_conf_base.h b/ports/stm32/boards/stm32l4xx_hal_conf_base.h new file mode 100644 index 0000000000..7e249138f5 --- /dev/null +++ b/ports/stm32/boards/stm32l4xx_hal_conf_base.h @@ -0,0 +1,99 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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_STM32L4XX_HAL_CONF_BASE_H +#define MICROPY_INCLUDED_STM32L4XX_HAL_CONF_BASE_H + +// Include various HAL modules for convenience +#include "stm32l4xx_hal_dma.h" +#include "stm32l4xx_hal_adc.h" +#include "stm32l4xx_hal_can.h" +#include "stm32l4xx_hal_cortex.h" +#include "stm32l4xx_hal_crc.h" +#include "stm32l4xx_hal_dac.h" +#include "stm32l4xx_hal_dcmi.h" +#include "stm32l4xx_hal_flash.h" +#include "stm32l4xx_hal_gpio.h" +#include "stm32l4xx_hal_hash.h" +#include "stm32l4xx_hal_hcd.h" +#include "stm32l4xx_hal_i2c.h" +#include "stm32l4xx_hal_iwdg.h" +#include "stm32l4xx_hal_pcd.h" +#include "stm32l4xx_hal_pwr.h" +#include "stm32l4xx_hal_rcc.h" +#include "stm32l4xx_hal_rtc.h" +#include "stm32l4xx_hal_sd.h" +#include "stm32l4xx_hal_spi.h" +#include "stm32l4xx_hal_tim.h" +#include "stm32l4xx_hal_uart.h" +#include "stm32l4xx_hal_usart.h" +#include "stm32l4xx_hal_wwdg.h" + +// Enable various HAL modules +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_CRC_MODULE_ENABLED +#define HAL_DAC_MODULE_ENABLED +#define HAL_DCMI_MODULE_ENABLED +#define HAL_DMA_MODULE_ENABLED +#define HAL_FLASH_MODULE_ENABLED +#define HAL_GPIO_MODULE_ENABLED +#define HAL_HASH_MODULE_ENABLED +#define HAL_HCD_MODULE_ENABLED +#define HAL_I2C_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_SD_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +#define HAL_USART_MODULE_ENABLED +#define HAL_WWDG_MODULE_ENABLED + +// Oscillator values in Hz +#define HSI_VALUE (16000000) +#define HSI48_VALUE (48000000) +#define LSI_VALUE (32000) +#define MSI_VALUE (4000000) + +// SysTick has the highest priority +#define TICK_INT_PRIORITY (0x00) + +// Miscellaneous HAL settings +#define DATA_CACHE_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define PREFETCH_ENABLE 1 +#define USE_SPI_CRC 0 +#define USE_RTOS 0 + +// HAL parameter assertions are disabled +#define assert_param(expr) ((void)0) + +#endif // MICROPY_INCLUDED_STM32L4XX_HAL_CONF_BASE_H From 009b1f6559fa2a621dcd35916886385327e6abc1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 25 Jun 2019 13:42:06 +1000 Subject: [PATCH 0453/1788] stm32/boards: Rework all stm32??xx_hal_conf.h files to use common code. This eliminates a lot of duplicated code in these header files. --- .../B_L475E_IOT01A/stm32l4xx_hal_conf.h | 384 +-------------- .../stm32/boards/CERB40/stm32f4xx_hal_conf.h | 420 +---------------- .../boards/ESPRUINO_PICO/stm32f4xx_hal_conf.h | 420 +---------------- .../boards/HYDRABUS/stm32f4xx_hal_conf.h | 420 +---------------- .../boards/LIMIFROG/stm32l4xx_hal_conf.h | 384 +-------------- .../NETDUINO_PLUS_2/stm32f4xx_hal_conf.h | 420 +---------------- .../boards/NUCLEO_F091RC/stm32f0xx_hal_conf.h | 322 +------------ .../boards/NUCLEO_F401RE/stm32f4xx_hal_conf.h | 420 +---------------- .../boards/NUCLEO_F411RE/stm32f4xx_hal_conf.h | 420 +---------------- .../boards/NUCLEO_F413ZH/stm32f4xx_hal_conf.h | 420 +---------------- .../boards/NUCLEO_F429ZI/stm32f4xx_hal_conf.h | 420 +---------------- .../boards/NUCLEO_F446RE/stm32f4xx_hal_conf.h | 420 +---------------- .../boards/NUCLEO_F746ZG/stm32f7xx_hal_conf.h | 438 +---------------- .../boards/NUCLEO_F767ZI/stm32f7xx_hal_conf.h | 438 +---------------- .../boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h | 445 +----------------- .../boards/NUCLEO_L432KC/stm32l4xx_hal_conf.h | 396 +--------------- .../boards/NUCLEO_L476RG/stm32l4xx_hal_conf.h | 384 +-------------- .../boards/OLIMEX_E407/stm32f4xx_hal_conf.h | 420 +---------------- .../boards/PYBD_SF2/stm32f7xx_hal_conf.h | 75 +-- .../boards/PYBLITEV10/stm32f4xx_hal_conf.h | 420 +---------------- .../stm32/boards/PYBV10/stm32f4xx_hal_conf.h | 420 +---------------- .../stm32/boards/PYBV11/stm32f4xx_hal_conf.h | 420 +---------------- ports/stm32/boards/PYBV3/stm32f4xx_hal_conf.h | 420 +---------------- ports/stm32/boards/PYBV4/stm32f4xx_hal_conf.h | 420 +---------------- .../boards/STM32F411DISC/stm32f4xx_hal_conf.h | 420 +---------------- .../boards/STM32F429DISC/stm32f4xx_hal_conf.h | 420 +---------------- .../boards/STM32F439/stm32f4xx_hal_conf.h | 420 +---------------- .../boards/STM32F4DISC/stm32f4xx_hal_conf.h | 420 +---------------- .../boards/STM32F769DISC/stm32f7xx_hal_conf.h | 438 +---------------- .../boards/STM32F7DISC/stm32f7xx_hal_conf.h | 438 +---------------- .../boards/STM32L476DISC/stm32l4xx_hal_conf.h | 384 +-------------- .../STM32L496GDISC/stm32l4xx_hal_conf.h | 431 +---------------- 32 files changed, 472 insertions(+), 12465 deletions(-) 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 6bfb28118a..fd380ab735 100644 --- a/ports/stm32/boards/B_L475E_IOT01A/stm32l4xx_hal_conf.h +++ b/ports/stm32/boards/B_L475E_IOT01A/stm32l4xx_hal_conf.h @@ -1,372 +1,20 @@ -/** - ****************************************************************************** - * @file stm32l4xx_hal_conf.h - * @author MCD Application Team - * @version V1.2.0 - * @date 25-November-2015 - * @brief HAL configuration template file. - * This file should be copied to the application folder and renamed - * to stm32l4xx_hal_conf.h. - ****************************************************************************** - * @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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32L4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32L4XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32L4xx_HAL_CONF_H -#define __STM32L4xx_HAL_CONF_H +#include "boards/stm32l4xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define LSE_VALUE (32768) +#define EXTERNAL_SAI1_CLOCK_VALUE (48000) +#define EXTERNAL_SAI2_CLOCK_VALUE (48000) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) -/* ########################## 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_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_DFSDM_MODULE_ENABLED */ -#define HAL_DMA_MODULE_ENABLED -/* #define HAL_FIREWALL_MODULE_ENABLED */ -#define HAL_FLASH_MODULE_ENABLED -/* #define HAL_HCD_MODULE_ENABLED */ -/* #define HAL_NAND_MODULE_ENABLED */ -/* #define HAL_NOR_MODULE_ENABLED */ -/* #define HAL_SRAM_MODULE_ENABLED */ -#define HAL_GPIO_MODULE_ENABLED -#define HAL_I2C_MODULE_ENABLED -/* #define HAL_IRDA_MODULE_ENABLED */ -/* #define HAL_IWDG_MODULE_ENABLED */ -/* #define HAL_LCD_MODULE_ENABLED */ -/* #define HAL_LPTIM_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_SMARTCARD_MODULE_ENABLED */ -/* #define HAL_SMBUS_MODULE_ENABLED */ -#define HAL_SPI_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 */ - - -/* ########################## 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 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 */ - -/* Includes ------------------------------------------------------------------*/ -/** - * @brief Include module's header file - */ - -#ifdef HAL_RCC_MODULE_ENABLED - #include "stm32l4xx_hal_rcc.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_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_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_OPAMP_MODULE_ENABLED -#include "stm32l4xx_hal_opamp.h" -#endif /* HAL_OPAMP_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 */ - -/* 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 /* __STM32L4xx_HAL_CONF_H */ - - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +#endif // MICROPY_INCLUDED_STM32L4XX_HAL_CONF_H diff --git a/ports/stm32/boards/CERB40/stm32f4xx_hal_conf.h b/ports/stm32/boards/CERB40/stm32f4xx_hal_conf.h index e71ba33697..9719157e55 100644 --- a/ports/stm32/boards/CERB40/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/CERB40/stm32f4xx_hal_conf.h @@ -1,409 +1,19 @@ -/** - ****************************************************************************** - * @file stm32f4xx_hal_conf.h - * @author MCD Application Team - * @version V1.1.0 - * @date 19-June-2014 - * @brief HAL configuration file. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F4xx_HAL_CONF_H -#define __STM32F4xx_HAL_CONF_H +#include "boards/stm32f4xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (12000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) -/* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */ -#define HAL_PWR_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_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 */ - - -/* ########################## 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)12000000) /*!< Value of the External oscillator in Hz */ -#endif /* HSE_VALUE */ - -#if !defined (HSE_STARTUP_TIMEOUT) - #define HSE_STARTUP_TIMEOUT ((uint32_t)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 ((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)40000) -#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 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 */ - -/* ################## 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 0 -#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ -#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ - -/* Section 2: PHY configuration section */ - -/* DP83848 PHY Address*/ -#define DP83848_PHY_ADDRESS 0x01 -/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ -#define PHY_RESET_DELAY ((uint32_t)0x000000FF) -/* PHY Configuration delay */ -#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) - -#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 "stm32f4xx_hal_rcc.h" -#endif /* HAL_RCC_MODULE_ENABLED */ - -#ifdef HAL_GPIO_MODULE_ENABLED - #include "stm32f4xx_hal_gpio.h" -#endif /* HAL_GPIO_MODULE_ENABLED */ - -#ifdef HAL_DMA_MODULE_ENABLED - #include "stm32f4xx_hal_dma.h" -#endif /* HAL_DMA_MODULE_ENABLED */ - -#ifdef HAL_CORTEX_MODULE_ENABLED - #include "stm32f4xx_hal_cortex.h" -#endif /* HAL_CORTEX_MODULE_ENABLED */ - -#ifdef HAL_ADC_MODULE_ENABLED - #include "stm32f4xx_hal_adc.h" -#endif /* HAL_ADC_MODULE_ENABLED */ - -#ifdef HAL_CAN_MODULE_ENABLED - #include "stm32f4xx_hal_can.h" -#endif /* HAL_CAN_MODULE_ENABLED */ - -#ifdef HAL_CRC_MODULE_ENABLED - #include "stm32f4xx_hal_crc.h" -#endif /* HAL_CRC_MODULE_ENABLED */ - -#ifdef HAL_CRYP_MODULE_ENABLED - #include "stm32f4xx_hal_cryp.h" -#endif /* HAL_CRYP_MODULE_ENABLED */ - -#ifdef HAL_DMA2D_MODULE_ENABLED - #include "stm32f4xx_hal_dma2d.h" -#endif /* HAL_DMA2D_MODULE_ENABLED */ - -#ifdef HAL_DAC_MODULE_ENABLED - #include "stm32f4xx_hal_dac.h" -#endif /* HAL_DAC_MODULE_ENABLED */ - -#ifdef HAL_DCMI_MODULE_ENABLED - #include "stm32f4xx_hal_dcmi.h" -#endif /* HAL_DCMI_MODULE_ENABLED */ - -#ifdef HAL_ETH_MODULE_ENABLED - #include "stm32f4xx_hal_eth.h" -#endif /* HAL_ETH_MODULE_ENABLED */ - -#ifdef HAL_FLASH_MODULE_ENABLED - #include "stm32f4xx_hal_flash.h" -#endif /* HAL_FLASH_MODULE_ENABLED */ - -#ifdef HAL_SRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sram.h" -#endif /* HAL_SRAM_MODULE_ENABLED */ - -#ifdef HAL_NOR_MODULE_ENABLED - #include "stm32f4xx_hal_nor.h" -#endif /* HAL_NOR_MODULE_ENABLED */ - -#ifdef HAL_NAND_MODULE_ENABLED - #include "stm32f4xx_hal_nand.h" -#endif /* HAL_NAND_MODULE_ENABLED */ - -#ifdef HAL_PCCARD_MODULE_ENABLED - #include "stm32f4xx_hal_pccard.h" -#endif /* HAL_PCCARD_MODULE_ENABLED */ - -#ifdef HAL_SDRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sdram.h" -#endif /* HAL_SDRAM_MODULE_ENABLED */ - -#ifdef HAL_HASH_MODULE_ENABLED - #include "stm32f4xx_hal_hash.h" -#endif /* HAL_HASH_MODULE_ENABLED */ - -#ifdef HAL_I2C_MODULE_ENABLED - #include "stm32f4xx_hal_i2c.h" -#endif /* HAL_I2C_MODULE_ENABLED */ - -#ifdef HAL_I2S_MODULE_ENABLED - #include "stm32f4xx_hal_i2s.h" -#endif /* HAL_I2S_MODULE_ENABLED */ - -#ifdef HAL_IWDG_MODULE_ENABLED - #include "stm32f4xx_hal_iwdg.h" -#endif /* HAL_IWDG_MODULE_ENABLED */ - -#ifdef HAL_LTDC_MODULE_ENABLED - #include "stm32f4xx_hal_ltdc.h" -#endif /* HAL_LTDC_MODULE_ENABLED */ - -#ifdef HAL_PWR_MODULE_ENABLED - #include "stm32f4xx_hal_pwr.h" -#endif /* HAL_PWR_MODULE_ENABLED */ - -#ifdef HAL_RNG_MODULE_ENABLED - #include "stm32f4xx_hal_rng.h" -#endif /* HAL_RNG_MODULE_ENABLED */ - -#ifdef HAL_RTC_MODULE_ENABLED - #include "stm32f4xx_hal_rtc.h" -#endif /* HAL_RTC_MODULE_ENABLED */ - -#ifdef HAL_SAI_MODULE_ENABLED - #include "stm32f4xx_hal_sai.h" -#endif /* HAL_SAI_MODULE_ENABLED */ - -#ifdef HAL_SD_MODULE_ENABLED - #include "stm32f4xx_hal_sd.h" -#endif /* HAL_SD_MODULE_ENABLED */ - -#ifdef HAL_SPI_MODULE_ENABLED - #include "stm32f4xx_hal_spi.h" -#endif /* HAL_SPI_MODULE_ENABLED */ - -#ifdef HAL_TIM_MODULE_ENABLED - #include "stm32f4xx_hal_tim.h" -#endif /* HAL_TIM_MODULE_ENABLED */ - -#ifdef HAL_UART_MODULE_ENABLED - #include "stm32f4xx_hal_uart.h" -#endif /* HAL_UART_MODULE_ENABLED */ - -#ifdef HAL_USART_MODULE_ENABLED - #include "stm32f4xx_hal_usart.h" -#endif /* HAL_USART_MODULE_ENABLED */ - -#ifdef HAL_IRDA_MODULE_ENABLED - #include "stm32f4xx_hal_irda.h" -#endif /* HAL_IRDA_MODULE_ENABLED */ - -#ifdef HAL_SMARTCARD_MODULE_ENABLED - #include "stm32f4xx_hal_smartcard.h" -#endif /* HAL_SMARTCARD_MODULE_ENABLED */ - -#ifdef HAL_WWDG_MODULE_ENABLED - #include "stm32f4xx_hal_wwdg.h" -#endif /* HAL_WWDG_MODULE_ENABLED */ - -#ifdef HAL_PCD_MODULE_ENABLED - #include "stm32f4xx_hal_pcd.h" -#endif /* HAL_PCD_MODULE_ENABLED */ - -#ifdef HAL_HCD_MODULE_ENABLED - #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */ - - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H diff --git a/ports/stm32/boards/ESPRUINO_PICO/stm32f4xx_hal_conf.h b/ports/stm32/boards/ESPRUINO_PICO/stm32f4xx_hal_conf.h index d27e2e9ef0..de19251e08 100644 --- a/ports/stm32/boards/ESPRUINO_PICO/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/ESPRUINO_PICO/stm32f4xx_hal_conf.h @@ -1,409 +1,19 @@ -/** - ****************************************************************************** - * @file stm32f4xx_hal_conf.h - * @author MCD Application Team - * @version V1.1.0 - * @date 19-June-2014 - * @brief HAL configuration file. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F4xx_HAL_CONF_H -#define __STM32F4xx_HAL_CONF_H +#include "boards/stm32f4xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) -/* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */ -#define HAL_PWR_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_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 */ - - -/* ########################## 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)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 ((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)40000) -#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 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 */ - -/* ################## 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 0 -#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ -#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ - -/* Section 2: PHY configuration section */ - -/* DP83848 PHY Address*/ -#define DP83848_PHY_ADDRESS 0x01 -/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ -#define PHY_RESET_DELAY ((uint32_t)0x000000FF) -/* PHY Configuration delay */ -#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) - -#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 "stm32f4xx_hal_rcc.h" -#endif /* HAL_RCC_MODULE_ENABLED */ - -#ifdef HAL_GPIO_MODULE_ENABLED - #include "stm32f4xx_hal_gpio.h" -#endif /* HAL_GPIO_MODULE_ENABLED */ - -#ifdef HAL_DMA_MODULE_ENABLED - #include "stm32f4xx_hal_dma.h" -#endif /* HAL_DMA_MODULE_ENABLED */ - -#ifdef HAL_CORTEX_MODULE_ENABLED - #include "stm32f4xx_hal_cortex.h" -#endif /* HAL_CORTEX_MODULE_ENABLED */ - -#ifdef HAL_ADC_MODULE_ENABLED - #include "stm32f4xx_hal_adc.h" -#endif /* HAL_ADC_MODULE_ENABLED */ - -#ifdef HAL_CAN_MODULE_ENABLED - #include "stm32f4xx_hal_can.h" -#endif /* HAL_CAN_MODULE_ENABLED */ - -#ifdef HAL_CRC_MODULE_ENABLED - #include "stm32f4xx_hal_crc.h" -#endif /* HAL_CRC_MODULE_ENABLED */ - -#ifdef HAL_CRYP_MODULE_ENABLED - #include "stm32f4xx_hal_cryp.h" -#endif /* HAL_CRYP_MODULE_ENABLED */ - -#ifdef HAL_DMA2D_MODULE_ENABLED - #include "stm32f4xx_hal_dma2d.h" -#endif /* HAL_DMA2D_MODULE_ENABLED */ - -#ifdef HAL_DAC_MODULE_ENABLED - #include "stm32f4xx_hal_dac.h" -#endif /* HAL_DAC_MODULE_ENABLED */ - -#ifdef HAL_DCMI_MODULE_ENABLED - #include "stm32f4xx_hal_dcmi.h" -#endif /* HAL_DCMI_MODULE_ENABLED */ - -#ifdef HAL_ETH_MODULE_ENABLED - #include "stm32f4xx_hal_eth.h" -#endif /* HAL_ETH_MODULE_ENABLED */ - -#ifdef HAL_FLASH_MODULE_ENABLED - #include "stm32f4xx_hal_flash.h" -#endif /* HAL_FLASH_MODULE_ENABLED */ - -#ifdef HAL_SRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sram.h" -#endif /* HAL_SRAM_MODULE_ENABLED */ - -#ifdef HAL_NOR_MODULE_ENABLED - #include "stm32f4xx_hal_nor.h" -#endif /* HAL_NOR_MODULE_ENABLED */ - -#ifdef HAL_NAND_MODULE_ENABLED - #include "stm32f4xx_hal_nand.h" -#endif /* HAL_NAND_MODULE_ENABLED */ - -#ifdef HAL_PCCARD_MODULE_ENABLED - #include "stm32f4xx_hal_pccard.h" -#endif /* HAL_PCCARD_MODULE_ENABLED */ - -#ifdef HAL_SDRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sdram.h" -#endif /* HAL_SDRAM_MODULE_ENABLED */ - -#ifdef HAL_HASH_MODULE_ENABLED - #include "stm32f4xx_hal_hash.h" -#endif /* HAL_HASH_MODULE_ENABLED */ - -#ifdef HAL_I2C_MODULE_ENABLED - #include "stm32f4xx_hal_i2c.h" -#endif /* HAL_I2C_MODULE_ENABLED */ - -#ifdef HAL_I2S_MODULE_ENABLED - #include "stm32f4xx_hal_i2s.h" -#endif /* HAL_I2S_MODULE_ENABLED */ - -#ifdef HAL_IWDG_MODULE_ENABLED - #include "stm32f4xx_hal_iwdg.h" -#endif /* HAL_IWDG_MODULE_ENABLED */ - -#ifdef HAL_LTDC_MODULE_ENABLED - #include "stm32f4xx_hal_ltdc.h" -#endif /* HAL_LTDC_MODULE_ENABLED */ - -#ifdef HAL_PWR_MODULE_ENABLED - #include "stm32f4xx_hal_pwr.h" -#endif /* HAL_PWR_MODULE_ENABLED */ - -#ifdef HAL_RNG_MODULE_ENABLED - #include "stm32f4xx_hal_rng.h" -#endif /* HAL_RNG_MODULE_ENABLED */ - -#ifdef HAL_RTC_MODULE_ENABLED - #include "stm32f4xx_hal_rtc.h" -#endif /* HAL_RTC_MODULE_ENABLED */ - -#ifdef HAL_SAI_MODULE_ENABLED - #include "stm32f4xx_hal_sai.h" -#endif /* HAL_SAI_MODULE_ENABLED */ - -#ifdef HAL_SD_MODULE_ENABLED - #include "stm32f4xx_hal_sd.h" -#endif /* HAL_SD_MODULE_ENABLED */ - -#ifdef HAL_SPI_MODULE_ENABLED - #include "stm32f4xx_hal_spi.h" -#endif /* HAL_SPI_MODULE_ENABLED */ - -#ifdef HAL_TIM_MODULE_ENABLED - #include "stm32f4xx_hal_tim.h" -#endif /* HAL_TIM_MODULE_ENABLED */ - -#ifdef HAL_UART_MODULE_ENABLED - #include "stm32f4xx_hal_uart.h" -#endif /* HAL_UART_MODULE_ENABLED */ - -#ifdef HAL_USART_MODULE_ENABLED - #include "stm32f4xx_hal_usart.h" -#endif /* HAL_USART_MODULE_ENABLED */ - -#ifdef HAL_IRDA_MODULE_ENABLED - #include "stm32f4xx_hal_irda.h" -#endif /* HAL_IRDA_MODULE_ENABLED */ - -#ifdef HAL_SMARTCARD_MODULE_ENABLED - #include "stm32f4xx_hal_smartcard.h" -#endif /* HAL_SMARTCARD_MODULE_ENABLED */ - -#ifdef HAL_WWDG_MODULE_ENABLED - #include "stm32f4xx_hal_wwdg.h" -#endif /* HAL_WWDG_MODULE_ENABLED */ - -#ifdef HAL_PCD_MODULE_ENABLED - #include "stm32f4xx_hal_pcd.h" -#endif /* HAL_PCD_MODULE_ENABLED */ - -#ifdef HAL_HCD_MODULE_ENABLED - #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */ - - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H diff --git a/ports/stm32/boards/HYDRABUS/stm32f4xx_hal_conf.h b/ports/stm32/boards/HYDRABUS/stm32f4xx_hal_conf.h index daf9b63cec..de19251e08 100644 --- a/ports/stm32/boards/HYDRABUS/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/HYDRABUS/stm32f4xx_hal_conf.h @@ -1,409 +1,19 @@ -/** - ****************************************************************************** - * @file stm32f4xx_hal_conf.h - * @author MCD Application Team - * @version V1.1.0 - * @date 19-June-2014 - * @brief HAL configuration file. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F4xx_HAL_CONF_H -#define __STM32F4xx_HAL_CONF_H +#include "boards/stm32f4xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) -/* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */ -#define HAL_PWR_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_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 */ - - -/* ########################## 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)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 ((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)40000) -#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 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 */ - -/* ################## 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 0 -#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ -#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ - -/* Section 2: PHY configuration section */ - -/* DP83848 PHY Address*/ -#define DP83848_PHY_ADDRESS 0x01 -/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ -#define PHY_RESET_DELAY ((uint32_t)0x000000FF) -/* PHY Configuration delay */ -#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) - -#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 "stm32f4xx_hal_rcc.h" -#endif /* HAL_RCC_MODULE_ENABLED */ - -#ifdef HAL_GPIO_MODULE_ENABLED - #include "stm32f4xx_hal_gpio.h" -#endif /* HAL_GPIO_MODULE_ENABLED */ - -#ifdef HAL_DMA_MODULE_ENABLED - #include "stm32f4xx_hal_dma.h" -#endif /* HAL_DMA_MODULE_ENABLED */ - -#ifdef HAL_CORTEX_MODULE_ENABLED - #include "stm32f4xx_hal_cortex.h" -#endif /* HAL_CORTEX_MODULE_ENABLED */ - -#ifdef HAL_ADC_MODULE_ENABLED - #include "stm32f4xx_hal_adc.h" -#endif /* HAL_ADC_MODULE_ENABLED */ - -#ifdef HAL_CAN_MODULE_ENABLED - #include "stm32f4xx_hal_can.h" -#endif /* HAL_CAN_MODULE_ENABLED */ - -#ifdef HAL_CRC_MODULE_ENABLED - #include "stm32f4xx_hal_crc.h" -#endif /* HAL_CRC_MODULE_ENABLED */ - -#ifdef HAL_CRYP_MODULE_ENABLED - #include "stm32f4xx_hal_cryp.h" -#endif /* HAL_CRYP_MODULE_ENABLED */ - -#ifdef HAL_DMA2D_MODULE_ENABLED - #include "stm32f4xx_hal_dma2d.h" -#endif /* HAL_DMA2D_MODULE_ENABLED */ - -#ifdef HAL_DAC_MODULE_ENABLED - #include "stm32f4xx_hal_dac.h" -#endif /* HAL_DAC_MODULE_ENABLED */ - -#ifdef HAL_DCMI_MODULE_ENABLED - #include "stm32f4xx_hal_dcmi.h" -#endif /* HAL_DCMI_MODULE_ENABLED */ - -#ifdef HAL_ETH_MODULE_ENABLED - #include "stm32f4xx_hal_eth.h" -#endif /* HAL_ETH_MODULE_ENABLED */ - -#ifdef HAL_FLASH_MODULE_ENABLED - #include "stm32f4xx_hal_flash.h" -#endif /* HAL_FLASH_MODULE_ENABLED */ - -#ifdef HAL_SRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sram.h" -#endif /* HAL_SRAM_MODULE_ENABLED */ - -#ifdef HAL_NOR_MODULE_ENABLED - #include "stm32f4xx_hal_nor.h" -#endif /* HAL_NOR_MODULE_ENABLED */ - -#ifdef HAL_NAND_MODULE_ENABLED - #include "stm32f4xx_hal_nand.h" -#endif /* HAL_NAND_MODULE_ENABLED */ - -#ifdef HAL_PCCARD_MODULE_ENABLED - #include "stm32f4xx_hal_pccard.h" -#endif /* HAL_PCCARD_MODULE_ENABLED */ - -#ifdef HAL_SDRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sdram.h" -#endif /* HAL_SDRAM_MODULE_ENABLED */ - -#ifdef HAL_HASH_MODULE_ENABLED - #include "stm32f4xx_hal_hash.h" -#endif /* HAL_HASH_MODULE_ENABLED */ - -#ifdef HAL_I2C_MODULE_ENABLED - #include "stm32f4xx_hal_i2c.h" -#endif /* HAL_I2C_MODULE_ENABLED */ - -#ifdef HAL_I2S_MODULE_ENABLED - #include "stm32f4xx_hal_i2s.h" -#endif /* HAL_I2S_MODULE_ENABLED */ - -#ifdef HAL_IWDG_MODULE_ENABLED - #include "stm32f4xx_hal_iwdg.h" -#endif /* HAL_IWDG_MODULE_ENABLED */ - -#ifdef HAL_LTDC_MODULE_ENABLED - #include "stm32f4xx_hal_ltdc.h" -#endif /* HAL_LTDC_MODULE_ENABLED */ - -#ifdef HAL_PWR_MODULE_ENABLED - #include "stm32f4xx_hal_pwr.h" -#endif /* HAL_PWR_MODULE_ENABLED */ - -#ifdef HAL_RNG_MODULE_ENABLED - #include "stm32f4xx_hal_rng.h" -#endif /* HAL_RNG_MODULE_ENABLED */ - -#ifdef HAL_RTC_MODULE_ENABLED - #include "stm32f4xx_hal_rtc.h" -#endif /* HAL_RTC_MODULE_ENABLED */ - -#ifdef HAL_SAI_MODULE_ENABLED - #include "stm32f4xx_hal_sai.h" -#endif /* HAL_SAI_MODULE_ENABLED */ - -#ifdef HAL_SD_MODULE_ENABLED - #include "stm32f4xx_hal_sd.h" -#endif /* HAL_SD_MODULE_ENABLED */ - -#ifdef HAL_SPI_MODULE_ENABLED - #include "stm32f4xx_hal_spi.h" -#endif /* HAL_SPI_MODULE_ENABLED */ - -#ifdef HAL_TIM_MODULE_ENABLED - #include "stm32f4xx_hal_tim.h" -#endif /* HAL_TIM_MODULE_ENABLED */ - -#ifdef HAL_UART_MODULE_ENABLED - #include "stm32f4xx_hal_uart.h" -#endif /* HAL_UART_MODULE_ENABLED */ - -#ifdef HAL_USART_MODULE_ENABLED - #include "stm32f4xx_hal_usart.h" -#endif /* HAL_USART_MODULE_ENABLED */ - -#ifdef HAL_IRDA_MODULE_ENABLED - #include "stm32f4xx_hal_irda.h" -#endif /* HAL_IRDA_MODULE_ENABLED */ - -#ifdef HAL_SMARTCARD_MODULE_ENABLED - #include "stm32f4xx_hal_smartcard.h" -#endif /* HAL_SMARTCARD_MODULE_ENABLED */ - -#ifdef HAL_WWDG_MODULE_ENABLED - #include "stm32f4xx_hal_wwdg.h" -#endif /* HAL_WWDG_MODULE_ENABLED */ - -#ifdef HAL_PCD_MODULE_ENABLED - #include "stm32f4xx_hal_pcd.h" -#endif /* HAL_PCD_MODULE_ENABLED */ - -#ifdef HAL_HCD_MODULE_ENABLED - #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */ - - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H diff --git a/ports/stm32/boards/LIMIFROG/stm32l4xx_hal_conf.h b/ports/stm32/boards/LIMIFROG/stm32l4xx_hal_conf.h index 6bfb28118a..fd380ab735 100644 --- a/ports/stm32/boards/LIMIFROG/stm32l4xx_hal_conf.h +++ b/ports/stm32/boards/LIMIFROG/stm32l4xx_hal_conf.h @@ -1,372 +1,20 @@ -/** - ****************************************************************************** - * @file stm32l4xx_hal_conf.h - * @author MCD Application Team - * @version V1.2.0 - * @date 25-November-2015 - * @brief HAL configuration template file. - * This file should be copied to the application folder and renamed - * to stm32l4xx_hal_conf.h. - ****************************************************************************** - * @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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32L4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32L4XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32L4xx_HAL_CONF_H -#define __STM32L4xx_HAL_CONF_H +#include "boards/stm32l4xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define LSE_VALUE (32768) +#define EXTERNAL_SAI1_CLOCK_VALUE (48000) +#define EXTERNAL_SAI2_CLOCK_VALUE (48000) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) -/* ########################## 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_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_DFSDM_MODULE_ENABLED */ -#define HAL_DMA_MODULE_ENABLED -/* #define HAL_FIREWALL_MODULE_ENABLED */ -#define HAL_FLASH_MODULE_ENABLED -/* #define HAL_HCD_MODULE_ENABLED */ -/* #define HAL_NAND_MODULE_ENABLED */ -/* #define HAL_NOR_MODULE_ENABLED */ -/* #define HAL_SRAM_MODULE_ENABLED */ -#define HAL_GPIO_MODULE_ENABLED -#define HAL_I2C_MODULE_ENABLED -/* #define HAL_IRDA_MODULE_ENABLED */ -/* #define HAL_IWDG_MODULE_ENABLED */ -/* #define HAL_LCD_MODULE_ENABLED */ -/* #define HAL_LPTIM_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_SMARTCARD_MODULE_ENABLED */ -/* #define HAL_SMBUS_MODULE_ENABLED */ -#define HAL_SPI_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 */ - - -/* ########################## 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 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 */ - -/* Includes ------------------------------------------------------------------*/ -/** - * @brief Include module's header file - */ - -#ifdef HAL_RCC_MODULE_ENABLED - #include "stm32l4xx_hal_rcc.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_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_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_OPAMP_MODULE_ENABLED -#include "stm32l4xx_hal_opamp.h" -#endif /* HAL_OPAMP_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 */ - -/* 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 /* __STM32L4xx_HAL_CONF_H */ - - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +#endif // MICROPY_INCLUDED_STM32L4XX_HAL_CONF_H 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 4cb5a83e45..f186d5a292 100644 --- a/ports/stm32/boards/NETDUINO_PLUS_2/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/NETDUINO_PLUS_2/stm32f4xx_hal_conf.h @@ -1,409 +1,19 @@ -/** - ****************************************************************************** - * @file stm32f4xx_hal_conf.h - * @author MCD Application Team - * @version V1.1.0 - * @date 19-June-2014 - * @brief HAL configuration file. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F4xx_HAL_CONF_H -#define __STM32F4xx_HAL_CONF_H +#include "boards/stm32f4xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (25000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) -/* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */ -#define HAL_PWR_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_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 */ - - -/* ########################## 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)25000000) /*!< Value of the External oscillator in Hz */ -#endif /* HSE_VALUE */ - -#if !defined (HSE_STARTUP_TIMEOUT) - #define HSE_STARTUP_TIMEOUT ((uint32_t)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 ((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)40000) -#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 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 */ - -/* ################## 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 0 -#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ -#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ - -/* Section 2: PHY configuration section */ - -/* DP83848 PHY Address*/ -#define DP83848_PHY_ADDRESS 0x01 -/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ -#define PHY_RESET_DELAY ((uint32_t)0x000000FF) -/* PHY Configuration delay */ -#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) - -#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 "stm32f4xx_hal_rcc.h" -#endif /* HAL_RCC_MODULE_ENABLED */ - -#ifdef HAL_GPIO_MODULE_ENABLED - #include "stm32f4xx_hal_gpio.h" -#endif /* HAL_GPIO_MODULE_ENABLED */ - -#ifdef HAL_DMA_MODULE_ENABLED - #include "stm32f4xx_hal_dma.h" -#endif /* HAL_DMA_MODULE_ENABLED */ - -#ifdef HAL_CORTEX_MODULE_ENABLED - #include "stm32f4xx_hal_cortex.h" -#endif /* HAL_CORTEX_MODULE_ENABLED */ - -#ifdef HAL_ADC_MODULE_ENABLED - #include "stm32f4xx_hal_adc.h" -#endif /* HAL_ADC_MODULE_ENABLED */ - -#ifdef HAL_CAN_MODULE_ENABLED - #include "stm32f4xx_hal_can.h" -#endif /* HAL_CAN_MODULE_ENABLED */ - -#ifdef HAL_CRC_MODULE_ENABLED - #include "stm32f4xx_hal_crc.h" -#endif /* HAL_CRC_MODULE_ENABLED */ - -#ifdef HAL_CRYP_MODULE_ENABLED - #include "stm32f4xx_hal_cryp.h" -#endif /* HAL_CRYP_MODULE_ENABLED */ - -#ifdef HAL_DMA2D_MODULE_ENABLED - #include "stm32f4xx_hal_dma2d.h" -#endif /* HAL_DMA2D_MODULE_ENABLED */ - -#ifdef HAL_DAC_MODULE_ENABLED - #include "stm32f4xx_hal_dac.h" -#endif /* HAL_DAC_MODULE_ENABLED */ - -#ifdef HAL_DCMI_MODULE_ENABLED - #include "stm32f4xx_hal_dcmi.h" -#endif /* HAL_DCMI_MODULE_ENABLED */ - -#ifdef HAL_ETH_MODULE_ENABLED - #include "stm32f4xx_hal_eth.h" -#endif /* HAL_ETH_MODULE_ENABLED */ - -#ifdef HAL_FLASH_MODULE_ENABLED - #include "stm32f4xx_hal_flash.h" -#endif /* HAL_FLASH_MODULE_ENABLED */ - -#ifdef HAL_SRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sram.h" -#endif /* HAL_SRAM_MODULE_ENABLED */ - -#ifdef HAL_NOR_MODULE_ENABLED - #include "stm32f4xx_hal_nor.h" -#endif /* HAL_NOR_MODULE_ENABLED */ - -#ifdef HAL_NAND_MODULE_ENABLED - #include "stm32f4xx_hal_nand.h" -#endif /* HAL_NAND_MODULE_ENABLED */ - -#ifdef HAL_PCCARD_MODULE_ENABLED - #include "stm32f4xx_hal_pccard.h" -#endif /* HAL_PCCARD_MODULE_ENABLED */ - -#ifdef HAL_SDRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sdram.h" -#endif /* HAL_SDRAM_MODULE_ENABLED */ - -#ifdef HAL_HASH_MODULE_ENABLED - #include "stm32f4xx_hal_hash.h" -#endif /* HAL_HASH_MODULE_ENABLED */ - -#ifdef HAL_I2C_MODULE_ENABLED - #include "stm32f4xx_hal_i2c.h" -#endif /* HAL_I2C_MODULE_ENABLED */ - -#ifdef HAL_I2S_MODULE_ENABLED - #include "stm32f4xx_hal_i2s.h" -#endif /* HAL_I2S_MODULE_ENABLED */ - -#ifdef HAL_IWDG_MODULE_ENABLED - #include "stm32f4xx_hal_iwdg.h" -#endif /* HAL_IWDG_MODULE_ENABLED */ - -#ifdef HAL_LTDC_MODULE_ENABLED - #include "stm32f4xx_hal_ltdc.h" -#endif /* HAL_LTDC_MODULE_ENABLED */ - -#ifdef HAL_PWR_MODULE_ENABLED - #include "stm32f4xx_hal_pwr.h" -#endif /* HAL_PWR_MODULE_ENABLED */ - -#ifdef HAL_RNG_MODULE_ENABLED - #include "stm32f4xx_hal_rng.h" -#endif /* HAL_RNG_MODULE_ENABLED */ - -#ifdef HAL_RTC_MODULE_ENABLED - #include "stm32f4xx_hal_rtc.h" -#endif /* HAL_RTC_MODULE_ENABLED */ - -#ifdef HAL_SAI_MODULE_ENABLED - #include "stm32f4xx_hal_sai.h" -#endif /* HAL_SAI_MODULE_ENABLED */ - -#ifdef HAL_SD_MODULE_ENABLED - #include "stm32f4xx_hal_sd.h" -#endif /* HAL_SD_MODULE_ENABLED */ - -#ifdef HAL_SPI_MODULE_ENABLED - #include "stm32f4xx_hal_spi.h" -#endif /* HAL_SPI_MODULE_ENABLED */ - -#ifdef HAL_TIM_MODULE_ENABLED - #include "stm32f4xx_hal_tim.h" -#endif /* HAL_TIM_MODULE_ENABLED */ - -#ifdef HAL_UART_MODULE_ENABLED - #include "stm32f4xx_hal_uart.h" -#endif /* HAL_UART_MODULE_ENABLED */ - -#ifdef HAL_USART_MODULE_ENABLED - #include "stm32f4xx_hal_usart.h" -#endif /* HAL_USART_MODULE_ENABLED */ - -#ifdef HAL_IRDA_MODULE_ENABLED - #include "stm32f4xx_hal_irda.h" -#endif /* HAL_IRDA_MODULE_ENABLED */ - -#ifdef HAL_SMARTCARD_MODULE_ENABLED - #include "stm32f4xx_hal_smartcard.h" -#endif /* HAL_SMARTCARD_MODULE_ENABLED */ - -#ifdef HAL_WWDG_MODULE_ENABLED - #include "stm32f4xx_hal_wwdg.h" -#endif /* HAL_WWDG_MODULE_ENABLED */ - -#ifdef HAL_PCD_MODULE_ENABLED - #include "stm32f4xx_hal_pcd.h" -#endif /* HAL_PCD_MODULE_ENABLED */ - -#ifdef HAL_HCD_MODULE_ENABLED - #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */ - - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H diff --git a/ports/stm32/boards/NUCLEO_F091RC/stm32f0xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F091RC/stm32f0xx_hal_conf.h index 53ea047cbd..d5b2c4f7a2 100644 --- a/ports/stm32/boards/NUCLEO_F091RC/stm32f0xx_hal_conf.h +++ b/ports/stm32/boards/NUCLEO_F091RC/stm32f0xx_hal_conf.h @@ -1,312 +1,18 @@ -/** - ****************************************************************************** - * @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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32F0XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F0XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F0xx_HAL_CONF_H -#define __STM32F0xx_HAL_CONF_H +#include "boards/stm32f0xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define LSE_VALUE (32768) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) -/* ########################## 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)0x00) /*!< tick interrupt priority */ -#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****/ +#endif // MICROPY_INCLUDED_STM32F0XX_HAL_CONF_H diff --git a/ports/stm32/boards/NUCLEO_F401RE/stm32f4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F401RE/stm32f4xx_hal_conf.h index daf9b63cec..de19251e08 100644 --- a/ports/stm32/boards/NUCLEO_F401RE/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/NUCLEO_F401RE/stm32f4xx_hal_conf.h @@ -1,409 +1,19 @@ -/** - ****************************************************************************** - * @file stm32f4xx_hal_conf.h - * @author MCD Application Team - * @version V1.1.0 - * @date 19-June-2014 - * @brief HAL configuration file. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F4xx_HAL_CONF_H -#define __STM32F4xx_HAL_CONF_H +#include "boards/stm32f4xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) -/* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */ -#define HAL_PWR_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_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 */ - - -/* ########################## 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)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 ((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)40000) -#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 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 */ - -/* ################## 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 0 -#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ -#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ - -/* Section 2: PHY configuration section */ - -/* DP83848 PHY Address*/ -#define DP83848_PHY_ADDRESS 0x01 -/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ -#define PHY_RESET_DELAY ((uint32_t)0x000000FF) -/* PHY Configuration delay */ -#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) - -#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 "stm32f4xx_hal_rcc.h" -#endif /* HAL_RCC_MODULE_ENABLED */ - -#ifdef HAL_GPIO_MODULE_ENABLED - #include "stm32f4xx_hal_gpio.h" -#endif /* HAL_GPIO_MODULE_ENABLED */ - -#ifdef HAL_DMA_MODULE_ENABLED - #include "stm32f4xx_hal_dma.h" -#endif /* HAL_DMA_MODULE_ENABLED */ - -#ifdef HAL_CORTEX_MODULE_ENABLED - #include "stm32f4xx_hal_cortex.h" -#endif /* HAL_CORTEX_MODULE_ENABLED */ - -#ifdef HAL_ADC_MODULE_ENABLED - #include "stm32f4xx_hal_adc.h" -#endif /* HAL_ADC_MODULE_ENABLED */ - -#ifdef HAL_CAN_MODULE_ENABLED - #include "stm32f4xx_hal_can.h" -#endif /* HAL_CAN_MODULE_ENABLED */ - -#ifdef HAL_CRC_MODULE_ENABLED - #include "stm32f4xx_hal_crc.h" -#endif /* HAL_CRC_MODULE_ENABLED */ - -#ifdef HAL_CRYP_MODULE_ENABLED - #include "stm32f4xx_hal_cryp.h" -#endif /* HAL_CRYP_MODULE_ENABLED */ - -#ifdef HAL_DMA2D_MODULE_ENABLED - #include "stm32f4xx_hal_dma2d.h" -#endif /* HAL_DMA2D_MODULE_ENABLED */ - -#ifdef HAL_DAC_MODULE_ENABLED - #include "stm32f4xx_hal_dac.h" -#endif /* HAL_DAC_MODULE_ENABLED */ - -#ifdef HAL_DCMI_MODULE_ENABLED - #include "stm32f4xx_hal_dcmi.h" -#endif /* HAL_DCMI_MODULE_ENABLED */ - -#ifdef HAL_ETH_MODULE_ENABLED - #include "stm32f4xx_hal_eth.h" -#endif /* HAL_ETH_MODULE_ENABLED */ - -#ifdef HAL_FLASH_MODULE_ENABLED - #include "stm32f4xx_hal_flash.h" -#endif /* HAL_FLASH_MODULE_ENABLED */ - -#ifdef HAL_SRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sram.h" -#endif /* HAL_SRAM_MODULE_ENABLED */ - -#ifdef HAL_NOR_MODULE_ENABLED - #include "stm32f4xx_hal_nor.h" -#endif /* HAL_NOR_MODULE_ENABLED */ - -#ifdef HAL_NAND_MODULE_ENABLED - #include "stm32f4xx_hal_nand.h" -#endif /* HAL_NAND_MODULE_ENABLED */ - -#ifdef HAL_PCCARD_MODULE_ENABLED - #include "stm32f4xx_hal_pccard.h" -#endif /* HAL_PCCARD_MODULE_ENABLED */ - -#ifdef HAL_SDRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sdram.h" -#endif /* HAL_SDRAM_MODULE_ENABLED */ - -#ifdef HAL_HASH_MODULE_ENABLED - #include "stm32f4xx_hal_hash.h" -#endif /* HAL_HASH_MODULE_ENABLED */ - -#ifdef HAL_I2C_MODULE_ENABLED - #include "stm32f4xx_hal_i2c.h" -#endif /* HAL_I2C_MODULE_ENABLED */ - -#ifdef HAL_I2S_MODULE_ENABLED - #include "stm32f4xx_hal_i2s.h" -#endif /* HAL_I2S_MODULE_ENABLED */ - -#ifdef HAL_IWDG_MODULE_ENABLED - #include "stm32f4xx_hal_iwdg.h" -#endif /* HAL_IWDG_MODULE_ENABLED */ - -#ifdef HAL_LTDC_MODULE_ENABLED - #include "stm32f4xx_hal_ltdc.h" -#endif /* HAL_LTDC_MODULE_ENABLED */ - -#ifdef HAL_PWR_MODULE_ENABLED - #include "stm32f4xx_hal_pwr.h" -#endif /* HAL_PWR_MODULE_ENABLED */ - -#ifdef HAL_RNG_MODULE_ENABLED - #include "stm32f4xx_hal_rng.h" -#endif /* HAL_RNG_MODULE_ENABLED */ - -#ifdef HAL_RTC_MODULE_ENABLED - #include "stm32f4xx_hal_rtc.h" -#endif /* HAL_RTC_MODULE_ENABLED */ - -#ifdef HAL_SAI_MODULE_ENABLED - #include "stm32f4xx_hal_sai.h" -#endif /* HAL_SAI_MODULE_ENABLED */ - -#ifdef HAL_SD_MODULE_ENABLED - #include "stm32f4xx_hal_sd.h" -#endif /* HAL_SD_MODULE_ENABLED */ - -#ifdef HAL_SPI_MODULE_ENABLED - #include "stm32f4xx_hal_spi.h" -#endif /* HAL_SPI_MODULE_ENABLED */ - -#ifdef HAL_TIM_MODULE_ENABLED - #include "stm32f4xx_hal_tim.h" -#endif /* HAL_TIM_MODULE_ENABLED */ - -#ifdef HAL_UART_MODULE_ENABLED - #include "stm32f4xx_hal_uart.h" -#endif /* HAL_UART_MODULE_ENABLED */ - -#ifdef HAL_USART_MODULE_ENABLED - #include "stm32f4xx_hal_usart.h" -#endif /* HAL_USART_MODULE_ENABLED */ - -#ifdef HAL_IRDA_MODULE_ENABLED - #include "stm32f4xx_hal_irda.h" -#endif /* HAL_IRDA_MODULE_ENABLED */ - -#ifdef HAL_SMARTCARD_MODULE_ENABLED - #include "stm32f4xx_hal_smartcard.h" -#endif /* HAL_SMARTCARD_MODULE_ENABLED */ - -#ifdef HAL_WWDG_MODULE_ENABLED - #include "stm32f4xx_hal_wwdg.h" -#endif /* HAL_WWDG_MODULE_ENABLED */ - -#ifdef HAL_PCD_MODULE_ENABLED - #include "stm32f4xx_hal_pcd.h" -#endif /* HAL_PCD_MODULE_ENABLED */ - -#ifdef HAL_HCD_MODULE_ENABLED - #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */ - - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H diff --git a/ports/stm32/boards/NUCLEO_F411RE/stm32f4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F411RE/stm32f4xx_hal_conf.h index 8f0b663811..de19251e08 100644 --- a/ports/stm32/boards/NUCLEO_F411RE/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/NUCLEO_F411RE/stm32f4xx_hal_conf.h @@ -1,409 +1,19 @@ -/** - ****************************************************************************** - * @file stm32f4xx_hal_conf.h - * @author MCD Application Team - * @version V1.1.0 - * @date 19-June-2014 - * @brief HAL configuration file. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F4xx_HAL_CONF_H -#define __STM32F4xx_HAL_CONF_H +#include "boards/stm32f4xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) -/* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */ -#define HAL_PWR_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_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 */ - - -/* ########################## 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)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 ((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)40000) -#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 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 */ - -/* ################## 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 0 -#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ -#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ - -/* Section 2: PHY configuration section */ - -/* DP83848 PHY Address*/ -#define DP83848_PHY_ADDRESS 0x01 -/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ -#define PHY_RESET_DELAY ((uint32_t)0x000000FF) -/* PHY Configuration delay */ -#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) - -#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 "stm32f4xx_hal_rcc.h" -#endif /* HAL_RCC_MODULE_ENABLED */ - -#ifdef HAL_GPIO_MODULE_ENABLED - #include "stm32f4xx_hal_gpio.h" -#endif /* HAL_GPIO_MODULE_ENABLED */ - -#ifdef HAL_DMA_MODULE_ENABLED - #include "stm32f4xx_hal_dma.h" -#endif /* HAL_DMA_MODULE_ENABLED */ - -#ifdef HAL_CORTEX_MODULE_ENABLED - #include "stm32f4xx_hal_cortex.h" -#endif /* HAL_CORTEX_MODULE_ENABLED */ - -#ifdef HAL_ADC_MODULE_ENABLED - #include "stm32f4xx_hal_adc.h" -#endif /* HAL_ADC_MODULE_ENABLED */ - -#ifdef HAL_CAN_MODULE_ENABLED - #include "stm32f4xx_hal_can.h" -#endif /* HAL_CAN_MODULE_ENABLED */ - -#ifdef HAL_CRC_MODULE_ENABLED - #include "stm32f4xx_hal_crc.h" -#endif /* HAL_CRC_MODULE_ENABLED */ - -#ifdef HAL_CRYP_MODULE_ENABLED - #include "stm32f4xx_hal_cryp.h" -#endif /* HAL_CRYP_MODULE_ENABLED */ - -#ifdef HAL_DMA2D_MODULE_ENABLED - #include "stm32f4xx_hal_dma2d.h" -#endif /* HAL_DMA2D_MODULE_ENABLED */ - -#ifdef HAL_DAC_MODULE_ENABLED - #include "stm32f4xx_hal_dac.h" -#endif /* HAL_DAC_MODULE_ENABLED */ - -#ifdef HAL_DCMI_MODULE_ENABLED - #include "stm32f4xx_hal_dcmi.h" -#endif /* HAL_DCMI_MODULE_ENABLED */ - -#ifdef HAL_ETH_MODULE_ENABLED - #include "stm32f4xx_hal_eth.h" -#endif /* HAL_ETH_MODULE_ENABLED */ - -#ifdef HAL_FLASH_MODULE_ENABLED - #include "stm32f4xx_hal_flash.h" -#endif /* HAL_FLASH_MODULE_ENABLED */ - -#ifdef HAL_SRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sram.h" -#endif /* HAL_SRAM_MODULE_ENABLED */ - -#ifdef HAL_NOR_MODULE_ENABLED - #include "stm32f4xx_hal_nor.h" -#endif /* HAL_NOR_MODULE_ENABLED */ - -#ifdef HAL_NAND_MODULE_ENABLED - #include "stm32f4xx_hal_nand.h" -#endif /* HAL_NAND_MODULE_ENABLED */ - -#ifdef HAL_PCCARD_MODULE_ENABLED - #include "stm32f4xx_hal_pccard.h" -#endif /* HAL_PCCARD_MODULE_ENABLED */ - -#ifdef HAL_SDRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sdram.h" -#endif /* HAL_SDRAM_MODULE_ENABLED */ - -#ifdef HAL_HASH_MODULE_ENABLED - #include "stm32f4xx_hal_hash.h" -#endif /* HAL_HASH_MODULE_ENABLED */ - -#ifdef HAL_I2C_MODULE_ENABLED - #include "stm32f4xx_hal_i2c.h" -#endif /* HAL_I2C_MODULE_ENABLED */ - -#ifdef HAL_I2S_MODULE_ENABLED - #include "stm32f4xx_hal_i2s.h" -#endif /* HAL_I2S_MODULE_ENABLED */ - -#ifdef HAL_IWDG_MODULE_ENABLED - #include "stm32f4xx_hal_iwdg.h" -#endif /* HAL_IWDG_MODULE_ENABLED */ - -#ifdef HAL_LTDC_MODULE_ENABLED - #include "stm32f4xx_hal_ltdc.h" -#endif /* HAL_LTDC_MODULE_ENABLED */ - -#ifdef HAL_PWR_MODULE_ENABLED - #include "stm32f4xx_hal_pwr.h" -#endif /* HAL_PWR_MODULE_ENABLED */ - -#ifdef HAL_RNG_MODULE_ENABLED - #include "stm32f4xx_hal_rng.h" -#endif /* HAL_RNG_MODULE_ENABLED */ - -#ifdef HAL_RTC_MODULE_ENABLED - #include "stm32f4xx_hal_rtc.h" -#endif /* HAL_RTC_MODULE_ENABLED */ - -#ifdef HAL_SAI_MODULE_ENABLED - #include "stm32f4xx_hal_sai.h" -#endif /* HAL_SAI_MODULE_ENABLED */ - -#ifdef HAL_SD_MODULE_ENABLED - #include "stm32f4xx_hal_sd.h" -#endif /* HAL_SD_MODULE_ENABLED */ - -#ifdef HAL_SPI_MODULE_ENABLED - #include "stm32f4xx_hal_spi.h" -#endif /* HAL_SPI_MODULE_ENABLED */ - -#ifdef HAL_TIM_MODULE_ENABLED - #include "stm32f4xx_hal_tim.h" -#endif /* HAL_TIM_MODULE_ENABLED */ - -#ifdef HAL_UART_MODULE_ENABLED - #include "stm32f4xx_hal_uart.h" -#endif /* HAL_UART_MODULE_ENABLED */ - -#ifdef HAL_USART_MODULE_ENABLED - #include "stm32f4xx_hal_usart.h" -#endif /* HAL_USART_MODULE_ENABLED */ - -#ifdef HAL_IRDA_MODULE_ENABLED - #include "stm32f4xx_hal_irda.h" -#endif /* HAL_IRDA_MODULE_ENABLED */ - -#ifdef HAL_SMARTCARD_MODULE_ENABLED - #include "stm32f4xx_hal_smartcard.h" -#endif /* HAL_SMARTCARD_MODULE_ENABLED */ - -#ifdef HAL_WWDG_MODULE_ENABLED - #include "stm32f4xx_hal_wwdg.h" -#endif /* HAL_WWDG_MODULE_ENABLED */ - -#ifdef HAL_PCD_MODULE_ENABLED - #include "stm32f4xx_hal_pcd.h" -#endif /* HAL_PCD_MODULE_ENABLED */ - -#ifdef HAL_HCD_MODULE_ENABLED - #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */ - - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H diff --git a/ports/stm32/boards/NUCLEO_F413ZH/stm32f4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F413ZH/stm32f4xx_hal_conf.h index 5b5a8a3e43..de19251e08 100644 --- a/ports/stm32/boards/NUCLEO_F413ZH/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/NUCLEO_F413ZH/stm32f4xx_hal_conf.h @@ -1,409 +1,19 @@ -/** - ****************************************************************************** - * @file stm32f4xx_hal_conf.h - * @author MCD Application Team - * @version V1.1.0 - * @date 19-June-2014 - * @brief HAL configuration file. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F4xx_HAL_CONF_H -#define __STM32F4xx_HAL_CONF_H +#include "boards/stm32f4xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) - /* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */ -#define HAL_PWR_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_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 */ - - -/* ########################## 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)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 ((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)40000) -#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 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 */ - -/* ################## 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 0 -#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ -#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ - -/* Section 2: PHY configuration section */ - -/* DP83848 PHY Address*/ -#define DP83848_PHY_ADDRESS 0x01 -/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ -#define PHY_RESET_DELAY ((uint32_t)0x000000FF) -/* PHY Configuration delay */ -#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) - -#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 "stm32f4xx_hal_rcc.h" -#endif /* HAL_RCC_MODULE_ENABLED */ - -#ifdef HAL_GPIO_MODULE_ENABLED - #include "stm32f4xx_hal_gpio.h" -#endif /* HAL_GPIO_MODULE_ENABLED */ - -#ifdef HAL_DMA_MODULE_ENABLED - #include "stm32f4xx_hal_dma.h" -#endif /* HAL_DMA_MODULE_ENABLED */ - -#ifdef HAL_CORTEX_MODULE_ENABLED - #include "stm32f4xx_hal_cortex.h" -#endif /* HAL_CORTEX_MODULE_ENABLED */ - -#ifdef HAL_ADC_MODULE_ENABLED - #include "stm32f4xx_hal_adc.h" -#endif /* HAL_ADC_MODULE_ENABLED */ - -#ifdef HAL_CAN_MODULE_ENABLED - #include "stm32f4xx_hal_can.h" -#endif /* HAL_CAN_MODULE_ENABLED */ - -#ifdef HAL_CRC_MODULE_ENABLED - #include "stm32f4xx_hal_crc.h" -#endif /* HAL_CRC_MODULE_ENABLED */ - -#ifdef HAL_CRYP_MODULE_ENABLED - #include "stm32f4xx_hal_cryp.h" -#endif /* HAL_CRYP_MODULE_ENABLED */ - -#ifdef HAL_DMA2D_MODULE_ENABLED - #include "stm32f4xx_hal_dma2d.h" -#endif /* HAL_DMA2D_MODULE_ENABLED */ - -#ifdef HAL_DAC_MODULE_ENABLED - #include "stm32f4xx_hal_dac.h" -#endif /* HAL_DAC_MODULE_ENABLED */ - -#ifdef HAL_DCMI_MODULE_ENABLED - #include "stm32f4xx_hal_dcmi.h" -#endif /* HAL_DCMI_MODULE_ENABLED */ - -#ifdef HAL_ETH_MODULE_ENABLED - #include "stm32f4xx_hal_eth.h" -#endif /* HAL_ETH_MODULE_ENABLED */ - -#ifdef HAL_FLASH_MODULE_ENABLED - #include "stm32f4xx_hal_flash.h" -#endif /* HAL_FLASH_MODULE_ENABLED */ - -#ifdef HAL_SRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sram.h" -#endif /* HAL_SRAM_MODULE_ENABLED */ - -#ifdef HAL_NOR_MODULE_ENABLED - #include "stm32f4xx_hal_nor.h" -#endif /* HAL_NOR_MODULE_ENABLED */ - -#ifdef HAL_NAND_MODULE_ENABLED - #include "stm32f4xx_hal_nand.h" -#endif /* HAL_NAND_MODULE_ENABLED */ - -#ifdef HAL_PCCARD_MODULE_ENABLED - #include "stm32f4xx_hal_pccard.h" -#endif /* HAL_PCCARD_MODULE_ENABLED */ - -#ifdef HAL_SDRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sdram.h" -#endif /* HAL_SDRAM_MODULE_ENABLED */ - -#ifdef HAL_HASH_MODULE_ENABLED - #include "stm32f4xx_hal_hash.h" -#endif /* HAL_HASH_MODULE_ENABLED */ - -#ifdef HAL_I2C_MODULE_ENABLED - #include "stm32f4xx_hal_i2c.h" -#endif /* HAL_I2C_MODULE_ENABLED */ - -#ifdef HAL_I2S_MODULE_ENABLED - #include "stm32f4xx_hal_i2s.h" -#endif /* HAL_I2S_MODULE_ENABLED */ - -#ifdef HAL_IWDG_MODULE_ENABLED - #include "stm32f4xx_hal_iwdg.h" -#endif /* HAL_IWDG_MODULE_ENABLED */ - -#ifdef HAL_LTDC_MODULE_ENABLED - #include "stm32f4xx_hal_ltdc.h" -#endif /* HAL_LTDC_MODULE_ENABLED */ - -#ifdef HAL_PWR_MODULE_ENABLED - #include "stm32f4xx_hal_pwr.h" -#endif /* HAL_PWR_MODULE_ENABLED */ - -#ifdef HAL_RNG_MODULE_ENABLED - #include "stm32f4xx_hal_rng.h" -#endif /* HAL_RNG_MODULE_ENABLED */ - -#ifdef HAL_RTC_MODULE_ENABLED - #include "stm32f4xx_hal_rtc.h" -#endif /* HAL_RTC_MODULE_ENABLED */ - -#ifdef HAL_SAI_MODULE_ENABLED - #include "stm32f4xx_hal_sai.h" -#endif /* HAL_SAI_MODULE_ENABLED */ - -#ifdef HAL_SD_MODULE_ENABLED - #include "stm32f4xx_hal_sd.h" -#endif /* HAL_SD_MODULE_ENABLED */ - -#ifdef HAL_SPI_MODULE_ENABLED - #include "stm32f4xx_hal_spi.h" -#endif /* HAL_SPI_MODULE_ENABLED */ - -#ifdef HAL_TIM_MODULE_ENABLED - #include "stm32f4xx_hal_tim.h" -#endif /* HAL_TIM_MODULE_ENABLED */ - -#ifdef HAL_UART_MODULE_ENABLED - #include "stm32f4xx_hal_uart.h" -#endif /* HAL_UART_MODULE_ENABLED */ - -#ifdef HAL_USART_MODULE_ENABLED - #include "stm32f4xx_hal_usart.h" -#endif /* HAL_USART_MODULE_ENABLED */ - -#ifdef HAL_IRDA_MODULE_ENABLED - #include "stm32f4xx_hal_irda.h" -#endif /* HAL_IRDA_MODULE_ENABLED */ - -#ifdef HAL_SMARTCARD_MODULE_ENABLED - #include "stm32f4xx_hal_smartcard.h" -#endif /* HAL_SMARTCARD_MODULE_ENABLED */ - -#ifdef HAL_WWDG_MODULE_ENABLED - #include "stm32f4xx_hal_wwdg.h" -#endif /* HAL_WWDG_MODULE_ENABLED */ - -#ifdef HAL_PCD_MODULE_ENABLED - #include "stm32f4xx_hal_pcd.h" -#endif /* HAL_PCD_MODULE_ENABLED */ - -#ifdef HAL_HCD_MODULE_ENABLED - #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */ - - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H diff --git a/ports/stm32/boards/NUCLEO_F429ZI/stm32f4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F429ZI/stm32f4xx_hal_conf.h index 5b5a8a3e43..de19251e08 100644 --- a/ports/stm32/boards/NUCLEO_F429ZI/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/NUCLEO_F429ZI/stm32f4xx_hal_conf.h @@ -1,409 +1,19 @@ -/** - ****************************************************************************** - * @file stm32f4xx_hal_conf.h - * @author MCD Application Team - * @version V1.1.0 - * @date 19-June-2014 - * @brief HAL configuration file. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F4xx_HAL_CONF_H -#define __STM32F4xx_HAL_CONF_H +#include "boards/stm32f4xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) - /* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */ -#define HAL_PWR_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_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 */ - - -/* ########################## 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)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 ((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)40000) -#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 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 */ - -/* ################## 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 0 -#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ -#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ - -/* Section 2: PHY configuration section */ - -/* DP83848 PHY Address*/ -#define DP83848_PHY_ADDRESS 0x01 -/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ -#define PHY_RESET_DELAY ((uint32_t)0x000000FF) -/* PHY Configuration delay */ -#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) - -#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 "stm32f4xx_hal_rcc.h" -#endif /* HAL_RCC_MODULE_ENABLED */ - -#ifdef HAL_GPIO_MODULE_ENABLED - #include "stm32f4xx_hal_gpio.h" -#endif /* HAL_GPIO_MODULE_ENABLED */ - -#ifdef HAL_DMA_MODULE_ENABLED - #include "stm32f4xx_hal_dma.h" -#endif /* HAL_DMA_MODULE_ENABLED */ - -#ifdef HAL_CORTEX_MODULE_ENABLED - #include "stm32f4xx_hal_cortex.h" -#endif /* HAL_CORTEX_MODULE_ENABLED */ - -#ifdef HAL_ADC_MODULE_ENABLED - #include "stm32f4xx_hal_adc.h" -#endif /* HAL_ADC_MODULE_ENABLED */ - -#ifdef HAL_CAN_MODULE_ENABLED - #include "stm32f4xx_hal_can.h" -#endif /* HAL_CAN_MODULE_ENABLED */ - -#ifdef HAL_CRC_MODULE_ENABLED - #include "stm32f4xx_hal_crc.h" -#endif /* HAL_CRC_MODULE_ENABLED */ - -#ifdef HAL_CRYP_MODULE_ENABLED - #include "stm32f4xx_hal_cryp.h" -#endif /* HAL_CRYP_MODULE_ENABLED */ - -#ifdef HAL_DMA2D_MODULE_ENABLED - #include "stm32f4xx_hal_dma2d.h" -#endif /* HAL_DMA2D_MODULE_ENABLED */ - -#ifdef HAL_DAC_MODULE_ENABLED - #include "stm32f4xx_hal_dac.h" -#endif /* HAL_DAC_MODULE_ENABLED */ - -#ifdef HAL_DCMI_MODULE_ENABLED - #include "stm32f4xx_hal_dcmi.h" -#endif /* HAL_DCMI_MODULE_ENABLED */ - -#ifdef HAL_ETH_MODULE_ENABLED - #include "stm32f4xx_hal_eth.h" -#endif /* HAL_ETH_MODULE_ENABLED */ - -#ifdef HAL_FLASH_MODULE_ENABLED - #include "stm32f4xx_hal_flash.h" -#endif /* HAL_FLASH_MODULE_ENABLED */ - -#ifdef HAL_SRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sram.h" -#endif /* HAL_SRAM_MODULE_ENABLED */ - -#ifdef HAL_NOR_MODULE_ENABLED - #include "stm32f4xx_hal_nor.h" -#endif /* HAL_NOR_MODULE_ENABLED */ - -#ifdef HAL_NAND_MODULE_ENABLED - #include "stm32f4xx_hal_nand.h" -#endif /* HAL_NAND_MODULE_ENABLED */ - -#ifdef HAL_PCCARD_MODULE_ENABLED - #include "stm32f4xx_hal_pccard.h" -#endif /* HAL_PCCARD_MODULE_ENABLED */ - -#ifdef HAL_SDRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sdram.h" -#endif /* HAL_SDRAM_MODULE_ENABLED */ - -#ifdef HAL_HASH_MODULE_ENABLED - #include "stm32f4xx_hal_hash.h" -#endif /* HAL_HASH_MODULE_ENABLED */ - -#ifdef HAL_I2C_MODULE_ENABLED - #include "stm32f4xx_hal_i2c.h" -#endif /* HAL_I2C_MODULE_ENABLED */ - -#ifdef HAL_I2S_MODULE_ENABLED - #include "stm32f4xx_hal_i2s.h" -#endif /* HAL_I2S_MODULE_ENABLED */ - -#ifdef HAL_IWDG_MODULE_ENABLED - #include "stm32f4xx_hal_iwdg.h" -#endif /* HAL_IWDG_MODULE_ENABLED */ - -#ifdef HAL_LTDC_MODULE_ENABLED - #include "stm32f4xx_hal_ltdc.h" -#endif /* HAL_LTDC_MODULE_ENABLED */ - -#ifdef HAL_PWR_MODULE_ENABLED - #include "stm32f4xx_hal_pwr.h" -#endif /* HAL_PWR_MODULE_ENABLED */ - -#ifdef HAL_RNG_MODULE_ENABLED - #include "stm32f4xx_hal_rng.h" -#endif /* HAL_RNG_MODULE_ENABLED */ - -#ifdef HAL_RTC_MODULE_ENABLED - #include "stm32f4xx_hal_rtc.h" -#endif /* HAL_RTC_MODULE_ENABLED */ - -#ifdef HAL_SAI_MODULE_ENABLED - #include "stm32f4xx_hal_sai.h" -#endif /* HAL_SAI_MODULE_ENABLED */ - -#ifdef HAL_SD_MODULE_ENABLED - #include "stm32f4xx_hal_sd.h" -#endif /* HAL_SD_MODULE_ENABLED */ - -#ifdef HAL_SPI_MODULE_ENABLED - #include "stm32f4xx_hal_spi.h" -#endif /* HAL_SPI_MODULE_ENABLED */ - -#ifdef HAL_TIM_MODULE_ENABLED - #include "stm32f4xx_hal_tim.h" -#endif /* HAL_TIM_MODULE_ENABLED */ - -#ifdef HAL_UART_MODULE_ENABLED - #include "stm32f4xx_hal_uart.h" -#endif /* HAL_UART_MODULE_ENABLED */ - -#ifdef HAL_USART_MODULE_ENABLED - #include "stm32f4xx_hal_usart.h" -#endif /* HAL_USART_MODULE_ENABLED */ - -#ifdef HAL_IRDA_MODULE_ENABLED - #include "stm32f4xx_hal_irda.h" -#endif /* HAL_IRDA_MODULE_ENABLED */ - -#ifdef HAL_SMARTCARD_MODULE_ENABLED - #include "stm32f4xx_hal_smartcard.h" -#endif /* HAL_SMARTCARD_MODULE_ENABLED */ - -#ifdef HAL_WWDG_MODULE_ENABLED - #include "stm32f4xx_hal_wwdg.h" -#endif /* HAL_WWDG_MODULE_ENABLED */ - -#ifdef HAL_PCD_MODULE_ENABLED - #include "stm32f4xx_hal_pcd.h" -#endif /* HAL_PCD_MODULE_ENABLED */ - -#ifdef HAL_HCD_MODULE_ENABLED - #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */ - - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H diff --git a/ports/stm32/boards/NUCLEO_F446RE/stm32f4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F446RE/stm32f4xx_hal_conf.h index 245fb9a06a..de19251e08 100644 --- a/ports/stm32/boards/NUCLEO_F446RE/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/NUCLEO_F446RE/stm32f4xx_hal_conf.h @@ -1,409 +1,19 @@ -/** - ****************************************************************************** - * @file stm32f4xx_hal_conf.h - * @author MCD Application Team - * @version V1.1.0 - * @date 19-June-2014 - * @brief HAL configuration file. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F4xx_HAL_CONF_H -#define __STM32F4xx_HAL_CONF_H +#include "boards/stm32f4xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) -/* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */ -#define HAL_PWR_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_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 */ - - -/* ########################## 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)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 ((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)40000) -#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 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 */ - -/* ################## 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 0 -#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ -#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ - -/* Section 2: PHY configuration section */ - -/* DP83848 PHY Address*/ -#define DP83848_PHY_ADDRESS 0x01 -/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ -#define PHY_RESET_DELAY ((uint32_t)0x000000FF) -/* PHY Configuration delay */ -#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) - -#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 "stm32f4xx_hal_rcc.h" -#endif /* HAL_RCC_MODULE_ENABLED */ - -#ifdef HAL_GPIO_MODULE_ENABLED - #include "stm32f4xx_hal_gpio.h" -#endif /* HAL_GPIO_MODULE_ENABLED */ - -#ifdef HAL_DMA_MODULE_ENABLED - #include "stm32f4xx_hal_dma.h" -#endif /* HAL_DMA_MODULE_ENABLED */ - -#ifdef HAL_CORTEX_MODULE_ENABLED - #include "stm32f4xx_hal_cortex.h" -#endif /* HAL_CORTEX_MODULE_ENABLED */ - -#ifdef HAL_ADC_MODULE_ENABLED - #include "stm32f4xx_hal_adc.h" -#endif /* HAL_ADC_MODULE_ENABLED */ - -#ifdef HAL_CAN_MODULE_ENABLED - #include "stm32f4xx_hal_can.h" -#endif /* HAL_CAN_MODULE_ENABLED */ - -#ifdef HAL_CRC_MODULE_ENABLED - #include "stm32f4xx_hal_crc.h" -#endif /* HAL_CRC_MODULE_ENABLED */ - -#ifdef HAL_CRYP_MODULE_ENABLED - #include "stm32f4xx_hal_cryp.h" -#endif /* HAL_CRYP_MODULE_ENABLED */ - -#ifdef HAL_DMA2D_MODULE_ENABLED - #include "stm32f4xx_hal_dma2d.h" -#endif /* HAL_DMA2D_MODULE_ENABLED */ - -#ifdef HAL_DAC_MODULE_ENABLED - #include "stm32f4xx_hal_dac.h" -#endif /* HAL_DAC_MODULE_ENABLED */ - -#ifdef HAL_DCMI_MODULE_ENABLED - #include "stm32f4xx_hal_dcmi.h" -#endif /* HAL_DCMI_MODULE_ENABLED */ - -#ifdef HAL_ETH_MODULE_ENABLED - #include "stm32f4xx_hal_eth.h" -#endif /* HAL_ETH_MODULE_ENABLED */ - -#ifdef HAL_FLASH_MODULE_ENABLED - #include "stm32f4xx_hal_flash.h" -#endif /* HAL_FLASH_MODULE_ENABLED */ - -#ifdef HAL_SRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sram.h" -#endif /* HAL_SRAM_MODULE_ENABLED */ - -#ifdef HAL_NOR_MODULE_ENABLED - #include "stm32f4xx_hal_nor.h" -#endif /* HAL_NOR_MODULE_ENABLED */ - -#ifdef HAL_NAND_MODULE_ENABLED - #include "stm32f4xx_hal_nand.h" -#endif /* HAL_NAND_MODULE_ENABLED */ - -#ifdef HAL_PCCARD_MODULE_ENABLED - #include "stm32f4xx_hal_pccard.h" -#endif /* HAL_PCCARD_MODULE_ENABLED */ - -#ifdef HAL_SDRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sdram.h" -#endif /* HAL_SDRAM_MODULE_ENABLED */ - -#ifdef HAL_HASH_MODULE_ENABLED - #include "stm32f4xx_hal_hash.h" -#endif /* HAL_HASH_MODULE_ENABLED */ - -#ifdef HAL_I2C_MODULE_ENABLED - #include "stm32f4xx_hal_i2c.h" -#endif /* HAL_I2C_MODULE_ENABLED */ - -#ifdef HAL_I2S_MODULE_ENABLED - #include "stm32f4xx_hal_i2s.h" -#endif /* HAL_I2S_MODULE_ENABLED */ - -#ifdef HAL_IWDG_MODULE_ENABLED - #include "stm32f4xx_hal_iwdg.h" -#endif /* HAL_IWDG_MODULE_ENABLED */ - -#ifdef HAL_LTDC_MODULE_ENABLED - #include "stm32f4xx_hal_ltdc.h" -#endif /* HAL_LTDC_MODULE_ENABLED */ - -#ifdef HAL_PWR_MODULE_ENABLED - #include "stm32f4xx_hal_pwr.h" -#endif /* HAL_PWR_MODULE_ENABLED */ - -#ifdef HAL_RNG_MODULE_ENABLED - #include "stm32f4xx_hal_rng.h" -#endif /* HAL_RNG_MODULE_ENABLED */ - -#ifdef HAL_RTC_MODULE_ENABLED - #include "stm32f4xx_hal_rtc.h" -#endif /* HAL_RTC_MODULE_ENABLED */ - -#ifdef HAL_SAI_MODULE_ENABLED - #include "stm32f4xx_hal_sai.h" -#endif /* HAL_SAI_MODULE_ENABLED */ - -#ifdef HAL_SD_MODULE_ENABLED - #include "stm32f4xx_hal_sd.h" -#endif /* HAL_SD_MODULE_ENABLED */ - -#ifdef HAL_SPI_MODULE_ENABLED - #include "stm32f4xx_hal_spi.h" -#endif /* HAL_SPI_MODULE_ENABLED */ - -#ifdef HAL_TIM_MODULE_ENABLED - #include "stm32f4xx_hal_tim.h" -#endif /* HAL_TIM_MODULE_ENABLED */ - -#ifdef HAL_UART_MODULE_ENABLED - #include "stm32f4xx_hal_uart.h" -#endif /* HAL_UART_MODULE_ENABLED */ - -#ifdef HAL_USART_MODULE_ENABLED - #include "stm32f4xx_hal_usart.h" -#endif /* HAL_USART_MODULE_ENABLED */ - -#ifdef HAL_IRDA_MODULE_ENABLED - #include "stm32f4xx_hal_irda.h" -#endif /* HAL_IRDA_MODULE_ENABLED */ - -#ifdef HAL_SMARTCARD_MODULE_ENABLED - #include "stm32f4xx_hal_smartcard.h" -#endif /* HAL_SMARTCARD_MODULE_ENABLED */ - -#ifdef HAL_WWDG_MODULE_ENABLED - #include "stm32f4xx_hal_wwdg.h" -#endif /* HAL_WWDG_MODULE_ENABLED */ - -#ifdef HAL_PCD_MODULE_ENABLED - #include "stm32f4xx_hal_pcd.h" -#endif /* HAL_PCD_MODULE_ENABLED */ - -#ifdef HAL_HCD_MODULE_ENABLED - #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */ - - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H diff --git a/ports/stm32/boards/NUCLEO_F746ZG/stm32f7xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F746ZG/stm32f7xx_hal_conf.h index a019ee4ce9..e241921ddd 100644 --- a/ports/stm32/boards/NUCLEO_F746ZG/stm32f7xx_hal_conf.h +++ b/ports/stm32/boards/NUCLEO_F746ZG/stm32f7xx_hal_conf.h @@ -1,427 +1,19 @@ -/** - ****************************************************************************** - * @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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32F7XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F7XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F7xx_HAL_CONF_H -#define __STM32F7xx_HAL_CONF_H +#include "boards/stm32f7xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (5000) +#define LSE_STARTUP_TIMEOUT (5000) -/* ########################## 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****/ +#endif // MICROPY_INCLUDED_STM32F7XX_HAL_CONF_H diff --git a/ports/stm32/boards/NUCLEO_F767ZI/stm32f7xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F767ZI/stm32f7xx_hal_conf.h index a019ee4ce9..e241921ddd 100644 --- a/ports/stm32/boards/NUCLEO_F767ZI/stm32f7xx_hal_conf.h +++ b/ports/stm32/boards/NUCLEO_F767ZI/stm32f7xx_hal_conf.h @@ -1,427 +1,19 @@ -/** - ****************************************************************************** - * @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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32F7XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F7XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F7xx_HAL_CONF_H -#define __STM32F7xx_HAL_CONF_H +#include "boards/stm32f7xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (5000) +#define LSE_STARTUP_TIMEOUT (5000) -/* ########################## 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****/ +#endif // MICROPY_INCLUDED_STM32F7XX_HAL_CONF_H diff --git a/ports/stm32/boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h b/ports/stm32/boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h index 97b141d49f..45400cdcd7 100644 --- a/ports/stm32/boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h +++ b/ports/stm32/boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h @@ -1,434 +1,19 @@ -/** - ****************************************************************************** - * @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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32H7XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32H7XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32H7xx_HAL_CONF_H -#define __STM32H7xx_HAL_CONF_H +#include "boards/stm32h7xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (5000) +#define LSE_STARTUP_TIMEOUT (5000) -/* ########################## 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)0x00) /*!< tick interrupt priority */ -#define USE_RTOS 0 -#define USE_SD_TRANSCEIVER 0U /*!< 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****/ +#endif // MICROPY_INCLUDED_STM32H7XX_HAL_CONF_H diff --git a/ports/stm32/boards/NUCLEO_L432KC/stm32l4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_L432KC/stm32l4xx_hal_conf.h index 1ee8fbabc4..fd380ab735 100755 --- a/ports/stm32/boards/NUCLEO_L432KC/stm32l4xx_hal_conf.h +++ b/ports/stm32/boards/NUCLEO_L432KC/stm32l4xx_hal_conf.h @@ -1,384 +1,20 @@ -/** - ****************************************************************************** - * @file stm32l4xx_hal_conf.h - * @author MCD Application Team - * @version V1.2.0 - * @date 25-November-2015 - * @brief HAL configuration template file. - * This file should be copied to the application folder and renamed - * to stm32l4xx_hal_conf.h. - ****************************************************************************** - * @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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32L4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32L4XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32L4xx_HAL_CONF_H -#define __STM32L4xx_HAL_CONF_H +#include "boards/stm32l4xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define LSE_VALUE (32768) +#define EXTERNAL_SAI1_CLOCK_VALUE (48000) +#define EXTERNAL_SAI2_CLOCK_VALUE (48000) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) -/* ########################## 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_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_DFSDM_MODULE_ENABLED */ -#define HAL_DMA_MODULE_ENABLED -/* #define HAL_FIREWALL_MODULE_ENABLED */ -#define HAL_FLASH_MODULE_ENABLED -/* #define HAL_HCD_MODULE_ENABLED */ -/* #define HAL_NAND_MODULE_ENABLED */ -/* #define HAL_NOR_MODULE_ENABLED */ -/* #define HAL_SRAM_MODULE_ENABLED */ -#define HAL_GPIO_MODULE_ENABLED -#define HAL_I2C_MODULE_ENABLED -/* #define HAL_IRDA_MODULE_ENABLED */ -/* #define HAL_IWDG_MODULE_ENABLED */ -/* #define HAL_LCD_MODULE_ENABLED */ -/* #define HAL_LPTIM_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_SMARTCARD_MODULE_ENABLED */ -/* #define HAL_SMBUS_MODULE_ENABLED */ -#define HAL_SPI_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 */ - - -/* ########################## 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 */ - -/* Includes ------------------------------------------------------------------*/ -/** - * @brief Include module's header file - */ - -#ifdef HAL_RCC_MODULE_ENABLED - #include "stm32l4xx_hal_rcc.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_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_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_OPAMP_MODULE_ENABLED -#include "stm32l4xx_hal_opamp.h" -#endif /* HAL_OPAMP_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 */ - -/* 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 /* __STM32L4xx_HAL_CONF_H */ - - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +#endif // MICROPY_INCLUDED_STM32L4XX_HAL_CONF_H diff --git a/ports/stm32/boards/NUCLEO_L476RG/stm32l4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_L476RG/stm32l4xx_hal_conf.h index 6bfb28118a..fd380ab735 100755 --- a/ports/stm32/boards/NUCLEO_L476RG/stm32l4xx_hal_conf.h +++ b/ports/stm32/boards/NUCLEO_L476RG/stm32l4xx_hal_conf.h @@ -1,372 +1,20 @@ -/** - ****************************************************************************** - * @file stm32l4xx_hal_conf.h - * @author MCD Application Team - * @version V1.2.0 - * @date 25-November-2015 - * @brief HAL configuration template file. - * This file should be copied to the application folder and renamed - * to stm32l4xx_hal_conf.h. - ****************************************************************************** - * @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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32L4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32L4XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32L4xx_HAL_CONF_H -#define __STM32L4xx_HAL_CONF_H +#include "boards/stm32l4xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define LSE_VALUE (32768) +#define EXTERNAL_SAI1_CLOCK_VALUE (48000) +#define EXTERNAL_SAI2_CLOCK_VALUE (48000) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) -/* ########################## 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_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_DFSDM_MODULE_ENABLED */ -#define HAL_DMA_MODULE_ENABLED -/* #define HAL_FIREWALL_MODULE_ENABLED */ -#define HAL_FLASH_MODULE_ENABLED -/* #define HAL_HCD_MODULE_ENABLED */ -/* #define HAL_NAND_MODULE_ENABLED */ -/* #define HAL_NOR_MODULE_ENABLED */ -/* #define HAL_SRAM_MODULE_ENABLED */ -#define HAL_GPIO_MODULE_ENABLED -#define HAL_I2C_MODULE_ENABLED -/* #define HAL_IRDA_MODULE_ENABLED */ -/* #define HAL_IWDG_MODULE_ENABLED */ -/* #define HAL_LCD_MODULE_ENABLED */ -/* #define HAL_LPTIM_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_SMARTCARD_MODULE_ENABLED */ -/* #define HAL_SMBUS_MODULE_ENABLED */ -#define HAL_SPI_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 */ - - -/* ########################## 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 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 */ - -/* Includes ------------------------------------------------------------------*/ -/** - * @brief Include module's header file - */ - -#ifdef HAL_RCC_MODULE_ENABLED - #include "stm32l4xx_hal_rcc.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_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_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_OPAMP_MODULE_ENABLED -#include "stm32l4xx_hal_opamp.h" -#endif /* HAL_OPAMP_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 */ - -/* 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 /* __STM32L4xx_HAL_CONF_H */ - - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +#endif // MICROPY_INCLUDED_STM32L4XX_HAL_CONF_H diff --git a/ports/stm32/boards/OLIMEX_E407/stm32f4xx_hal_conf.h b/ports/stm32/boards/OLIMEX_E407/stm32f4xx_hal_conf.h index 24cc9228b8..9719157e55 100644 --- a/ports/stm32/boards/OLIMEX_E407/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/OLIMEX_E407/stm32f4xx_hal_conf.h @@ -1,409 +1,19 @@ -/** - ****************************************************************************** - * @file stm32f4xx_hal_conf.h - * @author MCD Application Team - * @version V1.1.0 - * @date 19-June-2014 - * @brief HAL configuration file. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F4xx_HAL_CONF_H -#define __STM32F4xx_HAL_CONF_H +#include "boards/stm32f4xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (12000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) -/* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */ -#define HAL_PWR_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_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 */ - - -/* ########################## 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)12000000) /*!< Value of the External oscillator in Hz */ -#endif /* HSE_VALUE */ - -#if !defined (HSE_STARTUP_TIMEOUT) - #define HSE_STARTUP_TIMEOUT ((uint32_t)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 ((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)40000) -#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 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 */ - -/* ################## 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 0 -#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ -#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ - -/* Section 2: PHY configuration section */ - -/* DP83848 PHY Address*/ -#define DP83848_PHY_ADDRESS 0x01 -/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ -#define PHY_RESET_DELAY ((uint32_t)0x000000FF) -/* PHY Configuration delay */ -#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) - -#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 "stm32f4xx_hal_rcc.h" -#endif /* HAL_RCC_MODULE_ENABLED */ - -#ifdef HAL_GPIO_MODULE_ENABLED - #include "stm32f4xx_hal_gpio.h" -#endif /* HAL_GPIO_MODULE_ENABLED */ - -#ifdef HAL_DMA_MODULE_ENABLED - #include "stm32f4xx_hal_dma.h" -#endif /* HAL_DMA_MODULE_ENABLED */ - -#ifdef HAL_CORTEX_MODULE_ENABLED - #include "stm32f4xx_hal_cortex.h" -#endif /* HAL_CORTEX_MODULE_ENABLED */ - -#ifdef HAL_ADC_MODULE_ENABLED - #include "stm32f4xx_hal_adc.h" -#endif /* HAL_ADC_MODULE_ENABLED */ - -#ifdef HAL_CAN_MODULE_ENABLED - #include "stm32f4xx_hal_can.h" -#endif /* HAL_CAN_MODULE_ENABLED */ - -#ifdef HAL_CRC_MODULE_ENABLED - #include "stm32f4xx_hal_crc.h" -#endif /* HAL_CRC_MODULE_ENABLED */ - -#ifdef HAL_CRYP_MODULE_ENABLED - #include "stm32f4xx_hal_cryp.h" -#endif /* HAL_CRYP_MODULE_ENABLED */ - -#ifdef HAL_DMA2D_MODULE_ENABLED - #include "stm32f4xx_hal_dma2d.h" -#endif /* HAL_DMA2D_MODULE_ENABLED */ - -#ifdef HAL_DAC_MODULE_ENABLED - #include "stm32f4xx_hal_dac.h" -#endif /* HAL_DAC_MODULE_ENABLED */ - -#ifdef HAL_DCMI_MODULE_ENABLED - #include "stm32f4xx_hal_dcmi.h" -#endif /* HAL_DCMI_MODULE_ENABLED */ - -#ifdef HAL_ETH_MODULE_ENABLED - #include "stm32f4xx_hal_eth.h" -#endif /* HAL_ETH_MODULE_ENABLED */ - -#ifdef HAL_FLASH_MODULE_ENABLED - #include "stm32f4xx_hal_flash.h" -#endif /* HAL_FLASH_MODULE_ENABLED */ - -#ifdef HAL_SRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sram.h" -#endif /* HAL_SRAM_MODULE_ENABLED */ - -#ifdef HAL_NOR_MODULE_ENABLED - #include "stm32f4xx_hal_nor.h" -#endif /* HAL_NOR_MODULE_ENABLED */ - -#ifdef HAL_NAND_MODULE_ENABLED - #include "stm32f4xx_hal_nand.h" -#endif /* HAL_NAND_MODULE_ENABLED */ - -#ifdef HAL_PCCARD_MODULE_ENABLED - #include "stm32f4xx_hal_pccard.h" -#endif /* HAL_PCCARD_MODULE_ENABLED */ - -#ifdef HAL_SDRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sdram.h" -#endif /* HAL_SDRAM_MODULE_ENABLED */ - -#ifdef HAL_HASH_MODULE_ENABLED - #include "stm32f4xx_hal_hash.h" -#endif /* HAL_HASH_MODULE_ENABLED */ - -#ifdef HAL_I2C_MODULE_ENABLED - #include "stm32f4xx_hal_i2c.h" -#endif /* HAL_I2C_MODULE_ENABLED */ - -#ifdef HAL_I2S_MODULE_ENABLED - #include "stm32f4xx_hal_i2s.h" -#endif /* HAL_I2S_MODULE_ENABLED */ - -#ifdef HAL_IWDG_MODULE_ENABLED - #include "stm32f4xx_hal_iwdg.h" -#endif /* HAL_IWDG_MODULE_ENABLED */ - -#ifdef HAL_LTDC_MODULE_ENABLED - #include "stm32f4xx_hal_ltdc.h" -#endif /* HAL_LTDC_MODULE_ENABLED */ - -#ifdef HAL_PWR_MODULE_ENABLED - #include "stm32f4xx_hal_pwr.h" -#endif /* HAL_PWR_MODULE_ENABLED */ - -#ifdef HAL_RNG_MODULE_ENABLED - #include "stm32f4xx_hal_rng.h" -#endif /* HAL_RNG_MODULE_ENABLED */ - -#ifdef HAL_RTC_MODULE_ENABLED - #include "stm32f4xx_hal_rtc.h" -#endif /* HAL_RTC_MODULE_ENABLED */ - -#ifdef HAL_SAI_MODULE_ENABLED - #include "stm32f4xx_hal_sai.h" -#endif /* HAL_SAI_MODULE_ENABLED */ - -#ifdef HAL_SD_MODULE_ENABLED - #include "stm32f4xx_hal_sd.h" -#endif /* HAL_SD_MODULE_ENABLED */ - -#ifdef HAL_SPI_MODULE_ENABLED - #include "stm32f4xx_hal_spi.h" -#endif /* HAL_SPI_MODULE_ENABLED */ - -#ifdef HAL_TIM_MODULE_ENABLED - #include "stm32f4xx_hal_tim.h" -#endif /* HAL_TIM_MODULE_ENABLED */ - -#ifdef HAL_UART_MODULE_ENABLED - #include "stm32f4xx_hal_uart.h" -#endif /* HAL_UART_MODULE_ENABLED */ - -#ifdef HAL_USART_MODULE_ENABLED - #include "stm32f4xx_hal_usart.h" -#endif /* HAL_USART_MODULE_ENABLED */ - -#ifdef HAL_IRDA_MODULE_ENABLED - #include "stm32f4xx_hal_irda.h" -#endif /* HAL_IRDA_MODULE_ENABLED */ - -#ifdef HAL_SMARTCARD_MODULE_ENABLED - #include "stm32f4xx_hal_smartcard.h" -#endif /* HAL_SMARTCARD_MODULE_ENABLED */ - -#ifdef HAL_WWDG_MODULE_ENABLED - #include "stm32f4xx_hal_wwdg.h" -#endif /* HAL_WWDG_MODULE_ENABLED */ - -#ifdef HAL_PCD_MODULE_ENABLED - #include "stm32f4xx_hal_pcd.h" -#endif /* HAL_PCD_MODULE_ENABLED */ - -#ifdef HAL_HCD_MODULE_ENABLED - #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */ - - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H diff --git a/ports/stm32/boards/PYBD_SF2/stm32f7xx_hal_conf.h b/ports/stm32/boards/PYBD_SF2/stm32f7xx_hal_conf.h index c820dafc44..621b05c719 100644 --- a/ports/stm32/boards/PYBD_SF2/stm32f7xx_hal_conf.h +++ b/ports/stm32/boards/PYBD_SF2/stm32f7xx_hal_conf.h @@ -1,74 +1,14 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * +/* This file is part of the MicroPython project, http://micropython.org/ * The MIT License (MIT) - * * Copyright (c) 2019 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_STM32F7XX_HAL_CONF_H #define MICROPY_INCLUDED_STM32F7XX_HAL_CONF_H -// Include various HAL modules for convenience -#include "stm32f7xx_hal_dma.h" -#include "stm32f7xx_hal_adc.h" -#include "stm32f7xx_hal_can.h" -#include "stm32f7xx_hal_cortex.h" -#include "stm32f7xx_hal_dac.h" -#include "stm32f7xx_hal_flash.h" -#include "stm32f7xx_hal_gpio.h" -#include "stm32f7xx_hal_i2c.h" -#include "stm32f7xx_hal_mmc.h" -#include "stm32f7xx_hal_pcd.h" -#include "stm32f7xx_hal_pwr.h" -#include "stm32f7xx_hal_rcc.h" -#include "stm32f7xx_hal_rtc.h" -#include "stm32f7xx_hal_sd.h" -#include "stm32f7xx_hal_spi.h" -#include "stm32f7xx_hal_tim.h" -#include "stm32f7xx_hal_uart.h" - -// Enable various HAL modules -#define HAL_MODULE_ENABLED -#define HAL_ADC_MODULE_ENABLED -#define HAL_CAN_MODULE_ENABLED -#define HAL_CORTEX_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_MMC_MODULE_ENABLED -#define HAL_PCD_MODULE_ENABLED -#define HAL_PWR_MODULE_ENABLED -#define HAL_RCC_MODULE_ENABLED -#define HAL_RTC_MODULE_ENABLED -#define HAL_SD_MODULE_ENABLED -#define HAL_SPI_MODULE_ENABLED -#define HAL_TIM_MODULE_ENABLED -#define HAL_UART_MODULE_ENABLED +#include "boards/stm32f7xx_hal_conf_base.h" // Oscillator values in Hz -#define HSI_VALUE (16000000) -#define HSE_VALUE ((uint32_t)25000000) -#define LSI_VALUE (32000) +#define HSE_VALUE (25000000) #define LSE_VALUE (32768) #define EXTERNAL_CLOCK_VALUE (12288000) @@ -76,13 +16,4 @@ #define HSE_STARTUP_TIMEOUT (5000) #define LSE_STARTUP_TIMEOUT (5000) -// SysTick has the highest priority -#define TICK_INT_PRIORITY (0x00) - -// No RTOS is used -#define USE_RTOS 0 - -// HAL parameter assertions are disabled -#define assert_param(expr) ((void)0) - #endif // MICROPY_INCLUDED_STM32F7XX_HAL_CONF_H diff --git a/ports/stm32/boards/PYBLITEV10/stm32f4xx_hal_conf.h b/ports/stm32/boards/PYBLITEV10/stm32f4xx_hal_conf.h index 4e96f785ad..9719157e55 100644 --- a/ports/stm32/boards/PYBLITEV10/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/PYBLITEV10/stm32f4xx_hal_conf.h @@ -1,409 +1,19 @@ -/** - ****************************************************************************** - * @file stm32f4xx_hal_conf.h - * @author MCD Application Team - * @version V1.1.0 - * @date 19-June-2014 - * @brief HAL configuration file. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F4xx_HAL_CONF_H -#define __STM32F4xx_HAL_CONF_H +#include "boards/stm32f4xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (12000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) -/* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */ -#define HAL_PWR_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_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 */ - - -/* ########################## 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)12000000) /*!< Value of the External oscillator in Hz */ -#endif /* HSE_VALUE */ - -#if !defined (HSE_STARTUP_TIMEOUT) - #define HSE_STARTUP_TIMEOUT ((uint32_t)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 ((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)40000) -#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 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 */ - -/* ################## 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 0 -#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ -#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ - -/* Section 2: PHY configuration section */ - -/* DP83848 PHY Address*/ -#define DP83848_PHY_ADDRESS 0x01 -/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ -#define PHY_RESET_DELAY ((uint32_t)0x000000FF) -/* PHY Configuration delay */ -#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) - -#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 "stm32f4xx_hal_rcc.h" -#endif /* HAL_RCC_MODULE_ENABLED */ - -#ifdef HAL_GPIO_MODULE_ENABLED - #include "stm32f4xx_hal_gpio.h" -#endif /* HAL_GPIO_MODULE_ENABLED */ - -#ifdef HAL_DMA_MODULE_ENABLED - #include "stm32f4xx_hal_dma.h" -#endif /* HAL_DMA_MODULE_ENABLED */ - -#ifdef HAL_CORTEX_MODULE_ENABLED - #include "stm32f4xx_hal_cortex.h" -#endif /* HAL_CORTEX_MODULE_ENABLED */ - -#ifdef HAL_ADC_MODULE_ENABLED - #include "stm32f4xx_hal_adc.h" -#endif /* HAL_ADC_MODULE_ENABLED */ - -#ifdef HAL_CAN_MODULE_ENABLED - #include "stm32f4xx_hal_can.h" -#endif /* HAL_CAN_MODULE_ENABLED */ - -#ifdef HAL_CRC_MODULE_ENABLED - #include "stm32f4xx_hal_crc.h" -#endif /* HAL_CRC_MODULE_ENABLED */ - -#ifdef HAL_CRYP_MODULE_ENABLED - #include "stm32f4xx_hal_cryp.h" -#endif /* HAL_CRYP_MODULE_ENABLED */ - -#ifdef HAL_DMA2D_MODULE_ENABLED - #include "stm32f4xx_hal_dma2d.h" -#endif /* HAL_DMA2D_MODULE_ENABLED */ - -#ifdef HAL_DAC_MODULE_ENABLED - #include "stm32f4xx_hal_dac.h" -#endif /* HAL_DAC_MODULE_ENABLED */ - -#ifdef HAL_DCMI_MODULE_ENABLED - #include "stm32f4xx_hal_dcmi.h" -#endif /* HAL_DCMI_MODULE_ENABLED */ - -#ifdef HAL_ETH_MODULE_ENABLED - #include "stm32f4xx_hal_eth.h" -#endif /* HAL_ETH_MODULE_ENABLED */ - -#ifdef HAL_FLASH_MODULE_ENABLED - #include "stm32f4xx_hal_flash.h" -#endif /* HAL_FLASH_MODULE_ENABLED */ - -#ifdef HAL_SRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sram.h" -#endif /* HAL_SRAM_MODULE_ENABLED */ - -#ifdef HAL_NOR_MODULE_ENABLED - #include "stm32f4xx_hal_nor.h" -#endif /* HAL_NOR_MODULE_ENABLED */ - -#ifdef HAL_NAND_MODULE_ENABLED - #include "stm32f4xx_hal_nand.h" -#endif /* HAL_NAND_MODULE_ENABLED */ - -#ifdef HAL_PCCARD_MODULE_ENABLED - #include "stm32f4xx_hal_pccard.h" -#endif /* HAL_PCCARD_MODULE_ENABLED */ - -#ifdef HAL_SDRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sdram.h" -#endif /* HAL_SDRAM_MODULE_ENABLED */ - -#ifdef HAL_HASH_MODULE_ENABLED - #include "stm32f4xx_hal_hash.h" -#endif /* HAL_HASH_MODULE_ENABLED */ - -#ifdef HAL_I2C_MODULE_ENABLED - #include "stm32f4xx_hal_i2c.h" -#endif /* HAL_I2C_MODULE_ENABLED */ - -#ifdef HAL_I2S_MODULE_ENABLED - #include "stm32f4xx_hal_i2s.h" -#endif /* HAL_I2S_MODULE_ENABLED */ - -#ifdef HAL_IWDG_MODULE_ENABLED - #include "stm32f4xx_hal_iwdg.h" -#endif /* HAL_IWDG_MODULE_ENABLED */ - -#ifdef HAL_LTDC_MODULE_ENABLED - #include "stm32f4xx_hal_ltdc.h" -#endif /* HAL_LTDC_MODULE_ENABLED */ - -#ifdef HAL_PWR_MODULE_ENABLED - #include "stm32f4xx_hal_pwr.h" -#endif /* HAL_PWR_MODULE_ENABLED */ - -#ifdef HAL_RNG_MODULE_ENABLED - #include "stm32f4xx_hal_rng.h" -#endif /* HAL_RNG_MODULE_ENABLED */ - -#ifdef HAL_RTC_MODULE_ENABLED - #include "stm32f4xx_hal_rtc.h" -#endif /* HAL_RTC_MODULE_ENABLED */ - -#ifdef HAL_SAI_MODULE_ENABLED - #include "stm32f4xx_hal_sai.h" -#endif /* HAL_SAI_MODULE_ENABLED */ - -#ifdef HAL_SD_MODULE_ENABLED - #include "stm32f4xx_hal_sd.h" -#endif /* HAL_SD_MODULE_ENABLED */ - -#ifdef HAL_SPI_MODULE_ENABLED - #include "stm32f4xx_hal_spi.h" -#endif /* HAL_SPI_MODULE_ENABLED */ - -#ifdef HAL_TIM_MODULE_ENABLED - #include "stm32f4xx_hal_tim.h" -#endif /* HAL_TIM_MODULE_ENABLED */ - -#ifdef HAL_UART_MODULE_ENABLED - #include "stm32f4xx_hal_uart.h" -#endif /* HAL_UART_MODULE_ENABLED */ - -#ifdef HAL_USART_MODULE_ENABLED - #include "stm32f4xx_hal_usart.h" -#endif /* HAL_USART_MODULE_ENABLED */ - -#ifdef HAL_IRDA_MODULE_ENABLED - #include "stm32f4xx_hal_irda.h" -#endif /* HAL_IRDA_MODULE_ENABLED */ - -#ifdef HAL_SMARTCARD_MODULE_ENABLED - #include "stm32f4xx_hal_smartcard.h" -#endif /* HAL_SMARTCARD_MODULE_ENABLED */ - -#ifdef HAL_WWDG_MODULE_ENABLED - #include "stm32f4xx_hal_wwdg.h" -#endif /* HAL_WWDG_MODULE_ENABLED */ - -#ifdef HAL_PCD_MODULE_ENABLED - #include "stm32f4xx_hal_pcd.h" -#endif /* HAL_PCD_MODULE_ENABLED */ - -#ifdef HAL_HCD_MODULE_ENABLED - #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */ - - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H diff --git a/ports/stm32/boards/PYBV10/stm32f4xx_hal_conf.h b/ports/stm32/boards/PYBV10/stm32f4xx_hal_conf.h index 4f18ac81e3..de19251e08 100644 --- a/ports/stm32/boards/PYBV10/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/PYBV10/stm32f4xx_hal_conf.h @@ -1,409 +1,19 @@ -/** - ****************************************************************************** - * @file stm32f4xx_hal_conf.h - * @author MCD Application Team - * @version V1.1.0 - * @date 19-June-2014 - * @brief HAL configuration file. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F4xx_HAL_CONF_H -#define __STM32F4xx_HAL_CONF_H +#include "boards/stm32f4xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) -/* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */ -#define HAL_PWR_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_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 */ - - -/* ########################## 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)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 ((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)40000) -#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 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 */ - -/* ################## 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 0 -#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ -#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ - -/* Section 2: PHY configuration section */ - -/* DP83848 PHY Address*/ -#define DP83848_PHY_ADDRESS 0x01 -/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ -#define PHY_RESET_DELAY ((uint32_t)0x000000FF) -/* PHY Configuration delay */ -#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) - -#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 "stm32f4xx_hal_rcc.h" -#endif /* HAL_RCC_MODULE_ENABLED */ - -#ifdef HAL_GPIO_MODULE_ENABLED - #include "stm32f4xx_hal_gpio.h" -#endif /* HAL_GPIO_MODULE_ENABLED */ - -#ifdef HAL_DMA_MODULE_ENABLED - #include "stm32f4xx_hal_dma.h" -#endif /* HAL_DMA_MODULE_ENABLED */ - -#ifdef HAL_CORTEX_MODULE_ENABLED - #include "stm32f4xx_hal_cortex.h" -#endif /* HAL_CORTEX_MODULE_ENABLED */ - -#ifdef HAL_ADC_MODULE_ENABLED - #include "stm32f4xx_hal_adc.h" -#endif /* HAL_ADC_MODULE_ENABLED */ - -#ifdef HAL_CAN_MODULE_ENABLED - #include "stm32f4xx_hal_can.h" -#endif /* HAL_CAN_MODULE_ENABLED */ - -#ifdef HAL_CRC_MODULE_ENABLED - #include "stm32f4xx_hal_crc.h" -#endif /* HAL_CRC_MODULE_ENABLED */ - -#ifdef HAL_CRYP_MODULE_ENABLED - #include "stm32f4xx_hal_cryp.h" -#endif /* HAL_CRYP_MODULE_ENABLED */ - -#ifdef HAL_DMA2D_MODULE_ENABLED - #include "stm32f4xx_hal_dma2d.h" -#endif /* HAL_DMA2D_MODULE_ENABLED */ - -#ifdef HAL_DAC_MODULE_ENABLED - #include "stm32f4xx_hal_dac.h" -#endif /* HAL_DAC_MODULE_ENABLED */ - -#ifdef HAL_DCMI_MODULE_ENABLED - #include "stm32f4xx_hal_dcmi.h" -#endif /* HAL_DCMI_MODULE_ENABLED */ - -#ifdef HAL_ETH_MODULE_ENABLED - #include "stm32f4xx_hal_eth.h" -#endif /* HAL_ETH_MODULE_ENABLED */ - -#ifdef HAL_FLASH_MODULE_ENABLED - #include "stm32f4xx_hal_flash.h" -#endif /* HAL_FLASH_MODULE_ENABLED */ - -#ifdef HAL_SRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sram.h" -#endif /* HAL_SRAM_MODULE_ENABLED */ - -#ifdef HAL_NOR_MODULE_ENABLED - #include "stm32f4xx_hal_nor.h" -#endif /* HAL_NOR_MODULE_ENABLED */ - -#ifdef HAL_NAND_MODULE_ENABLED - #include "stm32f4xx_hal_nand.h" -#endif /* HAL_NAND_MODULE_ENABLED */ - -#ifdef HAL_PCCARD_MODULE_ENABLED - #include "stm32f4xx_hal_pccard.h" -#endif /* HAL_PCCARD_MODULE_ENABLED */ - -#ifdef HAL_SDRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sdram.h" -#endif /* HAL_SDRAM_MODULE_ENABLED */ - -#ifdef HAL_HASH_MODULE_ENABLED - #include "stm32f4xx_hal_hash.h" -#endif /* HAL_HASH_MODULE_ENABLED */ - -#ifdef HAL_I2C_MODULE_ENABLED - #include "stm32f4xx_hal_i2c.h" -#endif /* HAL_I2C_MODULE_ENABLED */ - -#ifdef HAL_I2S_MODULE_ENABLED - #include "stm32f4xx_hal_i2s.h" -#endif /* HAL_I2S_MODULE_ENABLED */ - -#ifdef HAL_IWDG_MODULE_ENABLED - #include "stm32f4xx_hal_iwdg.h" -#endif /* HAL_IWDG_MODULE_ENABLED */ - -#ifdef HAL_LTDC_MODULE_ENABLED - #include "stm32f4xx_hal_ltdc.h" -#endif /* HAL_LTDC_MODULE_ENABLED */ - -#ifdef HAL_PWR_MODULE_ENABLED - #include "stm32f4xx_hal_pwr.h" -#endif /* HAL_PWR_MODULE_ENABLED */ - -#ifdef HAL_RNG_MODULE_ENABLED - #include "stm32f4xx_hal_rng.h" -#endif /* HAL_RNG_MODULE_ENABLED */ - -#ifdef HAL_RTC_MODULE_ENABLED - #include "stm32f4xx_hal_rtc.h" -#endif /* HAL_RTC_MODULE_ENABLED */ - -#ifdef HAL_SAI_MODULE_ENABLED - #include "stm32f4xx_hal_sai.h" -#endif /* HAL_SAI_MODULE_ENABLED */ - -#ifdef HAL_SD_MODULE_ENABLED - #include "stm32f4xx_hal_sd.h" -#endif /* HAL_SD_MODULE_ENABLED */ - -#ifdef HAL_SPI_MODULE_ENABLED - #include "stm32f4xx_hal_spi.h" -#endif /* HAL_SPI_MODULE_ENABLED */ - -#ifdef HAL_TIM_MODULE_ENABLED - #include "stm32f4xx_hal_tim.h" -#endif /* HAL_TIM_MODULE_ENABLED */ - -#ifdef HAL_UART_MODULE_ENABLED - #include "stm32f4xx_hal_uart.h" -#endif /* HAL_UART_MODULE_ENABLED */ - -#ifdef HAL_USART_MODULE_ENABLED - #include "stm32f4xx_hal_usart.h" -#endif /* HAL_USART_MODULE_ENABLED */ - -#ifdef HAL_IRDA_MODULE_ENABLED - #include "stm32f4xx_hal_irda.h" -#endif /* HAL_IRDA_MODULE_ENABLED */ - -#ifdef HAL_SMARTCARD_MODULE_ENABLED - #include "stm32f4xx_hal_smartcard.h" -#endif /* HAL_SMARTCARD_MODULE_ENABLED */ - -#ifdef HAL_WWDG_MODULE_ENABLED - #include "stm32f4xx_hal_wwdg.h" -#endif /* HAL_WWDG_MODULE_ENABLED */ - -#ifdef HAL_PCD_MODULE_ENABLED - #include "stm32f4xx_hal_pcd.h" -#endif /* HAL_PCD_MODULE_ENABLED */ - -#ifdef HAL_HCD_MODULE_ENABLED - #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */ - - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H diff --git a/ports/stm32/boards/PYBV11/stm32f4xx_hal_conf.h b/ports/stm32/boards/PYBV11/stm32f4xx_hal_conf.h index 24cc9228b8..9719157e55 100644 --- a/ports/stm32/boards/PYBV11/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/PYBV11/stm32f4xx_hal_conf.h @@ -1,409 +1,19 @@ -/** - ****************************************************************************** - * @file stm32f4xx_hal_conf.h - * @author MCD Application Team - * @version V1.1.0 - * @date 19-June-2014 - * @brief HAL configuration file. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F4xx_HAL_CONF_H -#define __STM32F4xx_HAL_CONF_H +#include "boards/stm32f4xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (12000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) -/* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */ -#define HAL_PWR_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_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 */ - - -/* ########################## 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)12000000) /*!< Value of the External oscillator in Hz */ -#endif /* HSE_VALUE */ - -#if !defined (HSE_STARTUP_TIMEOUT) - #define HSE_STARTUP_TIMEOUT ((uint32_t)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 ((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)40000) -#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 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 */ - -/* ################## 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 0 -#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ -#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ - -/* Section 2: PHY configuration section */ - -/* DP83848 PHY Address*/ -#define DP83848_PHY_ADDRESS 0x01 -/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ -#define PHY_RESET_DELAY ((uint32_t)0x000000FF) -/* PHY Configuration delay */ -#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) - -#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 "stm32f4xx_hal_rcc.h" -#endif /* HAL_RCC_MODULE_ENABLED */ - -#ifdef HAL_GPIO_MODULE_ENABLED - #include "stm32f4xx_hal_gpio.h" -#endif /* HAL_GPIO_MODULE_ENABLED */ - -#ifdef HAL_DMA_MODULE_ENABLED - #include "stm32f4xx_hal_dma.h" -#endif /* HAL_DMA_MODULE_ENABLED */ - -#ifdef HAL_CORTEX_MODULE_ENABLED - #include "stm32f4xx_hal_cortex.h" -#endif /* HAL_CORTEX_MODULE_ENABLED */ - -#ifdef HAL_ADC_MODULE_ENABLED - #include "stm32f4xx_hal_adc.h" -#endif /* HAL_ADC_MODULE_ENABLED */ - -#ifdef HAL_CAN_MODULE_ENABLED - #include "stm32f4xx_hal_can.h" -#endif /* HAL_CAN_MODULE_ENABLED */ - -#ifdef HAL_CRC_MODULE_ENABLED - #include "stm32f4xx_hal_crc.h" -#endif /* HAL_CRC_MODULE_ENABLED */ - -#ifdef HAL_CRYP_MODULE_ENABLED - #include "stm32f4xx_hal_cryp.h" -#endif /* HAL_CRYP_MODULE_ENABLED */ - -#ifdef HAL_DMA2D_MODULE_ENABLED - #include "stm32f4xx_hal_dma2d.h" -#endif /* HAL_DMA2D_MODULE_ENABLED */ - -#ifdef HAL_DAC_MODULE_ENABLED - #include "stm32f4xx_hal_dac.h" -#endif /* HAL_DAC_MODULE_ENABLED */ - -#ifdef HAL_DCMI_MODULE_ENABLED - #include "stm32f4xx_hal_dcmi.h" -#endif /* HAL_DCMI_MODULE_ENABLED */ - -#ifdef HAL_ETH_MODULE_ENABLED - #include "stm32f4xx_hal_eth.h" -#endif /* HAL_ETH_MODULE_ENABLED */ - -#ifdef HAL_FLASH_MODULE_ENABLED - #include "stm32f4xx_hal_flash.h" -#endif /* HAL_FLASH_MODULE_ENABLED */ - -#ifdef HAL_SRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sram.h" -#endif /* HAL_SRAM_MODULE_ENABLED */ - -#ifdef HAL_NOR_MODULE_ENABLED - #include "stm32f4xx_hal_nor.h" -#endif /* HAL_NOR_MODULE_ENABLED */ - -#ifdef HAL_NAND_MODULE_ENABLED - #include "stm32f4xx_hal_nand.h" -#endif /* HAL_NAND_MODULE_ENABLED */ - -#ifdef HAL_PCCARD_MODULE_ENABLED - #include "stm32f4xx_hal_pccard.h" -#endif /* HAL_PCCARD_MODULE_ENABLED */ - -#ifdef HAL_SDRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sdram.h" -#endif /* HAL_SDRAM_MODULE_ENABLED */ - -#ifdef HAL_HASH_MODULE_ENABLED - #include "stm32f4xx_hal_hash.h" -#endif /* HAL_HASH_MODULE_ENABLED */ - -#ifdef HAL_I2C_MODULE_ENABLED - #include "stm32f4xx_hal_i2c.h" -#endif /* HAL_I2C_MODULE_ENABLED */ - -#ifdef HAL_I2S_MODULE_ENABLED - #include "stm32f4xx_hal_i2s.h" -#endif /* HAL_I2S_MODULE_ENABLED */ - -#ifdef HAL_IWDG_MODULE_ENABLED - #include "stm32f4xx_hal_iwdg.h" -#endif /* HAL_IWDG_MODULE_ENABLED */ - -#ifdef HAL_LTDC_MODULE_ENABLED - #include "stm32f4xx_hal_ltdc.h" -#endif /* HAL_LTDC_MODULE_ENABLED */ - -#ifdef HAL_PWR_MODULE_ENABLED - #include "stm32f4xx_hal_pwr.h" -#endif /* HAL_PWR_MODULE_ENABLED */ - -#ifdef HAL_RNG_MODULE_ENABLED - #include "stm32f4xx_hal_rng.h" -#endif /* HAL_RNG_MODULE_ENABLED */ - -#ifdef HAL_RTC_MODULE_ENABLED - #include "stm32f4xx_hal_rtc.h" -#endif /* HAL_RTC_MODULE_ENABLED */ - -#ifdef HAL_SAI_MODULE_ENABLED - #include "stm32f4xx_hal_sai.h" -#endif /* HAL_SAI_MODULE_ENABLED */ - -#ifdef HAL_SD_MODULE_ENABLED - #include "stm32f4xx_hal_sd.h" -#endif /* HAL_SD_MODULE_ENABLED */ - -#ifdef HAL_SPI_MODULE_ENABLED - #include "stm32f4xx_hal_spi.h" -#endif /* HAL_SPI_MODULE_ENABLED */ - -#ifdef HAL_TIM_MODULE_ENABLED - #include "stm32f4xx_hal_tim.h" -#endif /* HAL_TIM_MODULE_ENABLED */ - -#ifdef HAL_UART_MODULE_ENABLED - #include "stm32f4xx_hal_uart.h" -#endif /* HAL_UART_MODULE_ENABLED */ - -#ifdef HAL_USART_MODULE_ENABLED - #include "stm32f4xx_hal_usart.h" -#endif /* HAL_USART_MODULE_ENABLED */ - -#ifdef HAL_IRDA_MODULE_ENABLED - #include "stm32f4xx_hal_irda.h" -#endif /* HAL_IRDA_MODULE_ENABLED */ - -#ifdef HAL_SMARTCARD_MODULE_ENABLED - #include "stm32f4xx_hal_smartcard.h" -#endif /* HAL_SMARTCARD_MODULE_ENABLED */ - -#ifdef HAL_WWDG_MODULE_ENABLED - #include "stm32f4xx_hal_wwdg.h" -#endif /* HAL_WWDG_MODULE_ENABLED */ - -#ifdef HAL_PCD_MODULE_ENABLED - #include "stm32f4xx_hal_pcd.h" -#endif /* HAL_PCD_MODULE_ENABLED */ - -#ifdef HAL_HCD_MODULE_ENABLED - #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */ - - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H diff --git a/ports/stm32/boards/PYBV3/stm32f4xx_hal_conf.h b/ports/stm32/boards/PYBV3/stm32f4xx_hal_conf.h index daf9b63cec..de19251e08 100644 --- a/ports/stm32/boards/PYBV3/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/PYBV3/stm32f4xx_hal_conf.h @@ -1,409 +1,19 @@ -/** - ****************************************************************************** - * @file stm32f4xx_hal_conf.h - * @author MCD Application Team - * @version V1.1.0 - * @date 19-June-2014 - * @brief HAL configuration file. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F4xx_HAL_CONF_H -#define __STM32F4xx_HAL_CONF_H +#include "boards/stm32f4xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) -/* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */ -#define HAL_PWR_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_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 */ - - -/* ########################## 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)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 ((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)40000) -#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 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 */ - -/* ################## 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 0 -#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ -#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ - -/* Section 2: PHY configuration section */ - -/* DP83848 PHY Address*/ -#define DP83848_PHY_ADDRESS 0x01 -/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ -#define PHY_RESET_DELAY ((uint32_t)0x000000FF) -/* PHY Configuration delay */ -#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) - -#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 "stm32f4xx_hal_rcc.h" -#endif /* HAL_RCC_MODULE_ENABLED */ - -#ifdef HAL_GPIO_MODULE_ENABLED - #include "stm32f4xx_hal_gpio.h" -#endif /* HAL_GPIO_MODULE_ENABLED */ - -#ifdef HAL_DMA_MODULE_ENABLED - #include "stm32f4xx_hal_dma.h" -#endif /* HAL_DMA_MODULE_ENABLED */ - -#ifdef HAL_CORTEX_MODULE_ENABLED - #include "stm32f4xx_hal_cortex.h" -#endif /* HAL_CORTEX_MODULE_ENABLED */ - -#ifdef HAL_ADC_MODULE_ENABLED - #include "stm32f4xx_hal_adc.h" -#endif /* HAL_ADC_MODULE_ENABLED */ - -#ifdef HAL_CAN_MODULE_ENABLED - #include "stm32f4xx_hal_can.h" -#endif /* HAL_CAN_MODULE_ENABLED */ - -#ifdef HAL_CRC_MODULE_ENABLED - #include "stm32f4xx_hal_crc.h" -#endif /* HAL_CRC_MODULE_ENABLED */ - -#ifdef HAL_CRYP_MODULE_ENABLED - #include "stm32f4xx_hal_cryp.h" -#endif /* HAL_CRYP_MODULE_ENABLED */ - -#ifdef HAL_DMA2D_MODULE_ENABLED - #include "stm32f4xx_hal_dma2d.h" -#endif /* HAL_DMA2D_MODULE_ENABLED */ - -#ifdef HAL_DAC_MODULE_ENABLED - #include "stm32f4xx_hal_dac.h" -#endif /* HAL_DAC_MODULE_ENABLED */ - -#ifdef HAL_DCMI_MODULE_ENABLED - #include "stm32f4xx_hal_dcmi.h" -#endif /* HAL_DCMI_MODULE_ENABLED */ - -#ifdef HAL_ETH_MODULE_ENABLED - #include "stm32f4xx_hal_eth.h" -#endif /* HAL_ETH_MODULE_ENABLED */ - -#ifdef HAL_FLASH_MODULE_ENABLED - #include "stm32f4xx_hal_flash.h" -#endif /* HAL_FLASH_MODULE_ENABLED */ - -#ifdef HAL_SRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sram.h" -#endif /* HAL_SRAM_MODULE_ENABLED */ - -#ifdef HAL_NOR_MODULE_ENABLED - #include "stm32f4xx_hal_nor.h" -#endif /* HAL_NOR_MODULE_ENABLED */ - -#ifdef HAL_NAND_MODULE_ENABLED - #include "stm32f4xx_hal_nand.h" -#endif /* HAL_NAND_MODULE_ENABLED */ - -#ifdef HAL_PCCARD_MODULE_ENABLED - #include "stm32f4xx_hal_pccard.h" -#endif /* HAL_PCCARD_MODULE_ENABLED */ - -#ifdef HAL_SDRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sdram.h" -#endif /* HAL_SDRAM_MODULE_ENABLED */ - -#ifdef HAL_HASH_MODULE_ENABLED - #include "stm32f4xx_hal_hash.h" -#endif /* HAL_HASH_MODULE_ENABLED */ - -#ifdef HAL_I2C_MODULE_ENABLED - #include "stm32f4xx_hal_i2c.h" -#endif /* HAL_I2C_MODULE_ENABLED */ - -#ifdef HAL_I2S_MODULE_ENABLED - #include "stm32f4xx_hal_i2s.h" -#endif /* HAL_I2S_MODULE_ENABLED */ - -#ifdef HAL_IWDG_MODULE_ENABLED - #include "stm32f4xx_hal_iwdg.h" -#endif /* HAL_IWDG_MODULE_ENABLED */ - -#ifdef HAL_LTDC_MODULE_ENABLED - #include "stm32f4xx_hal_ltdc.h" -#endif /* HAL_LTDC_MODULE_ENABLED */ - -#ifdef HAL_PWR_MODULE_ENABLED - #include "stm32f4xx_hal_pwr.h" -#endif /* HAL_PWR_MODULE_ENABLED */ - -#ifdef HAL_RNG_MODULE_ENABLED - #include "stm32f4xx_hal_rng.h" -#endif /* HAL_RNG_MODULE_ENABLED */ - -#ifdef HAL_RTC_MODULE_ENABLED - #include "stm32f4xx_hal_rtc.h" -#endif /* HAL_RTC_MODULE_ENABLED */ - -#ifdef HAL_SAI_MODULE_ENABLED - #include "stm32f4xx_hal_sai.h" -#endif /* HAL_SAI_MODULE_ENABLED */ - -#ifdef HAL_SD_MODULE_ENABLED - #include "stm32f4xx_hal_sd.h" -#endif /* HAL_SD_MODULE_ENABLED */ - -#ifdef HAL_SPI_MODULE_ENABLED - #include "stm32f4xx_hal_spi.h" -#endif /* HAL_SPI_MODULE_ENABLED */ - -#ifdef HAL_TIM_MODULE_ENABLED - #include "stm32f4xx_hal_tim.h" -#endif /* HAL_TIM_MODULE_ENABLED */ - -#ifdef HAL_UART_MODULE_ENABLED - #include "stm32f4xx_hal_uart.h" -#endif /* HAL_UART_MODULE_ENABLED */ - -#ifdef HAL_USART_MODULE_ENABLED - #include "stm32f4xx_hal_usart.h" -#endif /* HAL_USART_MODULE_ENABLED */ - -#ifdef HAL_IRDA_MODULE_ENABLED - #include "stm32f4xx_hal_irda.h" -#endif /* HAL_IRDA_MODULE_ENABLED */ - -#ifdef HAL_SMARTCARD_MODULE_ENABLED - #include "stm32f4xx_hal_smartcard.h" -#endif /* HAL_SMARTCARD_MODULE_ENABLED */ - -#ifdef HAL_WWDG_MODULE_ENABLED - #include "stm32f4xx_hal_wwdg.h" -#endif /* HAL_WWDG_MODULE_ENABLED */ - -#ifdef HAL_PCD_MODULE_ENABLED - #include "stm32f4xx_hal_pcd.h" -#endif /* HAL_PCD_MODULE_ENABLED */ - -#ifdef HAL_HCD_MODULE_ENABLED - #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */ - - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H diff --git a/ports/stm32/boards/PYBV4/stm32f4xx_hal_conf.h b/ports/stm32/boards/PYBV4/stm32f4xx_hal_conf.h index daf9b63cec..de19251e08 100644 --- a/ports/stm32/boards/PYBV4/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/PYBV4/stm32f4xx_hal_conf.h @@ -1,409 +1,19 @@ -/** - ****************************************************************************** - * @file stm32f4xx_hal_conf.h - * @author MCD Application Team - * @version V1.1.0 - * @date 19-June-2014 - * @brief HAL configuration file. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F4xx_HAL_CONF_H -#define __STM32F4xx_HAL_CONF_H +#include "boards/stm32f4xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) -/* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */ -#define HAL_PWR_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_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 */ - - -/* ########################## 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)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 ((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)40000) -#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 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 */ - -/* ################## 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 0 -#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ -#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ - -/* Section 2: PHY configuration section */ - -/* DP83848 PHY Address*/ -#define DP83848_PHY_ADDRESS 0x01 -/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ -#define PHY_RESET_DELAY ((uint32_t)0x000000FF) -/* PHY Configuration delay */ -#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) - -#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 "stm32f4xx_hal_rcc.h" -#endif /* HAL_RCC_MODULE_ENABLED */ - -#ifdef HAL_GPIO_MODULE_ENABLED - #include "stm32f4xx_hal_gpio.h" -#endif /* HAL_GPIO_MODULE_ENABLED */ - -#ifdef HAL_DMA_MODULE_ENABLED - #include "stm32f4xx_hal_dma.h" -#endif /* HAL_DMA_MODULE_ENABLED */ - -#ifdef HAL_CORTEX_MODULE_ENABLED - #include "stm32f4xx_hal_cortex.h" -#endif /* HAL_CORTEX_MODULE_ENABLED */ - -#ifdef HAL_ADC_MODULE_ENABLED - #include "stm32f4xx_hal_adc.h" -#endif /* HAL_ADC_MODULE_ENABLED */ - -#ifdef HAL_CAN_MODULE_ENABLED - #include "stm32f4xx_hal_can.h" -#endif /* HAL_CAN_MODULE_ENABLED */ - -#ifdef HAL_CRC_MODULE_ENABLED - #include "stm32f4xx_hal_crc.h" -#endif /* HAL_CRC_MODULE_ENABLED */ - -#ifdef HAL_CRYP_MODULE_ENABLED - #include "stm32f4xx_hal_cryp.h" -#endif /* HAL_CRYP_MODULE_ENABLED */ - -#ifdef HAL_DMA2D_MODULE_ENABLED - #include "stm32f4xx_hal_dma2d.h" -#endif /* HAL_DMA2D_MODULE_ENABLED */ - -#ifdef HAL_DAC_MODULE_ENABLED - #include "stm32f4xx_hal_dac.h" -#endif /* HAL_DAC_MODULE_ENABLED */ - -#ifdef HAL_DCMI_MODULE_ENABLED - #include "stm32f4xx_hal_dcmi.h" -#endif /* HAL_DCMI_MODULE_ENABLED */ - -#ifdef HAL_ETH_MODULE_ENABLED - #include "stm32f4xx_hal_eth.h" -#endif /* HAL_ETH_MODULE_ENABLED */ - -#ifdef HAL_FLASH_MODULE_ENABLED - #include "stm32f4xx_hal_flash.h" -#endif /* HAL_FLASH_MODULE_ENABLED */ - -#ifdef HAL_SRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sram.h" -#endif /* HAL_SRAM_MODULE_ENABLED */ - -#ifdef HAL_NOR_MODULE_ENABLED - #include "stm32f4xx_hal_nor.h" -#endif /* HAL_NOR_MODULE_ENABLED */ - -#ifdef HAL_NAND_MODULE_ENABLED - #include "stm32f4xx_hal_nand.h" -#endif /* HAL_NAND_MODULE_ENABLED */ - -#ifdef HAL_PCCARD_MODULE_ENABLED - #include "stm32f4xx_hal_pccard.h" -#endif /* HAL_PCCARD_MODULE_ENABLED */ - -#ifdef HAL_SDRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sdram.h" -#endif /* HAL_SDRAM_MODULE_ENABLED */ - -#ifdef HAL_HASH_MODULE_ENABLED - #include "stm32f4xx_hal_hash.h" -#endif /* HAL_HASH_MODULE_ENABLED */ - -#ifdef HAL_I2C_MODULE_ENABLED - #include "stm32f4xx_hal_i2c.h" -#endif /* HAL_I2C_MODULE_ENABLED */ - -#ifdef HAL_I2S_MODULE_ENABLED - #include "stm32f4xx_hal_i2s.h" -#endif /* HAL_I2S_MODULE_ENABLED */ - -#ifdef HAL_IWDG_MODULE_ENABLED - #include "stm32f4xx_hal_iwdg.h" -#endif /* HAL_IWDG_MODULE_ENABLED */ - -#ifdef HAL_LTDC_MODULE_ENABLED - #include "stm32f4xx_hal_ltdc.h" -#endif /* HAL_LTDC_MODULE_ENABLED */ - -#ifdef HAL_PWR_MODULE_ENABLED - #include "stm32f4xx_hal_pwr.h" -#endif /* HAL_PWR_MODULE_ENABLED */ - -#ifdef HAL_RNG_MODULE_ENABLED - #include "stm32f4xx_hal_rng.h" -#endif /* HAL_RNG_MODULE_ENABLED */ - -#ifdef HAL_RTC_MODULE_ENABLED - #include "stm32f4xx_hal_rtc.h" -#endif /* HAL_RTC_MODULE_ENABLED */ - -#ifdef HAL_SAI_MODULE_ENABLED - #include "stm32f4xx_hal_sai.h" -#endif /* HAL_SAI_MODULE_ENABLED */ - -#ifdef HAL_SD_MODULE_ENABLED - #include "stm32f4xx_hal_sd.h" -#endif /* HAL_SD_MODULE_ENABLED */ - -#ifdef HAL_SPI_MODULE_ENABLED - #include "stm32f4xx_hal_spi.h" -#endif /* HAL_SPI_MODULE_ENABLED */ - -#ifdef HAL_TIM_MODULE_ENABLED - #include "stm32f4xx_hal_tim.h" -#endif /* HAL_TIM_MODULE_ENABLED */ - -#ifdef HAL_UART_MODULE_ENABLED - #include "stm32f4xx_hal_uart.h" -#endif /* HAL_UART_MODULE_ENABLED */ - -#ifdef HAL_USART_MODULE_ENABLED - #include "stm32f4xx_hal_usart.h" -#endif /* HAL_USART_MODULE_ENABLED */ - -#ifdef HAL_IRDA_MODULE_ENABLED - #include "stm32f4xx_hal_irda.h" -#endif /* HAL_IRDA_MODULE_ENABLED */ - -#ifdef HAL_SMARTCARD_MODULE_ENABLED - #include "stm32f4xx_hal_smartcard.h" -#endif /* HAL_SMARTCARD_MODULE_ENABLED */ - -#ifdef HAL_WWDG_MODULE_ENABLED - #include "stm32f4xx_hal_wwdg.h" -#endif /* HAL_WWDG_MODULE_ENABLED */ - -#ifdef HAL_PCD_MODULE_ENABLED - #include "stm32f4xx_hal_pcd.h" -#endif /* HAL_PCD_MODULE_ENABLED */ - -#ifdef HAL_HCD_MODULE_ENABLED - #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */ - - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H diff --git a/ports/stm32/boards/STM32F411DISC/stm32f4xx_hal_conf.h b/ports/stm32/boards/STM32F411DISC/stm32f4xx_hal_conf.h index 8f0b663811..de19251e08 100644 --- a/ports/stm32/boards/STM32F411DISC/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/STM32F411DISC/stm32f4xx_hal_conf.h @@ -1,409 +1,19 @@ -/** - ****************************************************************************** - * @file stm32f4xx_hal_conf.h - * @author MCD Application Team - * @version V1.1.0 - * @date 19-June-2014 - * @brief HAL configuration file. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F4xx_HAL_CONF_H -#define __STM32F4xx_HAL_CONF_H +#include "boards/stm32f4xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) -/* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */ -#define HAL_PWR_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_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 */ - - -/* ########################## 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)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 ((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)40000) -#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 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 */ - -/* ################## 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 0 -#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ -#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ - -/* Section 2: PHY configuration section */ - -/* DP83848 PHY Address*/ -#define DP83848_PHY_ADDRESS 0x01 -/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ -#define PHY_RESET_DELAY ((uint32_t)0x000000FF) -/* PHY Configuration delay */ -#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) - -#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 "stm32f4xx_hal_rcc.h" -#endif /* HAL_RCC_MODULE_ENABLED */ - -#ifdef HAL_GPIO_MODULE_ENABLED - #include "stm32f4xx_hal_gpio.h" -#endif /* HAL_GPIO_MODULE_ENABLED */ - -#ifdef HAL_DMA_MODULE_ENABLED - #include "stm32f4xx_hal_dma.h" -#endif /* HAL_DMA_MODULE_ENABLED */ - -#ifdef HAL_CORTEX_MODULE_ENABLED - #include "stm32f4xx_hal_cortex.h" -#endif /* HAL_CORTEX_MODULE_ENABLED */ - -#ifdef HAL_ADC_MODULE_ENABLED - #include "stm32f4xx_hal_adc.h" -#endif /* HAL_ADC_MODULE_ENABLED */ - -#ifdef HAL_CAN_MODULE_ENABLED - #include "stm32f4xx_hal_can.h" -#endif /* HAL_CAN_MODULE_ENABLED */ - -#ifdef HAL_CRC_MODULE_ENABLED - #include "stm32f4xx_hal_crc.h" -#endif /* HAL_CRC_MODULE_ENABLED */ - -#ifdef HAL_CRYP_MODULE_ENABLED - #include "stm32f4xx_hal_cryp.h" -#endif /* HAL_CRYP_MODULE_ENABLED */ - -#ifdef HAL_DMA2D_MODULE_ENABLED - #include "stm32f4xx_hal_dma2d.h" -#endif /* HAL_DMA2D_MODULE_ENABLED */ - -#ifdef HAL_DAC_MODULE_ENABLED - #include "stm32f4xx_hal_dac.h" -#endif /* HAL_DAC_MODULE_ENABLED */ - -#ifdef HAL_DCMI_MODULE_ENABLED - #include "stm32f4xx_hal_dcmi.h" -#endif /* HAL_DCMI_MODULE_ENABLED */ - -#ifdef HAL_ETH_MODULE_ENABLED - #include "stm32f4xx_hal_eth.h" -#endif /* HAL_ETH_MODULE_ENABLED */ - -#ifdef HAL_FLASH_MODULE_ENABLED - #include "stm32f4xx_hal_flash.h" -#endif /* HAL_FLASH_MODULE_ENABLED */ - -#ifdef HAL_SRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sram.h" -#endif /* HAL_SRAM_MODULE_ENABLED */ - -#ifdef HAL_NOR_MODULE_ENABLED - #include "stm32f4xx_hal_nor.h" -#endif /* HAL_NOR_MODULE_ENABLED */ - -#ifdef HAL_NAND_MODULE_ENABLED - #include "stm32f4xx_hal_nand.h" -#endif /* HAL_NAND_MODULE_ENABLED */ - -#ifdef HAL_PCCARD_MODULE_ENABLED - #include "stm32f4xx_hal_pccard.h" -#endif /* HAL_PCCARD_MODULE_ENABLED */ - -#ifdef HAL_SDRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sdram.h" -#endif /* HAL_SDRAM_MODULE_ENABLED */ - -#ifdef HAL_HASH_MODULE_ENABLED - #include "stm32f4xx_hal_hash.h" -#endif /* HAL_HASH_MODULE_ENABLED */ - -#ifdef HAL_I2C_MODULE_ENABLED - #include "stm32f4xx_hal_i2c.h" -#endif /* HAL_I2C_MODULE_ENABLED */ - -#ifdef HAL_I2S_MODULE_ENABLED - #include "stm32f4xx_hal_i2s.h" -#endif /* HAL_I2S_MODULE_ENABLED */ - -#ifdef HAL_IWDG_MODULE_ENABLED - #include "stm32f4xx_hal_iwdg.h" -#endif /* HAL_IWDG_MODULE_ENABLED */ - -#ifdef HAL_LTDC_MODULE_ENABLED - #include "stm32f4xx_hal_ltdc.h" -#endif /* HAL_LTDC_MODULE_ENABLED */ - -#ifdef HAL_PWR_MODULE_ENABLED - #include "stm32f4xx_hal_pwr.h" -#endif /* HAL_PWR_MODULE_ENABLED */ - -#ifdef HAL_RNG_MODULE_ENABLED - #include "stm32f4xx_hal_rng.h" -#endif /* HAL_RNG_MODULE_ENABLED */ - -#ifdef HAL_RTC_MODULE_ENABLED - #include "stm32f4xx_hal_rtc.h" -#endif /* HAL_RTC_MODULE_ENABLED */ - -#ifdef HAL_SAI_MODULE_ENABLED - #include "stm32f4xx_hal_sai.h" -#endif /* HAL_SAI_MODULE_ENABLED */ - -#ifdef HAL_SD_MODULE_ENABLED - #include "stm32f4xx_hal_sd.h" -#endif /* HAL_SD_MODULE_ENABLED */ - -#ifdef HAL_SPI_MODULE_ENABLED - #include "stm32f4xx_hal_spi.h" -#endif /* HAL_SPI_MODULE_ENABLED */ - -#ifdef HAL_TIM_MODULE_ENABLED - #include "stm32f4xx_hal_tim.h" -#endif /* HAL_TIM_MODULE_ENABLED */ - -#ifdef HAL_UART_MODULE_ENABLED - #include "stm32f4xx_hal_uart.h" -#endif /* HAL_UART_MODULE_ENABLED */ - -#ifdef HAL_USART_MODULE_ENABLED - #include "stm32f4xx_hal_usart.h" -#endif /* HAL_USART_MODULE_ENABLED */ - -#ifdef HAL_IRDA_MODULE_ENABLED - #include "stm32f4xx_hal_irda.h" -#endif /* HAL_IRDA_MODULE_ENABLED */ - -#ifdef HAL_SMARTCARD_MODULE_ENABLED - #include "stm32f4xx_hal_smartcard.h" -#endif /* HAL_SMARTCARD_MODULE_ENABLED */ - -#ifdef HAL_WWDG_MODULE_ENABLED - #include "stm32f4xx_hal_wwdg.h" -#endif /* HAL_WWDG_MODULE_ENABLED */ - -#ifdef HAL_PCD_MODULE_ENABLED - #include "stm32f4xx_hal_pcd.h" -#endif /* HAL_PCD_MODULE_ENABLED */ - -#ifdef HAL_HCD_MODULE_ENABLED - #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */ - - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H diff --git a/ports/stm32/boards/STM32F429DISC/stm32f4xx_hal_conf.h b/ports/stm32/boards/STM32F429DISC/stm32f4xx_hal_conf.h index ec70793c8b..de19251e08 100644 --- a/ports/stm32/boards/STM32F429DISC/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/STM32F429DISC/stm32f4xx_hal_conf.h @@ -1,409 +1,19 @@ -/** - ****************************************************************************** - * @file stm32f4xx_hal_conf.h - * @author MCD Application Team - * @version V1.1.0 - * @date 19-June-2014 - * @brief HAL configuration file. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F4xx_HAL_CONF_H -#define __STM32F4xx_HAL_CONF_H +#include "boards/stm32f4xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) - /* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */ -#define HAL_PWR_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_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 */ - - -/* ########################## 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)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 ((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)40000) -#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 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 */ - -/* ################## 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 0 -#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ -#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ - -/* Section 2: PHY configuration section */ - -/* DP83848 PHY Address*/ -#define DP83848_PHY_ADDRESS 0x01 -/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ -#define PHY_RESET_DELAY ((uint32_t)0x000000FF) -/* PHY Configuration delay */ -#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) - -#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 "stm32f4xx_hal_rcc.h" -#endif /* HAL_RCC_MODULE_ENABLED */ - -#ifdef HAL_GPIO_MODULE_ENABLED - #include "stm32f4xx_hal_gpio.h" -#endif /* HAL_GPIO_MODULE_ENABLED */ - -#ifdef HAL_DMA_MODULE_ENABLED - #include "stm32f4xx_hal_dma.h" -#endif /* HAL_DMA_MODULE_ENABLED */ - -#ifdef HAL_CORTEX_MODULE_ENABLED - #include "stm32f4xx_hal_cortex.h" -#endif /* HAL_CORTEX_MODULE_ENABLED */ - -#ifdef HAL_ADC_MODULE_ENABLED - #include "stm32f4xx_hal_adc.h" -#endif /* HAL_ADC_MODULE_ENABLED */ - -#ifdef HAL_CAN_MODULE_ENABLED - #include "stm32f4xx_hal_can.h" -#endif /* HAL_CAN_MODULE_ENABLED */ - -#ifdef HAL_CRC_MODULE_ENABLED - #include "stm32f4xx_hal_crc.h" -#endif /* HAL_CRC_MODULE_ENABLED */ - -#ifdef HAL_CRYP_MODULE_ENABLED - #include "stm32f4xx_hal_cryp.h" -#endif /* HAL_CRYP_MODULE_ENABLED */ - -#ifdef HAL_DMA2D_MODULE_ENABLED - #include "stm32f4xx_hal_dma2d.h" -#endif /* HAL_DMA2D_MODULE_ENABLED */ - -#ifdef HAL_DAC_MODULE_ENABLED - #include "stm32f4xx_hal_dac.h" -#endif /* HAL_DAC_MODULE_ENABLED */ - -#ifdef HAL_DCMI_MODULE_ENABLED - #include "stm32f4xx_hal_dcmi.h" -#endif /* HAL_DCMI_MODULE_ENABLED */ - -#ifdef HAL_ETH_MODULE_ENABLED - #include "stm32f4xx_hal_eth.h" -#endif /* HAL_ETH_MODULE_ENABLED */ - -#ifdef HAL_FLASH_MODULE_ENABLED - #include "stm32f4xx_hal_flash.h" -#endif /* HAL_FLASH_MODULE_ENABLED */ - -#ifdef HAL_SRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sram.h" -#endif /* HAL_SRAM_MODULE_ENABLED */ - -#ifdef HAL_NOR_MODULE_ENABLED - #include "stm32f4xx_hal_nor.h" -#endif /* HAL_NOR_MODULE_ENABLED */ - -#ifdef HAL_NAND_MODULE_ENABLED - #include "stm32f4xx_hal_nand.h" -#endif /* HAL_NAND_MODULE_ENABLED */ - -#ifdef HAL_PCCARD_MODULE_ENABLED - #include "stm32f4xx_hal_pccard.h" -#endif /* HAL_PCCARD_MODULE_ENABLED */ - -#ifdef HAL_SDRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sdram.h" -#endif /* HAL_SDRAM_MODULE_ENABLED */ - -#ifdef HAL_HASH_MODULE_ENABLED - #include "stm32f4xx_hal_hash.h" -#endif /* HAL_HASH_MODULE_ENABLED */ - -#ifdef HAL_I2C_MODULE_ENABLED - #include "stm32f4xx_hal_i2c.h" -#endif /* HAL_I2C_MODULE_ENABLED */ - -#ifdef HAL_I2S_MODULE_ENABLED - #include "stm32f4xx_hal_i2s.h" -#endif /* HAL_I2S_MODULE_ENABLED */ - -#ifdef HAL_IWDG_MODULE_ENABLED - #include "stm32f4xx_hal_iwdg.h" -#endif /* HAL_IWDG_MODULE_ENABLED */ - -#ifdef HAL_LTDC_MODULE_ENABLED - #include "stm32f4xx_hal_ltdc.h" -#endif /* HAL_LTDC_MODULE_ENABLED */ - -#ifdef HAL_PWR_MODULE_ENABLED - #include "stm32f4xx_hal_pwr.h" -#endif /* HAL_PWR_MODULE_ENABLED */ - -#ifdef HAL_RNG_MODULE_ENABLED - #include "stm32f4xx_hal_rng.h" -#endif /* HAL_RNG_MODULE_ENABLED */ - -#ifdef HAL_RTC_MODULE_ENABLED - #include "stm32f4xx_hal_rtc.h" -#endif /* HAL_RTC_MODULE_ENABLED */ - -#ifdef HAL_SAI_MODULE_ENABLED - #include "stm32f4xx_hal_sai.h" -#endif /* HAL_SAI_MODULE_ENABLED */ - -#ifdef HAL_SD_MODULE_ENABLED - #include "stm32f4xx_hal_sd.h" -#endif /* HAL_SD_MODULE_ENABLED */ - -#ifdef HAL_SPI_MODULE_ENABLED - #include "stm32f4xx_hal_spi.h" -#endif /* HAL_SPI_MODULE_ENABLED */ - -#ifdef HAL_TIM_MODULE_ENABLED - #include "stm32f4xx_hal_tim.h" -#endif /* HAL_TIM_MODULE_ENABLED */ - -#ifdef HAL_UART_MODULE_ENABLED - #include "stm32f4xx_hal_uart.h" -#endif /* HAL_UART_MODULE_ENABLED */ - -#ifdef HAL_USART_MODULE_ENABLED - #include "stm32f4xx_hal_usart.h" -#endif /* HAL_USART_MODULE_ENABLED */ - -#ifdef HAL_IRDA_MODULE_ENABLED - #include "stm32f4xx_hal_irda.h" -#endif /* HAL_IRDA_MODULE_ENABLED */ - -#ifdef HAL_SMARTCARD_MODULE_ENABLED - #include "stm32f4xx_hal_smartcard.h" -#endif /* HAL_SMARTCARD_MODULE_ENABLED */ - -#ifdef HAL_WWDG_MODULE_ENABLED - #include "stm32f4xx_hal_wwdg.h" -#endif /* HAL_WWDG_MODULE_ENABLED */ - -#ifdef HAL_PCD_MODULE_ENABLED - #include "stm32f4xx_hal_pcd.h" -#endif /* HAL_PCD_MODULE_ENABLED */ - -#ifdef HAL_HCD_MODULE_ENABLED - #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */ - - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H diff --git a/ports/stm32/boards/STM32F439/stm32f4xx_hal_conf.h b/ports/stm32/boards/STM32F439/stm32f4xx_hal_conf.h index 5b5a8a3e43..de19251e08 100644 --- a/ports/stm32/boards/STM32F439/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/STM32F439/stm32f4xx_hal_conf.h @@ -1,409 +1,19 @@ -/** - ****************************************************************************** - * @file stm32f4xx_hal_conf.h - * @author MCD Application Team - * @version V1.1.0 - * @date 19-June-2014 - * @brief HAL configuration file. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F4xx_HAL_CONF_H -#define __STM32F4xx_HAL_CONF_H +#include "boards/stm32f4xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) - /* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */ -#define HAL_PWR_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_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 */ - - -/* ########################## 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)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 ((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)40000) -#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 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 */ - -/* ################## 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 0 -#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ -#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ - -/* Section 2: PHY configuration section */ - -/* DP83848 PHY Address*/ -#define DP83848_PHY_ADDRESS 0x01 -/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ -#define PHY_RESET_DELAY ((uint32_t)0x000000FF) -/* PHY Configuration delay */ -#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) - -#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 "stm32f4xx_hal_rcc.h" -#endif /* HAL_RCC_MODULE_ENABLED */ - -#ifdef HAL_GPIO_MODULE_ENABLED - #include "stm32f4xx_hal_gpio.h" -#endif /* HAL_GPIO_MODULE_ENABLED */ - -#ifdef HAL_DMA_MODULE_ENABLED - #include "stm32f4xx_hal_dma.h" -#endif /* HAL_DMA_MODULE_ENABLED */ - -#ifdef HAL_CORTEX_MODULE_ENABLED - #include "stm32f4xx_hal_cortex.h" -#endif /* HAL_CORTEX_MODULE_ENABLED */ - -#ifdef HAL_ADC_MODULE_ENABLED - #include "stm32f4xx_hal_adc.h" -#endif /* HAL_ADC_MODULE_ENABLED */ - -#ifdef HAL_CAN_MODULE_ENABLED - #include "stm32f4xx_hal_can.h" -#endif /* HAL_CAN_MODULE_ENABLED */ - -#ifdef HAL_CRC_MODULE_ENABLED - #include "stm32f4xx_hal_crc.h" -#endif /* HAL_CRC_MODULE_ENABLED */ - -#ifdef HAL_CRYP_MODULE_ENABLED - #include "stm32f4xx_hal_cryp.h" -#endif /* HAL_CRYP_MODULE_ENABLED */ - -#ifdef HAL_DMA2D_MODULE_ENABLED - #include "stm32f4xx_hal_dma2d.h" -#endif /* HAL_DMA2D_MODULE_ENABLED */ - -#ifdef HAL_DAC_MODULE_ENABLED - #include "stm32f4xx_hal_dac.h" -#endif /* HAL_DAC_MODULE_ENABLED */ - -#ifdef HAL_DCMI_MODULE_ENABLED - #include "stm32f4xx_hal_dcmi.h" -#endif /* HAL_DCMI_MODULE_ENABLED */ - -#ifdef HAL_ETH_MODULE_ENABLED - #include "stm32f4xx_hal_eth.h" -#endif /* HAL_ETH_MODULE_ENABLED */ - -#ifdef HAL_FLASH_MODULE_ENABLED - #include "stm32f4xx_hal_flash.h" -#endif /* HAL_FLASH_MODULE_ENABLED */ - -#ifdef HAL_SRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sram.h" -#endif /* HAL_SRAM_MODULE_ENABLED */ - -#ifdef HAL_NOR_MODULE_ENABLED - #include "stm32f4xx_hal_nor.h" -#endif /* HAL_NOR_MODULE_ENABLED */ - -#ifdef HAL_NAND_MODULE_ENABLED - #include "stm32f4xx_hal_nand.h" -#endif /* HAL_NAND_MODULE_ENABLED */ - -#ifdef HAL_PCCARD_MODULE_ENABLED - #include "stm32f4xx_hal_pccard.h" -#endif /* HAL_PCCARD_MODULE_ENABLED */ - -#ifdef HAL_SDRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sdram.h" -#endif /* HAL_SDRAM_MODULE_ENABLED */ - -#ifdef HAL_HASH_MODULE_ENABLED - #include "stm32f4xx_hal_hash.h" -#endif /* HAL_HASH_MODULE_ENABLED */ - -#ifdef HAL_I2C_MODULE_ENABLED - #include "stm32f4xx_hal_i2c.h" -#endif /* HAL_I2C_MODULE_ENABLED */ - -#ifdef HAL_I2S_MODULE_ENABLED - #include "stm32f4xx_hal_i2s.h" -#endif /* HAL_I2S_MODULE_ENABLED */ - -#ifdef HAL_IWDG_MODULE_ENABLED - #include "stm32f4xx_hal_iwdg.h" -#endif /* HAL_IWDG_MODULE_ENABLED */ - -#ifdef HAL_LTDC_MODULE_ENABLED - #include "stm32f4xx_hal_ltdc.h" -#endif /* HAL_LTDC_MODULE_ENABLED */ - -#ifdef HAL_PWR_MODULE_ENABLED - #include "stm32f4xx_hal_pwr.h" -#endif /* HAL_PWR_MODULE_ENABLED */ - -#ifdef HAL_RNG_MODULE_ENABLED - #include "stm32f4xx_hal_rng.h" -#endif /* HAL_RNG_MODULE_ENABLED */ - -#ifdef HAL_RTC_MODULE_ENABLED - #include "stm32f4xx_hal_rtc.h" -#endif /* HAL_RTC_MODULE_ENABLED */ - -#ifdef HAL_SAI_MODULE_ENABLED - #include "stm32f4xx_hal_sai.h" -#endif /* HAL_SAI_MODULE_ENABLED */ - -#ifdef HAL_SD_MODULE_ENABLED - #include "stm32f4xx_hal_sd.h" -#endif /* HAL_SD_MODULE_ENABLED */ - -#ifdef HAL_SPI_MODULE_ENABLED - #include "stm32f4xx_hal_spi.h" -#endif /* HAL_SPI_MODULE_ENABLED */ - -#ifdef HAL_TIM_MODULE_ENABLED - #include "stm32f4xx_hal_tim.h" -#endif /* HAL_TIM_MODULE_ENABLED */ - -#ifdef HAL_UART_MODULE_ENABLED - #include "stm32f4xx_hal_uart.h" -#endif /* HAL_UART_MODULE_ENABLED */ - -#ifdef HAL_USART_MODULE_ENABLED - #include "stm32f4xx_hal_usart.h" -#endif /* HAL_USART_MODULE_ENABLED */ - -#ifdef HAL_IRDA_MODULE_ENABLED - #include "stm32f4xx_hal_irda.h" -#endif /* HAL_IRDA_MODULE_ENABLED */ - -#ifdef HAL_SMARTCARD_MODULE_ENABLED - #include "stm32f4xx_hal_smartcard.h" -#endif /* HAL_SMARTCARD_MODULE_ENABLED */ - -#ifdef HAL_WWDG_MODULE_ENABLED - #include "stm32f4xx_hal_wwdg.h" -#endif /* HAL_WWDG_MODULE_ENABLED */ - -#ifdef HAL_PCD_MODULE_ENABLED - #include "stm32f4xx_hal_pcd.h" -#endif /* HAL_PCD_MODULE_ENABLED */ - -#ifdef HAL_HCD_MODULE_ENABLED - #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */ - - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H diff --git a/ports/stm32/boards/STM32F4DISC/stm32f4xx_hal_conf.h b/ports/stm32/boards/STM32F4DISC/stm32f4xx_hal_conf.h index daf9b63cec..de19251e08 100644 --- a/ports/stm32/boards/STM32F4DISC/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/STM32F4DISC/stm32f4xx_hal_conf.h @@ -1,409 +1,19 @@ -/** - ****************************************************************************** - * @file stm32f4xx_hal_conf.h - * @author MCD Application Team - * @version V1.1.0 - * @date 19-June-2014 - * @brief HAL configuration file. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F4xx_HAL_CONF_H -#define __STM32F4xx_HAL_CONF_H +#include "boards/stm32f4xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) -/* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */ -#define HAL_PWR_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_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 */ - - -/* ########################## 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)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 ((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)40000) -#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 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 */ - -/* ################## 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 0 -#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ -#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ - -/* Section 2: PHY configuration section */ - -/* DP83848 PHY Address*/ -#define DP83848_PHY_ADDRESS 0x01 -/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ -#define PHY_RESET_DELAY ((uint32_t)0x000000FF) -/* PHY Configuration delay */ -#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) - -#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 "stm32f4xx_hal_rcc.h" -#endif /* HAL_RCC_MODULE_ENABLED */ - -#ifdef HAL_GPIO_MODULE_ENABLED - #include "stm32f4xx_hal_gpio.h" -#endif /* HAL_GPIO_MODULE_ENABLED */ - -#ifdef HAL_DMA_MODULE_ENABLED - #include "stm32f4xx_hal_dma.h" -#endif /* HAL_DMA_MODULE_ENABLED */ - -#ifdef HAL_CORTEX_MODULE_ENABLED - #include "stm32f4xx_hal_cortex.h" -#endif /* HAL_CORTEX_MODULE_ENABLED */ - -#ifdef HAL_ADC_MODULE_ENABLED - #include "stm32f4xx_hal_adc.h" -#endif /* HAL_ADC_MODULE_ENABLED */ - -#ifdef HAL_CAN_MODULE_ENABLED - #include "stm32f4xx_hal_can.h" -#endif /* HAL_CAN_MODULE_ENABLED */ - -#ifdef HAL_CRC_MODULE_ENABLED - #include "stm32f4xx_hal_crc.h" -#endif /* HAL_CRC_MODULE_ENABLED */ - -#ifdef HAL_CRYP_MODULE_ENABLED - #include "stm32f4xx_hal_cryp.h" -#endif /* HAL_CRYP_MODULE_ENABLED */ - -#ifdef HAL_DMA2D_MODULE_ENABLED - #include "stm32f4xx_hal_dma2d.h" -#endif /* HAL_DMA2D_MODULE_ENABLED */ - -#ifdef HAL_DAC_MODULE_ENABLED - #include "stm32f4xx_hal_dac.h" -#endif /* HAL_DAC_MODULE_ENABLED */ - -#ifdef HAL_DCMI_MODULE_ENABLED - #include "stm32f4xx_hal_dcmi.h" -#endif /* HAL_DCMI_MODULE_ENABLED */ - -#ifdef HAL_ETH_MODULE_ENABLED - #include "stm32f4xx_hal_eth.h" -#endif /* HAL_ETH_MODULE_ENABLED */ - -#ifdef HAL_FLASH_MODULE_ENABLED - #include "stm32f4xx_hal_flash.h" -#endif /* HAL_FLASH_MODULE_ENABLED */ - -#ifdef HAL_SRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sram.h" -#endif /* HAL_SRAM_MODULE_ENABLED */ - -#ifdef HAL_NOR_MODULE_ENABLED - #include "stm32f4xx_hal_nor.h" -#endif /* HAL_NOR_MODULE_ENABLED */ - -#ifdef HAL_NAND_MODULE_ENABLED - #include "stm32f4xx_hal_nand.h" -#endif /* HAL_NAND_MODULE_ENABLED */ - -#ifdef HAL_PCCARD_MODULE_ENABLED - #include "stm32f4xx_hal_pccard.h" -#endif /* HAL_PCCARD_MODULE_ENABLED */ - -#ifdef HAL_SDRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sdram.h" -#endif /* HAL_SDRAM_MODULE_ENABLED */ - -#ifdef HAL_HASH_MODULE_ENABLED - #include "stm32f4xx_hal_hash.h" -#endif /* HAL_HASH_MODULE_ENABLED */ - -#ifdef HAL_I2C_MODULE_ENABLED - #include "stm32f4xx_hal_i2c.h" -#endif /* HAL_I2C_MODULE_ENABLED */ - -#ifdef HAL_I2S_MODULE_ENABLED - #include "stm32f4xx_hal_i2s.h" -#endif /* HAL_I2S_MODULE_ENABLED */ - -#ifdef HAL_IWDG_MODULE_ENABLED - #include "stm32f4xx_hal_iwdg.h" -#endif /* HAL_IWDG_MODULE_ENABLED */ - -#ifdef HAL_LTDC_MODULE_ENABLED - #include "stm32f4xx_hal_ltdc.h" -#endif /* HAL_LTDC_MODULE_ENABLED */ - -#ifdef HAL_PWR_MODULE_ENABLED - #include "stm32f4xx_hal_pwr.h" -#endif /* HAL_PWR_MODULE_ENABLED */ - -#ifdef HAL_RNG_MODULE_ENABLED - #include "stm32f4xx_hal_rng.h" -#endif /* HAL_RNG_MODULE_ENABLED */ - -#ifdef HAL_RTC_MODULE_ENABLED - #include "stm32f4xx_hal_rtc.h" -#endif /* HAL_RTC_MODULE_ENABLED */ - -#ifdef HAL_SAI_MODULE_ENABLED - #include "stm32f4xx_hal_sai.h" -#endif /* HAL_SAI_MODULE_ENABLED */ - -#ifdef HAL_SD_MODULE_ENABLED - #include "stm32f4xx_hal_sd.h" -#endif /* HAL_SD_MODULE_ENABLED */ - -#ifdef HAL_SPI_MODULE_ENABLED - #include "stm32f4xx_hal_spi.h" -#endif /* HAL_SPI_MODULE_ENABLED */ - -#ifdef HAL_TIM_MODULE_ENABLED - #include "stm32f4xx_hal_tim.h" -#endif /* HAL_TIM_MODULE_ENABLED */ - -#ifdef HAL_UART_MODULE_ENABLED - #include "stm32f4xx_hal_uart.h" -#endif /* HAL_UART_MODULE_ENABLED */ - -#ifdef HAL_USART_MODULE_ENABLED - #include "stm32f4xx_hal_usart.h" -#endif /* HAL_USART_MODULE_ENABLED */ - -#ifdef HAL_IRDA_MODULE_ENABLED - #include "stm32f4xx_hal_irda.h" -#endif /* HAL_IRDA_MODULE_ENABLED */ - -#ifdef HAL_SMARTCARD_MODULE_ENABLED - #include "stm32f4xx_hal_smartcard.h" -#endif /* HAL_SMARTCARD_MODULE_ENABLED */ - -#ifdef HAL_WWDG_MODULE_ENABLED - #include "stm32f4xx_hal_wwdg.h" -#endif /* HAL_WWDG_MODULE_ENABLED */ - -#ifdef HAL_PCD_MODULE_ENABLED - #include "stm32f4xx_hal_pcd.h" -#endif /* HAL_PCD_MODULE_ENABLED */ - -#ifdef HAL_HCD_MODULE_ENABLED - #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */ - - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H diff --git a/ports/stm32/boards/STM32F769DISC/stm32f7xx_hal_conf.h b/ports/stm32/boards/STM32F769DISC/stm32f7xx_hal_conf.h index 1593390672..621b05c719 100644 --- a/ports/stm32/boards/STM32F769DISC/stm32f7xx_hal_conf.h +++ b/ports/stm32/boards/STM32F769DISC/stm32f7xx_hal_conf.h @@ -1,427 +1,19 @@ -/** - ****************************************************************************** - * @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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32F7XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F7XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F7xx_HAL_CONF_H -#define __STM32F7xx_HAL_CONF_H +#include "boards/stm32f7xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (25000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (5000) +#define LSE_STARTUP_TIMEOUT (5000) -/* ########################## 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)25000000) /*!< 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****/ +#endif // MICROPY_INCLUDED_STM32F7XX_HAL_CONF_H diff --git a/ports/stm32/boards/STM32F7DISC/stm32f7xx_hal_conf.h b/ports/stm32/boards/STM32F7DISC/stm32f7xx_hal_conf.h index 1593390672..621b05c719 100644 --- a/ports/stm32/boards/STM32F7DISC/stm32f7xx_hal_conf.h +++ b/ports/stm32/boards/STM32F7DISC/stm32f7xx_hal_conf.h @@ -1,427 +1,19 @@ -/** - ****************************************************************************** - * @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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32F7XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F7XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F7xx_HAL_CONF_H -#define __STM32F7xx_HAL_CONF_H +#include "boards/stm32f7xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (25000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (5000) +#define LSE_STARTUP_TIMEOUT (5000) -/* ########################## 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)25000000) /*!< 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****/ +#endif // MICROPY_INCLUDED_STM32F7XX_HAL_CONF_H diff --git a/ports/stm32/boards/STM32L476DISC/stm32l4xx_hal_conf.h b/ports/stm32/boards/STM32L476DISC/stm32l4xx_hal_conf.h index 6bfb28118a..fd380ab735 100644 --- a/ports/stm32/boards/STM32L476DISC/stm32l4xx_hal_conf.h +++ b/ports/stm32/boards/STM32L476DISC/stm32l4xx_hal_conf.h @@ -1,372 +1,20 @@ -/** - ****************************************************************************** - * @file stm32l4xx_hal_conf.h - * @author MCD Application Team - * @version V1.2.0 - * @date 25-November-2015 - * @brief HAL configuration template file. - * This file should be copied to the application folder and renamed - * to stm32l4xx_hal_conf.h. - ****************************************************************************** - * @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. - * - ****************************************************************************** - */ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32L4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32L4XX_HAL_CONF_H -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32L4xx_HAL_CONF_H -#define __STM32L4xx_HAL_CONF_H +#include "boards/stm32l4xx_hal_conf_base.h" -#ifdef __cplusplus - extern "C" { -#endif +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define LSE_VALUE (32768) +#define EXTERNAL_SAI1_CLOCK_VALUE (48000) +#define EXTERNAL_SAI2_CLOCK_VALUE (48000) -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) -/* ########################## 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_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_DFSDM_MODULE_ENABLED */ -#define HAL_DMA_MODULE_ENABLED -/* #define HAL_FIREWALL_MODULE_ENABLED */ -#define HAL_FLASH_MODULE_ENABLED -/* #define HAL_HCD_MODULE_ENABLED */ -/* #define HAL_NAND_MODULE_ENABLED */ -/* #define HAL_NOR_MODULE_ENABLED */ -/* #define HAL_SRAM_MODULE_ENABLED */ -#define HAL_GPIO_MODULE_ENABLED -#define HAL_I2C_MODULE_ENABLED -/* #define HAL_IRDA_MODULE_ENABLED */ -/* #define HAL_IWDG_MODULE_ENABLED */ -/* #define HAL_LCD_MODULE_ENABLED */ -/* #define HAL_LPTIM_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_SMARTCARD_MODULE_ENABLED */ -/* #define HAL_SMBUS_MODULE_ENABLED */ -#define HAL_SPI_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 */ - - -/* ########################## 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 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 */ - -/* Includes ------------------------------------------------------------------*/ -/** - * @brief Include module's header file - */ - -#ifdef HAL_RCC_MODULE_ENABLED - #include "stm32l4xx_hal_rcc.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_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_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_OPAMP_MODULE_ENABLED -#include "stm32l4xx_hal_opamp.h" -#endif /* HAL_OPAMP_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 */ - -/* 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 /* __STM32L4xx_HAL_CONF_H */ - - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +#endif // MICROPY_INCLUDED_STM32L4XX_HAL_CONF_H diff --git a/ports/stm32/boards/STM32L496GDISC/stm32l4xx_hal_conf.h b/ports/stm32/boards/STM32L496GDISC/stm32l4xx_hal_conf.h index 884db5ef1a..fd380ab735 100644 --- a/ports/stm32/boards/STM32L496GDISC/stm32l4xx_hal_conf.h +++ b/ports/stm32/boards/STM32L496GDISC/stm32l4xx_hal_conf.h @@ -1,421 +1,20 @@ -/** - ****************************************************************************** - * @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 +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George */ +#ifndef MICROPY_INCLUDED_STM32L4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32L4XX_HAL_CONF_H -#define USE_SPI_CRC 0 +#include "boards/stm32l4xx_hal_conf_base.h" -/* Includes ------------------------------------------------------------------*/ -/** - * @brief Include module's header file - */ +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define LSE_VALUE (32768) +#define EXTERNAL_SAI1_CLOCK_VALUE (48000) +#define EXTERNAL_SAI2_CLOCK_VALUE (48000) -#ifdef HAL_RCC_MODULE_ENABLED - #include "stm32l4xx_hal_rcc.h" - #include "stm32l4xx_hal_rcc_ex.h" -#endif /* HAL_RCC_MODULE_ENABLED */ +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) -#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****/ +#endif // MICROPY_INCLUDED_STM32L4XX_HAL_CONF_H From c60e0a09f0f9db84aee8fdf1de5f416a87cdf868 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 24 Jun 2019 12:05:17 +1000 Subject: [PATCH 0454/1788] travis: Selectively fetch git submodules only when needed. This saves time when building on Travis CI: unconditionally fetching all submodules takes about 40 seconds, but not all are needed for any given port, so only fetch as necessary. --- .travis.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.travis.yml b/.travis.yml index 4ec5069050..e16c36058c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,8 @@ cache: env: global: - MAKEOPTS="-j4" +git: + submodules: false # define the successive stages stages: @@ -30,6 +32,7 @@ jobs: - sudo apt-get install libnewlib-arm-none-eabi - arm-none-eabi-gcc --version script: + - git submodule update --init lib/lwip lib/mbedtls lib/stm32lib - make ${MAKEOPTS} -C mpy-cross - make ${MAKEOPTS} -C ports/stm32 - make ${MAKEOPTS} -C ports/stm32 BOARD=PYBV11 MICROPY_PY_WIZNET5K=5200 MICROPY_PY_CC3K=1 @@ -60,6 +63,7 @@ jobs: - gcc --version - python3 --version script: + - git submodule update --init lib/axtls lib/berkeley-db-1.xx lib/libffi - make ${MAKEOPTS} -C mpy-cross - make ${MAKEOPTS} -C ports/unix deplibs - make ${MAKEOPTS} -C ports/unix coverage @@ -80,6 +84,7 @@ jobs: - stage: test env: NAME="unix port build and tests" script: + - git submodule update --init lib/axtls lib/berkeley-db-1.xx lib/libffi - make ${MAKEOPTS} -C mpy-cross - make ${MAKEOPTS} -C ports/unix deplibs - make ${MAKEOPTS} -C ports/unix @@ -91,6 +96,7 @@ jobs: install: - sudo apt-get install gcc-multilib libffi-dev:i386 script: + - git submodule update --init lib/axtls lib/berkeley-db-1.xx lib/libffi - make ${MAKEOPTS} -C mpy-cross - make ${MAKEOPTS} -C ports/unix deplibs - make ${MAKEOPTS} -C ports/unix nanbox @@ -100,6 +106,7 @@ jobs: - stage: test env: NAME="unix stackless port build and tests" script: + - git submodule update --init lib/axtls lib/berkeley-db-1.xx lib/libffi - make ${MAKEOPTS} -C mpy-cross - make ${MAKEOPTS} -C ports/unix deplibs - make ${MAKEOPTS} -C ports/unix CFLAGS_EXTRA="-DMICROPY_STACKLESS=1 -DMICROPY_STACKLESS_STRICT=1" @@ -122,6 +129,7 @@ jobs: - sudo apt-get install libnewlib-arm-none-eabi - arm-none-eabi-gcc --version script: + - git submodule update --init lib/nrfx - make ${MAKEOPTS} -C ports/nrf # bare-arm and minimal ports From cc12f750b4020f65ef00b5de2ca3c5ab2627b9d6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 24 Jun 2019 12:52:34 +1000 Subject: [PATCH 0455/1788] travis: Build esp8266 firmware as part of Travis CI. Toolchain installation and build takes about 1 minute. --- .travis.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.travis.yml b/.travis.yml index e16c36058c..ff6b24b958 100644 --- a/.travis.yml +++ b/.travis.yml @@ -121,6 +121,18 @@ jobs: - make ${MAKEOPTS} -C mpy-cross - make ${MAKEOPTS} -C ports/windows CROSS_COMPILE=i686-w64-mingw32- + # esp8266 port + - stage: test + env: NAME="esp8266 port build" + install: + - wget https://github.com/jepler/esp-open-sdk/releases/download/2018-06-10/xtensa-lx106-elf-standalone.tar.gz + - zcat xtensa-lx106-elf-standalone.tar.gz | tar x + - export PATH=$(pwd)/xtensa-lx106-elf/bin:$PATH + script: + - git submodule update --init lib/axtls lib/berkeley-db-1.xx + - make ${MAKEOPTS} -C mpy-cross + - make ${MAKEOPTS} -C ports/esp8266 + # nrf port - stage: test env: NAME="nrf port build" From e06dcad5d385369762f62aeccaff0ae3c6626acf Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 25 Jun 2019 11:18:36 +1000 Subject: [PATCH 0456/1788] travis: Build esp32 firmware as part of Travis CI. Toolchain installation and build takes about 3 minutes. --- .travis.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.travis.yml b/.travis.yml index ff6b24b958..b71cabcc80 100644 --- a/.travis.yml +++ b/.travis.yml @@ -121,6 +121,23 @@ jobs: - make ${MAKEOPTS} -C mpy-cross - make ${MAKEOPTS} -C ports/windows CROSS_COMPILE=i686-w64-mingw32- + # esp32 port + - stage: test + env: NAME="esp32 port build" + install: + - sudo apt-get install python3-pip + - sudo pip3 install pyparsing + - wget https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz + - zcat xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz | tar x + - export PATH=$(pwd)/xtensa-esp32-elf/bin:$PATH + - git clone https://github.com/espressif/esp-idf.git + - git -C esp-idf checkout $(grep "ESPIDF_SUPHASH :=" ports/esp32/Makefile | cut -d " " -f 3) + - git -C esp-idf submodule update --init components/json/cJSON components/esp32/lib components/esptool_py/esptool components/expat/expat components/lwip/lwip components/mbedtls/mbedtls components/micro-ecc/micro-ecc components/nghttp/nghttp2 + script: + - git submodule update --init lib/berkeley-db-1.xx + - make ${MAKEOPTS} -C mpy-cross + - make ${MAKEOPTS} -C ports/esp32 ESPIDF=$(pwd)/esp-idf + # esp8266 port - stage: test env: NAME="esp8266 port build" From 862cc45a9c3241101c5d89e18063724793f73e43 Mon Sep 17 00:00:00 2001 From: "Paul m. p. P" Date: Mon, 24 Jun 2019 14:11:56 +0200 Subject: [PATCH 0457/1788] py/mkrules.mk: Use $(CPP) not $(CC) -E for preprocessor rule. --- py/mkrules.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/mkrules.mk b/py/mkrules.mk index 5c214090cc..7690c54092 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -53,7 +53,7 @@ vpath %.c . $(TOP) $(USER_C_MODULES) $(BUILD)/%.pp: %.c $(ECHO) "PreProcess $<" - $(Q)$(CC) $(CFLAGS) -E -Wp,-C,-dD,-dI -o $@ $< + $(Q)$(CPP) $(CFLAGS) -Wp,-C,-dD,-dI -o $@ $< # The following rule uses | to create an order only prerequisite. Order only # prerequisites only get built if they don't exist. They don't cause timestamp From 2f262d5f9a8a77ec611548162100d6df8e9703c0 Mon Sep 17 00:00:00 2001 From: Josh Lloyd Date: Tue, 25 Jun 2019 15:32:25 +1200 Subject: [PATCH 0458/1788] esp32/Makefile: Include all driver/*.c source files in the build. Fixes #4869. --- ports/esp32/Makefile | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 67e2f52415..ec6d29695b 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -256,21 +256,7 @@ $(HEADER_BUILD)/qstrdefs.generated.h: $(SDKCONFIG_H) ################################################################################ # 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 \ - sdmmc_host.o \ - sdmmc_transaction.o \ - sdspi_crc.o \ - sdspi_host.o \ - sdspi_transaction.o \ - spi_master.o \ - spi_common.o \ - rtc_module.o \ - ) +ESPIDF_DRIVER_O = $(subst .c,.o,$(wildcard $(ESPCOMP)/driver/*.c)) ESPIDF_EFUSE_O = $(addprefix $(ESPCOMP)/efuse/,\ esp32/esp_efuse_table.o \ From d21d57864426d56fa13104e82568fe94dcf079ab Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 25 Jun 2019 15:43:54 +1000 Subject: [PATCH 0459/1788] stm32/usb: Fix regression with auto USB PID value giving PID=0xffff. Commit 9e68eec8eac1188eab0bc059560b877928783978 introduced a regression where the PID of the USB device would be 0xffff if the default value was used. This commit fixes that by using a signed int type. --- 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 2807d512be..69ba26c438 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -302,7 +302,7 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * // note: PID=-1 means select PID based on mode // note: we support CDC as a synonym for VCP for backward compatibility uint16_t vid = args[ARG_vid].u_int; - uint16_t pid = args[ARG_pid].u_int; + mp_int_t pid = args[ARG_pid].u_int; uint8_t mode; if (strcmp(mode_str, "CDC+MSC") == 0 || strcmp(mode_str, "VCP+MSC") == 0) { if (pid == -1) { From d889def06b8cce97c8ef31c986e051f28cc6fbd7 Mon Sep 17 00:00:00 2001 From: Glenn Ruben Bakke Date: Fri, 3 May 2019 20:21:45 +0200 Subject: [PATCH 0460/1788] nrf/led: Adjust how board LEDs are defined. Change static LED functions to lowercase names, and trim down source code lines for variants of MICROPY_HW_LED_COUNT. Also rename configuration for MICROPY_HW_LEDx_LEVEL to MICROPY_HW_LEDx_PULLUP to align with global PULLUP configuration. --- .../boards/blueio_tag_evim/mpconfigboard.h | 5 +- ports/nrf/modules/board/led.c | 116 ++++++------------ 2 files changed, 36 insertions(+), 85 deletions(-) diff --git a/ports/nrf/boards/blueio_tag_evim/mpconfigboard.h b/ports/nrf/boards/blueio_tag_evim/mpconfigboard.h index afc3f00a81..2f1a106101 100644 --- a/ports/nrf/boards/blueio_tag_evim/mpconfigboard.h +++ b/ports/nrf/boards/blueio_tag_evim/mpconfigboard.h @@ -46,13 +46,10 @@ #define MICROPY_HW_LED_PULLUP (1) #define MICROPY_HW_LED1 (30) // LED1 -#define MICROPY_HW_LED1_LEVEL (0) +#define MICROPY_HW_LED1_PULLUP (0) #define MICROPY_HW_LED2 (20) // LED2 -#define MICROPY_HW_LED2_LEVEL (1) #define MICROPY_HW_LED3 (19) // LED3 -#define MICROPY_HW_LED3_LEVEL (1) #define MICROPY_HW_LED4 (18) // LED4 -#define MICROPY_HW_LED4_LEVEL (1) // UART config #define MICROPY_HW_UART1_RX (8) diff --git a/ports/nrf/modules/board/led.c b/ports/nrf/modules/board/led.c index 8b1eb560ea..5d7b54ecba 100644 --- a/ports/nrf/modules/board/led.c +++ b/ports/nrf/modules/board/led.c @@ -38,24 +38,24 @@ typedef struct _board_led_obj_t { mp_uint_t led_id; mp_uint_t hw_pin; uint8_t hw_pin_port; - bool act_level; + bool pullup; } board_led_obj_t; -static inline void LED_OFF(board_led_obj_t * const led_obj) { - if (led_obj->act_level) { - nrf_gpio_pin_clear(led_obj->hw_pin); +static inline void led_off(board_led_obj_t * const led_obj) { + if (led_obj->pullup) { + nrf_gpio_pin_set(led_obj->hw_pin); } else { - nrf_gpio_pin_set(led_obj->hw_pin); + nrf_gpio_pin_clear(led_obj->hw_pin); } } -static inline void LED_ON(board_led_obj_t * const led_obj) { - if (led_obj->act_level) { - nrf_gpio_pin_set(led_obj->hw_pin); +static inline void led_on(board_led_obj_t * const led_obj) { + if (led_obj->pullup) { + nrf_gpio_pin_clear(led_obj->hw_pin); } else { - nrf_gpio_pin_clear(led_obj->hw_pin); + nrf_gpio_pin_set(led_obj->hw_pin); } } @@ -64,89 +64,43 @@ static const board_led_obj_t board_led_obj[] = { #if MICROPY_HW_LED_TRICOLOR - {{&board_led_type}, BOARD_LED_RED, MICROPY_HW_LED_RED, 0, MICROPY_HW_LED_PULLUP != 0 ? 0 : 1}, - {{&board_led_type}, BOARD_LED_GREEN, MICROPY_HW_LED_GREEN,0, MICROPY_HW_LED_PULLUP != 0 ? 0 : 1}, - {{&board_led_type}, BOARD_LED_BLUE, MICROPY_HW_LED_BLUE,0, MICROPY_HW_LED_PULLUP != 0 ? 0 : 1}, - -#elif (MICROPY_HW_LED_COUNT == 1) - + {{&board_led_type}, BOARD_LED_RED, MICROPY_HW_LED_RED, 0, MICROPY_HW_LED_PULLUP}, + {{&board_led_type}, BOARD_LED_GREEN, MICROPY_HW_LED_GREEN,0, MICROPY_HW_LED_PULLUP}, + {{&board_led_type}, BOARD_LED_BLUE, MICROPY_HW_LED_BLUE,0, MICROPY_HW_LED_PULLUP}, +#endif +#if (MICROPY_HW_LED_COUNT >= 1) {{&board_led_type}, BOARD_LED1, MICROPY_HW_LED1, 0, - #ifdef MICROPY_HW_LED1_LEVEL - MICROPY_HW_LED1_LEVEL, + #ifdef MICROPY_HW_LED1_PULLUP + MICROPY_HW_LED1_PULLUP #else - MICROPY_HW_LED_PULLUP != 0 ? 0 : 1 - #endif - }, - -#elif (MICROPY_HW_LED_COUNT == 2) - - {{&board_led_type}, BOARD_LED1, MICROPY_HW_LED1, 0, - #ifdef MICROPY_HW_LED1_LEVEL - MICROPY_HW_LED1_LEVEL, - #else - MICROPY_HW_LED_PULLUP != 0 ? 0 : 1 + MICROPY_HW_LED_PULLUP #endif }, +#endif +#if (MICROPY_HW_LED_COUNT >= 2) {{&board_led_type}, BOARD_LED2, MICROPY_HW_LED2, 0, - #ifdef MICROPY_HW_LED2_LEVEL - MICROPY_HW_LED2_LEVEL, + #ifdef MICROPY_HW_LED2_PULLUP + MICROPY_HW_LED2_PULLUP #else - MICROPY_HW_LED_PULLUP != 0 ? 0 : 1 - #endif - }, - -#elif (MICROPY_HW_LED_COUNT == 3) - - {{&board_led_type}, BOARD_LED1, MICROPY_HW_LED1, 0, - #ifdef MICROPY_HW_LED1_LEVEL - MICROPY_HW_LED1_LEVEL, - #else - MICROPY_HW_LED_PULLUP != 0 ? 0 : 1 - #endif - }, - {{&board_led_type}, BOARD_LED2, MICROPY_HW_LED2, 0, - #ifdef MICROPY_HW_LED2_LEVEL - MICROPY_HW_LED2_LEVEL, - #else - MICROPY_HW_LED_PULLUP != 0 ? 0 : 1 + MICROPY_HW_LED_PULLUP #endif }, +#endif +#if (MICROPY_HW_LED_COUNT >= 3) {{&board_led_type}, BOARD_LED3, MICROPY_HW_LED3, 0, - #ifdef MICROPY_HW_LED3_LEVEL - MICROPY_HW_LED3_LEVEL, + #ifdef MICROPY_HW_LED3_PULLUP + MICROPY_HW_LED3_PULLUP #else - MICROPY_HW_LED_PULLUP != 0 ? 0 : 1 - #endif - }, - -#else - - {{&board_led_type}, BOARD_LED1, MICROPY_HW_LED1, 0, - #ifdef MICROPY_HW_LED1_LEVEL - MICROPY_HW_LED1_LEVEL, - #else - MICROPY_HW_LED_PULLUP != 0 ? 0 : 1 - #endif - }, - {{&board_led_type}, BOARD_LED2, MICROPY_HW_LED2, 0, - #ifdef MICROPY_HW_LED2_LEVEL - MICROPY_HW_LED2_LEVEL, - #else - MICROPY_HW_LED_PULLUP != 0 ? 0 : 1 - #endif - }, - {{&board_led_type}, BOARD_LED3, MICROPY_HW_LED3, 0, - #ifdef MICROPY_HW_LED3_LEVEL - MICROPY_HW_LED3_LEVEL, - #else - MICROPY_HW_LED_PULLUP != 0 ? 0 : 1 + MICROPY_HW_LED_PULLUP #endif }, +#endif +#if (MICROPY_HW_LED_COUNT == 4) {{&board_led_type}, BOARD_LED4, MICROPY_HW_LED4, 0, - #ifdef MICROPY_HW_LED4_LEVEL - MICROPY_HW_LED4_LEVEL, + #ifdef MICROPY_HW_LED4_PULLUP + MICROPY_HW_LED4_PULLUP #else - MICROPY_HW_LED_PULLUP != 0 ? 0 : 1 + MICROPY_HW_LED_PULLUP #endif }, #endif @@ -156,17 +110,17 @@ static const board_led_obj_t board_led_obj[] = { void led_init(void) { for (uint8_t i = 0; i < NUM_LEDS; i++) { - LED_OFF((board_led_obj_t*)&board_led_obj[i]); + led_off((board_led_obj_t*)&board_led_obj[i]); nrf_gpio_cfg_output(board_led_obj[i].hw_pin); } } void led_state(board_led_obj_t * led_obj, int state) { if (state == 1) { - LED_ON(led_obj); + led_on(led_obj); } else { - LED_OFF(led_obj); + led_off(led_obj); } } From ced340d739e84737dd5c8e6b4ab9af2ea44e29e7 Mon Sep 17 00:00:00 2001 From: Mikhail Zakharov Date: Tue, 23 Apr 2019 11:06:11 -0400 Subject: [PATCH 0461/1788] unix/unix_mphal: Use CLOCK_MONOTONIC for ticks_ms/us when available. --- ports/unix/unix_mphal.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ports/unix/unix_mphal.c b/ports/unix/unix_mphal.c index f27c62fd1d..71edaa57ac 100644 --- a/ports/unix/unix_mphal.c +++ b/ports/unix/unix_mphal.c @@ -187,13 +187,25 @@ void mp_hal_stdout_tx_str(const char *str) { } mp_uint_t mp_hal_ticks_ms(void) { + #if (defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0) && defined(_POSIX_MONOTONIC_CLOCK) + struct timespec tv; + clock_gettime(CLOCK_MONOTONIC, &tv); + return tv.tv_sec * 1000 + tv.tv_nsec / 1000000; + #else struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec * 1000 + tv.tv_usec / 1000; + #endif } mp_uint_t mp_hal_ticks_us(void) { + #if (defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0) && defined(_POSIX_MONOTONIC_CLOCK) + struct timespec tv; + clock_gettime(CLOCK_MONOTONIC, &tv); + return tv.tv_sec * 1000000 + tv.tv_nsec / 1000; + #else struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec * 1000000 + tv.tv_usec; + #endif } From b152bbddd132cf3f147a526efebedaf25eba29cd Mon Sep 17 00:00:00 2001 From: Jun Wu Date: Mon, 6 May 2019 00:31:11 -0700 Subject: [PATCH 0462/1788] py: Define EMIT_MACHINE_CODE as EMIT_NATIVE || EMIT_INLINE_ASM. The combination MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM is used in many places, so define a new macro for it. --- py/asmbase.c | 4 ++-- py/emitglue.c | 2 +- py/emitglue.h | 4 ++-- py/mpconfig.h | 3 +++ py/nativeglue.c | 2 +- tools/mpy-tool.py | 4 ++-- 6 files changed, 11 insertions(+), 8 deletions(-) diff --git a/py/asmbase.c b/py/asmbase.c index 4c84c3b255..ab861da152 100644 --- a/py/asmbase.c +++ b/py/asmbase.c @@ -31,7 +31,7 @@ #include "py/misc.h" #include "py/asmbase.h" -#if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM +#if MICROPY_EMIT_MACHINE_CODE void mp_asm_base_init(mp_asm_base_t *as, size_t max_num_labels) { as->max_num_labels = max_num_labels; @@ -99,4 +99,4 @@ void mp_asm_base_data(mp_asm_base_t* as, unsigned int bytesize, uintptr_t val) { } } -#endif // MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM +#endif // MICROPY_EMIT_MACHINE_CODE diff --git a/py/emitglue.c b/py/emitglue.c index c073258f01..483a47025b 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -88,7 +88,7 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, #endif } -#if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM +#if MICROPY_EMIT_MACHINE_CODE void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, const mp_uint_t *const_table, #if MICROPY_PERSISTENT_CODE_SAVE uint16_t prelude_offset, diff --git a/py/emitglue.h b/py/emitglue.h index 058f060186..b67d49ed6d 100644 --- a/py/emitglue.h +++ b/py/emitglue.h @@ -63,13 +63,13 @@ typedef struct _mp_raw_code_t { size_t fun_data_len; uint16_t n_obj; uint16_t n_raw_code; - #if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM + #if MICROPY_EMIT_MACHINE_CODE uint16_t prelude_offset; uint16_t n_qstr; mp_qstr_link_entry_t *qstr_link; #endif #endif - #if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM + #if MICROPY_EMIT_MACHINE_CODE mp_uint_t type_sig; // for viper, compressed as 2-bit types; ret is MSB, then arg0, arg1, etc #endif } mp_raw_code_t; diff --git a/py/mpconfig.h b/py/mpconfig.h index 4172e175b2..a111b27aec 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -329,6 +329,9 @@ // Convenience definition for whether any inline assembler emitter is enabled #define MICROPY_EMIT_INLINE_ASM (MICROPY_EMIT_INLINE_THUMB || MICROPY_EMIT_INLINE_XTENSA) +// Convenience definition for whether any native or inline assembler emitter is enabled +#define MICROPY_EMIT_MACHINE_CODE (MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM) + /*****************************************************************************/ /* Compiler configuration */ diff --git a/py/nativeglue.c b/py/nativeglue.c index 11d7a283a2..979265a870 100644 --- a/py/nativeglue.c +++ b/py/nativeglue.c @@ -77,7 +77,7 @@ mp_uint_t mp_native_from_obj(mp_obj_t obj, mp_uint_t type) { #endif -#if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM +#if MICROPY_EMIT_MACHINE_CODE // convert a native value to a MicroPython object based on type mp_obj_t mp_native_to_obj(mp_uint_t val, mp_uint_t type) { diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index a97af7737f..648d56fe05 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -410,13 +410,13 @@ class RawCode(object): print(' .fun_data_len = %u,' % len(self.bytecode)) print(' .n_obj = %u,' % len(self.objs)) print(' .n_raw_code = %u,' % len(self.raw_codes)) - print(' #if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM') + print(' #if MICROPY_EMIT_MACHINE_CODE') print(' .prelude_offset = %u,' % self.prelude_offset) print(' .n_qstr = %u,' % len(qstr_links)) print(' .qstr_link = NULL,') # TODO print(' #endif') print(' #endif') - print(' #if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM') + print(' #if MICROPY_EMIT_MACHINE_CODE') print(' .type_sig = %u,' % type_sig) print(' #endif') print('};') From d165a401dce66ba952b016d116b60e77b11f3e1f Mon Sep 17 00:00:00 2001 From: Jun Wu Date: Sun, 5 May 2019 23:14:25 -0700 Subject: [PATCH 0463/1788] py/persistentcode: Fix compilation with load and save both enabled. With both MICROPY_PERSISTENT_CODE_SAVE and MICROPY_PERSISTENT_CODE_LOAD enabled the code fails to compile, due to undeclared 'n_obj'. If MICROPY_EMIT_NATIVE is disabled there are more errors due to the use of undefined fields in mp_raw_code_t. This patch fixes such compilation by avoiding undefined fields. MICROPY_EMIT_NATIVE was changed to MICROPY_EMIT_MACHINE_CODE in this file to match the mp_raw_code_t definition. --- py/persistentcode.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/py/persistentcode.c b/py/persistentcode.c index cc6e161f42..c1ca46f7e9 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -157,7 +157,7 @@ typedef struct _bytecode_prelude_t { uint code_info_size; } bytecode_prelude_t; -#if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_EMIT_NATIVE +#if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_EMIT_MACHINE_CODE // ip will point to start of opcodes // ip2 will point to simple_name, source_file qstrs @@ -183,7 +183,7 @@ STATIC void extract_prelude(const byte **ip, const byte **ip2, bytecode_prelude_ #include "py/parsenum.h" -#if MICROPY_EMIT_NATIVE +#if MICROPY_EMIT_MACHINE_CODE #if MICROPY_EMIT_THUMB STATIC void asm_thumb_rewrite_mov(uint8_t *pc, uint16_t val) { @@ -327,7 +327,7 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { int kind = (kind_len & 3) + MP_CODE_BYTECODE; size_t fun_data_len = kind_len >> 2; - #if !MICROPY_EMIT_NATIVE + #if !MICROPY_EMIT_MACHINE_CODE if (kind != MP_CODE_BYTECODE) { mp_raise_ValueError("incompatible .mpy file"); } @@ -336,7 +336,7 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { uint8_t *fun_data = NULL; byte *ip2; bytecode_prelude_t prelude = {0}; - #if MICROPY_EMIT_NATIVE + #if MICROPY_EMIT_MACHINE_CODE size_t prelude_offset; mp_uint_t type_sig = 0; size_t n_qstr_link = 0; @@ -353,7 +353,7 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { // Load bytecode load_bytecode(reader, qw, ip, fun_data + fun_data_len); - #if MICROPY_EMIT_NATIVE + #if MICROPY_EMIT_MACHINE_CODE } else { // Allocate memory for native data and load it size_t fun_alloc; @@ -404,13 +404,16 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { ip2[2] = source_file; ip2[3] = source_file >> 8; } + size_t n_obj = 0; + size_t n_raw_code = 0; mp_uint_t *const_table = NULL; + if (kind != MP_CODE_NATIVE_ASM) { // Load constant table for bytecode, native and viper // Number of entries in constant table - size_t n_obj = read_uint(reader, NULL); - size_t n_raw_code = read_uint(reader, NULL); + n_obj = read_uint(reader, NULL); + n_raw_code = read_uint(reader, NULL); // Allocate constant table size_t n_alloc = prelude.n_pos_args + prelude.n_kwonly_args + n_obj + n_raw_code; @@ -426,7 +429,7 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { *ct++ = (mp_uint_t)MP_OBJ_NEW_QSTR(load_qstr(reader, qw)); } - #if MICROPY_EMIT_NATIVE + #if MICROPY_EMIT_MACHINE_CODE if (kind != MP_CODE_BYTECODE) { // Populate mp_fun_table entry *ct++ = (mp_uint_t)(uintptr_t)mp_fun_table; @@ -455,7 +458,7 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { #endif prelude.scope_flags); - #if MICROPY_EMIT_NATIVE + #if MICROPY_EMIT_MACHINE_CODE } else { #if defined(MP_PLAT_COMMIT_EXEC) fun_data = MP_PLAT_COMMIT_EXEC(fun_data, fun_data_len); @@ -626,6 +629,7 @@ STATIC void save_raw_code(mp_print_t *print, mp_raw_code_t *rc, qstr_window_t *q // Save bytecode save_bytecode(print, qstr_window, ip, ip_top); + #if MICROPY_EMIT_MACHINE_CODE } else { // Save native code mp_print_bytes(print, rc->fun_data, rc->fun_data_len); @@ -654,6 +658,7 @@ STATIC void save_raw_code(mp_print_t *print, mp_raw_code_t *rc, qstr_window_t *q mp_print_uint(print, rc->type_sig); } } + #endif } if (rc->kind == MP_CODE_BYTECODE || rc->kind == MP_CODE_NATIVE_PY) { From d86fb670e6d78ca38dbaedfdde35180e3b8f4bb3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 18 Jun 2019 23:44:16 +1000 Subject: [PATCH 0464/1788] tests: Rename "bench" tests to "internal_bench" and run-internalbench.py To emphasise these benchmark tests compare the internal performance of features amongst themselves, rather than absolute performance testing. --- tests/{bench => internal_bench}/arrayop-1-list_inplace.py | 0 tests/{bench => internal_bench}/arrayop-2-list_map.py | 0 tests/{bench => internal_bench}/arrayop-3-bytearray_inplace.py | 0 tests/{bench => internal_bench}/arrayop-4-bytearray_map.py | 0 tests/{bench => internal_bench}/bench.py | 0 tests/{bench => internal_bench}/bytealloc-1-bytes_n.py | 0 tests/{bench => internal_bench}/bytealloc-2-repeat.py | 0 tests/{bench => internal_bench}/bytebuf-1-inplace.py | 0 tests/{bench => internal_bench}/bytebuf-2-join_map_bytes.py | 0 tests/{bench => internal_bench}/bytebuf-3-bytarray_map.py | 0 tests/{bench => internal_bench}/from_iter-1-list_bound.py | 0 tests/{bench => internal_bench}/from_iter-2-list_unbound.py | 0 tests/{bench => internal_bench}/from_iter-3-tuple_bound.py | 0 tests/{bench => internal_bench}/from_iter-4-tuple_unbound.py | 0 tests/{bench => internal_bench}/from_iter-5-bytes_bound.py | 0 tests/{bench => internal_bench}/from_iter-6-bytes_unbound.py | 0 tests/{bench => internal_bench}/from_iter-7-bytearray_bound.py | 0 .../{bench => internal_bench}/from_iter-8-bytearray_unbound.py | 0 tests/{bench => internal_bench}/func_args-1.1-pos_1.py | 0 tests/{bench => internal_bench}/func_args-1.2-pos_3.py | 0 .../{bench => internal_bench}/func_args-2-pos_default_2_of_3.py | 0 tests/{bench => internal_bench}/func_args-3.1-kw_1.py | 0 tests/{bench => internal_bench}/func_args-3.2-kw_3.py | 0 tests/{bench => internal_bench}/func_builtin-1-enum_pos.py | 0 tests/{bench => internal_bench}/func_builtin-2-enum_kw.py | 0 tests/{bench => internal_bench}/funcall-1-inline.py | 0 tests/{bench => internal_bench}/funcall-2-funcall.py | 0 tests/{bench => internal_bench}/funcall-3-funcall-local.py | 0 tests/{bench => internal_bench}/loop_count-1-range.py | 0 tests/{bench => internal_bench}/loop_count-2-range_iter.py | 0 tests/{bench => internal_bench}/loop_count-3-while_up.py | 0 tests/{bench => internal_bench}/loop_count-4-while_down_gt.py | 0 tests/{bench => internal_bench}/loop_count-5-while_down_ne.py | 0 .../loop_count-5.1-while_down_ne_localvar.py | 0 tests/{bench => internal_bench}/var-1-constant.py | 0 tests/{bench => internal_bench}/var-2-global.py | 0 tests/{bench => internal_bench}/var-3-local.py | 0 tests/{bench => internal_bench}/var-4-arg.py | 0 tests/{bench => internal_bench}/var-5-class-attr.py | 0 tests/{bench => internal_bench}/var-6-instance-attr.py | 0 tests/{bench => internal_bench}/var-6.1-instance-attr-5.py | 0 tests/{bench => internal_bench}/var-7-instance-meth.py | 0 tests/{bench => internal_bench}/var-8-namedtuple-1st.py | 0 tests/{bench => internal_bench}/var-8.1-namedtuple-5th.py | 0 tests/{run-bench-tests => run-internalbench.py} | 2 +- 45 files changed, 1 insertion(+), 1 deletion(-) rename tests/{bench => internal_bench}/arrayop-1-list_inplace.py (100%) rename tests/{bench => internal_bench}/arrayop-2-list_map.py (100%) rename tests/{bench => internal_bench}/arrayop-3-bytearray_inplace.py (100%) rename tests/{bench => internal_bench}/arrayop-4-bytearray_map.py (100%) rename tests/{bench => internal_bench}/bench.py (100%) rename tests/{bench => internal_bench}/bytealloc-1-bytes_n.py (100%) rename tests/{bench => internal_bench}/bytealloc-2-repeat.py (100%) rename tests/{bench => internal_bench}/bytebuf-1-inplace.py (100%) rename tests/{bench => internal_bench}/bytebuf-2-join_map_bytes.py (100%) rename tests/{bench => internal_bench}/bytebuf-3-bytarray_map.py (100%) rename tests/{bench => internal_bench}/from_iter-1-list_bound.py (100%) rename tests/{bench => internal_bench}/from_iter-2-list_unbound.py (100%) rename tests/{bench => internal_bench}/from_iter-3-tuple_bound.py (100%) rename tests/{bench => internal_bench}/from_iter-4-tuple_unbound.py (100%) rename tests/{bench => internal_bench}/from_iter-5-bytes_bound.py (100%) rename tests/{bench => internal_bench}/from_iter-6-bytes_unbound.py (100%) rename tests/{bench => internal_bench}/from_iter-7-bytearray_bound.py (100%) rename tests/{bench => internal_bench}/from_iter-8-bytearray_unbound.py (100%) rename tests/{bench => internal_bench}/func_args-1.1-pos_1.py (100%) rename tests/{bench => internal_bench}/func_args-1.2-pos_3.py (100%) rename tests/{bench => internal_bench}/func_args-2-pos_default_2_of_3.py (100%) rename tests/{bench => internal_bench}/func_args-3.1-kw_1.py (100%) rename tests/{bench => internal_bench}/func_args-3.2-kw_3.py (100%) rename tests/{bench => internal_bench}/func_builtin-1-enum_pos.py (100%) rename tests/{bench => internal_bench}/func_builtin-2-enum_kw.py (100%) rename tests/{bench => internal_bench}/funcall-1-inline.py (100%) rename tests/{bench => internal_bench}/funcall-2-funcall.py (100%) rename tests/{bench => internal_bench}/funcall-3-funcall-local.py (100%) rename tests/{bench => internal_bench}/loop_count-1-range.py (100%) rename tests/{bench => internal_bench}/loop_count-2-range_iter.py (100%) rename tests/{bench => internal_bench}/loop_count-3-while_up.py (100%) rename tests/{bench => internal_bench}/loop_count-4-while_down_gt.py (100%) rename tests/{bench => internal_bench}/loop_count-5-while_down_ne.py (100%) rename tests/{bench => internal_bench}/loop_count-5.1-while_down_ne_localvar.py (100%) rename tests/{bench => internal_bench}/var-1-constant.py (100%) rename tests/{bench => internal_bench}/var-2-global.py (100%) rename tests/{bench => internal_bench}/var-3-local.py (100%) rename tests/{bench => internal_bench}/var-4-arg.py (100%) rename tests/{bench => internal_bench}/var-5-class-attr.py (100%) rename tests/{bench => internal_bench}/var-6-instance-attr.py (100%) rename tests/{bench => internal_bench}/var-6.1-instance-attr-5.py (100%) rename tests/{bench => internal_bench}/var-7-instance-meth.py (100%) rename tests/{bench => internal_bench}/var-8-namedtuple-1st.py (100%) rename tests/{bench => internal_bench}/var-8.1-namedtuple-5th.py (100%) rename tests/{run-bench-tests => run-internalbench.py} (98%) diff --git a/tests/bench/arrayop-1-list_inplace.py b/tests/internal_bench/arrayop-1-list_inplace.py similarity index 100% rename from tests/bench/arrayop-1-list_inplace.py rename to tests/internal_bench/arrayop-1-list_inplace.py diff --git a/tests/bench/arrayop-2-list_map.py b/tests/internal_bench/arrayop-2-list_map.py similarity index 100% rename from tests/bench/arrayop-2-list_map.py rename to tests/internal_bench/arrayop-2-list_map.py diff --git a/tests/bench/arrayop-3-bytearray_inplace.py b/tests/internal_bench/arrayop-3-bytearray_inplace.py similarity index 100% rename from tests/bench/arrayop-3-bytearray_inplace.py rename to tests/internal_bench/arrayop-3-bytearray_inplace.py diff --git a/tests/bench/arrayop-4-bytearray_map.py b/tests/internal_bench/arrayop-4-bytearray_map.py similarity index 100% rename from tests/bench/arrayop-4-bytearray_map.py rename to tests/internal_bench/arrayop-4-bytearray_map.py diff --git a/tests/bench/bench.py b/tests/internal_bench/bench.py similarity index 100% rename from tests/bench/bench.py rename to tests/internal_bench/bench.py diff --git a/tests/bench/bytealloc-1-bytes_n.py b/tests/internal_bench/bytealloc-1-bytes_n.py similarity index 100% rename from tests/bench/bytealloc-1-bytes_n.py rename to tests/internal_bench/bytealloc-1-bytes_n.py diff --git a/tests/bench/bytealloc-2-repeat.py b/tests/internal_bench/bytealloc-2-repeat.py similarity index 100% rename from tests/bench/bytealloc-2-repeat.py rename to tests/internal_bench/bytealloc-2-repeat.py diff --git a/tests/bench/bytebuf-1-inplace.py b/tests/internal_bench/bytebuf-1-inplace.py similarity index 100% rename from tests/bench/bytebuf-1-inplace.py rename to tests/internal_bench/bytebuf-1-inplace.py diff --git a/tests/bench/bytebuf-2-join_map_bytes.py b/tests/internal_bench/bytebuf-2-join_map_bytes.py similarity index 100% rename from tests/bench/bytebuf-2-join_map_bytes.py rename to tests/internal_bench/bytebuf-2-join_map_bytes.py diff --git a/tests/bench/bytebuf-3-bytarray_map.py b/tests/internal_bench/bytebuf-3-bytarray_map.py similarity index 100% rename from tests/bench/bytebuf-3-bytarray_map.py rename to tests/internal_bench/bytebuf-3-bytarray_map.py diff --git a/tests/bench/from_iter-1-list_bound.py b/tests/internal_bench/from_iter-1-list_bound.py similarity index 100% rename from tests/bench/from_iter-1-list_bound.py rename to tests/internal_bench/from_iter-1-list_bound.py diff --git a/tests/bench/from_iter-2-list_unbound.py b/tests/internal_bench/from_iter-2-list_unbound.py similarity index 100% rename from tests/bench/from_iter-2-list_unbound.py rename to tests/internal_bench/from_iter-2-list_unbound.py diff --git a/tests/bench/from_iter-3-tuple_bound.py b/tests/internal_bench/from_iter-3-tuple_bound.py similarity index 100% rename from tests/bench/from_iter-3-tuple_bound.py rename to tests/internal_bench/from_iter-3-tuple_bound.py diff --git a/tests/bench/from_iter-4-tuple_unbound.py b/tests/internal_bench/from_iter-4-tuple_unbound.py similarity index 100% rename from tests/bench/from_iter-4-tuple_unbound.py rename to tests/internal_bench/from_iter-4-tuple_unbound.py diff --git a/tests/bench/from_iter-5-bytes_bound.py b/tests/internal_bench/from_iter-5-bytes_bound.py similarity index 100% rename from tests/bench/from_iter-5-bytes_bound.py rename to tests/internal_bench/from_iter-5-bytes_bound.py diff --git a/tests/bench/from_iter-6-bytes_unbound.py b/tests/internal_bench/from_iter-6-bytes_unbound.py similarity index 100% rename from tests/bench/from_iter-6-bytes_unbound.py rename to tests/internal_bench/from_iter-6-bytes_unbound.py diff --git a/tests/bench/from_iter-7-bytearray_bound.py b/tests/internal_bench/from_iter-7-bytearray_bound.py similarity index 100% rename from tests/bench/from_iter-7-bytearray_bound.py rename to tests/internal_bench/from_iter-7-bytearray_bound.py diff --git a/tests/bench/from_iter-8-bytearray_unbound.py b/tests/internal_bench/from_iter-8-bytearray_unbound.py similarity index 100% rename from tests/bench/from_iter-8-bytearray_unbound.py rename to tests/internal_bench/from_iter-8-bytearray_unbound.py diff --git a/tests/bench/func_args-1.1-pos_1.py b/tests/internal_bench/func_args-1.1-pos_1.py similarity index 100% rename from tests/bench/func_args-1.1-pos_1.py rename to tests/internal_bench/func_args-1.1-pos_1.py diff --git a/tests/bench/func_args-1.2-pos_3.py b/tests/internal_bench/func_args-1.2-pos_3.py similarity index 100% rename from tests/bench/func_args-1.2-pos_3.py rename to tests/internal_bench/func_args-1.2-pos_3.py diff --git a/tests/bench/func_args-2-pos_default_2_of_3.py b/tests/internal_bench/func_args-2-pos_default_2_of_3.py similarity index 100% rename from tests/bench/func_args-2-pos_default_2_of_3.py rename to tests/internal_bench/func_args-2-pos_default_2_of_3.py diff --git a/tests/bench/func_args-3.1-kw_1.py b/tests/internal_bench/func_args-3.1-kw_1.py similarity index 100% rename from tests/bench/func_args-3.1-kw_1.py rename to tests/internal_bench/func_args-3.1-kw_1.py diff --git a/tests/bench/func_args-3.2-kw_3.py b/tests/internal_bench/func_args-3.2-kw_3.py similarity index 100% rename from tests/bench/func_args-3.2-kw_3.py rename to tests/internal_bench/func_args-3.2-kw_3.py diff --git a/tests/bench/func_builtin-1-enum_pos.py b/tests/internal_bench/func_builtin-1-enum_pos.py similarity index 100% rename from tests/bench/func_builtin-1-enum_pos.py rename to tests/internal_bench/func_builtin-1-enum_pos.py diff --git a/tests/bench/func_builtin-2-enum_kw.py b/tests/internal_bench/func_builtin-2-enum_kw.py similarity index 100% rename from tests/bench/func_builtin-2-enum_kw.py rename to tests/internal_bench/func_builtin-2-enum_kw.py diff --git a/tests/bench/funcall-1-inline.py b/tests/internal_bench/funcall-1-inline.py similarity index 100% rename from tests/bench/funcall-1-inline.py rename to tests/internal_bench/funcall-1-inline.py diff --git a/tests/bench/funcall-2-funcall.py b/tests/internal_bench/funcall-2-funcall.py similarity index 100% rename from tests/bench/funcall-2-funcall.py rename to tests/internal_bench/funcall-2-funcall.py diff --git a/tests/bench/funcall-3-funcall-local.py b/tests/internal_bench/funcall-3-funcall-local.py similarity index 100% rename from tests/bench/funcall-3-funcall-local.py rename to tests/internal_bench/funcall-3-funcall-local.py diff --git a/tests/bench/loop_count-1-range.py b/tests/internal_bench/loop_count-1-range.py similarity index 100% rename from tests/bench/loop_count-1-range.py rename to tests/internal_bench/loop_count-1-range.py diff --git a/tests/bench/loop_count-2-range_iter.py b/tests/internal_bench/loop_count-2-range_iter.py similarity index 100% rename from tests/bench/loop_count-2-range_iter.py rename to tests/internal_bench/loop_count-2-range_iter.py diff --git a/tests/bench/loop_count-3-while_up.py b/tests/internal_bench/loop_count-3-while_up.py similarity index 100% rename from tests/bench/loop_count-3-while_up.py rename to tests/internal_bench/loop_count-3-while_up.py diff --git a/tests/bench/loop_count-4-while_down_gt.py b/tests/internal_bench/loop_count-4-while_down_gt.py similarity index 100% rename from tests/bench/loop_count-4-while_down_gt.py rename to tests/internal_bench/loop_count-4-while_down_gt.py diff --git a/tests/bench/loop_count-5-while_down_ne.py b/tests/internal_bench/loop_count-5-while_down_ne.py similarity index 100% rename from tests/bench/loop_count-5-while_down_ne.py rename to tests/internal_bench/loop_count-5-while_down_ne.py diff --git a/tests/bench/loop_count-5.1-while_down_ne_localvar.py b/tests/internal_bench/loop_count-5.1-while_down_ne_localvar.py similarity index 100% rename from tests/bench/loop_count-5.1-while_down_ne_localvar.py rename to tests/internal_bench/loop_count-5.1-while_down_ne_localvar.py diff --git a/tests/bench/var-1-constant.py b/tests/internal_bench/var-1-constant.py similarity index 100% rename from tests/bench/var-1-constant.py rename to tests/internal_bench/var-1-constant.py diff --git a/tests/bench/var-2-global.py b/tests/internal_bench/var-2-global.py similarity index 100% rename from tests/bench/var-2-global.py rename to tests/internal_bench/var-2-global.py diff --git a/tests/bench/var-3-local.py b/tests/internal_bench/var-3-local.py similarity index 100% rename from tests/bench/var-3-local.py rename to tests/internal_bench/var-3-local.py diff --git a/tests/bench/var-4-arg.py b/tests/internal_bench/var-4-arg.py similarity index 100% rename from tests/bench/var-4-arg.py rename to tests/internal_bench/var-4-arg.py diff --git a/tests/bench/var-5-class-attr.py b/tests/internal_bench/var-5-class-attr.py similarity index 100% rename from tests/bench/var-5-class-attr.py rename to tests/internal_bench/var-5-class-attr.py diff --git a/tests/bench/var-6-instance-attr.py b/tests/internal_bench/var-6-instance-attr.py similarity index 100% rename from tests/bench/var-6-instance-attr.py rename to tests/internal_bench/var-6-instance-attr.py diff --git a/tests/bench/var-6.1-instance-attr-5.py b/tests/internal_bench/var-6.1-instance-attr-5.py similarity index 100% rename from tests/bench/var-6.1-instance-attr-5.py rename to tests/internal_bench/var-6.1-instance-attr-5.py diff --git a/tests/bench/var-7-instance-meth.py b/tests/internal_bench/var-7-instance-meth.py similarity index 100% rename from tests/bench/var-7-instance-meth.py rename to tests/internal_bench/var-7-instance-meth.py diff --git a/tests/bench/var-8-namedtuple-1st.py b/tests/internal_bench/var-8-namedtuple-1st.py similarity index 100% rename from tests/bench/var-8-namedtuple-1st.py rename to tests/internal_bench/var-8-namedtuple-1st.py diff --git a/tests/bench/var-8.1-namedtuple-5th.py b/tests/internal_bench/var-8.1-namedtuple-5th.py similarity index 100% rename from tests/bench/var-8.1-namedtuple-5th.py rename to tests/internal_bench/var-8.1-namedtuple-5th.py diff --git a/tests/run-bench-tests b/tests/run-internalbench.py similarity index 98% rename from tests/run-bench-tests rename to tests/run-internalbench.py index f4a6776cbc..f6294572f0 100755 --- a/tests/run-bench-tests +++ b/tests/run-internalbench.py @@ -74,7 +74,7 @@ def main(): if len(args.files) == 0: if pyb is None: # run PC tests - test_dirs = ('bench',) + test_dirs = ('internal_bench',) else: # run pyboard tests test_dirs = ('basics', 'float', 'pyb') From e92c9aa9c94eae7971c8e82f4e875fc53ef52f07 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 26 Jun 2019 14:23:03 +1000 Subject: [PATCH 0465/1788] tests: Add performance benchmarking test-suite framework. This benchmarking test suite is intended to be run on any MicroPython target. As such all tests are parameterised with N and M: N is the approximate CPU frequency (in MHz) of the target and M is the approximate amount of heap memory (in kbytes) available on the target. When running the benchmark suite these parameters must be specified and then each test is tuned to run on that target in a reasonable time (<1 second). The test scripts are not standalone: they require adding some extra code at the end to run the test with the appropriate parameters. This is done automatically by the run-perfbench.py script, in such a way that imports are minimised (so the tests can be run on targets without filesystem support). To interface with the benchmarking framework, each test provides a bm_params dict and a bm_setup function, with the later taking a set of parameters (chosen based on N, M) and returning a pair of functions, one to run the test and one to get the results. When running the test the number of microseconds taken by the test are recorded. Then this is converted into a benchmark score by inverting it (so higher number is faster) and normalising it with an appropriate factor (based roughly on the amount of work done by the test, eg number of iterations). Test outputs are also compared against a "truth" value, computed by running the test with CPython. This provides a basic way of making sure the test actually ran correctly. Each test is run multiple times and the results averaged and standard deviation computed. This is output as a summary of the test. To make comparisons of performance across different runs the run-perfbench.py script also includes a diff mode that reads in the output of two previous runs and computes the difference in performance. Reports are given as a percentage change in performance with a combined standard deviation to give an indication if the noise in the benchmarking is less than the thing that is being measured. Example invocations for PC, pyboard and esp8266 targets respectively: $ ./run-perfbench.py 1000 1000 $ ./run-perfbench.py --pyboard 100 100 $ ./run-perfbench.py --pyboard --device /dev/ttyUSB0 50 25 --- tests/perf_bench/benchrun.py | 26 ++++ tests/run-perfbench.py | 241 +++++++++++++++++++++++++++++++++++ 2 files changed, 267 insertions(+) create mode 100644 tests/perf_bench/benchrun.py create mode 100755 tests/run-perfbench.py diff --git a/tests/perf_bench/benchrun.py b/tests/perf_bench/benchrun.py new file mode 100644 index 0000000000..9cbc9695ac --- /dev/null +++ b/tests/perf_bench/benchrun.py @@ -0,0 +1,26 @@ +def bm_run(N, M): + try: + from utime import ticks_us, ticks_diff + except ImportError: + import time + ticks_us = lambda: int(time.perf_counter() * 1000000) + ticks_diff = lambda a, b: a - b + + # Pick sensible parameters given N, M + cur_nm = (0, 0) + param = None + for nm, p in bm_params.items(): + if 10 * nm[0] <= 12 * N and nm[1] <= M and nm > cur_nm: + cur_nm = nm + param = p + if param is None: + print(-1, -1, 'no matching params') + return + + # Run and time benchmark + run, result = bm_setup(param) + t0 = ticks_us() + run() + t1 = ticks_us() + norm, out = result() + print(ticks_diff(t1, t0), norm, out) diff --git a/tests/run-perfbench.py b/tests/run-perfbench.py new file mode 100755 index 0000000000..d8100ef81d --- /dev/null +++ b/tests/run-perfbench.py @@ -0,0 +1,241 @@ +#!/usr/bin/env python3 + +# This file is part of the MicroPython project, http://micropython.org/ +# The MIT License (MIT) +# Copyright (c) 2019 Damien P. George + +import os +import subprocess +import sys +import argparse +from glob import glob + +sys.path.append('../tools') +import pyboard + +# Paths for host executables +if os.name == 'nt': + CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python3.exe') + MICROPYTHON = os.getenv('MICROPY_MICROPYTHON', '../ports/windows/micropython.exe') +else: + CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python3') + MICROPYTHON = os.getenv('MICROPY_MICROPYTHON', '../ports/unix/micropython') + +PYTHON_TRUTH = CPYTHON3 + +BENCH_SCRIPT_DIR = 'perf_bench/' + +def compute_stats(lst): + avg = 0 + var = 0 + for x in lst: + avg += x + var += x * x + avg /= len(lst) + var = max(0, var / len(lst) - avg ** 2) + return avg, var ** 0.5 + +def run_script_on_target(target, script): + output = b'' + err = None + + if isinstance(target, pyboard.Pyboard): + # Run via pyboard interface + try: + target.enter_raw_repl() + output = target.exec_(script) + except pyboard.PyboardError as er: + err = er + else: + # Run local executable + try: + p = subprocess.run([target], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, input=script) + output = p.stdout + except subprocess.CalledProcessError as er: + err = er + + return str(output.strip(), 'ascii'), err + +def run_feature_test(target, test): + with open('feature_check/' + test + '.py', 'rb') as f: + script = f.read() + output, err = run_script_on_target(target, script) + if err is None: + return output + else: + return 'CRASH: %r' % err + +def run_benchmark_on_target(target, script): + output, err = run_script_on_target(target, script) + if err is None: + time, norm, result = output.split(None, 2) + try: + return int(time), int(norm), result + except ValueError: + return -1, -1, 'CRASH: %r' % output + else: + return -1, -1, 'CRASH: %r' % err + +def run_benchmarks(target, param_n, param_m, n_average, test_list): + skip_native = run_feature_test(target, 'native_check') != '' + + for test_file in sorted(test_list): + print(test_file + ': ', end='') + + # Check if test should be skipped + skip = skip_native and test_file.find('viper_') != -1 + if skip: + print('skip') + continue + + # Create test script + with open(test_file, 'rb') as f: + test_script = f.read() + with open(BENCH_SCRIPT_DIR + 'benchrun.py', 'rb') as f: + test_script += f.read() + test_script += b'bm_run(%u, %u)\n' % (param_n, param_m) + + # Write full test script if needed + if 0: + with open('%s.full' % test_file, 'wb') as f: + f.write(test_script) + + # Run MicroPython a given number of times + times = [] + scores = [] + error = None + result_out = None + for _ in range(n_average): + time, norm, result = run_benchmark_on_target(target, test_script) + if time < 0 or norm < 0: + error = result + break + if result_out is None: + result_out = result + elif result != result_out: + error = 'FAIL self' + break + times.append(time) + scores.append(1e6 * norm / time) + + # Check result against truth if needed + if error is None and result_out != 'None': + _, _, result_exp = run_benchmark_on_target(PYTHON_TRUTH, test_script) + if result_out != result_exp: + error = 'FAIL truth' + break + + if error is not None: + print(error) + else: + t_avg, t_sd = compute_stats(times) + s_avg, s_sd = compute_stats(scores) + print('{:.2f} {:.4f} {:.2f} {:.4f}'.format(t_avg, 100 * t_sd / t_avg, s_avg, 100 * s_sd / s_avg)) + if 0: + print(' times: ', times) + print(' scores:', scores) + + sys.stdout.flush() + +def parse_output(filename): + with open(filename) as f: + params = f.readline() + n, m, _ = params.strip().split() + n = int(n.split('=')[1]) + m = int(m.split('=')[1]) + data = [] + for l in f: + if l.find(': ') != -1 and l.find(': skip') == -1 and l.find('CRASH: ') == -1: + name, values = l.strip().split(': ') + values = tuple(float(v) for v in values.split()) + data.append((name,) + values) + return n, m, data + +def compute_diff(file1, file2, diff_score): + # Parse output data from previous runs + n1, m1, d1 = parse_output(file1) + n2, m2, d2 = parse_output(file2) + + # Print header + if diff_score: + print('diff of scores (higher is better)') + else: + print('diff of microsecond times (lower is better)') + if n1 == n2 and m1 == m2: + hdr = 'N={} M={}'.format(n1, m1) + else: + hdr = 'N={} M={} vs N={} M={}'.format(n1, m1, n2, m2) + print('{:24} {:>10} -> {:>10} {:>10} {:>7}% (error%)'.format(hdr, file1, file2, 'diff', 'diff')) + + # Print entries + while d1 and d2: + if d1[0][0] == d2[0][0]: + # Found entries with matching names + entry1 = d1.pop(0) + entry2 = d2.pop(0) + name = entry1[0].rsplit('/')[-1] + av1, sd1 = entry1[1 + 2 * diff_score], entry1[2 + 2 * diff_score] + av2, sd2 = entry2[1 + 2 * diff_score], entry2[2 + 2 * diff_score] + sd1 *= av1 / 100 # convert from percent sd to absolute sd + sd2 *= av2 / 100 # convert from percent sd to absolute sd + av_diff = av2 - av1 + sd_diff = (sd1 ** 2 + sd2 ** 2) ** 0.5 + percent = 100 * av_diff / av1 + percent_sd = 100 * sd_diff / av1 + print('{:24} {:10.2f} -> {:10.2f} : {:+10.2f} = {:+7.3f}% (+/-{:.2f}%)'.format(name, av1, av2, av_diff, percent, percent_sd)) + elif d1[0][0] < d2[0][0]: + d1.pop(0) + else: + d2.pop(0) + +def main(): + cmd_parser = argparse.ArgumentParser(description='Run benchmarks for MicroPython') + cmd_parser.add_argument('-t', '--diff-time', action='store_true', help='diff time outputs from a previous run') + cmd_parser.add_argument('-s', '--diff-score', action='store_true', help='diff score outputs from a previous run') + cmd_parser.add_argument('-p', '--pyboard', action='store_true', help='run tests via pyboard.py') + cmd_parser.add_argument('-d', '--device', default='/dev/ttyACM0', help='the device for pyboard.py') + cmd_parser.add_argument('-a', '--average', default='8', help='averaging number') + cmd_parser.add_argument('N', nargs=1, help='N parameter (approximate target CPU frequency)') + cmd_parser.add_argument('M', nargs=1, help='M parameter (approximate target heap in kbytes)') + cmd_parser.add_argument('files', nargs='*', help='input test files') + args = cmd_parser.parse_args() + + if args.diff_time or args.diff_score: + compute_diff(args.N[0], args.M[0], args.diff_score) + sys.exit(0) + + # N, M = 50, 25 # esp8266 + # N, M = 100, 100 # pyboard, esp32 + # N, M = 1000, 1000 # PC + N = int(args.N[0]) + M = int(args.M[0]) + n_average = int(args.average) + + if args.pyboard: + target = pyboard.Pyboard(args.device) + target.enter_raw_repl() + else: + target = MICROPYTHON + + if len(args.files) == 0: + tests_skip = ('benchrun.py',) + if M <= 25: + # These scripts are too big to be compiled by the target + tests_skip += ('bm_chaos.py', 'bm_hexiom.py', 'misc_raytrace.py') + tests = sorted( + BENCH_SCRIPT_DIR + test_file for test_file in os.listdir(BENCH_SCRIPT_DIR) + if test_file.endswith('.py') and test_file not in tests_skip + ) + else: + tests = sorted(args.files) + + print('N={} M={} n_average={}'.format(N, M, n_average)) + + run_benchmarks(target, N, M, n_average, tests) + + if isinstance(target, pyboard.Pyboard): + target.exit_raw_repl() + target.close() + +if __name__ == "__main__": + main() From 127714c3af73633ba723dad2cf7267131e7ac6c2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 26 Jun 2019 14:24:13 +1000 Subject: [PATCH 0466/1788] tests/perf_bench: Add some benchmarks from python-performance. From https://github.com/python/pyperformance commit 6690642ddeda46fc5ee6e97c3ef4b2f292348ab8 --- tests/perf_bench/bm_chaos.py | 274 ++++++++++++++ tests/perf_bench/bm_fannkuch.py | 67 ++++ tests/perf_bench/bm_float.py | 70 ++++ tests/perf_bench/bm_hexiom.py | 647 ++++++++++++++++++++++++++++++++ tests/perf_bench/bm_nqueens.py | 62 +++ tests/perf_bench/bm_pidigits.py | 62 +++ 6 files changed, 1182 insertions(+) create mode 100644 tests/perf_bench/bm_chaos.py create mode 100644 tests/perf_bench/bm_fannkuch.py create mode 100644 tests/perf_bench/bm_float.py create mode 100644 tests/perf_bench/bm_hexiom.py create mode 100644 tests/perf_bench/bm_nqueens.py create mode 100644 tests/perf_bench/bm_pidigits.py diff --git a/tests/perf_bench/bm_chaos.py b/tests/perf_bench/bm_chaos.py new file mode 100644 index 0000000000..04e04531ca --- /dev/null +++ b/tests/perf_bench/bm_chaos.py @@ -0,0 +1,274 @@ +# Source: https://github.com/python/pyperformance +# License: MIT + +# create chaosgame-like fractals +# Copyright (C) 2005 Carl Friedrich Bolz + +import math +import random + + +class GVector(object): + + def __init__(self, x=0, y=0, z=0): + self.x = x + self.y = y + self.z = z + + def Mag(self): + return math.sqrt(self.x ** 2 + self.y ** 2 + self.z ** 2) + + def dist(self, other): + return math.sqrt((self.x - other.x) ** 2 + + (self.y - other.y) ** 2 + + (self.z - other.z) ** 2) + + def __add__(self, other): + if not isinstance(other, GVector): + raise ValueError("Can't add GVector to " + str(type(other))) + v = GVector(self.x + other.x, self.y + other.y, self.z + other.z) + return v + + def __sub__(self, other): + return self + other * -1 + + def __mul__(self, other): + v = GVector(self.x * other, self.y * other, self.z * other) + return v + __rmul__ = __mul__ + + def linear_combination(self, other, l1, l2=None): + if l2 is None: + l2 = 1 - l1 + v = GVector(self.x * l1 + other.x * l2, + self.y * l1 + other.y * l2, + self.z * l1 + other.z * l2) + return v + + def __str__(self): + return "<%f, %f, %f>" % (self.x, self.y, self.z) + + def __repr__(self): + return "GVector(%f, %f, %f)" % (self.x, self.y, self.z) + + +class Spline(object): + """Class for representing B-Splines and NURBS of arbitrary degree""" + + def __init__(self, points, degree, knots): + """Creates a Spline. + + points is a list of GVector, degree is the degree of the Spline. + """ + if len(points) > len(knots) - degree + 1: + raise ValueError("too many control points") + elif len(points) < len(knots) - degree + 1: + raise ValueError("not enough control points") + last = knots[0] + for cur in knots[1:]: + if cur < last: + raise ValueError("knots not strictly increasing") + last = cur + self.knots = knots + self.points = points + self.degree = degree + + def GetDomain(self): + """Returns the domain of the B-Spline""" + return (self.knots[self.degree - 1], + self.knots[len(self.knots) - self.degree]) + + def __call__(self, u): + """Calculates a point of the B-Spline using de Boors Algorithm""" + dom = self.GetDomain() + if u < dom[0] or u > dom[1]: + raise ValueError("Function value not in domain") + if u == dom[0]: + return self.points[0] + if u == dom[1]: + return self.points[-1] + I = self.GetIndex(u) + d = [self.points[I - self.degree + 1 + ii] + for ii in range(self.degree + 1)] + U = self.knots + for ik in range(1, self.degree + 1): + for ii in range(I - self.degree + ik + 1, I + 2): + ua = U[ii + self.degree - ik] + ub = U[ii - 1] + co1 = (ua - u) / (ua - ub) + co2 = (u - ub) / (ua - ub) + index = ii - I + self.degree - ik - 1 + d[index] = d[index].linear_combination(d[index + 1], co1, co2) + return d[0] + + def GetIndex(self, u): + dom = self.GetDomain() + for ii in range(self.degree - 1, len(self.knots) - self.degree): + if u >= self.knots[ii] and u < self.knots[ii + 1]: + I = ii + break + else: + I = dom[1] - 1 + return I + + def __len__(self): + return len(self.points) + + def __repr__(self): + return "Spline(%r, %r, %r)" % (self.points, self.degree, self.knots) + + +def write_ppm(im, w, h, filename): + with open(filename, "wb") as f: + f.write(b'P6\n%i %i\n255\n' % (w, h)) + for j in range(h): + for i in range(w): + val = im[j * w + i] + c = val * 255 + f.write(b'%c%c%c' % (c, c, c)) + + +class Chaosgame(object): + + def __init__(self, splines, thickness, subdivs): + self.splines = splines + self.thickness = thickness + self.minx = min([p.x for spl in splines for p in spl.points]) + self.miny = min([p.y for spl in splines for p in spl.points]) + self.maxx = max([p.x for spl in splines for p in spl.points]) + self.maxy = max([p.y for spl in splines for p in spl.points]) + self.height = self.maxy - self.miny + self.width = self.maxx - self.minx + self.num_trafos = [] + maxlength = thickness * self.width / self.height + for spl in splines: + length = 0 + curr = spl(0) + for i in range(1, subdivs + 1): + last = curr + t = 1 / subdivs * i + curr = spl(t) + length += curr.dist(last) + self.num_trafos.append(max(1, int(length / maxlength * 1.5))) + self.num_total = sum(self.num_trafos) + + def get_random_trafo(self): + r = random.randrange(int(self.num_total) + 1) + l = 0 + for i in range(len(self.num_trafos)): + if r >= l and r < l + self.num_trafos[i]: + return i, random.randrange(self.num_trafos[i]) + l += self.num_trafos[i] + return len(self.num_trafos) - 1, random.randrange(self.num_trafos[-1]) + + def transform_point(self, point, trafo=None): + x = (point.x - self.minx) / self.width + y = (point.y - self.miny) / self.height + if trafo is None: + trafo = self.get_random_trafo() + start, end = self.splines[trafo[0]].GetDomain() + length = end - start + seg_length = length / self.num_trafos[trafo[0]] + t = start + seg_length * trafo[1] + seg_length * x + basepoint = self.splines[trafo[0]](t) + if t + 1 / 50000 > end: + neighbour = self.splines[trafo[0]](t - 1 / 50000) + derivative = neighbour - basepoint + else: + neighbour = self.splines[trafo[0]](t + 1 / 50000) + derivative = basepoint - neighbour + if derivative.Mag() != 0: + basepoint.x += derivative.y / derivative.Mag() * (y - 0.5) * \ + self.thickness + basepoint.y += -derivative.x / derivative.Mag() * (y - 0.5) * \ + self.thickness + else: + # can happen, especially with single precision float + pass + self.truncate(basepoint) + return basepoint + + def truncate(self, point): + if point.x >= self.maxx: + point.x = self.maxx + if point.y >= self.maxy: + point.y = self.maxy + if point.x < self.minx: + point.x = self.minx + if point.y < self.miny: + point.y = self.miny + + def create_image_chaos(self, w, h, iterations, rng_seed): + # Always use the same sequence of random numbers + # to get reproductible benchmark + random.seed(rng_seed) + + im = bytearray(w * h) + point = GVector((self.maxx + self.minx) / 2, + (self.maxy + self.miny) / 2, 0) + for _ in range(iterations): + point = self.transform_point(point) + x = (point.x - self.minx) / self.width * w + y = (point.y - self.miny) / self.height * h + x = int(x) + y = int(y) + if x == w: + x -= 1 + if y == h: + y -= 1 + im[(h - y - 1) * w + x] = 1 + + return im + + +########################################################################### +# Benchmark interface + +bm_params = { + (100, 50): (0.25, 100, 50, 50, 50, 1234), + (1000, 1000): (0.25, 200, 400, 400, 1000, 1234), + (5000, 1000): (0.25, 400, 500, 500, 7000, 1234), +} + +def bm_setup(params): + splines = [ + Spline([ + GVector(1.597, 3.304, 0.0), + GVector(1.576, 4.123, 0.0), + GVector(1.313, 5.288, 0.0), + GVector(1.619, 5.330, 0.0), + GVector(2.890, 5.503, 0.0), + GVector(2.373, 4.382, 0.0), + GVector(1.662, 4.360, 0.0)], + 3, [0, 0, 0, 1, 1, 1, 2, 2, 2]), + Spline([ + GVector(2.805, 4.017, 0.0), + GVector(2.551, 3.525, 0.0), + GVector(1.979, 2.620, 0.0), + GVector(1.979, 2.620, 0.0)], + 3, [0, 0, 0, 1, 1, 1]), + Spline([ + GVector(2.002, 4.011, 0.0), + GVector(2.335, 3.313, 0.0), + GVector(2.367, 3.233, 0.0), + GVector(2.367, 3.233, 0.0)], + 3, [0, 0, 0, 1, 1, 1]) + ] + + chaos = Chaosgame(splines, params[0], params[1]) + image = None + + def run(): + nonlocal image + _, _, width, height, iter, rng_seed = params + image = chaos.create_image_chaos(width, height, iter, rng_seed) + + def result(): + norm = params[4] + # Images are not the same when floating point behaviour is different, + # so return percentage of pixels that are set (rounded to int). + #write_ppm(image, params[2], params[3], 'out-.ppm') + pix = int(100 * sum(image) / len(image)) + return norm, pix + + return run, result diff --git a/tests/perf_bench/bm_fannkuch.py b/tests/perf_bench/bm_fannkuch.py new file mode 100644 index 0000000000..c9782e3e9a --- /dev/null +++ b/tests/perf_bench/bm_fannkuch.py @@ -0,0 +1,67 @@ +# Source: https://github.com/python/pyperformance +# License: MIT + +# The Computer Language Benchmarks Game +# http://benchmarksgame.alioth.debian.org/ +# Contributed by Sokolov Yura, modified by Tupteq. + +def fannkuch(n): + count = list(range(1, n + 1)) + max_flips = 0 + m = n - 1 + r = n + check = 0 + perm1 = list(range(n)) + perm = list(range(n)) + perm1_ins = perm1.insert + perm1_pop = perm1.pop + + while 1: + if check < 30: + check += 1 + + while r != 1: + count[r - 1] = r + r -= 1 + + if perm1[0] != 0 and perm1[m] != m: + perm = perm1[:] + flips_count = 0 + k = perm[0] + while k: + perm[:k + 1] = perm[k::-1] + flips_count += 1 + k = perm[0] + + if flips_count > max_flips: + max_flips = flips_count + + while r != n: + perm1_ins(r, perm1_pop(0)) + count[r] -= 1 + if count[r] > 0: + break + r += 1 + else: + return max_flips + + +########################################################################### +# Benchmark interface + +bm_params = { + (50, 10): (5,), + (100, 10): (6,), + (500, 10): (7,), + (1000, 10): (8,), + (5000, 10): (9,), +} + +def bm_setup(params): + state = None + def run(): + nonlocal state + state = fannkuch(params[0]) + def result(): + return params[0], state + return run, result diff --git a/tests/perf_bench/bm_float.py b/tests/perf_bench/bm_float.py new file mode 100644 index 0000000000..5a66b9bb3e --- /dev/null +++ b/tests/perf_bench/bm_float.py @@ -0,0 +1,70 @@ +# Source: https://github.com/python/pyperformance +# License: MIT + +# Artificial, floating point-heavy benchmark originally used by Factor. + +from math import sin, cos, sqrt + + +class Point(object): + __slots__ = ('x', 'y', 'z') + + def __init__(self, i): + self.x = x = sin(i) + self.y = cos(i) * 3 + self.z = (x * x) / 2 + + def __repr__(self): + return "" % (self.x, self.y, self.z) + + def normalize(self): + x = self.x + y = self.y + z = self.z + norm = sqrt(x * x + y * y + z * z) + self.x /= norm + self.y /= norm + self.z /= norm + + def maximize(self, other): + self.x = self.x if self.x > other.x else other.x + self.y = self.y if self.y > other.y else other.y + self.z = self.z if self.z > other.z else other.z + return self + + +def maximize(points): + next = points[0] + for p in points[1:]: + next = next.maximize(p) + return next + + +def benchmark(n): + points = [None] * n + for i in range(n): + points[i] = Point(i) + for p in points: + p.normalize() + return maximize(points) + + +########################################################################### +# Benchmark interface + +bm_params = { + (50, 25): (1, 150), + (100, 100): (1, 250), + (1000, 1000): (10, 1500), + (5000, 1000): (20, 3000), +} + +def bm_setup(params): + state = None + def run(): + nonlocal state + for _ in range(params[0]): + state = benchmark(params[1]) + def result(): + return params[0] * params[1], 'Point(%.4f, %.4f, %.4f)' % (state.x, state.y, state.z) + return run, result diff --git a/tests/perf_bench/bm_hexiom.py b/tests/perf_bench/bm_hexiom.py new file mode 100644 index 0000000000..3a6f1f6c4b --- /dev/null +++ b/tests/perf_bench/bm_hexiom.py @@ -0,0 +1,647 @@ +# Source: https://github.com/python/pyperformance +# License: MIT + +# Solver of Hexiom board game. +# Benchmark from Laurent Vaucher. +# Source: https://github.com/slowfrog/hexiom : hexiom2.py, level36.txt +# (Main function tweaked by Armin Rigo.) + + +################################## +class Dir(object): + + def __init__(self, x, y): + self.x = x + self.y = y + + +DIRS = [Dir(1, 0), + Dir(-1, 0), + Dir(0, 1), + Dir(0, -1), + Dir(1, 1), + Dir(-1, -1)] + +EMPTY = 7 + +################################## + + +class Done(object): + MIN_CHOICE_STRATEGY = 0 + MAX_CHOICE_STRATEGY = 1 + HIGHEST_VALUE_STRATEGY = 2 + FIRST_STRATEGY = 3 + MAX_NEIGHBORS_STRATEGY = 4 + MIN_NEIGHBORS_STRATEGY = 5 + + def __init__(self, count, empty=False): + self.count = count + self.cells = None if empty else [ + [0, 1, 2, 3, 4, 5, 6, EMPTY] for i in range(count)] + + def clone(self): + ret = Done(self.count, True) + ret.cells = [self.cells[i][:] for i in range(self.count)] + return ret + + def __getitem__(self, i): + return self.cells[i] + + def set_done(self, i, v): + self.cells[i] = [v] + + def already_done(self, i): + return len(self.cells[i]) == 1 + + def remove(self, i, v): + if v in self.cells[i]: + self.cells[i].remove(v) + return True + else: + return False + + def remove_all(self, v): + for i in range(self.count): + self.remove(i, v) + + def remove_unfixed(self, v): + changed = False + for i in range(self.count): + if not self.already_done(i): + if self.remove(i, v): + changed = True + return changed + + def filter_tiles(self, tiles): + for v in range(8): + if tiles[v] == 0: + self.remove_all(v) + + def next_cell_min_choice(self): + minlen = 10 + mini = -1 + for i in range(self.count): + if 1 < len(self.cells[i]) < minlen: + minlen = len(self.cells[i]) + mini = i + return mini + + def next_cell_max_choice(self): + maxlen = 1 + maxi = -1 + for i in range(self.count): + if maxlen < len(self.cells[i]): + maxlen = len(self.cells[i]) + maxi = i + return maxi + + def next_cell_highest_value(self): + maxval = -1 + maxi = -1 + for i in range(self.count): + if (not self.already_done(i)): + maxvali = max(k for k in self.cells[i] if k != EMPTY) + if maxval < maxvali: + maxval = maxvali + maxi = i + return maxi + + def next_cell_first(self): + for i in range(self.count): + if (not self.already_done(i)): + return i + return -1 + + def next_cell_max_neighbors(self, pos): + maxn = -1 + maxi = -1 + for i in range(self.count): + if not self.already_done(i): + cells_around = pos.hex.get_by_id(i).links + n = sum(1 if (self.already_done(nid) and (self[nid][0] != EMPTY)) else 0 + for nid in cells_around) + if n > maxn: + maxn = n + maxi = i + return maxi + + def next_cell_min_neighbors(self, pos): + minn = 7 + mini = -1 + for i in range(self.count): + if not self.already_done(i): + cells_around = pos.hex.get_by_id(i).links + n = sum(1 if (self.already_done(nid) and (self[nid][0] != EMPTY)) else 0 + for nid in cells_around) + if n < minn: + minn = n + mini = i + return mini + + def next_cell(self, pos, strategy=HIGHEST_VALUE_STRATEGY): + if strategy == Done.HIGHEST_VALUE_STRATEGY: + return self.next_cell_highest_value() + elif strategy == Done.MIN_CHOICE_STRATEGY: + return self.next_cell_min_choice() + elif strategy == Done.MAX_CHOICE_STRATEGY: + return self.next_cell_max_choice() + elif strategy == Done.FIRST_STRATEGY: + return self.next_cell_first() + elif strategy == Done.MAX_NEIGHBORS_STRATEGY: + return self.next_cell_max_neighbors(pos) + elif strategy == Done.MIN_NEIGHBORS_STRATEGY: + return self.next_cell_min_neighbors(pos) + else: + raise Exception("Wrong strategy: %d" % strategy) + +################################## + + +class Node(object): + + def __init__(self, pos, id, links): + self.pos = pos + self.id = id + self.links = links + +################################## + + +class Hex(object): + + def __init__(self, size): + self.size = size + self.count = 3 * size * (size - 1) + 1 + self.nodes_by_id = self.count * [None] + self.nodes_by_pos = {} + id = 0 + for y in range(size): + for x in range(size + y): + pos = (x, y) + node = Node(pos, id, []) + self.nodes_by_pos[pos] = node + self.nodes_by_id[node.id] = node + id += 1 + for y in range(1, size): + for x in range(y, size * 2 - 1): + ry = size + y - 1 + pos = (x, ry) + node = Node(pos, id, []) + self.nodes_by_pos[pos] = node + self.nodes_by_id[node.id] = node + id += 1 + + def link_nodes(self): + for node in self.nodes_by_id: + (x, y) = node.pos + for dir in DIRS: + nx = x + dir.x + ny = y + dir.y + if self.contains_pos((nx, ny)): + node.links.append(self.nodes_by_pos[(nx, ny)].id) + + def contains_pos(self, pos): + return pos in self.nodes_by_pos + + def get_by_pos(self, pos): + return self.nodes_by_pos[pos] + + def get_by_id(self, id): + return self.nodes_by_id[id] + + +################################## +class Pos(object): + + def __init__(self, hex, tiles, done=None): + self.hex = hex + self.tiles = tiles + self.done = Done(hex.count) if done is None else done + + def clone(self): + return Pos(self.hex, self.tiles, self.done.clone()) + +################################## + + +def constraint_pass(pos, last_move=None): + changed = False + left = pos.tiles[:] + done = pos.done + + # Remove impossible values from free cells + free_cells = (range(done.count) if last_move is None + else pos.hex.get_by_id(last_move).links) + for i in free_cells: + if not done.already_done(i): + vmax = 0 + vmin = 0 + cells_around = pos.hex.get_by_id(i).links + for nid in cells_around: + if done.already_done(nid): + if done[nid][0] != EMPTY: + vmin += 1 + vmax += 1 + else: + vmax += 1 + + for num in range(7): + if (num < vmin) or (num > vmax): + if done.remove(i, num): + changed = True + + # Computes how many of each value is still free + for cell in done.cells: + if len(cell) == 1: + left[cell[0]] -= 1 + + for v in range(8): + # If there is none, remove the possibility from all tiles + if (pos.tiles[v] > 0) and (left[v] == 0): + if done.remove_unfixed(v): + changed = True + else: + possible = sum((1 if v in cell else 0) for cell in done.cells) + # If the number of possible cells for a value is exactly the number of available tiles + # put a tile in each cell + if pos.tiles[v] == possible: + for i in range(done.count): + cell = done.cells[i] + if (not done.already_done(i)) and (v in cell): + done.set_done(i, v) + changed = True + + # Force empty or non-empty around filled cells + filled_cells = (range(done.count) if last_move is None + else [last_move]) + for i in filled_cells: + if done.already_done(i): + num = done[i][0] + empties = 0 + filled = 0 + unknown = [] + cells_around = pos.hex.get_by_id(i).links + for nid in cells_around: + if done.already_done(nid): + if done[nid][0] == EMPTY: + empties += 1 + else: + filled += 1 + else: + unknown.append(nid) + if len(unknown) > 0: + if num == filled: + for u in unknown: + if EMPTY in done[u]: + done.set_done(u, EMPTY) + changed = True + # else: + # raise Exception("Houston, we've got a problem") + elif num == filled + len(unknown): + for u in unknown: + if done.remove(u, EMPTY): + changed = True + + return changed + + +ASCENDING = 1 +DESCENDING = -1 + + +def find_moves(pos, strategy, order): + done = pos.done + cell_id = done.next_cell(pos, strategy) + if cell_id < 0: + return [] + + if order == ASCENDING: + return [(cell_id, v) for v in done[cell_id]] + else: + # Try higher values first and EMPTY last + moves = list(reversed([(cell_id, v) + for v in done[cell_id] if v != EMPTY])) + if EMPTY in done[cell_id]: + moves.append((cell_id, EMPTY)) + return moves + + +def play_move(pos, move): + (cell_id, i) = move + pos.done.set_done(cell_id, i) + + +def print_pos(pos, output): + hex = pos.hex + done = pos.done + size = hex.size + for y in range(size): + print(" " * (size - y - 1), end="", file=output) + for x in range(size + y): + pos2 = (x, y) + id = hex.get_by_pos(pos2).id + if done.already_done(id): + c = done[id][0] if done[id][0] != EMPTY else "." + else: + c = "?" + print("%s " % c, end="", file=output) + print(end="\n", file=output) + for y in range(1, size): + print(" " * y, end="", file=output) + for x in range(y, size * 2 - 1): + ry = size + y - 1 + pos2 = (x, ry) + id = hex.get_by_pos(pos2).id + if done.already_done(id): + c = done[id][0] if done[id][0] != EMPTY else "." + else: + c = "?" + print("%s " % c, end="", file=output) + print(end="\n", file=output) + + +OPEN = 0 +SOLVED = 1 +IMPOSSIBLE = -1 + + +def solved(pos, output, verbose=False): + hex = pos.hex + tiles = pos.tiles[:] + done = pos.done + exact = True + all_done = True + for i in range(hex.count): + if len(done[i]) == 0: + return IMPOSSIBLE + elif done.already_done(i): + num = done[i][0] + tiles[num] -= 1 + if (tiles[num] < 0): + return IMPOSSIBLE + vmax = 0 + vmin = 0 + if num != EMPTY: + cells_around = hex.get_by_id(i).links + for nid in cells_around: + if done.already_done(nid): + if done[nid][0] != EMPTY: + vmin += 1 + vmax += 1 + else: + vmax += 1 + + if (num < vmin) or (num > vmax): + return IMPOSSIBLE + if num != vmin: + exact = False + else: + all_done = False + + if (not all_done) or (not exact): + return OPEN + + print_pos(pos, output) + return SOLVED + + +def solve_step(prev, strategy, order, output, first=False): + if first: + pos = prev.clone() + while constraint_pass(pos): + pass + else: + pos = prev + + moves = find_moves(pos, strategy, order) + if len(moves) == 0: + return solved(pos, output) + else: + for move in moves: + # print("Trying (%d, %d)" % (move[0], move[1])) + ret = OPEN + new_pos = pos.clone() + play_move(new_pos, move) + # print_pos(new_pos) + while constraint_pass(new_pos, move[0]): + pass + cur_status = solved(new_pos, output) + if cur_status != OPEN: + ret = cur_status + else: + ret = solve_step(new_pos, strategy, order, output) + if ret == SOLVED: + return SOLVED + return IMPOSSIBLE + + +def check_valid(pos): + hex = pos.hex + tiles = pos.tiles + # fill missing entries in tiles + tot = 0 + for i in range(8): + if tiles[i] > 0: + tot += tiles[i] + else: + tiles[i] = 0 + # check total + if tot != hex.count: + raise Exception( + "Invalid input. Expected %d tiles, got %d." % (hex.count, tot)) + + +def solve(pos, strategy, order, output): + check_valid(pos) + return solve_step(pos, strategy, order, output, first=True) + + +# TODO Write an 'iterator' to go over all x,y positions + +def read_file(file): + lines = [line.strip("\r\n") for line in file.splitlines()] + size = int(lines[0]) + hex = Hex(size) + linei = 1 + tiles = 8 * [0] + done = Done(hex.count) + for y in range(size): + line = lines[linei][size - y - 1:] + p = 0 + for x in range(size + y): + tile = line[p:p + 2] + p += 2 + if tile[1] == ".": + inctile = EMPTY + else: + inctile = int(tile) + tiles[inctile] += 1 + # Look for locked tiles + if tile[0] == "+": + # print("Adding locked tile: %d at pos %d, %d, id=%d" % + # (inctile, x, y, hex.get_by_pos((x, y)).id)) + done.set_done(hex.get_by_pos((x, y)).id, inctile) + + linei += 1 + for y in range(1, size): + ry = size - 1 + y + line = lines[linei][y:] + p = 0 + for x in range(y, size * 2 - 1): + tile = line[p:p + 2] + p += 2 + if tile[1] == ".": + inctile = EMPTY + else: + inctile = int(tile) + tiles[inctile] += 1 + # Look for locked tiles + if tile[0] == "+": + # print("Adding locked tile: %d at pos %d, %d, id=%d" % + # (inctile, x, ry, hex.get_by_pos((x, ry)).id)) + done.set_done(hex.get_by_pos((x, ry)).id, inctile) + linei += 1 + hex.link_nodes() + done.filter_tiles(tiles) + return Pos(hex, tiles, done) + + +def solve_file(file, strategy, order, output): + pos = read_file(file) + solve(pos, strategy, order, output) + + +LEVELS = {} + +LEVELS[2] = (""" +2 + . 1 + . 1 1 + 1 . +""", """\ + 1 1 +. . . + 1 1 +""") + +LEVELS[10] = (""" +3 + +.+. . + +. 0 . 2 + . 1+2 1 . + 2 . 0+. + .+.+. +""", """\ + . . 1 + . 1 . 2 +0 . 2 2 . + . . . . + 0 . . +""") + +LEVELS[20] = (""" +3 + . 5 4 + . 2+.+1 + . 3+2 3 . + +2+. 5 . + . 3 . +""", """\ + 3 3 2 + 4 5 . 1 +3 5 2 . . + 2 . . . + . . . +""") + +LEVELS[25] = (""" +3 + 4 . . + . . 2 . + 4 3 2 . 4 + 2 2 3 . + 4 2 4 +""", """\ + 3 4 2 + 2 4 4 . +. . . 4 2 + . 2 4 3 + . 2 . +""") + +LEVELS[30] = (""" +4 + 5 5 . . + 3 . 2+2 6 + 3 . 2 . 5 . + . 3 3+4 4 . 3 + 4 5 4 . 5 4 + 5+2 . . 3 + 4 . . . +""", """\ + 3 4 3 . + 4 6 5 2 . + 2 5 5 . . 2 +. . 5 4 . 4 3 + . 3 5 4 5 4 + . 2 . 3 3 + . . . . +""") + +LEVELS[36] = (""" +4 + 2 1 1 2 + 3 3 3 . . + 2 3 3 . 4 . + . 2 . 2 4 3 2 + 2 2 . . . 2 + 4 3 4 . . + 3 2 3 3 +""", """\ + 3 4 3 2 + 3 4 4 . 3 + 2 . . 3 4 3 +2 . 1 . 3 . 2 + 3 3 . 2 . 2 + 3 . 2 . 2 + 2 2 . 1 +""") + + +########################################################################### +# Benchmark interface + +bm_params = { + (100, 100): (1, 10, DESCENDING, Done.FIRST_STRATEGY), + (1000, 1000): (1, 25, DESCENDING, Done.FIRST_STRATEGY), + (5000, 1000): (10, 25, DESCENDING, Done.FIRST_STRATEGY), +} + +def bm_setup(params): + try: + import uio as io + except ImportError: + import io + + loops, level, order, strategy = params + + board, solution = LEVELS[level] + board = board.strip() + expected = solution.rstrip() + output = None + + def run(): + nonlocal output + for _ in range(loops): + stream = io.StringIO() + solve_file(board, strategy, order, stream) + output = stream.getvalue() + stream = None + + def result(): + norm = params[0] * params[1] + out = '\n'.join(line.rstrip() for line in output.splitlines()) + return norm, ((out == expected), out) + + return run, result diff --git a/tests/perf_bench/bm_nqueens.py b/tests/perf_bench/bm_nqueens.py new file mode 100644 index 0000000000..87e7245c04 --- /dev/null +++ b/tests/perf_bench/bm_nqueens.py @@ -0,0 +1,62 @@ +# Source: https://github.com/python/pyperformance +# License: MIT + +# Simple, brute-force N-Queens solver. +# author: collinwinter@google.com (Collin Winter) +# n_queens function: Copyright 2009 Raymond Hettinger + +# Pure-Python implementation of itertools.permutations(). +def permutations(iterable, r=None): + """permutations(range(3), 2) --> (0,1) (0,2) (1,0) (1,2) (2,0) (2,1)""" + pool = tuple(iterable) + n = len(pool) + if r is None: + r = n + indices = list(range(n)) + cycles = list(range(n - r + 1, n + 1))[::-1] + yield tuple(pool[i] for i in indices[:r]) + while n: + for i in reversed(range(r)): + cycles[i] -= 1 + if cycles[i] == 0: + indices[i:] = indices[i + 1:] + indices[i:i + 1] + cycles[i] = n - i + else: + j = cycles[i] + indices[i], indices[-j] = indices[-j], indices[i] + yield tuple(pool[i] for i in indices[:r]) + break + else: + return + +# From http://code.activestate.com/recipes/576647/ +def n_queens(queen_count): + """N-Queens solver. + Args: queen_count: the number of queens to solve for, same as board size. + Yields: Solutions to the problem, each yielded value is a N-tuple. + """ + cols = range(queen_count) + for vec in permutations(cols): + if (queen_count == len(set(vec[i] + i for i in cols)) + == len(set(vec[i] - i for i in cols))): + yield vec + +########################################################################### +# Benchmark interface + +bm_params = { + (50, 25): (1, 5), + (100, 25): (1, 6), + (1000, 100): (1, 7), + (5000, 100): (1, 8), +} + +def bm_setup(params): + res = None + def run(): + nonlocal res + for _ in range(params[0]): + res = len(list(n_queens(params[1]))) + def result(): + return params[0] * 10 ** (params[1] - 3), res + return run, result diff --git a/tests/perf_bench/bm_pidigits.py b/tests/perf_bench/bm_pidigits.py new file mode 100644 index 0000000000..ca2e5297d0 --- /dev/null +++ b/tests/perf_bench/bm_pidigits.py @@ -0,0 +1,62 @@ +# Source: https://github.com/python/pyperformance +# License: MIT + +# Calculating some of the digits of Ï€. +# This benchmark stresses big integer arithmetic. +# Adapted from code on: http://benchmarksgame.alioth.debian.org/ + + +def compose(a, b): + aq, ar, as_, at = a + bq, br, bs, bt = b + return (aq * bq, + aq * br + ar * bt, + as_ * bq + at * bs, + as_ * br + at * bt) + + +def extract(z, j): + q, r, s, t = z + return (q * j + r) // (s * j + t) + + +def gen_pi_digits(n): + z = (1, 0, 0, 1) + k = 1 + digs = [] + for _ in range(n): + y = extract(z, 3) + while y != extract(z, 4): + z = compose(z, (k, 4 * k + 2, 0, 2 * k + 1)) + k += 1 + y = extract(z, 3) + z = compose((10, -10 * y, 0, 1), z) + digs.append(y) + return digs + + +########################################################################### +# Benchmark interface + +bm_params = { + (50, 25): (1, 35), + (100, 100): (1, 65), + (1000, 1000): (2, 250), + (5000, 1000): (3, 350), +} + +def bm_setup(params): + state = None + + def run(): + nonlocal state + nloop, ndig = params + ndig = params[1] + for _ in range(nloop): + state = None # free previous result + state = gen_pi_digits(ndig) + + def result(): + return params[0] * params[1], ''.join(str(d) for d in state) + + return run, result From 73c269414f41dac87122963dc1fc456442de8b85 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 26 Jun 2019 14:26:20 +1000 Subject: [PATCH 0467/1788] tests/perf_bench: Add some miscellaneous performance benchmarks. misc_aes.py and misc_mandel.py are adapted from sources in this repository. misc_pystone.py is the standard Python pystone test. misc_raytrace.py is written from scratch. --- tests/perf_bench/misc_aes.py | 225 +++++++++++++++++++++++++++ tests/perf_bench/misc_mandel.py | 31 ++++ tests/perf_bench/misc_pystone.py | 226 ++++++++++++++++++++++++++++ tests/perf_bench/misc_raytrace.py | 242 ++++++++++++++++++++++++++++++ 4 files changed, 724 insertions(+) create mode 100644 tests/perf_bench/misc_aes.py create mode 100644 tests/perf_bench/misc_mandel.py create mode 100644 tests/perf_bench/misc_pystone.py create mode 100644 tests/perf_bench/misc_raytrace.py diff --git a/tests/perf_bench/misc_aes.py b/tests/perf_bench/misc_aes.py new file mode 100644 index 0000000000..5413a06b12 --- /dev/null +++ b/tests/perf_bench/misc_aes.py @@ -0,0 +1,225 @@ +# Pure Python AES encryption routines. +# +# AES is integer based and inplace so doesn't use the heap. It is therefore +# a good test of raw performance and correctness of the VM/runtime. +# +# The AES code comes first (code originates from a C version authored by D.P.George) +# and then the test harness at the bottom. +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +################################################################## +# discrete arithmetic routines, mostly from a precomputed table + +# non-linear, invertible, substitution box +aes_s_box_table = bytes(( + 0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76, + 0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0, + 0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15, + 0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75, + 0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84, + 0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf, + 0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8, + 0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2, + 0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73, + 0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb, + 0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79, + 0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08, + 0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a, + 0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e, + 0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf, + 0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16, +)) + +# multiplication of polynomials modulo x^8 + x^4 + x^3 + x + 1 = 0x11b +def aes_gf8_mul_2(x): + if x & 0x80: + return (x << 1) ^ 0x11b + else: + return x << 1 + +def aes_gf8_mul_3(x): + return x ^ aes_gf8_mul_2(x) + +# non-linear, invertible, substitution box +def aes_s_box(a): + return aes_s_box_table[a & 0xff] + +# return 0x02^(a-1) in GF(2^8) +def aes_r_con(a): + ans = 1 + while a > 1: + ans <<= 1; + if ans & 0x100: + ans ^= 0x11b + a -= 1 + return ans + +################################################################## +# basic AES algorithm; see FIPS-197 + +# all inputs must be size 16 +def aes_add_round_key(state, w): + for i in range(16): + state[i] ^= w[i] + +# combined sub_bytes, shift_rows, mix_columns, add_round_key +# all inputs must be size 16 +def aes_sb_sr_mc_ark(state, w, w_idx, temp): + temp_idx = 0 + for i in range(4): + x0 = aes_s_box_table[state[i * 4]] + x1 = aes_s_box_table[state[1 + ((i + 1) & 3) * 4]] + x2 = aes_s_box_table[state[2 + ((i + 2) & 3) * 4]] + x3 = aes_s_box_table[state[3 + ((i + 3) & 3) * 4]] + temp[temp_idx] = aes_gf8_mul_2(x0) ^ aes_gf8_mul_3(x1) ^ x2 ^ x3 ^ w[w_idx] + temp[temp_idx + 1] = x0 ^ aes_gf8_mul_2(x1) ^ aes_gf8_mul_3(x2) ^ x3 ^ w[w_idx + 1] + temp[temp_idx + 2] = x0 ^ x1 ^ aes_gf8_mul_2(x2) ^ aes_gf8_mul_3(x3) ^ w[w_idx + 2] + temp[temp_idx + 3] = aes_gf8_mul_3(x0) ^ x1 ^ x2 ^ aes_gf8_mul_2(x3) ^ w[w_idx + 3] + w_idx += 4 + temp_idx += 4 + for i in range(16): + state[i] = temp[i] + +# combined sub_bytes, shift_rows, add_round_key +# all inputs must be size 16 +def aes_sb_sr_ark(state, w, w_idx, temp): + temp_idx = 0 + for i in range(4): + x0 = aes_s_box_table[state[i * 4]] + x1 = aes_s_box_table[state[1 + ((i + 1) & 3) * 4]] + x2 = aes_s_box_table[state[2 + ((i + 2) & 3) * 4]] + x3 = aes_s_box_table[state[3 + ((i + 3) & 3) * 4]] + temp[temp_idx] = x0 ^ w[w_idx] + temp[temp_idx + 1] = x1 ^ w[w_idx + 1] + temp[temp_idx + 2] = x2 ^ w[w_idx + 2] + temp[temp_idx + 3] = x3 ^ w[w_idx + 3] + w_idx += 4 + temp_idx += 4 + for i in range(16): + state[i] = temp[i] + +# take state as input and change it to the next state in the sequence +# state and temp have size 16, w has size 16 * (Nr + 1), Nr >= 1 +def aes_state(state, w, temp, nr): + aes_add_round_key(state, w) + w_idx = 16 + for i in range(nr - 1): + aes_sb_sr_mc_ark(state, w, w_idx, temp) + w_idx += 16 + aes_sb_sr_ark(state, w, w_idx, temp) + +# expand 'key' to 'w' for use with aes_state +# key has size 4 * Nk, w has size 16 * (Nr + 1), temp has size 16 +def aes_key_expansion(key, w, temp, nk, nr): + for i in range(4 * nk): + w[i] = key[i] + w_idx = 4 * nk - 4 + for i in range(nk, 4 * (nr + 1)): + t = temp + t_idx = 0 + if i % nk == 0: + t[0] = aes_s_box(w[w_idx + 1]) ^ aes_r_con(i // nk) + for j in range(1, 4): + t[j] = aes_s_box(w[w_idx + (j + 1) % 4]) + elif nk > 6 and i % nk == 4: + for j in range(0, 4): + t[j] = aes_s_box(w[w_idx + j]) + else: + t = w + t_idx = w_idx + w_idx += 4 + for j in range(4): + w[w_idx + j] = w[w_idx + j - 4 * nk] ^ t[t_idx + j] + +################################################################## +# simple use of AES algorithm, using output feedback (OFB) mode + +class AES: + def __init__(self, keysize): + if keysize == 128: + self.nk = 4 + self.nr = 10 + elif keysize == 192: + self.nk = 6 + self.nr = 12 + else: + assert keysize == 256 + self.nk = 8 + self.nr = 14 + + self.state = bytearray(16) + self.w = bytearray(16 * (self.nr + 1)) + self.temp = bytearray(16) + self.state_pos = 16 + + def set_key(self, key): + aes_key_expansion(key, self.w, self.temp, self.nk, self.nr) + self.state_pos = 16 + + def set_iv(self, iv): + for i in range(16): + self.state[i] = iv[i] + self.state_pos = 16; + + def get_some_state(self, n_needed): + if self.state_pos >= 16: + aes_state(self.state, self.w, self.temp, self.nr) + self.state_pos = 0 + n = 16 - self.state_pos + if n > n_needed: + n = n_needed + return n + + def apply_to(self, data): + idx = 0 + n = len(data) + while n > 0: + ln = self.get_some_state(n) + n -= ln + for i in range(ln): + data[idx + i] ^= self.state[self.state_pos + i] + idx += ln + self.state_pos += n + +########################################################################### +# Benchmark interface + +bm_params = { + (50, 25): (1, 16), + (100, 100): (1, 32), + (1000, 1000): (4, 256), + (5000, 1000): (20, 256), +} + +def bm_setup(params): + nloop, datalen = params + + aes = AES(256) + key = bytearray(256 // 8) + iv = bytearray(16) + data = bytearray(datalen) + # from now on we don't use the heap + + def run(): + for loop in range(nloop): + # encrypt + aes.set_key(key) + aes.set_iv(iv) + for i in range(2): + aes.apply_to(data) + + # decrypt + aes.set_key(key) + aes.set_iv(iv) + for i in range(2): + aes.apply_to(data) + + # verify + for i in range(len(data)): + assert data[i] == 0 + + def result(): + return params[0] * params[1], True + + return run, result diff --git a/tests/perf_bench/misc_mandel.py b/tests/perf_bench/misc_mandel.py new file mode 100644 index 0000000000..a4b789136d --- /dev/null +++ b/tests/perf_bench/misc_mandel.py @@ -0,0 +1,31 @@ +# Compute the Mandelbrot set, to test complex numbers + +def mandelbrot(w, h): + def in_set(c): + z = 0 + for i in range(32): + z = z * z + c + if abs(z) > 100: + return i + return 0 + + img = bytearray(w * h) + + xscale = ((w - 1) / 2.4) + yscale = ((h - 1) / 3.2) + for v in range(h): + line = memoryview(img)[v * w:v * w + w] + for u in range(w): + c = in_set(complex(v / yscale - 2.3, u / xscale - 1.2)) + line[u] = c + + return img + +bm_params = { + (100, 100): (20, 20), + (1000, 1000): (80, 80), + (5000, 1000): (150, 150), +} + +def bm_setup(ps): + return lambda: mandelbrot(ps[0], ps[1]), lambda: (ps[0] * ps[1], None) diff --git a/tests/perf_bench/misc_pystone.py b/tests/perf_bench/misc_pystone.py new file mode 100644 index 0000000000..88626774b2 --- /dev/null +++ b/tests/perf_bench/misc_pystone.py @@ -0,0 +1,226 @@ +""" +"PYSTONE" Benchmark Program + +Version: Python/1.2 (corresponds to C/1.1 plus 3 Pystone fixes) + +Author: Reinhold P. Weicker, CACM Vol 27, No 10, 10/84 pg. 1013. + + Translated from ADA to C by Rick Richardson. + Every method to preserve ADA-likeness has been used, + at the expense of C-ness. + + Translated from C to Python by Guido van Rossum. +""" + +__version__ = "1.2" + +[Ident1, Ident2, Ident3, Ident4, Ident5] = range(1, 6) + +class Record: + + def __init__(self, PtrComp = None, Discr = 0, EnumComp = 0, + IntComp = 0, StringComp = 0): + self.PtrComp = PtrComp + self.Discr = Discr + self.EnumComp = EnumComp + self.IntComp = IntComp + self.StringComp = StringComp + + def copy(self): + return Record(self.PtrComp, self.Discr, self.EnumComp, + self.IntComp, self.StringComp) + +TRUE = 1 +FALSE = 0 + +def Setup(): + global IntGlob + global BoolGlob + global Char1Glob + global Char2Glob + global Array1Glob + global Array2Glob + + IntGlob = 0 + BoolGlob = FALSE + Char1Glob = '\0' + Char2Glob = '\0' + Array1Glob = [0]*51 + Array2Glob = [x[:] for x in [Array1Glob]*51] + +def Proc0(loops): + global IntGlob + global BoolGlob + global Char1Glob + global Char2Glob + global Array1Glob + global Array2Glob + global PtrGlb + global PtrGlbNext + + PtrGlbNext = Record() + PtrGlb = Record() + PtrGlb.PtrComp = PtrGlbNext + PtrGlb.Discr = Ident1 + PtrGlb.EnumComp = Ident3 + PtrGlb.IntComp = 40 + PtrGlb.StringComp = "DHRYSTONE PROGRAM, SOME STRING" + String1Loc = "DHRYSTONE PROGRAM, 1'ST STRING" + Array2Glob[8][7] = 10 + + for i in range(loops): + Proc5() + Proc4() + IntLoc1 = 2 + IntLoc2 = 3 + String2Loc = "DHRYSTONE PROGRAM, 2'ND STRING" + EnumLoc = Ident2 + BoolGlob = not Func2(String1Loc, String2Loc) + while IntLoc1 < IntLoc2: + IntLoc3 = 5 * IntLoc1 - IntLoc2 + IntLoc3 = Proc7(IntLoc1, IntLoc2) + IntLoc1 = IntLoc1 + 1 + Proc8(Array1Glob, Array2Glob, IntLoc1, IntLoc3) + PtrGlb = Proc1(PtrGlb) + CharIndex = 'A' + while CharIndex <= Char2Glob: + if EnumLoc == Func1(CharIndex, 'C'): + EnumLoc = Proc6(Ident1) + CharIndex = chr(ord(CharIndex)+1) + IntLoc3 = IntLoc2 * IntLoc1 + IntLoc2 = IntLoc3 // IntLoc1 + IntLoc2 = 7 * (IntLoc3 - IntLoc2) - IntLoc1 + IntLoc1 = Proc2(IntLoc1) + +def Proc1(PtrParIn): + PtrParIn.PtrComp = NextRecord = PtrGlb.copy() + PtrParIn.IntComp = 5 + NextRecord.IntComp = PtrParIn.IntComp + NextRecord.PtrComp = PtrParIn.PtrComp + NextRecord.PtrComp = Proc3(NextRecord.PtrComp) + if NextRecord.Discr == Ident1: + NextRecord.IntComp = 6 + NextRecord.EnumComp = Proc6(PtrParIn.EnumComp) + NextRecord.PtrComp = PtrGlb.PtrComp + NextRecord.IntComp = Proc7(NextRecord.IntComp, 10) + else: + PtrParIn = NextRecord.copy() + NextRecord.PtrComp = None + return PtrParIn + +def Proc2(IntParIO): + IntLoc = IntParIO + 10 + while 1: + if Char1Glob == 'A': + IntLoc = IntLoc - 1 + IntParIO = IntLoc - IntGlob + EnumLoc = Ident1 + if EnumLoc == Ident1: + break + return IntParIO + +def Proc3(PtrParOut): + global IntGlob + + if PtrGlb is not None: + PtrParOut = PtrGlb.PtrComp + else: + IntGlob = 100 + PtrGlb.IntComp = Proc7(10, IntGlob) + return PtrParOut + +def Proc4(): + global Char2Glob + + BoolLoc = Char1Glob == 'A' + BoolLoc = BoolLoc or BoolGlob + Char2Glob = 'B' + +def Proc5(): + global Char1Glob + global BoolGlob + + Char1Glob = 'A' + BoolGlob = FALSE + +def Proc6(EnumParIn): + EnumParOut = EnumParIn + if not Func3(EnumParIn): + EnumParOut = Ident4 + if EnumParIn == Ident1: + EnumParOut = Ident1 + elif EnumParIn == Ident2: + if IntGlob > 100: + EnumParOut = Ident1 + else: + EnumParOut = Ident4 + elif EnumParIn == Ident3: + EnumParOut = Ident2 + elif EnumParIn == Ident4: + pass + elif EnumParIn == Ident5: + EnumParOut = Ident3 + return EnumParOut + +def Proc7(IntParI1, IntParI2): + IntLoc = IntParI1 + 2 + IntParOut = IntParI2 + IntLoc + return IntParOut + +def Proc8(Array1Par, Array2Par, IntParI1, IntParI2): + global IntGlob + + IntLoc = IntParI1 + 5 + Array1Par[IntLoc] = IntParI2 + Array1Par[IntLoc+1] = Array1Par[IntLoc] + Array1Par[IntLoc+30] = IntLoc + for IntIndex in range(IntLoc, IntLoc+2): + Array2Par[IntLoc][IntIndex] = IntLoc + Array2Par[IntLoc][IntLoc-1] = Array2Par[IntLoc][IntLoc-1] + 1 + Array2Par[IntLoc+20][IntLoc] = Array1Par[IntLoc] + IntGlob = 5 + +def Func1(CharPar1, CharPar2): + CharLoc1 = CharPar1 + CharLoc2 = CharLoc1 + if CharLoc2 != CharPar2: + return Ident1 + else: + return Ident2 + +def Func2(StrParI1, StrParI2): + IntLoc = 1 + while IntLoc <= 1: + if Func1(StrParI1[IntLoc], StrParI2[IntLoc+1]) == Ident1: + CharLoc = 'A' + IntLoc = IntLoc + 1 + if CharLoc >= 'W' and CharLoc <= 'Z': + IntLoc = 7 + if CharLoc == 'X': + return TRUE + else: + if StrParI1 > StrParI2: + IntLoc = IntLoc + 7 + return TRUE + else: + return FALSE + +def Func3(EnumParIn): + EnumLoc = EnumParIn + if EnumLoc == Ident3: return TRUE + return FALSE + + +########################################################################### +# Benchmark interface + +bm_params = { + (50, 10): (80,), + (100, 10): (300,), + (1000, 10): (4000,), + (5000, 10): (20000,), +} + +def bm_setup(params): + Setup() + return lambda: Proc0(params[0]), lambda: (params[0], 0) diff --git a/tests/perf_bench/misc_raytrace.py b/tests/perf_bench/misc_raytrace.py new file mode 100644 index 0000000000..76d4194bce --- /dev/null +++ b/tests/perf_bench/misc_raytrace.py @@ -0,0 +1,242 @@ +# A simple ray tracer +# MIT license; Copyright (c) 2019 Damien P. George + +INF = 1e30 +EPS = 1e-6 + +class Vec: + def __init__(self, x, y, z): + self.x, self.y, self.z = x, y, z + + def __neg__(self): + return Vec(-self.x, -self.y, -self.z) + + def __add__(self, rhs): + return Vec(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z) + + def __sub__(self, rhs): + return Vec(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z) + + def __mul__(self, rhs): + return Vec(self.x * rhs, self.y * rhs, self.z * rhs) + + def length(self): + return (self.x ** 2 + self.y ** 2 + self.z ** 2) ** 0.5 + + def normalise(self): + l = self.length() + return Vec(self.x / l, self.y / l, self.z / l) + + def dot(self, rhs): + return self.x * rhs.x + self.y * rhs.y + self.z * rhs.z + +RGB = Vec + +class Ray: + def __init__(self, p, d): + self.p, self.d = p, d + +class View: + def __init__(self, width, height, depth, pos, xdir, ydir, zdir): + self.width = width + self.height = height + self.depth = depth + self.pos = pos + self.xdir = xdir + self.ydir = ydir + self.zdir = zdir + + def calc_dir(self, dx, dy): + return (self.xdir * dx + self.ydir * dy + self.zdir * self.depth).normalise() + +class Light: + def __init__(self, pos, colour, casts_shadows): + self.pos = pos + self.colour = colour + self.casts_shadows = casts_shadows + +class Surface: + def __init__(self, diffuse, specular, spec_idx, reflect, transp, colour): + self.diffuse = diffuse + self.specular = specular + self.spec_idx = spec_idx + self.reflect = reflect + self.transp = transp + self.colour = colour + + @staticmethod + def dull(colour): + return Surface(0.7, 0.0, 1, 0.0, 0.0, colour * 0.6) + + @staticmethod + def shiny(colour): + return Surface(0.2, 0.9, 32, 0.8, 0.0, colour * 0.3) + + @staticmethod + def transparent(colour): + return Surface(0.2, 0.9, 32, 0.0, 0.8, colour * 0.3) + +class Sphere: + def __init__(self, surface, centre, radius): + self.surface = surface + self.centre = centre + self.radsq = radius ** 2 + + def intersect(self, ray): + v = self.centre - ray.p + b = v.dot(ray.d) + det = b ** 2 - v.dot(v) + self.radsq + if det > 0: + det **= 0.5 + t1 = b - det + if t1 > EPS: + return t1 + t2 = b + det + if t2 > EPS: + return t2 + return INF + + def surface_at(self, v): + return self.surface, (v - self.centre).normalise() + +class Plane: + def __init__(self, surface, centre, normal): + self.surface = surface + self.normal = normal.normalise() + self.cdotn = centre.dot(normal) + + def intersect(self, ray): + ddotn = ray.d.dot(self.normal) + if abs(ddotn) > EPS: + t = (self.cdotn - ray.p.dot(self.normal)) / ddotn + if t > 0: + return t + return INF + + def surface_at(self, p): + return self.surface, self.normal + +class Scene: + def __init__(self, ambient, light, objs): + self.ambient = ambient + self.light = light + self.objs = objs + +def trace_scene(canvas, view, scene, max_depth): + for v in range(canvas.height): + y = (-v + 0.5 * (canvas.height - 1)) * view.height / canvas.height + for u in range(canvas.width): + x = (u - 0.5 * (canvas.width - 1)) * view.width / canvas.width + ray = Ray(view.pos, view.calc_dir(x, y)) + c = trace_ray(scene, ray, max_depth) + canvas.put_pix(u, v, c) + +def trace_ray(scene, ray, depth): + # Find closest intersecting object + hit_t = INF + hit_obj = None + for obj in scene.objs: + t = obj.intersect(ray) + if t < hit_t: + hit_t = t + hit_obj = obj + + # Check if any objects hit + if hit_obj is None: + return RGB(0, 0, 0) + + # Compute location of ray intersection + point = ray.p + ray.d * hit_t + surf, surf_norm = hit_obj.surface_at(point) + if ray.d.dot(surf_norm) > 0: + surf_norm = -surf_norm + + # Compute reflected ray + reflected = ray.d - surf_norm * (surf_norm.dot(ray.d) * 2) + + # Ambient light + col = surf.colour * scene.ambient + + # Diffuse, specular and shadow from light source + light_vec = scene.light.pos - point + light_dist = light_vec.length() + light_vec = light_vec.normalise() + ndotl = surf_norm.dot(light_vec) + ldotv = light_vec.dot(reflected) + if ndotl > 0 or ldotv > 0: + light_ray = Ray(point + light_vec * EPS, light_vec) + light_col = trace_to_light(scene, light_ray, light_dist) + if ndotl > 0: + col += light_col * surf.diffuse * ndotl + if ldotv > 0: + col += light_col * surf.specular * ldotv ** surf.spec_idx + + # Reflections + if depth > 0 and surf.reflect > 0: + col += trace_ray(scene, Ray(point + reflected * EPS, reflected), depth - 1) * surf.reflect + + # Transparency + if depth > 0 and surf.transp > 0: + col += trace_ray(scene, Ray(point + ray.d * EPS, ray.d), depth - 1) * surf.transp + + return col + +def trace_to_light(scene, ray, light_dist): + col = scene.light.colour + for obj in scene.objs: + t = obj.intersect(ray) + if t < light_dist: + col *= obj.surface.transp + return col + +class Canvas: + def __init__(self, width, height): + self.width = width + self.height = height + self.data = bytearray(3 * width * height) + + def put_pix(self, x, y, c): + off = 3 * (y * self.width + x) + self.data[off] = min(255, max(0, int(255 * c.x))) + self.data[off + 1] = min(255, max(0, int(255 * c.y))) + self.data[off + 2] = min(255, max(0, int(255 * c.z))) + + def write_ppm(self, filename): + with open(filename, 'wb') as f: + f.write(bytes('P6 %d %d 255\n' % (self.width, self.height), 'ascii')) + f.write(self.data) + +def main(w, h, d): + canvas = Canvas(w, h) + view = View(32, 32, 64, Vec(0, 0, 50), Vec(1, 0, 0), Vec(0, 1, 0), Vec(0, 0, -1)) + scene = Scene( + 0.5, + Light(Vec(0, 8, 0), RGB(1, 1, 1), True), + [ + Plane(Surface.dull(RGB(1, 0, 0)), Vec(-10, 0, 0), Vec(1, 0, 0)), + Plane(Surface.dull(RGB(0, 1, 0)), Vec(10, 0, 0), Vec(-1, 0, 0)), + Plane(Surface.dull(RGB(1, 1, 1)), Vec(0, 0, -10), Vec(0, 0, 1)), + Plane(Surface.dull(RGB(1, 1, 1)), Vec(0, -10, 0), Vec(0, 1, 0)), + Plane(Surface.dull(RGB(1, 1, 1)), Vec(0, 10, 0), Vec(0, -1, 0)), + Sphere(Surface.shiny(RGB(1, 1, 1)), Vec(-5, -4, 3), 4), + Sphere(Surface.dull(RGB(0, 0, 1)), Vec(4, -5, 0), 4), + Sphere(Surface.transparent(RGB(0.2, 0.2, 0.2)), Vec(6, -1, 8), 4), + ] + ) + trace_scene(canvas, view, scene, d) + return canvas + +# For testing +#main(256, 256, 4).write_ppm('rt.ppm') + +########################################################################### +# Benchmark interface + +bm_params = { + (100, 100): (5, 5, 2), + (1000, 100): (18, 18, 3), + (5000, 100): (40, 40, 3), +} + +def bm_setup(params): + return lambda: main(*params), lambda: (params[0] * params[1] * params[2], None) From 73fccf59672c7087d6290bb036fe5c72899086b6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 26 Jun 2019 14:27:32 +1000 Subject: [PATCH 0468/1788] tests/perf_bench: Add some viper performance benchmarks. To test raw viper function call overhead: function entry, exit and conversion of arguments to/from objects. --- tests/perf_bench/viper_call0.py | 19 +++++++++++++++++++ tests/perf_bench/viper_call1a.py | 19 +++++++++++++++++++ tests/perf_bench/viper_call1b.py | 19 +++++++++++++++++++ tests/perf_bench/viper_call1c.py | 19 +++++++++++++++++++ tests/perf_bench/viper_call2a.py | 19 +++++++++++++++++++ tests/perf_bench/viper_call2b.py | 19 +++++++++++++++++++ 6 files changed, 114 insertions(+) create mode 100644 tests/perf_bench/viper_call0.py create mode 100644 tests/perf_bench/viper_call1a.py create mode 100644 tests/perf_bench/viper_call1b.py create mode 100644 tests/perf_bench/viper_call1c.py create mode 100644 tests/perf_bench/viper_call2a.py create mode 100644 tests/perf_bench/viper_call2b.py diff --git a/tests/perf_bench/viper_call0.py b/tests/perf_bench/viper_call0.py new file mode 100644 index 0000000000..0f476b127b --- /dev/null +++ b/tests/perf_bench/viper_call0.py @@ -0,0 +1,19 @@ +@micropython.viper +def f0(): + pass + +@micropython.native +def call(r): + f = f0 + for _ in r: + f() + +bm_params = { + (50, 10): (15000,), + (100, 10): (30000,), + (1000, 10): (300000,), + (5000, 10): (1500000,), +} + +def bm_setup(params): + return lambda: call(range(params[0])), lambda: (params[0] // 1000, None) diff --git a/tests/perf_bench/viper_call1a.py b/tests/perf_bench/viper_call1a.py new file mode 100644 index 0000000000..2bb4a28fd3 --- /dev/null +++ b/tests/perf_bench/viper_call1a.py @@ -0,0 +1,19 @@ +@micropython.viper +def f1a(x): + return x + +@micropython.native +def call(r): + f = f1a + for _ in r: + f(1) + +bm_params = { + (50, 10): (15000,), + (100, 10): (30000,), + (1000, 10): (300000,), + (5000, 10): (1500000,), +} + +def bm_setup(params): + return lambda: call(range(params[0])), lambda: (params[0] // 1000, None) diff --git a/tests/perf_bench/viper_call1b.py b/tests/perf_bench/viper_call1b.py new file mode 100644 index 0000000000..cda64007fe --- /dev/null +++ b/tests/perf_bench/viper_call1b.py @@ -0,0 +1,19 @@ +@micropython.viper +def f1b(x) -> int: + return int(x) + +@micropython.native +def call(r): + f = f1b + for _ in r: + f(1) + +bm_params = { + (50, 10): (15000,), + (100, 10): (30000,), + (1000, 10): (300000,), + (5000, 10): (1500000,), +} + +def bm_setup(params): + return lambda: call(range(params[0])), lambda: (params[0] // 1000, None) diff --git a/tests/perf_bench/viper_call1c.py b/tests/perf_bench/viper_call1c.py new file mode 100644 index 0000000000..c653eb8d3e --- /dev/null +++ b/tests/perf_bench/viper_call1c.py @@ -0,0 +1,19 @@ +@micropython.viper +def f1c(x:int) -> int: + return x + +@micropython.native +def call(r): + f = f1c + for _ in r: + f(1) + +bm_params = { + (50, 10): (15000,), + (100, 10): (30000,), + (1000, 10): (300000,), + (5000, 10): (1500000,), +} + +def bm_setup(params): + return lambda: call(range(params[0])), lambda: (params[0] // 1000, None) diff --git a/tests/perf_bench/viper_call2a.py b/tests/perf_bench/viper_call2a.py new file mode 100644 index 0000000000..6204f985f9 --- /dev/null +++ b/tests/perf_bench/viper_call2a.py @@ -0,0 +1,19 @@ +@micropython.viper +def f2a(x, y): + return x + +@micropython.native +def call(r): + f = f2a + for _ in r: + f(1, 2) + +bm_params = { + (50, 10): (15000,), + (100, 10): (30000,), + (1000, 10): (300000,), + (5000, 10): (1500000,), +} + +def bm_setup(params): + return lambda: call(range(params[0])), lambda: (params[0] // 1000, None) diff --git a/tests/perf_bench/viper_call2b.py b/tests/perf_bench/viper_call2b.py new file mode 100644 index 0000000000..087cf8ab0c --- /dev/null +++ b/tests/perf_bench/viper_call2b.py @@ -0,0 +1,19 @@ +@micropython.viper +def f2b(x:int, y:int) -> int: + return x + y + +@micropython.native +def call(r): + f = f2b + for _ in r: + f(1, 2) + +bm_params = { + (50, 10): (15000,), + (100, 10): (30000,), + (1000, 10): (300000,), + (5000, 10): (1500000,), +} + +def bm_setup(params): + return lambda: call(range(params[0])), lambda: (params[0] // 1000, None) From 9cebead27600f86a73f3326b455dcfcb065afe5f Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 26 Jun 2019 14:29:06 +1000 Subject: [PATCH 0469/1788] travis: Enable performance benchmark tests on standard unix build. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index b71cabcc80..9fbdb1698e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -89,6 +89,7 @@ jobs: - make ${MAKEOPTS} -C ports/unix deplibs - make ${MAKEOPTS} -C ports/unix - make ${MAKEOPTS} -C ports/unix test + - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython ./run-perfbench.py 1000 1000) # unix nanbox - stage: test From 378659209778a1bde24e9b15793087023b02bbd9 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Mon, 13 May 2019 00:13:59 +1000 Subject: [PATCH 0470/1788] stm32/boards: Optimise flash and RAM allocation for L4 boards. Optimisations are: - Remove FLASH_ISR section since devices with a small flash sector erase size don't need special FLASH_ISR handling. This reduces flash image by approx 1.5k. - Make SRAM2 contiguous with SRAM1 where possible. - Simplify configuration of 2k RAM buffer used for flash filesystem. RAM changes with this commit: - L432: stack 6k -> 10k, bss + heap 42k -> 52k - L476: stack 16k -> 30k, bss + heap 80k -> 96k - L496: stack 206k -> 16k, bss + heap 112k -> 302k --- .../boards/B_L475E_IOT01A/mpconfigboard.mk | 6 ++-- ports/stm32/boards/LIMIFROG/mpconfigboard.mk | 4 +-- .../boards/NUCLEO_L476RG/mpconfigboard.mk | 5 ++-- .../boards/STM32L476DISC/mpconfigboard.mk | 4 +-- .../boards/STM32L496GDISC/mpconfigboard.mk | 4 +-- ports/stm32/boards/stm32l432.ld | 25 ++++++++++------ ports/stm32/boards/stm32l476xe.ld | 24 +++++++-------- ports/stm32/boards/stm32l476xg.ld | 24 +++++++-------- ports/stm32/boards/stm32l496xg.ld | 29 +++++++++---------- 9 files changed, 61 insertions(+), 64 deletions(-) diff --git a/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk b/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk index 55e443e919..137b6be23d 100644 --- a/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk +++ b/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk @@ -1,9 +1,7 @@ MCU_SERIES = l4 CMSIS_MCU = STM32L475xx # The stm32l475 does not have a LDC controller which is -# the only diffrence to the stm32l476 - so reuse some files. +# the only difference 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 +LD_FILES = boards/stm32l476xg.ld boards/common_basic.ld OPENOCD_CONFIG = boards/openocd_stm32l4.cfg diff --git a/ports/stm32/boards/LIMIFROG/mpconfigboard.mk b/ports/stm32/boards/LIMIFROG/mpconfigboard.mk index 2adc98f0b1..ef1ec93b0b 100644 --- a/ports/stm32/boards/LIMIFROG/mpconfigboard.mk +++ b/ports/stm32/boards/LIMIFROG/mpconfigboard.mk @@ -1,6 +1,4 @@ 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 +LD_FILES = boards/stm32l476xe.ld boards/common_basic.ld diff --git a/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk index 38ae5af212..10c69461c9 100644 --- a/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk @@ -1,6 +1,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 +LD_FILES = boards/stm32l476xg.ld boards/common_basic.ld +OPENOCD_CONFIG = boards/openocd_stm32l4.cfg diff --git a/ports/stm32/boards/STM32L476DISC/mpconfigboard.mk b/ports/stm32/boards/STM32L476DISC/mpconfigboard.mk index 2cad9e2e56..10c69461c9 100644 --- a/ports/stm32/boards/STM32L476DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32L476DISC/mpconfigboard.mk @@ -1,7 +1,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 +LD_FILES = boards/stm32l476xg.ld boards/common_basic.ld OPENOCD_CONFIG = boards/openocd_stm32l4.cfg diff --git a/ports/stm32/boards/STM32L496GDISC/mpconfigboard.mk b/ports/stm32/boards/STM32L496GDISC/mpconfigboard.mk index 3a61746556..a85635e306 100644 --- a/ports/stm32/boards/STM32L496GDISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32L496GDISC/mpconfigboard.mk @@ -1,7 +1,5 @@ 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 +LD_FILES = boards/stm32l496xg.ld boards/common_basic.ld OPENOCD_CONFIG = boards/openocd_stm32l4.cfg diff --git a/ports/stm32/boards/stm32l432.ld b/ports/stm32/boards/stm32l432.ld index 5558b13c89..4699543d66 100644 --- a/ports/stm32/boards/stm32l432.ld +++ b/ports/stm32/boards/stm32l432.ld @@ -5,23 +5,30 @@ /* Specify the memory areas */ MEMORY { - FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 256K - FLASH_TEXT (rx) : ORIGIN = 0x08000000, LENGTH = 256K - RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 48K - SRAM2 (xrw) : ORIGIN = 0x10000000, LENGTH = 16K + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 230K /* sectors 0-114 */ + FLASH_FS (r) : ORIGIN = 0x08060000, LENGTH = 26K /* sectors 115-127 */ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K /* SRAM1, 48K + SRAM2, 16K */ } /* 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 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) - _estack_reserve; -_sstack = _estack - 6K; /* tunable */ +/* Define the stack. The stack is full descending so begins just above last byte of RAM, + or bottom of FS cache.. Note that EABI requires the stack to be 8-byte aligned for a call. */ /* RAM extents for the garbage collector */ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); + +_ram_fs_cache_end = _ram_end; +_ram_fs_cache_start = _ram_fs_cache_end - 2K; /* fs cache = 2K */ + +_estack = _ram_fs_cache_start - _estack_reserve; +_sstack = _estack - 10K; /* stack = 10K */ + _heap_start = _ebss; /* heap starts just after statically allocated memory */ -_heap_end = _sstack; +_heap_end = _sstack; /* bss + heap = 52K, tunable by adjusting stack size */ + +_flash_fs_start = ORIGIN(FLASH_FS); +_flash_fs_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); diff --git a/ports/stm32/boards/stm32l476xe.ld b/ports/stm32/boards/stm32l476xe.ld index e4bcda1f16..6eaf71545d 100644 --- a/ports/stm32/boards/stm32l476xe.ld +++ b/ports/stm32/boards/stm32l476xe.ld @@ -5,31 +5,31 @@ /* Specify the memory areas */ MEMORY { - FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K - FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 16K /* sectors 0-7 */ - FLASH_TEXT (rx) : ORIGIN = 0x08004000, LENGTH = 368K /* sectors 8-191 */ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 384K /* sectors 0-191 */ 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 + SRAM2 (xrw) : ORIGIN = 0x10000000, LENGTH = 32K /* not contiguous with RAM */ } /* 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 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) - _estack_reserve; -_sstack = _estack - 16K; /* tunable */ +/* Define the stack. The stack is full descending so begins just above last byte of RAM, + or bottom of FS cache.. Note that EABI requires the stack to be 8-byte aligned for a call. */ /* RAM extents for the garbage collector */ -_ram_fs_cache_start = ORIGIN(FS_CACHE); -_ram_fs_cache_end = ORIGIN(FS_CACHE) + LENGTH(FS_CACHE); _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); + +_ram_fs_cache_end = ORIGIN(SRAM2) + LENGTH(SRAM2); /* fs_cache in SRAM2 */ +_ram_fs_cache_start = _ram_fs_cache_end - 2K; /* fs cache = 2K */ + +_estack = _ram_fs_cache_start - _estack_reserve; /* stack in SRAM2 */ +_sstack = ORIGIN(SRAM2); /* stack = 30K */ + _heap_start = _ebss; /* heap starts just after statically allocated memory */ -_heap_end = _sstack; +_heap_end = _ram_end; /* bss + heap = 96K, tunable by adjusting stack size */ _flash_fs_start = ORIGIN(FLASH_FS); _flash_fs_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); diff --git a/ports/stm32/boards/stm32l476xg.ld b/ports/stm32/boards/stm32l476xg.ld index 9fe83c74a4..09c3f29c54 100644 --- a/ports/stm32/boards/stm32l476xg.ld +++ b/ports/stm32/boards/stm32l476xg.ld @@ -5,31 +5,31 @@ /* 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 = 496K /* sectors 8-255 */ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K /* sectors 0-255 */ 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 + SRAM2 (xrw) : ORIGIN = 0x10000000, LENGTH = 32K /* not contiguous with RAM */ } /* 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 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) - _estack_reserve; -_sstack = _estack - 16K; /* tunable */ +/* Define the stack. The stack is full descending so begins just above last byte of RAM, + or bottom of FS cache.. Note that EABI requires the stack to be 8-byte aligned for a call. */ /* RAM extents for the garbage collector */ -_ram_fs_cache_start = ORIGIN(FS_CACHE); -_ram_fs_cache_end = ORIGIN(FS_CACHE) + LENGTH(FS_CACHE); _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); + +_ram_fs_cache_end = ORIGIN(SRAM2) + LENGTH(SRAM2); /* fs_cache in SRAM2 */ +_ram_fs_cache_start = _ram_fs_cache_end - 2K; /* fs cache = 2K */ + +_estack = _ram_fs_cache_start - _estack_reserve; /* stack in SRAM2 */ +_sstack = ORIGIN(SRAM2); /* stack = 30K */ + _heap_start = _ebss; /* heap starts just after statically allocated memory */ -_heap_end = _sstack; +_heap_end = _ram_end; /* bss + heap = 96K, tunable by adjusting stack size */ _flash_fs_start = ORIGIN(FLASH_FS); _flash_fs_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); diff --git a/ports/stm32/boards/stm32l496xg.ld b/ports/stm32/boards/stm32l496xg.ld index c339903422..327cb5ce13 100644 --- a/ports/stm32/boards/stm32l496xg.ld +++ b/ports/stm32/boards/stm32l496xg.ld @@ -5,31 +5,30 @@ /* 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 + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 612K /* sectors 0-305 */ + FLASH_FS (r) : ORIGIN = 0x08099000, LENGTH = 412K /* sectors 306-511 412 KiB */ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 320K /* SRAM1, 256K + SRAM2, 64K */ } /* 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 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) - _estack_reserve; -_sstack = _estack - 206K; /* tunable */ +/* Define the stack. The stack is full descending so begins just above last byte of RAM, + or bottom of FS cache.. Note that EABI requires the stack to be 8-byte aligned for a call. */ /* RAM extents for the garbage collector */ -_ram_fs_cache_start = ORIGIN(FS_CACHE); -_ram_fs_cache_end = ORIGIN(FS_CACHE) + LENGTH(FS_CACHE); _ram_start = ORIGIN(RAM); -_ram_end = ORIGIN(RAM) + LENGTH(RAM) + LENGTH(SRAM2); +_ram_end = ORIGIN(RAM) + LENGTH(RAM); + +_ram_fs_cache_end = _ram_end; +_ram_fs_cache_start = _ram_fs_cache_end - 2K; /* fs cache = 2K */ + +_estack = _ram_fs_cache_start - _estack_reserve; +_sstack = _estack - 16K; /* stack = 16K */ + _heap_start = _ebss; /* heap starts just after statically allocated memory */ -_heap_end = _sstack; +_heap_end = _sstack; /* bss + heap = 302K, tunable by adjusting stack size */ _flash_fs_start = ORIGIN(FLASH_FS); _flash_fs_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); From b7da67cdaaf32317cfc9a3940bd58f2aab4976c9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 19 Jun 2019 14:02:08 +1000 Subject: [PATCH 0471/1788] lib/utils/sys_stdio_mphal: Add support to poll sys.stdin and sys.stdout. A port must provide the following function for this to work: uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags); --- lib/utils/sys_stdio_mphal.c | 14 +++++++++++++- py/mphal.h | 4 ++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/utils/sys_stdio_mphal.c b/lib/utils/sys_stdio_mphal.c index 234db0829b..3fcaf8e598 100644 --- a/lib/utils/sys_stdio_mphal.c +++ b/lib/utils/sys_stdio_mphal.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013-2017 Damien P. George + * Copyright (c) 2013-2019 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 @@ -85,6 +85,16 @@ STATIC mp_uint_t stdio_write(mp_obj_t self_in, const void *buf, mp_uint_t size, } } +STATIC mp_uint_t stdio_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + (void)self_in; + if (request == MP_STREAM_POLL) { + return mp_hal_stdio_poll(arg); + } else { + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } +} + STATIC mp_obj_t stdio_obj___exit__(size_t n_args, const mp_obj_t *args) { return mp_const_none; } @@ -112,6 +122,7 @@ STATIC MP_DEFINE_CONST_DICT(stdio_locals_dict, stdio_locals_dict_table); STATIC const mp_stream_p_t stdio_obj_stream_p = { .read = stdio_read, .write = stdio_write, + .ioctl = stdio_ioctl, .is_text = true, }; @@ -146,6 +157,7 @@ STATIC mp_uint_t stdio_buffer_write(mp_obj_t self_in, const void *buf, mp_uint_t STATIC const mp_stream_p_t stdio_buffer_obj_stream_p = { .read = stdio_buffer_read, .write = stdio_buffer_write, + .ioctl = stdio_ioctl, .is_text = false, }; diff --git a/py/mphal.h b/py/mphal.h index 92de01d08b..66d80705a6 100644 --- a/py/mphal.h +++ b/py/mphal.h @@ -34,6 +34,10 @@ #include #endif +#ifndef mp_hal_stdio_poll +uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags); +#endif + #ifndef mp_hal_stdin_rx_chr int mp_hal_stdin_rx_chr(void); #endif From 964ae328cd00260d9a017a4e67909694fded9902 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 24 Jun 2019 16:20:33 +1000 Subject: [PATCH 0472/1788] extmod/uos_dupterm: Add mp_uos_dupterm_poll to poll all dupterms. --- extmod/misc.h | 1 + extmod/uos_dupterm.c | 41 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/extmod/misc.h b/extmod/misc.h index dae6bec4a1..40b091e5f7 100644 --- a/extmod/misc.h +++ b/extmod/misc.h @@ -36,6 +36,7 @@ MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_uos_dupterm_obj); #if MICROPY_PY_OS_DUPTERM bool mp_uos_dupterm_is_builtin_stream(mp_const_obj_t stream); +uintptr_t mp_uos_dupterm_poll(uintptr_t poll_flags); int mp_uos_dupterm_rx_chr(void); void mp_uos_dupterm_tx_strn(const char *str, size_t len); void mp_uos_deactivate(size_t dupterm_idx, const char *msg, mp_obj_t exc); diff --git a/extmod/uos_dupterm.c b/extmod/uos_dupterm.c index 42cb21444b..9a8f0af4ed 100644 --- a/extmod/uos_dupterm.c +++ b/extmod/uos_dupterm.c @@ -4,7 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2016 Paul Sokolovsky - * Copyright (c) 2017 Damien P. George + * Copyright (c) 2017-2019 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 @@ -53,6 +53,45 @@ void mp_uos_deactivate(size_t dupterm_idx, const char *msg, mp_obj_t exc) { } } +uintptr_t mp_uos_dupterm_poll(uintptr_t poll_flags) { + uintptr_t poll_flags_out = 0; + + for (size_t idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) { + mp_obj_t s = MP_STATE_VM(dupterm_objs[idx]); + if (s == MP_OBJ_NULL) { + continue; + } + + int errcode = 0; + mp_uint_t ret = 0; + const mp_stream_p_t *stream_p = mp_get_stream(s); + #if MICROPY_PY_UOS_DUPTERM_BUILTIN_STREAM + if (mp_uos_dupterm_is_builtin_stream(s)) { + ret = stream_p->ioctl(s, MP_STREAM_POLL, poll_flags, &errcode); + } else + #endif + { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + ret = stream_p->ioctl(s, MP_STREAM_POLL, poll_flags, &errcode); + nlr_pop(); + } else { + // Ignore error with ioctl + } + } + + if (ret != MP_STREAM_ERROR) { + poll_flags_out |= ret; + if (poll_flags_out == poll_flags) { + // Finish early if all requested flags are set + break; + } + } + } + + return poll_flags_out; +} + int mp_uos_dupterm_rx_chr(void) { for (size_t idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) { if (MP_STATE_VM(dupterm_objs[idx]) == MP_OBJ_NULL) { From c80614dfc8b6454819380e4886d49dfd93193691 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 19 Jun 2019 14:02:38 +1000 Subject: [PATCH 0473/1788] ports: Provide mp_hal_stdio_poll for sys.stdio polling where needed. --- ports/cc3200/hal/cc3200_hal.h | 1 + ports/esp32/mphalport.c | 9 +++++++++ ports/esp8266/esp_mphal.c | 9 +++++++++ ports/pic16bit/pic16bit_mphal.c | 9 +++++++++ ports/stm32/mphalport.c | 11 +++++++++++ ports/teensy/teensy_hal.c | 14 ++++++++++++++ 6 files changed, 53 insertions(+) diff --git a/ports/cc3200/hal/cc3200_hal.h b/ports/cc3200/hal/cc3200_hal.h index 71e245eeb1..3d0d632d51 100644 --- a/ports/cc3200/hal/cc3200_hal.h +++ b/ports/cc3200/hal/cc3200_hal.h @@ -64,5 +64,6 @@ extern void HAL_SystemDeInit (void); extern void HAL_IncrementTick(void); extern void mp_hal_set_interrupt_char (int c); +#define mp_hal_stdio_poll(poll_flags) (0) // not implemented #define mp_hal_delay_us(usec) UtilsDelay(UTILS_DELAY_US_TO_COUNT(usec)) #define mp_hal_ticks_cpu() (SysTickPeriodGet() - SysTickValueGet()) diff --git a/ports/esp32/mphalport.c b/ports/esp32/mphalport.c index 804c719869..0d1ea74d6b 100644 --- a/ports/esp32/mphalport.c +++ b/ports/esp32/mphalport.c @@ -34,6 +34,7 @@ #include "rom/uart.h" #include "py/obj.h" +#include "py/stream.h" #include "py/mpstate.h" #include "py/mphal.h" #include "extmod/misc.h" @@ -45,6 +46,14 @@ TaskHandle_t mp_main_task_handle; STATIC uint8_t stdin_ringbuf_array[256]; ringbuf_t stdin_ringbuf = {stdin_ringbuf_array, sizeof(stdin_ringbuf_array)}; +uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) { + uintptr_t ret = 0; + if ((poll_flags & MP_STREAM_POLL_RD) && stdin_ringbuf.iget != stdin_ringbuf.iput) { + ret |= MP_STREAM_POLL_RD; + } + return ret; +} + int mp_hal_stdin_rx_chr(void) { for (;;) { int c = ringbuf_get(&stdin_ringbuf); diff --git a/ports/esp8266/esp_mphal.c b/ports/esp8266/esp_mphal.c index 351bf522c8..2ce288ea3f 100644 --- a/ports/esp8266/esp_mphal.c +++ b/ports/esp8266/esp_mphal.c @@ -32,6 +32,7 @@ #include "user_interface.h" #include "ets_alt_task.h" #include "py/runtime.h" +#include "py/stream.h" #include "extmod/misc.h" #include "lib/utils/pyexec.h" @@ -56,6 +57,14 @@ void mp_hal_delay_us(uint32_t us) { } } +uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) { + uintptr_t ret = 0; + if ((poll_flags & MP_STREAM_POLL_RD) && stdin_ringbuf.iget != stdin_ringbuf.iput) { + ret |= MP_STREAM_POLL_RD; + } + return ret; +} + int mp_hal_stdin_rx_chr(void) { for (;;) { int c = ringbuf_get(&stdin_ringbuf); diff --git a/ports/pic16bit/pic16bit_mphal.c b/ports/pic16bit/pic16bit_mphal.c index 35955f2d3e..adab381934 100644 --- a/ports/pic16bit/pic16bit_mphal.c +++ b/ports/pic16bit/pic16bit_mphal.c @@ -25,6 +25,7 @@ */ #include +#include "py/stream.h" #include "py/mphal.h" #include "board.h" @@ -51,6 +52,14 @@ void mp_hal_set_interrupt_char(int c) { interrupt_char = c; } +uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) { + uintptr_t ret = 0; + if ((poll_flags & MP_STREAM_POLL_RD) && uart_rx_any()) { + ret |= MP_STREAM_POLL_RD; + } + return ret; +} + int mp_hal_stdin_rx_chr(void) { for (;;) { if (uart_rx_any()) { diff --git a/ports/stm32/mphalport.c b/ports/stm32/mphalport.c index f4ae7293c8..79b28bd3de 100644 --- a/ports/stm32/mphalport.c +++ b/ports/stm32/mphalport.c @@ -1,6 +1,7 @@ #include #include "py/runtime.h" +#include "py/stream.h" #include "py/mperrno.h" #include "py/mphal.h" #include "extmod/misc.h" @@ -19,6 +20,16 @@ NORETURN void mp_hal_raise(HAL_StatusTypeDef status) { mp_raise_OSError(mp_hal_status_to_errno_table[status]); } +MP_WEAK uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) { + uintptr_t ret = 0; + if (MP_STATE_PORT(pyb_stdio_uart) != NULL) { + int errcode; + const mp_stream_p_t *stream_p = mp_get_stream(MP_STATE_PORT(pyb_stdio_uart)); + ret = stream_p->ioctl(MP_STATE_PORT(pyb_stdio_uart), MP_STREAM_POLL, poll_flags, &errcode); + } + return ret | mp_uos_dupterm_poll(poll_flags); +} + MP_WEAK int mp_hal_stdin_rx_chr(void) { for (;;) { #if 0 diff --git a/ports/teensy/teensy_hal.c b/ports/teensy/teensy_hal.c index 7ce82f1d2a..e9cc6778d5 100644 --- a/ports/teensy/teensy_hal.c +++ b/ports/teensy/teensy_hal.c @@ -2,6 +2,7 @@ #include #include "py/runtime.h" +#include "py/stream.h" #include "py/mphal.h" #include "usb.h" #include "uart.h" @@ -21,6 +22,19 @@ void mp_hal_set_interrupt_char(int c) { // you can't press Control-C and get your python script to stop. } +uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) { + uintptr_t ret = 0; + if (poll_flags & MP_STREAM_POLL_RD) { + if (usb_vcp_rx_num()) { + ret |= MP_STREAM_POLL_RD; + } + if (MP_STATE_PORT(pyb_stdio_uart) != NULL && uart_rx_any(MP_STATE_PORT(pyb_stdio_uart))) { + ret |= MP_STREAM_POLL_RD; + } + } + return ret; +} + int mp_hal_stdin_rx_chr(void) { for (;;) { byte c; From 875af757bd248dab636f06efd359f61ca91baeaa Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 22 Jun 2019 23:00:34 +1000 Subject: [PATCH 0474/1788] lib: Add asf4 as a submodule. --- .gitmodules | 3 +++ lib/asf4 | 1 + 2 files changed, 4 insertions(+) create mode 160000 lib/asf4 diff --git a/.gitmodules b/.gitmodules index 216a3b909c..25e7077cde 100644 --- a/.gitmodules +++ b/.gitmodules @@ -21,3 +21,6 @@ [submodule "lib/mbedtls"] path = lib/mbedtls url = https://github.com/ARMmbed/mbedtls.git +[submodule "lib/asf4"] + path = lib/asf4 + url = https://github.com/adafruit/asf4 diff --git a/lib/asf4 b/lib/asf4 new file mode 160000 index 0000000000..d270f79aa1 --- /dev/null +++ b/lib/asf4 @@ -0,0 +1 @@ +Subproject commit d270f79aa16dd8fd4ae3b6c14544283dcb992e9c From 258d10862df43c5a90ce8893ec44a627b155dd19 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 22 Jun 2019 23:01:31 +1000 Subject: [PATCH 0475/1788] lib: Add tinyusb as a submodule. --- .gitmodules | 3 +++ lib/tinyusb | 1 + 2 files changed, 4 insertions(+) create mode 160000 lib/tinyusb diff --git a/.gitmodules b/.gitmodules index 25e7077cde..544815b3a3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -24,3 +24,6 @@ [submodule "lib/asf4"] path = lib/asf4 url = https://github.com/adafruit/asf4 +[submodule "lib/tinyusb"] + path = lib/tinyusb + url = https://github.com/hathach/tinyusb diff --git a/lib/tinyusb b/lib/tinyusb new file mode 160000 index 0000000000..393492823c --- /dev/null +++ b/lib/tinyusb @@ -0,0 +1 @@ +Subproject commit 393492823ce037a2e46d367d61fad1235859af2e From f073f2b543683eeab6573b01b9152800660cd5cc Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 22 Jun 2019 23:01:55 +1000 Subject: [PATCH 0476/1788] tools: Add uf2conv.py from Microsoft/uf2 repository. Repository https://github.com/Microsoft/uf2 commit 19615407727073e36d81bf239c52108ba92e7660 --- tools/uf2conv.py | 319 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 319 insertions(+) create mode 100755 tools/uf2conv.py diff --git a/tools/uf2conv.py b/tools/uf2conv.py new file mode 100755 index 0000000000..2f2812abf9 --- /dev/null +++ b/tools/uf2conv.py @@ -0,0 +1,319 @@ +#!/usr/bin/env python3 + +# Microsoft UF2 +# +# The MIT License (MIT) +# +# Copyright (c) Microsoft Corporation +# +# All rights reserved. +# +# 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. + +import sys +import struct +import subprocess +import re +import os +import os.path +import argparse + + +UF2_MAGIC_START0 = 0x0A324655 # "UF2\n" +UF2_MAGIC_START1 = 0x9E5D5157 # Randomly selected +UF2_MAGIC_END = 0x0AB16F30 # Ditto + +families = { + 'SAMD21': 0x68ed2b88, + 'SAMD51': 0x55114460, + 'NRF52': 0x1b57745f, + 'STM32F1': 0x5ee21072, + 'STM32F4': 0x57755a57, + 'ATMEGA32': 0x16573617, +} + +INFO_FILE = "/INFO_UF2.TXT" + +appstartaddr = 0x2000 +familyid = 0x0 + + +def is_uf2(buf): + w = struct.unpack(" 476: + assert False, "Invalid UF2 data size at " + ptr + newaddr = hd[3] + if curraddr == None: + appstartaddr = newaddr + curraddr = newaddr + padding = newaddr - curraddr + if padding < 0: + assert False, "Block out of order at " + ptr + if padding > 10*1024*1024: + assert False, "More than 10M of padding needed at " + ptr + if padding % 4 != 0: + assert False, "Non-word padding size at " + ptr + while padding > 0: + padding -= 4 + outp += b"\x00\x00\x00\x00" + outp += block[32 : 32 + datalen] + curraddr = newaddr + datalen + return outp + +def convert_to_carray(file_content): + outp = "const unsigned char bindata[] __attribute__((aligned(16))) = {" + for i in range(len(file_content)): + if i % 16 == 0: + outp += "\n" + outp += "0x%02x, " % ord(file_content[i]) + outp += "\n};\n" + return outp + +def convert_to_uf2(file_content): + global familyid + datapadding = b"" + while len(datapadding) < 512 - 256 - 32 - 4: + datapadding += b"\x00\x00\x00\x00" + numblocks = (len(file_content) + 255) // 256 + outp = b"" + for blockno in range(numblocks): + ptr = 256 * blockno + chunk = file_content[ptr:ptr + 256] + flags = 0x0 + if familyid: + flags |= 0x2000 + hd = struct.pack(b"= 3 and words[1] == "2" and words[2] == "FAT": + drives.append(words[0]) + else: + rootpath = "/media" + if sys.platform == "darwin": + rootpath = "/Volumes" + elif sys.platform == "linux": + tmp = rootpath + "/" + os.environ["USER"] + if os.path.isdir(tmp): + rootpath = tmp + for d in os.listdir(rootpath): + drives.append(os.path.join(rootpath, d)) + + + def has_info(d): + try: + return os.path.isfile(d + INFO_FILE) + except: + return False + + return list(filter(has_info, drives)) + + +def board_id(path): + with open(path + INFO_FILE, mode='r') as file: + file_content = file.read() + return re.search("Board-ID: ([^\r\n]*)", file_content).group(1) + + +def list_drives(): + for d in get_drives(): + print(d, board_id(d)) + + +def write_file(name, buf): + with open(name, "wb") as f: + f.write(buf) + print("Wrote %d bytes to %s." % (len(buf), name)) + + +def main(): + global appstartaddr, familyid + def error(msg): + print(msg) + sys.exit(1) + parser = argparse.ArgumentParser(description='Convert to UF2 or flash directly.') + parser.add_argument('input', metavar='INPUT', type=str, nargs='?', + help='input file (HEX, BIN or UF2)') + parser.add_argument('-b' , '--base', dest='base', type=str, + default="0x2000", + help='set base address of application for BIN format (default: 0x2000)') + parser.add_argument('-o' , '--output', metavar="FILE", dest='output', type=str, + help='write output to named file; defaults to "flash.uf2" or "flash.bin" where sensible') + parser.add_argument('-d' , '--device', dest="device_path", + help='select a device path to flash') + parser.add_argument('-l' , '--list', action='store_true', + help='list connected devices') + parser.add_argument('-c' , '--convert', action='store_true', + help='do not flash, just convert') + parser.add_argument('-f' , '--family', dest='family', type=str, + default="0x0", + help='specify familyID - number or name (default: 0x0)') + parser.add_argument('-C' , '--carray', action='store_true', + help='convert binary file to a C array, not UF2') + args = parser.parse_args() + appstartaddr = int(args.base, 0) + + if args.family.upper() in families: + familyid = families[args.family.upper()] + else: + try: + familyid = int(args.family, 0) + except ValueError: + error("Family ID needs to be a number or one of: " + ", ".join(families.keys())) + + if args.list: + list_drives() + else: + if not args.input: + error("Need input file") + with open(args.input, mode='rb') as f: + inpbuf = f.read() + from_uf2 = is_uf2(inpbuf) + ext = "uf2" + if from_uf2: + outbuf = convert_from_uf2(inpbuf) + ext = "bin" + elif is_hex(inpbuf): + outbuf = convert_from_hex_to_uf2(inpbuf.decode("utf-8")) + elif args.carray: + outbuf = convert_to_carray(inpbuf) + ext = "h" + else: + outbuf = convert_to_uf2(inpbuf) + print("Converting to %s, output size: %d, start address: 0x%x" % + (ext, len(outbuf), appstartaddr)) + if args.convert: + drives = [] + if args.output == None: + args.output = "flash." + ext + else: + drives = get_drives() + + if args.output: + write_file(args.output, outbuf) + else: + if len(drives) == 0: + error("No drive to deploy.") + for d in drives: + print("Flashing %s (%s)" % (d, board_id(d))) + write_file(d + "/NEW.UF2", outbuf) + + +if __name__ == "__main__": + main() From 5f9bd11527cfa9b643ccd75841f2faf9918457dd Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 22 Jun 2019 23:03:41 +1000 Subject: [PATCH 0477/1788] samd: Add new port to Microchip SAMDxx microcontrollers. Initially supporting SAMD21 and SAMD51. --- ports/samd/Makefile | 100 +++++++ ports/samd/README.md | 7 + .../ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.mk | 4 + .../ADAFRUIT_ITSYBITSY_M4_EXPRESS/link.ld | 17 ++ .../mpconfigboard.h | 7 + .../samd/boards/ADAFRUIT_TRINKET_M0/board.mk | 4 + ports/samd/boards/ADAFRUIT_TRINKET_M0/link.ld | 17 ++ .../ADAFRUIT_TRINKET_M0/mpconfigboard.h | 2 + ports/samd/main.c | 98 +++++++ ports/samd/makefile | 12 + ports/samd/modmachine.c | 72 +++++ ports/samd/modutime.c | 47 ++++ ports/samd/mpconfigport.h | 109 ++++++++ ports/samd/mphalport.c | 112 ++++++++ ports/samd/mphalport.h | 39 +++ ports/samd/qstrdefsport.h | 1 + ports/samd/samd_isr.c | 252 ++++++++++++++++++ ports/samd/samd_soc.c | 152 +++++++++++ ports/samd/samd_soc.h | 53 ++++ ports/samd/sections.ld | 37 +++ ports/samd/tusb_config.h | 47 ++++ ports/samd/tusb_port.c | 146 ++++++++++ 22 files changed, 1335 insertions(+) create mode 100644 ports/samd/Makefile create mode 100644 ports/samd/README.md create mode 100644 ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.mk create mode 100644 ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/link.ld create mode 100644 ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.h create mode 100644 ports/samd/boards/ADAFRUIT_TRINKET_M0/board.mk create mode 100644 ports/samd/boards/ADAFRUIT_TRINKET_M0/link.ld create mode 100644 ports/samd/boards/ADAFRUIT_TRINKET_M0/mpconfigboard.h create mode 100644 ports/samd/main.c create mode 100644 ports/samd/makefile create mode 100644 ports/samd/modmachine.c create mode 100644 ports/samd/modutime.c create mode 100644 ports/samd/mpconfigport.h create mode 100644 ports/samd/mphalport.c create mode 100644 ports/samd/mphalport.h create mode 100644 ports/samd/qstrdefsport.h create mode 100644 ports/samd/samd_isr.c create mode 100644 ports/samd/samd_soc.c create mode 100644 ports/samd/samd_soc.h create mode 100644 ports/samd/sections.ld create mode 100644 ports/samd/tusb_config.h create mode 100644 ports/samd/tusb_port.c diff --git a/ports/samd/Makefile b/ports/samd/Makefile new file mode 100644 index 0000000000..f4a09ad7c1 --- /dev/null +++ b/ports/samd/Makefile @@ -0,0 +1,100 @@ +BOARD ?= ADAFRUIT_ITSYBITSY_M4_EXPRESS +BOARD_DIR ?= boards/$(BOARD) +BUILD ?= build-$(BOARD) + +CROSS_COMPILE ?= arm-none-eabi- +UF2CONV ?= $(TOP)/tools/uf2conv.py + +ifeq ($(wildcard $(BOARD_DIR)/.),) +$(error Invalid BOARD specified: $(BOARD_DIR)) +endif + +include ../../py/mkenv.mk +include $(BOARD_DIR)/board.mk + +# Qstr definitions (must come before including py.mk) +QSTR_DEFS = qstrdefsport.h +QSTR_GLOBAL_DEPENDENCIES = $(BOARD_DIR)/mpconfigboard.h + +# Include py core make definitions +include $(TOP)/py/py.mk + +INC += -I. +INC += -I$(TOP) +INC += -I$(BUILD) +INC += -I$(BOARD_DIR) +INC += -I$(TOP)/lib/cmsis/inc +INC += -I$(TOP)/lib/asf4/$(shell echo $(MCU_SERIES) | tr '[:upper:]' '[:lower:]')/include +INC += -I$(TOP)/lib/tinyusb/src + +CFLAGS_MCU_SAMD21 = -mtune=cortex-m0plus -mcpu=cortex-m0plus -msoft-float +CFLAGS_MCU_SAMD51 = -mtune=cortex-m4 -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard +CFLAGS = $(INC) -Wall -Werror -std=c99 -nostdlib -mthumb $(CFLAGS_MCU_$(MCU_SERIES)) -fsingle-precision-constant -Wdouble-promotion +CFLAGS += -DMCU_$(MCU_SERIES) -D__$(CMSIS_MCU)__ +LDFLAGS = -nostdlib $(addprefix -T,$(LD_FILES)) -Map=$@.map --cref +LIBS = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) + +# Tune for Debugging or Optimization +ifeq ($(DEBUG),1) +CFLAGS += -O0 -ggdb +else +CFLAGS += -Os -DNDEBUG +LDFLAGS += --gc-sections +CFLAGS += -fdata-sections -ffunction-sections +endif + +SRC_C = \ + main.c \ + modutime.c \ + modmachine.c \ + mphalport.c \ + samd_isr.c \ + samd_soc.c \ + tusb_port.c \ + lib/libc/string0.c \ + lib/libm/ef_sqrt.c \ + lib/libm/fmodf.c \ + lib/libm/math.c \ + lib/libm/nearbyintf.c \ + lib/mp-readline/readline.c \ + lib/tinyusb/src/class/cdc/cdc_device.c \ + lib/tinyusb/src/common/tusb_fifo.c \ + lib/tinyusb/src/device/usbd.c \ + lib/tinyusb/src/device/usbd_control.c \ + lib/tinyusb/src/tusb.c \ + lib/utils/printf.c \ + lib/utils/pyexec.c \ + lib/utils/stdout_helpers.c \ + +ifeq ($(MCU_SERIES),SAMD21) +SRC_C += lib/tinyusb/src/portable/microchip/samd21/dcd_samd21.c +SRC_S = lib/utils/gchelper_m0.s +else +SRC_C += lib/tinyusb/src/portable/microchip/samd51/dcd_samd51.c +SRC_S = lib/utils/gchelper_m3.s +endif + +# List of sources for qstr extraction +SRC_QSTR += modutime.c modmachine.c + +OBJ += $(PY_O) +OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) + +# Workaround for bug in older gcc, warning on "static usbd_device_t _usbd_dev = { 0 };" +$(BUILD)/lib/tinyusb/src/device/usbd.o: CFLAGS += -Wno-missing-braces + +all: $(BUILD)/firmware.uf2 + +$(BUILD)/firmware.elf: $(OBJ) + $(ECHO) "LINK $@" + $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS) + $(Q)$(SIZE) $@ + +$(BUILD)/firmware.bin: $(BUILD)/firmware.elf + $(Q)$(OBJCOPY) -O binary -j .isr_vector -j .text -j .data $^ $(BUILD)/firmware.bin + +$(BUILD)/firmware.uf2: $(BUILD)/firmware.bin + $(Q)$(PYTHON) $(UF2CONV) -b $(TEXT0) -c -o $@ $< + +include $(TOP)/py/mkrules.mk diff --git a/ports/samd/README.md b/ports/samd/README.md new file mode 100644 index 0000000000..b2ff4023ec --- /dev/null +++ b/ports/samd/README.md @@ -0,0 +1,7 @@ +Port of MicroPython to Microchip SAMD MCUs +========================================== + +Supports SAMD21 and SAMD51. + +Features: +- REPL over USB VCP diff --git a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.mk b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.mk new file mode 100644 index 0000000000..8cbd1885e4 --- /dev/null +++ b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.mk @@ -0,0 +1,4 @@ +MCU_SERIES = SAMD51 +CMSIS_MCU = SAMD51G19A +LD_FILES = $(BOARD_DIR)/link.ld sections.ld +TEXT0 = 0x4000 diff --git a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/link.ld b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/link.ld new file mode 100644 index 0000000000..e0baa9bba0 --- /dev/null +++ b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/link.ld @@ -0,0 +1,17 @@ +/* + GNU linker script for SAMD51 +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00004000, LENGTH = 512K - 16K + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 192K +} + +/* Top end of the stack, with room for double-tap variable */ +_estack = ORIGIN(RAM) + LENGTH(RAM) - 8; +_sstack = _estack - 16K; + +_sheap = _ebss; +_eheap = _sstack; diff --git a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.h b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.h new file mode 100644 index 0000000000..490704eadb --- /dev/null +++ b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.h @@ -0,0 +1,7 @@ +#define MICROPY_HW_BOARD_NAME "ItsyBitsy M4 Express" +#define MICROPY_HW_MCU_NAME "SAMD51G19A" + +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) +#define MICROPY_PY_BUILTINS_COMPLEX (0) +#define MICROPY_PY_MATH (0) +#define MICROPY_PY_CMATH (0) diff --git a/ports/samd/boards/ADAFRUIT_TRINKET_M0/board.mk b/ports/samd/boards/ADAFRUIT_TRINKET_M0/board.mk new file mode 100644 index 0000000000..3955a4f719 --- /dev/null +++ b/ports/samd/boards/ADAFRUIT_TRINKET_M0/board.mk @@ -0,0 +1,4 @@ +MCU_SERIES = SAMD21 +CMSIS_MCU = SAMD21E18A +LD_FILES = $(BOARD_DIR)/link.ld sections.ld +TEXT0 = 0x2000 diff --git a/ports/samd/boards/ADAFRUIT_TRINKET_M0/link.ld b/ports/samd/boards/ADAFRUIT_TRINKET_M0/link.ld new file mode 100644 index 0000000000..b7d59c315b --- /dev/null +++ b/ports/samd/boards/ADAFRUIT_TRINKET_M0/link.ld @@ -0,0 +1,17 @@ +/* + GNU linker script for SAMD21 +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00002000, LENGTH = 256K - 8K + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K +} + +/* Top end of the stack, with room for double-tap variable */ +_estack = ORIGIN(RAM) + LENGTH(RAM) - 8; +_sstack = _estack - 8K; + +_sheap = _ebss; +_eheap = _sstack; diff --git a/ports/samd/boards/ADAFRUIT_TRINKET_M0/mpconfigboard.h b/ports/samd/boards/ADAFRUIT_TRINKET_M0/mpconfigboard.h new file mode 100644 index 0000000000..d3a6ba2d86 --- /dev/null +++ b/ports/samd/boards/ADAFRUIT_TRINKET_M0/mpconfigboard.h @@ -0,0 +1,2 @@ +#define MICROPY_HW_BOARD_NAME "Trinket M0" +#define MICROPY_HW_MCU_NAME "SAMD21E18A" diff --git a/ports/samd/main.c b/ports/samd/main.c new file mode 100644 index 0000000000..a66bdfbebd --- /dev/null +++ b/ports/samd/main.c @@ -0,0 +1,98 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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/compile.h" +#include "py/runtime.h" +#include "py/gc.h" +#include "py/mperrno.h" +#include "py/stackctrl.h" +#include "lib/utils/gchelper.h" +#include "lib/utils/pyexec.h" + +extern uint8_t _sstack, _estack, _sheap, _eheap; + +void samd_main(void) { + mp_stack_set_top(&_estack); + mp_stack_set_limit(&_estack - &_sstack - 1024); + + for (;;) { + gc_init(&_sheap, &_eheap); + mp_init(); + mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_path), 0); + mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); + mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0); + + for (;;) { + if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { + if (pyexec_raw_repl() != 0) { + break; + } + } else { + if (pyexec_friendly_repl() != 0) { + break; + } + } + } + + mp_printf(MP_PYTHON_PRINTER, "MPY: soft reboot\n"); + gc_sweep_all(); + mp_deinit(); + } +} + +void gc_collect(void) { + gc_collect_start(); + uintptr_t regs[10]; + uintptr_t sp = gc_helper_get_regs_and_sp(regs); + gc_collect_root((void**)sp, ((uintptr_t)MP_STATE_THREAD(stack_top) - sp) / sizeof(uint32_t)); + gc_collect_end(); +} + +mp_lexer_t *mp_lexer_new_from_file(const char *filename) { + mp_raise_OSError(MP_ENOENT); +} + +mp_import_stat_t mp_import_stat(const char *path) { + return MP_IMPORT_STAT_NO_EXIST; +} + +mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open); + +void nlr_jump_fail(void *val) { + for (;;) { + } +} + +#ifndef NDEBUG +void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) { + mp_printf(MP_PYTHON_PRINTER, "Assertion '%s' failed, at file %s:%d\n", expr, file, line); + for(;;) { + } +} +#endif diff --git a/ports/samd/makefile b/ports/samd/makefile new file mode 100644 index 0000000000..336d6f2800 --- /dev/null +++ b/ports/samd/makefile @@ -0,0 +1,12 @@ +#BOARD = TRINKET +UF2DEV = /dev/sdb +#UF2CONV = /home/damien/others/uf2/utils/uf2conv.py + +include Makefile + +deploy: $(BUILD)/firmware.uf2 + $(ECHO) "Copying $< to the board" + mount $(UF2DEV) + cat /mnt/INFO_UF2.TXT > /dev/null + cp $< /mnt + umount /mnt diff --git a/ports/samd/modmachine.c b/ports/samd/modmachine.c new file mode 100644 index 0000000000..5362ef172c --- /dev/null +++ b/ports/samd/modmachine.c @@ -0,0 +1,72 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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 "extmod/machine_mem.h" +#include "samd_soc.h" + +#if defined(MCU_SAMD21) +#define DBL_TAP_ADDR ((volatile uint32_t *)(0x20000000 + 32 * 1024 - 4)) +#elif defined(MCU_SAMD51) +#define DBL_TAP_ADDR ((volatile uint32_t *)(0x20000000 + 192 * 1024 - 4)) +#endif +#define DBL_TAP_MAGIC_LOADER 0xf01669ef +#define DBL_TAP_MAGIC_RESET 0xf02669ef + +STATIC mp_obj_t machine_reset(void) { + *DBL_TAP_ADDR = DBL_TAP_MAGIC_RESET; + NVIC_SystemReset(); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset); + +STATIC mp_obj_t machine_bootloader(void) { + *DBL_TAP_ADDR = DBL_TAP_MAGIC_LOADER; + NVIC_SystemReset(); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_bootloader_obj, machine_bootloader); + +STATIC mp_obj_t machine_freq(void) { + return MP_OBJ_NEW_SMALL_INT(CPU_FREQ); +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_freq_obj, machine_freq); + +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_reset), MP_ROM_PTR(&machine_reset_obj) }, + { MP_ROM_QSTR(MP_QSTR_bootloader), MP_ROM_PTR(&machine_bootloader_obj) }, + { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_freq_obj) }, + { 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) }, +}; +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, +}; diff --git a/ports/samd/modutime.c b/ports/samd/modutime.c new file mode 100644 index 0000000000..c3c152bb71 --- /dev/null +++ b/ports/samd/modutime.c @@ -0,0 +1,47 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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 "extmod/utime_mphal.h" + +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_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 mp_module_utime = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&time_module_globals, +}; diff --git a/ports/samd/mpconfigport.h b/ports/samd/mpconfigport.h new file mode 100644 index 0000000000..5b81d96b3a --- /dev/null +++ b/ports/samd/mpconfigport.h @@ -0,0 +1,109 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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. + */ + +// Options controlling how MicroPython is built, overriding defaults in py/mpconfig.h + +// Board specific definitions +#include "mpconfigboard.h" + +// Memory allocation policies +#define MICROPY_GC_STACK_ENTRY_TYPE uint16_t +#define MICROPY_GC_ALLOC_THRESHOLD (0) +#define MICROPY_ALLOC_PARSE_CHUNK_INIT (32) +#define MICROPY_ALLOC_PATH_MAX (256) +#define MICROPY_QSTR_BYTES_IN_HASH (1) + +// Compiler configuration +#define MICROPY_COMP_CONST (0) + +// Python internal features +#define MICROPY_ENABLE_GC (1) +#define MICROPY_KBD_EXCEPTION (1) +#define MICROPY_HELPER_REPL (1) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) +#define MICROPY_ENABLE_SOURCE_LINE (1) +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) +#define MICROPY_CPYTHON_COMPAT (0) +#define MICROPY_CAN_OVERRIDE_BUILTINS (1) + +// Control over Python builtins +#define MICROPY_PY_ASYNC_AWAIT (0) +#define MICROPY_PY_BUILTINS_STR_COUNT (0) +#define MICROPY_PY_BUILTINS_MEMORYVIEW (1) +#define MICROPY_PY_BUILTINS_SET (0) +#define MICROPY_PY_BUILTINS_FROZENSET (0) +#define MICROPY_PY_BUILTINS_PROPERTY (0) +#define MICROPY_PY_BUILTINS_ENUMERATE (0) +#define MICROPY_PY_BUILTINS_FILTER (0) +#define MICROPY_PY_BUILTINS_REVERSED (0) +#define MICROPY_PY_BUILTINS_MIN_MAX (0) +#define MICROPY_PY___FILE__ (0) +#define MICROPY_PY_MICROPYTHON_MEM_INFO (1) +#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) +#define MICROPY_PY_ATTRTUPLE (0) +#define MICROPY_PY_COLLECTIONS (0) +#define MICROPY_PY_SYS_MAXSIZE (1) + +// Extended modules +#define MICROPY_PY_UTIME_MP_HAL (1) +#define MICROPY_PY_MACHINE (1) + +// Hooks to add builtins + +#define MICROPY_PORT_BUILTINS \ + { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) }, + +extern const struct _mp_obj_module_t mp_module_machine; +extern const struct _mp_obj_module_t mp_module_utime; + +#define MICROPY_PORT_BUILTIN_MODULES \ + { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&mp_module_machine) }, \ + { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_utime) }, \ + +#define MICROPY_PORT_ROOT_POINTERS \ + const char *readline_hist[8]; + +#define MP_STATE_PORT MP_STATE_VM + +// Miscellaneous settings + +#define MICROPY_EVENT_POLL_HOOK \ + do { \ + extern void mp_handle_pending(void); \ + mp_handle_pending(); \ + __WFI(); \ + } while (0); + +#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1)) +#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) + +#define MP_SSIZE_MAX (0x7fffffff) +typedef int mp_int_t; // must be pointer size +typedef unsigned mp_uint_t; // must be pointer size +typedef long mp_off_t; + +// Need to provide a declaration/definition of alloca() +#include diff --git a/ports/samd/mphalport.c b/ports/samd/mphalport.c new file mode 100644 index 0000000000..9f3105c698 --- /dev/null +++ b/ports/samd/mphalport.c @@ -0,0 +1,112 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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" +#include "py/mphal.h" +#include "lib/utils/interrupt_char.h" +#include "samd_soc.h" +#include "tusb.h" + +#if MICROPY_KBD_EXCEPTION + +void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) { + (void)itf; + (void)wanted_char; + tud_cdc_read_char(); // discard interrupt char + mp_keyboard_interrupt(); +} + +void mp_hal_set_interrupt_char(int c) { + if (c != -1) { + mp_obj_exception_clear_traceback(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception))); + } + tud_cdc_set_wanted_char(c); +} + +void mp_keyboard_interrupt(void) { + 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 +} + +#endif + +void mp_hal_delay_ms(mp_uint_t ms) { + ms += 1; + uint32_t t0 = systick_ms; + while (systick_ms - t0 < ms) { + MICROPY_EVENT_POLL_HOOK + } +} + +void mp_hal_delay_us(mp_uint_t us) { + uint32_t ms = us / 1000 + 1; + uint32_t t0 = systick_ms; + while (systick_ms - t0 < ms) { + __WFI(); + } +} + +int mp_hal_stdin_rx_chr(void) { + for (;;) { + if (USARTx->USART.INTFLAG.bit.RXC) { + return USARTx->USART.DATA.bit.DATA; + } + if (tud_cdc_connected() && tud_cdc_available()) { + uint8_t buf[1]; + uint32_t count = tud_cdc_read(buf, sizeof(buf)); + if (count) { + return buf[0]; + } + } + __WFI(); + } +} + +void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { + if (tud_cdc_connected()) { + for (size_t i = 0; i < len;) { + uint32_t n = len - i; + uint32_t n2 = tud_cdc_write(str + i, n); + if (n2 < n) { + while (!tud_cdc_write_flush()) { + __WFI(); + } + } + i += n2; + } + while (!tud_cdc_write_flush()) { + __WFI(); + } + } + while (len--) { + while (!(USARTx->USART.INTFLAG.bit.DRE)) { } + USARTx->USART.DATA.bit.DATA = *str++; + } +} diff --git a/ports/samd/mphalport.h b/ports/samd/mphalport.h new file mode 100644 index 0000000000..52562652e1 --- /dev/null +++ b/ports/samd/mphalport.h @@ -0,0 +1,39 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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_SAMD_MPHALPORT_H +#define MICROPY_INCLUDED_SAMD_MPHALPORT_H + +#include + +extern volatile uint32_t systick_ms; + +void mp_hal_set_interrupt_char(int c); + +static inline mp_uint_t mp_hal_ticks_ms(void) { return systick_ms; } +static inline mp_uint_t mp_hal_ticks_us(void) { return systick_ms * 1000; } +static inline mp_uint_t mp_hal_ticks_cpu(void) { return 0; } + +#endif // MICROPY_INCLUDED_SAMD_MPHALPORT_H diff --git a/ports/samd/qstrdefsport.h b/ports/samd/qstrdefsport.h new file mode 100644 index 0000000000..3ba897069b --- /dev/null +++ b/ports/samd/qstrdefsport.h @@ -0,0 +1 @@ +// qstrs specific to this port diff --git a/ports/samd/samd_isr.c b/ports/samd/samd_isr.c new file mode 100644 index 0000000000..8341df8c64 --- /dev/null +++ b/ports/samd/samd_isr.c @@ -0,0 +1,252 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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 "samd_soc.h" + +typedef void (*ISR)(void); + +extern uint32_t _estack, _sidata, _sdata, _edata, _sbss, _ebss; + +const ISR isr_vector[]; +uint32_t systick_ms; + +void Reset_Handler(void) __attribute__((naked)); +void Reset_Handler(void) { + // Set stack pointer + #if __CORTEX_M >= 0x03 + __asm volatile ("ldr sp, =_estack"); + #else + __asm volatile ("ldr r0, =_estack"); + __asm volatile ("mov sp, r0"); + #endif + // Copy .data section from flash to RAM + for (uint32_t *src = &_sidata, *dest = &_sdata; dest < &_edata;) { + *dest++ = *src++; + } + // Zero out .bss section + for (uint32_t *dest = &_sbss; dest < &_ebss;) { + *dest++ = 0; + } + + // When we get here: stack is initialised, bss is clear, data is copied + + #if __FPU_PRESENT == 1 && __FPU_USED == 1 + // Set CP10 and CP11 Full Access + SCB->CPACR |= (3UL << 10 * 2) | (3UL << 11 * 2); + #endif + + // SCB->VTOR + *((volatile uint32_t*)0xe000ed08) = (uint32_t)&isr_vector; + + // SCB->CCR: enable 8-byte stack alignment for IRQ handlers, in accord with EABI + *((volatile uint32_t*)0xe000ed14) |= 1 << 9; + + // Initialise the cpu and peripherals + samd_init(); + + // Now that we have a basic system up and running we can call main + samd_main(); + + // we must not return + for (;;) { + } +} + +void Default_Handler(void) { + for (;;) { + } +} + +void SysTick_Handler(void) { + systick_ms += 1; +} + +const ISR isr_vector[] __attribute__((section(".isr_vector"))) = { + (ISR)&_estack, + &Reset_Handler, + &Default_Handler, // NMI_Handler + &Default_Handler, // HardFault_Handler + &Default_Handler, // MemManage_Handler + &Default_Handler, // BusFault_Handler + &Default_Handler, // UsageFault_Handler + 0, + 0, + 0, + 0, + &Default_Handler, // SVC_Handler + &Default_Handler, // DebugMon_Handler + 0, + &Default_Handler, // PendSV_Handler + &SysTick_Handler, // SysTick_Handler + 0, // line 0 + 0, + 0, + 0, + 0, + 0, + 0, + #if defined(MCU_SAMD21) + USB_Handler_wrapper, // line 7 + #else + 0, + #endif + 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, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + #if defined(MCU_SAMD51) + &USB_0_Handler_wrapper, // line 80 + &USB_1_Handler_wrapper, + &USB_2_Handler_wrapper, + &USB_3_Handler_wrapper, + #else + 0, + 0, + 0, + 0, + #endif + 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, +}; diff --git a/ports/samd/samd_soc.c b/ports/samd/samd_soc.c new file mode 100644 index 0000000000..569cd3802e --- /dev/null +++ b/ports/samd/samd_soc.c @@ -0,0 +1,152 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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 "samd_soc.h" +#include "tusb.h" + +static void uart0_init(void) { + #if defined(MCU_SAMD21) + + // SERCOM0, TX=PA06=PAD2, RX=PA07=PAD3, ALT-D + PORT->Group[0].PMUX[3].reg = 0x33; + PORT->Group[0].PINCFG[6].reg = 1; + PORT->Group[0].PINCFG[7].reg = 1; + + PM->APBCMASK.bit.SERCOM0_ = 1; + GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID_SERCOM0_CORE; + while (GCLK->STATUS.bit.SYNCBUSY) { } + + uint32_t rxpo = 3; + uint32_t txpo = 1; + + #elif defined(MCU_SAMD51) + + // SERCOM3, TX=PA17=PAD0, RX=PA16=PAD1, ALT-D + PORT->Group[0].PMUX[8].reg = 0x33; + PORT->Group[0].PINCFG[16].reg = 1; + PORT->Group[0].PINCFG[17].reg = 1; + + // Use Generator 0 which is already enabled and switched to DFLL @ 48MHz + GCLK->PCHCTRL[SERCOM3_GCLK_ID_CORE].reg = GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN_GCLK0; + MCLK->APBBMASK.bit.SERCOM3_ = 1; + + uint32_t rxpo = 1; + uint32_t txpo = 2; + + #endif + + while (USARTx->USART.SYNCBUSY.bit.SWRST) { } + USARTx->USART.CTRLA.bit.SWRST = 1; + while (USARTx->USART.SYNCBUSY.bit.SWRST) { } + + USARTx->USART.CTRLA.reg = + SERCOM_USART_CTRLA_DORD + | SERCOM_USART_CTRLA_RXPO(rxpo) + | SERCOM_USART_CTRLA_TXPO(txpo) + | SERCOM_USART_CTRLA_MODE(1) + ; + USARTx->USART.CTRLB.reg = SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN; + while (USARTx->USART.SYNCBUSY.bit.CTRLB) { } + #if CPU_FREQ == 8000000 + uint32_t baud = 50437; // 115200 baud; 65536*(1 - 16 * 115200/8e6) + #elif CPU_FREQ == 48000000 + uint32_t baud = 63019; // 115200 baud; 65536*(1 - 16 * 115200/48e6) + #elif CPU_FREQ == 120000000 + uint32_t baud = 64529; // 115200 baud; 65536*(1 - 16 * 115200/120e6) + #endif + USARTx->USART.BAUD.bit.BAUD = baud; + USARTx->USART.CTRLA.bit.ENABLE = 1; + while (USARTx->USART.SYNCBUSY.bit.ENABLE) { } +} + +static void usb_init(void) { + // Init USB clock + #if defined(MCU_SAMD21) + GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID_USB; + PM->AHBMASK.bit.USB_ = 1; + PM->APBBMASK.bit.USB_ = 1; + uint8_t alt = 6; // alt G, USB + #elif defined(MCU_SAMD51) + GCLK->PCHCTRL[USB_GCLK_ID].reg = GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN_GCLK1; + while (GCLK->PCHCTRL[USB_GCLK_ID].bit.CHEN == 0) { } + MCLK->AHBMASK.bit.USB_ = 1; + MCLK->APBBMASK.bit.USB_ = 1; + uint8_t alt = 7; // alt H, USB + #endif + + // Init USB pins + PORT->Group[0].DIRSET.reg = 1 << 25 | 1 << 24; + PORT->Group[0].OUTCLR.reg = 1 << 25 | 1 << 24; + PORT->Group[0].PMUX[12].reg = alt << 4 | alt; + PORT->Group[0].PINCFG[24].reg = PORT_PINCFG_PMUXEN; + PORT->Group[0].PINCFG[25].reg = PORT_PINCFG_PMUXEN; + + tusb_init(); +} + +void samd_init(void) { + #if defined(MCU_SAMD21) + + NVMCTRL->CTRLB.bit.MANW = 1; // errata "Spurious Writes" + NVMCTRL->CTRLB.bit.RWS = 1; // 1 read wait state for 48MHz + + // Enable DFLL48M + SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE; + while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {} + SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP(1) | SYSCTRL_DFLLMUL_FSTEP(1) + | SYSCTRL_DFLLMUL_MUL(48000); + uint32_t coarse = (*((uint32_t*)FUSES_DFLL48M_COARSE_CAL_ADDR) & FUSES_DFLL48M_COARSE_CAL_Msk) + >> FUSES_DFLL48M_COARSE_CAL_Pos; + if (coarse == 0x3f) { + coarse = 0x1f; + } + uint32_t fine = 512; + SYSCTRL->DFLLVAL.reg = SYSCTRL_DFLLVAL_COARSE(coarse) | SYSCTRL_DFLLVAL_FINE(fine); + SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_CCDIS | SYSCTRL_DFLLCTRL_USBCRM + | SYSCTRL_DFLLCTRL_MODE | SYSCTRL_DFLLCTRL_ENABLE; + while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {} + + GCLK->GENDIV.reg = GCLK_GENDIV_ID(0) | GCLK_GENDIV_DIV(1); + GCLK->GENCTRL.reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DFLL48M | GCLK_GENCTRL_ID(0); + while (GCLK->STATUS.bit.SYNCBUSY) { } + + // Configure PA10 as output for LED + PORT->Group[0].DIRSET.reg = 1 << 10; + + #elif defined(MCU_SAMD51) + + GCLK->GENCTRL[1].reg = 1 << GCLK_GENCTRL_DIV_Pos | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DFLL; + while (GCLK->SYNCBUSY.bit.GENCTRL1) { } + + // Configure PA22 as output for LED + PORT->Group[0].DIRSET.reg = 1 << 22; + + #endif + + SysTick_Config(CPU_FREQ / 1000); + uart0_init(); + usb_init(); +} diff --git a/ports/samd/samd_soc.h b/ports/samd/samd_soc.h new file mode 100644 index 0000000000..5f68610e4d --- /dev/null +++ b/ports/samd/samd_soc.h @@ -0,0 +1,53 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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_SAMD_SAMD_SOC_H +#define MICROPY_INCLUDED_SAMD_SAMD_SOC_H + +#include +#include "sam.h" + +#if defined(MCU_SAMD21) + +#define CPU_FREQ (48000000) +#define USARTx SERCOM0 + +#elif defined(MCU_SAMD51) + +#define CPU_FREQ (48000000) +#define USARTx SERCOM3 + +#endif + +void samd_init(void); +void samd_main(void); + +void USB_Handler_wrapper(void); +void USB_0_Handler_wrapper(void); +void USB_1_Handler_wrapper(void); +void USB_2_Handler_wrapper(void); +void USB_3_Handler_wrapper(void); + +#endif // MICROPY_INCLUDED_SAMD_SAMD_SOC_H diff --git a/ports/samd/sections.ld b/ports/samd/sections.ld new file mode 100644 index 0000000000..cbcad463d0 --- /dev/null +++ b/ports/samd/sections.ld @@ -0,0 +1,37 @@ +/* Define output sections */ +SECTIONS +{ + .text : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) + *(.text) + *(.text*) + *(.rodata) + *(.rodata*) + . = ALIGN(4); + _etext = .; + _sidata = _etext; + } >FLASH + + .data : AT ( _sidata ) + { + . = ALIGN(4); + _sdata = .; + *(.data) + *(.data*) + . = ALIGN(4); + _edata = .; + } >RAM + + .bss : + { + . = ALIGN(4); + _sbss = .; + *(.bss) + *(.bss*) + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >RAM +} diff --git a/ports/samd/tusb_config.h b/ports/samd/tusb_config.h new file mode 100644 index 0000000000..07fa680cbb --- /dev/null +++ b/ports/samd/tusb_config.h @@ -0,0 +1,47 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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_SAMD_TUSB_CONFIG_H +#define MICROPY_INCLUDED_SAMD_TUSB_CONFIG_H + +// Common configuration + +#if defined(MCU_SAMD21) +#define CFG_TUSB_MCU OPT_MCU_SAMD21 +#elif defined(MCU_SAMD51) +#define CFG_TUSB_MCU OPT_MCU_SAMD51 +#endif +#define CFG_TUSB_RHPORT0_MODE OPT_MODE_DEVICE +#define CFG_TUSB_MEM_SECTION +#define CFG_TUSB_MEM_ALIGN TU_ATTR_ALIGNED(4) + +// Device configuration + +#define CFG_TUD_ENDOINT0_SIZE (64) +#define CFG_TUD_CDC (1) +#define CFG_TUD_CDC_RX_BUFSIZE (64) +#define CFG_TUD_CDC_TX_BUFSIZE (64) + +#endif // MICROPY_INCLUDED_SAMD_TUSB_CONFIG_H diff --git a/ports/samd/tusb_port.c b/ports/samd/tusb_port.c new file mode 100644 index 0000000000..23c242b400 --- /dev/null +++ b/ports/samd/tusb_port.c @@ -0,0 +1,146 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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 "samd_soc.h" +#include "tusb.h" + +#define USBD_VID (0xf055) +#define USBD_PID (0x9802) + +#define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN) +#define USBD_MAX_POWER_MA (250) + +#define USBD_ITF_CDC (0) // needs 2 interfaces +#define USBD_ITF_MAX (2) + +#define USBD_CDC_EP_CMD (0x81) +#define USBD_CDC_EP_OUT (0x02) +#define USBD_CDC_EP_IN (0x82) +#define USBD_CDC_CMD_MAX_SIZE (8) + +#define USBD_STR_0 (0x00) +#define USBD_STR_MANUF (0x01) +#define USBD_STR_PRODUCT (0x02) +#define USBD_STR_SERIAL (0x03) +#define USBD_STR_CDC (0x04) + +// Note: descriptors returned from callbacks must exist long enough for transfer to complete + +static const tusb_desc_device_t usbd_desc_device = { + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, + .bMaxPacketSize0 = CFG_TUD_ENDOINT0_SIZE, + .idVendor = USBD_VID, + .idProduct = USBD_PID, + .bcdDevice = 0x0100, + .iManufacturer = USBD_STR_MANUF, + .iProduct = USBD_STR_PRODUCT, + .iSerialNumber = USBD_STR_SERIAL, + .bNumConfigurations = 1, +}; + +static const uint8_t usbd_desc_cfg[USBD_DESC_LEN] = { + TUD_CONFIG_DESCRIPTOR(USBD_ITF_MAX, USBD_STR_0, USBD_DESC_LEN, + TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, USBD_MAX_POWER_MA), + + TUD_CDC_DESCRIPTOR(USBD_ITF_CDC, USBD_STR_CDC, USBD_CDC_EP_CMD, + USBD_CDC_CMD_MAX_SIZE, USBD_CDC_EP_OUT, USBD_CDC_EP_IN, CFG_TUD_CDC_RX_BUFSIZE), +}; + +static const char *const usbd_desc_str[] = { + [USBD_STR_MANUF] = "MicroPython", + [USBD_STR_PRODUCT] = "Board in FS mode", + [USBD_STR_SERIAL] = "000000000000", // TODO + [USBD_STR_CDC] = "Board CDC", +}; + +const uint8_t *tud_descriptor_device_cb(void) { + return (const uint8_t*)&usbd_desc_device; +} + +const uint8_t *tud_descriptor_configuration_cb(uint8_t index) { + (void)index; + return usbd_desc_cfg; +} + +const uint16_t *tud_descriptor_string_cb(uint8_t index) { + #define DESC_STR_MAX (20) + static uint16_t desc_str[DESC_STR_MAX]; + + uint8_t len; + if (index == 0) { + desc_str[1] = 0x0409; // supported language is English + len = 1; + } else { + if (index >= sizeof(usbd_desc_str) / sizeof(usbd_desc_str[0])) { + return NULL; + } + const char* str = usbd_desc_str[index]; + for (len = 0; len < DESC_STR_MAX - 1 && str[len]; ++len) { + desc_str[1 + len] = str[len]; + } + } + + // first byte is len, second byte is string type + desc_str[0] = TUD_DESC_STR_HEADER(len); + + return desc_str; +} + +#if defined(MCU_SAMD21) + +void USB_Handler_wrapper(void) { + USB_Handler(); + tud_task(); +} + +#elif defined(MCU_SAMD51) + +void USB_0_Handler_wrapper(void) { + USB_0_Handler(); + tud_task(); +} + +void USB_1_Handler_wrapper(void) { + USB_1_Handler(); + tud_task(); +} + +void USB_2_Handler_wrapper(void) { + USB_2_Handler(); + tud_task(); +} + +void USB_3_Handler_wrapper(void) { + USB_3_Handler(); + tud_task(); +} + +#endif From 9ca478913040d0fe6fe72582a432c400ec1386ac Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 22 Jun 2019 23:06:42 +1000 Subject: [PATCH 0478/1788] travis: Add samd port to Travis build. --- .travis.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.travis.yml b/.travis.yml index 9fbdb1698e..284d311f7e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -188,6 +188,16 @@ jobs: - make ${MAKEOPTS} -C ports/cc3200 BTARGET=application BTYPE=release - make ${MAKEOPTS} -C ports/cc3200 BTARGET=bootloader BTYPE=release + # samd port + - stage: test + env: NAME="samd port build" + install: + - sudo apt-get install gcc-arm-none-eabi + - sudo apt-get install libnewlib-arm-none-eabi + script: + - git submodule update --init lib/asf4 lib/tinyusb + - make ${MAKEOPTS} -C ports/samd + # teensy port - stage: test env: NAME="teensy port build" From 999733b1fb08fb07a31846115998dbf43a913327 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 1 Jul 2019 22:41:47 +1000 Subject: [PATCH 0479/1788] minimal: Use soft float for CROSS=1 Cortex-M4 target. When compiled with hard float the system should enable FP access when it starts or else FP instructions lead to a fault. But this minimal port does not enable (or use) FP and so, to keep it minimal, switch to use soft floating point. (This became an issue due to the recent commit 34c04d2319cdfae01ed7bf7f9e341d69b86d751a which saves/restores FP registers in the NLR state.) --- ports/minimal/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/minimal/Makefile b/ports/minimal/Makefile index 64ad3cc0b2..b3e27509f1 100644 --- a/ports/minimal/Makefile +++ b/ports/minimal/Makefile @@ -19,7 +19,7 @@ INC += -I$(BUILD) ifeq ($(CROSS), 1) DFU = $(TOP)/tools/dfu.py PYDFU = $(TOP)/tools/pydfu.py -CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -mabi=aapcs-linux -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -fsingle-precision-constant -Wdouble-promotion +CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -mcpu=cortex-m4 -msoft-float -fsingle-precision-constant -Wdouble-promotion CFLAGS = $(INC) -Wall -Werror -std=c99 -nostdlib $(CFLAGS_CORTEX_M4) $(COPT) LDFLAGS = -nostdlib -T stm32f405.ld -Map=$@.map --cref --gc-sections else From 89a23a05b3feb2f81fb00d272202b274c2a325cd Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 24 Jun 2019 13:18:43 +1000 Subject: [PATCH 0480/1788] esp8266: Provide custom machine_time_pulse_us that feeds soft WDT. So that the timeout for machine.time_pulse_us() can be large. Fixes issue #2775. --- extmod/machine_pulse.c | 2 +- ports/esp8266/modmachine.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/extmod/machine_pulse.c b/extmod/machine_pulse.c index 5f837479dd..7178b22d79 100644 --- a/extmod/machine_pulse.c +++ b/extmod/machine_pulse.c @@ -30,7 +30,7 @@ #if MICROPY_PY_MACHINE_PULSE -mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us) { +MP_WEAK mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us) { mp_uint_t start = mp_hal_ticks_us(); while (mp_hal_pin_read(pin) != pulse_level) { if ((mp_uint_t)(mp_hal_ticks_us() - start) >= timeout_us) { diff --git a/ports/esp8266/modmachine.c b/ports/esp8266/modmachine.c index ccde1e5ed8..e20e8cb757 100644 --- a/ports/esp8266/modmachine.c +++ b/ports/esp8266/modmachine.c @@ -355,6 +355,35 @@ STATIC mp_obj_t machine_enable_irq(mp_obj_t state_in) { } MP_DEFINE_CONST_FUN_OBJ_1(machine_enable_irq_obj, machine_enable_irq); +// Custom version of this function that feeds system WDT if necessary +mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us) { + int nchanges = 2; + uint32_t start = system_get_time(); // in microseconds + for (;;) { + uint32_t dt = system_get_time() - start; + + // Check if pin changed to wanted value + if (mp_hal_pin_read(pin) == pulse_level) { + if (--nchanges == 0) { + return dt; + } + pulse_level = 1 - pulse_level; + start = system_get_time(); + continue; + } + + // Check for timeout + if (dt >= timeout_us) { + return (mp_uint_t)-nchanges; + } + + // Only feed WDT every now and then, to make sure edge timing is accurate + if ((dt & 0xffff) == 0xffff && !ets_loop_dont_feed_sw_wdt) { + system_soft_wdt_feed(); + } + } +} + 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) }, From 097b0f939754833c3fac40f4a4c8e568bf8ae430 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 24 Jun 2019 13:32:41 +1000 Subject: [PATCH 0481/1788] windows/mpconfigport.h: Define empty MP_WEAK symbol. --- ports/windows/mpconfigport.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/windows/mpconfigport.h b/ports/windows/mpconfigport.h index 81464d72a7..86e44183bf 100644 --- a/ports/windows/mpconfigport.h +++ b/ports/windows/mpconfigport.h @@ -214,6 +214,7 @@ extern const struct _mp_obj_module_t mp_module_time; // CL specific overrides from mpconfig #define NORETURN __declspec(noreturn) +#define MP_WEAK #define MP_NOINLINE __declspec(noinline) #define MP_LIKELY(x) (x) #define MP_UNLIKELY(x) (x) From 2920d26af579363ac9f64a9d941d1a4eff880ffe Mon Sep 17 00:00:00 2001 From: "Paul m. p. P" Date: Sun, 30 Jun 2019 11:39:24 +0200 Subject: [PATCH 0482/1788] py/persistentcode: Ensure prelude_offset is always initialised. --- py/persistentcode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/persistentcode.c b/py/persistentcode.c index c1ca46f7e9..f55478ca0b 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -337,7 +337,7 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { byte *ip2; bytecode_prelude_t prelude = {0}; #if MICROPY_EMIT_MACHINE_CODE - size_t prelude_offset; + size_t prelude_offset = 0; mp_uint_t type_sig = 0; size_t n_qstr_link = 0; #endif From 08075beeb9b45557f8ed6970e4e3e4a00bd26879 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 2 Jul 2019 17:09:59 +1000 Subject: [PATCH 0483/1788] samd: Remove "makefile" file. This file can be added by a user to customise the build process. --- ports/samd/makefile | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 ports/samd/makefile diff --git a/ports/samd/makefile b/ports/samd/makefile deleted file mode 100644 index 336d6f2800..0000000000 --- a/ports/samd/makefile +++ /dev/null @@ -1,12 +0,0 @@ -#BOARD = TRINKET -UF2DEV = /dev/sdb -#UF2CONV = /home/damien/others/uf2/utils/uf2conv.py - -include Makefile - -deploy: $(BUILD)/firmware.uf2 - $(ECHO) "Copying $< to the board" - mount $(UF2DEV) - cat /mnt/INFO_UF2.TXT > /dev/null - cp $< /mnt - umount /mnt From 62b00dd5d8cd6207147d37222e1c249ef6381841 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 27 Jun 2019 13:36:15 -0500 Subject: [PATCH 0484/1788] py/asmarm: Use __clear_cache on Linux/GCC when creating new asm code. Comes from https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/caches-and-self-modifying-code This fixes a crash when running MicroPython using qemu-arm. --- py/asmarm.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/py/asmarm.c b/py/asmarm.c index f2221f8a92..2a84f985ba 100644 --- a/py/asmarm.c +++ b/py/asmarm.c @@ -40,7 +40,11 @@ void asm_arm_end_pass(asm_arm_t *as) { if (as->base.pass == MP_ASM_PASS_EMIT) { -#ifdef __arm__ +#if defined(__linux__) && defined(__GNUC__) + char *start = mp_asm_base_get_code(&as->base); + char *end = start + mp_asm_base_get_code_size(&as->base); + __clear_cache(start, end); +#elif defined(__arm__) // flush I- and D-cache asm volatile( "0:" From f3a5b313e55e8853928702eec16c932481f370fc Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 27 Jun 2019 16:43:05 -0500 Subject: [PATCH 0485/1788] py/nlrthumb: Check __thumb2__ instead of __ARM_ARCH_6M__. This fixes compiling for older architectures (e.g. armv5tej). According to [1], the limit of R0-R7 for the STR and LDR instructions is tied to the Thumb instruction set and not any specific processor architectures. [1]: http://www.keil.com/support/man/docs/armasm/armasm_dom1361289906890.htm --- py/nlrthumb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/py/nlrthumb.c b/py/nlrthumb.c index 32fa6b1176..eef05229d6 100644 --- a/py/nlrthumb.c +++ b/py/nlrthumb.c @@ -44,7 +44,7 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { "str r6, [r0, #20] \n" // store r6 into nlr_buf "str r7, [r0, #24] \n" // store r7 into nlr_buf -#if defined(__ARM_ARCH_6M__) +#if !defined(__thumb2__) "mov r1, r8 \n" "str r1, [r0, #28] \n" // store r8 into nlr_buf "mov r1, r9 \n" @@ -71,7 +71,7 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { "str lr, [r0, #8] \n" // store lr into nlr_buf #endif -#if defined(__ARM_ARCH_6M__) +#if !defined(__thumb2__) "ldr r1, nlr_push_tail_var \n" "bx r1 \n" // do the rest in C ".align 2 \n" @@ -102,7 +102,7 @@ NORETURN void nlr_jump(void *val) { "ldr r6, [r0, #20] \n" // load r6 from nlr_buf "ldr r7, [r0, #24] \n" // load r7 from nlr_buf -#if defined(__ARM_ARCH_6M__) +#if !defined(__thumb2__) "ldr r1, [r0, #28] \n" // load r8 from nlr_buf "mov r8, r1 \n" "ldr r1, [r0, #32] \n" // load r9 from nlr_buf From 8dcf25e1bd9bfd1c6d8723b6a2d9c27615b109c2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Jul 2019 00:46:20 +1000 Subject: [PATCH 0486/1788] stm32/mpu: Add helper functions for configuring MPU. --- ports/stm32/main.c | 3 ++ ports/stm32/mpu.h | 74 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 ports/stm32/mpu.h diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 2dcc09ae7a..1a1c505dc4 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -43,6 +43,7 @@ #include "drivers/cyw43/cyw43.h" #endif +#include "mpu.h" #include "systick.h" #include "pendsv.h" #include "powerctrl.h" @@ -409,6 +410,8 @@ void stm32_main(uint32_t reset_mode) { #endif + mpu_init(); + #if __CORTEX_M >= 0x03 // Set the priority grouping NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); diff --git a/ports/stm32/mpu.h b/ports/stm32/mpu.h new file mode 100644 index 0000000000..d90a768e7a --- /dev/null +++ b/ports/stm32/mpu.h @@ -0,0 +1,74 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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_MPU_H +#define MICROPY_INCLUDED_STM32_MPU_H + +#if defined(STM32F7) || defined(STM32H7) + +#define MPU_CONFIG_DISABLE(srd, size) ( \ + MPU_INSTRUCTION_ACCESS_DISABLE << MPU_RASR_XN_Pos \ + | MPU_REGION_NO_ACCESS << MPU_RASR_AP_Pos \ + | MPU_TEX_LEVEL0 << MPU_RASR_TEX_Pos \ + | MPU_ACCESS_NOT_SHAREABLE << MPU_RASR_S_Pos \ + | MPU_ACCESS_NOT_CACHEABLE << MPU_RASR_C_Pos \ + | MPU_ACCESS_NOT_BUFFERABLE << MPU_RASR_B_Pos \ + | (srd) << MPU_RASR_SRD_Pos \ + | (size) << MPU_RASR_SIZE_Pos \ + | MPU_REGION_ENABLE << MPU_RASR_ENABLE_Pos \ + ) + +static inline void mpu_init(void) { + MPU->CTRL = MPU_PRIVILEGED_DEFAULT | MPU_CTRL_ENABLE_Msk; + SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk; + __DSB(); + __ISB(); +} + +static inline void mpu_config_start(void) { + __disable_irq(); +} + +static inline void mpu_config_region(uint32_t region, uint32_t base_addr, uint32_t attr_size) { + MPU->RNR = region; + MPU->RBAR = base_addr; + MPU->RASR = attr_size; +} + +static inline void mpu_config_end(void) { + __ISB(); + __DSB(); + __DMB(); + __enable_irq(); +} + +#else + +static inline void mpu_init(void) { +} + +#endif + +#endif // MICROPY_INCLUDED_STM32_MPU_H From f7eb2c72f76be6033a32247c145128153e3449ac Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Jul 2019 00:47:32 +1000 Subject: [PATCH 0487/1788] stm32/eth: Use MPU helper functions to configure MPU for ETH use. --- ports/stm32/eth.c | 34 ++++------------------------------ ports/stm32/mpu.h | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 30 deletions(-) diff --git a/ports/stm32/eth.c b/ports/stm32/eth.c index 6a1ef99afa..9633d32b28 100644 --- a/ports/stm32/eth.c +++ b/ports/stm32/eth.c @@ -30,6 +30,7 @@ #include "lib/netutils/netutils.h" #include "pin_static_af.h" #include "modnetwork.h" +#include "mpu.h" #include "eth.h" #if defined(MICROPY_HW_ETH_MDC) @@ -141,35 +142,6 @@ STATIC uint32_t eth_phy_read(uint32_t reg) { return ETH->MACMIIDR; } -STATIC void mpu_config(uint32_t region, uint32_t base_addr, uint32_t size) { - __DMB(); - - // Disable MPU - SCB->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk; - MPU->CTRL = 0; - - // Config MPU region - MPU->RNR = region; - MPU->RBAR = base_addr; - MPU->RASR = - MPU_INSTRUCTION_ACCESS_DISABLE << MPU_RASR_XN_Pos - | MPU_REGION_FULL_ACCESS << MPU_RASR_AP_Pos - | MPU_TEX_LEVEL1 << MPU_RASR_TEX_Pos - | MPU_ACCESS_SHAREABLE << MPU_RASR_S_Pos - | MPU_ACCESS_NOT_CACHEABLE << MPU_RASR_C_Pos - | MPU_ACCESS_NOT_BUFFERABLE << MPU_RASR_B_Pos - | 0x00 << MPU_RASR_SRD_Pos - | size << MPU_RASR_SIZE_Pos - | MPU_REGION_ENABLE << MPU_RASR_ENABLE_Pos; - - // Enable MPU - MPU->CTRL = MPU_PRIVILEGED_DEFAULT | MPU_CTRL_ENABLE_Msk; - SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk; - - __DSB(); - __ISB(); -} - void eth_init(eth_t *self, int mac_idx) { mp_hal_get_mac(mac_idx, &self->netif.hwaddr[0]); self->netif.hwaddr_len = 6; @@ -181,7 +153,9 @@ void eth_set_trace(eth_t *self, uint32_t value) { STATIC int eth_mac_init(eth_t *self) { // Configure MPU - mpu_config(MPU_REGION_NUMBER0, (uint32_t)ð_dma, MPU_REGION_SIZE_16KB); + mpu_config_start(); + mpu_config_region(MPU_REGION_ETH, (uint32_t)ð_dma, MPU_CONFIG_ETH(MPU_REGION_SIZE_16KB)); + mpu_config_end(); // Configure GPIO mp_hal_pin_config_alt_static(MICROPY_HW_ETH_MDC, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_MDC); diff --git a/ports/stm32/mpu.h b/ports/stm32/mpu.h index d90a768e7a..c0cd2108c1 100644 --- a/ports/stm32/mpu.h +++ b/ports/stm32/mpu.h @@ -28,6 +28,8 @@ #if defined(STM32F7) || defined(STM32H7) +#define MPU_REGION_ETH (MPU_REGION_NUMBER0) + #define MPU_CONFIG_DISABLE(srd, size) ( \ MPU_INSTRUCTION_ACCESS_DISABLE << MPU_RASR_XN_Pos \ | MPU_REGION_NO_ACCESS << MPU_RASR_AP_Pos \ @@ -40,6 +42,18 @@ | MPU_REGION_ENABLE << MPU_RASR_ENABLE_Pos \ ) +#define MPU_CONFIG_ETH(size) ( \ + MPU_INSTRUCTION_ACCESS_DISABLE << MPU_RASR_XN_Pos \ + | MPU_REGION_FULL_ACCESS << MPU_RASR_AP_Pos \ + | MPU_TEX_LEVEL1 << MPU_RASR_TEX_Pos \ + | MPU_ACCESS_SHAREABLE << MPU_RASR_S_Pos \ + | MPU_ACCESS_NOT_CACHEABLE << MPU_RASR_C_Pos \ + | MPU_ACCESS_NOT_BUFFERABLE << MPU_RASR_B_Pos \ + | 0x00 << MPU_RASR_SRD_Pos \ + | (size) << MPU_RASR_SIZE_Pos \ + | MPU_REGION_ENABLE << MPU_RASR_ENABLE_Pos \ + ) + static inline void mpu_init(void) { MPU->CTRL = MPU_PRIVILEGED_DEFAULT | MPU_CTRL_ENABLE_Msk; SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk; From eca4115f666f8b5e1e0155ce930353b698dcd7ef Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Jul 2019 00:48:19 +1000 Subject: [PATCH 0488/1788] stm32/sdram: Use MPU helper functions to configure MPU for SDRAM use. --- ports/stm32/mpu.h | 14 ++++++++++++++ ports/stm32/sdram.c | 41 +++++------------------------------------ 2 files changed, 19 insertions(+), 36 deletions(-) diff --git a/ports/stm32/mpu.h b/ports/stm32/mpu.h index c0cd2108c1..c5881d8fde 100644 --- a/ports/stm32/mpu.h +++ b/ports/stm32/mpu.h @@ -29,6 +29,8 @@ #if defined(STM32F7) || defined(STM32H7) #define MPU_REGION_ETH (MPU_REGION_NUMBER0) +#define MPU_REGION_SDRAM1 (MPU_REGION_NUMBER4) +#define MPU_REGION_SDRAM2 (MPU_REGION_NUMBER5) #define MPU_CONFIG_DISABLE(srd, size) ( \ MPU_INSTRUCTION_ACCESS_DISABLE << MPU_RASR_XN_Pos \ @@ -54,6 +56,18 @@ | MPU_REGION_ENABLE << MPU_RASR_ENABLE_Pos \ ) +#define MPU_CONFIG_SDRAM(size) ( \ + MPU_INSTRUCTION_ACCESS_ENABLE << MPU_RASR_XN_Pos \ + | MPU_REGION_FULL_ACCESS << MPU_RASR_AP_Pos \ + | MPU_TEX_LEVEL1 << MPU_RASR_TEX_Pos \ + | MPU_ACCESS_NOT_SHAREABLE << MPU_RASR_S_Pos \ + | MPU_ACCESS_CACHEABLE << MPU_RASR_C_Pos \ + | MPU_ACCESS_BUFFERABLE << MPU_RASR_B_Pos \ + | 0x00 << MPU_RASR_SRD_Pos \ + | (size) << MPU_RASR_SIZE_Pos \ + | MPU_REGION_ENABLE << MPU_RASR_ENABLE_Pos \ + ) + static inline void mpu_init(void) { MPU->CTRL = MPU_PRIVILEGED_DEFAULT | MPU_CTRL_ENABLE_Msk; SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk; diff --git a/ports/stm32/sdram.c b/ports/stm32/sdram.c index b3c5bbeeed..5d54dc2cb3 100644 --- a/ports/stm32/sdram.c +++ b/ports/stm32/sdram.c @@ -13,6 +13,7 @@ #include "py/mphal.h" #include "pin.h" #include "pin_static_af.h" +#include "mpu.h" #include "systick.h" #include "sdram.h" @@ -244,45 +245,13 @@ static void sdram_init_seq(SDRAM_HandleTypeDef #if defined(STM32F7) /* Enable MPU for the SDRAM Memory Region to allow non-aligned accesses (hard-fault otherwise) - */ - - MPU_Region_InitTypeDef MPU_InitStruct; - - /* Disable the MPU */ - HAL_MPU_Disable(); - - /* Configure the MPU attributes for External SDRAM Initially disable all access for the entire SDRAM memory space, then enable access/caching for the size used */ - MPU_InitStruct.Enable = MPU_REGION_ENABLE; - MPU_InitStruct.Number = MPU_REGION_NUMBER4; - MPU_InitStruct.BaseAddress = SDRAM_START_ADDRESS; - MPU_InitStruct.Size = MPU_REGION_SIZE_512MB; - MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS; - MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE; - MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; - MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; - MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0; - MPU_InitStruct.SubRegionDisable = 0x00; - MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE; - HAL_MPU_ConfigRegion(&MPU_InitStruct); - - MPU_InitStruct.Enable = MPU_REGION_ENABLE; - MPU_InitStruct.Number = MPU_REGION_NUMBER5; - MPU_InitStruct.BaseAddress = SDRAM_START_ADDRESS; - MPU_InitStruct.Size = SDRAM_MPU_REGION_SIZE; - MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; - MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; - MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE; - MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; - MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1; - MPU_InitStruct.SubRegionDisable = 0x00; - MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE; - HAL_MPU_ConfigRegion(&MPU_InitStruct); - - /* Enable the MPU */ - HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT); + mpu_config_start(); + mpu_config_region(MPU_REGION_SDRAM1, SDRAM_START_ADDRESS, MPU_CONFIG_DISABLE(0x00, MPU_REGION_SIZE_512MB)); + mpu_config_region(MPU_REGION_SDRAM2, SDRAM_START_ADDRESS, MPU_CONFIG_SDRAM(SDRAM_MPU_REGION_SIZE)); + mpu_config_end(); #endif } From 8da39fd182aee0f357c34d8e17f54601c078f6e0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Jul 2019 00:50:32 +1000 Subject: [PATCH 0489/1788] stm32/qspi: Use MPU to allow access to valid memory-mapped QSPI region. The Cortex-M7 CPU will do speculative loads from any memory location that is not explicitly forbidden. This includes the QSPI memory-mapped region starting at 0x90000000 and with size 256MiB. Speculative loads to this QSPI region may 1) interfere with the QSPI peripheral registers (eg the address register) if the QSPI is not in memory-mapped mode; 2) attempt to access data outside the configured size of the QSPI flash when it is in memory-mapped mode. Both of these scenarios will lead to issues with the QSPI peripheral (eg Cortex bus lock up in scenario 2). To prevent such speculative loads from interfering with the peripheral the MPU is configured in this commit to restrict access to the QSPI mapped region: when not memory mapped the entire region is forbidden; when memory mapped only accesses to the valid flash size are permitted. --- ports/stm32/mpu.h | 3 +++ ports/stm32/qspi.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/ports/stm32/mpu.h b/ports/stm32/mpu.h index c5881d8fde..2541d86bfb 100644 --- a/ports/stm32/mpu.h +++ b/ports/stm32/mpu.h @@ -29,6 +29,9 @@ #if defined(STM32F7) || defined(STM32H7) #define MPU_REGION_ETH (MPU_REGION_NUMBER0) +#define MPU_REGION_QSPI1 (MPU_REGION_NUMBER1) +#define MPU_REGION_QSPI2 (MPU_REGION_NUMBER2) +#define MPU_REGION_QSPI3 (MPU_REGION_NUMBER3) #define MPU_REGION_SDRAM1 (MPU_REGION_NUMBER4) #define MPU_REGION_SDRAM2 (MPU_REGION_NUMBER5) diff --git a/ports/stm32/qspi.c b/ports/stm32/qspi.c index 8c8b9c4940..8ed3a17dd5 100644 --- a/ports/stm32/qspi.c +++ b/ports/stm32/qspi.c @@ -28,11 +28,14 @@ #include "py/mperrno.h" #include "py/mphal.h" +#include "mpu.h" #include "qspi.h" #include "pin_static_af.h" #if defined(MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2) +#define QSPI_MAP_ADDR (0x90000000) + #ifndef MICROPY_HW_QSPI_PRESCALER #define MICROPY_HW_QSPI_PRESCALER 3 // F_CLK = F_AHB/3 (72MHz when CPU is 216MHz) #endif @@ -49,7 +52,31 @@ #define MICROPY_HW_QSPI_CS_HIGH_CYCLES 2 // nCS stays high for 2 cycles #endif +static inline void qspi_mpu_disable_all(void) { + // Configure MPU to disable access to entire QSPI region, to prevent CPU + // speculative execution from accessing this region and modifying QSPI registers. + mpu_config_start(); + mpu_config_region(MPU_REGION_QSPI1, QSPI_MAP_ADDR, MPU_CONFIG_DISABLE(0x00, MPU_REGION_SIZE_256MB)); + mpu_config_end(); +} + +static inline void qspi_mpu_enable_mapped(void) { + // Configure MPU to allow access to only the valid part of external SPI flash. + // The memory accesses to the mapped QSPI are faster if the MPU is not used + // for the memory-mapped region, so 3 MPU regions are used to disable access + // to everything except the valid address space, using holes in the bottom + // of the regions and nesting them. + // At the moment this is hard-coded to 2MiB of QSPI address space. + mpu_config_start(); + mpu_config_region(MPU_REGION_QSPI1, QSPI_MAP_ADDR, MPU_CONFIG_DISABLE(0x01, MPU_REGION_SIZE_256MB)); + mpu_config_region(MPU_REGION_QSPI2, QSPI_MAP_ADDR, MPU_CONFIG_DISABLE(0x0f, MPU_REGION_SIZE_32MB)); + mpu_config_region(MPU_REGION_QSPI3, QSPI_MAP_ADDR, MPU_CONFIG_DISABLE(0x01, MPU_REGION_SIZE_16MB)); + mpu_config_end(); +} + void qspi_init(void) { + qspi_mpu_disable_all(); + // Configure pins mp_hal_pin_config_alt_static_speed(MICROPY_HW_QSPIFLASH_CS, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_QUADSPI_BK1_NCS); mp_hal_pin_config_alt_static_speed(MICROPY_HW_QSPIFLASH_SCK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_QUADSPI_CLK); @@ -100,6 +127,8 @@ void qspi_memory_map(void) { | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line | 0xeb << QUADSPI_CCR_INSTRUCTION_Pos // quad read opcode ; + + qspi_mpu_enable_mapped(); } STATIC int qspi_ioctl(void *self_in, uint32_t cmd) { From 2034c0a2e364404216c8cadeb661fbc72647d16a Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Jul 2019 00:59:56 +1000 Subject: [PATCH 0490/1788] stm32/qspi: Force a reset of the QSPI peripheral when initialising it. To ensure it is in a known state on start up. --- ports/stm32/qspi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/stm32/qspi.c b/ports/stm32/qspi.c index 8ed3a17dd5..282759967e 100644 --- a/ports/stm32/qspi.c +++ b/ports/stm32/qspi.c @@ -88,6 +88,8 @@ void qspi_init(void) { // Bring up the QSPI peripheral __HAL_RCC_QSPI_CLK_ENABLE(); + __HAL_RCC_QSPI_FORCE_RESET(); + __HAL_RCC_QSPI_RELEASE_RESET(); QUADSPI->CR = (MICROPY_HW_QSPI_PRESCALER - 1) << QUADSPI_CR_PRESCALER_Pos From caabdd99c0f8402f5a141123f02cdf4be0a10ecf Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Jul 2019 01:00:40 +1000 Subject: [PATCH 0491/1788] stm32/qspi: Handle bus acquisition. When going out of memory-mapped mode to do a control transfer to the QSPI flash, the MPU settings must be changed to forbid access to the memory mapped region. And any ongoing transfer (eg memory mapped continuous read) must be aborted. --- ports/stm32/qspi.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ports/stm32/qspi.c b/ports/stm32/qspi.c index 282759967e..ec744bfb27 100644 --- a/ports/stm32/qspi.c +++ b/ports/stm32/qspi.c @@ -139,6 +139,16 @@ STATIC int qspi_ioctl(void *self_in, uint32_t cmd) { case MP_QSPI_IOCTL_INIT: qspi_init(); break; + case MP_QSPI_IOCTL_BUS_ACQUIRE: + // Disable memory-mapped region during bus access + qspi_mpu_disable_all(); + // Abort any ongoing transfer if peripheral is busy + if (QUADSPI->SR & QUADSPI_SR_BUSY) { + QUADSPI->CR |= QUADSPI_CR_ABORT; + while (QUADSPI->CR & QUADSPI_CR_ABORT) { + } + } + break; case MP_QSPI_IOCTL_BUS_RELEASE: // Switch to memory-map mode when bus is idle qspi_memory_map(); From 8cde5faedd63ea1b21b7adef87e50e6a036c7e5a Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Jul 2019 01:03:25 +1000 Subject: [PATCH 0492/1788] drivers/memory/spiflash: Add support to put SPI flash in sleep mode. --- drivers/memory/spiflash.c | 17 +++++++++++++++++ drivers/memory/spiflash.h | 1 + 2 files changed, 18 insertions(+) diff --git a/drivers/memory/spiflash.c b/drivers/memory/spiflash.c index 22775d5416..0eacc710e3 100644 --- a/drivers/memory/spiflash.c +++ b/drivers/memory/spiflash.c @@ -146,6 +146,10 @@ STATIC int mp_spiflash_wait_wip0(mp_spiflash_t *self) { return mp_spiflash_wait_sr(self, 1, 0, WAIT_SR_TIMEOUT); } +static inline void mp_spiflash_deepsleep_internal(mp_spiflash_t *self, int value) { + mp_spiflash_write_cmd(self, value ? 0xb9 : 0xab); // sleep/wake +} + void mp_spiflash_init(mp_spiflash_t *self) { self->flags = 0; @@ -159,6 +163,9 @@ void mp_spiflash_init(mp_spiflash_t *self) { mp_spiflash_acquire_bus(self); + // Ensure SPI flash is out of sleep mode + mp_spiflash_deepsleep_internal(self, 0); + #if defined(CHECK_DEVID) // Validate device id uint32_t devid = mp_spiflash_read_cmd(self, CMD_RD_DEVID, 3); @@ -182,6 +189,16 @@ void mp_spiflash_init(mp_spiflash_t *self) { mp_spiflash_release_bus(self); } +void mp_spiflash_deepsleep(mp_spiflash_t *self, int value) { + if (value) { + mp_spiflash_acquire_bus(self); + } + mp_spiflash_deepsleep_internal(self, value); + if (!value) { + mp_spiflash_release_bus(self); + } +} + STATIC int mp_spiflash_erase_block_internal(mp_spiflash_t *self, uint32_t addr) { // enable writes mp_spiflash_write_cmd(self, CMD_WREN); diff --git a/drivers/memory/spiflash.h b/drivers/memory/spiflash.h index a5b8a1dcae..96dfdeeab6 100644 --- a/drivers/memory/spiflash.h +++ b/drivers/memory/spiflash.h @@ -68,6 +68,7 @@ typedef struct _mp_spiflash_t { } mp_spiflash_t; void mp_spiflash_init(mp_spiflash_t *self); +void mp_spiflash_deepsleep(mp_spiflash_t *self, int value); // These functions go direct to the SPI flash device int mp_spiflash_erase_block(mp_spiflash_t *self, uint32_t addr); From ea033bf25a08c26b8b43fc316c797ae6526a894f Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Jul 2019 01:04:25 +1000 Subject: [PATCH 0493/1788] stm32/powerctrl: Add hooks for a board to perform actions on sleep/wake. --- ports/stm32/powerctrl.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c index 2ad2426005..e3ad20039c 100644 --- a/ports/stm32/powerctrl.c +++ b/ports/stm32/powerctrl.c @@ -324,6 +324,10 @@ void powerctrl_enter_stop_mode(void) { // executed until after the clocks are reconfigured uint32_t irq_state = disable_irq(); + #if defined(MICROPY_BOARD_ENTER_STOP) + MICROPY_BOARD_ENTER_STOP + #endif + #if defined(STM32L4) // Configure the MSI as the clock source after waking up __HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_MSI); @@ -399,6 +403,10 @@ void powerctrl_enter_stop_mode(void) { #endif + #if defined(MICROPY_BOARD_LEAVE_STOP) + MICROPY_BOARD_LEAVE_STOP + #endif + // Enable IRQs now that all clocks are reconfigured enable_irq(irq_state); } @@ -406,6 +414,10 @@ void powerctrl_enter_stop_mode(void) { void powerctrl_enter_standby_mode(void) { rtc_init_finalise(); + #if defined(MICROPY_BOARD_ENTER_STANDBY) + MICROPY_BOARD_ENTER_STANDBY + #endif + // We need to clear the PWR wake-up-flag before entering standby, since // the flag may have been set by a previous wake-up event. Furthermore, // we need to disable the wake-up sources while clearing this flag, so From d821a27b584740c21d451a882f7ca58d01486021 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Jul 2019 01:05:39 +1000 Subject: [PATCH 0494/1788] stm32/boards/PYBD_SFx: Put SPI flash to sleep during sleep modes. --- ports/stm32/boards/PYBD_SF2/board_init.c | 5 +++++ ports/stm32/boards/PYBD_SF2/mpconfigboard.h | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/ports/stm32/boards/PYBD_SF2/board_init.c b/ports/stm32/boards/PYBD_SF2/board_init.c index 3dc2c85e22..8438b82317 100644 --- a/ports/stm32/boards/PYBD_SF2/board_init.c +++ b/ports/stm32/boards/PYBD_SF2/board_init.c @@ -36,3 +36,8 @@ void board_early_init(void) { // Explicitly init SPI2 because it's not enabled as a block device spi_bdev_ioctl(&spi_bdev2, BDEV_IOCTL_INIT, (uint32_t)&spiflash2_config); } + +void board_sleep(int value) { + mp_spiflash_deepsleep(&spi_bdev.spiflash, value); + mp_spiflash_deepsleep(&spi_bdev2.spiflash, value); +} diff --git a/ports/stm32/boards/PYBD_SF2/mpconfigboard.h b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h index 56650ba158..a46b5ca5bc 100644 --- a/ports/stm32/boards/PYBD_SF2/mpconfigboard.h +++ b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h @@ -41,7 +41,11 @@ #define MICROPY_HW_ENABLE_MMCARD (1) #define MICROPY_BOARD_EARLY_INIT board_early_init +#define MICROPY_BOARD_ENTER_STOP board_sleep(1); +#define MICROPY_BOARD_LEAVE_STOP board_sleep(0); +#define MICROPY_BOARD_ENTER_STANDBY board_sleep(1); void board_early_init(void); +void board_sleep(int value); // HSE is 25MHz, run SYS at 120MHz #define MICROPY_HW_CLK_PLLM (20) From 6d2e654b1411d0816c8f7eaa159b9c57a2617859 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Jul 2019 11:21:45 +1000 Subject: [PATCH 0495/1788] stm32/mpconfigport.h: Enable useful networking modules if lwIP enabled. --- ports/stm32/mpconfigport.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index d802300637..5095dde52b 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -139,6 +139,9 @@ #define MICROPY_PY_URE_SUB (1) #define MICROPY_PY_UHEAPQ (1) #define MICROPY_PY_UHASHLIB (1) +#define MICROPY_PY_UHASHLIB_MD5 (MICROPY_PY_USSL) +#define MICROPY_PY_UHASHLIB_SHA1 (MICROPY_PY_USSL) +#define MICROPY_PY_UCRYPTOLIB (MICROPY_PY_USSL) #define MICROPY_PY_UBINASCII (1) #define MICROPY_PY_URANDOM (1) #define MICROPY_PY_URANDOM_EXTRA_FUNCS (1) @@ -160,6 +163,8 @@ #define MICROPY_PY_MACHINE_SPI_MAKE_NEW machine_hard_spi_make_new #define MICROPY_HW_SOFTSPI_MIN_DELAY (0) #define MICROPY_HW_SOFTSPI_MAX_BAUDRATE (HAL_RCC_GetSysClockFreq() / 48) +#define MICROPY_PY_UWEBSOCKET (MICROPY_PY_LWIP) +#define MICROPY_PY_WEBREPL (MICROPY_PY_LWIP) #define MICROPY_PY_FRAMEBUF (1) #ifndef MICROPY_PY_USOCKET #define MICROPY_PY_USOCKET (1) From 46b3cc4572036c9e2185b4aa8fb77dff29967680 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Jul 2019 11:51:13 +1000 Subject: [PATCH 0496/1788] stm32/usb: Add support to auto-detect USB interface, either FS or HS. If both FS and HS USB peripherals are enabled for a board then the active one used for the REPL will now be auto-detected, by checking to see if both the DP and DM lines are actively pulled low. By default the code falls back to use MICROPY_HW_USB_MAIN_DEV if nothing can be detected. --- ports/stm32/main.c | 2 +- ports/stm32/usb.c | 31 ++++++++++++++++++++++++++++--- ports/stm32/usb.h | 3 ++- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 1a1c505dc4..e470522fbd 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -652,7 +652,7 @@ soft_reset: #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, 0, NULL, NULL); + pyb_usb_dev_init(pyb_usb_dev_detect(), USBD_VID, USBD_PID_CDC_MSC, USBD_MODE_CDC_MSC, 0, NULL, NULL); } #endif diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index 69ba26c438..12e1388185 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -120,14 +120,39 @@ void pyb_usb_init0(void) { pyb_usb_vcp_init0(); } -bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, uint8_t mode, size_t msc_n, const void *msc_unit, USBD_HID_ModeInfoTypeDef *hid_info) { +int pyb_usb_dev_detect(void) { + if (usb_device.enabled) { + return usb_device.hUSBDDevice.id; + } + + #if MICROPY_HW_USB_FS && MICROPY_HW_USB_HS + // Try to auto-detect which USB is connected by reading DP/DM pins + for (int i = 0; i < 2; ++i) { + mp_hal_pin_obj_t dp = i == 0 ? pyb_pin_USB_DP : pyb_pin_USB_HS_DP; + mp_hal_pin_obj_t dm = i == 0 ? pyb_pin_USB_DM : pyb_pin_USB_HS_DM; + mp_hal_pin_config(dp, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_UP, 0); + mp_hal_pin_config(dm, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_UP, 0); + int state = mp_hal_pin_read(dp) == 0 && mp_hal_pin_read(dm) == 0; + mp_hal_pin_config(dp, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_NONE, 0); + mp_hal_pin_config(dm, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_NONE, 0); + if (state) { + // DP and DM pins are actively held low so assume USB is connected + return i == 0 ? USB_PHY_FS_ID : USB_PHY_HS_ID; + } + } + #endif + + return MICROPY_HW_USB_MAIN_DEV; +} + +bool pyb_usb_dev_init(int dev_id, uint16_t vid, uint16_t pid, uint8_t mode, size_t msc_n, const void *msc_unit, USBD_HID_ModeInfoTypeDef *hid_info) { usb_device_t *usb_dev = &usb_device; if (!usb_dev->enabled) { // only init USB once in the device's power-lifetime // set up the USBD state USBD_HandleTypeDef *usbd = &usb_dev->hUSBDDevice; - usbd->id = MICROPY_HW_USB_MAIN_DEV; + usbd->id = dev_id; usbd->dev_state = USBD_STATE_DEFAULT; usbd->pDesc = (USBD_DescriptorsTypeDef*)&USBD_Descriptors; usbd->pClass = &USBD_CDC_MSC_HID; @@ -403,7 +428,7 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * #endif // init the USB device - if (!pyb_usb_dev_init(vid, pid, mode, msc_n, msc_unit, &hid_info)) { + if (!pyb_usb_dev_init(pyb_usb_dev_detect(), vid, pid, mode, msc_n, msc_unit, &hid_info)) { goto bad_mode; } diff --git a/ports/stm32/usb.h b/ports/stm32/usb.h index b1c8b476a7..cb017902ec 100644 --- a/ports/stm32/usb.h +++ b/ports/stm32/usb.h @@ -66,7 +66,8 @@ MP_DECLARE_CONST_FUN_OBJ_0(pyb_have_cdc_obj); // deprecated MP_DECLARE_CONST_FUN_OBJ_1(pyb_hid_send_report_obj); // deprecated void pyb_usb_init0(void); -bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, uint8_t mode, size_t msc_n, const void *msc_unit, USBD_HID_ModeInfoTypeDef *hid_info); +int pyb_usb_dev_detect(void); +bool pyb_usb_dev_init(int dev_id, uint16_t vid, uint16_t pid, uint8_t mode, size_t msc_n, const void *msc_unit, USBD_HID_ModeInfoTypeDef *hid_info); void pyb_usb_dev_deinit(void); bool usb_vcp_is_enabled(void); int usb_vcp_recv_byte(uint8_t *c); // if a byte is available, return 1 and put the byte in *c, else return 0 From f114ce0a4b43474a73e9e5ddddbcf9a36553f954 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Jul 2019 11:58:56 +1000 Subject: [PATCH 0497/1788] stm32/usb: Add "port" keyword argument to pyb.usb_mode, to select FS/HS. If the board supports it, the USB port can now be explicitly specified, eg: pyb.usb_mode('VCP', port=0). port=0 is USB FS and port=1 is USB HS. --- ports/stm32/usb.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index 12e1388185..51e6e7a392 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -255,9 +255,10 @@ usbd_cdc_itf_t *usb_vcp_get(int idx) { */ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_mode, ARG_vid, ARG_pid, ARG_msc, ARG_hid, ARG_high_speed }; + enum { ARG_mode, ARG_port, ARG_vid, ARG_pid, ARG_msc, ARG_hid, ARG_high_speed }; static const mp_arg_t allowed_args[] = { { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_port, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, { 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_msc, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_empty_tuple_obj)} }, @@ -427,8 +428,14 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * } #endif + // Work out which port/peripheral to use, either user supplied or auto detect + int dev_id = args[ARG_port].u_int; + if (dev_id == -1) { + dev_id = pyb_usb_dev_detect(); + } + // init the USB device - if (!pyb_usb_dev_init(pyb_usb_dev_detect(), vid, pid, mode, msc_n, msc_unit, &hid_info)) { + if (!pyb_usb_dev_init(dev_id, vid, pid, mode, msc_n, msc_unit, &hid_info)) { goto bad_mode; } From 14bec7964fa49d905521caf697d94401eb789cfa Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Jul 2019 12:02:46 +1000 Subject: [PATCH 0498/1788] stm32/spi: Factor out code to calculate SPI source frequency. --- ports/stm32/spi.c | 86 ++++++++++++++++++----------------------------- 1 file changed, 33 insertions(+), 53 deletions(-) diff --git a/ports/stm32/spi.c b/ports/stm32/spi.c index 545cb3365e..e6336fb5d0 100644 --- a/ports/stm32/spi.c +++ b/ports/stm32/spi.c @@ -186,6 +186,37 @@ int spi_find_index(mp_obj_t id) { } } +STATIC uint32_t spi_get_source_freq(SPI_HandleTypeDef *spi) { + #if defined(STM32F0) + return HAL_RCC_GetPCLK1Freq(); + #elif defined(STM32H7) + if (spi->Instance == SPI1 || spi->Instance == SPI2 || spi->Instance == SPI3) { + return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI123); + } else if (spi->Instance == SPI4 || spi->Instance == SPI5) { + return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI45); + } else { + return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI6); + } + #else + #if defined(SPI2) + if (spi->Instance == SPI2) { + // SPI2 is on APB1 + return HAL_RCC_GetPCLK1Freq(); + } else + #endif + #if defined(SPI3) + if (spi->Instance == SPI3) { + // SPI3 is on APB1 + return HAL_RCC_GetPCLK1Freq(); + } else + #endif + { + // SPI1, SPI4, SPI5 and SPI6 are on APB2 + return HAL_RCC_GetPCLK2Freq(); + } + #endif +} + // sets the parameters in the SPI_InitTypeDef struct // if an argument is -1 then the corresponding parameter is not changed void spi_set_params(const spi_t *spi_obj, uint32_t prescale, int32_t baudrate, @@ -196,32 +227,7 @@ void spi_set_params(const spi_t *spi_obj, uint32_t prescale, int32_t baudrate, if (prescale != 0xffffffff || baudrate != -1) { 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(); - #elif defined(STM32H7) - if (spi->Instance == SPI1 || spi->Instance == SPI2 || spi->Instance == SPI3) { - spi_clock = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI123); - } else if (spi->Instance == SPI4 || spi->Instance == SPI5) { - spi_clock = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI45); - } else { - spi_clock = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI6); - } - #else - if (spi->Instance == SPI3) { - // SPI3 is on APB1 - spi_clock = HAL_RCC_GetPCLK1Freq(); - #if defined(SPI2) - } else if (spi->Instance == SPI2) { - // SPI2 is on APB1 - spi_clock = HAL_RCC_GetPCLK1Freq(); - #endif - } else { - // SPI1, SPI4, SPI5 and SPI6 are on APB2 - spi_clock = HAL_RCC_GetPCLK2Freq(); - } - #endif - prescale = (spi_clock + baudrate - 1) / baudrate; + prescale = (spi_get_source_freq(spi) + baudrate - 1) / baudrate; } if (prescale <= 2) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; } else if (prescale <= 4) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; } @@ -578,34 +584,8 @@ void spi_print(const mp_print_t *print, const spi_t *spi_obj, bool legacy) { if (spi->State != HAL_SPI_STATE_RESET) { if (spi->Init.Mode == SPI_MODE_MASTER) { // compute baudrate - uint spi_clock; - #if defined(STM32F0) - spi_clock = HAL_RCC_GetPCLK1Freq(); - #elif defined(STM32H7) - if (spi->Instance == SPI1 || spi->Instance == SPI2 || spi->Instance == SPI3) { - spi_clock = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI123); - } else if (spi->Instance == SPI4 || spi->Instance == SPI5) { - spi_clock = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI45); - } else { - spi_clock = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI6); - } - #else - #if defined(SPI2) - if (spi->Instance == SPI2) { - // SPI2 is on APB1 - spi_clock = HAL_RCC_GetPCLK1Freq(); - } else - #endif - if (spi->Instance == SPI3) { - // SPI2 and SPI3 are on APB1 - spi_clock = HAL_RCC_GetPCLK1Freq(); - } else { - // 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; + uint baudrate = spi_get_source_freq(spi) >> log_prescaler; if (legacy) { mp_printf(print, ", SPI.MASTER"); } From 79b66885583925cc0854f32f487627d4d188ed64 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Jul 2019 12:02:58 +1000 Subject: [PATCH 0499/1788] stm32/extint: Simplify bitband support config for different MCUs. --- ports/stm32/extint.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/ports/stm32/extint.c b/ports/stm32/extint.c index 4a67d1824f..0b1ba8eb09 100644 --- a/ports/stm32/extint.c +++ b/ports/stm32/extint.c @@ -84,11 +84,12 @@ // TODO Add python method to change callback object. +#if defined(STM32F4) || defined(STM32L4) +// These MCUs have bitband support so define macros to atomically set/clear bits in IMR/EMR and SWIER #define EXTI_OFFSET (EXTI_BASE - PERIPH_BASE) - -// Macro used to set/clear the bit corresponding to the line in the IMR/EMR -// 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))) +#define EXTI_SWIER_BB(line) (*(__IO uint32_t *)(PERIPH_BB_BASE + ((EXTI_OFFSET + offsetof(EXTI_TypeDef, SWIER)) * 32) + ((line) * 4))) +#endif #if defined(STM32L4) // The L4 MCU supports 40 Events/IRQs lines of the type configurable and direct. @@ -116,8 +117,6 @@ #define EXTI_FTSR EXTI->FTSR #endif -#define EXTI_SWIER_BB(line) (*(__IO uint32_t *)(PERIPH_BB_BASE + ((EXTI_OFFSET + offsetof(EXTI_TypeDef, SWIER)) * 32) + ((line) * 4))) - typedef struct { mp_obj_base_t base; mp_int_t line; @@ -349,8 +348,8 @@ void extint_enable(uint line) { if (line >= EXTI_NUM_VECTORS) { return; } - #if defined(STM32F0) || defined(STM32F7) || defined(STM32H7) - // The Cortex-M7 doesn't have bitband support. + #if !defined(EXTI_MODE_BB) + // This MCU doesn't have bitband support. mp_uint_t irq_state = disable_irq(); if (pyb_extint_mode[line] == EXTI_Mode_Interrupt) { #if defined(STM32H7) @@ -379,8 +378,8 @@ void extint_disable(uint line) { return; } - #if defined(STM32F0) || defined(STM32F7) || defined(STM32H7) - // The Cortex-M7 doesn't have bitband support. + #if !defined(EXTI_MODE_BB) + // This MCU doesn't have bitband support. mp_uint_t irq_state = disable_irq(); #if defined(STM32H7) EXTI_D1->IMR1 &= ~(1 << line); @@ -417,8 +416,8 @@ void extint_trigger_mode(uint line, uint32_t mode) { if (line >= EXTI_NUM_VECTORS) { return; } - #if defined(STM32F0) || defined(STM32F7) || defined(STM32H7) - // The Cortex-M7 doesn't have bitband support. + #if !defined(EXTI_MODE_BB) + // This MCU doesn't have bitband support. mp_uint_t irq_state = disable_irq(); // Enable or disable the rising detector if ((mode & GPIO_MODE_IT_RISING) == GPIO_MODE_IT_RISING) { From fad3d08d2df4b7e62627969510c1507615c5ad3c Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Jul 2019 12:47:13 +1000 Subject: [PATCH 0500/1788] extmod/moduwebsocket: Make close_resp static array const to not use RAM. The esp8266 lwip_open library is compiled with -mforce-l32 so this array does not need to be in RAM. --- extmod/moduwebsocket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extmod/moduwebsocket.c b/extmod/moduwebsocket.c index eb5e20c6e3..d90ee49a74 100644 --- a/extmod/moduwebsocket.c +++ b/extmod/moduwebsocket.c @@ -194,7 +194,7 @@ no_payload: if (last_state == CONTROL) { byte frame_type = self->last_flags & FRAME_OPCODE_MASK; if (frame_type == FRAME_CLOSE) { - static char close_resp[2] = {0x88, 0}; + static const char close_resp[2] = {0x88, 0}; int err; websocket_write(self_in, close_resp, sizeof(close_resp), &err); return 0; From fa2c7ece8f0c48cab77098f8f4ffe940c459dfee Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Jul 2019 12:50:13 +1000 Subject: [PATCH 0501/1788] extmod/modwebrepl: Make prompt/ver static arrays const to not use RAM. The esp8266 lwip_open library is compiled with -mforce-l32 so these arrays do not need to be in RAM. --- extmod/modwebrepl.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/extmod/modwebrepl.c b/extmod/modwebrepl.c index c9ef774340..3c0cfe72f7 100644 --- a/extmod/modwebrepl.c +++ b/extmod/modwebrepl.c @@ -67,10 +67,9 @@ typedef struct _mp_obj_webrepl_t { mp_obj_t cur_file; } mp_obj_webrepl_t; -// These get passed to functions which aren't force-l32, so can't be const -STATIC char passwd_prompt[] = "Password: "; -STATIC char connected_prompt[] = "\r\nWebREPL connected\r\n>>> "; -STATIC char denied_prompt[] = "\r\nAccess denied\r\n"; +STATIC const char passwd_prompt[] = "Password: "; +STATIC const char connected_prompt[] = "\r\nWebREPL connected\r\n>>> "; +STATIC const char denied_prompt[] = "\r\nAccess denied\r\n"; STATIC char webrepl_passwd[10]; @@ -138,7 +137,7 @@ STATIC void handle_op(mp_obj_webrepl_t *self) { switch (self->hdr.type) { case GET_VER: { - static char ver[] = {MICROPY_VERSION_MAJOR, MICROPY_VERSION_MINOR, MICROPY_VERSION_MICRO}; + static const char ver[] = {MICROPY_VERSION_MAJOR, MICROPY_VERSION_MINOR, MICROPY_VERSION_MICRO}; write_webrepl(self->sock, ver, sizeof(ver)); self->hdr_to_recv = sizeof(struct webrepl_file); return; From ef00048fed079c922a4e2bc9ce854cc3824e2bfc Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Jul 2019 12:55:57 +1000 Subject: [PATCH 0502/1788] extmod/modwebrepl: Add config option to put filebuf[512] on stack/bss. Since the esp8266 has a small stack this buffer is kept in the BSS. --- extmod/modwebrepl.c | 6 +++++- ports/esp8266/mpconfigport.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/extmod/modwebrepl.c b/extmod/modwebrepl.c index 3c0cfe72f7..c92d1dc1b0 100644 --- a/extmod/modwebrepl.c +++ b/extmod/modwebrepl.c @@ -245,7 +245,11 @@ STATIC mp_uint_t _webrepl_read(mp_obj_t self_in, void *buf, mp_uint_t size, int } if (self->data_to_recv != 0) { - static byte filebuf[512]; + // Ports that don't have much available stack can make this filebuf static + #if MICROPY_PY_WEBREPL_STATIC_FILEBUF + static + #endif + byte filebuf[512]; filebuf[0] = *(byte*)buf; mp_uint_t buf_sz = 1; if (--self->data_to_recv != 0) { diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h index 03be59b063..3bf8220282 100644 --- a/ports/esp8266/mpconfigport.h +++ b/ports/esp8266/mpconfigport.h @@ -90,6 +90,7 @@ #define MICROPY_PY_UWEBSOCKET (1) #define MICROPY_PY_WEBREPL (1) #define MICROPY_PY_WEBREPL_DELAY (20) +#define MICROPY_PY_WEBREPL_STATIC_FILEBUF (1) #define MICROPY_PY_FRAMEBUF (1) #define MICROPY_PY_MICROPYTHON_MEM_INFO (1) #define MICROPY_PY_OS_DUPTERM (2) From 1d6cb6357a2cde40822712211fb51c4a4bbe41cf Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Jul 2019 15:50:13 +1000 Subject: [PATCH 0503/1788] extmod/modlwip: For TCP send keep trying tcp_write if it returns ERR_MEM If tcp_write returns ERR_MEM then it's not a fatal error but instead means the caller should retry the write later on (and this is what lwIP's netconn API does). This fixes problems where a TCP send would raise OSError(ENOMEM) in situations where the TCP/IP stack is under heavy load. See eg issues #1897 and #1971. --- extmod/modlwip.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index 4127d21add..aed69f9200 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -668,7 +668,25 @@ STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui u16_t write_len = MIN(available, len); - err_t err = tcp_write(socket->pcb.tcp, buf, write_len, TCP_WRITE_FLAG_COPY); + // If tcp_write returns ERR_MEM then there's currently not enough memory to + // queue the write, so wait and keep trying until it succeeds (with 10s limit). + // Note: if the socket is non-blocking then this code will actually block until + // there's enough memory to do the write, but by this stage we have already + // committed to being able to write the data. + err_t err; + for (int i = 0; i < 200; ++i) { + err = tcp_write(socket->pcb.tcp, buf, write_len, TCP_WRITE_FLAG_COPY); + if (err != ERR_MEM) { + break; + } + err = tcp_output(socket->pcb.tcp); + if (err != ERR_OK) { + break; + } + MICROPY_PY_LWIP_EXIT + mp_hal_delay_ms(50); + MICROPY_PY_LWIP_REENTER + } // 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) { From c60caf19951c8326be9c3b6f3b016a4d21f69276 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Jul 2019 16:22:48 +1000 Subject: [PATCH 0504/1788] extmod/modlwip: Use mp_sched_schedule to schedule socket callbacks. The helper function exec_user_callback executes within the context of an lwIP C callback, and the user (Python) callback to be scheduled may want to perform further TCP/IP actions, so the latter should be scheduled to run outside the lwIP context (otherwise it's effectively a "hard IRQ" and such callbacks have lots of restrictions). --- extmod/modlwip.c | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index aed69f9200..be932b6a9d 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -356,7 +356,8 @@ STATIC void lwip_socket_free_incoming(lwip_socket_obj_t *socket) { static inline void exec_user_callback(lwip_socket_obj_t *socket) { if (socket->callback != MP_OBJ_NULL) { - mp_call_function_1_protected(socket->callback, MP_OBJ_FROM_PTR(socket)); + // Schedule the user callback to execute outside the lwIP context + mp_sched_schedule(socket->callback, MP_OBJ_FROM_PTR(socket)); } } @@ -446,18 +447,6 @@ STATIC err_t _lwip_tcp_recv_unaccepted(void *arg, struct tcp_pcb *pcb, struct pb return ERR_BUF; } -// "Poll" (idle) callback to be called ASAP after accept callback -// to execute Python callback function, as it can't be executed -// from accept callback itself. -STATIC err_t _lwip_tcp_accept_finished(void *arg, struct tcp_pcb *pcb) -{ - // The ->connected entry of the pcb holds the listening socket of the accept - lwip_socket_obj_t *socket = (lwip_socket_obj_t*)pcb->connected; - tcp_poll(pcb, NULL, 0); - exec_user_callback(socket); - return ERR_OK; -} - // Callback for incoming tcp connections. STATIC err_t _lwip_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err) { // err can be ERR_MEM to notify us that there was no memory for an incoming connection @@ -476,12 +465,9 @@ STATIC err_t _lwip_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err) { if (++socket->incoming.connection.iput >= socket->incoming.connection.alloc) { socket->incoming.connection.iput = 0; } - if (socket->callback != MP_OBJ_NULL) { - // Schedule accept callback to be called when lwIP is done - // with processing this incoming connection on its side and - // is idle. - tcp_poll(newpcb, _lwip_tcp_accept_finished, 1); - } + + // Schedule user accept callback + exec_user_callback(socket); // Set the error callback to handle the case of a dropped connection before we // have a chance to take it off the accept queue. From f88cb8a51412d8570e473045adf09699664f553a Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Jul 2019 16:46:07 +1000 Subject: [PATCH 0505/1788] stm32/modmachine: Make RTC class available in machine module. This is a start to make a more consistent machine.RTC class across ports. The stm32 pyb.RTC class at least has the datetime() method which behaves the same as esp8266 and esp32, and with this patch the ntptime.py script now works with stm32. --- ports/stm32/modmachine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index a4ee47470b..7ea14bdcd6 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -384,8 +384,8 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pin_type) }, { MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) }, -#if 0 { MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&pyb_rtc_type) }, +#if 0 { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pyb_adc_type) }, #endif #if MICROPY_PY_MACHINE_I2C From 3581deec816ff88a7dc2c0274b7c60b11e4ade34 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Jul 2019 16:50:02 +1000 Subject: [PATCH 0506/1788] stm32/boards/PYBD_SF2: Put mbedtls library code in external QSPI flash. mbedtls is large and self contained so is a good candidate to be in external XIP flash, to keep enough spare ROM in internal flash. --- ports/stm32/boards/PYBD_SF2/f722_qspi.ld | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/stm32/boards/PYBD_SF2/f722_qspi.ld b/ports/stm32/boards/PYBD_SF2/f722_qspi.ld index b6d3e08e30..554d34b492 100644 --- a/ports/stm32/boards/PYBD_SF2/f722_qspi.ld +++ b/ports/stm32/boards/PYBD_SF2/f722_qspi.ld @@ -47,6 +47,8 @@ SECTIONS { .text_ext : { + . = ALIGN(4); + *lib/mbedtls/*(.text* .rodata*) . = ALIGN(512); *(.big_const*) . = ALIGN(4); From 9083166c4f943938afd160918f1be6dc31861557 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Jul 2019 23:36:43 +1000 Subject: [PATCH 0507/1788] lib/stm32lib: Update library for updated H7xx, new L0xx, new WBxx. And this library now includes the startup_stm32*.s files for each MCU. --- lib/stm32lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/stm32lib b/lib/stm32lib index 615329f1a6..668d7a9e54 160000 --- a/lib/stm32lib +++ b/lib/stm32lib @@ -1 +1 @@ -Subproject commit 615329f1a61bd0689bfb095cb3fd74865cca88ff +Subproject commit 668d7a9e54aea98f8fe8a858eac1d3daa80fa824 From 73e8b7e0e4a7c9f89094ffe7d93c6d897a86b67a Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Jul 2019 23:40:49 +1000 Subject: [PATCH 0508/1788] stm32: Update components to work with new H7xx HAL. --- ports/stm32/adc.c | 2 -- ports/stm32/boards/stm32h7xx_hal_conf_base.h | 1 + ports/stm32/mphalport.h | 5 ----- ports/stm32/stm32_it.c | 2 ++ ports/stm32/uart.c | 2 ++ ports/stm32/uart.h | 2 ++ ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c | 6 ++++++ 7 files changed, 13 insertions(+), 7 deletions(-) diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index 46fbbe7364..1215690333 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -110,7 +110,6 @@ #define ADC_CAL1 ((uint16_t*)(0x1FF1E820)) #define ADC_CAL2 ((uint16_t*)(0x1FF1E840)) #define ADC_CAL_BITS (16) -#define ADC_CHANNEL_VBAT ADC_CHANNEL_VBAT_DIV4 #elif defined(STM32L4) @@ -247,7 +246,6 @@ STATIC void adcx_init_periph(ADC_HandleTypeDef *adch, uint32_t resolution) { 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; diff --git a/ports/stm32/boards/stm32h7xx_hal_conf_base.h b/ports/stm32/boards/stm32h7xx_hal_conf_base.h index 334c6df4bd..1d06be14fa 100644 --- a/ports/stm32/boards/stm32h7xx_hal_conf_base.h +++ b/ports/stm32/boards/stm32h7xx_hal_conf_base.h @@ -28,6 +28,7 @@ // Include various HAL modules for convenience #include "stm32h7xx_hal_dma.h" +#include "stm32h7xx_hal_mdma.h" #include "stm32h7xx_hal_adc.h" #include "stm32h7xx_hal_cortex.h" #include "stm32h7xx_hal_crc.h" diff --git a/ports/stm32/mphalport.h b/ports/stm32/mphalport.h index 0c163fbf85..bd71adf77b 100644 --- a/ports/stm32/mphalport.h +++ b/ports/stm32/mphalport.h @@ -63,13 +63,8 @@ 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) diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index a3740d59cd..fd3aea6c1c 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -378,8 +378,10 @@ void OTG_FS_WKUP_IRQHandler(void) { OTG_CMD_WKUP_Handler(&pcd_fs_handle); + #if !defined(STM32H7) /* Clear EXTI pending Bit*/ __HAL_USB_FS_EXTI_CLEAR_FLAG(); + #endif IRQ_EXIT(OTG_FS_WKUP_IRQn); } diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c index 317dbe95b6..3a21a0b31e 100644 --- a/ports/stm32/uart.c +++ b/ports/stm32/uart.c @@ -40,6 +40,8 @@ #if defined(STM32F4) #define UART_RXNE_IS_SET(uart) ((uart)->SR & USART_SR_RXNE) +#elif defined(STM32H7) +#define UART_RXNE_IS_SET(uart) ((uart)->ISR & USART_ISR_RXNE_RXFNE) #else #define UART_RXNE_IS_SET(uart) ((uart)->ISR & USART_ISR_RXNE) #endif diff --git a/ports/stm32/uart.h b/ports/stm32/uart.h index 9b0d139588..62676fb91b 100644 --- a/ports/stm32/uart.h +++ b/ports/stm32/uart.h @@ -88,6 +88,8 @@ void uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len); static inline bool uart_tx_avail(pyb_uart_obj_t *self) { #if defined(STM32F4) return self->uartx->SR & USART_SR_TXE; + #elif defined(STM32H7) + return self->uartx->ISR & USART_ISR_TXE_TXFNF; #else return self->uartx->ISR & USART_ISR_TXE; #endif 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 d982fe8e6f..627fb054c0 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -1129,6 +1129,9 @@ uint8_t USBD_HID_SetNAK(usbd_hid_state_t *hid) { // get USBx object from pdev (needed for USBx_OUTEP macro below) PCD_HandleTypeDef *hpcd = hid->usbd->pdev->pData; USB_OTG_GlobalTypeDef *USBx = hpcd->Instance; + #if defined(STM32H7) + uint32_t USBx_BASE = (uint32_t)USBx; + #endif // set NAK on HID OUT endpoint USBx_OUTEP(HID_OUT_EP_WITH_CDC)->DOEPCTL |= USB_OTG_DOEPCTL_SNAK; return USBD_OK; @@ -1138,6 +1141,9 @@ uint8_t USBD_HID_ClearNAK(usbd_hid_state_t *hid) { // get USBx object from pdev (needed for USBx_OUTEP macro below) PCD_HandleTypeDef *hpcd = hid->usbd->pdev->pData; USB_OTG_GlobalTypeDef *USBx = hpcd->Instance; + #if defined(STM32H7) + uint32_t USBx_BASE = (uint32_t)USBx; + #endif // clear NAK on HID OUT endpoint USBx_OUTEP(HID_OUT_EP_WITH_CDC)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; return USBD_OK; From 241e57775359bc55738cb56b044ba4cc9056eba5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Jul 2019 23:41:33 +1000 Subject: [PATCH 0509/1788] stm32/Makefile: Remove Wno-attributes for ll_usb HAL file. This HAL file is now patched so it doesn't have these warnings. --- ports/stm32/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 153ea44626..45d4653dba 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -319,7 +319,6 @@ SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ ) ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 h7 l4)) -$(BUILD)/$(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_ll_usb.o: CFLAGS += -Wno-attributes SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ hal_sd.c \ ll_sdmmc.c \ From 6b6403ce76e11fd564d9bbe90f190c99fe4e4fa2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Jul 2019 23:42:36 +1000 Subject: [PATCH 0510/1788] stm32/Makefile: Use startup_stm32*.s file from stm32lib. This means that each MCU now gets a unique IRQ table, eg a specific one for STM32F405, STM32F411, etc rather than just STM32F4xx. --- ports/stm32/Makefile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 45d4653dba..3967e63117 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -24,9 +24,11 @@ FROZEN_MPY_DIR ?= modules # include py core make definitions include $(TOP)/py/py.mk +MCU_SERIES_UPPER = $(shell echo $(MCU_SERIES) | tr '[:lower:]' '[:upper:]') +CMSIS_MCU_LOWER = $(shell echo $(CMSIS_MCU) | tr '[:upper:]' '[:lower:]') + LD_DIR=boards 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 #USBHOST_DIR=usbhost @@ -40,7 +42,7 @@ DEVICE=0483:df11 STFLASH ?= st-flash OPENOCD ?= openocd OPENOCD_CONFIG ?= boards/openocd_stm32f4.cfg -STARTUP_FILE ?= boards/startup_stm32$(MCU_SERIES).o +STARTUP_FILE ?= lib/stm32lib/CMSIS/STM32$(MCU_SERIES_UPPER)xx/Source/Templates/gcc/startup_$(CMSIS_MCU_LOWER).o # Select the cross compile prefix CROSS_COMPILE ?= arm-none-eabi- @@ -576,7 +578,6 @@ GEN_PLLFREQTABLE_HDR = $(HEADER_BUILD)/pllfreqtable.h GEN_STMCONST_HDR = $(HEADER_BUILD)/modstm_const.h GEN_STMCONST_QSTR = $(BUILD)/modstm_qstr.h GEN_STMCONST_MPZ = $(HEADER_BUILD)/modstm_mpz.h -CMSIS_MCU_LOWER = $(shell echo $(CMSIS_MCU) | tr '[:upper:]' '[:lower:]') CMSIS_MCU_HDR = $(CMSIS_DIR)/$(CMSIS_MCU_LOWER).h modmachine.c: $(GEN_PLLFREQTABLE_HDR) From 7cf8285ac852c86d102fb85383e955f836222e69 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Jul 2019 23:44:17 +1000 Subject: [PATCH 0511/1788] stm32/boards: Remove startup_stm32*.s files now they are in stm32lib. --- ports/stm32/boards/startup_stm32f0.s | 303 --------- ports/stm32/boards/startup_stm32f4.s | 530 ---------------- ports/stm32/boards/startup_stm32f413xx.s | 580 ----------------- ports/stm32/boards/startup_stm32f7.s | 604 ------------------ ports/stm32/boards/startup_stm32h7.s | 763 ----------------------- ports/stm32/boards/startup_stm32l4.s | 549 ---------------- 6 files changed, 3329 deletions(-) delete mode 100644 ports/stm32/boards/startup_stm32f0.s delete mode 100644 ports/stm32/boards/startup_stm32f4.s delete mode 100644 ports/stm32/boards/startup_stm32f413xx.s delete mode 100644 ports/stm32/boards/startup_stm32f7.s delete mode 100644 ports/stm32/boards/startup_stm32h7.s delete mode 100644 ports/stm32/boards/startup_stm32l4.s diff --git a/ports/stm32/boards/startup_stm32f0.s b/ports/stm32/boards/startup_stm32f0.s deleted file mode 100644 index eb5c4961e0..0000000000 --- a/ports/stm32/boards/startup_stm32f0.s +++ /dev/null @@ -1,303 +0,0 @@ -/** - ****************************************************************************** - * @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****/ - diff --git a/ports/stm32/boards/startup_stm32f4.s b/ports/stm32/boards/startup_stm32f4.s deleted file mode 100644 index 3e29a79a56..0000000000 --- a/ports/stm32/boards/startup_stm32f4.s +++ /dev/null @@ -1,530 +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 - .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 */ - .word UART7_IRQHandler /* UART7 */ - .word UART8_IRQHandler /* UART8 */ - -/******************************************************************************* -* -* 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 - - .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/startup_stm32f413xx.s b/ports/stm32/boards/startup_stm32f413xx.s deleted file mode 100644 index 64108ad38d..0000000000 --- a/ports/stm32/boards/startup_stm32f413xx.s +++ /dev/null @@ -1,580 +0,0 @@ -/** - ****************************************************************************** - * @file startup_stm32f413xx.s - * @author MCD Application Team - * @brief STM32F413xx Devices vector table for GCC based toolchains. - * 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 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-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 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 M3. 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, DAC1 and DAC2 */ - .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 DFSDM1_FLT0_IRQHandler /* DFSDM1 Filter0 */ - .word DFSDM1_FLT1_IRQHandler /* DFSDM1 Filter1 */ - .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 CAN3_TX_IRQHandler /* CAN3 TX */ - .word CAN3_RX0_IRQHandler /* CAN3 RX0 */ - .word CAN3_RX1_IRQHandler /* CAN3 RX1 */ - .word CAN3_SCE_IRQHandler /* CAN3 SCE */ - .word 0 /* Reserved */ - .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 0 /* Reserved */ - .word SAI1_IRQHandler /* SAI1 */ - .word UART9_IRQHandler /* UART9 */ - .word UART10_IRQHandler /* UART10 */ - .word 0 /* Reserved */ - .word 0 /* Reserved */ - .word QUADSPI_IRQHandler /* QuadSPI */ - .word 0 /* Reserved */ - .word 0 /* Reserved */ - .word FMPI2C1_EV_IRQHandler /* FMPI2C1 Event */ - .word FMPI2C1_ER_IRQHandler /* FMPI2C1 Error */ - .word LPTIM1_IRQHandler /* LPTIM1 */ - .word DFSDM2_FLT0_IRQHandler /* DFSDM2 Filter0 */ - .word DFSDM2_FLT1_IRQHandler /* DFSDM2 Filter1 */ - .word DFSDM2_FLT2_IRQHandler /* DFSDM2 Filter2 */ - .word DFSDM2_FLT3_IRQHandler /* DFSDM2 Filter3 */ - -/******************************************************************************* -* -* 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 DFSDM1_FLT0_IRQHandler - .thumb_set DFSDM1_FLT0_IRQHandler,Default_Handler - - .weak DFSDM1_FLT1_IRQHandler - .thumb_set DFSDM1_FLT1_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 CAN3_TX_IRQHandler - .thumb_set CAN3_TX_IRQHandler,Default_Handler - - .weak CAN3_RX0_IRQHandler - .thumb_set CAN3_RX0_IRQHandler,Default_Handler - - .weak CAN3_RX1_IRQHandler - .thumb_set CAN3_RX1_IRQHandler,Default_Handler - - .weak CAN3_SCE_IRQHandler - .thumb_set CAN3_SCE_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 SAI1_IRQHandler - .thumb_set SAI1_IRQHandler,Default_Handler - - .weak UART9_IRQHandler - .thumb_set UART9_IRQHandler,Default_Handler - - .weak UART10_IRQHandler - .thumb_set UART10_IRQHandler,Default_Handler - - .weak QUADSPI_IRQHandler - .thumb_set QUADSPI_IRQHandler,Default_Handler - - .weak FMPI2C1_EV_IRQHandler - .thumb_set FMPI2C1_EV_IRQHandler,Default_Handler - - .weak FMPI2C1_ER_IRQHandler - .thumb_set FMPI2C1_ER_IRQHandler,Default_Handler - - .weak LPTIM1_IRQHandler - .thumb_set LPTIM1_IRQHandler,Default_Handler - - .weak DFSDM2_FLT0_IRQHandler - .thumb_set DFSDM2_FLT0_IRQHandler,Default_Handler - - .weak DFSDM2_FLT1_IRQHandler - .thumb_set DFSDM2_FLT1_IRQHandler,Default_Handler - - .weak DFSDM2_FLT2_IRQHandler - .thumb_set DFSDM2_FLT2_IRQHandler,Default_Handler - - .weak DFSDM2_FLT3_IRQHandler - .thumb_set DFSDM2_FLT3_IRQHandler,Default_Handler -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32/boards/startup_stm32f7.s b/ports/stm32/boards/startup_stm32f7.s deleted file mode 100644 index 633ba01e93..0000000000 --- a/ports/stm32/boards/startup_stm32f7.s +++ /dev/null @@ -1,604 +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 - .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****/ diff --git a/ports/stm32/boards/startup_stm32h7.s b/ports/stm32/boards/startup_stm32h7.s deleted file mode 100644 index 53d46205fd..0000000000 --- a/ports/stm32/boards/startup_stm32h7.s +++ /dev/null @@ -1,763 +0,0 @@ -/** - ****************************************************************************** - * @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****/ - diff --git a/ports/stm32/boards/startup_stm32l4.s b/ports/stm32/boards/startup_stm32l4.s deleted file mode 100644 index 3225723ff5..0000000000 --- a/ports/stm32/boards/startup_stm32l4.s +++ /dev/null @@ -1,549 +0,0 @@ -/** - ****************************************************************************** - * @file startup_stm32l496xx.s - * @author MCD Application Team - * @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, - * - Branches to main in the C library (which eventually - * calls main()). - * 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 2017 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. - * - ****************************************************************************** - */ - - .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 */ - -.equ BootRAM, 0xF1E0F85F -/** - * @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. 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 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 */ - .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 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 */ - .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 */ - /* 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 */ - -/******************************************************************************* -* -* 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 DFSDM1_FLT3_IRQHandler - .thumb_set DFSDM1_FLT3_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 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 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 - - .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****/ From 592f68449d8261f978a8d0198f9eaf9bc76927d3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Jul 2019 23:49:49 +1000 Subject: [PATCH 0512/1788] stm32/mpu: Include MPU functions when ETH is enabled. --- ports/stm32/mpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/mpu.h b/ports/stm32/mpu.h index 2541d86bfb..1efe93a68b 100644 --- a/ports/stm32/mpu.h +++ b/ports/stm32/mpu.h @@ -26,7 +26,7 @@ #ifndef MICROPY_INCLUDED_STM32_MPU_H #define MICROPY_INCLUDED_STM32_MPU_H -#if defined(STM32F7) || defined(STM32H7) +#if defined(STM32F7) || defined(STM32H7) || defined(MICROPY_HW_ETH_MDC) #define MPU_REGION_ETH (MPU_REGION_NUMBER0) #define MPU_REGION_QSPI1 (MPU_REGION_NUMBER1) From 1b79484ee3bfdb7cbd68a17effe60407580398c2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 4 Jul 2019 10:36:23 +1000 Subject: [PATCH 0513/1788] lib/lwip: Update lwIP to v2.1.2, tag STABLE-2_1_2_RELEASE. --- lib/lwip | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/lwip b/lib/lwip index 92f23d6ca0..159e31b689 160000 --- a/lib/lwip +++ b/lib/lwip @@ -1 +1 @@ -Subproject commit 92f23d6ca0971a32f2085b9480e738d34174417b +Subproject commit 159e31b689577dbf69cf0683bbaffbd71fa5ee10 From 04da8864e5113e8ef8d4b017bb277b145cfcf34f Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 4 Jul 2019 10:36:51 +1000 Subject: [PATCH 0514/1788] stm32/lwip_inc: Define LWIP_NO_CTYPE_H=1 to use lwIP ctype funcs. --- ports/stm32/lwip_inc/arch/cc.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/stm32/lwip_inc/arch/cc.h b/ports/stm32/lwip_inc/arch/cc.h index 635b1c8056..fc5230ef72 100644 --- a/ports/stm32/lwip_inc/arch/cc.h +++ b/ports/stm32/lwip_inc/arch/cc.h @@ -5,4 +5,6 @@ #define LWIP_PLATFORM_DIAG(x) #define LWIP_PLATFORM_ASSERT(x) { assert(1); } +#define LWIP_NO_CTYPE_H 1 + #endif // MICROPY_INCLUDED_STM32_LWIP_ARCH_CC_H From afb2e9dd942a77125d4447a96def5be48fee19af Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 4 Jul 2019 10:49:51 +1000 Subject: [PATCH 0515/1788] stm32/modmachine: Disable IRQs before entering bootloader. To make sure that the code that enters the bootloader is not interrupted. --- ports/stm32/modmachine.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index 7ea14bdcd6..ba0ee28471 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -257,6 +257,8 @@ STATIC NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args) storage_flush(); #endif + __disable_irq(); + #if MICROPY_HW_USES_BOOTLOADER if (n_args == 0 || !mp_obj_is_true(args[0])) { // By default, with no args given, we enter the custom bootloader (mboot) From 1cd2bc066de7cfec778631d99fe64d29b093ba80 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 4 Jul 2019 11:03:10 +1000 Subject: [PATCH 0516/1788] stm32/boards/PYBD_SFx: Configure EN_3V3 pin as output on boot. But leave it turned off, the application must turn it on if/when needed. --- ports/stm32/boards/PYBD_SF2/board_init.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ports/stm32/boards/PYBD_SF2/board_init.c b/ports/stm32/boards/PYBD_SF2/board_init.c index 8438b82317..a8cf10f3a5 100644 --- a/ports/stm32/boards/PYBD_SF2/board_init.c +++ b/ports/stm32/boards/PYBD_SF2/board_init.c @@ -33,6 +33,9 @@ void mboot_board_early_init(void) { } void board_early_init(void) { + // Configure EN_3V3 as an output pin, but keep it turned off + mp_hal_pin_config(pyb_pin_EN_3V3, MP_HAL_PIN_MODE_OUTPUT, MP_HAL_PIN_PULL_NONE, 0); + // Explicitly init SPI2 because it's not enabled as a block device spi_bdev_ioctl(&spi_bdev2, BDEV_IOCTL_INIT, (uint32_t)&spiflash2_config); } From 7f33f158b9212846b94c737793da4df71825df48 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 4 Jul 2019 11:10:54 +1000 Subject: [PATCH 0517/1788] stm32/sdcard: Add hook for a board to power on SD/MMC. --- ports/stm32/sdcard.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/stm32/sdcard.c b/ports/stm32/sdcard.c index 8ffba0b4c5..0cb09b8189 100644 --- a/ports/stm32/sdcard.c +++ b/ports/stm32/sdcard.c @@ -304,6 +304,10 @@ bool sdcard_power_on(void) { return true; } + #ifdef MICROPY_BOARD_SDCARD_POWER + MICROPY_BOARD_SDCARD_POWER + #endif + HAL_StatusTypeDef status = HAL_ERROR; switch (pyb_sdmmc_flags) { #if MICROPY_HW_ENABLE_SDCARD From c1a8c7fc0985f1322d76e7b149bdb54535b457d2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 4 Jul 2019 11:11:11 +1000 Subject: [PATCH 0518/1788] stm32/boards/PYBD_SFx: Automatically turn on EN_3V3 when powering SD/MMC --- ports/stm32/boards/PYBD_SF2/mpconfigboard.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/stm32/boards/PYBD_SF2/mpconfigboard.h b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h index a46b5ca5bc..215b3f4016 100644 --- a/ports/stm32/boards/PYBD_SF2/mpconfigboard.h +++ b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h @@ -44,6 +44,7 @@ #define MICROPY_BOARD_ENTER_STOP board_sleep(1); #define MICROPY_BOARD_LEAVE_STOP board_sleep(0); #define MICROPY_BOARD_ENTER_STANDBY board_sleep(1); +#define MICROPY_BOARD_SDCARD_POWER mp_hal_pin_high(pyb_pin_EN_3V3); void board_early_init(void); void board_sleep(int value); From fa5c0b819c33fe81b0292570a7a1d07b6733b988 Mon Sep 17 00:00:00 2001 From: Eric Poulsen Date: Tue, 2 Jul 2019 14:30:43 -0700 Subject: [PATCH 0519/1788] esp32/network_ppp: Add ppp_set_usepeerdns(pcb, 1) when init'ing iface. Without this you often don't get any DNS server from your network provider. Additionally, setting your own DNS _does not work_ without this option set (which could be a bug in the PPP stack). --- ports/esp32/network_ppp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/esp32/network_ppp.c b/ports/esp32/network_ppp.c index 96d9ead305..8065409158 100644 --- a/ports/esp32/network_ppp.c +++ b/ports/esp32/network_ppp.c @@ -130,6 +130,7 @@ STATIC mp_obj_t ppp_active(size_t n_args, const mp_obj_t *args) { mp_raise_msg(&mp_type_RuntimeError, "init failed"); } pppapi_set_default(self->pcb); + ppp_set_usepeerdns(self->pcb, 1); pppapi_connect(self->pcb, 0); xTaskCreate(pppos_client_task, "ppp", 2048, self, 1, (TaskHandle_t*)&self->client_task_handle); From 23d9c6a0fd4c125abd56fe6828084b05d6d897dd Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 5 Jul 2019 17:24:59 +1000 Subject: [PATCH 0520/1788] stm32: Add initial support for STM32L0xx MCUs. --- ports/stm32/Makefile | 16 ++++- ports/stm32/dma.c | 106 ++++++++++++++++++++++++++--- ports/stm32/dma.h | 15 ++++ ports/stm32/extint.c | 6 +- ports/stm32/flash.c | 9 ++- ports/stm32/machine_uart.c | 2 +- ports/stm32/modmachine.c | 7 +- ports/stm32/mpconfigboard_common.h | 9 +++ ports/stm32/mphalport.c | 3 + ports/stm32/powerctrl.c | 32 +++++++-- ports/stm32/rtc.c | 15 +++- ports/stm32/timer.c | 70 +++++++++++++++---- ports/stm32/uart.c | 9 ++- 13 files changed, 264 insertions(+), 35 deletions(-) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 3967e63117..3d39f0c94a 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -64,7 +64,7 @@ CFLAGS_CORTEX_M = -mthumb ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32F765xx STM32F767xx STM32F769xx STM32H743xx)) CFLAGS_CORTEX_M += -mfpu=fpv5-d16 -mfloat-abi=hard else -ifeq ($(MCU_SERIES),f0) +ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f0 l0)) CFLAGS_CORTEX_M += -msoft-float else CFLAGS_CORTEX_M += -mfpu=fpv4-sp-d16 -mfloat-abi=hard @@ -75,6 +75,7 @@ endif 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_l0 = $(CFLAGS_CORTEX_M) -mtune=cortex-m0plus -mcpu=cortex-m0plus CFLAGS_MCU_l4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 CFLAGS_MCU_h7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7 @@ -200,7 +201,7 @@ SRC_LIBM = $(addprefix lib/libm/,\ wf_lgamma.c \ wf_tgamma.c \ ) -ifeq ($(MCU_SERIES),f0) +ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f0 l0)) SRC_LIBM += lib/libm/ef_sqrt.c else SRC_LIBM += lib/libm/thumb_vfp_sqrtf.c @@ -289,12 +290,21 @@ SRC_O = \ resethandler_m0.o \ lib/utils/gchelper_m0.o else +ifeq ($(MCU_SERIES),l0) +CSUPEROPT = -Os # save some code space +SRC_O = \ + $(STARTUP_FILE) \ + lib/stm32lib/CMSIS/STM32$(MCU_SERIES_UPPER)xx/Source/Templates/system_stm32$(MCU_SERIES)xx.o \ + resethandler_m0.o \ + lib/utils/gchelper_m0.o +else SRC_O = \ $(STARTUP_FILE) \ system_stm32.o \ resethandler.o \ lib/utils/gchelper_m3.o endif +endif SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ hal.c \ @@ -341,8 +351,10 @@ endif ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32H743xx)) SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_, hal_fdcan.c) else +ifneq ($(MCU_SERIES),$(filter $(MCU_SERIES),l0)) SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_, hal_can.c) endif +endif SRC_USBDEV = $(addprefix $(USBDEV_DIR)/,\ core/src/usbd_core.c \ diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c index a1dd40c352..32b9a74d70 100644 --- a/ports/stm32/dma.c +++ b/ports/stm32/dma.c @@ -70,7 +70,7 @@ typedef union { struct _dma_descr_t { #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) DMA_Stream_TypeDef *instance; - #elif defined(STM32F0) || defined(STM32L4) + #elif defined(STM32F0) || defined(STM32L0) || defined(STM32L4) DMA_Channel_TypeDef *instance; #else #error "Unsupported Processor" @@ -310,6 +310,47 @@ static const uint8_t dma_irqn[NSTREAM] = { DMA2_Stream7_IRQn, }; +#elif defined(STM32L0) + +#define NCONTROLLERS (1) +#define NSTREAMS_PER_CONTROLLER (7) +#define NSTREAM (NCONTROLLERS * NSTREAMS_PER_CONTROLLER) + +#define DMA_SUB_INSTANCE_AS_UINT8(dma_request) (dma_request) + +#define DMA1_ENABLE_MASK (0x007f) // Bits in dma_enable_mask corresponding to DMA1 + +// These descriptors are ordered by DMAx_Channel number, and within a channel by request +// number. The duplicate streams are ok as long as they aren't used at the same time. + +// DMA1 streams +const dma_descr_t dma_SPI_1_RX = { DMA1_Channel2, DMA_REQUEST_1, dma_id_1, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_3_TX = { DMA1_Channel2, DMA_REQUEST_3, dma_id_1, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_1_TX = { DMA1_Channel3, DMA_REQUEST_1, dma_id_2, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_3_RX = { DMA1_Channel3, DMA_REQUEST_3, dma_id_2, &dma_init_struct_spi_i2c }; +#if MICROPY_HW_ENABLE_DAC +const dma_descr_t dma_DAC_1_TX = { DMA1_Channel3, DMA_REQUEST_6, dma_id_2, &dma_init_struct_dac }; +#endif +const dma_descr_t dma_SPI_2_RX = { DMA1_Channel4, DMA_REQUEST_1, dma_id_3, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_2_TX = { DMA1_Channel4, DMA_REQUEST_3, dma_id_3, &dma_init_struct_spi_i2c }; +#if MICROPY_HW_ENABLE_DAC +const dma_descr_t dma_DAC_2_TX = { DMA1_Channel4, DMA_REQUEST_5, dma_id_3, &dma_init_struct_dac }; +#endif +const dma_descr_t dma_SPI_2_TX = { DMA1_Channel5, DMA_REQUEST_1, dma_id_4, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_2_RX = { DMA1_Channel5, DMA_REQUEST_3, dma_id_4, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_1_TX = { DMA1_Channel6, DMA_REQUEST_3, dma_id_5, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_1_RX = { DMA1_Channel7, DMA_REQUEST_3, dma_id_6, &dma_init_struct_spi_i2c }; + +static const uint8_t dma_irqn[NSTREAM] = { + DMA1_Channel1_IRQn, + DMA1_Channel2_3_IRQn, + DMA1_Channel4_5_6_7_IRQn, + 0, + 0, + 0, + 0, +}; + #elif defined(STM32L4) #define NCONTROLLERS (2) @@ -459,9 +500,11 @@ volatile dma_idle_count_t dma_idle; #define DMA_INVALID_CHANNEL 0xff // Value stored in dma_last_channel which means invalid -#if defined(STM32F0) +#if defined(STM32F0) || defined(STM32L0) #define DMA1_IS_CLK_ENABLED() ((RCC->AHBENR & RCC_AHBENR_DMA1EN) != 0) +#if defined(DMA2) #define DMA2_IS_CLK_ENABLED() ((RCC->AHBENR & RCC_AHBENR_DMA2EN) != 0) +#endif #else #define DMA1_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA1EN) != 0) #define DMA2_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA2EN) != 0) @@ -526,6 +569,44 @@ 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(STM32L0) + +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_3_IRQHandler(void) { + IRQ_ENTER(DMA1_Channel2_3_IRQn); + if (dma_handle[dma_id_1] != NULL) { + HAL_DMA_IRQHandler(dma_handle[dma_id_1]); + } + if (dma_handle[dma_id_2] != NULL) { + HAL_DMA_IRQHandler(dma_handle[dma_id_2]); + } + IRQ_EXIT(DMA1_Channel2_3_IRQn); +} + +void DMA1_Channel4_5_6_7_IRQHandler(void) { + IRQ_ENTER(DMA1_Channel4_5_6_7_IRQn); + if (dma_handle[dma_id_3] != NULL) { + HAL_DMA_IRQHandler(dma_handle[dma_id_3]); + } + if (dma_handle[dma_id_4] != NULL) { + HAL_DMA_IRQHandler(dma_handle[dma_id_4]); + } + if (dma_handle[dma_id_5] != NULL) { + HAL_DMA_IRQHandler(dma_handle[dma_id_5]); + } + if (dma_handle[dma_id_6] != NULL) { + HAL_DMA_IRQHandler(dma_handle[dma_id_6]); + } + IRQ_EXIT(DMA1_Channel4_5_6_7_IRQn); +} + #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); } @@ -572,18 +653,21 @@ static void dma_enable_clock(dma_id_t dma_id) { dma_last_sub_instance[channel] = DMA_INVALID_CHANNEL; } } - } else { + } + #if defined(DMA2) + else { if (((old_enable_mask & DMA2_ENABLE_MASK) == 0) && !DMA2_IS_CLK_ENABLED()) { __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. + // in dma_last_channel (for DMA2) needs to be invalidated. for (int channel = NSTREAMS_PER_CONTROLLER; channel < NSTREAM; channel++) { dma_last_sub_instance[channel] = DMA_INVALID_CHANNEL; } } } + #endif } static void dma_disable_clock(dma_id_t dma_id) { @@ -599,7 +683,7 @@ void dma_init_handle(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint3 dma->Instance = dma_descr->instance; dma->Init = *dma_descr->init; dma->Init.Direction = dir; - #if defined(STM32L4) || defined(STM32H7) + #if defined(STM32L0) || defined(STM32L4) || defined(STM32H7) dma->Init.Request = dma_descr->sub_instance; #else #if !defined(STM32F0) @@ -705,7 +789,10 @@ static void dma_idle_handler(uint32_t tick) { } static const uint32_t controller_mask[] = { - DMA1_ENABLE_MASK, DMA2_ENABLE_MASK + DMA1_ENABLE_MASK, + #if defined(DMA2) + DMA2_ENABLE_MASK, + #endif }; { int controller = (tick >> DMA_SYSTICK_LOG2) & 1; @@ -719,9 +806,12 @@ static void dma_idle_handler(uint32_t tick) { dma_idle.counter[controller] = 0; if (controller == 0) { __HAL_RCC_DMA1_CLK_DISABLE(); - } else { + } + #if defined(DMA2) + else { __HAL_RCC_DMA2_CLK_DISABLE(); } + #endif } else { // Something is still active, but the counter never got // reset, so we'll reset the counter here. @@ -731,7 +821,7 @@ static void dma_idle_handler(uint32_t tick) { } } -#if defined(STM32F0) || defined(STM32L4) +#if defined(STM32F0) || defined(STM32L0) || defined(STM32L4) void dma_nohal_init(const dma_descr_t *descr, uint32_t config) { DMA_Channel_TypeDef *dma = descr->instance; diff --git a/ports/stm32/dma.h b/ports/stm32/dma.h index 7b74a73993..bedabe7f89 100644 --- a/ports/stm32/dma.h +++ b/ports/stm32/dma.h @@ -58,6 +58,21 @@ extern const dma_descr_t dma_SPI_6_RX; extern const dma_descr_t dma_SDIO_0; extern const dma_descr_t dma_DCMI_0; +#elif defined(STM32L0) + +extern const dma_descr_t dma_SPI_1_RX; +extern const dma_descr_t dma_I2C_3_TX; +extern const dma_descr_t dma_SPI_1_TX; +extern const dma_descr_t dma_I2C_3_RX; +extern const dma_descr_t dma_DAC_1_TX; +extern const dma_descr_t dma_SPI_2_RX; +extern const dma_descr_t dma_I2C_2_TX; +extern const dma_descr_t dma_DAC_2_TX; +extern const dma_descr_t dma_SPI_2_TX; +extern const dma_descr_t dma_I2C_2_RX; +extern const dma_descr_t dma_I2C_1_TX; +extern const dma_descr_t dma_I2C_1_RX; + #elif defined(STM32L4) extern const dma_descr_t dma_ADC_1_RX; diff --git a/ports/stm32/extint.c b/ports/stm32/extint.c index 0b1ba8eb09..9a7295995a 100644 --- a/ports/stm32/extint.c +++ b/ports/stm32/extint.c @@ -139,12 +139,16 @@ 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) + #if defined(STM32F0) || defined(STM32L0) 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, + #if defined(STM32L0) + PVD_IRQn, + #else PVD_VDDIO2_IRQn, + #endif RTC_IRQn, 0, // internal USB wakeup event RTC_IRQn, diff --git a/ports/stm32/flash.c b/ports/stm32/flash.c index 56896a7037..aff85f7e37 100644 --- a/ports/stm32/flash.c +++ b/ports/stm32/flash.c @@ -68,7 +68,7 @@ static const flash_layout_t flash_layout[] = { { 0x08040000, 0x40000, 3 }, }; -#elif defined(STM32L4) +#elif defined(STM32L0) || defined(STM32L4) static const flash_layout_t flash_layout[] = { { (uint32_t)FLASH_BASE, (uint32_t)FLASH_PAGE_SIZE, 512 }, @@ -170,7 +170,12 @@ void flash_erase(uint32_t flash_dest, uint32_t num_word32) { EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; EraseInitStruct.PageAddress = flash_dest; EraseInitStruct.NbPages = (4 * num_word32 + FLASH_PAGE_SIZE - 4) / FLASH_PAGE_SIZE; - #elif (defined(STM32L4) && !defined(SYSCFG_MEMRMP_FB_MODE)) + #elif defined(STM32L0) + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR); + EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; + EraseInitStruct.PageAddress = flash_dest; + EraseInitStruct.NbPages = (4 * num_word32 + FLASH_PAGE_SIZE - 4) / FLASH_PAGE_SIZE; + #elif defined(STM32L4) && !defined(SYSCFG_MEMRMP_FB_MODE) __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS); EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; EraseInitStruct.Page = get_page(flash_dest); diff --git a/ports/stm32/machine_uart.c b/ports/stm32/machine_uart.c index 29369c0c14..92343ba6d7 100644 --- a/ports/stm32/machine_uart.c +++ b/ports/stm32/machine_uart.c @@ -489,7 +489,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 = MP_OBJ_TO_PTR(self_in); - #if defined(STM32F0) || defined(STM32F7) || defined(STM32L4) || defined(STM32H7) + #if defined(STM32F0) || defined(STM32F7) || defined(STM32L0) || defined(STM32L4) || defined(STM32H7) self->uartx->RQR = USART_RQR_SBKRQ; // write-only register #else self->uartx->CR1 |= USART_CR1_SBK; diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index ba0ee28471..8d6dbf4fec 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -56,6 +56,11 @@ #include "uart.h" #include "wdt.h" +#if defined(STM32L0) +// L0 does not have a BOR, so use POR instead +#define RCC_CSR_BORRSTF RCC_CSR_PORRSTF +#endif + #if defined(STM32L4) // L4 does not have a POR, so use BOR instead #define RCC_CSR_PORRSTF RCC_CSR_BORRSTF @@ -300,7 +305,7 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { return mp_obj_new_tuple(MP_ARRAY_SIZE(tuple), tuple); } else { // set - #if defined(STM32F0) || defined(STM32L4) + #if defined(STM32F0) || defined(STM32L0) || defined(STM32L4) mp_raise_NotImplementedError("machine.freq set not supported yet"); #else mp_int_t sysclk = mp_obj_get_int(args[0]); diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index 036e1f6ccd..94a86ca92a 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -184,6 +184,15 @@ #define MICROPY_HW_MAX_TIMER (17) #define MICROPY_HW_MAX_UART (8) +// Configuration for STM32L0 series +#elif defined(STM32L0) + +#define MP_HAL_UNIQUE_ID_ADDRESS (0x1FF80050) +#define PYB_EXTI_NUM_VECTORS (30) // TODO (22 configurable, 7 direct) +#define MICROPY_HW_MAX_I2C (3) +#define MICROPY_HW_MAX_TIMER (22) +#define MICROPY_HW_MAX_UART (4) + // Configuration for STM32L4 series #elif defined(STM32L4) diff --git a/ports/stm32/mphalport.c b/ports/stm32/mphalport.c index 79b28bd3de..c5786e7409 100644 --- a/ports/stm32/mphalport.c +++ b/ports/stm32/mphalport.c @@ -119,6 +119,9 @@ void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio) { #elif defined(STM32H7) #define AHBxENR AHB4ENR #define AHBxENR_GPIOAEN_Pos RCC_AHB4ENR_GPIOAEN_Pos + #elif defined(STM32L0) + #define AHBxENR IOPENR + #define AHBxENR_GPIOAEN_Pos RCC_IOPENR_GPIOAEN #elif defined(STM32L4) #define AHBxENR AHB2ENR #define AHBxENR_GPIOAEN_Pos RCC_AHB2ENR_GPIOAEN_Pos diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c index e3ad20039c..cf2445c7d9 100644 --- a/ports/stm32/powerctrl.c +++ b/ports/stm32/powerctrl.c @@ -84,7 +84,31 @@ void powerctrl_check_enter_bootloader(void) { } } -#if !defined(STM32F0) +#if defined(STM32L0) +void SystemClock_Config(void) { + // Enable power control peripheral + __HAL_RCC_PWR_CLK_ENABLE(); + + // Use the 16MHz internal oscillator + RCC->CR |= RCC_CR_HSION; + while (!(RCC->CR & RCC_CR_HSIRDY)) { + } + const uint32_t sysclk_src = 1; + + // Select SYSCLK source + RCC->CFGR |= sysclk_src << RCC_CFGR_SW_Pos; + while (((RCC->CFGR >> RCC_CFGR_SWS_Pos) & 0x3) != sysclk_src) { + // Wait for SYSCLK source to change + } + + SystemCoreClockUpdate(); + + HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000); + HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); +} +#endif + +#if !defined(STM32F0) && !defined(STM32L0) // Assumes that PLL is used as the SYSCLK source int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk_mhz, bool need_pllsai) { @@ -158,7 +182,7 @@ int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk #endif -#if !(defined(STM32F0) || defined(STM32L4)) +#if !defined(STM32F0) && !defined(STM32L0) && !defined(STM32L4) STATIC uint32_t calc_ahb_div(uint32_t wanted_div) { if (wanted_div <= 1) { return RCC_SYSCLK_DIV1; } @@ -333,7 +357,7 @@ void powerctrl_enter_stop_mode(void) { __HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_MSI); #endif - #if !defined(STM32F0) && !defined(STM32L4) + #if !defined(STM32F0) && !defined(STM32L0) && !defined(STM32L4) // takes longer to wake but reduces stop current HAL_PWREx_EnableFlashPowerDown(); #endif @@ -426,7 +450,7 @@ void powerctrl_enter_standby_mode(void) { // Note: we only support RTC ALRA, ALRB, WUT and TS. // TODO support TAMP and WKUP (PA0 external pin). - #if defined(STM32F0) + #if defined(STM32F0) || defined(STM32L0) #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 diff --git a/ports/stm32/rtc.c b/ports/stm32/rtc.c index a7c3f2068b..d0f444c216 100644 --- a/ports/stm32/rtc.c +++ b/ports/stm32/rtc.c @@ -73,6 +73,17 @@ STATIC bool rtc_use_lse = false; STATIC uint32_t rtc_startup_tick; STATIC bool rtc_need_init_finalise = false; +#if defined(STM32L0) +#define BDCR CSR +#define RCC_BDCR_RTCEN RCC_CSR_RTCEN +#define RCC_BDCR_RTCSEL RCC_CSR_RTCSEL +#define RCC_BDCR_RTCSEL_0 RCC_CSR_RTCSEL_0 +#define RCC_BDCR_RTCSEL_1 RCC_CSR_RTCSEL_1 +#define RCC_BDCR_LSEON RCC_CSR_LSEON +#define RCC_BDCR_LSERDY RCC_CSR_LSERDY +#define RCC_BDCR_LSEBYP RCC_CSR_LSEBYP +#endif + void rtc_init_start(bool force_init) { RTCHandle.Instance = RTC; @@ -287,7 +298,7 @@ STATIC HAL_StatusTypeDef PYB_RTC_Init(RTC_HandleTypeDef *hrtc) { // Exit Initialization mode hrtc->Instance->ISR &= (uint32_t)~RTC_ISR_INIT; - #if defined(STM32L4) || defined(STM32H7) + #if defined(STM32L0) || defined(STM32L4) || defined(STM32H7) hrtc->Instance->OR &= (uint32_t)~RTC_OR_ALARMOUTTYPE; hrtc->Instance->OR |= (uint32_t)(hrtc->Init.OutPutType); #elif defined(STM32F7) @@ -539,7 +550,7 @@ 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) +#if defined(STM32F0) || defined(STM32L0) #define RTC_WKUP_IRQn RTC_IRQn #endif diff --git a/ports/stm32/timer.c b/ports/stm32/timer.c index 7f4c0d85a9..cd01a41741 100644 --- a/ports/stm32/timer.c +++ b/ports/stm32/timer.c @@ -427,6 +427,8 @@ STATIC mp_obj_t compute_percent_from_pwm_value(uint32_t period, uint32_t cmp) { #endif } +#if !defined(STM32L0) + // Computes the 8-bit value for the DTG field in the BDTR register. // // 1 tick = 1 count of the timer's clock (source_freq) divided by div. @@ -486,6 +488,8 @@ STATIC void config_deadtime(pyb_timer_obj_t *self, mp_int_t ticks, mp_int_t brk) HAL_TIMEx_ConfigBreakDeadTime(&self->tim, &deadTimeConfig); } +#endif + TIM_HandleTypeDef *pyb_timer_get_handle(mp_obj_t timer) { if (mp_obj_get_type(timer) != &pyb_timer_type) { mp_raise_ValueError("need a Timer object"); @@ -514,6 +518,7 @@ STATIC void pyb_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ self->tim.Init.ClockDivision == TIM_CLOCKDIVISION_DIV4 ? 4 : self->tim.Init.ClockDivision == TIM_CLOCKDIVISION_DIV2 ? 2 : 1); + #if !defined(STM32L0) #if defined(IS_TIM_ADVANCED_INSTANCE) if (IS_TIM_ADVANCED_INSTANCE(self->tim.Instance)) #elif defined(IS_TIM_BREAK_INSTANCE) @@ -531,6 +536,7 @@ STATIC void pyb_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ mp_printf(print, ", brk=BRK_OFF"); } } + #endif mp_print_str(print, ")"); } } @@ -630,11 +636,15 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, size_t n_args, cons args[ARG_div].u_int == 4 ? TIM_CLOCKDIVISION_DIV4 : TIM_CLOCKDIVISION_DIV1; + #if !defined(STM32L0) init->RepetitionCounter = 0; + #endif // enable TIM clock switch (self->tim_id) { + #if defined(TIM1) case 1: __HAL_RCC_TIM1_CLK_ENABLE(); break; + #endif case 2: __HAL_RCC_TIM2_CLK_ENABLE(); break; #if defined(TIM3) case 3: __HAL_RCC_TIM3_CLK_ENABLE(); break; @@ -681,22 +691,40 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, size_t n_args, cons #if defined(TIM17) case 17: __HAL_RCC_TIM17_CLK_ENABLE(); break; #endif + #if defined(TIM18) + case 18: __HAL_RCC_TIM18_CLK_ENABLE(); break; + #endif + #if defined(TIM19) + case 19: __HAL_RCC_TIM19_CLK_ENABLE(); break; + #endif + #if defined(TIM20) + case 20: __HAL_RCC_TIM20_CLK_ENABLE(); break; + #endif + #if defined(TIM21) + case 21: __HAL_RCC_TIM21_CLK_ENABLE(); break; + #endif + #if defined(TIM22) + case 22: __HAL_RCC_TIM22_CLK_ENABLE(); break; + #endif } // set IRQ priority (if not a special timer) if (self->tim_id != 5) { NVIC_SetPriority(IRQn_NONNEG(self->irqn), IRQ_PRI_TIMX); if (self->tim_id == 1) { + #if defined(TIM1) NVIC_SetPriority(TIM1_CC_IRQn, IRQ_PRI_TIMX); - #if defined(TIM8) + #endif } else if (self->tim_id == 8) { + #if defined(TIM8) NVIC_SetPriority(TIM8_CC_IRQn, IRQ_PRI_TIMX); - #endif + #endif } } // init TIM HAL_TIM_Base_Init(&self->tim); + #if !defined(STM32L0) #if defined(IS_TIM_ADVANCED_INSTANCE) if (IS_TIM_ADVANCED_INSTANCE(self->tim.Instance)) { #elif defined(IS_TIM_BREAK_INSTANCE) @@ -707,6 +735,7 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, size_t n_args, cons config_deadtime(self, args[ARG_deadtime].u_int, args[ARG_brk].u_int); } + #endif // Enable ARPE so that the auto-reload register is buffered. // This allows to smoothly change the frequency of the timer. @@ -726,6 +755,7 @@ 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(TIM1) #if defined(STM32F0) TIM_ENTRY(1, TIM1_BRK_UP_TRG_COM_IRQn), #elif defined(STM32F4) || defined(STM32F7) @@ -733,6 +763,7 @@ STATIC const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = { #elif defined(STM32L4) TIM_ENTRY(1, TIM1_UP_TIM16_IRQn), #endif + #endif TIM_ENTRY(2, TIM2_IRQn), #if defined(TIM3) TIM_ENTRY(3, TIM3_IRQn), @@ -1054,10 +1085,12 @@ STATIC mp_obj_t pyb_timer_channel(size_t n_args, const mp_obj_t *pos_args, mp_ma oc_config.Pulse = args[3].u_int; } oc_config.OCPolarity = TIM_OCPOLARITY_HIGH; - oc_config.OCNPolarity = TIM_OCNPOLARITY_HIGH; oc_config.OCFastMode = TIM_OCFAST_DISABLE; + #if !defined(STM32L0) + oc_config.OCNPolarity = TIM_OCNPOLARITY_HIGH; oc_config.OCIdleState = TIM_OCIDLESTATE_SET; oc_config.OCNIdleState = TIM_OCNIDLESTATE_SET; + #endif HAL_TIM_PWM_ConfigChannel(&self->tim, &oc_config, TIMER_CHANNEL(chan)); if (chan->callback == mp_const_none) { @@ -1065,10 +1098,12 @@ STATIC mp_obj_t pyb_timer_channel(size_t n_args, const mp_obj_t *pos_args, mp_ma } else { pyb_timer_channel_callback(MP_OBJ_FROM_PTR(chan), chan->callback); } + #if !defined(STM32L0) // Start the complimentary channel too (if its supported) if (IS_TIM_CCXN_INSTANCE(self->tim.Instance, TIMER_CHANNEL(chan))) { HAL_TIMEx_PWMN_Start(&self->tim, TIMER_CHANNEL(chan)); } + #endif break; } @@ -1085,14 +1120,16 @@ STATIC mp_obj_t pyb_timer_channel(size_t n_args, const mp_obj_t *pos_args, mp_ma if (oc_config.OCPolarity == 0xffffffff) { oc_config.OCPolarity = TIM_OCPOLARITY_HIGH; } + oc_config.OCFastMode = TIM_OCFAST_DISABLE; + #if !defined(STM32L0) if (oc_config.OCPolarity == TIM_OCPOLARITY_HIGH) { oc_config.OCNPolarity = TIM_OCNPOLARITY_HIGH; } else { oc_config.OCNPolarity = TIM_OCNPOLARITY_LOW; } - oc_config.OCFastMode = TIM_OCFAST_DISABLE; oc_config.OCIdleState = TIM_OCIDLESTATE_SET; oc_config.OCNIdleState = TIM_OCNIDLESTATE_SET; + #endif if (!IS_TIM_OC_POLARITY(oc_config.OCPolarity)) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid polarity (%d)", oc_config.OCPolarity)); @@ -1103,10 +1140,12 @@ STATIC mp_obj_t pyb_timer_channel(size_t n_args, const mp_obj_t *pos_args, mp_ma } else { pyb_timer_channel_callback(MP_OBJ_FROM_PTR(chan), chan->callback); } + #if !defined(STM32L0) // Start the complimentary channel too (if its supported) if (IS_TIM_CCXN_INSTANCE(self->tim.Instance, TIMER_CHANNEL(chan))) { HAL_TIMEx_OCN_Start(&self->tim, TIMER_CHANNEL(chan)); } + #endif break; } @@ -1155,8 +1194,12 @@ STATIC mp_obj_t pyb_timer_channel(size_t n_args, const mp_obj_t *pos_args, mp_ma nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid polarity (%d)", enc_config.IC1Polarity)); } // Only Timers 1, 2, 3, 4, 5, and 8 support encoder mode - if (self->tim.Instance != TIM1 - && self->tim.Instance != TIM2 + if ( + #if defined(TIM1) + self->tim.Instance != TIM1 + && + #endif + self->tim.Instance != TIM2 #if defined(TIM3) && self->tim.Instance != TIM3 #endif @@ -1426,15 +1469,18 @@ STATIC mp_obj_t pyb_timer_channel_callback(mp_obj_t self_in, mp_obj_t callback) self->callback = mp_const_none; } else if (mp_obj_is_callable(callback)) { self->callback = callback; - uint8_t tim_id = self->timer->tim_id; __HAL_TIM_CLEAR_IT(&self->timer->tim, TIMER_IRQ_MASK(self->channel)); - if (tim_id == 1) { + #if defined(TIM1) + if (self->timer->tim_id == 1) { HAL_NVIC_EnableIRQ(TIM1_CC_IRQn); - #if defined(TIM8) // STM32F401 doesn't have a TIM8 - } else if (tim_id == 8) { - HAL_NVIC_EnableIRQ(TIM8_CC_IRQn); + } else #endif - } else { + #if defined(TIM8) // STM32F401 doesn't have a TIM8 + if (self->timer->tim_id == 8) { + HAL_NVIC_EnableIRQ(TIM8_CC_IRQn); + } else + #endif + { HAL_NVIC_EnableIRQ(self->timer->irqn); } // start timer, so that it interrupts on overflow diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c index 3a21a0b31e..0d46ea9473 100644 --- a/ports/stm32/uart.c +++ b/ports/stm32/uart.c @@ -76,6 +76,11 @@ #define USART_CR2_IE_ALL (USART_CR2_IE_BASE) #define USART_CR3_IE_ALL (USART_CR3_IE_BASE | USART_CR3_RXFTIE | USART_CR3_TCBGTIE | USART_CR3_TXFTIE | USART_CR3_WUFIE) +#elif defined(STM32L0) +#define USART_CR1_IE_ALL (USART_CR1_IE_BASE | USART_CR1_EOBIE | USART_CR1_RTOIE | USART_CR1_CMIE) +#define USART_CR2_IE_ALL (USART_CR2_IE_BASE) +#define USART_CR3_IE_ALL (USART_CR3_IE_BASE | USART_CR3_WUFIE) + #elif defined(STM32L4) #define USART_CR1_IE_ALL (USART_CR1_IE_BASE | USART_CR1_EOBIE | USART_CR1_RTOIE | USART_CR1_CMIE) #define USART_CR2_IE_ALL (USART_CR2_IE_BASE) @@ -648,7 +653,7 @@ int uart_rx_char(pyb_uart_obj_t *self) { return data; } else { // no buffering - #if defined(STM32F0) || defined(STM32F7) || defined(STM32L4) || defined(STM32H7) + #if defined(STM32F0) || defined(STM32F7) || defined(STM32L0) || defined(STM32L4) || defined(STM32H7) int data = self->uartx->RDR & self->char_mask; self->uartx->ICR = USART_ICR_ORECF; // clear ORE if it was set return data; @@ -774,7 +779,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(STM32F0) || defined(STM32F7) || defined(STM32L4) || defined(STM32H7) + #if defined(STM32F0) || defined(STM32F7) || defined(STM32L0) || defined(STM32L4) || defined(STM32H7) int data = self->uartx->RDR; // clears UART_FLAG_RXNE self->uartx->ICR = USART_ICR_ORECF; // clear ORE if it was set #else From 9c096c190c68e527d617d596037f6f0d497da85a Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 5 Jul 2019 17:26:03 +1000 Subject: [PATCH 0521/1788] stm32/boards: Add MCU support files for STM32L072. --- ports/stm32/boards/stm32l072_af.csv | 84 ++++++++++++++++++ ports/stm32/boards/stm32l072xz.ld | 27 ++++++ ports/stm32/boards/stm32l0xx_hal_conf_base.h | 91 ++++++++++++++++++++ 3 files changed, 202 insertions(+) create mode 100644 ports/stm32/boards/stm32l072_af.csv create mode 100644 ports/stm32/boards/stm32l072xz.ld create mode 100644 ports/stm32/boards/stm32l0xx_hal_conf_base.h diff --git a/ports/stm32/boards/stm32l072_af.csv b/ports/stm32/boards/stm32l072_af.csv new file mode 100644 index 0000000000..0b1115b164 --- /dev/null +++ b/ports/stm32/boards/stm32l072_af.csv @@ -0,0 +1,84 @@ +Port,Pin,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,, +,,SPI1/SPI2/I2S2/USART1/2/LPUART1/USB/LPTIM1/TSC/TIM2/21/22/EVENTOUT/SYS_AF,SPI1/SPI2/I2S2/I2C1/TIM2/21,SPI1/SPI2/I2S2/LPUART1/USART5/USB/LPTIM1/TIM2/3/EVENTOUT/SYS_AF,I2C1/TSC/EVENTOUT,I2C1/USART1/2/LPUART1/TIM3/22/EVENTOUT,SPI2/I2S2/I2C2/USART1/TIM2/21/22,I2C1/2/LPUART1/USART4/UASRT5/TIM21/EVENTOUT,I2C3/LPUART1/COMP1/2/TIM3,,ADC +PortA,PA0,,,TIM2_CH1,TSC_G1_IO1,USART2_CTS,TIM2_ETR,USART4_TX,COMP1_OUT,,ADC_IN0 +PortA,PA1,EVENTOUT,,TIM2_CH2,TSC_G1_IO2,USART2_RTS_DE,TIM21_ETR,USART4_RX,,,ADC_IN1 +PortA,PA2,TIM21_CH1,,TIM2_CH3,TSC_G1_IO3,USART2_TX,,LPUART1_TX,COMP2_OUT,,ADC_IN2 +PortA,PA3,TIM21_CH2,,TIM2_CH4,TSC_G1_IO4,USART2_RX,,LPUART1_RX,,,ADC_IN3 +PortA,PA4,SPI1_NSS,,,TSC_G2_IO1,USART2_CK,TIM22_ETR,,,,ADC_IN4 +PortA,PA5,SPI1_SCK,,TIM2_ETR,TSC_G2_IO2,,TIM2_CH1,,,,ADC_IN5 +PortA,PA6,SPI1_MISO,,TIM3_CH1,TSC_G2_IO3,LPUART1_CTS,TIM22_CH1,EVENTOUT,COMP1_OUT,,ADC_IN6 +PortA,PA7,SPI1_MOSI,,TIM3_CH2,TSC_G2_IO4,,TIM22_CH2,EVENTOUT,COMP2_OUT,,ADC_IN7 +PortA,PA8,MCO,,USB_CRS_SYNC,EVENTOUT,USART1_CK,,,I2C3_SCL,, +PortA,PA9,MCO,,,TSC_G4_IO1,USART1_TX,,I2C1_SCL,I2C3_SMBA,, +PortA,PA10,,,,TSC_G4_IO2,USART1_RX,,I2C1_SDA,,, +PortA,PA11,SPI1_MISO,,EVENTOUT,TSC_G4_IO3,USART1_CTS,,,COMP1_OUT,, +PortA,PA12,SPI1_MOSI,,EVENTOUT,TSC_G4_IO4,USART1_RTS_DE,,,COMP2_OUT,, +PortA,PA13,SWDIO,,USB_NOE,,,,LPUART1_RX,,, +PortA,PA14,SWCLK,,,,USART2_TX,,LPUART1_TX,,, +PortA,PA15,SPI1_NSS,,TIM2_ETR,EVENTOUT,USART2_RX,TIM2_CH1,USART4_RTS_DE,,, +PortB,PB0,EVENTOUT,,TIM3_CH3,TSC_G3_IO2,,,,,,ADC_IN8 +PortB,PB1,,,TIM3_CH4,TSC_G3_IO3,LPUART1_RTS_DE,,,,,ADC_IN9 +PortB,PB2,,,LPTIM1_OUT,TSC_G3_IO4,,,,I2C3_SMBA,, +PortB,PB3,SPI1_SCK,,TIM2_CH2,TSC_G5_IO1,EVENTOUT,USART1_RTS_DE,USART5_TX,,, +PortB,PB4,SPI1_MISO,,TIM3_CH1,TSC_G5_IO2,TIM22_CH1,USART1_CTS,USART5_RX,I2C3_SDA,, +PortB,PB5,SPI1_MOSI,,LPTIM1_IN1,I2C1_SMBA,TIM3_CH2/TIM22_CH2,USART1_CK,USART5_CK/USART5_RTS_DE,,, +PortB,PB6,USART1_TX,I2C1_SCL,LPTIM1_ETR,TSC_G5_IO3,,,,,, +PortB,PB7,USART1_RX,I2C1_SDA,LPTIM1_IN2,TSC_G5_IO4,,,USART4_CTS,,, +PortB,PB8,,,,TSC_SYNC,I2C1_SCL,,,,, +PortB,PB9,,,EVENTOUT,,I2C1_SDA,SPI2_NSS/I2S2_WS,,,, +PortB,PB10,,,TIM2_CH3,TSC_SYNC,LPUART1_TX,SPI2_SCK,I2C2_SCL,LPUART1_RX,, +PortB,PB11,EVENTOUT,,TIM2_CH4,TSC_G6_IO1,LPUART1_RX,,I2C2_SDA,LPUART1_TX,, +PortB,PB12,SPI2_NSS/I2S2_WS,,LPUART1_RTS_DE,TSC_G6_IO2,I2C2_SMBA,,EVENTOUT,,, +PortB,PB13,SPI2_SCK/I2S2_CK,,MCO,TSC_G6_IO3,LPUART1_CTS,I2C2_SCL,TIM21_CH1,,, +PortB,PB14,SPI2_MISO/I2S2_MCK,,RTC_OUT,TSC_G6_IO4,LPUART1_RTS_DE,I2C2_SDA,TIM21_CH2,,, +PortB,PB15,SPI2_MOSI/I2S2_SD,,RTC_REFIN,,,,,,, +PortC,PC0,LPTIM1_IN1,,EVENTOUT,TSC_G7_IO1,,,LPUART1_RX,I2C3_SCL,,ADC_IN10 +PortC,PC1,LPTIM1_OUT,,EVENTOUT,TSC_G7_IO2,,,LPUART1_TX,I2C3_SDA,,ADC_IN11 +PortC,PC2,LPTIM1_IN2,,SPI2_MISO/I2S2_MCK,TSC_G7_IO3,,,,,,ADC_IN12 +PortC,PC3,LPTIM1_ETR,,SPI2_MOSI/I2S2_SD,TSC_G7_IO4,,,,,,ADC_IN13 +PortC,PC4,EVENTOUT,,LPUART1_TX,,,,,,,ADC_IN14 +PortC,PC5,LPUART1_RX,,TSC_G3_IO1,,,,,,,ADC_IN15 +PortC,PC6,TIM22_CH1,,TIM3_CH1,TSC_G8_IO1,,,,,, +PortC,PC7,TIM22_CH2,,TIM3_CH2,TSC_G8_IO2,,,,,, +PortC,PC8,TIM22_ETR,,TIM3_CH3,TSC_G8_IO3,,,,,, +PortC,PC9,TIM21_ETR,,USB_NOE/TIM3_CH4,TSC_G8_IO4,,,,I2C3_SDA,, +PortC,PC10,LPUART1_TX,,,,,,USART4_TX,,, +PortC,PC11,LPUART1_RX,,,,,,USART4_RX,,, +PortC,PC12,,,USART5_TX,,,,USART4_CK,,, +PortC,PC13,,,,,,,,,, +PortC,PC14,,,,,,,,,, +PortC,PC15,,,,,,,,,, +PortD,PD0,TIM21_CH1,SPI2_NSS/I2S2_WS,,,,,,,, +PortD,PD1,,SPI2_SCK/I2S2_CK,,,,,,,, +PortD,PD2,LPUART1_RTS_DE,,TIM3_ETR,,,,USART5_RX,,, +PortD,PD3,USART2_CTS,,SPI2_MISO/I2S2_MCK,,,,,,, +PortD,PD4,USART2_RTS_DE,SPI2_MOSI/I2S2_SD,,,,,,,, +PortD,PD5,USART2_TX,,,,,,,,, +PortD,PD6,USART2_RX,,,,,,,,, +PortD,PD7,USART2_CK,TIM21_CH2,,,,,,,, +PortD,PD8,LPUART1_TX,,,,,,,,, +PortD,PD9,LPUART1_RX,,,,,,,,, +PortD,PD10,,,,,,,,,, +PortD,PD11,LPUART1_CTS,,,,,,,,, +PortD,PD12,LPUART1_RTS_DE,,,,,,,,, +PortD,PD13,,,,,,,,,, +PortD,PD14,,,,,,,,,, +PortD,PD15,USB_CRS_SYNC,,,,,,,,, +PortE,PE0,,,EVENTOUT,,,,,,, +PortE,PE1,,,EVENTOUT,,,,,,, +PortE,PE2,,,TIM3_ETR,,,,,,, +PortE,PE3,TIM22_CH1,,TIM3_CH1,,,,,,, +PortE,PE4,TIM22_CH2,,TIM3_CH2,,,,,,, +PortE,PE5,TIM21_CH1,,TIM3_CH3,,,,,,, +PortE,PE6,TIM21_CH2,,TIM3_CH4,,,,,,, +PortE,PE7,,,,,,,USART5_CK/USART5_RTS_DE,,, +PortE,PE8,,,,,,,USART4_TX,,, +PortE,PE9,TIM2_CH1,,TIM2_ETR,,,,USART4_RX,,, +PortE,PE10,TIM2_CH2,,,,,,USART5_TX,,, +PortE,PE11,TIM2_CH3,,,,,,USART5_RX,,, +PortE,PE12,TIM2_CH4,,SPI1_NSS,,,,,,, +PortE,PE13,,,SPI1_SCK,,,,,,, +PortE,PE14,,,SPI1_MISO,,,,,,, +PortE,PE15,,,SPI1_MOSI,,,,,,, +PortH,PH0,USB_CRS_SYNC,,,,,,,,, +PortH,PH1,,,,,,,,,, diff --git a/ports/stm32/boards/stm32l072xz.ld b/ports/stm32/boards/stm32l072xz.ld new file mode 100644 index 0000000000..538950747b --- /dev/null +++ b/ports/stm32/boards/stm32l072xz.ld @@ -0,0 +1,27 @@ +/* + GNU linker script for STM32F072xZ +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 192K + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 8K; + +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM); + +/* 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) - _estack_reserve; +_sstack = _estack - 4K; + +/* RAM extents for the main heap */ +_heap_start = _ebss; +_heap_end = _sstack; diff --git a/ports/stm32/boards/stm32l0xx_hal_conf_base.h b/ports/stm32/boards/stm32l0xx_hal_conf_base.h new file mode 100644 index 0000000000..ed524fecca --- /dev/null +++ b/ports/stm32/boards/stm32l0xx_hal_conf_base.h @@ -0,0 +1,91 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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_STM32L0XX_HAL_CONF_BASE_H +#define MICROPY_INCLUDED_STM32L0XX_HAL_CONF_BASE_H + +// Include various HAL modules for convenience +#include "stm32l0xx_hal_dma.h" +#include "stm32l0xx_hal_adc.h" +#include "stm32l0xx_hal_cortex.h" +#include "stm32l0xx_hal_crc.h" +#include "stm32l0xx_hal_dac.h" +#include "stm32l0xx_hal_flash.h" +#include "stm32l0xx_hal_gpio.h" +#include "stm32l0xx_hal_i2c.h" +#include "stm32l0xx_hal_i2s.h" +#include "stm32l0xx_hal_iwdg.h" +#include "stm32l0xx_hal_pcd.h" +#include "stm32l0xx_hal_pwr.h" +#include "stm32l0xx_hal_rcc.h" +#include "stm32l0xx_hal_rtc.h" +#include "stm32l0xx_hal_spi.h" +#include "stm32l0xx_hal_tim.h" +#include "stm32l0xx_hal_uart.h" +#include "stm32l0xx_hal_usart.h" +#include "stm32l0xx_hal_wwdg.h" + +// Enable various HAL modules +#define HAL_MODULE_ENABLED +#define HAL_ADC_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_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_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +#define HAL_USART_MODULE_ENABLED +#define HAL_WWDG_MODULE_ENABLED + +// Oscillator values in Hz +#define HSI_VALUE (16000000) +#define HSI48_VALUE (48000000) +#define LSI_VALUE (37000) +#define MSI_VALUE (2097152) + +// SysTick has the highest priority +#define TICK_INT_PRIORITY (0x00) + +// Miscellaneous HAL settings +#define PREFETCH_ENABLE 1 +#define PREREAD_ENABLE 0 +#define BUFFER_CACHE_DISABLE 0 +#define USE_RTOS 0 +#define USE_SPI_CRC 0 + +// HAL parameter assertions are disabled +#define assert_param(expr) ((void)0) + +#endif // MICROPY_INCLUDED_STM32L0XX_HAL_CONF_BASE_H From 6053e450b8e3600b96a3e99174ea3385cec9c2dd Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 5 Jul 2019 17:26:49 +1000 Subject: [PATCH 0522/1788] stm32/mpconfigport.h: Make "framebuf" module configurable by a board. --- ports/stm32/mpconfigport.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 5095dde52b..3e615c3437 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -165,7 +165,9 @@ #define MICROPY_HW_SOFTSPI_MAX_BAUDRATE (HAL_RCC_GetSysClockFreq() / 48) #define MICROPY_PY_UWEBSOCKET (MICROPY_PY_LWIP) #define MICROPY_PY_WEBREPL (MICROPY_PY_LWIP) +#ifndef MICROPY_PY_FRAMEBUF #define MICROPY_PY_FRAMEBUF (1) +#endif #ifndef MICROPY_PY_USOCKET #define MICROPY_PY_USOCKET (1) #endif From 7c2e83324b1abfbec2bfaee2c60b50ceb3f9185a Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 5 Jul 2019 17:28:54 +1000 Subject: [PATCH 0523/1788] stm32/boards/NUCLEO_L073RZ: Add definition files for new board. --- .../boards/NUCLEO_L073RZ/mpconfigboard.h | 53 +++++++++++ .../boards/NUCLEO_L073RZ/mpconfigboard.mk | 7 ++ ports/stm32/boards/NUCLEO_L073RZ/pins.csv | 87 +++++++++++++++++++ .../boards/NUCLEO_L073RZ/stm32l0xx_hal_conf.h | 18 ++++ 4 files changed, 165 insertions(+) create mode 100644 ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.h create mode 100644 ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.mk create mode 100644 ports/stm32/boards/NUCLEO_L073RZ/pins.csv create mode 100644 ports/stm32/boards/NUCLEO_L073RZ/stm32l0xx_hal_conf.h diff --git a/ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.h b/ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.h new file mode 100644 index 0000000000..ff4be4a277 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.h @@ -0,0 +1,53 @@ +/* This file is part of the MicroPython project, http://micropython.org/ + * MIT License; Copyright (c) 2019 Damien P. George + */ + +#define MICROPY_HW_BOARD_NAME "NUCLEO-L073RZ" +#define MICROPY_HW_MCU_NAME "STM32F073RZT6" + +#define MICROPY_EMIT_THUMB (0) +#define MICROPY_EMIT_INLINE_THUMB (0) +#define MICROPY_PY_BUILTINS_COMPLEX (0) +#define MICROPY_PY_MATH (0) +#define MICROPY_PY_FRAMEBUF (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 (0) +#define MICROPY_HW_HAS_SWITCH (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 + +// 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 + +// 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_L073RZ/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.mk new file mode 100644 index 0000000000..69601f8602 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.mk @@ -0,0 +1,7 @@ +MCU_SERIES = l0 +CMSIS_MCU = STM32L073xx +AF_FILE = boards/stm32l072_af.csv +LD_FILES = boards/stm32l072xz.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_L073RZ/pins.csv b/ports/stm32/boards/NUCLEO_L073RZ/pins.csv new file mode 100644 index 0000000000..36d3141083 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_L073RZ/pins.csv @@ -0,0 +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,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 diff --git a/ports/stm32/boards/NUCLEO_L073RZ/stm32l0xx_hal_conf.h b/ports/stm32/boards/NUCLEO_L073RZ/stm32l0xx_hal_conf.h new file mode 100644 index 0000000000..c88a706510 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_L073RZ/stm32l0xx_hal_conf.h @@ -0,0 +1,18 @@ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32L0XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32L0XX_HAL_CONF_H + +#include "boards/stm32l0xx_hal_conf_base.h" + +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define LSE_VALUE (32768) + +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) + +#endif // MICROPY_INCLUDED_STM32L0XX_HAL_CONF_H From 21ecf8be5fd13510299acfad557f5d129bed3706 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 8 Jul 2019 15:07:39 +1000 Subject: [PATCH 0524/1788] stm32/powerctrl: Move L0's SystemClock_Config to powerctrlboot.c file. --- ports/stm32/Makefile | 1 + ports/stm32/main.c | 2 -- ports/stm32/powerctrl.c | 24 ----------------- ports/stm32/powerctrl.h | 2 ++ ports/stm32/powerctrlboot.c | 54 +++++++++++++++++++++++++++++++++++++ 5 files changed, 57 insertions(+), 26 deletions(-) create mode 100644 ports/stm32/powerctrlboot.c diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 3d39f0c94a..cddebbf542 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -233,6 +233,7 @@ SRC_C = \ pendsv.c \ systick.c \ powerctrl.c \ + powerctrlboot.c \ pybthread.c \ factoryreset.c \ timer.c \ diff --git a/ports/stm32/main.c b/ports/stm32/main.c index e470522fbd..cd4aaa4845 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -71,8 +71,6 @@ #include "can.h" #include "modnetwork.h" -void SystemClock_Config(void); - #if MICROPY_PY_THREAD STATIC pyb_thread_t pyb_thread_main; #endif diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c index cf2445c7d9..067e4c176e 100644 --- a/ports/stm32/powerctrl.c +++ b/ports/stm32/powerctrl.c @@ -84,30 +84,6 @@ void powerctrl_check_enter_bootloader(void) { } } -#if defined(STM32L0) -void SystemClock_Config(void) { - // Enable power control peripheral - __HAL_RCC_PWR_CLK_ENABLE(); - - // Use the 16MHz internal oscillator - RCC->CR |= RCC_CR_HSION; - while (!(RCC->CR & RCC_CR_HSIRDY)) { - } - const uint32_t sysclk_src = 1; - - // Select SYSCLK source - RCC->CFGR |= sysclk_src << RCC_CFGR_SW_Pos; - while (((RCC->CFGR >> RCC_CFGR_SWS_Pos) & 0x3) != sysclk_src) { - // Wait for SYSCLK source to change - } - - SystemCoreClockUpdate(); - - HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000); - HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); -} -#endif - #if !defined(STM32F0) && !defined(STM32L0) // Assumes that PLL is used as the SYSCLK source diff --git a/ports/stm32/powerctrl.h b/ports/stm32/powerctrl.h index 6eb0342287..6e5f899a4c 100644 --- a/ports/stm32/powerctrl.h +++ b/ports/stm32/powerctrl.h @@ -28,6 +28,8 @@ #include +void SystemClock_Config(void); + NORETURN void powerctrl_mcu_reset(void); NORETURN void powerctrl_enter_bootloader(uint32_t r0, uint32_t bl_addr); void powerctrl_check_enter_bootloader(void); diff --git a/ports/stm32/powerctrlboot.c b/ports/stm32/powerctrlboot.c new file mode 100644 index 0000000000..66beff27c6 --- /dev/null +++ b/ports/stm32/powerctrlboot.c @@ -0,0 +1,54 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2019 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 "powerctrl.h" + +#if defined(STM32L0) + +void SystemClock_Config(void) { + // Enable power control peripheral + __HAL_RCC_PWR_CLK_ENABLE(); + + // Use the 16MHz internal oscillator + RCC->CR |= RCC_CR_HSION; + while (!(RCC->CR & RCC_CR_HSIRDY)) { + } + const uint32_t sysclk_src = 1; + + // Select SYSCLK source + RCC->CFGR |= sysclk_src << RCC_CFGR_SW_Pos; + while (((RCC->CFGR >> RCC_CFGR_SWS_Pos) & 0x3) != sysclk_src) { + // Wait for SYSCLK source to change + } + + SystemCoreClockUpdate(); + + HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000); + HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); +} + +#endif From c15dc2c4b964811c150ccf164edb86a06ed6cd51 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 8 Jul 2019 15:13:54 +1000 Subject: [PATCH 0525/1788] stm32/powerctrl: Move F0's SystemClock_Config to powerctrlboot.c. --- ports/stm32/powerctrlboot.c | 51 +++++++++++++++++++++++++++++++++++- ports/stm32/system_stm32f0.c | 47 --------------------------------- 2 files changed, 50 insertions(+), 48 deletions(-) diff --git a/ports/stm32/powerctrlboot.c b/ports/stm32/powerctrlboot.c index 66beff27c6..527118ba88 100644 --- a/ports/stm32/powerctrlboot.c +++ b/ports/stm32/powerctrlboot.c @@ -27,7 +27,56 @@ #include "py/mphal.h" #include "powerctrl.h" -#if defined(STM32L0) +#if defined(STM32F0) + +void SystemClock_Config(void) { + // Enable power control peripheral + __HAL_RCC_PWR_CLK_ENABLE(); + + // Set flash latency to 1 because SYSCLK > 24MHz + FLASH->ACR = (FLASH->ACR & ~0x7) | 0x1; + + #if MICROPY_HW_CLK_USE_HSI48 + // Use the 48MHz internal oscillator + + RCC->CR2 |= RCC_CR2_HSI48ON; + while ((RCC->CR2 & RCC_CR2_HSI48RDY) == 0) { + } + const uint32_t sysclk_src = 3; + + #else + // Use HSE and the PLL to get a 48MHz SYSCLK + + #if MICROPY_HW_CLK_USE_BYPASS + RCC->CR |= RCC_CR_HSEBYP; + #endif + RCC->CR |= RCC_CR_HSEON; + while ((RCC->CR & RCC_CR_HSERDY) == 0) { + // Wait for HSE to be ready + } + RCC->CFGR = ((48000000 / HSE_VALUE) - 2) << RCC_CFGR_PLLMUL_Pos | 2 << RCC_CFGR_PLLSRC_Pos; + RCC->CFGR2 = 0; // Input clock not divided + RCC->CR |= RCC_CR_PLLON; // Turn PLL on + while ((RCC->CR & RCC_CR_PLLRDY) == 0) { + // Wait for PLL to lock + } + const uint32_t sysclk_src = 2; + + #endif + + // Select SYSCLK source + RCC->CFGR |= sysclk_src << RCC_CFGR_SW_Pos; + while (((RCC->CFGR >> RCC_CFGR_SWS_Pos) & 0x3) != sysclk_src) { + // Wait for SYSCLK source to change + } + + SystemCoreClockUpdate(); + + HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000); + HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); +} + +#elif defined(STM32L0) void SystemClock_Config(void) { // Enable power control peripheral diff --git a/ports/stm32/system_stm32f0.c b/ports/stm32/system_stm32f0.c index c3c675c745..4f561145cc 100644 --- a/ports/stm32/system_stm32f0.c +++ b/ports/stm32/system_stm32f0.c @@ -128,53 +128,6 @@ void SystemInit(void) { SCB->CCR |= SCB_CCR_STKALIGN_Msk; } -void SystemClock_Config(void) { - // Enable power control peripheral - __HAL_RCC_PWR_CLK_ENABLE(); - - // Set flash latency to 1 because SYSCLK > 24MHz - FLASH->ACR = (FLASH->ACR & ~0x7) | 0x1; - - #if MICROPY_HW_CLK_USE_HSI48 - // Use the 48MHz internal oscillator - - RCC->CR2 |= RCC_CR2_HSI48ON; - while ((RCC->CR2 & RCC_CR2_HSI48RDY) == 0) { - } - const uint32_t sysclk_src = 3; - - #else - // Use HSE and the PLL to get a 48MHz SYSCLK - - #if MICROPY_HW_CLK_USE_BYPASS - RCC->CR |= RCC_CR_HSEBYP; - #endif - RCC->CR |= RCC_CR_HSEON; - while ((RCC->CR & RCC_CR_HSERDY) == 0) { - // Wait for HSE to be ready - } - RCC->CFGR = ((48000000 / HSE_VALUE) - 2) << RCC_CFGR_PLLMUL_Pos | 2 << RCC_CFGR_PLLSRC_Pos; - RCC->CFGR2 = 0; // Input clock not divided - RCC->CR |= RCC_CR_PLLON; // Turn PLL on - while ((RCC->CR & RCC_CR_PLLRDY) == 0) { - // Wait for PLL to lock - } - const uint32_t sysclk_src = 2; - - #endif - - // Select SYSCLK source - RCC->CFGR |= sysclk_src << RCC_CFGR_SW_Pos; - while (((RCC->CFGR >> RCC_CFGR_SWS_Pos) & 0x3) != sysclk_src) { - // 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; From 5fd62c899226fbaac96a758e9f2b4fef5afcf19b Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 8 Jul 2019 15:16:26 +1000 Subject: [PATCH 0526/1788] stm32: Remove SystemInit funcs, use stm32lib versions instead. stm32lib now provides system_stm32XXxx.c source files for all MCU variants, which includes SystemInit and prescaler tables. Since these are quite standard and don't need to be changed, switch to use them instead of custom variants, making the start-up code cleaner. The SystemInit code in stm32lib was checked and is equivalent to what is removed from the stm32 port in this commit. --- ports/stm32/Makefile | 14 +-- ports/stm32/main.c | 8 ++ ports/stm32/system_stm32.c | 211 ----------------------------------- ports/stm32/system_stm32f0.c | 184 ------------------------------ 4 files changed, 15 insertions(+), 402 deletions(-) delete mode 100644 ports/stm32/system_stm32f0.c diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index cddebbf542..84ce01e8f9 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -43,6 +43,7 @@ STFLASH ?= st-flash OPENOCD ?= openocd OPENOCD_CONFIG ?= boards/openocd_stm32f4.cfg STARTUP_FILE ?= lib/stm32lib/CMSIS/STM32$(MCU_SERIES_UPPER)xx/Source/Templates/gcc/startup_$(CMSIS_MCU_LOWER).o +SYSTEM_FILE ?= lib/stm32lib/CMSIS/STM32$(MCU_SERIES_UPPER)xx/Source/Templates/system_stm32$(MCU_SERIES)xx.o # Select the cross compile prefix CROSS_COMPILE ?= arm-none-eabi- @@ -284,23 +285,22 @@ SRC_C = \ adc.c \ $(wildcard $(BOARD_DIR)/*.c) -ifeq ($(MCU_SERIES),f0) SRC_O = \ $(STARTUP_FILE) \ - system_stm32f0.o \ + $(SYSTEM_FILE) + +ifeq ($(MCU_SERIES),f0) +SRC_O += \ resethandler_m0.o \ lib/utils/gchelper_m0.o else ifeq ($(MCU_SERIES),l0) CSUPEROPT = -Os # save some code space -SRC_O = \ - $(STARTUP_FILE) \ - lib/stm32lib/CMSIS/STM32$(MCU_SERIES_UPPER)xx/Source/Templates/system_stm32$(MCU_SERIES)xx.o \ +SRC_O += \ resethandler_m0.o \ lib/utils/gchelper_m0.o else -SRC_O = \ - $(STARTUP_FILE) \ +SRC_O += \ system_stm32.o \ resethandler.o \ lib/utils/gchelper_m3.o diff --git a/ports/stm32/main.c b/ports/stm32/main.c index cd4aaa4845..c057814320 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -368,6 +368,14 @@ STATIC uint update_reset_mode(uint reset_mode) { #endif void stm32_main(uint32_t reset_mode) { + #if !defined(STM32F0) && defined(MICROPY_HW_VTOR) + // Change IRQ vector table if configured differently + SCB->VTOR = MICROPY_HW_VTOR; + #endif + + // Enable 8-byte stack alignment for IRQ handlers, in accord with EABI + SCB->CCR |= SCB_CCR_STKALIGN_Msk; + // Check if bootloader should be entered instead of main application powerctrl_check_enter_bootloader(); diff --git a/ports/stm32/system_stm32.c b/ports/stm32/system_stm32.c index be8badea43..deb23e2f5f 100644 --- a/ports/stm32/system_stm32.c +++ b/ports/stm32/system_stm32.c @@ -75,222 +75,11 @@ ****************************************************************************** */ -/** @addtogroup CMSIS - * @{ - */ - -/** @addtogroup stm32fxxx_system - * @{ - */ - -/** @addtogroup STM32Fxxx_System_Private_Includes - * @{ - */ - #include "py/mphal.h" #include "powerctrl.h" void __fatal_error(const char *msg); -/** - * @} - */ - -/** @addtogroup STM32Fxxx_System_Private_TypesDefinitions - * @{ - */ - -/** - * @} - */ - -/** @addtogroup STM32Fxxx_System_Private_Defines - * @{ - */ - -#if defined(STM32F4) || defined(STM32F7) - -#define CONFIG_RCC_CR_1ST (RCC_CR_HSION) -#define CONFIG_RCC_CR_2ND (MICROPY_HW_RCC_CR_HSxON | RCC_CR_CSSON | RCC_CR_PLLON) -#define CONFIG_RCC_PLLCFGR (0x24003010) - -#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(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(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) -#define CONFIG_RCC_PLLCFGR (0x00001000) -/* - * FIXME Do not know why I have to define these arrays here! they should be defined in the - * hal_rcc-file!! - * - */ -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}; -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 - -/************************* Miscellaneous Configuration ************************/ - -/*!< Uncomment the following line if you need to relocate your vector Table in - Internal SRAM. */ -/* #define VECT_TAB_SRAM */ -#define VECT_TAB_OFFSET 0x00 /*!< Vector Table base offset field. - This value must be a multiple of 0x200. */ -/******************************************************************************/ - -/** - * @} - */ - -/** @addtogroup STM32Fxxx_System_Private_Macros - * @{ - */ - -/** - * @} - */ - -/** @addtogroup STM32Fxxx_System_Private_Variables - * @{ - */ - /* 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; then there - is no need to call the 2 first functions listed above, since SystemCoreClock - variable is updated automatically. - */ - uint32_t SystemCoreClock = 16000000; - -/** - * @} - */ - -/** @addtogroup STM32Fxxx_System_Private_FunctionPrototypes - * @{ - */ - -/** - * @} - */ - -/** @addtogroup STM32Fxxx_System_Private_Functions - * @{ - */ - -/** - * @brief Setup the microcontroller system - * Initialize the FPU setting, vector table location and External memory - * configuration. - * @param None - * @retval None - */ -void SystemInit(void) -{ - /* FPU settings ------------------------------------------------------------*/ - #if (__FPU_PRESENT == 1) && (__FPU_USED == 1) - SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */ - #endif - /* Reset the RCC clock configuration to the default reset state ------------*/ - - /* Set configured startup clk source */ - RCC->CR |= CONFIG_RCC_CR_1ST; - - /* Reset CFGR register */ - RCC->CFGR = 0x00000000; - - /* Reset HSxON, CSSON and PLLON bits */ - RCC->CR &= ~ CONFIG_RCC_CR_2ND; - - /* 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(STM32F4) || defined(STM32F7) - RCC->CIR = 0x00000000; - #elif defined(STM32L4) || 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 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 */ - SCB->CCR |= SCB_CCR_STKALIGN_Msk; -} - - /** * @brief System Clock Configuration * diff --git a/ports/stm32/system_stm32f0.c b/ports/stm32/system_stm32f0.c deleted file mode 100644 index 4f561145cc..0000000000 --- a/ports/stm32/system_stm32f0.c +++ /dev/null @@ -1,184 +0,0 @@ -/* - * 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 "py/mphal.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 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****/ From eea61a09c4b26e8f909bbf52fa9df14f1e2f0390 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 8 Jul 2019 16:08:40 +1000 Subject: [PATCH 0527/1788] stm32/boards/NUCLEO_F446RE: Enable DAC. --- ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.h index d801fa1885..cd4ad36fa0 100644 --- a/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F446RE/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_DAC (1) // HSE is 8MHz, CPU freq set to 168MHz. Using PLLQ for USB this gives a nice // 48 MHz clock for USB. To goto 180 MHz, I think that USB would need to be From 64181b5f767e627591f9684a57bbae19e0415b86 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Mon, 20 May 2019 22:00:41 +1000 Subject: [PATCH 0528/1788] stm32: Add support for STM32L452 MCUs. --- ports/stm32/adc.c | 4 +- ports/stm32/boards/stm32l452_af.csv | 85 +++++++++++++++++++++++++++++ ports/stm32/boards/stm32l452xe.ld | 34 ++++++++++++ ports/stm32/dac.c | 14 ++++- ports/stm32/dma.c | 2 + ports/stm32/dma.h | 2 + ports/stm32/flashbdev.c | 6 +- 7 files changed, 143 insertions(+), 4 deletions(-) create mode 100644 ports/stm32/boards/stm32l452_af.csv create mode 100644 ports/stm32/boards/stm32l452xe.ld diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index 1215690333..a4eaefd758 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -145,7 +145,9 @@ #define VBAT_DIV (4) #elif defined(STM32H743xx) #define VBAT_DIV (4) -#elif defined(STM32L432xx) || defined(STM32L475xx) || \ +#elif defined(STM32L432xx) || \ + defined(STM32L451xx) || defined(STM32L452xx) || \ + defined(STM32L462xx) || defined(STM32L475xx) || \ defined(STM32L476xx) || defined(STM32L496xx) #define VBAT_DIV (3) #else diff --git a/ports/stm32/boards/stm32l452_af.csv b/ports/stm32/boards/stm32l452_af.csv new file mode 100644 index 0000000000..f7170d1c65 --- /dev/null +++ b/ports/stm32/boards/stm32l452_af.csv @@ -0,0 +1,85 @@ +Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15,,, +,,SYS_AF,TIM1/TIM2/LPTIM1,I2C4/TIM1/TIM2/TIM3,I2C4/USART2/CAN1/TIM1,I2C1/I2C2/I2C3/I2C4,SPI1/SPI2/I2C4,SPI3/DFSDM/COMP1,USART1/USART2/USART3,UART4/LPUART1/CAN1,CAN1/TSC,CAN1/USB/QUADSPI,,SDMMC1/COMP1/COMP2,SAI1,TIM2/TIM15/TIM16/LPTIM2,EVENTOUT,ADC,COMP,DAC +PortA,PA0,,TIM2_CH1,,,,,,USART2_CTS,UART4_TX,,,,COMP1_OUT,SAI1_EXTCLK,TIM2_ETR,EVENTOUT,ADC12_IN5,COMP1_INM, +PortA,PA1,,TIM2_CH2,,,I2C1_SMBA,SPI1_SCK,,USART2_RTS/USART2_DE,UART4_RX,,,,,,TIM15_CH1N,EVENTOUT,ADC12_IN6,COMP1_INP, +PortA,PA2,,TIM2_CH3,,,,,,USART2_TX,LPUART1_TX,,QUADSPI_BK1_NCS,,COMP2_OUT,,TIM15_CH1,EVENTOUT,ADC12_IN7,COMP2_INM, +PortA,PA3,,TIM2_CH4,,,,,,USART2_RX,LPUART1_RX,,QUADSPI_CLK,,,SAI1_MCLK_A,TIM15_CH2,EVENTOUT,ADC12_IN8,COMP2_INP, +PortA,PA4,,,,,,SPI1_NSS,SPI3_NSS,USART2_CK,,,,,,SAI1_FS_B,LPTIM2_OUT,EVENTOUT,ADC12_IN9,COMP1_INM/COMP2_INM,DAC1_OUT1 +PortA,PA5,,TIM2_CH1,TIM2_ETR,,,SPI1_SCK,DFSDM1_CKOUT,,,,,,,,LPTIM2_ETR,EVENTOUT,ADC12_IN10,COMP1_INM/COMP2_INM, +PortA,PA6,,TIM1_BKIN,TIM3_CH1,,,SPI1_MISO,COMP1_OUT,USART3_CTS,LPUART1_CTS,,QUADSPI_BK1_IO3,,TIM1_BKIN_COMP2,,TIM16_CH1,EVENTOUT,ADC12_IN11,, +PortA,PA7,,TIM1_CH1N,TIM3_CH2,,I2C3_SCL,SPI1_MOSI,DFSDM1_DATIN0,,,,QUADSPI_BK1_IO2,,COMP2_OUT,,,EVENTOUT,ADC12_IN12,, +PortA,PA8,MCO,TIM1_CH1,,,,,DFSDM1_CKIN1,USART1_CK,,,,,,SAI1_SCK_A,LPTIM2_OUT,EVENTOUT,,, +PortA,PA9,,TIM1_CH2,,,I2C1_SCL,,DFSDM1_DATIN1,USART1_TX,,,,,,SAI1_FS_A,TIM15_BKIN,EVENTOUT,,, +PortA,PA10,,TIM1_CH3,,,I2C1_SDA,,,USART1_RX,,,USBCRS_SYNC,,,SAI1_SD_A,,EVENTOUT,,, +PortA,PA11,,TIM1_CH4,TIM1_BKIN2,,,SPI1_MISO,COMP1_OUT,USART1_CTS,,CAN1_RX,USBDM,,TIM1_BKIN2_COMP1,,,EVENTOUT,,, +PortA,PA12,,TIM1_ETR,,,,SPI1_MOSI,,USART1_RTS/USART1_DE,,CAN1_TX,USBDP,,,,,EVENTOUT,,, +PortA,PA13,JTMS/SWDIO,IR_OUT,,,,,,,,,USBNOE,,,SAI1_SD_B,,EVENTOUT,,, +PortA,PA14,JTCK/SWCLK,LPTIM1_OUT,,,I2C1_SMBA,I2C4_SMBA,,,,,,,,SAI1_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,,,,,,EVENTOUT,,, +PortB,PB0,,TIM1_CH2N,TIM3_CH3,,,SPI1_NSS,DFSDM1_CKIN0,USART3_CK,,,QUADSPI_BK1_IO1,,COMP1_OUT,SAI1_EXTCLK,,EVENTOUT,ADC12_IN15,, +PortB,PB1,,TIM1_CH3N,TIM3_CH4,,,,DFSDM_DATIN0,USART3_RTS/USART3_DE,LPUART1_RTS/LPUART1_DE,,QUADSPI_BK1_IO0,,,,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/USART1_DE,,,,,,SAI1_SCK_B,,EVENTOUT,,COMP2_INM, +PortB,PB4,NJTRST,,TIM3_CH1,,I2C3_SDA,SPI1_MISO,SPI3_MISO,USART1_CTS,,TSC_G2_IO1,,,,SAI1_MCLK_B,,EVENTOUT,,COMP2_INP, +PortB,PB5,,LPTIM1_IN1,TIM3_CH2,CAN1_RX,I2C1_SMBA,SPI1_MOSI,SPI3_MOSI,USART1_CK,,TSC_G2_IO2,,,COMP2_OUT,SAI1_SD_B,TIM16_BKIN,EVENTOUT,,, +PortB,PB6,,LPTIM1_ETR,,,I2C1_SCL,I2C4_SCL,,USART1_TX,CAN1_TX,TSC_G2_IO3,,,,SAI1_FS_B,TIM16_CH1N,EVENTOUT,,COMP2_INP, +PortB,PB7,,LPTIM1_IN2,,,I2C1_SDA,I2C4_SDA,,USART1_RX,UART4_CTS,TSC_G2_IO4,,,,,,EVENTOUT,,COMP2_INM, +PortB,PB8,,,,,I2C1_SCL,,,,,CAN1_RX,,,SDMMC1_D4,SAI1_MCLK_A,TIM16_CH1,EVENTOUT,,, +PortB,PB9,,IR_OUT,,,I2C1_SDA,SPI2_NSS,,,,CAN1_TX,,,SDMMC1_D5,SAI1_FS_A,,EVENTOUT,,, +PortB,PB10,,TIM2_CH3,,I2C4_SCL,I2C2_SCL,SPI2_SCK,,USART3_TX,LPUART1_RX,TSC_SYNC,QUADSPI_CLK,,COMP1_OUT,SAI1_SCK_A,,EVENTOUT,,, +PortB,PB11,,TIM2_CH4,,I2C4_SDA,I2C2_SDA,,,USART3_RX,LPUART1_TX,,QUADSPI_NCS,,COMP2_OUT,,,EVENTOUT,,, +PortB,PB12,,TIM1_BKIN,,TIM1_BKIN_COMP2,I2C2_SMBA,SPI2_NSS,DFSDM_DATIN1,USART3_CK,LPUART1_RTS/LPUART1_DE,TSC_G1_IO1,CAN1_RX,,,SAI1_FS_A,TIM15_BKIN,EVENTOUT,,, +PortB,PB13,,TIM1_CH1N,,,I2C2_SCL,SPI2_SCK,DFSDM_CKIN1,USART3_CTS,LPUART1_CTS,TSC_G1_IO2,CAN1_TX,,,SAI1_SCK_A,TIM15_CH1N,EVENTOUT,,, +PortB,PB14,,TIM1_CH2N,,,I2C2_SDA,SPI2_MISO,DFSDM_DATIN2,USART3_RTS_DE,,TSC_G1_IO3,,,,SAI1_MCLK_A,TIM15_CH1,EVENTOUT,,, +PortB,PB15,RTC_REFIN,TIM1_CH3N,,,,SPI2_MOSI,DFSDM_CKIN2,,,TSC_G1_IO4,,,,SAI1_SD_A,TIM15_CH2,EVENTOUT,,, +PortC,PC0,,LPTIM1_IN1,I2C4_SCL,,I2C3_SCL,,,,LPUART1_RX,,,,,,LPTIM2_IN1,EVENTOUT,ADC123_IN1,, +PortC,PC1,TRACED0,LPTIM1_OUT,I2C4_SDA,,I2C3_SDA,,,,LPUART1_TX,,,,,,,EVENTOUT,ADC123_IN2,, +PortC,PC2,,LPTIM1_IN2,,,,SPI2_MISO,DFSDM_CKOUT,,,,,,,,,EVENTOUT,ADC123_IN3,, +PortC,PC3,,LPTIM1_ETR,,,,SPI2_MOSI,,,,,,,,SAI1_SD_A,LPTIM2_ETR,EVENTOUT,ADC123_IN4,, +PortC,PC4,,,,,,,,USART3_TX,,,,,,,,EVENTOUT,ADC12_IN13,COMP1_INM, +PortC,PC5,,,,,,,,USART3_RX,,,,,,,,EVENTOUT,ADC12_IN14,COMP1_INP, +PortC,PC6,,,TIM3_CH1,,,,DFSDM_CKIN3,,,TSC_G4_IO1,,,SDMMC1_D6,,,EVENTOUT,,, +PortC,PC7,,,TIM3_CH2,,,,DFSDM_DATIN3,,,TSC_G4_IO2,,,SDMMC1_D7,,,EVENTOUT,,, +PortC,PC8,,,TIM3_CH3,,,,,,,TSC_G4_IO3,,,SDMMC1_D0,,,EVENTOUT,,, +PortC,PC9,,,TIM3_CH4,,,,,,,TSC_G4_IO4,USBNOE,,SDMMC1_D1,,,EVENTOUT,,, +PortC,PC10,TRACED1,,,,,,SPI3_SCK,USART3_TX,UART4_TX,TSC_G3_IO2,,,SDMMC1_D2,,,EVENTOUT,,, +PortC,PC11,,,,,,,SPI3_MISO,USART3_RX,UART4_RX,TSC_G3_IO3,,,SDMMC1_D3,,,EVENTOUT,,, +PortC,PC12,TRACED3,,,,,,SPI3_MOSI,USART3_CK,,TSC_G3_IO4,,,SDMMC1_CK,,,EVENTOUT,,, +PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT,,, +PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT,,, +PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT,,, +PortD,PD0,,,,,,SPI2_NSS,,,,CAN1_RX,,,,,,EVENTOUT,,, +PortD,PD1,,,,,,SPI2_SCK,,,,CAN1_TX,,,,,,EVENTOUT,,, +PortD,PD2,TRACED2,,TIM3_ETR,,,,,USART3_RTS/USART3_DE,,TSC_SYNC,,,SDMMC1_CMD,,,EVENTOUT,,, +PortD,PD3,,,,,,SPI2_MISO,DFSDM_DATIN0,USART2_CTS,,,QUADSPI_BK2_NCS,,,,,EVENTOUT,,, +PortD,PD4,,,,,,SPI2_MOSI,DFSDM_CKIN0,USART2_RTS/USART2_DE,,,QUADSPI_BK2_IO0,,,,,EVENTOUT,,, +PortD,PD5,,,,,,,,USART2_TX,,,QUADSPI_BK2_IO1,,,,,EVENTOUT,,, +PortD,PD6,,,,,,,DFSDM_DATIN1,USART2_RX,,,QUADSPI_BK2_IO2,,,SAI1_SD_A,,EVENTOUT,,, +PortD,PD7,,,,,,,DFSDM_CKIN1,USART2_CK,,,QUADSPI_BK2_IO3,,,,,EVENTOUT,,, +PortD,PD8,,,,,,,,USART3_TX,,,,,,,,EVENTOUT,,, +PortD,PD9,,,,,,,,USART3_RX,,,,,,,,EVENTOUT,,, +PortD,PD10,,,,,,,,USART3_CK,,TSC_G6_IO1,,,,,,EVENTOUT,,, +PortD,PD11,,,,,I2C4_SMBA,,,USART3_CTS,,TSC_G6_IO2,,,,,LPTIM2_ETR,EVENTOUT,,, +PortD,PD12,,,,,I2C4_SCL,,,USART3_RTS/USART3_DE,,TSC_G6_IO3,,,,,LPTIM2_IN1,EVENTOUT,,, +PortD,PD13,,,,,I2C4_SDA,,,,,TSC_G6_IO4,,,,,LPTIM2_OUT,EVENTOUT,,, +PortD,PD14,,,,,,,,,,,,,,,,EVENTOUT,,, +PortD,PD15,,,,,,,,,,,,,,,,EVENTOUT,,, +PortE,PE0,,,,,,,,,,,,,,,TIM16_CH1,EVENTOUT,,, +PortE,PE1,,,,,,,,,,,,,,,,EVENTOUT,,, +PortE,PE2,TRACECLK,,TIM3_ETR,,,,,,,TSC_G7_IO1,,,,SAI1_MCLK_A,,EVENTOUT,,, +PortE,PE3,TRACED0,,TIM3_CH1,,,,,,,TSC_G7_IO2,,,,SAI1_SD_B,,EVENTOUT,,, +PortE,PE4,TRACED1,,TIM3_CH2,,,,DFSDM_DATIN3,,,TSC_G7_IO3,,,,SAI1_FS_A,,EVENTOUT,,, +PortE,PE5,TRACED2,,TIM3_CH3,,,,DFSDM_CKIN3,,,TSC_G7_IO4,,,,SAI1_SCK_A,,EVENTOUT,,, +PortE,PE6,TRACED3,,TIM3_CH4,,,,,,,,,,,SAI1_SD_A,,EVENTOUT,,, +PortE,PE7,,TIM1_ETR,,,,,DFSDM_DATIN2,,,,,,,SAI1_SD_B,,EVENTOUT,,, +PortE,PE8,,TIM1_CH1N,,,,,DFSDM_CKIN2,,,,,,,SAI1_SCK_B,,EVENTOUT,,, +PortE,PE9,,TIM1_CH1,,,,,DFSDM_CKOUT,,,,,,,SAI1_FS_B,,EVENTOUT,,, +PortE,PE10,,TIM1_CH2N,,,,,,,,TSC_G5_IO1,QUADSPI_CLK,,,SAI1_MCLK_B,,EVENTOUT,,, +PortE,PE11,,TIM1_CH2,,,,,,,,TSC_G5_IO2,QUADSPI_BK1_NCS,,,,,EVENTOUT,,, +PortE,PE12,,TIM1_CH3N,,,,SPI1_NSS,,,,TSC_G5_IO3,QUADSPI_BK1_IO0,,,,,EVENTOUT,,, +PortE,PE13,,TIM1_CH3,,,,SPI1_SCK,,,,TSC_G5_IO4,QUADSPI_BK1_IO1,,,,,EVENTOUT,,, +PortE,PE14,,TIM1_CH4,TIM1_BKIN2,TIM1_BKIN2_COMP2,,SPI1_MISO,,,,,QUADSPI_BK1_IO2,,,,,EVENTOUT,,, +PortE,PE15,,TIM1_BKIN,,TIM1_BKIN_COMP1,,SPI1_MOSI,,,,,QUADSPI_BK1_IO3,,,,,EVENTOUT,,, +PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT,,, +PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT,,, +PortH,PH3,,,,,,,,,,,,,,,,,,, diff --git a/ports/stm32/boards/stm32l452xe.ld b/ports/stm32/boards/stm32l452xe.ld new file mode 100644 index 0000000000..7b07ee7018 --- /dev/null +++ b/ports/stm32/boards/stm32l452xe.ld @@ -0,0 +1,34 @@ +/* + GNU linker script for STM32L452XE +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 384K /* sectors 0-191 */ + FLASH_FS (r) : ORIGIN = 0x08060000, LENGTH = 128K /* sectors 192-255 */ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 160K /* SRAM1, 128K + SRAM2, 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 the stack. The stack is full descending so begins just above last byte of RAM, + or bottom of FS cache.. Note that EABI requires the stack to be 8-byte aligned for a call. */ + +/* RAM extents for the garbage collector */ +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM); + +_ram_fs_cache_end = _ram_end; +_ram_fs_cache_start = _ram_fs_cache_end - 2K; /* fs cache = 2K */ + +_estack = _ram_fs_cache_start - _estack_reserve; +_sstack = _estack - 16K; /* stack = 16K */ + +_heap_start = _ebss; /* heap starts just after statically allocated memory */ +_heap_end = _sstack; /* bss + heap = 142K, tunable by adjusting stack size */ + +_flash_fs_start = ORIGIN(FLASH_FS); +_flash_fs_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); diff --git a/ports/stm32/dac.c b/ports/stm32/dac.c index cb9157c3da..f3dcccb3da 100644 --- a/ports/stm32/dac.c +++ b/ports/stm32/dac.c @@ -148,8 +148,10 @@ STATIC void dac_set_value(uint32_t dac_channel, uint32_t align, uint32_t value) uint32_t base; if (dac_channel == DAC_CHANNEL_1) { base = (uint32_t)&DAC->DHR12R1; + #if !defined(STM32L452xx) } else { base = (uint32_t)&DAC->DHR12R2; + #endif } *(volatile uint32_t*)(base + align) = value; } @@ -169,8 +171,10 @@ STATIC void dac_start_dma(uint32_t dac_channel, const dma_descr_t *dma_descr, ui uint32_t base; if (dac_channel == DAC_CHANNEL_1) { base = (uint32_t)&DAC->DHR12R1; + #if !defined(STM32L452xx) } else { base = (uint32_t)&DAC->DHR12R2; + #endif } dma_nohal_deinit(dma_descr); @@ -185,7 +189,7 @@ STATIC void dac_start_dma(uint32_t dac_channel, const dma_descr_t *dma_descr, ui typedef struct _pyb_dac_obj_t { mp_obj_base_t base; - uint8_t dac_channel; // DAC_CHANNEL_1 or DAC_CHANNEL_2 + uint8_t dac_channel; // DAC_CHANNEL_1 or DAC_CHANNEL_2. STM32L452 only has CHANNEL_1. uint8_t bits; // 8 or 12 uint8_t outbuf_single; uint8_t outbuf_waveform; @@ -200,8 +204,10 @@ STATIC void pyb_dac_reconfigure(pyb_dac_obj_t *self, uint32_t cr, uint32_t outbu const dma_descr_t *tx_dma_descr; if (self->dac_channel == DAC_CHANNEL_1) { tx_dma_descr = &dma_DAC_1_TX; + #if !defined(STM32L452xx) } else { tx_dma_descr = &dma_DAC_2_TX; + #endif } dma_nohal_deinit(tx_dma_descr); dac_config_channel(self->dac_channel, cr, outbuf); @@ -234,8 +240,10 @@ STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, size_t n_args, const mp mp_hal_pin_obj_t pin; if (self->dac_channel == DAC_CHANNEL_1) { pin = pin_A4; + #if !defined(STM32L452xx) } else { pin = pin_A5; + #endif } mp_hal_pin_config(pin, MP_HAL_PIN_MODE_ANALOG, MP_HAL_PIN_PULL_NONE, 0); @@ -306,8 +314,10 @@ STATIC mp_obj_t pyb_dac_make_new(const mp_obj_type_t *type, size_t n_args, size_ uint32_t dac_channel; if (dac_id == 1) { dac_channel = DAC_CHANNEL_1; + #if !defined(STM32L452xx) } else if (dac_id == 2) { dac_channel = DAC_CHANNEL_2; + #endif } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "DAC(%d) doesn't exist", dac_id)); } @@ -446,8 +456,10 @@ mp_obj_t pyb_dac_write_timed(size_t n_args, const mp_obj_t *pos_args, mp_map_t * const dma_descr_t *tx_dma_descr; if (self->dac_channel == DAC_CHANNEL_1) { tx_dma_descr = &dma_DAC_1_TX; + #if !defined(STM32L452xx) } else { tx_dma_descr = &dma_DAC_2_TX; + #endif } uint32_t align; diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c index 32b9a74d70..2c7371e010 100644 --- a/ports/stm32/dma.c +++ b/ports/stm32/dma.c @@ -387,7 +387,9 @@ const dma_descr_t dma_I2C_1_TX = { DMA1_Channel6, DMA_REQUEST_3, dma_id_5, &dm const dma_descr_t dma_I2C_1_RX = { DMA1_Channel7, DMA_REQUEST_3, dma_id_6, &dma_init_struct_spi_i2c }; // DMA2 streams +const dma_descr_t dma_I2C_4_RX = { DMA2_Channel1, DMA_REQUEST_0, dma_id_0, &dma_init_struct_spi_i2c }; const dma_descr_t dma_SPI_3_RX = { DMA2_Channel1, DMA_REQUEST_3, dma_id_7, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_4_TX = { DMA2_Channel2, DMA_REQUEST_0, dma_id_1, &dma_init_struct_spi_i2c }; const dma_descr_t dma_SPI_3_TX = { DMA2_Channel2, DMA_REQUEST_3, dma_id_8, &dma_init_struct_spi_i2c }; /* not preferred streams const dma_descr_t dma_ADC_1_RX = { DMA2_Channel3, DMA_REQUEST_0, dma_id_9, NULL }; diff --git a/ports/stm32/dma.h b/ports/stm32/dma.h index bedabe7f89..6d07a94ed9 100644 --- a/ports/stm32/dma.h +++ b/ports/stm32/dma.h @@ -93,6 +93,8 @@ extern const dma_descr_t dma_I2C_1_RX; extern const dma_descr_t dma_SPI_3_RX; extern const dma_descr_t dma_SPI_3_TX; extern const dma_descr_t dma_SDIO_0; +extern const dma_descr_t dma_I2C_4_TX; +extern const dma_descr_t dma_I2C_4_RX; #endif diff --git a/ports/stm32/flashbdev.c b/ports/stm32/flashbdev.c index 484fa1a1bc..0a5f417040 100644 --- a/ports/stm32/flashbdev.c +++ b/ports/stm32/flashbdev.c @@ -103,9 +103,11 @@ 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(STM32L432xx) || defined(STM32L475xx) || defined(STM32L476xx) || defined(STM32L496xx) +#elif defined(STM32L432xx) || \ + defined(STM32L451xx) || defined(STM32L452xx) || defined(STM32L462xx) || \ + defined(STM32L475xx) || defined(STM32L476xx) || defined(STM32L496xx) -// The STM32L475/6 doesn't have CCRAM, so we use the 32K SRAM2 for this, although +// The STM32L4xx doesn't have CCRAM, so we use SRAM2 for this, although // actual location and size is defined by the linker script. extern uint8_t _flash_fs_start; extern uint8_t _flash_fs_end; From c24d81119c4e34936e2c8be1e7c7aa79a71e0d14 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Sat, 29 Jun 2019 20:55:19 +1000 Subject: [PATCH 0529/1788] stm32/boards/NUCLEO_L452RE: Add definition files for new board. --- .../boards/NUCLEO_L452RE/mpconfigboard.h | 74 ++++++++++++++++ .../boards/NUCLEO_L452RE/mpconfigboard.mk | 5 ++ ports/stm32/boards/NUCLEO_L452RE/pins.csv | 86 +++++++++++++++++++ .../boards/NUCLEO_L452RE/stm32l4xx_hal_conf.h | 20 +++++ 4 files changed, 185 insertions(+) create mode 100644 ports/stm32/boards/NUCLEO_L452RE/mpconfigboard.h create mode 100644 ports/stm32/boards/NUCLEO_L452RE/mpconfigboard.mk create mode 100644 ports/stm32/boards/NUCLEO_L452RE/pins.csv create mode 100644 ports/stm32/boards/NUCLEO_L452RE/stm32l4xx_hal_conf.h diff --git a/ports/stm32/boards/NUCLEO_L452RE/mpconfigboard.h b/ports/stm32/boards/NUCLEO_L452RE/mpconfigboard.h new file mode 100644 index 0000000000..9823ae9b9b --- /dev/null +++ b/ports/stm32/boards/NUCLEO_L452RE/mpconfigboard.h @@ -0,0 +1,74 @@ +#define MICROPY_HW_BOARD_NAME "NUCLEO-L452RE" +#define MICROPY_HW_MCU_NAME "STM32L452RE" + +#define MICROPY_PY_USOCKET (0) +#define MICROPY_PY_NETWORK (0) + +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_SERVO (0) // SERVO requires TIM5 (not on L452). +#define MICROPY_HW_HAS_SWITCH (1) + +// MSI is used and is 4MHz +#define MICROPY_HW_CLK_PLLM (1) +#define MICROPY_HW_CLK_PLLN (40) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV7) +#define MICROPY_HW_CLK_PLLQ (RCC_PLLQ_DIV2) +#define MICROPY_HW_CLK_PLLR (RCC_PLLR_DIV2) +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_4 + +// 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) // VCP TX +#define MICROPY_HW_UART2_RX (pin_A3) // VCP RX +#define MICROPY_HW_UART3_TX (pin_C10) +#define MICROPY_HW_UART3_RX (pin_C11) +#define MICROPY_HW_UART4_TX (pin_A0) +#define MICROPY_HW_UART4_RX (pin_A1) +// 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 +#define MICROPY_HW_I2C3_SCL (pin_A7) // pin 15 on CN10 +#define MICROPY_HW_I2C3_SDA (pin_B4) // pin 27 on CN10 +#define MICROPY_HW_I2C4_SCL (pin_C0) // pin 38 on CN7 +#define MICROPY_HW_I2C4_SDA (pin_C1) // pin 36 on CN7 + +// 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 +#define MICROPY_HW_SPI3_NSS (pin_A4) // pin 32 on CN7 +#define MICROPY_HW_SPI3_SCK (pin_C10) // pin 1 on CN7 +#define MICROPY_HW_SPI3_MISO (pin_C11) // pin 2 on CN7 +#define MICROPY_HW_SPI3_MOSI (pin_C12) // pin 3 on CN7 + +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) + +// 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_L452RE/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_L452RE/mpconfigboard.mk new file mode 100644 index 0000000000..25ccb45a94 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_L452RE/mpconfigboard.mk @@ -0,0 +1,5 @@ +MCU_SERIES = l4 +CMSIS_MCU = STM32L452xx +AF_FILE = boards/stm32l452_af.csv +LD_FILES = boards/stm32l452xe.ld boards/common_basic.ld +OPENOCD_CONFIG = boards/openocd_stm32l4.cfg diff --git a/ports/stm32/boards/NUCLEO_L452RE/pins.csv b/ports/stm32/boards/NUCLEO_L452RE/pins.csv new file mode 100644 index 0000000000..adc319575a --- /dev/null +++ b/ports/stm32/boards/NUCLEO_L452RE/pins.csv @@ -0,0 +1,86 @@ +CN9_D0,PA3 +CN9_D1,PA2 +CN9_D2,PA10 +CN9_D3,PB3 +CN9_D4,PB5 +CN9_D5,PB4 +CN9_D6,PB10 +CN9_D7,PA8 +CN5_D8,PA9 +CN5_D9,PC7 +CN5_D10,PB6 +CN5_D11,PA7 +CN5_D12,PA6 +CN5_D13,PA5 +CN5_D14,PB9 +CN5_D15,PB8 +CN8_A0,PA0 +CN8_A1,PA1 +CN8_A2,PA4 +CN8_A3,PB0 +CN8_A4,PC1 +CN8_A5,PC0 +CN9_RX,PA3 +CN9_TX,PA2 +CN5_SCL,PB8 +CN5_SDA,PB9 +CN5_SCK,PA5 +CN5_MISO,PA6 +CN5_MOSI,PA7 +CN5_CS,PB6 +CN7_28,PA0 +CN7_30,PA1 +CN10_35,PA2 +CN10_37,PA3 +CN7_32,PA4 +CN10_11,PA5 +CN10_13,PA6 +CN10_15,PA7 +CN10_23,PA8 +CN10_21,PA9 +CN10_33,PA10 +CN10_14,PA11 +CN10_12,PA12 +CN7_13,PA13 +CN7_15,PA14 +CN7_17,PA15 +CN7_34,PB0 +CN10_24,PB1 +CN10_22,PB2 +CN10_31,PB3 +CN10_27,PB4 +CN10_29,PB5 +CN10_17,PB6 +CN7_21,PB7 +CN10_3,PB8 +CN10_5,PB9 +CN10_25,PB10 +CN10_18,PB11 +CN10_16,PB12 +CN10_30,PB13 +CN10_28,PB14 +CN10_26,PB15 +CN7_38,PC0 +CN7_36,PC1 +CN7_35,PC2 +CN7_37,PC3 +CN10_34,PC4 +CN10_6,PC5 +CN10_4,PC6 +CN10_19,PC7 +CN10_2,PC8 +CN10_1,PC9 +CN7_1,PC10 +CN7_2,PC11 +CN7_3,PC12 +CN7_23,PC13 +CN7_25,PC14 +CN7_27,PC15 +CN7_4,PD2 +CN7_29,PH0 +CN7_31,PH1 +BOOT0,PH3 +SWDIO,PA13 +SWCLK,PA14 +USER_B1,PC13 +LED_GREEN,PA5 diff --git a/ports/stm32/boards/NUCLEO_L452RE/stm32l4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_L452RE/stm32l4xx_hal_conf.h new file mode 100644 index 0000000000..fd380ab735 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_L452RE/stm32l4xx_hal_conf.h @@ -0,0 +1,20 @@ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32L4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32L4XX_HAL_CONF_H + +#include "boards/stm32l4xx_hal_conf_base.h" + +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define LSE_VALUE (32768) +#define EXTERNAL_SAI1_CLOCK_VALUE (48000) +#define EXTERNAL_SAI2_CLOCK_VALUE (48000) + +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) + +#endif // MICROPY_INCLUDED_STM32L4XX_HAL_CONF_H From d43dd886a5d072f49d5c27779199f3e233d6afb5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 9 Jul 2019 11:32:12 +1000 Subject: [PATCH 0530/1788] stm32/boards/NUCLEO_F413ZH: Remove STARTUP_FILE, it's defined globally. The Makefile now defines this variable to the correct value (but it can still be overridden by a board if necessary). --- ports/stm32/boards/NUCLEO_F413ZH/mpconfigboard.mk | 1 - 1 file changed, 1 deletion(-) diff --git a/ports/stm32/boards/NUCLEO_F413ZH/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F413ZH/mpconfigboard.mk index efc05dba84..7d8ea6bf6b 100644 --- a/ports/stm32/boards/NUCLEO_F413ZH/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_F413ZH/mpconfigboard.mk @@ -1,6 +1,5 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F413xx -STARTUP_FILE = boards/startup_stm32f413xx.o AF_FILE = boards/stm32f413_af.csv LD_FILES = boards/stm32f413xh.ld boards/common_ifs.ld TEXT0_ADDR = 0x08000000 From c8f19f13715ca201815a8594e32121ae06f504c5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 9 Jul 2019 11:33:57 +1000 Subject: [PATCH 0531/1788] stm32/mboot: Make _estack an array to avoid compiler warnings. The compiler can warn about out-of-bounds array access if _estack is just a single uint8_t. --- ports/stm32/mboot/mboot.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ports/stm32/mboot/mboot.h b/ports/stm32/mboot/mboot.h index 54b3dc7298..7dc1ada0c3 100644 --- a/ports/stm32/mboot/mboot.h +++ b/ports/stm32/mboot/mboot.h @@ -30,8 +30,9 @@ // Use this to tag global static data in RAM that doesn't need to be zeroed on startup #define SECTION_NOZERO_BSS __attribute__((section(".nozero_bss"))) -#define ELEM_DATA_START (&_estack) -#define ELEM_DATA_MAX (ELEM_DATA_START + 1024) +#define ELEM_DATA_SIZE (1024) +#define ELEM_DATA_START (&_estack[0]) +#define ELEM_DATA_MAX (&_estack[ELEM_DATA_SIZE]) enum { ELEM_TYPE_END = 1, @@ -48,7 +49,7 @@ typedef struct _fsload_bdev_t { uint32_t byte_len; } fsload_bdev_t; -extern uint8_t _estack; +extern uint8_t _estack[ELEM_DATA_SIZE]; uint32_t get_le32(const uint8_t *b); void led_state_all(unsigned int mask); From 5a81d2d6b895e538909ca5bc66adf39ed412c7f3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 9 Jul 2019 11:34:54 +1000 Subject: [PATCH 0532/1788] stm32/mboot: Remove use of BSRRL/H for H7 MCUs due to stm32lib update. --- ports/stm32/mboot/mphalport.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ports/stm32/mboot/mphalport.h b/ports/stm32/mboot/mphalport.h index 69ca0b035b..86063c4ef2 100644 --- a/ports/stm32/mboot/mphalport.h +++ b/ports/stm32/mboot/mphalport.h @@ -48,13 +48,8 @@ #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_low(p) (((GPIO_TypeDef*)((p) & ~0xf))->BSRRH = 1 << ((p) & 0xf)) -#define mp_hal_pin_high(p) (((GPIO_TypeDef*)((p) & ~0xf))->BSRRL = 1 << ((p) & 0xf)) -#else #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)) -#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) ((((GPIO_TypeDef*)((p) & ~0xf))->IDR >> ((p) & 0xf)) & 1) From 342539bdcce5b00b53e01423bc57782d65d5ff4b Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 9 Jul 2019 11:35:47 +1000 Subject: [PATCH 0533/1788] stm32/mboot: Use STARTUP_FILE from stm32lib. --- ports/stm32/mboot/Makefile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ports/stm32/mboot/Makefile b/ports/stm32/mboot/Makefile index 0a5759347f..689daed54a 100755 --- a/ports/stm32/mboot/Makefile +++ b/ports/stm32/mboot/Makefile @@ -20,8 +20,10 @@ endif include ../../../py/mkenv.mk include $(BOARD_DIR)/mpconfigboard.mk -CMSIS_DIR=$(TOP)/lib/stm32lib/CMSIS/STM32$(MCU_SERIES_UPPER)xx/Include MCU_SERIES_UPPER = $(shell echo $(MCU_SERIES) | tr '[:lower:]' '[:upper:]') +CMSIS_MCU_LOWER = $(shell echo $(CMSIS_MCU) | tr '[:upper:]' '[:lower:]') + +CMSIS_DIR=$(TOP)/lib/stm32lib/CMSIS/STM32$(MCU_SERIES_UPPER)xx/Include HAL_DIR=lib/stm32lib/STM32$(MCU_SERIES_UPPER)xx_HAL_Driver USBDEV_DIR=usbdev DFU=$(TOP)/tools/dfu.py @@ -30,6 +32,7 @@ DEVICE=0483:df11 STFLASH ?= st-flash OPENOCD ?= openocd OPENOCD_CONFIG ?= boards/openocd_stm32f4.cfg +STARTUP_FILE ?= lib/stm32lib/CMSIS/STM32$(MCU_SERIES_UPPER)xx/Source/Templates/gcc/startup_$(CMSIS_MCU_LOWER).o CROSS_COMPILE = arm-none-eabi- @@ -101,7 +104,7 @@ SRC_C = \ $(wildcard $(BOARD_DIR)/*.c) SRC_O = \ - ports/stm32/boards/startup_stm32$(MCU_SERIES).o \ + $(STARTUP_FILE) \ ports/stm32/resethandler.o \ $(BUILD)/$(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_ll_usb.o: CFLAGS += -Wno-attributes From 278e9bffe9e6acf9072a5428af0ba3e61896e7a5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 9 Jul 2019 11:46:47 +1000 Subject: [PATCH 0534/1788] stm32/mboot: Update dependencies to enable parallel build with -j. --- ports/stm32/mboot/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/mboot/Makefile b/ports/stm32/mboot/Makefile index 689daed54a..f2c3baecc1 100755 --- a/ports/stm32/mboot/Makefile +++ b/ports/stm32/mboot/Makefile @@ -178,7 +178,7 @@ GEN_PINS_AF_CONST = $(HEADER_BUILD)/pins_af_const.h GEN_PINS_AF_DEFS = $(HEADER_BUILD)/pins_af_defs.h GEN_PINS_AF_PY = $(BUILD)/pins_af.py -$(BUILD)/main.o: $(GEN_QSTRDEFS_GENERATED) $(GEN_PINS_AF_DEFS) +$(OBJ): $(GEN_QSTRDEFS_GENERATED) $(GEN_PINS_AF_DEFS) $(HEADER_BUILD): $(MKDIR) -p $(BUILD)/genhdr From 14f61a224dd138b48623f16ed5a56e6244c7bffe Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 9 Jul 2019 11:47:57 +1000 Subject: [PATCH 0535/1788] travis: Build stm32 mboot for PYBD_SF6 as part of CI. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 284d311f7e..0088fbe90d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,6 +39,7 @@ jobs: - make ${MAKEOPTS} -C ports/stm32 BOARD=PYBD_SF2 - make ${MAKEOPTS} -C ports/stm32 BOARD=STM32F769DISC - make ${MAKEOPTS} -C ports/stm32 BOARD=STM32L476DISC + - make ${MAKEOPTS} -C ports/stm32/mboot BOARD=PYBD_SF6 # qemu-arm port - stage: test From a17b901a9ea8f2dfe2db0822cdcd47b9c719a90a Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 9 Jul 2019 12:54:09 +1000 Subject: [PATCH 0536/1788] stm32/boards/B_L072Z_LRWAN1: Add definition files for new board. --- .../boards/B_L072Z_LRWAN1/mpconfigboard.h | 60 +++++++++++++++++++ .../boards/B_L072Z_LRWAN1/mpconfigboard.mk | 7 +++ ports/stm32/boards/B_L072Z_LRWAN1/pins.csv | 51 ++++++++++++++++ .../B_L072Z_LRWAN1/stm32l0xx_hal_conf.h | 18 ++++++ 4 files changed, 136 insertions(+) create mode 100644 ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.h create mode 100644 ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.mk create mode 100644 ports/stm32/boards/B_L072Z_LRWAN1/pins.csv create mode 100644 ports/stm32/boards/B_L072Z_LRWAN1/stm32l0xx_hal_conf.h diff --git a/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.h b/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.h new file mode 100644 index 0000000000..da219abd30 --- /dev/null +++ b/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.h @@ -0,0 +1,60 @@ +/* This file is part of the MicroPython project, http://micropython.org/ + * MIT License; Copyright (c) 2019 Damien P. George + */ + +#define MICROPY_HW_BOARD_NAME "B-L072Z-LRWAN1" +#define MICROPY_HW_MCU_NAME "STM32L072CZ" + +#define MICROPY_EMIT_THUMB (0) +#define MICROPY_EMIT_INLINE_THUMB (0) +#define MICROPY_PY_BUILTINS_COMPLEX (0) +#define MICROPY_PY_MATH (0) +#define MICROPY_PY_FRAMEBUF (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 (0) +#define MICROPY_HW_HAS_SWITCH (1) + +// UART config +#define MICROPY_HW_UART1_TX (pin_A9) +#define MICROPY_HW_UART1_RX (pin_A10) +#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) +#define MICROPY_HW_I2C1_SDA (pin_B9) + +// SPI busses +#define MICROPY_HW_SPI1_NSS (pin_A15) +#define MICROPY_HW_SPI1_SCK (pin_A5) +#define MICROPY_HW_SPI1_MISO (pin_A6) +#define MICROPY_HW_SPI1_MOSI (pin_A7) +#define MICROPY_HW_SPI2_NSS (pin_B12) +#define MICROPY_HW_SPI2_SCK (pin_B13) +#define MICROPY_HW_SPI2_MISO (pin_B14) +#define MICROPY_HW_SPI2_MOSI (pin_B15) + +// USER B1 has a pull-up and is active low +#define MICROPY_HW_USRSW_PIN (pin_B2) +#define MICROPY_HW_USRSW_PULL (0) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_FALLING) +#define MICROPY_HW_USRSW_PRESSED (0) + +// 4 user LEDs +#define MICROPY_HW_LED1 (pin_B5) // Green +#define MICROPY_HW_LED2 (pin_A5) // Green (next to power LED) +#define MICROPY_HW_LED3 (pin_B6) // Blue +#define MICROPY_HW_LED4 (pin_B7) // Red +#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/B_L072Z_LRWAN1/mpconfigboard.mk b/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.mk new file mode 100644 index 0000000000..a39a2bd47b --- /dev/null +++ b/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.mk @@ -0,0 +1,7 @@ +MCU_SERIES = l0 +CMSIS_MCU = STM32L072xx +AF_FILE = boards/stm32l072_af.csv +LD_FILES = boards/stm32l072xz.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/B_L072Z_LRWAN1/pins.csv b/ports/stm32/boards/B_L072Z_LRWAN1/pins.csv new file mode 100644 index 0000000000..e54b8b818a --- /dev/null +++ b/ports/stm32/boards/B_L072Z_LRWAN1/pins.csv @@ -0,0 +1,51 @@ +D0,PA3 +D1,PA2 +D2,PA10 +D3,PB13 +D4,PB5 +D5,PB7 +D6,PB2 +D7,PA8 +D8,PA9 +D9,PB12 +D10,PB6 +D11,PB15 +D12,PB14 +D13,PB13 +D14,PB9 +D15,PB8 +A0,PA0 +A2,PA4 +USER_B1,PB2 +LED2,PA5 +LED1,PB5 +LED3,PB6 +LED4,PB7 +LED_GREEN,PB5 +LED_BLUE,PB6 +LED_RED,PB7 +,PA0 +,PA2 +,PA3 +,PA4 +,PA5 +,PA6 +,PA7 +,PA8 +,PA9 +,PA10 +,PA11 +,PA12 +,PA13 +,PA14 +,PA15 +,PB2 +,PB5 +,PB6 +,PB7 +,PB8 +,PB9 +,PB12 +,PB13 +,PB14 +,PB15 diff --git a/ports/stm32/boards/B_L072Z_LRWAN1/stm32l0xx_hal_conf.h b/ports/stm32/boards/B_L072Z_LRWAN1/stm32l0xx_hal_conf.h new file mode 100644 index 0000000000..c88a706510 --- /dev/null +++ b/ports/stm32/boards/B_L072Z_LRWAN1/stm32l0xx_hal_conf.h @@ -0,0 +1,18 @@ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32L0XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32L0XX_HAL_CONF_H + +#include "boards/stm32l0xx_hal_conf_base.h" + +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define LSE_VALUE (32768) + +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) + +#endif // MICROPY_INCLUDED_STM32L0XX_HAL_CONF_H From 42d30c5bafc4d1d94787257eedf5c845423658f1 Mon Sep 17 00:00:00 2001 From: "Paul m. p. P" Date: Fri, 5 Jul 2019 12:06:16 +0200 Subject: [PATCH 0537/1788] unix/unix_mphal: Include time.h for CLOCK_MONOTONIC. --- ports/unix/unix_mphal.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/unix/unix_mphal.c b/ports/unix/unix_mphal.c index 71edaa57ac..9b009dc502 100644 --- a/ports/unix/unix_mphal.c +++ b/ports/unix/unix_mphal.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include "py/mphal.h" From a1c870e9f4562e1c1fd056653ff49efdda8bd840 Mon Sep 17 00:00:00 2001 From: "Paul m. p. P" Date: Mon, 8 Jul 2019 09:45:02 +0200 Subject: [PATCH 0538/1788] javascript: Enable support for frozen bytecode via FROZEN_MPY_DIR. --- ports/javascript/Makefile | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ports/javascript/Makefile b/ports/javascript/Makefile index 7309dfa481..384253e544 100644 --- a/ports/javascript/Makefile +++ b/ports/javascript/Makefile @@ -25,6 +25,13 @@ LDFLAGS = -m32 -Wl,-Map=$@.map,--cref -Wl,--gc-sections CFLAGS += -O0 -DNDEBUG CFLAGS += -fdata-sections -ffunction-sections +ifneq ($(FROZEN_MPY_DIR),) +# To use frozen bytecode, put your .py files in a subdirectory (eg frozen/) and +# then invoke make with FROZEN_MPY_DIR=frozen (be sure to build from scratch). +CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool +CFLAGS += -DMICROPY_MODULE_FROZEN_MPY +endif + SRC_LIB = $(addprefix lib/,\ utils/interrupt_char.c \ utils/stdout_helpers.c \ From a73859d5af7bc08356f69cb0ee677a0e80047148 Mon Sep 17 00:00:00 2001 From: Laurens Valk Date: Mon, 8 Jul 2019 13:07:34 +0200 Subject: [PATCH 0539/1788] py/objgenerator: Add missing #if guard for PY_GENERATOR_PEND_THROW. Without it, gen_instance_pend_throw_obj is defined but not used when MICROPY_PY_GENERATOR_PEND_THROW is set to 0. --- py/objgenerator.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/py/objgenerator.c b/py/objgenerator.c index 29c7cb16d0..b7186b8d0b 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -297,6 +297,7 @@ 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); +#if MICROPY_PY_GENERATOR_PEND_THROW 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) { @@ -307,6 +308,7 @@ STATIC mp_obj_t gen_instance_pend_throw(mp_obj_t self_in, mp_obj_t exc_in) { return prev; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(gen_instance_pend_throw_obj, gen_instance_pend_throw); +#endif 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) }, From fd49fcb229b6694d69d8f7646c7940e40b67a0cb Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 11 Jul 2019 17:32:01 +1000 Subject: [PATCH 0540/1788] stm32/gccollect: Always use MP_STATE_THREAD(stack_top) to get stack top. In a non-thread build, using &_ram_end as the top-of-stack is no longer correct because the stack is not always at the very top end of RAM. See eg 04c7cdb668cc7ee391ef5fe000f825389197f7e2 and 378659209778a1bde24e9b15793087023b02bbd9. The correct value to use is &_estack, which is the value stored in MP_STATE_THREAD(stack_top), and using the same code for both thread and non-thread builds makes the code cleaner. --- ports/stm32/gccollect.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ports/stm32/gccollect.c b/ports/stm32/gccollect.c index 5c1bf1e06d..f5a49b7d08 100644 --- a/ports/stm32/gccollect.c +++ b/ports/stm32/gccollect.c @@ -48,11 +48,7 @@ void gc_collect(void) { uintptr_t sp = gc_helper_get_regs_and_sp(regs); // trace the stack, including the registers (since they live on the stack in this function) - #if MICROPY_PY_THREAD gc_collect_root((void**)sp, ((uint32_t)MP_STATE_THREAD(stack_top) - sp) / sizeof(uint32_t)); - #else - gc_collect_root((void**)sp, ((uint32_t)&_ram_end - sp) / sizeof(uint32_t)); - #endif // trace root pointers from any threads #if MICROPY_PY_THREAD From d6e3038a080adb4024cec9bad89b4883487e12c0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 12 Jul 2019 12:57:37 +1000 Subject: [PATCH 0541/1788] ACKNOWLEDGEMENTS: Remove entry as requested by backer. --- ACKNOWLEDGEMENTS | 1 - 1 file changed, 1 deletion(-) diff --git a/ACKNOWLEDGEMENTS b/ACKNOWLEDGEMENTS index 65f731b1ff..41ed6bf24b 100644 --- a/ACKNOWLEDGEMENTS +++ b/ACKNOWLEDGEMENTS @@ -762,7 +762,6 @@ today. The names appear in order of pledging. 1642 Udine 1643 Simon Critchley 1644 Sven Haiges, Germany - 1645 Yi Qing Sim 1646 "silicium" ("silicium_one", if "silicium" is busy) 1648 Andy O'Malia, @andyomalia 1650 RedCamelApps.com From 82dc9856b06da89463e955abe2ee73a613718430 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 5 Jul 2019 15:42:33 -0500 Subject: [PATCH 0542/1788] py/asmarm: Use __builtin___clear_cache instead of __clear_cache. __clear_cache causes a compile error when using clang. Instead use __builtin___clear_cache which is available under both gcc and clang. Also replace tabs with spaces in this section of code (introduced by a previous commit). --- py/asmarm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/py/asmarm.c b/py/asmarm.c index 2a84f985ba..59c661cc04 100644 --- a/py/asmarm.c +++ b/py/asmarm.c @@ -41,9 +41,9 @@ void asm_arm_end_pass(asm_arm_t *as) { if (as->base.pass == MP_ASM_PASS_EMIT) { #if defined(__linux__) && defined(__GNUC__) - char *start = mp_asm_base_get_code(&as->base); - char *end = start + mp_asm_base_get_code_size(&as->base); - __clear_cache(start, end); + char *start = mp_asm_base_get_code(&as->base); + char *end = start + mp_asm_base_get_code_size(&as->base); + __builtin___clear_cache(start, end); #elif defined(__arm__) // flush I- and D-cache asm volatile( From 154062d9cb1eeb1b5f1fafa25959df16bd0b0b78 Mon Sep 17 00:00:00 2001 From: "Paul m. p. P" Date: Sun, 7 Jul 2019 02:48:01 +0200 Subject: [PATCH 0543/1788] py/makeqstrdata.py: Allow using \r\n as a qstr if a port requires it. --- py/makeqstrdata.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/py/makeqstrdata.py b/py/makeqstrdata.py index 060ebb7fd7..163b7fce75 100644 --- a/py/makeqstrdata.py +++ b/py/makeqstrdata.py @@ -279,9 +279,11 @@ def parse_input_headers(infiles): # get the qstr value qstr = match.group(1) - # special case to specify control characters + # special cases to specify control characters if qstr == '\\n': qstr = '\n' + elif qstr == '\\r\\n': + qstr = '\r\n' # work out the corresponding qstr name ident = qstr_escape(qstr) From f302f784e96f0b7daa019b282bdf66c1792eec34 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 16 Jul 2019 14:39:21 +1000 Subject: [PATCH 0544/1788] stm32/usb: Add config options to disable USB MSC and/or HID. The new configurations MICROPY_HW_USB_MSC and MICROPY_HW_USB_HID can be used by a board to enabled or disable MSC and/or HID. They are both enabled by default. --- ports/stm32/main.c | 9 ++- ports/stm32/modpyb.c | 4 +- ports/stm32/mpconfigboard_common.h | 8 +- ports/stm32/usb.c | 33 +++++++- ports/stm32/usbd_hid_interface.c | 4 + ports/stm32/usbd_msc_interface.c | 4 + .../stm32/usbdev/class/inc/usbd_cdc_msc_hid.h | 6 ++ .../stm32/usbdev/class/src/usbd_cdc_msc_hid.c | 81 +++++++++++++++++-- ports/stm32/usbdev/class/src/usbd_msc_bot.c | 4 + ports/stm32/usbdev/class/src/usbd_msc_scsi.c | 4 +- 10 files changed, 145 insertions(+), 12 deletions(-) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index c057814320..14ea4e644b 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -658,7 +658,14 @@ soft_reset: #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(pyb_usb_dev_detect(), USBD_VID, USBD_PID_CDC_MSC, USBD_MODE_CDC_MSC, 0, NULL, NULL); + #if MICROPY_HW_USB_MSC + const uint16_t pid = USBD_PID_CDC_MSC; + const uint8_t mode = USBD_MODE_CDC_MSC; + #else + const uint16_t pid = USBD_PID_CDC; + const uint8_t mode = USBD_MODE_CDC; + #endif + pyb_usb_dev_init(pyb_usb_dev_detect(), USBD_VID, pid, mode, 0, NULL, NULL); } #endif diff --git a/ports/stm32/modpyb.c b/ports/stm32/modpyb.c index c3e60caebb..139defc53b 100644 --- a/ports/stm32/modpyb.c +++ b/ports/stm32/modpyb.c @@ -161,10 +161,12 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { #if MICROPY_HW_ENABLE_USB { MP_ROM_QSTR(MP_QSTR_usb_mode), MP_ROM_PTR(&pyb_usb_mode_obj) }, + #if MICROPY_HW_USB_HID { 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) }, - { 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) }, + #endif + { MP_ROM_QSTR(MP_QSTR_USB_VCP), MP_ROM_PTR(&pyb_usb_vcp_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) }, diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index 94a86ca92a..63d4238020 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -273,10 +273,16 @@ #define MICROPY_HW_MAX_CAN (1) #endif -// Configure maximum number of CDC VCP interfaces +// Configure maximum number of CDC VCP interfaces, and whether MSC/HID are supported #ifndef MICROPY_HW_USB_CDC_NUM #define MICROPY_HW_USB_CDC_NUM (1) #endif +#ifndef MICROPY_HW_USB_MSC +#define MICROPY_HW_USB_MSC (MICROPY_HW_ENABLE_USB) +#endif +#ifndef MICROPY_HW_USB_HID +#define MICROPY_HW_USB_HID (MICROPY_HW_ENABLE_USB) +#endif // Pin definition header file #define MICROPY_PIN_DEFS_PORT_H "pin_defs_stm32.h" diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index 51e6e7a392..2d1f6084fe 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -67,12 +67,15 @@ 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[MICROPY_HW_USB_CDC_NUM]; + #if MICROPY_HW_USB_HID usbd_hid_itf_t usbd_hid_itf; + #endif } usb_device_t; usb_device_t usb_device = {0}; pyb_usb_storage_medium_t pyb_usb_storage_medium = PYB_USB_STORAGE_MEDIUM_NONE; +#if MICROPY_HW_USB_HID // predefined hid mouse data STATIC const mp_obj_str_t pyb_usb_hid_mouse_desc_obj = { {&mp_type_bytes}, @@ -110,6 +113,7 @@ const mp_rom_obj_tuple_t pyb_usb_hid_keyboard_obj = { MP_ROM_PTR(&pyb_usb_hid_keyboard_desc_obj), }, }; +#endif void pyb_usb_init0(void) { for (int i = 0; i < MICROPY_HW_USB_CDC_NUM; ++i) { @@ -160,7 +164,9 @@ bool pyb_usb_dev_init(int dev_id, uint16_t vid, uint16_t pid, uint8_t mode, size for (int i = 0; i < MICROPY_HW_USB_CDC_NUM; ++i) { usb_dev->usbd_cdc_msc_hid_state.cdc[i] = &usb_dev->usbd_cdc_itf[i].base; } + #if MICROPY_HW_USB_HID usb_dev->usbd_cdc_msc_hid_state.hid = &usb_dev->usbd_hid_itf.base; + #endif usbd->pClassData = &usb_dev->usbd_cdc_msc_hid_state; // configure the VID, PID and the USBD mode (interfaces it will expose) @@ -170,6 +176,7 @@ bool pyb_usb_dev_init(int dev_id, uint16_t vid, uint16_t pid, uint8_t mode, size return false; } + #if MICROPY_HW_USB_MSC // Configure the MSC interface const void *msc_unit_default[1]; if (msc_n == 0) { @@ -188,6 +195,7 @@ bool pyb_usb_dev_init(int dev_id, uint16_t vid, uint16_t pid, uint8_t mode, size } usbd_msc_init_lu(msc_n, msc_unit); USBD_MSC_RegisterStorage(&usb_dev->usbd_cdc_msc_hid_state, (USBD_StorageTypeDef*)&usbd_msc_fops); + #endif // start the USB device USBD_LL_Init(usbd, (mode & USBD_MODE_HIGH_SPEED) != 0); @@ -255,14 +263,29 @@ usbd_cdc_itf_t *usb_vcp_get(int idx) { */ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_mode, ARG_port, ARG_vid, ARG_pid, ARG_msc, ARG_hid, ARG_high_speed }; + enum { + ARG_mode, ARG_port, ARG_vid, ARG_pid, + #if MICROPY_HW_USB_MSC + ARG_msc, + #endif + #if MICROPY_HW_USB_HID + ARG_hid, + #endif + #if USBD_SUPPORT_HS_MODE + ARG_high_speed + #endif + }; static const mp_arg_t allowed_args[] = { { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, { MP_QSTR_port, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, { 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} }, + #if MICROPY_HW_USB_MSC { MP_QSTR_msc, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_empty_tuple_obj)} }, + #endif + #if MICROPY_HW_USB_HID { MP_QSTR_hid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&pyb_usb_hid_mouse_obj)} }, + #endif #if USBD_SUPPORT_HS_MODE { MP_QSTR_high_speed, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, #endif @@ -381,6 +404,7 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * // Get MSC logical units size_t msc_n = 0; const void *msc_unit[USBD_MSC_MAX_LUN]; + #if MICROPY_HW_USB_MSC if (mode & USBD_MODE_IFACE_MSC) { mp_obj_t *items; mp_obj_get_array(args[ARG_msc].u_obj, &msc_n, &items); @@ -403,9 +427,11 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * } } } + #endif // get hid info if user selected such a mode USBD_HID_ModeInfoTypeDef hid_info; + #if MICROPY_HW_USB_HID if (mode & USBD_MODE_IFACE_HID) { mp_obj_t *items; mp_obj_get_array_fixed_n(args[ARG_hid].u_obj, 5, &items); @@ -421,6 +447,7 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * // need to keep a copy of this so report_desc does not get GC'd MP_STATE_PORT(pyb_hid_report_desc) = items[4]; } + #endif #if USBD_SUPPORT_HS_MODE if (args[ARG_high_speed].u_bool) { @@ -713,6 +740,8 @@ const mp_obj_type_t pyb_usb_vcp_type = { /******************************************************************************/ // MicroPython bindings for USB HID +#if MICROPY_HW_USB_HID + typedef struct _pyb_usb_hid_obj_t { mp_obj_base_t base; usb_device_t *usb_dev; @@ -841,6 +870,8 @@ const mp_obj_type_t pyb_usb_hid_type = { .locals_dict = (mp_obj_dict_t*)&pyb_usb_hid_locals_dict, }; +#endif // MICROPY_HW_USB_HID + /******************************************************************************/ // code for experimental USB OTG support diff --git a/ports/stm32/usbd_hid_interface.c b/ports/stm32/usbd_hid_interface.c index 3ffc0b425d..033d83ea64 100644 --- a/ports/stm32/usbd_hid_interface.c +++ b/ports/stm32/usbd_hid_interface.c @@ -42,6 +42,8 @@ #include "irq.h" #include "usb.h" +#if MICROPY_HW_USB_HID + uint8_t *usbd_hid_init(usbd_hid_state_t *hid_in) { usbd_hid_itf_t *hid = (usbd_hid_itf_t*)hid_in; @@ -107,3 +109,5 @@ int usbd_hid_rx(usbd_hid_itf_t *hid, size_t len, uint8_t *buf, uint32_t timeout) // Success, return number of bytes read return read_len; } + +#endif // MICROPY_HW_USB_HID diff --git a/ports/stm32/usbd_msc_interface.c b/ports/stm32/usbd_msc_interface.c index aa2b381a09..7f563004b8 100644 --- a/ports/stm32/usbd_msc_interface.c +++ b/ports/stm32/usbd_msc_interface.c @@ -33,6 +33,8 @@ #include "storage.h" #include "sdcard.h" +#if MICROPY_HW_USB_MSC + // This flag is needed to support removal of the medium, so that the USB drive // can be unmounted and won't be remounted automatically. #define FLAGS_STARTED (0x01) @@ -342,3 +344,5 @@ const USBD_StorageTypeDef usbd_msc_fops = { usbd_msc_Write, usbd_msc_GetMaxLun, }; + +#endif // MICROPY_HW_USB_MSC 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 c41908d25b..a01e75bed5 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h @@ -120,7 +120,9 @@ typedef struct _usbd_cdc_msc_hid_state_t { uint8_t usbd_mode; uint8_t usbd_config_desc_size; + #if MICROPY_HW_USB_MSC USBD_MSC_BOT_HandleTypeDef MSC_BOT_ClassData; + #endif // 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; @@ -128,7 +130,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[MICROPY_HW_USB_CDC_NUM]; + #if MICROPY_HW_USB_HID usbd_hid_state_t *hid; + #endif } usbd_cdc_msc_hid_state_t; extern const uint8_t USBD_MSC_Mode_Sense6_Data[4]; @@ -176,9 +180,11 @@ uint8_t USBD_GetMode(usbd_cdc_msc_hid_state_t *usbd); 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); +#if MICROPY_HW_USB_MSC static inline void USBD_MSC_RegisterStorage(usbd_cdc_msc_hid_state_t *usbd, USBD_StorageTypeDef *fops) { usbd->MSC_BOT_ClassData.bdev_ops = fops; } +#endif uint8_t USBD_HID_ReceivePacket(usbd_hid_state_t *usbd, uint8_t *buf); int USBD_HID_CanSendReport(usbd_hid_state_t *usbd); 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 627fb054c0..32ce4ca875 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -148,6 +148,7 @@ static const uint8_t head_desc_data[HEAD_DESC_SIZE] = { CONFIG_DESC_MAXPOWER, // bMaxPower }; +#if MICROPY_HW_USB_MSC // USB MSC partial configuration descriptor static const uint8_t msc_class_desc_data[MSC_CLASS_DESC_SIZE] = { //========================================================================== @@ -183,6 +184,7 @@ static const uint8_t msc_class_desc_data[MSC_CLASS_DESC_SIZE] = { HIBYTE(MSC_FS_MAX_PACKET), 0x00, // bInterval: ignore for Bulk transfer }; +#endif // USB CDC partial configuration descriptor static const uint8_t cdc_class_desc_data[CDC_CLASS_DESC_SIZE] = { @@ -276,6 +278,7 @@ static const uint8_t cdc_class_desc_data[CDC_CLASS_DESC_SIZE] = { 0x00, // bInterval: ignore for Bulk transfer }; +#if MICROPY_HW_USB_HID // USB HID partial configuration descriptor static const uint8_t hid_class_desc_data[HID_CLASS_DESC_SIZE] = { //========================================================================== @@ -399,6 +402,7 @@ __ALIGN_BEGIN const uint8_t USBD_HID_KEYBOARD_ReportDesc[USBD_HID_KEYBOARD_REPOR 0x81, 0x00, // Input (Data, Array), ;Key arrays (6 bytes) 0xC0 // End Collection }; +#endif static void make_head_desc(uint8_t *dest, uint16_t len, uint8_t num_itf) { memcpy(dest, head_desc_data, sizeof(head_desc_data)); @@ -407,10 +411,12 @@ static void make_head_desc(uint8_t *dest, uint16_t len, uint8_t num_itf) { dest[4] = num_itf; // bNumInterfaces } +#if MICROPY_HW_USB_MSC static size_t make_msc_desc(uint8_t *dest) { memcpy(dest, msc_class_desc_data, sizeof(msc_class_desc_data)); return sizeof(msc_class_desc_data); } +#endif static size_t make_cdc_desc(uint8_t *dest, int need_iad, uint8_t iface_num) { if (need_iad) { @@ -441,6 +447,7 @@ static size_t make_cdc_desc_ep(uint8_t *dest, int need_iad, uint8_t iface_num, u } #endif +#if MICROPY_HW_USB_HID static size_t make_hid_desc(uint8_t *dest, USBD_HID_ModeInfoTypeDef *hid_info) { memcpy(dest, hid_class_desc_data, sizeof(hid_class_desc_data)); dest[HID_DESC_OFFSET_SUBCLASS] = hid_info->subclass; @@ -454,6 +461,7 @@ static size_t make_hid_desc(uint8_t *dest, USBD_HID_ModeInfoTypeDef *hid_info) { dest[HID_DESC_OFFSET_POLLING_INTERVAL_OUT] = hid_info->polling_interval; return sizeof(hid_class_desc_data); } +#endif // return the saved usb mode uint8_t USBD_GetMode(usbd_cdc_msc_hid_state_t *usbd) { @@ -469,6 +477,7 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode uint8_t *d = usbd->usbd_config_desc; uint8_t num_itf = 0; switch (usbd->usbd_mode & USBD_MODE_IFACE_MASK) { + #if MICROPY_HW_USB_MSC case USBD_MODE_MSC: n += make_msc_desc(d + n); num_itf = 1; @@ -480,6 +489,7 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode usbd->cdc[0]->iface_num = CDC_IFACE_NUM_WITH_MSC; num_itf = 3; break; + #endif #if MICROPY_HW_USB_CDC_NUM >= 2 case USBD_MODE_CDC2: { @@ -491,6 +501,7 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode break; } + #if MICROPY_HW_USB_MSC case USBD_MODE_CDC2_MSC: { n += make_msc_desc(d + n); n += make_cdc_desc(d + n, 1, CDC_IFACE_NUM_WITH_MSC); @@ -501,6 +512,7 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode break; } #endif + #endif #if MICROPY_HW_USB_CDC_NUM >= 3 case USBD_MODE_CDC3: { @@ -514,6 +526,7 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode break; } + #if MICROPY_HW_USB_MSC case USBD_MODE_CDC3_MSC: { n += make_msc_desc(d + n); n += make_cdc_desc(d + n, 1, CDC_IFACE_NUM_WITH_MSC); @@ -526,7 +539,9 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode break; } #endif + #endif + #if MICROPY_HW_USB_HID case USBD_MODE_CDC_HID: usbd->hid->desc = d + n; n += make_hid_desc(d + n, hid_info); @@ -538,6 +553,7 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode usbd->hid->report_desc = hid_info->report_desc; num_itf = 3; break; + #endif case USBD_MODE_CDC: n += make_cdc_desc(d + n, 0, CDC_IFACE_NUM_ALONE); @@ -609,6 +625,7 @@ static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { } } + #if MICROPY_HW_USB_MSC if (usbd->usbd_mode & USBD_MODE_IFACE_MSC) { // MSC component @@ -629,7 +646,9 @@ static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { // Init the BOT layer MSC_BOT_Init(pdev); } + #endif + #if MICROPY_HW_USB_HID if (usbd->usbd_mode & USBD_MODE_IFACE_HID) { // HID component @@ -656,6 +675,7 @@ static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { usbd->hid->state = HID_IDLE; } + #endif return 0; } @@ -676,6 +696,7 @@ static uint8_t USBD_CDC_MSC_HID_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx) } } + #if MICROPY_HW_USB_MSC if (usbd->usbd_mode & USBD_MODE_IFACE_MSC) { // MSC component @@ -686,7 +707,9 @@ static uint8_t USBD_CDC_MSC_HID_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx) // DeInit the BOT layer MSC_BOT_DeInit(pdev); } + #endif + #if MICROPY_HW_USB_HID if (usbd->usbd_mode & USBD_MODE_IFACE_HID) { // HID component @@ -694,6 +717,7 @@ static uint8_t USBD_CDC_MSC_HID_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx) USBD_LL_CloseEP(pdev, usbd->hid->in_ep); USBD_LL_CloseEP(pdev, usbd->hid->out_ep); } + #endif return 0; } @@ -725,11 +749,17 @@ 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 MICROPY_HW_USB_MSC if ((mode & USBD_MODE_IFACE_MSC) && iface == MSC_IFACE_NUM_WITH_CDC) { recipient = USBD_MODE_MSC; - } else if ((mode & USBD_MODE_IFACE_HID) && iface == usbd->hid->iface_num) { + } else + #endif + #if MICROPY_HW_USB_HID + if ((mode & USBD_MODE_IFACE_HID) && iface == usbd->hid->iface_num) { recipient = USBD_MODE_HID; - } else { + } else + #endif + { for (int i = 0; i < MICROPY_HW_USB_CDC_NUM; ++i) { if ((mode & USBD_MODE_IFACE_CDC(i)) && iface == usbd->cdc[i]->iface_num) { recipient = USBD_MODE_CDC; @@ -742,11 +772,17 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp } case USB_REQ_RECIPIENT_ENDPOINT: { uint8_t ep = req->wIndex & 0x7f; + #if MICROPY_HW_USB_MSC if ((mode & USBD_MODE_IFACE_MSC) && ep == MSC_OUT_EP) { recipient = USBD_MODE_MSC; - } else if ((mode & USBD_MODE_IFACE_HID) && ep == usbd->hid->out_ep) { + } else + #endif + #if MICROPY_HW_USB_HID + if ((mode & USBD_MODE_IFACE_HID) && ep == usbd->hid->out_ep) { recipient = USBD_MODE_HID; - } else { + } else + #endif + { for (int i = 0; i < MICROPY_HW_USB_CDC_NUM; ++i) { if ((mode & USBD_MODE_IFACE_CDC(i)) && (ep == CDC_OUT_EP(i) || ep == (CDC_CMD_EP(i) & 0x7f))) { recipient = USBD_MODE_CDC; @@ -786,7 +822,9 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp // Transfer the command to the interface layer return usbd_cdc_control(cdc, req->bRequest, NULL, req->wValue); } - } else if (recipient == USBD_MODE_MSC) { + } + #if MICROPY_HW_USB_MSC + if (recipient == USBD_MODE_MSC) { switch (req->bRequest) { case BOT_GET_MAX_LUN: if ((req->wValue == 0) && (req->wLength == 1) && ((req->bmRequest & 0x80) == 0x80)) { @@ -811,7 +849,10 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp USBD_CtlError(pdev, req); return USBD_FAIL; } - } else if (recipient == USBD_MODE_HID) { + } + #endif + #if MICROPY_HW_USB_HID + if (recipient == USBD_MODE_HID) { switch (req->bRequest) { case HID_REQ_SET_PROTOCOL: usbd->hid->ctl_protocol = (uint8_t)(req->wValue); @@ -834,9 +875,11 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp return USBD_FAIL; } } + #endif break; case USB_REQ_TYPE_STANDARD: + #if MICROPY_HW_USB_MSC if (recipient == USBD_MODE_MSC) { switch (req->bRequest) { case USB_REQ_GET_INTERFACE : @@ -864,7 +907,10 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp MSC_BOT_CplClrFeature(pdev, (uint8_t)req->wIndex); break; } - } else if (recipient == USBD_MODE_HID) { + } + #endif + #if MICROPY_HW_USB_HID + if (recipient == USBD_MODE_HID) { switch (req->bRequest) { case USB_REQ_GET_DESCRIPTOR: { uint16_t len = 0; @@ -890,6 +936,7 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp break; } } + #endif break; } return USBD_OK; @@ -922,17 +969,21 @@ static uint8_t USBD_CDC_MSC_HID_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum) } } + #if MICROPY_HW_USB_MSC if ((usbd->usbd_mode & USBD_MODE_IFACE_MSC) && epnum == (MSC_IN_EP & 0x7f)) { MSC_BOT_DataIn(pdev, epnum); return USBD_OK; } + #endif + #if MICROPY_HW_USB_HID if ((usbd->usbd_mode & USBD_MODE_IFACE_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->state = HID_IDLE; return USBD_OK; } + #endif return USBD_OK; } @@ -948,15 +999,19 @@ static uint8_t USBD_CDC_MSC_HID_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) } } + #if MICROPY_HW_USB_MSC if ((usbd->usbd_mode & USBD_MODE_IFACE_MSC) && epnum == (MSC_OUT_EP & 0x7f)) { MSC_BOT_DataOut(pdev, epnum); return USBD_OK; } + #endif + #if MICROPY_HW_USB_HID if ((usbd->usbd_mode & USBD_MODE_IFACE_HID) && epnum == (usbd->hid->out_ep & 0x7f)) { size_t len = USBD_LL_GetRxDataSize(pdev, epnum); return usbd_hid_receive(usbd->hid, len); } + #endif return USBD_OK; } @@ -985,6 +1040,7 @@ static uint8_t *USBD_CDC_MSC_HID_GetCfgDesc(USBD_HandleTypeDef *pdev, uint16_t * uint8_t *cdc_desc[MICROPY_HW_USB_CDC_NUM] = {0}; uint8_t *msc_desc = NULL; switch (usbd->usbd_mode & USBD_MODE_IFACE_MASK) { + #if MICROPY_HW_USB_MSC case USBD_MODE_MSC: msc_desc = usbd->usbd_config_desc + MSC_TEMPLATE_MSC_DESC_OFFSET; break; @@ -993,6 +1049,7 @@ static uint8_t *USBD_CDC_MSC_HID_GetCfgDesc(USBD_HandleTypeDef *pdev, uint16_t * cdc_desc[0] = usbd->usbd_config_desc + CDC_MSC_TEMPLATE_CDC_DESC_OFFSET; msc_desc = usbd->usbd_config_desc + CDC_MSC_TEMPLATE_MSC_DESC_OFFSET; break; + #endif #if MICROPY_HW_USB_CDC_NUM >= 2 case USBD_MODE_CDC2: @@ -1000,12 +1057,14 @@ static uint8_t *USBD_CDC_MSC_HID_GetCfgDesc(USBD_HandleTypeDef *pdev, uint16_t * cdc_desc[1] = usbd->usbd_config_desc + CDC2_TEMPLATE_CDC2_DESC_OFFSET; break; + #if MICROPY_HW_USB_MSC case USBD_MODE_CDC2_MSC: cdc_desc[0] = usbd->usbd_config_desc + CDC2_MSC_TEMPLATE_CDC_DESC_OFFSET; cdc_desc[1] = usbd->usbd_config_desc + CDC2_MSC_TEMPLATE_CDC2_DESC_OFFSET; msc_desc = usbd->usbd_config_desc + CDC2_MSC_TEMPLATE_MSC_DESC_OFFSET; break; #endif + #endif #if MICROPY_HW_USB_CDC_NUM >= 3 case USBD_MODE_CDC3: @@ -1014,6 +1073,7 @@ static uint8_t *USBD_CDC_MSC_HID_GetCfgDesc(USBD_HandleTypeDef *pdev, uint16_t * cdc_desc[2] = usbd->usbd_config_desc + CDC3_TEMPLATE_CDC3_DESC_OFFSET; break; + #if MICROPY_HW_USB_MSC case USBD_MODE_CDC3_MSC: cdc_desc[0] = usbd->usbd_config_desc + CDC3_MSC_TEMPLATE_CDC_DESC_OFFSET; cdc_desc[1] = usbd->usbd_config_desc + CDC3_MSC_TEMPLATE_CDC2_DESC_OFFSET; @@ -1021,10 +1081,13 @@ static uint8_t *USBD_CDC_MSC_HID_GetCfgDesc(USBD_HandleTypeDef *pdev, uint16_t * msc_desc = usbd->usbd_config_desc + CDC3_MSC_TEMPLATE_MSC_DESC_OFFSET; break; #endif + #endif + #if MICROPY_HW_USB_HID case USBD_MODE_CDC_HID: cdc_desc[0] = usbd->usbd_config_desc + CDC_HID_TEMPLATE_CDC_DESC_OFFSET; break; + #endif case USBD_MODE_CDC: cdc_desc[0] = usbd->usbd_config_desc + CDC_TEMPLATE_CDC_DESC_OFFSET; @@ -1091,6 +1154,8 @@ uint8_t USBD_CDC_ReceivePacket(usbd_cdc_state_t *cdc, uint8_t *buf) { return USBD_OK; } +#if MICROPY_HW_USB_HID + // prepare OUT endpoint for reception uint8_t USBD_HID_ReceivePacket(usbd_hid_state_t *hid, uint8_t *buf) { // Suspend or Resume USB Out process @@ -1149,6 +1214,8 @@ uint8_t USBD_HID_ClearNAK(usbd_hid_state_t *hid) { return USBD_OK; } +#endif + // CDC/MSC/HID interface class callback structure const USBD_ClassTypeDef USBD_CDC_MSC_HID = { USBD_CDC_MSC_HID_Init, diff --git a/ports/stm32/usbdev/class/src/usbd_msc_bot.c b/ports/stm32/usbdev/class/src/usbd_msc_bot.c index d20f7a8dc0..44a74a6602 100644 --- a/ports/stm32/usbdev/class/src/usbd_msc_bot.c +++ b/ports/stm32/usbdev/class/src/usbd_msc_bot.c @@ -31,6 +31,8 @@ #include "usbd_cdc_msc_hid.h" #include "usbd_ioreq.h" +#if MICROPY_HW_USB_MSC + /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ */ @@ -404,4 +406,6 @@ void MSC_BOT_CplClrFeature (USBD_HandleTypeDef *pdev, uint8_t epnum) * @} */ +#endif // MICROPY_HW_USB_MSC + /************************ (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 26556bb48e..d0413b758a 100644 --- a/ports/stm32/usbdev/class/src/usbd_msc_scsi.c +++ b/ports/stm32/usbdev/class/src/usbd_msc_scsi.c @@ -30,7 +30,7 @@ #include "usbd_msc_scsi.h" #include "usbd_cdc_msc_hid.h" - +#if MICROPY_HW_USB_MSC /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ @@ -789,4 +789,6 @@ static int8_t SCSI_ProcessWrite (USBD_HandleTypeDef *pdev, uint8_t lun) * @} */ +#endif // MICROPY_HW_USB_MSC + /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ From 788e7f50f246a7e7641217cef147ca04fd3c3ed2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 16 Jul 2019 14:41:59 +1000 Subject: [PATCH 0545/1788] stm32/usbd_cdc_interface: Make CDC TX/RX buffer sizes configurable. --- ports/stm32/usbd_cdc_interface.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/stm32/usbd_cdc_interface.h b/ports/stm32/usbd_cdc_interface.h index 780d4816e8..a48516b1f6 100644 --- a/ports/stm32/usbd_cdc_interface.h +++ b/ports/stm32/usbd_cdc_interface.h @@ -31,8 +31,12 @@ ****************************************************************************** */ +#ifndef USBD_CDC_RX_DATA_SIZE #define USBD_CDC_RX_DATA_SIZE (1024) // this must be 2 or greater, and a power of 2 +#endif +#ifndef USBD_CDC_TX_DATA_SIZE #define USBD_CDC_TX_DATA_SIZE (1024) // I think this can be any value (was 2048) +#endif // Values for connect_state #define USBD_CDC_CONNECT_STATE_DISCONNECTED (0) From 4c1ad1f69160e2bb9fe683a72abba444a25d8d4f Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 16 Jul 2019 14:45:53 +1000 Subject: [PATCH 0546/1788] stm32: Add support for USB on L0 MCUs. --- ports/stm32/Makefile | 7 +++++- ports/stm32/irq.h | 11 +++++++++ ports/stm32/powerctrlboot.c | 21 ++++++++++++++++ ports/stm32/stm32_it.c | 12 +++++++++ ports/stm32/usbd_cdc_interface.c | 13 +++++++--- ports/stm32/usbd_conf.c | 42 ++++++++++++++++++++++++++++++-- 6 files changed, 100 insertions(+), 6 deletions(-) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 84ce01e8f9..d2ca4122a1 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -331,12 +331,17 @@ SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ hal_uart.c \ ) +ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 h7 l0 l4)) +SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ + ll_usb.c \ + ) +endif + 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_fmc.c \ - ll_usb.c \ ) endif diff --git a/ports/stm32/irq.h b/ports/stm32/irq.h index 075791357c..78ba46ced4 100644 --- a/ports/stm32/irq.h +++ b/ports/stm32/irq.h @@ -79,6 +79,17 @@ static inline void restore_irq_pri(uint32_t basepri) { __set_BASEPRI(basepri); } +#else + +static inline uint32_t raise_irq_pri(uint32_t pri) { + return disable_irq(); +} + +// "state" should be the value returned from raise_irq_pri +static inline void restore_irq_pri(uint32_t state) { + enable_irq(state); +} + #endif MP_DECLARE_CONST_FUN_OBJ_0(pyb_wfi_obj); diff --git a/ports/stm32/powerctrlboot.c b/ports/stm32/powerctrlboot.c index 527118ba88..e320cc4db1 100644 --- a/ports/stm32/powerctrlboot.c +++ b/ports/stm32/powerctrlboot.c @@ -98,6 +98,27 @@ void SystemClock_Config(void) { HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000); HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); + + #if MICROPY_HW_ENABLE_RNG || MICROPY_HW_ENABLE_USB + // Enable the 48MHz internal oscillator + RCC->CRRCR |= RCC_CRRCR_HSI48ON; + RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; + SYSCFG->CFGR3 |= SYSCFG_CFGR3_ENREF_HSI48; + while (!(RCC->CRRCR & RCC_CRRCR_HSI48RDY)) { + // Wait for HSI48 to be ready + } + + // Select RC48 as HSI48 for USB and RNG + RCC->CCIPR |= RCC_CCIPR_HSI48SEL; + + #if MICROPY_HW_ENABLE_USB + // Synchronise HSI48 with 1kHz USB SoF + __HAL_RCC_CRS_CLK_ENABLE(); + CRS->CR = 0x20 << CRS_CR_TRIM_Pos; + CRS->CFGR = 2 << CRS_CFGR_SYNCSRC_Pos | 0x22 << CRS_CFGR_FELIM_Pos + | __HAL_RCC_CRS_RELOADVALUE_CALCULATE(48000000, 1000) << CRS_CFGR_RELOAD_Pos; + #endif + #endif } #endif diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index fd3aea6c1c..1e2712b05f 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -298,6 +298,16 @@ void DebugMon_Handler(void) { /* file (startup_stm32f4xx.s). */ /******************************************************************************/ +#if defined(STM32L0) + +#if MICROPY_HW_USB_FS +void USB_IRQHandler(void) { + HAL_PCD_IRQHandler(&pcd_fs_handle); +} +#endif + +#else + /** * @brief This function handles USB-On-The-Go FS global interrupt request. * @param None @@ -405,6 +415,8 @@ void OTG_HS_WKUP_IRQHandler(void) { } #endif +#endif // !defined(STM32L0) + /** * @brief This function handles PPP interrupt request. * @param None diff --git a/ports/stm32/usbd_cdc_interface.c b/ports/stm32/usbd_cdc_interface.c index 49f0deec71..b27ea51d87 100644 --- a/ports/stm32/usbd_cdc_interface.c +++ b/ports/stm32/usbd_cdc_interface.c @@ -140,11 +140,14 @@ int8_t usbd_cdc_control(usbd_cdc_state_t *cdc_in, uint8_t cmd, uint8_t* pbuf, ui if (length & 1) { // The actual connection state is delayed to give the host a chance to // configure its serial port (in most cases to disable local echo) - PCD_HandleTypeDef *hpcd = cdc->base.usbd->pdev->pData; - USB_OTG_GlobalTypeDef *USBx = hpcd->Instance; cdc->connect_state = USBD_CDC_CONNECT_STATE_CONNECTING; usbd_cdc_connect_tx_timer = 8; // wait for 8 SOF IRQs - USBx->GINTMSK |= USB_OTG_GINTMSK_SOFM; + #if defined(STM32L0) + USB->CNTR |= USB_CNTR_SOFM; + #else + PCD_HandleTypeDef *hpcd = cdc->base.usbd->pdev->pData; + hpcd->Instance->GINTMSK |= USB_OTG_GINTMSK_SOFM; + #endif } else { cdc->connect_state = USBD_CDC_CONNECT_STATE_DISCONNECTED; } @@ -216,7 +219,11 @@ void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) { --usbd_cdc_connect_tx_timer; } else { usbd_cdc_msc_hid_state_t *usbd = ((USBD_HandleTypeDef*)hpcd->pData)->pClassData; + #if defined(STM32L0) + USB->CNTR &= ~USB_CNTR_SOFM; + #else hpcd->Instance->GINTMSK &= ~USB_OTG_GINTMSK_SOFM; + #endif for (int i = 0; i < MICROPY_HW_USB_CDC_NUM; ++i) { usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t*)usbd->cdc[i]; if (cdc->connect_state == USBD_CDC_CONNECT_STATE_CONNECTING) { diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c index ed99700e99..8e62a9cc8c 100644 --- a/ports/stm32/usbd_conf.c +++ b/ports/stm32/usbd_conf.c @@ -44,6 +44,11 @@ PCD_HandleTypeDef pcd_fs_handle; PCD_HandleTypeDef pcd_hs_handle; #endif +#if defined(STM32L0) +// The STM32L0xx has a single USB device-only instance +#define USB_OTG_FS USB +#endif + /******************************************************************************* PCD BSP Routines *******************************************************************************/ @@ -57,6 +62,8 @@ 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; + #elif defined(STM32L0) + const uint32_t otg_alt = GPIO_AF0_USB; #else const uint32_t otg_alt = GPIO_AF10_OTG_FS; #endif @@ -83,7 +90,11 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) { #endif // Enable USB FS Clocks + #if defined(STM32L0) + __HAL_RCC_USB_CLK_ENABLE(); + #else __USB_OTG_FS_CLK_ENABLE(); + #endif #if defined(STM32L4) // Enable VDDUSB @@ -97,8 +108,13 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) { #endif // Configure and enable USB FS interrupt + #if defined(STM32L0) + NVIC_SetPriority(USB_IRQn, IRQ_PRI_OTG_FS); + HAL_NVIC_EnableIRQ(USB_IRQn); + #else NVIC_SetPriority(OTG_FS_IRQn, IRQ_PRI_OTG_FS); HAL_NVIC_EnableIRQ(OTG_FS_IRQn); + #endif } #if MICROPY_HW_USB_HS else if (hpcd->Instance == USB_OTG_HS) { @@ -174,6 +190,10 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) { * @retval None */ void HAL_PCD_MspDeInit(PCD_HandleTypeDef *hpcd) { + #if defined(STM32L0) + __HAL_RCC_USB_CLK_DISABLE(); + #else + if (hpcd->Instance == USB_OTG_FS) { /* Disable USB FS Clocks */ __USB_OTG_FS_CLK_DISABLE(); @@ -186,6 +206,8 @@ void HAL_PCD_MspDeInit(PCD_HandleTypeDef *hpcd) { __SYSCFG_CLK_DISABLE(); } #endif + + #endif } /******************************************************************************* @@ -339,9 +361,7 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { #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; pcd_fs_handle.Init.low_power_enable = 0; pcd_fs_handle.Init.phy_itface = PCD_PHY_EMBEDDED; pcd_fs_handle.Init.Sof_enable = 0; @@ -350,11 +370,15 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { pcd_fs_handle.Init.lpm_enable = DISABLE; pcd_fs_handle.Init.battery_charging_enable = DISABLE; #endif + #if !defined(STM32L0) + pcd_fs_handle.Init.use_dedicated_ep1 = 0; + pcd_fs_handle.Init.dma_enable = 0; #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 + #endif // Link The driver to the stack pcd_fs_handle.pData = pdev; @@ -363,6 +387,18 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { // Initialize LL Driver HAL_PCD_Init(&pcd_fs_handle); + #if defined(STM32L0) + // We have 512 16-bit words it total to use here (when using PCD_SNG_BUF) + HAL_PCDEx_PMAConfig(&pcd_fs_handle, 0x00, PCD_SNG_BUF, 64); // EP0 + HAL_PCDEx_PMAConfig(&pcd_fs_handle, 0x80, PCD_SNG_BUF, 128); // EP0 + HAL_PCDEx_PMAConfig(&pcd_fs_handle, 0x01, PCD_SNG_BUF, 192); // MSC / HID + HAL_PCDEx_PMAConfig(&pcd_fs_handle, 0x81, PCD_SNG_BUF, 256); // MSC / HID + HAL_PCDEx_PMAConfig(&pcd_fs_handle, 0x02, PCD_SNG_BUF, 320); // unused + HAL_PCDEx_PMAConfig(&pcd_fs_handle, 0x82, PCD_SNG_BUF, 320); // CDC CMD + HAL_PCDEx_PMAConfig(&pcd_fs_handle, 0x03, PCD_SNG_BUF, 384); // CDC DATA + HAL_PCDEx_PMAConfig(&pcd_fs_handle, 0x83, PCD_SNG_BUF, 448); // CDC DATA + #else + // We have 320 32-bit words in total to use here #if MICROPY_HW_USB_CDC_NUM == 2 HAL_PCD_SetRxFiFo(&pcd_fs_handle, 128); @@ -379,6 +415,8 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { HAL_PCD_SetTxFiFo(&pcd_fs_handle, 2, 32); // CDC CMD HAL_PCD_SetTxFiFo(&pcd_fs_handle, 3, 64); // CDC DATA #endif + + #endif } #endif #if MICROPY_HW_USB_HS From 4096fa397b195a6ef82e48a74deaa8dd026d8a41 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 16 Jul 2019 14:46:31 +1000 Subject: [PATCH 0547/1788] stm32/powerctrlboot: Increase SYSCLK to 32MHz for L0 MCUs. --- ports/stm32/powerctrlboot.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/ports/stm32/powerctrlboot.c b/ports/stm32/powerctrlboot.c index e320cc4db1..de7c9d88a7 100644 --- a/ports/stm32/powerctrlboot.c +++ b/ports/stm32/powerctrlboot.c @@ -82,11 +82,21 @@ void SystemClock_Config(void) { // Enable power control peripheral __HAL_RCC_PWR_CLK_ENABLE(); - // Use the 16MHz internal oscillator + // Set flash latency to 1 because SYSCLK > 16MHz + FLASH->ACR |= FLASH_ACR_LATENCY; + + // Enable the 16MHz internal oscillator RCC->CR |= RCC_CR_HSION; while (!(RCC->CR & RCC_CR_HSIRDY)) { } - const uint32_t sysclk_src = 1; + + // Use HSI16 and the PLL to get a 32MHz SYSCLK + RCC->CFGR = 1 << RCC_CFGR_PLLDIV_Pos | 1 << RCC_CFGR_PLLMUL_Pos; + RCC->CR |= RCC_CR_PLLON; + while (!(RCC->CR & RCC_CR_PLLRDY)) { + // Wait for PLL to lock + } + const uint32_t sysclk_src = 3; // Select SYSCLK source RCC->CFGR |= sysclk_src << RCC_CFGR_SW_Pos; From 102d9911e988959a7ef0e5f8123c41b4aca5c144 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 16 Jul 2019 14:47:12 +1000 Subject: [PATCH 0548/1788] stm32/mphalport: Fix GPIO clock enable for L0 MCUs. --- ports/stm32/mphalport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/mphalport.c b/ports/stm32/mphalport.c index c5786e7409..fe7772cf68 100644 --- a/ports/stm32/mphalport.c +++ b/ports/stm32/mphalport.c @@ -121,7 +121,7 @@ void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio) { #define AHBxENR_GPIOAEN_Pos RCC_AHB4ENR_GPIOAEN_Pos #elif defined(STM32L0) #define AHBxENR IOPENR - #define AHBxENR_GPIOAEN_Pos RCC_IOPENR_GPIOAEN + #define AHBxENR_GPIOAEN_Pos RCC_IOPENR_IOPAEN_Pos #elif defined(STM32L4) #define AHBxENR AHB2ENR #define AHBxENR_GPIOAEN_Pos RCC_AHB2ENR_GPIOAEN_Pos From 64aebca1553bea62b4266c0194838a5a7df0e91f Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 16 Jul 2019 14:47:32 +1000 Subject: [PATCH 0549/1788] stm32/Makefile: Allow a board to disable float support. By using "MICROPY_FLOAT_IMPL = none" in its mpconfigboard.mk file. --- ports/stm32/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index d2ca4122a1..f74180d397 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -91,9 +91,13 @@ CFLAGS += -DMICROPY_HW_VTOR=$(TEXT0_ADDR) ifeq ($(MICROPY_FLOAT_IMPL),double) CFLAGS += -DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_DOUBLE else +ifeq ($(MICROPY_FLOAT_IMPL),none) +CFLAGS += -DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_NONE +else CFLAGS += -DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_FLOAT CFLAGS += -fsingle-precision-constant -Wdouble-promotion endif +endif LDFLAGS = -nostdlib -L $(LD_DIR) $(addprefix -T,$(LD_FILES)) -Map=$(@:.elf=.map) --cref LDFLAGS += --defsym=_estack_reserve=8 From baea43bba79152319e66668afa55b64a9e13c1a5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 16 Jul 2019 14:48:08 +1000 Subject: [PATCH 0550/1788] stm32/boards/B_L072Z_LRWAN1: Enable USB VCP support. --- ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.h | 8 ++++++++ ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.mk | 1 + 2 files changed, 9 insertions(+) diff --git a/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.h b/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.h index da219abd30..7a80f26356 100644 --- a/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.h +++ b/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.h @@ -19,6 +19,7 @@ #define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (0) #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_ADC (0) +#define MICROPY_HW_ENABLE_USB (1) #define MICROPY_HW_HAS_SWITCH (1) // UART config @@ -58,3 +59,10 @@ #define MICROPY_HW_LED4 (pin_B7) // 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 (need to bridge SB15/SB16) +#define MICROPY_HW_USB_FS (1) +#define MICROPY_HW_USB_MSC (0) +#define MICROPY_HW_USB_HID (0) +#define USBD_CDC_RX_DATA_SIZE (256) +#define USBD_CDC_TX_DATA_SIZE (256) diff --git a/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.mk b/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.mk index a39a2bd47b..084cf4d309 100644 --- a/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.mk +++ b/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.mk @@ -1,5 +1,6 @@ MCU_SERIES = l0 CMSIS_MCU = STM32L072xx +MICROPY_FLOAT_IMPL = none AF_FILE = boards/stm32l072_af.csv LD_FILES = boards/stm32l072xz.ld boards/common_basic.ld From a67d9155e61d41898888da3a6884e73c3a270781 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 8 Jul 2019 17:18:47 +1000 Subject: [PATCH 0551/1788] travis: Switch unix stackless build to use clang. To test a different compiler, other than gcc. --- .travis.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0088fbe90d..1229e6e689 100644 --- a/.travis.yml +++ b/.travis.yml @@ -106,13 +106,14 @@ jobs: # unix stackless - stage: test - env: NAME="unix stackless port build and tests" + env: NAME="unix stackless port build and tests with clang" + install: + - sudo apt-get install clang script: - git submodule update --init lib/axtls lib/berkeley-db-1.xx lib/libffi - - make ${MAKEOPTS} -C mpy-cross - - make ${MAKEOPTS} -C ports/unix deplibs - - make ${MAKEOPTS} -C ports/unix CFLAGS_EXTRA="-DMICROPY_STACKLESS=1 -DMICROPY_STACKLESS_STRICT=1" - - make ${MAKEOPTS} -C ports/unix test + - make ${MAKEOPTS} -C mpy-cross CC=clang + - make ${MAKEOPTS} -C ports/unix CC=clang CFLAGS_EXTRA="-DMICROPY_STACKLESS=1 -DMICROPY_STACKLESS_STRICT=1" + - make ${MAKEOPTS} -C ports/unix CC=clang test # windows port via mingw - stage: test From 3e558300669effa93e5e4dad4c8c4ecc167766c4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 17 Jul 2019 15:33:27 +1000 Subject: [PATCH 0552/1788] tests/stress/recursive_iternext.py: Increase large depth to 5000. So it fails correctly on Linux with clang. --- tests/stress/recursive_iternext.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/stress/recursive_iternext.py b/tests/stress/recursive_iternext.py index edb5a843f2..bbc389e726 100644 --- a/tests/stress/recursive_iternext.py +++ b/tests/stress/recursive_iternext.py @@ -14,7 +14,7 @@ except: try: # large stack/heap, eg unix [0] * 80000 - N = 2400 + N = 5000 except: try: # medium, eg pyboard From bc66fe9064c48268dbc88b8c3197f560351b1039 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Thu, 11 Jul 2019 11:55:31 +1000 Subject: [PATCH 0553/1788] py/scheduler: Rename sched_stack to sched_queue. Behaviour was changed from stack to queue in 8977c7eb581f5d06500edb1ea29aea5cbda04f28, and this updates variable names to match. Also updates other references (docs, error messages). --- docs/library/micropython.rst | 4 ++-- py/modmicropython.c | 2 +- py/mpstate.h | 2 +- py/scheduler.c | 8 ++++---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/library/micropython.rst b/docs/library/micropython.rst index d9f913bffd..2b4c1168c9 100644 --- a/docs/library/micropython.rst +++ b/docs/library/micropython.rst @@ -136,5 +136,5 @@ Functions :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. + There is a finite queue to hold the scheduled functions and `schedule()` + will raise a `RuntimeError` if the queue is full. diff --git a/py/modmicropython.c b/py/modmicropython.c index 864d1a5c5b..8d36697f15 100644 --- a/py/modmicropython.c +++ b/py/modmicropython.c @@ -150,7 +150,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_micropython_kbd_intr_obj, mp_micropython_kbd #if MICROPY_ENABLE_SCHEDULER STATIC mp_obj_t mp_micropython_schedule(mp_obj_t function, mp_obj_t arg) { if (!mp_sched_schedule(function, arg)) { - mp_raise_msg(&mp_type_RuntimeError, "schedule stack full"); + mp_raise_msg(&mp_type_RuntimeError, "schedule queue full"); } return mp_const_none; } diff --git a/py/mpstate.h b/py/mpstate.h index a9c2b32d66..b7eb6bdeb1 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -141,7 +141,7 @@ typedef struct _mp_state_vm_t { volatile mp_obj_t mp_pending_exception; #if MICROPY_ENABLE_SCHEDULER - mp_sched_item_t sched_stack[MICROPY_SCHEDULER_DEPTH]; + mp_sched_item_t sched_queue[MICROPY_SCHEDULER_DEPTH]; #endif // current exception being handled, for sys.exc_info() diff --git a/py/scheduler.c b/py/scheduler.c index 5edff45b6f..e7cbb524de 100644 --- a/py/scheduler.c +++ b/py/scheduler.c @@ -65,7 +65,7 @@ void mp_handle_pending(void) { void mp_handle_pending_tail(mp_uint_t atomic_state) { MP_STATE_VM(sched_state) = MP_SCHED_LOCKED; if (!mp_sched_empty()) { - mp_sched_item_t item = MP_STATE_VM(sched_stack)[MP_STATE_VM(sched_idx)]; + mp_sched_item_t item = MP_STATE_VM(sched_queue)[MP_STATE_VM(sched_idx)]; MP_STATE_VM(sched_idx) = IDX_MASK(MP_STATE_VM(sched_idx) + 1); --MP_STATE_VM(sched_len); MICROPY_END_ATOMIC_SECTION(atomic_state); @@ -107,11 +107,11 @@ bool mp_sched_schedule(mp_obj_t function, mp_obj_t arg) { MP_STATE_VM(sched_state) = MP_SCHED_PENDING; } uint8_t iput = IDX_MASK(MP_STATE_VM(sched_idx) + MP_STATE_VM(sched_len)++); - MP_STATE_VM(sched_stack)[iput].func = function; - MP_STATE_VM(sched_stack)[iput].arg = arg; + MP_STATE_VM(sched_queue)[iput].func = function; + MP_STATE_VM(sched_queue)[iput].arg = arg; ret = true; } else { - // schedule stack is full + // schedule queue is full ret = false; } MICROPY_END_ATOMIC_SECTION(atomic_state); From 3b3a4749ce46febe4d19a2392e94485c0659eb98 Mon Sep 17 00:00:00 2001 From: "Paul m. p. P" Date: Tue, 16 Jul 2019 06:00:36 +0200 Subject: [PATCH 0554/1788] py/objstringio: Guard bytesio_stream_p struct w/ MICROPY_PY_IO_BYTESIO. It's static and can lead to a compilation warning/error when MICROPY_PY_IO_BYTESIO is disabled. --- py/objstringio.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/py/objstringio.c b/py/objstringio.c index 89b6790312..8f1f761138 100644 --- a/py/objstringio.c +++ b/py/objstringio.c @@ -244,12 +244,6 @@ STATIC const mp_stream_p_t stringio_stream_p = { .is_text = true, }; -STATIC const mp_stream_p_t bytesio_stream_p = { - .read = stringio_read, - .write = stringio_write, - .ioctl = stringio_ioctl, -}; - const mp_obj_type_t mp_type_stringio = { { &mp_type_type }, .name = MP_QSTR_StringIO, @@ -262,6 +256,12 @@ const mp_obj_type_t mp_type_stringio = { }; #if MICROPY_PY_IO_BYTESIO +STATIC const mp_stream_p_t bytesio_stream_p = { + .read = stringio_read, + .write = stringio_write, + .ioctl = stringio_ioctl, +}; + const mp_obj_type_t mp_type_bytesio = { { &mp_type_type }, .name = MP_QSTR_BytesIO, From 02b2ad4fbdbfae3e06ee4d0c686be36509d53d7d Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 17 Jul 2019 16:19:06 +1000 Subject: [PATCH 0555/1788] stm32/boards/STM32F769DISC: Fix length of FLASH_APP section. Fixes issue #4924. --- ports/stm32/boards/STM32F769DISC/f769_qspi.ld | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/boards/STM32F769DISC/f769_qspi.ld b/ports/stm32/boards/STM32F769DISC/f769_qspi.ld index 9a0bd56fb3..5f920b417f 100644 --- a/ports/stm32/boards/STM32F769DISC/f769_qspi.ld +++ b/ports/stm32/boards/STM32F769DISC/f769_qspi.ld @@ -17,7 +17,7 @@ MEMORY { - FLASH_APP (rx) : ORIGIN = 0x08020000, LENGTH = 2016K /* sectors 1-11 3x32K 1*128K 7*256K */ + FLASH_APP (rx) : ORIGIN = 0x08020000, LENGTH = 1920K /* sectors 4-11 1*128K 7*256K */ FLASH_QSPI (rx) : ORIGIN = 0x90000000, LENGTH = 64M /* external QSPI flash in XIP mode */ DTCM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K /* Used for storage cache */ RAM (xrw) : ORIGIN = 0x20020000, LENGTH = 384K /* SRAM1 = 368K, SRAM2 = 16K */ From d42392b9a78d03080d12cc17283c570c3edf8016 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 17 Jul 2019 16:27:17 +1000 Subject: [PATCH 0556/1788] stm32/make-stmconst.py: Allow more variation in parens and int-suffix L. --- ports/stm32/make-stmconst.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/stm32/make-stmconst.py b/ports/stm32/make-stmconst.py index cfcc12f59e..41ec9b56f4 100644 --- a/ports/stm32/make-stmconst.py +++ b/ports/stm32/make-stmconst.py @@ -40,9 +40,9 @@ class Lexer: re_comment = r'(?P[A-Za-z0-9 \-/_()&]+)' re_addr_offset = r'Address offset: (?P0x[0-9A-Z]{2,3})' regexs = ( - ('#define hex', re.compile(r'#define +(?P[A-Z0-9_]+) +(?:\(\(uint32_t\))?(?P0x[0-9A-F]+)U?(?:\))?($| +/\*)')), + ('#define hex', re.compile(r'#define +(?P[A-Z0-9_]+) +\(?(\(uint32_t\))?(?P0x[0-9A-F]+)U?L?\)?($| */\*)')), ('#define X', re.compile(r'#define +(?P[A-Z0-9_]+) +(?P[A-Z0-9_]+)($| +/\*)')), - ('#define X+hex', re.compile(r'#define +(?P[A-Za-z0-9_]+) +\((?P[A-Z0-9_]+) \+ (?P0x[0-9A-F]+)U?\)($| +/\*)')), + ('#define X+hex', re.compile(r'#define +(?P[A-Za-z0-9_]+) +\(?(?P[A-Z0-9_]+) \+ (?P0x[0-9A-F]+)U?L?\)?($| +/\*)')), ('#define typedef', re.compile(r'#define +(?P[A-Z0-9_]+(ext)?) +\(\([A-Za-z0-9_]+_TypeDef \*\) (?P[A-Za-z0-9_]+)\)($| +/\*)')), ('typedef struct', re.compile(r'typedef struct$')), ('{', re.compile(r'{$')), From 59b7166d87b480517ca5905ee2239dc2cace18b9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 17 Jul 2019 16:33:31 +1000 Subject: [PATCH 0557/1788] stm32: Add initial support for STM32WBxx MCUs. This new series of MCUs is similar to the L4 series with an additional Cortex-M0 coprocessor. The firmware for the wireless stack must be managed separately and MicroPython does not currently interface to it. Supported features so far include: RTC, UART, USB, internal flash filesystem. --- ports/stm32/Makefile | 5 ++-- ports/stm32/dma.c | 14 +++++++++ ports/stm32/dma.h | 2 +- ports/stm32/extint.c | 28 ++++++++++++++++-- ports/stm32/extint.h | 2 +- ports/stm32/flash.c | 8 +++--- ports/stm32/flashbdev.c | 3 +- ports/stm32/machine_uart.c | 2 +- ports/stm32/modmachine.c | 4 +-- ports/stm32/mpconfigboard_common.h | 9 ++++++ ports/stm32/mphalport.c | 2 +- ports/stm32/powerctrl.c | 13 +++++---- ports/stm32/powerctrlboot.c | 46 ++++++++++++++++++++++++++++++ ports/stm32/rtc.c | 22 +++++++++----- ports/stm32/stm32_it.c | 8 ++++++ ports/stm32/system_stm32.c | 4 +++ ports/stm32/uart.c | 8 ++++-- ports/stm32/usbd_cdc_interface.c | 4 +-- ports/stm32/usbd_conf.c | 19 ++++++++---- 19 files changed, 165 insertions(+), 38 deletions(-) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index f74180d397..e868d6de1b 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -79,6 +79,7 @@ CFLAGS_MCU_f7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7 CFLAGS_MCU_l0 = $(CFLAGS_CORTEX_M) -mtune=cortex-m0plus -mcpu=cortex-m0plus 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_MCU_wb = $(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) @@ -335,7 +336,7 @@ SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ hal_uart.c \ ) -ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 h7 l0 l4)) +ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 h7 l0 l4 wb)) SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ ll_usb.c \ ) @@ -361,7 +362,7 @@ endif ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32H743xx)) SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_, hal_fdcan.c) else -ifneq ($(MCU_SERIES),$(filter $(MCU_SERIES),l0)) +ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f0 f4 f7 h7 l4)) SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_, hal_can.c) endif endif diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c index 2c7371e010..8a3f743fe7 100644 --- a/ports/stm32/dma.c +++ b/ports/stm32/dma.c @@ -34,6 +34,18 @@ #include "dma.h" #include "irq.h" +#if defined(STM32WB) + +// DMA is currently not implemented for this MCU + +void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint32_t dir, void *data) { +} + +void dma_deinit(const dma_descr_t *dma_descr) { +} + +#else + #define DMA_IDLE_ENABLED() (dma_idle.enabled != 0) #define DMA_SYSTICK_LOG2 (3) #define DMA_SYSTICK_MASK ((1 << DMA_SYSTICK_LOG2) - 1) @@ -919,3 +931,5 @@ void dma_nohal_start(const dma_descr_t *descr, uint32_t src_addr, uint32_t dst_a } #endif + +#endif // defined(STM32WB) diff --git a/ports/stm32/dma.h b/ports/stm32/dma.h index 6d07a94ed9..5a17276a49 100644 --- a/ports/stm32/dma.h +++ b/ports/stm32/dma.h @@ -73,7 +73,7 @@ extern const dma_descr_t dma_I2C_2_RX; extern const dma_descr_t dma_I2C_1_TX; extern const dma_descr_t dma_I2C_1_RX; -#elif defined(STM32L4) +#elif defined(STM32L4) || defined(STM32WB) 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 9a7295995a..836b0c5954 100644 --- a/ports/stm32/extint.c +++ b/ports/stm32/extint.c @@ -91,7 +91,7 @@ #define EXTI_SWIER_BB(line) (*(__IO uint32_t *)(PERIPH_BB_BASE + ((EXTI_OFFSET + offsetof(EXTI_TypeDef, SWIER)) * 32) + ((line) * 4))) #endif -#if defined(STM32L4) +#if defined(STM32L4) || defined(STM32WB) // 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. @@ -140,6 +140,7 @@ STATIC mp_obj_t pyb_extint_callback_arg[EXTI_NUM_VECTORS]; STATIC const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = { #if defined(STM32F0) || defined(STM32L0) + 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, @@ -155,11 +156,19 @@ STATIC const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = { RTC_IRQn, ADC1_COMP_IRQn, ADC1_COMP_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, EXTI15_10_IRQn, + #if defined(STM32WB) + PVD_PVM_IRQn, + RTC_Alarm_IRQn, + TAMP_STAMP_LSECSS_IRQn, + RTC_WKUP_IRQn, + #else #if defined(STM32L4) PVD_PVM_IRQn, #else @@ -177,6 +186,8 @@ STATIC const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = { TAMP_STAMP_IRQn, RTC_WKUP_IRQn, #endif + + #endif }; // Set override_callback_obj to true if you want to unconditionally set the @@ -285,7 +296,9 @@ void extint_register_pin(const pin_obj_t *pin, uint32_t mode, bool hard_irq, mp_ pyb_extint_callback_arg[line] = MP_OBJ_FROM_PTR(pin); // Route the GPIO to EXTI + #if !defined(STM32WB) __HAL_RCC_SYSCFG_CLK_ENABLE(); + #endif SYSCFG->EXTICR[line >> 2] = (SYSCFG->EXTICR[line >> 2] & ~(0x0f << (4 * (line & 0x03)))) | ((uint32_t)(GPIO_GET_INDEX(pin->gpio)) << (4 * (line & 0x03))); @@ -320,7 +333,9 @@ void extint_set(const pin_obj_t *pin, uint32_t mode) { pyb_extint_callback_arg[line] = MP_OBJ_FROM_PTR(pin); // Route the GPIO to EXTI + #if !defined(STM32WB) __HAL_RCC_SYSCFG_CLK_ENABLE(); + #endif SYSCFG->EXTICR[line >> 2] = (SYSCFG->EXTICR[line >> 2] & ~(0x0f << (4 * (line & 0x03)))) | ((uint32_t)(GPIO_GET_INDEX(pin->gpio)) << (4 * (line & 0x03))); @@ -358,12 +373,16 @@ void extint_enable(uint line) { if (pyb_extint_mode[line] == EXTI_Mode_Interrupt) { #if defined(STM32H7) EXTI_D1->IMR1 |= (1 << line); + #elif defined(STM32WB) + EXTI->IMR1 |= (1 << line); #else EXTI->IMR |= (1 << line); #endif } else { #if defined(STM32H7) EXTI_D1->EMR1 |= (1 << line); + #elif defined(STM32WB) + EXTI->EMR1 |= (1 << line); #else EXTI->EMR |= (1 << line); #endif @@ -388,6 +407,9 @@ void extint_disable(uint line) { #if defined(STM32H7) EXTI_D1->IMR1 &= ~(1 << line); EXTI_D1->EMR1 &= ~(1 << line); + #elif defined(STM32WB) + EXTI->IMR1 &= ~(1 << line); + EXTI->EMR1 &= ~(1 << line); #else EXTI->IMR &= ~(1 << line); EXTI->EMR &= ~(1 << line); @@ -407,7 +429,7 @@ void extint_swint(uint line) { return; } // we need 0 to 1 transition to trigger the interrupt -#if defined(STM32L4) || defined(STM32H7) +#if defined(STM32L4) || defined(STM32H7) || defined(STM32WB) EXTI->SWIER1 &= ~(1 << line); EXTI->SWIER1 |= (1 << line); #else @@ -485,7 +507,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(STM32L4) + #if defined(STM32L4) || defined(STM32WB) 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); diff --git a/ports/stm32/extint.h b/ports/stm32/extint.h index d275087c9e..907af53dc2 100644 --- a/ports/stm32/extint.h +++ b/ports/stm32/extint.h @@ -46,7 +46,7 @@ #if defined(STM32F0) || defined(STM32L4) #define EXTI_RTC_TIMESTAMP (19) #define EXTI_RTC_WAKEUP (20) -#elif defined(STM32H7) +#elif defined(STM32H7) || defined(STM32WB) #define EXTI_RTC_TIMESTAMP (18) #define EXTI_RTC_WAKEUP (19) #else diff --git a/ports/stm32/flash.c b/ports/stm32/flash.c index aff85f7e37..58cc012793 100644 --- a/ports/stm32/flash.c +++ b/ports/stm32/flash.c @@ -68,7 +68,7 @@ static const flash_layout_t flash_layout[] = { { 0x08040000, 0x40000, 3 }, }; -#elif defined(STM32L0) || defined(STM32L4) +#elif defined(STM32L0) || defined(STM32L4) || defined(STM32WB) static const flash_layout_t flash_layout[] = { { (uint32_t)FLASH_BASE, (uint32_t)FLASH_PAGE_SIZE, 512 }, @@ -122,7 +122,7 @@ static uint32_t get_page(uint32_t addr) { } #endif -#elif defined(STM32L4) && !defined(SYSCFG_MEMRMP_FB_MODE) +#elif (defined(STM32L4) && !defined(SYSCFG_MEMRMP_FB_MODE)) || defined(STM32WB) static uint32_t get_page(uint32_t addr) { return (addr - FLASH_BASE) / FLASH_PAGE_SIZE; @@ -175,7 +175,7 @@ void flash_erase(uint32_t flash_dest, uint32_t num_word32) { EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; EraseInitStruct.PageAddress = flash_dest; EraseInitStruct.NbPages = (4 * num_word32 + FLASH_PAGE_SIZE - 4) / FLASH_PAGE_SIZE; - #elif defined(STM32L4) && !defined(SYSCFG_MEMRMP_FB_MODE) + #elif (defined(STM32L4) && !defined(SYSCFG_MEMRMP_FB_MODE)) || defined(STM32WB) __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS); EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; EraseInitStruct.Page = get_page(flash_dest); @@ -247,7 +247,7 @@ void flash_erase_it(uint32_t flash_dest, uint32_t num_word32) { */ void flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) { - #if defined(STM32L4) + #if defined(STM32L4) || defined(STM32WB) // program the flash uint64 by uint64 for (int i = 0; i < num_word32 / 2; i++) { diff --git a/ports/stm32/flashbdev.c b/ports/stm32/flashbdev.c index 0a5f417040..470f3d0860 100644 --- a/ports/stm32/flashbdev.c +++ b/ports/stm32/flashbdev.c @@ -105,7 +105,8 @@ STATIC byte flash_cache_mem[0x4000] __attribute__((aligned(4))); // 16k #elif defined(STM32L432xx) || \ defined(STM32L451xx) || defined(STM32L452xx) || defined(STM32L462xx) || \ - defined(STM32L475xx) || defined(STM32L476xx) || defined(STM32L496xx) + defined(STM32L475xx) || defined(STM32L476xx) || defined(STM32L496xx) || \ + defined(STM32WB) // The STM32L4xx doesn't have CCRAM, so we use SRAM2 for this, although // actual location and size is defined by the linker script. diff --git a/ports/stm32/machine_uart.c b/ports/stm32/machine_uart.c index 92343ba6d7..5dbc133310 100644 --- a/ports/stm32/machine_uart.c +++ b/ports/stm32/machine_uart.c @@ -489,7 +489,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 = MP_OBJ_TO_PTR(self_in); - #if defined(STM32F0) || defined(STM32F7) || defined(STM32L0) || defined(STM32L4) || defined(STM32H7) + #if defined(STM32F0) || defined(STM32F7) || defined(STM32L0) || defined(STM32L4) || defined(STM32H7) || defined(STM32WB) self->uartx->RQR = USART_RQR_SBKRQ; // write-only register #else self->uartx->CR1 |= USART_CR1_SBK; diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index 8d6dbf4fec..e45f81479b 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -61,7 +61,7 @@ #define RCC_CSR_BORRSTF RCC_CSR_PORRSTF #endif -#if defined(STM32L4) +#if defined(STM32L4) || defined(STM32WB) // L4 does not have a POR, so use BOR instead #define RCC_CSR_PORRSTF RCC_CSR_BORRSTF #endif @@ -305,7 +305,7 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { return mp_obj_new_tuple(MP_ARRAY_SIZE(tuple), tuple); } else { // set - #if defined(STM32F0) || defined(STM32L0) || defined(STM32L4) + #if defined(STM32F0) || defined(STM32L0) || defined(STM32L4) || defined(STM32WB) mp_raise_NotImplementedError("machine.freq set not supported yet"); #else mp_int_t sysclk = mp_obj_get_int(args[0]); diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index 63d4238020..121b64d038 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -202,6 +202,15 @@ #define MICROPY_HW_MAX_TIMER (17) #define MICROPY_HW_MAX_UART (6) +// Configuration for STM32WB series +#elif defined(STM32WB) + +#define MP_HAL_UNIQUE_ID_ADDRESS (UID_BASE) +#define PYB_EXTI_NUM_VECTORS (20) +#define MICROPY_HW_MAX_I2C (3) +#define MICROPY_HW_MAX_TIMER (17) +#define MICROPY_HW_MAX_UART (1) + #else #error Unsupported MCU series #endif diff --git a/ports/stm32/mphalport.c b/ports/stm32/mphalport.c index fe7772cf68..ec4590b06b 100644 --- a/ports/stm32/mphalport.c +++ b/ports/stm32/mphalport.c @@ -122,7 +122,7 @@ void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio) { #elif defined(STM32L0) #define AHBxENR IOPENR #define AHBxENR_GPIOAEN_Pos RCC_IOPENR_IOPAEN_Pos - #elif defined(STM32L4) + #elif defined(STM32L4) || defined(STM32WB) #define AHBxENR AHB2ENR #define AHBxENR_GPIOAEN_Pos RCC_AHB2ENR_GPIOAEN_Pos #endif diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c index 067e4c176e..68a8bfdaf3 100644 --- a/ports/stm32/powerctrl.c +++ b/ports/stm32/powerctrl.c @@ -76,7 +76,7 @@ void powerctrl_check_enter_bootloader(void) { if ((bl_addr & 0xfff) == 0 && (RCC->RCC_SR & RCC_SR_SFTRSTF)) { // Reset by NVIC_SystemReset with bootloader data set -> branch to bootloader RCC->RCC_SR = RCC_SR_RMVF; - #if defined(STM32F0) || defined(STM32F4) || defined(STM32L4) + #if defined(STM32F0) || defined(STM32F4) || defined(STM32L4) || defined(STM32WB) __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH(); #endif uint32_t r0 = BL_STATE[0]; @@ -84,7 +84,7 @@ void powerctrl_check_enter_bootloader(void) { } } -#if !defined(STM32F0) && !defined(STM32L0) +#if !defined(STM32F0) && !defined(STM32L0) && !defined(STM32WB) // Assumes that PLL is used as the SYSCLK source int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk_mhz, bool need_pllsai) { @@ -158,7 +158,7 @@ int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk #endif -#if !defined(STM32F0) && !defined(STM32L0) && !defined(STM32L4) +#if !defined(STM32F0) && !defined(STM32L0) && !defined(STM32L4) && !defined(STM32WB) STATIC uint32_t calc_ahb_div(uint32_t wanted_div) { if (wanted_div <= 1) { return RCC_SYSCLK_DIV1; } @@ -333,7 +333,7 @@ void powerctrl_enter_stop_mode(void) { __HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_MSI); #endif - #if !defined(STM32F0) && !defined(STM32L0) && !defined(STM32L4) + #if !defined(STM32F0) && !defined(STM32L0) && !defined(STM32L4) && !defined(STM32WB) // takes longer to wake but reduces stop current HAL_PWREx_EnableFlashPowerDown(); #endif @@ -380,6 +380,9 @@ void powerctrl_enter_stop_mode(void) { #if defined(STM32H7) while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL1) { } + #elif defined(STM32WB) + while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_SYSCLKSOURCE_STATUS_PLLCLK) { + } #else while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL) { } @@ -450,7 +453,7 @@ void powerctrl_enter_standby_mode(void) { PWR->CR2 |= PWR_CR2_CWUPF6 | PWR_CR2_CWUPF5 | PWR_CR2_CWUPF4 | PWR_CR2_CWUPF3 | PWR_CR2_CWUPF2 | PWR_CR2_CWUPF1; #elif defined(STM32H7) // TODO - #elif defined(STM32L4) + #elif defined(STM32L4) || defined(STM32WB) // clear all wake-up flags PWR->SCR |= PWR_SCR_CWUF5 | PWR_SCR_CWUF4 | PWR_SCR_CWUF3 | PWR_SCR_CWUF2 | PWR_SCR_CWUF1; // TODO diff --git a/ports/stm32/powerctrlboot.c b/ports/stm32/powerctrlboot.c index de7c9d88a7..8884f596ed 100644 --- a/ports/stm32/powerctrlboot.c +++ b/ports/stm32/powerctrlboot.c @@ -131,4 +131,50 @@ void SystemClock_Config(void) { #endif } +#elif defined(STM32WB) + +void SystemClock_Config(void) { + // Enable the 32MHz external oscillator + RCC->CR |= RCC_CR_HSEON; + while (!(RCC->CR & RCC_CR_HSERDY)) { + } + + // Use HSE and the PLL to get a 64MHz SYSCLK + #define PLLM (HSE_VALUE / 8000000) // VCO input is 8MHz + #define PLLN (24) // 24*8MHz = 192MHz + #define PLLQ (4) // f_Q = 48MHz + #define PLLR (3) // f_R = 64MHz + RCC->PLLCFGR = + (PLLR - 1) << RCC_PLLCFGR_PLLR_Pos | RCC_PLLCFGR_PLLREN + | (PLLQ - 1) << RCC_PLLCFGR_PLLQ_Pos | RCC_PLLCFGR_PLLQEN + | PLLN << RCC_PLLCFGR_PLLN_Pos + | (PLLM - 1) << RCC_PLLCFGR_PLLM_Pos + | 3 << RCC_PLLCFGR_PLLSRC_Pos; + RCC->CR |= RCC_CR_PLLON; + while (!(RCC->CR & RCC_CR_PLLRDY)) { + // Wait for PLL to lock + } + const uint32_t sysclk_src = 3; + + // Set divider for HCLK2 to 2 so f_HCLK2 = 32MHz + RCC->EXTCFGR = 8 << RCC_EXTCFGR_C2HPRE_Pos; + + // Set flash latency to 3 because SYSCLK > 54MHz + FLASH->ACR |= 3 << FLASH_ACR_LATENCY_Pos; + + // Select SYSCLK source + RCC->CFGR |= sysclk_src << RCC_CFGR_SW_Pos; + while (((RCC->CFGR >> RCC_CFGR_SWS_Pos) & 0x3) != sysclk_src) { + // Wait for SYSCLK source to change + } + + // Select PLLQ as 48MHz source for USB and RNG + RCC->CCIPR = 2 << RCC_CCIPR_CLK48SEL_Pos; + + SystemCoreClockUpdate(); + + HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000); + HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); +} + #endif diff --git a/ports/stm32/rtc.c b/ports/stm32/rtc.c index d0f444c216..4019617ac8 100644 --- a/ports/stm32/rtc.c +++ b/ports/stm32/rtc.c @@ -31,6 +31,14 @@ #include "rtc.h" #include "irq.h" +#if defined(STM32WB) +#define RCC_CSR_LSION RCC_CSR_LSI1ON +#define RCC_FLAG_LSIRDY RCC_FLAG_LSI1RDY +#define RCC_OSCILLATORTYPE_LSI RCC_OSCILLATORTYPE_LSI1 +#define __HAL_RCC_LSI_ENABLE __HAL_RCC_LSI1_ENABLE +#define __HAL_RCC_LSI_DISABLE __HAL_RCC_LSI1_DISABLE +#endif + /// \moduleref pyb /// \class RTC - real time clock /// @@ -177,7 +185,7 @@ void rtc_init_finalise() { // fresh reset; configure RTC Calendar RTC_CalendarConfig(); - #if defined(STM32L4) + #if defined(STM32L4) || defined(STM32WB) if(__HAL_RCC_GET_FLAG(RCC_FLAG_BORRST) != RESET) { #else if(__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST) != RESET) { @@ -209,7 +217,7 @@ 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) + #if !defined(STM32H7) && !defined(STM32WB) // Enable Power Clock __HAL_RCC_PWR_CLK_ENABLE(); #endif @@ -218,7 +226,7 @@ STATIC HAL_StatusTypeDef PYB_RCC_OscConfig(RCC_OscInitTypeDef *RCC_OscInitStruc HAL_PWR_EnableBkUpAccess(); uint32_t tickstart = HAL_GetTick(); - #if defined(STM32F7) || defined(STM32L4) || defined(STM32H7) + #if defined(STM32F7) || defined(STM32L4) || defined(STM32H7) || defined(STM32WB) //__HAL_RCC_PWR_CLK_ENABLE(); // Enable write access to Backup domain //PWR->CR1 |= PWR_CR1_DBP; @@ -298,7 +306,7 @@ STATIC HAL_StatusTypeDef PYB_RTC_Init(RTC_HandleTypeDef *hrtc) { // Exit Initialization mode hrtc->Instance->ISR &= (uint32_t)~RTC_ISR_INIT; - #if defined(STM32L0) || defined(STM32L4) || defined(STM32H7) + #if defined(STM32L0) || defined(STM32L4) || defined(STM32H7) || defined(STM32WB) hrtc->Instance->OR &= (uint32_t)~RTC_OR_ALARMOUTTYPE; hrtc->Instance->OR |= (uint32_t)(hrtc->Init.OutPutType); #elif defined(STM32F7) @@ -649,7 +657,7 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) { RTC->WPR = 0xff; // enable external interrupts on line EXTI_RTC_WAKEUP - #if defined(STM32L4) + #if defined(STM32L4) || defined(STM32WB) EXTI->IMR1 |= 1 << EXTI_RTC_WAKEUP; EXTI->RTSR1 |= 1 << EXTI_RTC_WAKEUP; #elif defined(STM32H7) @@ -662,7 +670,7 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) { // clear interrupt flags RTC->ISR &= ~RTC_ISR_WUTF; - #if defined(STM32L4) + #if defined(STM32L4) || defined(STM32WB) EXTI->PR1 = 1 << EXTI_RTC_WAKEUP; #elif defined(STM32H7) EXTI_D1->PR1 = 1 << EXTI_RTC_WAKEUP; @@ -682,7 +690,7 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) { RTC->WPR = 0xff; // disable external interrupts on line EXTI_RTC_WAKEUP - #if defined(STM32L4) + #if defined(STM32L4) || defined(STM32WB) EXTI->IMR1 &= ~(1 << EXTI_RTC_WAKEUP); #elif defined(STM32H7) EXTI_D1->IMR1 |= 1 << EXTI_RTC_WAKEUP; diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index 1e2712b05f..16db92d1d7 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -306,6 +306,14 @@ void USB_IRQHandler(void) { } #endif +#elif defined(STM32WB) + +#if MICROPY_HW_USB_FS +void USB_LP_IRQHandler(void) { + HAL_PCD_IRQHandler(&pcd_fs_handle); +} +#endif + #else /** diff --git a/ports/stm32/system_stm32.c b/ports/stm32/system_stm32.c index deb23e2f5f..0792d124d6 100644 --- a/ports/stm32/system_stm32.c +++ b/ports/stm32/system_stm32.c @@ -78,6 +78,8 @@ #include "py/mphal.h" #include "powerctrl.h" +#if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) || defined(STM32L4) + void __fatal_error(const char *msg); /** @@ -392,3 +394,5 @@ void SystemClock_Config(void) NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, TICK_INT_PRIORITY, 0)); #endif } + +#endif diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c index 0d46ea9473..f577eb787f 100644 --- a/ports/stm32/uart.c +++ b/ports/stm32/uart.c @@ -81,7 +81,7 @@ #define USART_CR2_IE_ALL (USART_CR2_IE_BASE) #define USART_CR3_IE_ALL (USART_CR3_IE_BASE | USART_CR3_WUFIE) -#elif defined(STM32L4) +#elif defined(STM32L4) || defined(STM32WB) #define USART_CR1_IE_ALL (USART_CR1_IE_BASE | USART_CR1_EOBIE | USART_CR1_RTOIE | USART_CR1_CMIE) #define USART_CR2_IE_ALL (USART_CR2_IE_BASE) #if defined(USART_CR3_TCBGTIE) @@ -439,11 +439,13 @@ void uart_deinit(pyb_uart_obj_t *self) { __HAL_RCC_USART1_FORCE_RESET(); __HAL_RCC_USART1_RELEASE_RESET(); __HAL_RCC_USART1_CLK_DISABLE(); + #if defined(USART2) } else if (self->uart_id == 2) { HAL_NVIC_DisableIRQ(USART2_IRQn); __HAL_RCC_USART2_FORCE_RESET(); __HAL_RCC_USART2_RELEASE_RESET(); __HAL_RCC_USART2_CLK_DISABLE(); + #endif #if defined(USART3) } else if (self->uart_id == 3) { #if !defined(STM32F0) @@ -653,7 +655,7 @@ int uart_rx_char(pyb_uart_obj_t *self) { return data; } else { // no buffering - #if defined(STM32F0) || defined(STM32F7) || defined(STM32L0) || defined(STM32L4) || defined(STM32H7) + #if defined(STM32F0) || defined(STM32F7) || defined(STM32L0) || defined(STM32L4) || defined(STM32H7) || defined(STM32WB) int data = self->uartx->RDR & self->char_mask; self->uartx->ICR = USART_ICR_ORECF; // clear ORE if it was set return data; @@ -779,7 +781,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(STM32F0) || defined(STM32F7) || defined(STM32L0) || defined(STM32L4) || defined(STM32H7) + #if defined(STM32F0) || defined(STM32F7) || defined(STM32L0) || defined(STM32L4) || defined(STM32H7) || defined(STM32WB) int data = self->uartx->RDR; // clears UART_FLAG_RXNE self->uartx->ICR = USART_ICR_ORECF; // clear ORE if it was set #else diff --git a/ports/stm32/usbd_cdc_interface.c b/ports/stm32/usbd_cdc_interface.c index b27ea51d87..e234230196 100644 --- a/ports/stm32/usbd_cdc_interface.c +++ b/ports/stm32/usbd_cdc_interface.c @@ -142,7 +142,7 @@ int8_t usbd_cdc_control(usbd_cdc_state_t *cdc_in, uint8_t cmd, uint8_t* pbuf, ui // configure its serial port (in most cases to disable local echo) cdc->connect_state = USBD_CDC_CONNECT_STATE_CONNECTING; usbd_cdc_connect_tx_timer = 8; // wait for 8 SOF IRQs - #if defined(STM32L0) + #if defined(STM32L0) || defined(STM32WB) USB->CNTR |= USB_CNTR_SOFM; #else PCD_HandleTypeDef *hpcd = cdc->base.usbd->pdev->pData; @@ -219,7 +219,7 @@ void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) { --usbd_cdc_connect_tx_timer; } else { usbd_cdc_msc_hid_state_t *usbd = ((USBD_HandleTypeDef*)hpcd->pData)->pClassData; - #if defined(STM32L0) + #if defined(STM32L0) || defined(STM32WB) USB->CNTR &= ~USB_CNTR_SOFM; #else hpcd->Instance->GINTMSK &= ~USB_OTG_GINTMSK_SOFM; diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c index 8e62a9cc8c..437d96ae78 100644 --- a/ports/stm32/usbd_conf.c +++ b/ports/stm32/usbd_conf.c @@ -44,7 +44,7 @@ PCD_HandleTypeDef pcd_fs_handle; PCD_HandleTypeDef pcd_hs_handle; #endif -#if defined(STM32L0) +#if defined(STM32L0) || defined(STM32WB) // The STM32L0xx has a single USB device-only instance #define USB_OTG_FS USB #endif @@ -64,6 +64,8 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) { const uint32_t otg_alt = GPIO_AF10_OTG1_FS; #elif defined(STM32L0) const uint32_t otg_alt = GPIO_AF0_USB; + #elif defined(STM32WB) + const uint32_t otg_alt = GPIO_AF10_USB; #else const uint32_t otg_alt = GPIO_AF10_OTG_FS; #endif @@ -90,7 +92,7 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) { #endif // Enable USB FS Clocks - #if defined(STM32L0) + #if defined(STM32L0) || defined(STM32WB) __HAL_RCC_USB_CLK_ENABLE(); #else __USB_OTG_FS_CLK_ENABLE(); @@ -111,6 +113,9 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) { #if defined(STM32L0) NVIC_SetPriority(USB_IRQn, IRQ_PRI_OTG_FS); HAL_NVIC_EnableIRQ(USB_IRQn); + #elif defined(STM32WB) + NVIC_SetPriority(USB_LP_IRQn, IRQ_PRI_OTG_FS); + HAL_NVIC_EnableIRQ(USB_LP_IRQn); #else NVIC_SetPriority(OTG_FS_IRQn, IRQ_PRI_OTG_FS); HAL_NVIC_EnableIRQ(OTG_FS_IRQn); @@ -190,7 +195,7 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) { * @retval None */ void HAL_PCD_MspDeInit(PCD_HandleTypeDef *hpcd) { - #if defined(STM32L0) + #if defined(STM32L0) || defined(STM32WB) __HAL_RCC_USB_CLK_DISABLE(); #else @@ -354,6 +359,10 @@ void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd) { USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { #if MICROPY_HW_USB_FS if (pdev->id == USB_PHY_FS_ID) { + #if defined(STM32WB) + PWR->CR2 |= PWR_CR2_USV; // USB supply is valid + #endif + // Set LL Driver parameters pcd_fs_handle.Instance = USB_OTG_FS; #if MICROPY_HW_USB_CDC_NUM == 2 @@ -370,7 +379,7 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { pcd_fs_handle.Init.lpm_enable = DISABLE; pcd_fs_handle.Init.battery_charging_enable = DISABLE; #endif - #if !defined(STM32L0) + #if !defined(STM32L0) && !defined(STM32WB) pcd_fs_handle.Init.use_dedicated_ep1 = 0; pcd_fs_handle.Init.dma_enable = 0; #if !defined(MICROPY_HW_USB_VBUS_DETECT_PIN) @@ -387,7 +396,7 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { // Initialize LL Driver HAL_PCD_Init(&pcd_fs_handle); - #if defined(STM32L0) + #if defined(STM32L0) || defined(STM32WB) // We have 512 16-bit words it total to use here (when using PCD_SNG_BUF) HAL_PCDEx_PMAConfig(&pcd_fs_handle, 0x00, PCD_SNG_BUF, 64); // EP0 HAL_PCDEx_PMAConfig(&pcd_fs_handle, 0x80, PCD_SNG_BUF, 128); // EP0 From 9849567a065a1abee1dc406856ce4b50d1f678e5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 17 Jul 2019 16:40:02 +1000 Subject: [PATCH 0558/1788] stm32/boards: Add MCU support files for STM32WB55. --- ports/stm32/boards/stm32wb55_af.csv | 74 +++++++++++++++++++ ports/stm32/boards/stm32wb55xg.ld | 33 +++++++++ ports/stm32/boards/stm32wbxx_hal_conf_base.h | 78 ++++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 ports/stm32/boards/stm32wb55_af.csv create mode 100644 ports/stm32/boards/stm32wb55xg.ld create mode 100644 ports/stm32/boards/stm32wbxx_hal_conf_base.h diff --git a/ports/stm32/boards/stm32wb55_af.csv b/ports/stm32/boards/stm32wb55_af.csv new file mode 100644 index 0000000000..6e4ddd9608 --- /dev/null +++ b/ports/stm32/boards/stm32wb55_af.csv @@ -0,0 +1,74 @@ +Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15, +,,SYS_AF,TIM1/TIM2/LPTIM1,TIM1/TIM2,SPI2/SAI1/TIM1,I2C1/I2C3,SPI1/SPI2,RF,USART1,LPUART1,TSC,USB/QUADSPI,LCD,COMP1/COMP2/TIM1,SAI1,TIM2/TIM16/TIM17/LPTIM2,EVENTOUT,ADC +PortA,PA0,,TIM2_CH1,,,,,,,,,,,COMP1_OUT,SAI1_EXTCLK,TIM2_ETR,EVENTOUT,ADC123_IN0 +PortA,PA1,,TIM2_CH2,,,I2C1_SMBA,SPI1_SCK,,,,,,LCD_SEG0,,,,EVENTOUT,ADC123_IN1 +PortA,PA2,LSCO,TIM2_CH3,,,,,,,LPUART1_TX,,QUADSPI_BK1_NCS,LCD_SEG1,COMP2_OUT,,,EVENTOUT,ADC123_IN2 +PortA,PA3,,TIM2_CH4,,SAI1_PDM_CK1,,,,,LPUART1_RX,,QUADSPI_CLK,LCD_SEG2,,SAI1_MCLK_A,,EVENTOUT,ADC123_IN3 +PortA,PA4,,,,,,SPI1_NSS,,,,,,LCD_SEG5,,SAI1_FS_B,LPTIM2_OUT,EVENTOUT,ADC12_IN4 +PortA,PA5,,TIM2_CH1,TIM2_ETR,,,SPI1_SCK,,,,,,,,SAI1_SD_B,LPTIM2_ETR,EVENTOUT,ADC12_IN5 +PortA,PA6,,TIM1_BKIN,,,,SPI1_MISO,,,LPUART1_CTS,,QUADSPI_BK1_IO3,LCD_SEG3,TIM1_BKIN,,TIM16_CH1,EVENTOUT,ADC12_IN6 +PortA,PA7,,TIM1_CH1N,,,I2C3_SCL,SPI1_MOSI,,,,,QUADSPI_BK1_IO2,LCD_SEG4,COMP2_OUT,,TIM17_CH1,EVENTOUT,ADC12_IN7 +PortA,PA8,MCO,TIM1_CH1,,SAI1_PDM_CK2,,,,USART1_CK,,,,LCD_COM0,,SAI1_SCK_A,LPTIM2_OUT,EVENTOUT, +PortA,PA9,,TIM1_CH2,,SAI1_PDM_DI2,I2C1_SCL,SPI2_SCK,,USART1_TX,,,,LCD_COM1,,SAI1_FS_A,,EVENTOUT, +PortA,PA10,,TIM1_CH3,,SAI1_PDM_DI1,I2C1_SDA,,,USART1_RX,,,USB_CRS_SYNC,LCD_COM2,,SAI1_SD_A,TIM17_BKIN,EVENTOUT, +PortA,PA11,,TIM1_CH4,TIM1_BKIN2,,,SPI1_MISO,,USART1_CTS,,,USB_DM,,TIM1_BKIN2,,,EVENTOUT, +PortA,PA12,,TIM1_ETR,,,,SPI1_MOSI,,USART1_RTS_DE,LPUART1_RX,,USB_DP,,,,,EVENTOUT, +PortA,PA13,JTMS/SWDIO,,,,,,,,IR_OUT,,USB_NOE,,,SAI1_SD_B,,EVENTOUT, +PortA,PA14,JTCK/SWCLK,LPTIM1_OUT,,,I2C1_SMBA,,,,,,,LCD_SEG5,,SAI1_FS_B,,EVENTOUT, +PortA,PA15,JTDI,TIM2_CH1,TIM2_ETR,,,SPI1_NSS,,,,TSC_G3_IO1,,LCD_SEG17,,,,EVENTOUT, +PortB,PB0,,,,,,,EXT_PA_TX,,,,,,COMP1_OUT,,,EVENTOUT,ADC12_IN8 +PortB,PB1,,,,,,,,,LPUART1_RTS_DE,,,,,,LPTIM2_IN1,EVENTOUT,ADC12_IN9 +PortB,PB2,RTC_OUT,LPTIM1_OUT,,,I2C3_SMBA,SPI1_NSS,,,,,,LCD_VLCD,,SAI1_EXTCLK,,EVENTOUT, +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,,USART1_RTS_DE,,,,LCD_SEG7,,SAI1_SCK_B,,EVENTOUT, +PortB,PB4,NJTRST,,,,I2C3_SDA,SPI1_MISO,,USART1_CTS,,TSC_G2_IO1,,LCD_SEG8,,SAI1_MCLK_B,TIM17_BKIN,EVENTOUT, +PortB,PB5,,LPTIM1_IN1,,,I2C1_SMBA,SPI1_MOSI,,USART1_CK,LPUART1_TX,TSC_G2_IO2,,LCD_SEG9,COMP2_OUT,SAI1_SD_B,TIM16_BKIN,EVENTOUT, +PortB,PB6,MCO,LPTIM1_ETR,,,I2C1_SCL,,,USART1_TX,,TSC_G2_IO3,,LCD_SEG6,,SAI1_FS_B,TIM16_CH1N,EVENTOUT, +PortB,PB7,,LPTIM1_IN2,,TIM1_BKIN,I2C1_SDA,,,USART1_RX,,TSC_G2_IO4,,LCD_SEG21,,,TIM17_CH1N,EVENTOUT, +PortB,PB8,,TIM1_CH2N,,SAI1_PDM_CK1,I2C1_SCL,,,,,,QUADSPI_BK1_IO1,LCD_SEG16,,SAI1_MCLK_A,TIM16_CH1,EVENTOUT, +PortB,PB9,,TIM1_CH3N,,SAI1_PDM_DI2,I2C1_SDA,SPI2_NSS,,,IR_OUT,TSC_G7_IO4,QUADSPI_BK1_IO0,LCD_COM3,,SAI1_FS_A,TIM17_CH1,EVENTOUT, +PortB,PB10,,TIM2_CH3,,,I2C3_SCL,SPI2_SCK,,,LPUART1_RX,TSC_SYNC,QUADSPI_CLK,LCD_SEG10,COMP1_OUT,SAI1_SCK_A,,EVENTOUT, +PortB,PB11,,TIM2_CH4,,,I2C3_SDA,,,,LPUART1_TX,,QUADSPI_BK1_NCS,LCD_SEG11,COMP2_OUT,,,EVENTOUT, +PortB,PB12,,TIM1_BKIN,,TIM1_BKIN,I2C3_SMBA,SPI2_NSS,,,LPUART1_RTS,TSC_G1_IO1,,LCD_SEG12,,SAI1_FS_A,,EVENTOUT, +PortB,PB13,,TIM1_CH1N,,,I2C3_SCL,SPI2_SCK,,,LPUART1_CTS,TSC_G1_IO2,,LCD_SEG13,,SAI1_SCK_A,,EVENTOUT, +PortB,PB14,,TIM1_CH2N,,,I2C3_SDA,SPI2_MISO,,,,TSC_G1_IO3,,LCD_SEG14,,SAI1_MCLK_A,,EVENTOUT, +PortB,PB15,RTC_REFIN,TIM1_CH3N,,,,SPI2_MOSI,,,,TSC_G1_IO4,,LCD_SEG15,,SAI1_SD_A,,EVENTOUT, +PortC,PC0,,LPTIM1_IN1,,,I2C3_SCL,,,,LPUART1_RX,,,LCD_SEG18,,,LPTIM2_IN1,EVENTOUT,ADC123_IN10 +PortC,PC1,,LPTIM1_OUT,,SPI2_MOSI,I2C3_SDA,,,,LPUART1_TX,,,LCD_SEG19,,,,EVENTOUT,ADC123_IN11 +PortC,PC2,,LPTIM1_IN2,,,,SPI2_MISO,,,,,,LCD_SEG20,,,,EVENTOUT,ADC123_IN12 +PortC,PC3,,LPTIM1_ETR,,SAI1_PDM_DI1,,SPI2_MOSI,,,,,,LCD_VLCD,,SAI1_SD_A,LPTIM2_ETR,EVENTOUT,ADC123_IN13 +PortC,PC4,,,,,,,,,,,,LCD_SEG22,,,,EVENTOUT,ADC12_IN14 +PortC,PC5,,,,SAI1_PDM_DI3,,,,,,,,LCD_SEG23,,,,EVENTOUT,ADC12_IN15 +PortC,PC6,,,,,,,,,,TSC_G4_IO1,,LCD_SEG24,,,,EVENTOUT, +PortC,PC7,,,,,,,,,,TSC_G4_IO2,,LCD_SEG25,,,,EVENTOUT, +PortC,PC8,,,,,,,,,,TSC_G4_IO3,,LCD_SEG26,,,,EVENTOUT, +PortC,PC9,,,,TIM1_BKIN,,,,,,TSC_G4_IO4,USB_NOE,LCD_SEG27,,SAI1_SCK_B,,EVENTOUT, +PortC,PC10,TRACED1,,,,,,,,,TSC_G3_IO2,,LCD_COM4LCD_SEG28LCD_SEG40,,,,EVENTOUT, +PortC,PC11,,,,,,,,,,TSC_G3_IO3,,LCD_COM5LCD_SEG29LCD_SEG41,,,,EVENTOUT, +PortC,PC12,TRACED3,,,,,,,,,TSC_G3_IO4,,LCD_COM6LCD_SEG30LCD_SEG42,,,,EVENTOUT, +PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD0,,,,,,SPI2_NSS,,,,,,,,,,EVENTOUT, +PortD,PD1,,,,,,SPI2_SCK,,,,,,,,,,EVENTOUT, +PortD,PD2,TRACED2,,,,,,,,,TSC_SYNC,,LCD_COM7LCD_SEG31LCD_SEG43,,,,EVENTOUT, +PortD,PD3,,,,SPI2_SCK,,SPI2_MISO,,,,,QUADSPI_BK1_NCS,,,,,EVENTOUT, +PortD,PD4,,,,,,SPI2_MOSI,,,,TSC_G5_IO1,QUADSPI_BK1_IO0,,,,,EVENTOUT, +PortD,PD5,,,,,,,,,,TSC_G5_IO2,QUADSPI_BK1_IO1,,,SAI1_MCLK_B,,EVENTOUT, +PortD,PD6,,,,SAI1_PDM_DI1,,,,,,TSC_G5_IO3,QUADSPI_BK1_IO2,,,SAI1_SD_A,,EVENTOUT, +PortD,PD7,,,,,,,,,,TSC_G5_IO4,QUADSPI_BK1_IO3,LCD_SEG39,,,,EVENTOUT, +PortD,PD8,,,TIM1_BKIN2,,,,,,,,,LCD_SEG28,,,,EVENTOUT, +PortD,PD9,TRACED0,,,,,,,,,,,LCD_SEG29,,,,EVENTOUT, +PortD,PD10,TRIG_INOUT,,,,,,,,,TSC_G6_IO1,,LCD_SEG30,,,,EVENTOUT, +PortD,PD11,,,,,,,,,,TSC_G6_IO2,,LCD_SEG31,,,LPTIM2_ETR,EVENTOUT, +PortD,PD12,,,,,,,,,,TSC_G6_IO3,,LCD_SEG32,,,LPTIM2_IN1,EVENTOUT, +PortD,PD13,,,,,,,,,,TSC_G6_IO4,,LCD_SEG33,,,LPTIM2_OUT,EVENTOUT, +PortD,PD14,,TIM1_CH1,,,,,,,,,,LCD_SEG34,,,,EVENTOUT, +PortD,PD15,,TIM1_CH2,,,,,,,,,,LCD_SEG35,,,,EVENTOUT, +PortE,PE0,,TIM1_ETR,,,,,,,,TSC_G7_IO3,,LCD_SEG36,,,TIM16_CH1,EVENTOUT, +PortE,PE1,,,,,,,,,,TSC_G7_IO2,,LCD_SEG37,,,TIM17_CH1,EVENTOUT, +PortE,PE2,TRACECK,,,SAI1_PDM_CK1,,,,,,TSC_G7_IO1,,LCD_SEG38,,SAI1_MCLK_A,,EVENTOUT, +PortE,PE3,,,,,,,,,,,,,,,,EVENTOUT, +PortE,PE4,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH3,LSCO,,,,,,,,,,,,,,,EVENTOUT, diff --git a/ports/stm32/boards/stm32wb55xg.ld b/ports/stm32/boards/stm32wb55xg.ld new file mode 100644 index 0000000000..bdbf7e447e --- /dev/null +++ b/ports/stm32/boards/stm32wb55xg.ld @@ -0,0 +1,33 @@ +/* + GNU linker script for STM32WB55xG +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K /* sectors 0-127 */ + FLASH_FS (r) : ORIGIN = 0x08080000, LENGTH = 256K /* sectors 128-191 */ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 192K /* SRAM1 */ +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* RAM extents for the garbage collector */ +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM); + +_ram_fs_cache_end = ORIGIN(RAM) + LENGTH(RAM); +_ram_fs_cache_start = _ram_fs_cache_end - 4K; /* fs cache = 4K */ + +/* Define the stack. The stack is full descending so begins at the bottom of FS cache. + Note that EABI requires the stack to be 8-byte aligned for a call. */ +_estack = _ram_fs_cache_start - _estack_reserve; +_sstack = _estack - 16K; + +_heap_start = _ebss; /* heap starts just after statically allocated memory */ +_heap_end = _sstack; + +_flash_fs_start = ORIGIN(FLASH_FS); +_flash_fs_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); diff --git a/ports/stm32/boards/stm32wbxx_hal_conf_base.h b/ports/stm32/boards/stm32wbxx_hal_conf_base.h new file mode 100644 index 0000000000..8dbc9ecea7 --- /dev/null +++ b/ports/stm32/boards/stm32wbxx_hal_conf_base.h @@ -0,0 +1,78 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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_STM32WBXX_HAL_CONF_BASE_H +#define MICROPY_INCLUDED_STM32WBXX_HAL_CONF_BASE_H + +// Include various HAL modules for convenience +#include "stm32wbxx_hal_dma.h" +#include "stm32wbxx_hal_adc.h" +#include "stm32wbxx_hal_cortex.h" +#include "stm32wbxx_hal_flash.h" +#include "stm32wbxx_hal_gpio.h" +#include "stm32wbxx_hal_i2c.h" +#include "stm32wbxx_hal_pcd.h" +#include "stm32wbxx_hal_pwr.h" +#include "stm32wbxx_hal_rcc.h" +#include "stm32wbxx_hal_rtc.h" +#include "stm32wbxx_hal_spi.h" +#include "stm32wbxx_hal_tim.h" +#include "stm32wbxx_hal_uart.h" +#include "stm32wbxx_hal_usart.h" + +// Enable various HAL modules +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_DMA_MODULE_ENABLED +#define HAL_FLASH_MODULE_ENABLED +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +#define HAL_USART_MODULE_ENABLED + +// Oscillator values in Hz +#define MSI_VALUE (4000000) + +// SysTick has the highest priority +#define TICK_INT_PRIORITY (0x00) + +// Miscellaneous HAL settings +#define DATA_CACHE_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define PREFETCH_ENABLE 0 +#define USE_SPI_CRC 0 +#define USE_RTOS 0 + +// HAL parameter assertions are disabled +#define assert_param(expr) ((void)0) + +#endif // MICROPY_INCLUDED_STM32WBXX_HAL_CONF_BASE_H From d2a8fb747fbe2ac67cd266f6bc0fcccd9a5874e6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 17 Jul 2019 16:50:59 +1000 Subject: [PATCH 0559/1788] stm32/boards/NUCLEO_WB55: Add definition files for new board. --- .../stm32/boards/NUCLEO_WB55/mpconfigboard.h | 64 +++++++++++++++++++ .../stm32/boards/NUCLEO_WB55/mpconfigboard.mk | 5 ++ ports/stm32/boards/NUCLEO_WB55/pins.csv | 34 ++++++++++ .../boards/NUCLEO_WB55/stm32wbxx_hal_conf.h | 19 ++++++ 4 files changed, 122 insertions(+) create mode 100644 ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h create mode 100644 ports/stm32/boards/NUCLEO_WB55/mpconfigboard.mk create mode 100644 ports/stm32/boards/NUCLEO_WB55/pins.csv create mode 100644 ports/stm32/boards/NUCLEO_WB55/stm32wbxx_hal_conf.h diff --git a/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h b/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h new file mode 100644 index 0000000000..fc047880d1 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h @@ -0,0 +1,64 @@ +/* This file is part of the MicroPython project, http://micropython.org/ + * MIT License; Copyright (c) 2019 Damien P. George + */ + +#define MICROPY_HW_BOARD_NAME "NUCLEO-WB55" +#define MICROPY_HW_MCU_NAME "STM32WB55RGV6" + +#define MICROPY_PY_PYB_LEGACY (0) + +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_ADC (0) +#define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_HAS_SWITCH (1) + +// There is an external 32kHz oscillator +#define RTC_ASYNCH_PREDIV (0) +#define RTC_SYNCH_PREDIV (0x7fff) +#define MICROPY_HW_RTC_USE_LSE (1) +#define MICROPY_HW_RTC_USE_US (1) + +// UART buses +#define MICROPY_HW_UART1_TX (pin_B6) +#define MICROPY_HW_UART1_RX (pin_B7) +// USART 1 is connected to the virtual com port on the ST-LINK +#define MICROPY_HW_UART_REPL PYB_UART_1 +#define MICROPY_HW_UART_REPL_BAUD 115200 + +// I2C buses +#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_I2C3_SCL (pin_C0) // Arduino A0, pin 28 on CN7 +#define MICROPY_HW_I2C3_SDA (pin_C1) // Arduino A1, pin 30 on CN7 + +// SPI buses +#if 0 // TODO need working DMA +#define MICROPY_HW_SPI1_NSS (pin_A4) // Arduino D10 pin 17 on CN10 +#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 +#endif + +// User switch; pressing the button makes the input go low +#define MICROPY_HW_USRSW_PIN (pin_C4) +#define MICROPY_HW_USRSW_PULL (GPIO_PULLUP) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_FALLING) +#define MICROPY_HW_USRSW_PRESSED (0) + +// LEDs +#define MICROPY_HW_LED1 (pin_B1) // red +#define MICROPY_HW_LED2 (pin_B0) // green +#define MICROPY_HW_LED3 (pin_B5) // blue +#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_HID (0) +#define USBD_CDC_RX_DATA_SIZE (512) +#define USBD_CDC_TX_DATA_SIZE (512) diff --git a/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.mk new file mode 100644 index 0000000000..b0f93c006f --- /dev/null +++ b/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.mk @@ -0,0 +1,5 @@ +MCU_SERIES = wb +CMSIS_MCU = STM32WB55xx +AF_FILE = boards/stm32wb55_af.csv +LD_FILES = boards/stm32wb55xg.ld boards/common_basic.ld +STARTUP_FILE = lib/stm32lib/CMSIS/STM32WBxx/Source/Templates/gcc/startup_stm32wb55xx_cm4.o diff --git a/ports/stm32/boards/NUCLEO_WB55/pins.csv b/ports/stm32/boards/NUCLEO_WB55/pins.csv new file mode 100644 index 0000000000..49fdab0c28 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_WB55/pins.csv @@ -0,0 +1,34 @@ +,PA0 +,PA1 +,PA2 +,PA3 +,PA4 +,PA5 +,PA6 +,PA7 +,PB0 +,PB1 +,PB2 +,PB3 +,PB4 +,PB5 +,PB6 +,PB7 +,PB8 +,PB9 +,PB10 +,PB11 +,PB12 +,PB13 +,PB14 +,PB15 +,PC0 +,PC1 +,PC2 +,PC3 +SW,PC4 +LED_GREEN,PB0 +LED_RED,PB1 +LED_BLUE,PB5 +USB_DM,PA11 +USB_DP,PA12 diff --git a/ports/stm32/boards/NUCLEO_WB55/stm32wbxx_hal_conf.h b/ports/stm32/boards/NUCLEO_WB55/stm32wbxx_hal_conf.h new file mode 100644 index 0000000000..176857220e --- /dev/null +++ b/ports/stm32/boards/NUCLEO_WB55/stm32wbxx_hal_conf.h @@ -0,0 +1,19 @@ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32WBXX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32WBXX_HAL_CONF_H + +// Oscillator values in Hz +#define HSE_VALUE (32000000) +#define LSE_VALUE (32768) +#define EXTERNAL_SAI1_CLOCK_VALUE (48000) + +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) + +#include "boards/stm32wbxx_hal_conf_base.h" + +#endif // MICROPY_INCLUDED_STM32WBXX_HAL_CONF_H From 0c12adca4611c35763b7aaff1c7a4d76d160a29e Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 17 Jul 2019 16:51:24 +1000 Subject: [PATCH 0560/1788] stm32/boards/USBDONGLE_WB55: Add definition files for new board. --- .../boards/USBDONGLE_WB55/mpconfigboard.h | 43 +++++++++++++++++++ .../boards/USBDONGLE_WB55/mpconfigboard.mk | 5 +++ ports/stm32/boards/USBDONGLE_WB55/pins.csv | 32 ++++++++++++++ .../USBDONGLE_WB55/stm32wbxx_hal_conf.h | 19 ++++++++ 4 files changed, 99 insertions(+) create mode 100644 ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.h create mode 100644 ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.mk create mode 100644 ports/stm32/boards/USBDONGLE_WB55/pins.csv create mode 100644 ports/stm32/boards/USBDONGLE_WB55/stm32wbxx_hal_conf.h diff --git a/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.h b/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.h new file mode 100644 index 0000000000..77e2d4f329 --- /dev/null +++ b/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.h @@ -0,0 +1,43 @@ +/* This file is part of the MicroPython project, http://micropython.org/ + * MIT License; Copyright (c) 2019 Damien P. George + */ + +#define MICROPY_HW_BOARD_NAME "USBDongle-WB55" +#define MICROPY_HW_MCU_NAME "STM32WB55CGU6" + +#define MICROPY_PY_PYB_LEGACY (0) + +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_ADC (0) +#define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_HAS_SWITCH (1) + +// There is an external 32kHz oscillator +#define RTC_ASYNCH_PREDIV (0) +#define RTC_SYNCH_PREDIV (0x7fff) +#define MICROPY_HW_RTC_USE_LSE (1) +#define MICROPY_HW_RTC_USE_US (1) + +// I2C buses +#define MICROPY_HW_I2C1_SCL (pin_B8) +#define MICROPY_HW_I2C1_SDA (pin_B9) + +// User switch; pressing the button makes the input go low +#define MICROPY_HW_USRSW_PIN (pin_A10) +#define MICROPY_HW_USRSW_PULL (GPIO_PULLUP) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_FALLING) +#define MICROPY_HW_USRSW_PRESSED (0) + +// LEDs +#define MICROPY_HW_LED1 (pin_B1) // red +#define MICROPY_HW_LED2 (pin_B0) // green +#define MICROPY_HW_LED3 (pin_A4) // blue +#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_HID (0) +#define USBD_CDC_RX_DATA_SIZE (512) +#define USBD_CDC_TX_DATA_SIZE (512) diff --git a/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.mk b/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.mk new file mode 100644 index 0000000000..b0f93c006f --- /dev/null +++ b/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.mk @@ -0,0 +1,5 @@ +MCU_SERIES = wb +CMSIS_MCU = STM32WB55xx +AF_FILE = boards/stm32wb55_af.csv +LD_FILES = boards/stm32wb55xg.ld boards/common_basic.ld +STARTUP_FILE = lib/stm32lib/CMSIS/STM32WBxx/Source/Templates/gcc/startup_stm32wb55xx_cm4.o diff --git a/ports/stm32/boards/USBDONGLE_WB55/pins.csv b/ports/stm32/boards/USBDONGLE_WB55/pins.csv new file mode 100644 index 0000000000..2b115c5c40 --- /dev/null +++ b/ports/stm32/boards/USBDONGLE_WB55/pins.csv @@ -0,0 +1,32 @@ +,PA0 +,PA1 +,PA2 +,PA3 +,PA4 +,PA5 +,PA6 +,PA7 +,PA8 +,PA9 +,PA10 +,PA11 +,PA12 +,PA13 +,PA14 +,PA15 +,PB0 +,PB1 +,PB2 +,PB3 +,PB4 +,PB5 +,PB6 +,PB7 +,PB8 +,PB9 +SW,PA10 +LED_GREEN,PB0 +LED_RED,PB1 +LED_BLUE,PA4 +USB_DM,PA11 +USB_DP,PA12 diff --git a/ports/stm32/boards/USBDONGLE_WB55/stm32wbxx_hal_conf.h b/ports/stm32/boards/USBDONGLE_WB55/stm32wbxx_hal_conf.h new file mode 100644 index 0000000000..176857220e --- /dev/null +++ b/ports/stm32/boards/USBDONGLE_WB55/stm32wbxx_hal_conf.h @@ -0,0 +1,19 @@ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32WBXX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32WBXX_HAL_CONF_H + +// Oscillator values in Hz +#define HSE_VALUE (32000000) +#define LSE_VALUE (32768) +#define EXTERNAL_SAI1_CLOCK_VALUE (48000) + +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) + +#include "boards/stm32wbxx_hal_conf_base.h" + +#endif // MICROPY_INCLUDED_STM32WBXX_HAL_CONF_H From 3967dd68e80b296d1beead5e630807d914d98de6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 19 Jul 2019 14:07:41 +1000 Subject: [PATCH 0561/1788] tests/run-perfbench.py: Add --emit option to select emitter for tests. --- tests/run-perfbench.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/run-perfbench.py b/tests/run-perfbench.py index d8100ef81d..e52aa0ccbc 100755 --- a/tests/run-perfbench.py +++ b/tests/run-perfbench.py @@ -49,7 +49,7 @@ def run_script_on_target(target, script): else: # Run local executable try: - p = subprocess.run([target], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, input=script) + p = subprocess.run(target, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, input=script) output = p.stdout except subprocess.CalledProcessError as er: err = er @@ -195,6 +195,7 @@ def main(): cmd_parser.add_argument('-p', '--pyboard', action='store_true', help='run tests via pyboard.py') cmd_parser.add_argument('-d', '--device', default='/dev/ttyACM0', help='the device for pyboard.py') cmd_parser.add_argument('-a', '--average', default='8', help='averaging number') + cmd_parser.add_argument('--emit', default='bytecode', help='MicroPython emitter to use (bytecode or native)') cmd_parser.add_argument('N', nargs=1, help='N parameter (approximate target CPU frequency)') cmd_parser.add_argument('M', nargs=1, help='M parameter (approximate target heap in kbytes)') cmd_parser.add_argument('files', nargs='*', help='input test files') @@ -215,7 +216,7 @@ def main(): target = pyboard.Pyboard(args.device) target.enter_raw_repl() else: - target = MICROPYTHON + target = [MICROPYTHON, '-X', 'emit=' + args.emit] if len(args.files) == 0: tests_skip = ('benchrun.py',) From a29334761dc7b8eaf9f78611e3cd9033928b110c Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 10 Jul 2019 13:43:52 +1000 Subject: [PATCH 0562/1788] esp32: Add support for hardware I2C. --- docs/esp32/quickref.rst | 14 ++- ports/esp32/Makefile | 1 + ports/esp32/machine_i2c.c | 179 +++++++++++++++++++++++++++++++++++++ ports/esp32/mpconfigport.h | 1 + 4 files changed, 192 insertions(+), 3 deletions(-) create mode 100644 ports/esp32/machine_i2c.c diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst index 76fe0d9f9e..dd85b102b2 100644 --- a/docs/esp32/quickref.rst +++ b/docs/esp32/quickref.rst @@ -303,14 +303,22 @@ Hardware SPI has the same methods as Software SPI above:: I2C bus ------- -The I2C driver is implemented in software and works on all pins, -and is accessed via the :ref:`machine.I2C ` class:: +The I2C driver has both software and hardware implementations, and the two +hardware peripherals have identifiers 0 and 1. Any available output-capable +pins can be used for SCL and SDA. The driver is accessed via the +:ref:`machine.I2C ` class:: from machine import Pin, I2C - # construct an I2C bus + # construct a software I2C bus i2c = I2C(scl=Pin(5), sda=Pin(4), freq=100000) + # construct a hardware I2C bus + i2c = I2C(0) + i2c = I2C(1, scl=Pin(5), sda=Pin(4), freq=400000) + + i2c.scan() # scan for slave devices + i2c.readfrom(0x3a, 4) # read 4 bytes from slave device with address 0x3a i2c.writeto(0x3a, '12') # write '12' to slave device with address 0x3a diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index ec6d29695b..4ce4e48990 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -181,6 +181,7 @@ SRC_C = \ machine_touchpad.c \ machine_adc.c \ machine_dac.c \ + machine_i2c.c \ machine_pwm.c \ machine_uart.c \ modmachine.c \ diff --git a/ports/esp32/machine_i2c.c b/ports/esp32/machine_i2c.c new file mode 100644 index 0000000000..b34d24b16f --- /dev/null +++ b/ports/esp32/machine_i2c.c @@ -0,0 +1,179 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/mphal.h" +#include "py/mperrno.h" +#include "extmod/machine_i2c.h" + +#include "driver/i2c.h" + +#define I2C_0_DEFAULT_SCL (GPIO_NUM_18) +#define I2C_0_DEFAULT_SDA (GPIO_NUM_19) +#define I2C_1_DEFAULT_SCL (GPIO_NUM_25) +#define I2C_1_DEFAULT_SDA (GPIO_NUM_26) + +#define I2C_DEFAULT_TIMEOUT_US (10000) // 10ms + +typedef struct _machine_hw_i2c_obj_t { + mp_obj_base_t base; + i2c_port_t port : 8; + gpio_num_t scl : 8; + gpio_num_t sda : 8; +} machine_hw_i2c_obj_t; + +STATIC const mp_obj_type_t machine_hw_i2c_type; +STATIC machine_hw_i2c_obj_t machine_hw_i2c_obj[I2C_NUM_MAX]; + +STATIC void machine_hw_i2c_init(machine_hw_i2c_obj_t *self, uint32_t freq, uint32_t timeout_us, bool first_init) { + if (!first_init) { + i2c_driver_delete(self->port); + } + i2c_config_t conf = { + .mode = I2C_MODE_MASTER, + .sda_io_num = self->sda, + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_io_num = self->scl, + .scl_pullup_en = GPIO_PULLUP_ENABLE, + .master.clk_speed = freq, + }; + i2c_param_config(self->port, &conf); + i2c_set_timeout(self->port, I2C_APB_CLK_FREQ / 1000000 * timeout_us); + i2c_driver_install(self->port, I2C_MODE_MASTER, 0, 0, 0); +} + +int machine_hw_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags) { + machine_hw_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); + + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, addr << 1 | (flags & MP_MACHINE_I2C_FLAG_READ), true); + + int data_len = 0; + for (; n--; ++bufs) { + if (flags & MP_MACHINE_I2C_FLAG_READ) { + i2c_master_read(cmd, bufs->buf, bufs->len, n == 0 ? I2C_MASTER_LAST_NACK : I2C_MASTER_ACK); + } else { + if (bufs->len != 0) { + i2c_master_write(cmd, bufs->buf, bufs->len, true); + } + } + data_len += bufs->len; + } + + if (flags & MP_MACHINE_I2C_FLAG_STOP) { + i2c_master_stop(cmd); + } + + // TODO proper timeout + esp_err_t err = i2c_master_cmd_begin(self->port, cmd, 100 * (1 + data_len) / portTICK_RATE_MS); + i2c_cmd_link_delete(cmd); + + if (err == ESP_FAIL) { + return -MP_ENODEV; + } else if (err == ESP_ERR_TIMEOUT) { + return -MP_ETIMEDOUT; + } else if (err != ESP_OK) { + return -abs(err); + } + + return data_len; +} + +/******************************************************************************/ +// MicroPython bindings for machine API + +STATIC void machine_hw_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_hw_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); + int h, l; + i2c_get_period(self->port, &h, &l); + mp_printf(print, "I2C(%u, scl=%u, sda=%u, freq=%u)", + self->port, self->scl, self->sda, I2C_APB_CLK_FREQ / (h + l)); +} + +mp_obj_t machine_hw_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + // Parse args + enum { ARG_id, ARG_scl, ARG_sda, ARG_freq, ARG_timeout }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_scl, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_sda, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = I2C_DEFAULT_TIMEOUT_US} }, + }; + 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); + + // Get I2C bus + mp_int_t i2c_id = mp_obj_get_int(args[ARG_id].u_obj); + if (!(I2C_NUM_0 <= i2c_id && i2c_id < I2C_NUM_MAX)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "I2C(%d) doesn't exist", i2c_id)); + } + + // Get static peripheral object + machine_hw_i2c_obj_t *self = (machine_hw_i2c_obj_t*)&machine_hw_i2c_obj[i2c_id]; + + bool first_init = false; + if (self->base.type == NULL) { + // Created for the first time, set default pins + self->base.type = &machine_hw_i2c_type; + self->port = i2c_id; + if (self->port == I2C_NUM_0) { + self->scl = I2C_0_DEFAULT_SCL; + self->sda = I2C_0_DEFAULT_SDA; + } else { + self->scl = I2C_1_DEFAULT_SCL; + self->sda = I2C_1_DEFAULT_SDA; + } + first_init = true; + } + + // Set SCL/SDA pins if given + if (args[ARG_scl].u_obj != MP_OBJ_NULL) { + self->scl = mp_hal_get_pin_obj(args[ARG_scl].u_obj); + } + if (args[ARG_sda].u_obj != MP_OBJ_NULL) { + self->sda = mp_hal_get_pin_obj(args[ARG_sda].u_obj); + } + + // Initialise the I2C peripheral + machine_hw_i2c_init(self, args[ARG_freq].u_int, args[ARG_timeout].u_int, first_init); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC const mp_machine_i2c_p_t machine_hw_i2c_p = { + .transfer = machine_hw_i2c_transfer, +}; + +STATIC const mp_obj_type_t machine_hw_i2c_type = { + { &mp_type_type }, + .name = MP_QSTR_I2C, + .print = machine_hw_i2c_print, + .make_new = machine_hw_i2c_make_new, + .protocol = &machine_hw_i2c_p, + .locals_dict = (mp_obj_dict_t*)&mp_machine_soft_i2c_locals_dict, +}; diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index bd19c6bfbd..9ffe380fca 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -137,6 +137,7 @@ #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_I2C_MAKE_NEW machine_hw_i2c_make_new #define MICROPY_PY_MACHINE_SPI (1) #define MICROPY_PY_MACHINE_SPI_MSB (0) #define MICROPY_PY_MACHINE_SPI_LSB (1) From 9da46a98cbd20ea8cc48fc2378bf8092abd80795 Mon Sep 17 00:00:00 2001 From: stijn Date: Wed, 17 Jul 2019 12:08:40 +0200 Subject: [PATCH 0563/1788] windows/mpconfigport.h: Don't define restrict/inline/alignof for C++. The C++ standard forbids redefining keywords, like inline and alignof, so guard these definitions to avoid that, allowing to include the MicroPython headers by C++ code. --- ports/windows/mpconfigport.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/windows/mpconfigport.h b/ports/windows/mpconfigport.h index 86e44183bf..ffe7ae1443 100644 --- a/ports/windows/mpconfigport.h +++ b/ports/windows/mpconfigport.h @@ -228,9 +228,11 @@ extern const struct _mp_obj_module_t mp_module_time; // CL specific definitions +#ifndef __cplusplus #define restrict #define inline __inline #define alignof(t) __alignof(t) +#endif #define PATH_MAX MICROPY_ALLOC_PATH_MAX #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) From 331c224e07f5786e0ea814ed1e840ffa714c14fd Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Thu, 11 Jul 2019 14:57:40 +1000 Subject: [PATCH 0564/1788] esp32/Makefile: Fix path expansion for ESPIDF_DRIVER_O. It was using subst to s/.c/.o/ which changed .c anywhere in the path. --- ports/esp32/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 4ce4e48990..2d2db368a3 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -257,7 +257,7 @@ $(HEADER_BUILD)/qstrdefs.generated.h: $(SDKCONFIG_H) ################################################################################ # List of object files from the ESP32 IDF components -ESPIDF_DRIVER_O = $(subst .c,.o,$(wildcard $(ESPCOMP)/driver/*.c)) +ESPIDF_DRIVER_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/driver/*.c)) ESPIDF_EFUSE_O = $(addprefix $(ESPCOMP)/efuse/,\ esp32/esp_efuse_table.o \ From b88e51d718892f3f2fe185e40d949428ef89267d Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 20 Jul 2019 13:02:11 +1000 Subject: [PATCH 0565/1788] esp32/Makefile: Put OBJ and LIB rule additions in gen_espidf_lib_rule. --- ports/esp32/Makefile | 78 +++++++------------------------------------- 1 file changed, 12 insertions(+), 66 deletions(-) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 2d2db368a3..cbb653a582 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -678,76 +678,12 @@ ESPIDF_SDMMC_O = $(addprefix $(ESPCOMP)/sdmmc/,\ ) OBJ_ESPIDF = -OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NEWLIB_O)) -OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_DRIVER_O)) -OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_EFUSE_O)) -OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_ESP32_O)) -OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_ESP_RINGBUF_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_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)) -OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_SDMMC_O)) - -$(OBJ_ESPIDF): $(SDKCONFIG_H) - LIB_ESPIDF = -LIB_ESPIDF += driver -LIB_ESPIDF += efuse -LIB_ESPIDF += esp32 -LIB_ESPIDF += esp_ringbuf -LIB_ESPIDF += heap -LIB_ESPIDF += soc -LIB_ESPIDF += cxx -LIB_ESPIDF += ethernet -LIB_ESPIDF += expat -LIB_ESPIDF += pthread -LIB_ESPIDF += freertos -LIB_ESPIDF += vfs -LIB_ESPIDF += json -LIB_ESPIDF += log -LIB_ESPIDF += xtensa-debug-module -LIB_ESPIDF += tcpip_adapter -LIB_ESPIDF += app_trace -LIB_ESPIDF += app_update -LIB_ESPIDF += newlib -LIB_ESPIDF += nghttp -LIB_ESPIDF += nvs_flash -LIB_ESPIDF += smartconfig_ack -LIB_ESPIDF += spi_flash -LIB_ESPIDF += ulp -LIB_ESPIDF += lwip -LIB_ESPIDF += mbedtls -LIB_ESPIDF += wpa_supplicant -LIB_ESPIDF += sdmmc - BUILD_ESPIDF_LIB = $(BUILD)/esp-idf -OBJ_ESPIDF_DIRS = $(sort $(dir $(OBJ_ESPIDF))) $(BUILD_ESPIDF_LIB) $(addprefix $(BUILD_ESPIDF_LIB)/,$(LIB_ESPIDF)) -$(OBJ_ESPIDF): | $(OBJ_ESPIDF_DIRS) -$(OBJ_ESPIDF_DIRS): - $(MKDIR) -p $@ - define gen_espidf_lib_rule +OBJ_ESPIDF += $(addprefix $$(BUILD)/,$(2)) +LIB_ESPIDF += $(1) $(BUILD_ESPIDF_LIB)/$(1)/lib$(1).a: $(addprefix $$(BUILD)/,$(2)) $(ECHO) "AR $$@" $(Q)$(AR) cru $$@ $$^ @@ -782,6 +718,16 @@ $(eval $(call gen_espidf_lib_rule,mbedtls,$(ESPIDF_MBEDTLS_O))) $(eval $(call gen_espidf_lib_rule,wpa_supplicant,$(ESPIDF_WPA_SUPPLICANT_O))) $(eval $(call gen_espidf_lib_rule,sdmmc,$(ESPIDF_SDMMC_O))) +# Create all destination build dirs before compiling IDF source +OBJ_ESPIDF_DIRS = $(sort $(dir $(OBJ_ESPIDF))) $(BUILD_ESPIDF_LIB) $(addprefix $(BUILD_ESPIDF_LIB)/,$(LIB_ESPIDF)) +$(OBJ_ESPIDF): | $(OBJ_ESPIDF_DIRS) +$(OBJ_ESPIDF_DIRS): + $(MKDIR) -p $@ + +# Make all IDF object files depend on sdkconfig +$(OBJ_ESPIDF): $(SDKCONFIG_H) + +# Add all IDF components to the set of libraries LIB = $(foreach lib,$(LIB_ESPIDF),$(BUILD_ESPIDF_LIB)/$(lib)/lib$(lib).a) ################################################################################ From e3e7e3a781addf8743b783b9f1d464448f1c94bb Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 20 Jul 2019 13:04:20 +1000 Subject: [PATCH 0566/1788] esp32/Makefile: Simplify include of IDF source by using wildcards. --- ports/esp32/Makefile | 435 ++++++------------------------------------- 1 file changed, 55 insertions(+), 380 deletions(-) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index cbb653a582..cb8c88a2d7 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -259,109 +259,34 @@ $(HEADER_BUILD)/qstrdefs.generated.h: $(SDKCONFIG_H) ESPIDF_DRIVER_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/driver/*.c)) -ESPIDF_EFUSE_O = $(addprefix $(ESPCOMP)/efuse/,\ - esp32/esp_efuse_table.o \ - src/esp_efuse_api.o \ - src/esp_efuse_utility.o \ +ESPIDF_EFUSE_O = $(patsubst %.c,%.o,\ + $(wildcard $(ESPCOMP)/efuse/esp32/*.c)\ + $(wildcard $(ESPCOMP)/efuse/src/*.c)\ ) $(BUILD)/$(ESPCOMP)/esp32/dport_access.o: CFLAGS += -Wno-array-bounds -ESPIDF_ESP32_O = $(addprefix $(ESPCOMP)/esp32/,\ - brownout.o \ - cache_sram_mmu.o \ - coexist.o \ - dbg_stubs.o \ - dport_panic_highint_hdl.o \ - esp_adapter.o \ - esp_err_to_name.o \ - esp_himem.o \ - panic.o \ - pm_trace.o \ - reset_reason.o \ - restore.o \ - stack_check.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 \ - 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 \ - pm_esp32.o \ - pm_locks.o \ - intr_alloc.o \ - dport_access.o \ - wifi_init.o \ - sleep_modes.o \ - spiram.o \ - spiram_psram.o \ +ESPIDF_ESP32_O = \ + $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/esp32/*.c)) \ + $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/esp32/hwcrypto/*.c)) \ + $(patsubst %.S,%.o,$(wildcard $(ESPCOMP)/esp32/*.S)) \ + +ESPIDF_ESP_RINGBUF_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/esp_ringbuf/*.c)) + +ESPIDF_HEAP_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/heap/*.c)) + +ESPIDF_SOC_O = $(patsubst %.c,%.o,\ + $(wildcard $(ESPCOMP)/soc/esp32/*.c) \ + $(wildcard $(ESPCOMP)/soc/src/*.c) \ ) -ESPIDF_ESP_RINGBUF_O = $(addprefix $(ESPCOMP)/esp_ringbuf/,\ - ringbuf.o \ +ESPIDF_CXX_O = $(patsubst %.cpp,%.o,$(wildcard $(ESPCOMP)/cxx/*.cpp)) + +ESPIDF_ETHERNET_O = $(patsubst %.c,%.o,\ + $(wildcard $(ESPCOMP)/ethernet/*.c) \ + $(wildcard $(ESPCOMP)/ethernet/eth_phy/*.c) \ ) -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/gpio_periph.o \ - esp32/rtc_clk.o \ - esp32/rtc_init.o \ - esp32/rtc_periph.o \ - esp32/rtc_pm.o \ - esp32/rtc_sleep.o \ - esp32/rtc_time.o \ - esp32/rtc_wdt.o \ - esp32/sdmmc_periph.o \ - esp32/soc_memory_layout.o \ - esp32/spi_periph.o \ - src/memory_layout_utils.o \ - ) - -ESPIDF_CXX_O = $(addprefix $(ESPCOMP)/cxx/,\ - cxx_guards.o \ - ) - -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 += -DHAVE_EXPAT_CONFIG_H -DHAVE_GETRANDOM -ESPIDF_EXPAT_O = $(addprefix $(ESPCOMP)/expat/,\ - expat/expat/lib/xmltok_ns.o \ - expat/expat/lib/xmltok.o \ - expat/expat/lib/xmlparse.o \ - expat/expat/lib/xmlrole.o \ - expat/expat/lib/xmltok_impl.o \ - ) - -ESPIDF_PTHREAD_O = $(addprefix $(ESPCOMP)/pthread/,\ - pthread.o \ - pthread_local_storage.o \ - ) +ESPIDF_PTHREAD_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/pthread/*.c)) # Assembler .S files need only basic flags, and in particular should not have # -Os because that generates subtly different code. @@ -374,308 +299,60 @@ $(BUILD)/$(ESPCOMP)/freertos/xtensa_intr_asm.o: CFLAGS = $(CFLAGS_ASM) $(BUILD)/$(ESPCOMP)/freertos/xtensa_vectors.o: CFLAGS = $(CFLAGS_ASM) $(BUILD)/$(ESPCOMP)/freertos/xtensa_vector_defaults.o: CFLAGS = $(CFLAGS_ASM) $(BUILD)/$(ESPCOMP)/freertos/%.o: CFLAGS = $(CFLAGS_BASE) -I. -I$(BUILD) $(INC_ESPCOMP) -I$(ESPCOMP)/freertos/include/freertos -D_ESP_FREERTOS_INTERNAL -ESPIDF_FREERTOS_O = $(addprefix $(ESPCOMP)/freertos/,\ - croutine.o \ - event_groups.o \ - FreeRTOS-openocd.o \ - list.o \ - portasm.o \ - port.o \ - queue.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_FREERTOS_O = \ + $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/freertos/*.c)) \ + $(patsubst %.S,%.o,$(wildcard $(ESPCOMP)/freertos/*.S)) \ -ESPIDF_VFS_O = $(addprefix $(ESPCOMP)/vfs/,\ - vfs_uart.o \ - vfs.o \ - ) +ESPIDF_VFS_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/vfs/*.c)) -ESPIDF_JSON_O = $(addprefix $(ESPCOMP)/json/cJSON/,\ - cJSON.o \ - cJSON_Utils.o \ - ) +ESPIDF_JSON_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/json/cJSON/cJSON*.c)) -ESPIDF_LOG_O = $(addprefix $(ESPCOMP)/log/,\ - log.o \ - ) +ESPIDF_LOG_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/log/*.c)) -ESPIDF_XTENSA_DEBUG_MODULE_O = $(addprefix $(ESPCOMP)/xtensa-debug-module/,\ - eri.o \ - trax.o \ - ) +ESPIDF_XTENSA_DEBUG_MODULE_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/xtensa-debug-module/*.c)) -ESPIDF_TCPIP_ADAPTER_O = $(addprefix $(ESPCOMP)/tcpip_adapter/,\ - tcpip_adapter_lwip.o \ - ) +ESPIDF_TCPIP_ADAPTER_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/tcpip_adapter/*.c)) -ESPIDF_APP_TRACE_O = $(addprefix $(ESPCOMP)/app_trace/,\ - app_trace.o \ - ) +ESPIDF_APP_TRACE_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/app_trace/*.c)) -ESPIDF_APP_UPDATE_O = $(addprefix $(ESPCOMP)/app_update/,\ - esp_app_desc.o \ - esp_ota_ops.o \ - ) +ESPIDF_APP_UPDATE_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/app_update/*.c)) -ESPIDF_NEWLIB_O = $(addprefix $(ESPCOMP)/newlib/,\ - time.o \ - select.o \ - syscalls.o \ - syscall_table.o \ - reent_init.o \ - locks.o \ - ) +ESPIDF_NEWLIB_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/newlib/*.c)) -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 = $(patsubst %.cpp,%.o,$(wildcard $(ESPCOMP)/nvs_flash/src/*.cpp)) -ESPIDF_NVS_FLASH_O = $(addprefix $(ESPCOMP)/nvs_flash/,\ - src/nvs_ops.o \ - 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_SMARTCONFIG_ACK_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/smartconfig_ack/*.c)) -ESPIDF_OPENSSL_O = $(addprefix $(ESPCOMP)/openssl/,\ - ) +ESPIDF_SPI_FLASH_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/spi_flash/*.c)) -ESPIDF_SMARTCONFIG_ACK_O = $(addprefix $(ESPCOMP)/smartconfig_ack/,\ - smartconfig_ack.o \ - ) - -ESPIDF_SPI_FLASH_O = $(addprefix $(ESPCOMP)/spi_flash/,\ - flash_mmap.o \ - partition.o \ - spi_flash_rom_patch.o \ - cache_utils.o \ - flash_ops.o \ - ) - -ESPIDF_ULP_O = $(addprefix $(ESPCOMP)/ulp/,\ - ulp.o \ - ) +ESPIDF_ULP_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/ulp/*.c)) $(BUILD)/$(ESPCOMP)/lwip/%.o: CFLAGS += -Wno-address -Wno-unused-variable -Wno-unused-but-set-variable -ESPIDF_LWIP_O = $(addprefix $(ESPCOMP)/lwip/,\ - apps/dhcpserver/dhcpserver.o \ - lwip/src/api/netbuf.o \ - lwip/src/api/api_lib.o \ - lwip/src/api/netifapi.o \ - lwip/src/api/tcpip.o \ - lwip/src/api/netdb.o \ - lwip/src/api/err.o \ - lwip/src/api/api_msg.o \ - lwip/src/api/sockets.o \ - lwip/src/apps/sntp/sntp.o \ - lwip/src/core/ipv4/dhcp.o \ - lwip/src/core/ipv4/etharp.o \ - lwip/src/core/ipv4/ip4_addr.o \ - lwip/src/core/ipv4/igmp.o \ - lwip/src/core/ipv4/ip4.o \ - lwip/src/core/ipv4/autoip.o \ - lwip/src/core/ipv4/icmp.o \ - lwip/src/core/ipv6/ip6_frag.o \ - lwip/src/core/ipv6/dhcp6.o \ - lwip/src/core/ipv6/inet6.o \ - lwip/src/core/ipv6/ip6_addr.o \ - lwip/src/core/ipv6/ip6.o \ - lwip/src/core/ipv6/nd6.o \ - lwip/src/core/ipv6/mld6.o \ - lwip/src/core/ipv6/ethip6.o \ - lwip/src/core/ipv6/icmp6.o \ - lwip/src/core/mem.o \ - lwip/src/core/init.o \ - lwip/src/core/memp.o \ - lwip/src/core/sys.o \ - lwip/src/core/tcp_in.o \ - lwip/src/core/timeouts.o \ - lwip/src/core/dns.o \ - lwip/src/core/ip.o \ - lwip/src/core/pbuf.o \ - lwip/src/core/raw.o \ - lwip/src/core/tcp.o \ - lwip/src/core/def.o \ - lwip/src/core/netif.o \ - lwip/src/core/stats.o \ - lwip/src/core/inet_chksum.o \ - lwip/src/core/udp.o \ - lwip/src/core/tcp_out.o \ - lwip/src/netif/slipif.o \ - lwip/src/netif/ethernet.o \ - lwip/src/netif/lowpan6.o \ - lwip/src/netif/ethernetif.o \ - lwip/src/netif/ppp/auth.o \ - lwip/src/netif/ppp/chap-md5.o \ - lwip/src/netif/ppp/chap-new.o \ - lwip/src/netif/ppp/fsm.o \ - lwip/src/netif/ppp/ipcp.o \ - lwip/src/netif/ppp/ipv6cp.o \ - lwip/src/netif/ppp/lcp.o \ - lwip/src/netif/ppp/magic.o \ - lwip/src/netif/ppp/polarssl/md5.o \ - lwip/src/netif/ppp/ppp.o \ - lwip/src/netif/ppp/pppapi.o \ - lwip/src/netif/ppp/pppos.o \ - lwip/src/netif/ppp/upap.o \ - lwip/src/netif/ppp/utils.o \ - lwip/src/netif/ppp/vj.o \ - port/esp32/freertos/sys_arch.o \ - port/esp32/netif/ethernetif.o \ - port/esp32/netif/wlanif.o \ - port/esp32/vfs_lwip.o \ +ESPIDF_LWIP_O = $(patsubst %.c,%.o,\ + $(wildcard $(ESPCOMP)/lwip/apps/dhcpserver/*.c) \ + $(wildcard $(ESPCOMP)/lwip/lwip/src/api/*.c) \ + $(wildcard $(ESPCOMP)/lwip/lwip/src/apps/sntp/*.c) \ + $(wildcard $(ESPCOMP)/lwip/lwip/src/core/*.c) \ + $(wildcard $(ESPCOMP)/lwip/lwip/src/core/*/*.c) \ + $(wildcard $(ESPCOMP)/lwip/lwip/src/netif/*.c) \ + $(wildcard $(ESPCOMP)/lwip/lwip/src/netif/*/*.c) \ + $(wildcard $(ESPCOMP)/lwip/lwip/src/netif/*/*/*.c) \ + $(wildcard $(ESPCOMP)/lwip/port/esp32/*.c) \ + $(wildcard $(ESPCOMP)/lwip/port/esp32/*/*.c) \ ) -ESPIDF_MBEDTLS_O = $(addprefix $(ESPCOMP)/mbedtls/,\ - 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/platform_util.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_mem.o \ - port/esp_sha1.o \ - port/esp_sha256.o \ - port/esp_sha512.o \ +ESPIDF_MBEDTLS_O = $(patsubst %.c,%.o,\ + $(wildcard $(ESPCOMP)/mbedtls/mbedtls/library/*.c) \ + $(wildcard $(ESPCOMP)/mbedtls/port/*.c) \ ) -$(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 \ - 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 \ +$(BUILD)/$(ESPCOMP)/wpa_supplicant/%.o: CFLAGS += -DEMBEDDED_SUPP -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_MSCHAPv2 -DEAP_TTLS -DEAP_TLS -DEAP_PEAP -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -DALLOW_EVEN_MOD -D__ets__ -Wno-strict-aliasing +ESPIDF_WPA_SUPPLICANT_O = $(patsubst %.c,%.o,\ + $(wildcard $(ESPCOMP)/wpa_supplicant/port/*.c) \ + $(wildcard $(ESPCOMP)/wpa_supplicant/src/*/*.c) \ ) -ESPIDF_SDMMC_O = $(addprefix $(ESPCOMP)/sdmmc/,\ - sdmmc_cmd.o \ - sdmmc_common.o \ - sdmmc_init.o \ - sdmmc_mmc.o \ - sdmmc_sd.o \ - sdmmc_io.o \ - ) +ESPIDF_SDMMC_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/sdmmc/*.c)) OBJ_ESPIDF = LIB_ESPIDF = @@ -697,7 +374,6 @@ $(eval $(call gen_espidf_lib_rule,heap,$(ESPIDF_HEAP_O))) $(eval $(call gen_espidf_lib_rule,soc,$(ESPIDF_SOC_O))) $(eval $(call gen_espidf_lib_rule,cxx,$(ESPIDF_CXX_O))) $(eval $(call gen_espidf_lib_rule,ethernet,$(ESPIDF_ETHERNET_O))) -$(eval $(call gen_espidf_lib_rule,expat,$(ESPIDF_EXPAT_O))) $(eval $(call gen_espidf_lib_rule,pthread,$(ESPIDF_PTHREAD_O))) $(eval $(call gen_espidf_lib_rule,freertos,$(ESPIDF_FREERTOS_O))) $(eval $(call gen_espidf_lib_rule,vfs,$(ESPIDF_VFS_O))) @@ -708,7 +384,6 @@ $(eval $(call gen_espidf_lib_rule,tcpip_adapter,$(ESPIDF_TCPIP_ADAPTER_O))) $(eval $(call gen_espidf_lib_rule,app_trace,$(ESPIDF_APP_TRACE_O))) $(eval $(call gen_espidf_lib_rule,app_update,$(ESPIDF_APP_UPDATE_O))) $(eval $(call gen_espidf_lib_rule,newlib,$(ESPIDF_NEWLIB_O))) -$(eval $(call gen_espidf_lib_rule,nghttp,$(ESPIDF_NGHTTP_O))) $(eval $(call gen_espidf_lib_rule,nvs_flash,$(ESPIDF_NVS_FLASH_O))) $(eval $(call gen_espidf_lib_rule,smartconfig_ack,$(ESPIDF_SMARTCONFIG_ACK_O))) $(eval $(call gen_espidf_lib_rule,spi_flash,$(ESPIDF_SPI_FLASH_O))) From 995f9cfdfcda96698c63de7a707981ef8bf2cecc Mon Sep 17 00:00:00 2001 From: Amir Gonnen Date: Mon, 22 Jul 2019 22:59:55 +0300 Subject: [PATCH 0567/1788] esp32: Pin MicroPython tasks to a specific core. On this port the GIL is enabled and everything works under the assumption of the GIL, ie that a given task has exclusive access to the uPy state, and any ISRs interrupt the current task and therefore the ISR inherits exclusive access to the uPy state for the duration of its execution. If the MicroPython tasks are not pinned to a specific core then an ISR may be executed on a different core to the task, making it possible for the main task and an ISR to execute in parallel, breaking the assumption of the GIL. The easiest and safest fix for this is to pin all MicroPython related code to the same CPU core, as done by this patch. Then any ISR that accesses MicroPython state must be registered from a MicroPython task, to ensure it is invoked on the same core. See issue #4895. --- ports/esp32/main.c | 2 +- ports/esp32/mphalport.h | 3 +++ ports/esp32/mpthreadport.c | 5 ++--- ports/esp32/network_ppp.c | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/ports/esp32/main.c b/ports/esp32/main.c index d4f79646f6..c8dde337c5 100644 --- a/ports/esp32/main.c +++ b/ports/esp32/main.c @@ -151,7 +151,7 @@ soft_reset: void app_main(void) { nvs_flash_init(); - xTaskCreate(mp_task, "mp_task", MP_TASK_STACK_LEN, NULL, MP_TASK_PRIORITY, &mp_main_task_handle); + xTaskCreatePinnedToCore(mp_task, "mp_task", MP_TASK_STACK_LEN, NULL, MP_TASK_PRIORITY, &mp_main_task_handle, MP_TASK_COREID); } void nlr_jump_fail(void *val) { diff --git a/ports/esp32/mphalport.h b/ports/esp32/mphalport.h index ff39b7aa1c..575cdbe720 100644 --- a/ports/esp32/mphalport.h +++ b/ports/esp32/mphalport.h @@ -35,6 +35,9 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" +// The core that the MicroPython task(s) are pinned to +#define MP_TASK_COREID (1) + extern TaskHandle_t mp_main_task_handle; extern ringbuf_t stdin_ringbuf; diff --git a/ports/esp32/mpthreadport.c b/ports/esp32/mpthreadport.c index 6c4ed9b5e3..9557d40714 100644 --- a/ports/esp32/mpthreadport.c +++ b/ports/esp32/mpthreadport.c @@ -27,10 +27,9 @@ #include "stdio.h" -#include "py/mpconfig.h" -#include "py/mpstate.h" #include "py/gc.h" #include "py/mpthread.h" +#include "py/mphal.h" #include "mpthreadport.h" #include "esp_task.h" @@ -130,7 +129,7 @@ void mp_thread_create_ex(void *(*entry)(void*), void *arg, size_t *stack_size, i mp_thread_mutex_lock(&thread_mutex, 1); // create thread - BaseType_t result = xTaskCreate(freertos_entry, name, *stack_size / sizeof(StackType_t), arg, priority, &th->id); + BaseType_t result = xTaskCreatePinnedToCore(freertos_entry, name, *stack_size / sizeof(StackType_t), arg, priority, &th->id, MP_TASK_COREID); if (result != pdPASS) { mp_thread_mutex_unlock(&thread_mutex); nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread")); diff --git a/ports/esp32/network_ppp.c b/ports/esp32/network_ppp.c index 8065409158..aca4bbc1e9 100644 --- a/ports/esp32/network_ppp.c +++ b/ports/esp32/network_ppp.c @@ -133,7 +133,7 @@ STATIC mp_obj_t ppp_active(size_t n_args, const mp_obj_t *args) { ppp_set_usepeerdns(self->pcb, 1); pppapi_connect(self->pcb, 0); - xTaskCreate(pppos_client_task, "ppp", 2048, self, 1, (TaskHandle_t*)&self->client_task_handle); + xTaskCreatePinnedToCore(pppos_client_task, "ppp", 2048, self, 1, (TaskHandle_t*)&self->client_task_handle, MP_TASK_COREID); self->active = true; } else { if (!self->active) { From 4d94fae83322dd1b4197fd770fa9d0b7474ce72b Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 10 Jul 2019 16:48:37 +1000 Subject: [PATCH 0568/1788] tools/pyboard.py: Add filesystem commands to ls/cat/cp/rm remote files. Use "-f" to select filesystem mode, followed by the command to execute. Optionally put ":" at the start of a filename to indicate that it's on the remote device, if it would otherwise be ambiguous. Examples: $ pyboard.py -f ls $ pyboard.py -f cat main.py $ pyboard.py -f cp :main.py . # get from device $ pyboard.py -f cp main.py : # put to device $ pyboard.py -f rm main.py --- tools/pyboard.py | 110 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 105 insertions(+), 5 deletions(-) diff --git a/tools/pyboard.py b/tools/pyboard.py index d906235066..c32fb002ca 100755 --- a/tools/pyboard.py +++ b/tools/pyboard.py @@ -4,7 +4,7 @@ # # The MIT License (MIT) # -# Copyright (c) 2014-2016 Damien P. George +# Copyright (c) 2014-2019 Damien P. George # Copyright (c) 2017 Paul Sokolovsky # # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -363,8 +363,8 @@ class Pyboard: ret = ret.strip() return ret - def exec_(self, command): - ret, ret_err = self.exec_raw(command) + def exec_(self, command, data_consumer=None): + ret, ret_err = self.exec_raw(command, data_consumer=data_consumer) if ret_err: raise PyboardError('exception', ret, ret_err) return ret @@ -378,6 +378,52 @@ class Pyboard: t = str(self.eval('pyb.RTC().datetime()'), encoding='utf8')[1:-1].split(', ') return int(t[4]) * 3600 + int(t[5]) * 60 + int(t[6]) + def fs_ls(self, src): + cmd = "import uos\nfor f in uos.ilistdir(%s):\n" \ + " print('{:12} {}{}'.format(f[3]if len(f)>3 else 0,f[0],'/'if f[1]&0x4000 else ''))" % \ + (("'%s'" % src) if src else '') + self.exec_(cmd, data_consumer=stdout_write_bytes) + + def fs_cat(self, src, chunk_size=256): + cmd = "with open('%s') as f:\n while 1:\n" \ + " b=f.read(%u)\n if not b:break\n print(b,end='')" % (src, chunk_size) + self.exec_(cmd, data_consumer=stdout_write_bytes) + + def fs_get(self, src, dest, chunk_size=256): + self.exec_("f=open('%s','rb')\nr=f.read" % src) + with open(dest, 'wb') as f: + while True: + data = bytearray() + self.exec_("print(r(%u))" % chunk_size, data_consumer=lambda d:data.extend(d)) + assert data.endswith(b'\r\n\x04') + data = eval(str(data[:-3], 'ascii')) + if not data: + break + f.write(data) + self.exec_("f.close()") + + def fs_put(self, src, dest, chunk_size=256): + self.exec_("f=open('%s','wb')\nw=f.write" % dest) + with open(src, 'rb') as f: + while True: + data = f.read(chunk_size) + if not data: + break + if sys.version_info < (3,): + self.exec_('w(b' + repr(data) + ')') + else: + self.exec_('w(' + repr(data) + ')') + self.exec_("f.close()") + + def fs_mkdir(self, dir): + self.exec_("import uos\nuos.mkdir('%s')" % dir) + + def fs_rmdir(self, dir): + self.exec_("import uos\nuos.rmdir('%s')" % dir) + + def fs_rm(self, src): + self.exec_("import uos\nuos.remove('%s')" % src) + # in Python2 exec is a keyword so one must use "exec_" # but for Python3 we want to provide the nicer version "exec" setattr(Pyboard, "exec", Pyboard.exec_) @@ -390,6 +436,54 @@ def execfile(filename, device='/dev/ttyACM0', baudrate=115200, user='micro', pas pyb.exit_raw_repl() pyb.close() +def filesystem_command(pyb, args): + def fname_remote(src): + if src.startswith(':'): + src = src[1:] + return src + def fname_cp_dest(src, dest): + src = src.rsplit('/', 1)[-1] + if dest is None or dest == '': + dest = src + elif dest == '.': + dest = './' + src + elif dest.endswith('/'): + dest += src + return dest + + cmd = args[0] + args = args[1:] + try: + if cmd == 'cp': + srcs = args[:-1] + dest = args[-1] + if srcs[0].startswith('./') or dest.startswith(':'): + op = pyb.fs_put + fmt = 'cp %s :%s' + dest = fname_remote(dest) + else: + op = pyb.fs_get + fmt = 'cp :%s %s' + for src in srcs: + src = fname_remote(src) + dest2 = fname_cp_dest(src, dest) + print(fmt % (src, dest2)) + op(src, dest2) + else: + op = {'ls': pyb.fs_ls, 'cat': pyb.fs_cat, 'mkdir': pyb.fs_mkdir, + 'rmdir': pyb.fs_rmdir, 'rm': pyb.fs_rm}[cmd] + if cmd == 'ls' and not args: + args = [''] + for src in args: + src = fname_remote(src) + print('%s :%s' % (cmd, src)) + op(src) + except PyboardError as er: + print(str(er.args[2], 'ascii')) + pyb.exit_raw_repl() + pyb.close() + sys.exit(1) + def main(): import argparse cmd_parser = argparse.ArgumentParser(description='Run scripts on the pyboard.') @@ -400,6 +494,7 @@ def main(): cmd_parser.add_argument('-c', '--command', help='program passed in as string') cmd_parser.add_argument('-w', '--wait', default=0, type=int, help='seconds to wait for USB connected board to become available') cmd_parser.add_argument('--follow', action='store_true', help='follow the output after running the scripts [default if no scripts given]') + cmd_parser.add_argument('-f', '--filesystem', action='store_true', help='perform a filesystem action') cmd_parser.add_argument('files', nargs='*', help='input files') args = cmd_parser.parse_args() @@ -411,7 +506,7 @@ def main(): sys.exit(1) # run any command or file(s) - if args.command is not None or len(args.files): + if args.command is not None or args.filesystem or len(args.files): # we must enter raw-REPL mode to execute commands # this will do a soft-reset of the board try: @@ -436,6 +531,11 @@ def main(): stdout_write_bytes(ret_err) sys.exit(1) + # do filesystem commands, if given + if args.filesystem: + filesystem_command(pyb, args.files) + args.files.clear() + # run the command, if given if args.command is not None: execbuffer(args.command.encode('utf-8')) @@ -450,7 +550,7 @@ def main(): pyb.exit_raw_repl() # if asked explicitly, or no files given, then follow the output - if args.follow or (args.command is None and len(args.files) == 0): + if args.follow or (args.command is None and not args.filesystem and len(args.files) == 0): try: ret, ret_err = pyb.follow(timeout=None, data_consumer=stdout_write_bytes) except PyboardError as er: From 0da2f6f23a8316f6810c47b2d8410bf11029f2a1 Mon Sep 17 00:00:00 2001 From: badlyby Date: Fri, 19 Jul 2019 08:52:48 +0800 Subject: [PATCH 0569/1788] stm32/flashbdev: Support internal filesystem on STM32F722/23/32/33. --- ports/stm32/flash.c | 8 ++++++++ ports/stm32/flashbdev.c | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/ports/stm32/flash.c b/ports/stm32/flash.c index 58cc012793..49cbbe06aa 100644 --- a/ports/stm32/flash.c +++ b/ports/stm32/flash.c @@ -62,11 +62,19 @@ static const flash_layout_t flash_layout[] = { // FLASH_FLAG_ERSERR (Erasing Sequence Error) in STM32F7 #define FLASH_FLAG_PGSERR FLASH_FLAG_ERSERR +#if defined(STM32F722xx) || defined(STM32F723xx) || defined(STM32F732xx) || defined(STM32F733xx) +static const flash_layout_t flash_layout[] = { + { 0x08000000, 0x04000, 4 }, + { 0x08010000, 0x10000, 1 }, + { 0x08020000, 0x20000, 3 }, +}; +#else static const flash_layout_t flash_layout[] = { { 0x08000000, 0x08000, 4 }, { 0x08020000, 0x20000, 1 }, { 0x08040000, 0x40000, 3 }, }; +#endif #elif defined(STM32L0) || defined(STM32L4) || defined(STM32WB) diff --git a/ports/stm32/flashbdev.c b/ports/stm32/flashbdev.c index 470f3d0860..15bf0d6b0a 100644 --- a/ports/stm32/flashbdev.c +++ b/ports/stm32/flashbdev.c @@ -86,6 +86,13 @@ STATIC byte flash_cache_mem[0x4000] __attribute__((aligned(4))); // 16k #define FLASH_MEM_SEG2_START_ADDR (0x08140000) // sector 18 #define FLASH_MEM_SEG2_NUM_BLOCKS (128) // sector 18: 64k(of 128k) +#elif defined(STM32F722xx) || defined(STM32F723xx) || defined(STM32F732xx) || defined(STM32F733xx) + +#define CACHE_MEM_START_ADDR (0x20000000) // DTCM data RAM, 64k +#define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max +#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(STM32F746xx) || defined(STM32F765xx) || defined(STM32F767xx) || defined(STM32F769xx) // The STM32F746 doesn't really have CCRAM, so we use the 64K DTCM for this. From 09267bb147c06ef5350b91034342924a9d9efa05 Mon Sep 17 00:00:00 2001 From: badlyby Date: Fri, 19 Jul 2019 08:58:02 +0800 Subject: [PATCH 0570/1788] stm32/boards/stm32f722.ld: Provide memory regions for internal FS. --- ports/stm32/boards/stm32f722.ld | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ports/stm32/boards/stm32f722.ld b/ports/stm32/boards/stm32f722.ld index ab41f0ea90..fe84a49637 100644 --- a/ports/stm32/boards/stm32f722.ld +++ b/ports/stm32/boards/stm32f722.ld @@ -6,9 +6,11 @@ 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 */ + FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 16K /* sector 0, 16K */ + FLASH_FS (r) : ORIGIN = 0x08004000, LENGTH = 112K /* sectors 1-4 3*16KiB 1*64KiB*/ + FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 384K /* sectors 5-7 3*128KiB = 384K */ + DTCM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K /* Used for storage cache */ + RAM (xrw) : ORIGIN = 0x20010000, LENGTH = 192K /* SRAM1 = 176K, SRAM2 = 16K */ } /* produce a link error if there is not this amount of RAM for these sections */ From 3b258ef213d34b402c170fbb63dafbab53ea91b2 Mon Sep 17 00:00:00 2001 From: badlyby Date: Fri, 19 Jul 2019 21:44:16 +0800 Subject: [PATCH 0571/1788] stm32/boards/NUCLEO_F722ZE: Add definition files for new board. --- ports/stm32/boards/NUCLEO_F722ZE/board_init.c | 8 ++ .../boards/NUCLEO_F722ZE/mpconfigboard.h | 68 ++++++++++++ .../boards/NUCLEO_F722ZE/mpconfigboard.mk | 6 + ports/stm32/boards/NUCLEO_F722ZE/pins.csv | 104 ++++++++++++++++++ .../boards/NUCLEO_F722ZE/stm32f7xx_hal_conf.h | 18 +++ 5 files changed, 204 insertions(+) create mode 100644 ports/stm32/boards/NUCLEO_F722ZE/board_init.c create mode 100644 ports/stm32/boards/NUCLEO_F722ZE/mpconfigboard.h create mode 100644 ports/stm32/boards/NUCLEO_F722ZE/mpconfigboard.mk create mode 100644 ports/stm32/boards/NUCLEO_F722ZE/pins.csv create mode 100644 ports/stm32/boards/NUCLEO_F722ZE/stm32f7xx_hal_conf.h diff --git a/ports/stm32/boards/NUCLEO_F722ZE/board_init.c b/ports/stm32/boards/NUCLEO_F722ZE/board_init.c new file mode 100644 index 0000000000..5a7c6052af --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F722ZE/board_init.c @@ -0,0 +1,8 @@ +#include "py/mphal.h" + +void 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_F722ZE/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F722ZE/mpconfigboard.h new file mode 100644 index 0000000000..5a7f650067 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F722ZE/mpconfigboard.h @@ -0,0 +1,68 @@ +// 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-F722ZE" +#define MICROPY_HW_MCU_NAME "STM32F722" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_USB (1) + +#define MICROPY_BOARD_EARLY_INIT board_early_init +void board_early_init(void); + +// HSE is 8MHz, run SYSCLK at 216MHz +#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) +#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 buses +#define MICROPY_HW_I2C1_SCL (pin_B8) +#define MICROPY_HW_I2C1_SDA (pin_B9) + +// SPI buses +#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) + +// CAN buses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) + +// USRSW is pulled low, and 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_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_F722ZE/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F722ZE/mpconfigboard.mk new file mode 100644 index 0000000000..667c8e55da --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F722ZE/mpconfigboard.mk @@ -0,0 +1,6 @@ +MCU_SERIES = f7 +CMSIS_MCU = STM32F722xx +AF_FILE = boards/stm32f722_af.csv +LD_FILES = boards/stm32f722.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/NUCLEO_F722ZE/pins.csv b/ports/stm32/boards/NUCLEO_F722ZE/pins.csv new file mode 100644 index 0000000000..228d83a026 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F722ZE/pins.csv @@ -0,0 +1,104 @@ +A0,PA3 +A1,PC0 +A2,PC3 +A3,PF3 +A4,PF5 +A5,PF10 +A6,PB1 +A7,PC2 +A8,PF4 +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 +D26,PB6 +D27,PB2 +D28,PD13 +D29,PD12 +D30,PD11 +D31,PE2 +D32,PA0 +D33,PB0 +D34,PE0 +D35,PB11 +D36,PB10 +D37,PE15 +D38,PE14 +D39,PE12 +D40,PE10 +D41,PE7 +D42,PE8 +D43,PC8 +D44,PC9 +D45,PC10 +D46,PC11 +D47,PC12 +D48,PD2 +D49,PG2 +D50,PG3 +D51,PD7 +D52,PD6 +D53,PD5 +D54,PD4 +D55,PD3 +D56,PE2 +D57,PE4 +D58,PE5 +D59,PE6 +D60,PE3 +D61,PF8 +D62,PF7 +D63,PF9 +D64,PG1 +D65,PG0 +D66,PD1 +D67,PD0 +D68,PF0 +D69,PF1 +D70,PF2 +D71,PA7 +LED1,PB0 +LED2,PB7 +LED3,PB14 +SW,PC13 +SD_SW,PC13 +OTG_FS_POWER,PG6 +OTG_FS_OVER_CURRENT,PG7 +USB_VBUS,PA9 +USB_ID,PA10 +USB_DM,PA11 +USB_DP,PA12 +USB_POWER,PG6 +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_F722ZE/stm32f7xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F722ZE/stm32f7xx_hal_conf.h new file mode 100644 index 0000000000..9355a3867d --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F722ZE/stm32f7xx_hal_conf.h @@ -0,0 +1,18 @@ +/* This file is part of the MicroPython project, http://micropython.org/ + * MIT License; Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32F7XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F7XX_HAL_CONF_H + +#include "boards/stm32f7xx_hal_conf_base.h" + +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) + +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (5000) +#define LSE_STARTUP_TIMEOUT (5000) + +#endif // MICROPY_INCLUDED_STM32F7XX_HAL_CONF_H From e9593d50755cfdd157d1bd67a02a1314f9ccedb5 Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Sun, 21 Jul 2019 23:23:11 +0300 Subject: [PATCH 0572/1788] py/sequence: Fix grammar in comment about equality. --- py/sequence.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/sequence.c b/py/sequence.c index c66fde98f6..4c19fc69ea 100644 --- a/py/sequence.c +++ b/py/sequence.c @@ -165,7 +165,7 @@ bool mp_seq_cmp_bytes(mp_uint_t op, const byte *data1, size_t len1, const byte * size_t min_len = len1 < len2 ? len1 : len2; int res = memcmp(data1, data2, min_len); if (op == MP_BINARY_OP_EQUAL) { - // If we are checking for equality, here're the answer + // If we are checking for equality, here's the answer return res == 0; } if (res < 0) { From b1129df4780abc5f140b473d10ebe5316793aac2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 25 Jul 2019 15:16:57 +1000 Subject: [PATCH 0573/1788] stm32/dma: Fix re-start of DMA stream by clearing all event flags. As per the datasheet, all event flags for a stream must be cleared before enabling it. Fixes issue #4944 (with DAC.write_timed). --- ports/stm32/dma.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c index 8a3f743fe7..3d275684d2 100644 --- a/ports/stm32/dma.c +++ b/ports/stm32/dma.c @@ -922,6 +922,30 @@ void dma_nohal_deinit(const dma_descr_t *descr) { } void dma_nohal_start(const dma_descr_t *descr, uint32_t src_addr, uint32_t dst_addr, uint16_t len) { + // Must clear all event flags for this stream before enabling it + DMA_TypeDef *dma_ctrl; + uint32_t ch = descr->id; + if (ch < NSTREAMS_PER_CONTROLLER) { + dma_ctrl = DMA1; + } else { + dma_ctrl = DMA2; + ch -= NSTREAMS_PER_CONTROLLER; + } + __IO uint32_t *ifcr; + if (ch <= 3) { + ifcr = &dma_ctrl->LIFCR; + } else { + ifcr = &dma_ctrl->HIFCR; + ch -= 4; + } + if (ch <= 1) { + ch = ch * 6; + } else { + ch = 4 + ch * 6; + } + *ifcr = 0x3d << ch; + + // Configure and enable stream DMA_Stream_TypeDef *dma = descr->instance; dma->CR &= ~DMA_SxCR_DBM; dma->NDTR = len; From fa07deda9f129c1992726d2a51c6eaac168247f0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 25 Jul 2019 17:42:17 +1000 Subject: [PATCH 0574/1788] stm32/usbd_hid_interface: Rewrite USB HID interface code. The previous version did not work on MCUs that only had USB device mode (compared to OTG) because of the handling of NAK. And this previous handling of NAK had a race condition where a new packet could come in before USBD_HID_SetNAK was called (since USBD_HID_ReceivePacket clears NAK as part of its operation). Furthermore, the double buffering of incoming reports was not working, only one buffer could be used at a time. This commit rewrites the HID interface code to have a single incoming buffer, and only calls USBD_HID_ReceivePacket after the user has read the incoming report (similar to how the VCP does its flow control). As such, USBD_HID_SetNAK and USBD_HID_ClearNAK are no longer needed. API functionality from the user's point of view should be unchanged with this commit. --- ports/stm32/usb.c | 5 + ports/stm32/usbd_hid_interface.c | 127 ++++++------------ ports/stm32/usbd_hid_interface.h | 16 ++- .../stm32/usbdev/class/src/usbd_cdc_msc_hid.c | 24 ---- 4 files changed, 57 insertions(+), 115 deletions(-) diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index 2d1f6084fe..3308f07449 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -787,6 +787,11 @@ STATIC mp_obj_t pyb_usb_hid_recv(size_t n_args, const mp_obj_t *args, mp_map_t * // receive the data int ret = usbd_hid_rx(&self->usb_dev->usbd_hid_itf, vstr.len, (uint8_t*)vstr.buf, vals[1].u_int); + if (ret < 0) { + // error, just return 0/empty bytes + ret = 0; + } + // return the received data if (o_ret != MP_OBJ_NULL) { return mp_obj_new_int(ret); // number of bytes read into given buffer diff --git a/ports/stm32/usbd_hid_interface.c b/ports/stm32/usbd_hid_interface.c index 033d83ea64..386cf34d70 100644 --- a/ports/stm32/usbd_hid_interface.c +++ b/ports/stm32/usbd_hid_interface.c @@ -1,113 +1,70 @@ /* * This file is part of the MicroPython project, http://micropython.org/ * - * Taken from ST Cube library and heavily modified. See below for original - * copyright header. + * The MIT License (MIT) + * + * Copyright (c) 2019 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. */ -/** - ****************************************************************************** - * @file USB_Device/CDC_Standalone/Src/usbd_cdc_interface.c - * @author MCD Application Team - * @version V1.0.1 - * @date 26-February-2014 - * @brief Source file for USBD CDC interface - ****************************************************************************** - * @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 - #include "usbd_hid_interface.h" -#include "py/obj.h" -#include "irq.h" +#include "py/mperrno.h" +#include "py/mphal.h" #include "usb.h" #if MICROPY_HW_USB_HID 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; - - // Return the buffer to place the first USB OUT packet - return hid->buffer[hid->current_write_buffer]; + hid->report_in_len = USBD_HID_REPORT_INVALID; + return &hid->report_in_buf[0]; // location to place first incoming report } -// 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_state_t *hid_in, size_t len) { + // Incoming report: save the length but don't schedule next report until user reads this one 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->base, hid->buffer[hid->current_write_buffer]); - // Set NAK to indicate we need to process read buffer - USBD_HID_SetNAK(&hid->base); + hid->report_in_len = len; return USBD_OK; } -// Returns number of ready rx buffers. -int usbd_hid_rx_num(usbd_hid_itf_t *hid) { - return hid->current_read_buffer != hid->current_write_buffer; -} - -// timout in milliseconds. -// Returns number of bytes read from the device. -int usbd_hid_rx(usbd_hid_itf_t *hid, size_t len, uint8_t *buf, uint32_t timeout) { - // Wait until we have buffer to read - uint32_t start = HAL_GetTick(); - while (hid->current_read_buffer == hid->current_write_buffer) { - // Wraparound of tick is taken care of by 2's complement arithmetic. - if (HAL_GetTick() - start >= timeout) { - // timeout - return 0; +int usbd_hid_rx(usbd_hid_itf_t *hid, size_t len, uint8_t *buf, uint32_t timeout_ms) { + // Wait for an incoming report + uint32_t t0 = mp_hal_ticks_ms(); + while (hid->report_in_len == USBD_HID_REPORT_INVALID) { + if (mp_hal_ticks_ms() - t0 >= timeout_ms || query_irq() == IRQ_STATE_DISABLED) { + return -MP_ETIMEDOUT; } - if (query_irq() == IRQ_STATE_DISABLED) { - // IRQs disabled so buffer will never be filled; return immediately - return 0; - } - __WFI(); // enter sleep mode, waiting for interrupt + MICROPY_EVENT_POLL_HOOK } - // There is not enough space in buffer - if (len < hid->last_read_len) { - return 0; - } + // Copy bytes from report to user buffer + int n = MIN(len, hid->report_in_len); + memcpy(buf, &hid->report_in_buf[0], n); - // Copy bytes from device to user buffer - 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; + // Schedule to receive next incoming report + hid->report_in_len = USBD_HID_REPORT_INVALID; + USBD_HID_ReceivePacket(&hid->base, &hid->report_in_buf[0]); - // Clear NAK to indicate we are ready to read more data - USBD_HID_ClearNAK(&hid->base); - - // Success, return number of bytes read - return read_len; + // Return number of bytes read into user buffer + return n; } #endif // MICROPY_HW_USB_HID diff --git a/ports/stm32/usbd_hid_interface.h b/ports/stm32/usbd_hid_interface.h index 777fa93403..5d2c9ad870 100644 --- a/ports/stm32/usbd_hid_interface.h +++ b/ports/stm32/usbd_hid_interface.h @@ -4,18 +4,22 @@ #ifndef MICROPY_INCLUDED_STM32_USBD_HID_INTERFACE_H #define MICROPY_INCLUDED_STM32_USBD_HID_INTERFACE_H +#include #include "usbd_cdc_msc_hid.h" +#define USBD_HID_REPORT_INVALID ((size_t)-1) + typedef struct _usbd_hid_itf_t { 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 - uint32_t last_read_len; // length of last read - int8_t current_write_buffer; // which buffer to write to + volatile size_t report_in_len; + uint8_t report_in_buf[HID_DATA_FS_MAX_PACKET_SIZE]; } 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); +static inline int usbd_hid_rx_num(usbd_hid_itf_t *hid) { + return hid->report_in_len != USBD_HID_REPORT_INVALID; +} + +int usbd_hid_rx(usbd_hid_itf_t *hid, size_t len, uint8_t *buf, uint32_t timeout_ms); #endif // MICROPY_INCLUDED_STM32_USBD_HID_INTERFACE_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 32ce4ca875..e13a93ddbc 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -1190,30 +1190,6 @@ uint8_t USBD_HID_SendReport(usbd_hid_state_t *hid, uint8_t *report, uint16_t len return USBD_FAIL; } -uint8_t USBD_HID_SetNAK(usbd_hid_state_t *hid) { - // get USBx object from pdev (needed for USBx_OUTEP macro below) - PCD_HandleTypeDef *hpcd = hid->usbd->pdev->pData; - USB_OTG_GlobalTypeDef *USBx = hpcd->Instance; - #if defined(STM32H7) - uint32_t USBx_BASE = (uint32_t)USBx; - #endif - // 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_hid_state_t *hid) { - // get USBx object from pdev (needed for USBx_OUTEP macro below) - PCD_HandleTypeDef *hpcd = hid->usbd->pdev->pData; - USB_OTG_GlobalTypeDef *USBx = hpcd->Instance; - #if defined(STM32H7) - uint32_t USBx_BASE = (uint32_t)USBx; - #endif - // clear NAK on HID OUT endpoint - USBx_OUTEP(HID_OUT_EP_WITH_CDC)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; - return USBD_OK; -} - #endif // CDC/MSC/HID interface class callback structure From ad0b7cb017acf8f26db8ca630013abbff61abc75 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 25 Jul 2019 17:49:53 +1000 Subject: [PATCH 0575/1788] stm32/boards/xxx_WB55: Enable USB HID now that it works on WB MCUs. --- ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h | 1 - ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.h | 1 - 2 files changed, 2 deletions(-) diff --git a/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h b/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h index fc047880d1..beca216569 100644 --- a/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h @@ -59,6 +59,5 @@ // USB config #define MICROPY_HW_USB_FS (1) -#define MICROPY_HW_USB_HID (0) #define USBD_CDC_RX_DATA_SIZE (512) #define USBD_CDC_TX_DATA_SIZE (512) diff --git a/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.h b/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.h index 77e2d4f329..eebf30f628 100644 --- a/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.h +++ b/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.h @@ -38,6 +38,5 @@ // USB config #define MICROPY_HW_USB_FS (1) -#define MICROPY_HW_USB_HID (0) #define USBD_CDC_RX_DATA_SIZE (512) #define USBD_CDC_TX_DATA_SIZE (512) From 473157eeb9f88b3d62a963af087014920a47d624 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 26 Jul 2019 12:44:14 +1000 Subject: [PATCH 0576/1788] stm32/usbd_hid_interface: Include extra header to build with threading. --- ports/stm32/usbd_hid_interface.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/stm32/usbd_hid_interface.c b/ports/stm32/usbd_hid_interface.c index 386cf34d70..8dc39f53d8 100644 --- a/ports/stm32/usbd_hid_interface.c +++ b/ports/stm32/usbd_hid_interface.c @@ -26,6 +26,7 @@ #include "usbd_hid_interface.h" +#include "py/mpstate.h" #include "py/mperrno.h" #include "py/mphal.h" #include "usb.h" From 8f55a8fab625d645b189c471f3a32c0de7e5ef7d Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 26 Jul 2019 12:44:47 +1000 Subject: [PATCH 0577/1788] travis: Build an stm32 board with threading enabled to test it with CI. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1229e6e689..e319f095b1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,7 +37,7 @@ jobs: - 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=PYBD_SF2 - - make ${MAKEOPTS} -C ports/stm32 BOARD=STM32F769DISC + - make ${MAKEOPTS} -C ports/stm32 BOARD=STM32F769DISC CFLAGS_EXTRA='-DMICROPY_PY_THREAD=1' - make ${MAKEOPTS} -C ports/stm32 BOARD=STM32L476DISC - make ${MAKEOPTS} -C ports/stm32/mboot BOARD=PYBD_SF6 From 01054f20925b92229402750979864f8d38a76916 Mon Sep 17 00:00:00 2001 From: Eric Poulsen Date: Tue, 16 Jul 2019 14:29:22 -0700 Subject: [PATCH 0578/1788] py/objdict: Quote non-string types when used as keys in JSON output. JSON requires that keys of objects be strings. CPython will therefore automatically quote simple types (NoneType, bool, int, float) when they are used directly as keys in JSON output. To prevent subtle bugs and emit compliant JSON, MicroPython should at least test for such keys so they aren't silently let through. Then doing the actual quoting is a similar cost to raising an exception, so that's what is implemented by this patch. Fixes issue #4790. --- py/objdict.c | 8 ++++++++ tests/extmod/ujson_dumps.py | 4 ++++ tests/extmod/ujson_dumps_float.py | 1 + 3 files changed, 13 insertions(+) diff --git a/py/objdict.c b/py/objdict.c index 0a223f7314..02a2346fde 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -31,6 +31,7 @@ #include "py/runtime.h" #include "py/builtin.h" #include "py/objtype.h" +#include "py/objstr.h" #define mp_obj_is_dict_type(o) (mp_obj_is_obj(o) && ((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type->make_new == dict_make_new) @@ -70,7 +71,14 @@ STATIC void dict_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_ mp_print_str(print, ", "); } first = false; + bool add_quote = MICROPY_PY_UJSON && kind == PRINT_JSON && !mp_obj_is_str_or_bytes(next->key); + if (add_quote) { + mp_print_str(print, "\""); + } mp_obj_print_helper(print, next->key, kind); + if (add_quote) { + mp_print_str(print, "\""); + } mp_print_str(print, ": "); mp_obj_print_helper(print, next->value, kind); } diff --git a/tests/extmod/ujson_dumps.py b/tests/extmod/ujson_dumps.py index d732718019..c33126cec6 100644 --- a/tests/extmod/ujson_dumps.py +++ b/tests/extmod/ujson_dumps.py @@ -26,3 +26,7 @@ print(json.dumps({"a":1})) print(json.dumps({"a":(2,[3,None])})) print(json.dumps('"quoted"')) print(json.dumps('space\n\r\tspace')) +print(json.dumps({None: -1})) +print(json.dumps({False: 0})) +print(json.dumps({True: 1})) +print(json.dumps({1: 2})) diff --git a/tests/extmod/ujson_dumps_float.py b/tests/extmod/ujson_dumps_float.py index e8cceb6f1a..40adb1e267 100644 --- a/tests/extmod/ujson_dumps_float.py +++ b/tests/extmod/ujson_dumps_float.py @@ -8,3 +8,4 @@ except ImportError: raise SystemExit print(json.dumps(1.2)) +print(json.dumps({1.5: 'hi'})) From 7c15e50eb880f7246fca3fdd11c967b151117ddf Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 30 Jul 2019 17:31:23 +1000 Subject: [PATCH 0579/1788] esp32/Makefile: Include CFLAGS_EXTRA in CFLAGS definition. Following other ports, so builds can be customised more easily, eg on the command line building with a user C-module. --- ports/esp32/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index cb8c88a2d7..c6ef04b465 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -126,7 +126,7 @@ CFLAGS_COMMON = -Os -ffunction-sections -fdata-sections -fstrict-volatile-bitfie 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) +CFLAGS += $(CFLAGS_MOD) $(CFLAGS_EXTRA) # this is what ESPIDF uses for c++ compilation CXXFLAGS = -std=gnu++11 $(CFLAGS_COMMON) $(INC) $(INC_ESPCOMP) From a8e3201b376d931a77e66dc80293c570983f9c7b Mon Sep 17 00:00:00 2001 From: "Paul m. p. P" Date: Mon, 8 Jul 2019 11:26:20 +0200 Subject: [PATCH 0580/1788] py/builtinimport: Populate __file__ when importing frozen or mpy files. Note that bytecode already includes the source filename as a qstr so there is no additional memory used by the interning operation here. --- py/builtinimport.c | 12 ++++++------ tests/unix/extra_coverage.py | 6 ++++-- tests/unix/extra_coverage.py.exp | 6 ++++-- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/py/builtinimport.c b/py/builtinimport.c index 1a333b5404..008a21dcff 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -145,11 +145,11 @@ STATIC void do_load_from_lexer(mp_obj_t module_obj, mp_lexer_t *lex) { #endif #if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_MODULE_FROZEN_MPY -STATIC void do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code) { +STATIC void do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code, const char* source_name) { + (void)source_name; + #if MICROPY_PY___FILE__ - // TODO - //qstr source_name = lex->source_name; - //mp_store_attr(module_obj, MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); + mp_store_attr(module_obj, MP_QSTR___file__, MP_OBJ_NEW_QSTR(qstr_from_str(source_name))); #endif // execute the module in its context @@ -206,7 +206,7 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) { // its data) in the list of frozen files, execute it. #if MICROPY_MODULE_FROZEN_MPY if (frozen_type == MP_FROZEN_MPY) { - do_execute_raw_code(module_obj, modref); + do_execute_raw_code(module_obj, modref, file_str); return; } #endif @@ -216,7 +216,7 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) { #if MICROPY_HAS_FILE_READER && MICROPY_PERSISTENT_CODE_LOAD if (file_str[file->len - 3] == 'm') { mp_raw_code_t *raw_code = mp_raw_code_load_file(file_str); - do_execute_raw_code(module_obj, raw_code); + do_execute_raw_code(module_obj, raw_code, file_str); return; } #endif diff --git a/tests/unix/extra_coverage.py b/tests/unix/extra_coverage.py index 13721f1f47..cb68bae4d9 100644 --- a/tests/unix/extra_coverage.py +++ b/tests/unix/extra_coverage.py @@ -48,13 +48,15 @@ print(buf.write(bytearray(16))) # test basic import of frozen scripts import frzstr1 +print(frzstr1.__file__) import frzmpy1 +print(frzmpy1.__file__) # test import of frozen packages with __init__.py import frzstr_pkg1 -print(frzstr_pkg1.x) +print(frzstr_pkg1.__file__, frzstr_pkg1.x) import frzmpy_pkg1 -print(frzmpy_pkg1.x) +print(frzmpy_pkg1.__file__, frzmpy_pkg1.x) # test import of frozen packages without __init__.py from frzstr_pkg2.mod import Foo diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index 6c483f7e54..a9889c0e95 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -94,11 +94,13 @@ OSError None None frzstr1 +frzstr1.py frzmpy1 +frzmpy1.py frzstr_pkg1.__init__ -1 +frzstr_pkg1/__init__.py 1 frzmpy_pkg1.__init__ -1 +frzmpy_pkg1/__init__.py 1 frzstr_pkg2.mod 1 frzmpy_pkg2.mod From 60f1063797716cfec14c84afafec69bf06127777 Mon Sep 17 00:00:00 2001 From: "Paul m. p. P" Date: Fri, 19 Jul 2019 00:54:12 +0200 Subject: [PATCH 0581/1788] py/runtime: Allow to override builtins.__import__ with Python func. This patch adds a simple but powerful hook into the import system, in a CPython compatible way, by allowing to override builtins.__import__. This does introduce some overhead to all imports but it's minor: - the dict lookup of __import__ is bypassed if there are no modifications to the builtins module (which is the case at start up); - imports are not performance critical, usually done just at the start of a script; - compared to how much work is done in an import, looking up a value in a dict is a relatively small additional piece of work. --- py/runtime.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/py/runtime.c b/py/runtime.c index e502566059..70d7957198 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -1335,7 +1335,17 @@ mp_obj_t mp_import_name(qstr name, mp_obj_t fromlist, mp_obj_t level) { args[3] = fromlist; args[4] = level; - // TODO lookup __import__ and call that instead of going straight to builtin implementation + #if MICROPY_CAN_OVERRIDE_BUILTINS + // Lookup __import__ and call that if it exists + mp_obj_dict_t *bo_dict = MP_STATE_VM(mp_module_builtins_override_dict); + if (bo_dict != NULL) { + mp_map_elem_t *import = mp_map_lookup(&bo_dict->map, MP_OBJ_NEW_QSTR(MP_QSTR___import__), MP_MAP_LOOKUP); + if (import != NULL) { + return mp_call_function_n_kw(import->value, 5, 0, args); + } + } + #endif + return mp_builtin___import__(5, args); } From f60229e261e61b59d563023b2df7204c4e01c51c Mon Sep 17 00:00:00 2001 From: "Paul m. p. P" Date: Fri, 19 Jul 2019 00:56:40 +0200 Subject: [PATCH 0582/1788] py/modio: Call mp_import_name to do resource stream import. So code is not duplicated and it can take advantage of __import__ being overridden. --- py/modio.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/py/modio.c b/py/modio.c index 0f4a4326ca..94ef5d42e2 100644 --- a/py/modio.c +++ b/py/modio.c @@ -208,15 +208,8 @@ STATIC mp_obj_t resource_stream(mp_obj_t package_in, mp_obj_t path_in) { // package parameter being None, the path_in is interpreted as a // raw path. if (package_in != mp_const_none) { - mp_obj_t args[5]; - args[0] = package_in; - args[1] = mp_const_none; // TODO should be globals - args[2] = mp_const_none; // TODO should be locals - args[3] = mp_const_true; // Pass sentinel "non empty" value to force returning of leaf module - args[4] = MP_OBJ_NEW_SMALL_INT(0); - - // TODO lookup __import__ and call that instead of going straight to builtin implementation - mp_obj_t pkg = mp_builtin___import__(5, args); + // Pass "True" as sentinel value in fromlist to force returning of leaf module + mp_obj_t pkg = mp_import_name(mp_obj_str_get_qstr(package_in), mp_const_true, MP_OBJ_NEW_SMALL_INT(0)); mp_obj_t dest[2]; mp_load_method_maybe(pkg, MP_QSTR___path__, dest); From 48f43b77aa62b99147d52b794da26621bbd74ee8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 31 Jul 2019 22:34:43 +1000 Subject: [PATCH 0583/1788] tests: Add tests for overriding builtins.__import__. --- tests/basics/builtin_override.py | 18 ++++++++++++++++++ tests/import/import_override.py | 17 +++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 tests/import/import_override.py diff --git a/tests/basics/builtin_override.py b/tests/basics/builtin_override.py index 9f91341edd..e3cf9165fc 100644 --- a/tests/basics/builtin_override.py +++ b/tests/basics/builtin_override.py @@ -12,7 +12,25 @@ except AttributeError: print(abs(1)) # __build_class__ is handled in a special way +orig_build_class = __build_class__ builtins.__build_class__ = lambda x, y: ('class', y) class A: pass print(A) +builtins.__build_class__ = orig_build_class + +# __import__ is handled in a special way +def custom_import(name, globals, locals, fromlist, level): + print('import', name, fromlist, level) + class M: + a = 1 + b = 2 + return M +builtins.__import__ = custom_import +__import__('A', None, None, None, 0) +import a +import a.b +from a import a +from a.b import a, b +from .a import a +from ..a import a, b diff --git a/tests/import/import_override.py b/tests/import/import_override.py new file mode 100644 index 0000000000..6fe99009ee --- /dev/null +++ b/tests/import/import_override.py @@ -0,0 +1,17 @@ +# test overriding __import__ combined with importing from the filesystem + +def custom_import(name, globals, locals, fromlist, level): + print('import', name, fromlist, level) + class M: + var = 456 + return M + +orig_import = __import__ +try: + __import__("builtins").__import__ = custom_import +except AttributeError: + print("SKIP") + raise SystemExit + +# import1a will be done via normal import which will import1b via our custom import +orig_import('import1a') From 00e7fe8ab109a21e62ce367ebd9cc6a5dfb48803 Mon Sep 17 00:00:00 2001 From: Arsenijs Date: Tue, 30 Jul 2019 01:42:33 +0300 Subject: [PATCH 0584/1788] docs/library/framebuf: Add missing module reference in example code. --- docs/library/framebuf.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/library/framebuf.rst b/docs/library/framebuf.rst index ed4b78ab14..b6d7dba5de 100644 --- a/docs/library/framebuf.rst +++ b/docs/library/framebuf.rst @@ -19,7 +19,7 @@ For example:: import framebuf # FrameBuffer needs 2 bytes for every RGB565 pixel - fbuf = FrameBuffer(bytearray(10 * 100 * 2), 10, 100, framebuf.RGB565) + fbuf = framebuf.FrameBuffer(bytearray(10 * 100 * 2), 10, 100, framebuf.RGB565) fbuf.fill(0) fbuf.text('MicroPython!', 0, 0, 0xffff) From 80f5cef8d4937d1312a823a2a42c46b5140e5595 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 24 Jul 2019 17:05:02 +1000 Subject: [PATCH 0585/1788] extmod/modlwip: Implement raw sockets for lwIP. Configurable via MICROPY_PY_LWIP_SOCK_RAW. --- extmod/modlwip.c | 124 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 101 insertions(+), 23 deletions(-) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index be932b6a9d..050937750a 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -40,7 +40,7 @@ #include "lwip/init.h" #include "lwip/tcp.h" #include "lwip/udp.h" -//#include "lwip/raw.h" +#include "lwip/raw.h" #include "lwip/dns.h" #include "lwip/igmp.h" #if LWIP_VERSION_MAJOR < 2 @@ -280,6 +280,7 @@ typedef struct _lwip_socket_obj_t { volatile union { struct tcp_pcb *tcp; struct udp_pcb *udp; + struct raw_pcb *raw; } pcb; volatile union { struct pbuf *pbuf; @@ -361,6 +362,26 @@ static inline void exec_user_callback(lwip_socket_obj_t *socket) { } } +#if MICROPY_PY_LWIP_SOCK_RAW +// Callback for incoming raw packets. +#if LWIP_VERSION_MAJOR < 2 +STATIC u8_t _lwip_raw_incoming(void *arg, struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *addr) +#else +STATIC u8_t _lwip_raw_incoming(void *arg, struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *addr) +#endif +{ + lwip_socket_obj_t *socket = (lwip_socket_obj_t*)arg; + + if (socket->incoming.pbuf != NULL) { + pbuf_free(p); + } else { + socket->incoming.pbuf = p; + memcpy(&socket->peer, addr, sizeof(socket->peer)); + } + return 1; // we ate the packet +} +#endif + // Callback for incoming UDP packets. We simply stash the packet and the source address, // in case we need it for recvfrom. #if LWIP_VERSION_MAJOR < 2 @@ -515,8 +536,8 @@ STATIC err_t _lwip_tcp_recv(void *arg, struct tcp_pcb *tcpb, struct pbuf *p, err // Functions for socket send/receive operations. Socket send/recv and friends call // these to do the work. -// Helper function for send/sendto to handle UDP packets. -STATIC mp_uint_t lwip_udp_send(lwip_socket_obj_t *socket, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) { +// Helper function for send/sendto to handle raw/UDP packets. +STATIC mp_uint_t lwip_raw_udp_send(lwip_socket_obj_t *socket, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) { if (len > 0xffff) { // Any packet that big is probably going to fail the pbuf_alloc anyway, but may as well try len = 0xffff; @@ -536,11 +557,25 @@ STATIC mp_uint_t lwip_udp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui err_t err; if (ip == NULL) { - err = udp_send(socket->pcb.udp, p); + #if MICROPY_PY_LWIP_SOCK_RAW + if (socket->type == MOD_NETWORK_SOCK_RAW) { + err = raw_send(socket->pcb.raw, p); + } else + #endif + { + err = udp_send(socket->pcb.udp, p); + } } else { ip_addr_t dest; IP4_ADDR(&dest, ip[0], ip[1], ip[2], ip[3]); - err = udp_sendto(socket->pcb.udp, p, &dest, port); + #if MICROPY_PY_LWIP_SOCK_RAW + if (socket->type == MOD_NETWORK_SOCK_RAW) { + err = raw_sendto(socket->pcb.raw, p, &dest); + } else + #endif + { + err = udp_sendto(socket->pcb.udp, p, &dest, port); + } } pbuf_free(p); @@ -558,8 +593,8 @@ STATIC mp_uint_t lwip_udp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui return len; } -// Helper function for recv/recvfrom to handle UDP packets -STATIC mp_uint_t lwip_udp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) { +// Helper function for recv/recvfrom to handle raw/UDP packets +STATIC mp_uint_t lwip_raw_udp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) { if (socket->incoming.pbuf == NULL) { if (socket->timeout != -1) { @@ -795,7 +830,13 @@ STATIC mp_obj_t lwip_socket_make_new(const mp_obj_type_t *type, size_t n_args, s socket->pcb.udp = udp_new(); socket->incoming.pbuf = NULL; break; - //case MOD_NETWORK_SOCK_RAW: socket->pcb.raw = raw_new(); break; + #if MICROPY_PY_LWIP_SOCK_RAW + case MOD_NETWORK_SOCK_RAW: { + mp_int_t proto = n_args <= 2 ? 0 : mp_obj_get_int(args[2]); + socket->pcb.raw = raw_new(proto); + break; + } + #endif default: mp_raise_OSError(MP_EINVAL); } @@ -817,6 +858,14 @@ STATIC mp_obj_t lwip_socket_make_new(const mp_obj_type_t *type, size_t n_args, s udp_recv(socket->pcb.udp, _lwip_udp_incoming, (void*)socket); break; } + #if MICROPY_PY_LWIP_SOCK_RAW + case MOD_NETWORK_SOCK_RAW: { + // Register our receive callback now. Since raw sockets don't require binding or connection + // before use, there's no other good time to do it. + raw_recv(socket->pcb.raw, _lwip_raw_incoming, (void*)socket); + break; + } + #endif } socket->timeout = -1; @@ -1045,6 +1094,12 @@ STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { err = udp_connect(socket->pcb.udp, &dest, port); break; } + #if MICROPY_PY_LWIP_SOCK_RAW + case MOD_NETWORK_SOCK_RAW: { + err = raw_connect(socket->pcb.raw, &dest); + break; + } + #endif } if (err != ERR_OK) { @@ -1079,10 +1134,12 @@ STATIC mp_obj_t lwip_socket_send(mp_obj_t self_in, mp_obj_t buf_in) { ret = lwip_tcp_send(socket, bufinfo.buf, bufinfo.len, &_errno); break; } - case MOD_NETWORK_SOCK_DGRAM: { - ret = lwip_udp_send(socket, bufinfo.buf, bufinfo.len, NULL, 0, &_errno); + case MOD_NETWORK_SOCK_DGRAM: + #if MICROPY_PY_LWIP_SOCK_RAW + case MOD_NETWORK_SOCK_RAW: + #endif + ret = lwip_raw_udp_send(socket, bufinfo.buf, bufinfo.len, NULL, 0, &_errno); break; - } } if (ret == -1) { mp_raise_OSError(_errno); @@ -1108,10 +1165,12 @@ STATIC mp_obj_t lwip_socket_recv(mp_obj_t self_in, mp_obj_t len_in) { ret = lwip_tcp_receive(socket, (byte*)vstr.buf, len, &_errno); break; } - case MOD_NETWORK_SOCK_DGRAM: { - ret = lwip_udp_receive(socket, (byte*)vstr.buf, len, NULL, NULL, &_errno); + case MOD_NETWORK_SOCK_DGRAM: + #if MICROPY_PY_LWIP_SOCK_RAW + case MOD_NETWORK_SOCK_RAW: + #endif + ret = lwip_raw_udp_receive(socket, (byte*)vstr.buf, len, NULL, NULL, &_errno); break; - } } if (ret == -1) { mp_raise_OSError(_errno); @@ -1143,10 +1202,12 @@ STATIC mp_obj_t lwip_socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t ret = lwip_tcp_send(socket, bufinfo.buf, bufinfo.len, &_errno); break; } - case MOD_NETWORK_SOCK_DGRAM: { - ret = lwip_udp_send(socket, bufinfo.buf, bufinfo.len, ip, port, &_errno); + case MOD_NETWORK_SOCK_DGRAM: + #if MICROPY_PY_LWIP_SOCK_RAW + case MOD_NETWORK_SOCK_RAW: + #endif + ret = lwip_raw_udp_send(socket, bufinfo.buf, bufinfo.len, ip, port, &_errno); break; - } } if (ret == -1) { mp_raise_OSError(_errno); @@ -1176,10 +1237,12 @@ STATIC mp_obj_t lwip_socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) { ret = lwip_tcp_receive(socket, (byte*)vstr.buf, len, &_errno); break; } - case MOD_NETWORK_SOCK_DGRAM: { - ret = lwip_udp_receive(socket, (byte*)vstr.buf, len, ip, &port, &_errno); + case MOD_NETWORK_SOCK_DGRAM: + #if MICROPY_PY_LWIP_SOCK_RAW + case MOD_NETWORK_SOCK_RAW: + #endif + ret = lwip_raw_udp_receive(socket, (byte*)vstr.buf, len, ip, &port, &_errno); break; - } } if (ret == -1) { mp_raise_OSError(_errno); @@ -1331,7 +1394,10 @@ STATIC mp_uint_t lwip_socket_read(mp_obj_t self_in, void *buf, mp_uint_t size, i case MOD_NETWORK_SOCK_STREAM: return lwip_tcp_receive(socket, buf, size, errcode); case MOD_NETWORK_SOCK_DGRAM: - return lwip_udp_receive(socket, buf, size, NULL, NULL, errcode); + #if MICROPY_PY_LWIP_SOCK_RAW + case MOD_NETWORK_SOCK_RAW: + #endif + return lwip_raw_udp_receive(socket, buf, size, NULL, NULL, errcode); } // Unreachable return MP_STREAM_ERROR; @@ -1344,7 +1410,10 @@ STATIC mp_uint_t lwip_socket_write(mp_obj_t self_in, const void *buf, mp_uint_t case MOD_NETWORK_SOCK_STREAM: return lwip_tcp_send(socket, buf, size, errcode); case MOD_NETWORK_SOCK_DGRAM: - return lwip_udp_send(socket, buf, size, NULL, 0, errcode); + #if MICROPY_PY_LWIP_SOCK_RAW + case MOD_NETWORK_SOCK_RAW: + #endif + return lwip_raw_udp_send(socket, buf, size, NULL, 0, errcode); } // Unreachable return MP_STREAM_ERROR; @@ -1385,6 +1454,11 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ if (socket->type == MOD_NETWORK_SOCK_DGRAM && socket->pcb.udp != NULL) { // UDP socket is writable ret |= MP_STREAM_POLL_WR; + #if MICROPY_PY_LWIP_SOCK_RAW + } else if (socket->type == MOD_NETWORK_SOCK_RAW && socket->pcb.raw != NULL) { + // raw socket is writable + ret |= MP_STREAM_POLL_WR; + #endif } else if (socket->pcb.tcp != NULL && tcp_sndbuf(socket->pcb.tcp) > 0) { // TCP socket is writable // Note: pcb.tcp==NULL if state<0, and in this case we can't call tcp_sndbuf @@ -1438,7 +1512,9 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ break; } case MOD_NETWORK_SOCK_DGRAM: udp_remove(socket->pcb.udp); break; - //case MOD_NETWORK_SOCK_RAW: raw_remove(socket->pcb.raw); break; + #if MICROPY_PY_LWIP_SOCK_RAW + case MOD_NETWORK_SOCK_RAW: raw_remove(socket->pcb.raw); break; + #endif } socket->pcb.tcp = NULL; @@ -1660,7 +1736,9 @@ STATIC const mp_rom_map_elem_t mp_module_lwip_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_SOCK_STREAM), MP_ROM_INT(MOD_NETWORK_SOCK_STREAM) }, { MP_ROM_QSTR(MP_QSTR_SOCK_DGRAM), MP_ROM_INT(MOD_NETWORK_SOCK_DGRAM) }, + #if MICROPY_PY_LWIP_SOCK_RAW { MP_ROM_QSTR(MP_QSTR_SOCK_RAW), MP_ROM_INT(MOD_NETWORK_SOCK_RAW) }, + #endif { MP_ROM_QSTR(MP_QSTR_SOL_SOCKET), MP_ROM_INT(1) }, { MP_ROM_QSTR(MP_QSTR_SO_REUSEADDR), MP_ROM_INT(SOF_REUSEADDR) }, From 0e2b224b078d94e6ff2e346e3390572c1d24a4ec Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 25 Jul 2019 00:03:40 +1000 Subject: [PATCH 0586/1788] stm32/lwip_inc: Enable raw socket type. --- ports/stm32/lwip_inc/lwipopts.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/stm32/lwip_inc/lwipopts.h b/ports/stm32/lwip_inc/lwipopts.h index 8f54c83112..c9bbde92f7 100644 --- a/ports/stm32/lwip_inc/lwipopts.h +++ b/ports/stm32/lwip_inc/lwipopts.h @@ -17,6 +17,7 @@ #define LWIP_ARP 1 #define LWIP_ETHERNET 1 +#define LWIP_RAW 1 #define LWIP_NETCONN 0 #define LWIP_SOCKET 0 #define LWIP_STATS 0 From 102815f700fbc07fe58474570af933bc284a3fc5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 30 Jul 2019 22:58:41 +1000 Subject: [PATCH 0587/1788] stm32/mpconfigport.h: Enable lwIP raw sockets. --- ports/stm32/mpconfigport.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 3e615c3437..dbb6fa2d50 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -150,6 +150,7 @@ #define MICROPY_PY_UTIME_MP_HAL (1) #define MICROPY_PY_OS_DUPTERM (3) #define MICROPY_PY_UOS_DUPTERM_BUILTIN_STREAM (1) +#define MICROPY_PY_LWIP_SOCK_RAW (MICROPY_PY_LWIP) #define MICROPY_PY_MACHINE (1) #define MICROPY_PY_MACHINE_PULSE (1) #define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new From 2d3d4f74830eddaba8e13ca9a860a5cb7fb2f163 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 30 Jul 2019 22:58:54 +1000 Subject: [PATCH 0588/1788] esp8266/mpconfigport.h: Enable lwIP raw sockets. --- ports/esp8266/mpconfigport.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h index 3bf8220282..5a1ca098d8 100644 --- a/ports/esp8266/mpconfigport.h +++ b/ports/esp8266/mpconfigport.h @@ -81,6 +81,7 @@ #define MICROPY_PY_UTIME_MP_HAL (1) #define MICROPY_PY_UZLIB (1) #define MICROPY_PY_LWIP (1) +#define MICROPY_PY_LWIP_SOCK_RAW (1) #define MICROPY_PY_MACHINE (1) #define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new #define MICROPY_PY_MACHINE_PULSE (1) From cd35dd9d9a29836906acdce60c931f6352b536d0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 5 Aug 2019 16:32:10 +1000 Subject: [PATCH 0589/1788] py: Allow to pass in read-only buffers to viper and inline-asm funcs. Fixes #4936. --- py/nativeglue.c | 2 +- py/objfun.c | 2 +- tests/inlineasm/asmsum.py | 4 ++++ tests/inlineasm/asmsum.py.exp | 1 + tests/micropython/viper_addr.py | 10 ++++++++++ tests/micropython/viper_addr.py.exp | 1 + 6 files changed, 18 insertions(+), 2 deletions(-) diff --git a/py/nativeglue.c b/py/nativeglue.c index 979265a870..eb02907bdd 100644 --- a/py/nativeglue.c +++ b/py/nativeglue.c @@ -65,7 +65,7 @@ mp_uint_t mp_native_from_obj(mp_obj_t obj, mp_uint_t type) { case MP_NATIVE_TYPE_UINT: return mp_obj_get_int_truncated(obj); default: { // cast obj to a pointer mp_buffer_info_t bufinfo; - if (mp_get_buffer(obj, &bufinfo, MP_BUFFER_RW)) { + if (mp_get_buffer(obj, &bufinfo, MP_BUFFER_READ)) { return (mp_uint_t)bufinfo.buf; } else { // assume obj is an integer that represents an address diff --git a/py/objfun.c b/py/objfun.c index d96c79ede4..e0c6fb9271 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -472,7 +472,7 @@ STATIC mp_uint_t convert_obj_for_inline_asm(mp_obj_t obj) { return (mp_uint_t)items; } else { mp_buffer_info_t bufinfo; - if (mp_get_buffer(obj, &bufinfo, MP_BUFFER_WRITE)) { + if (mp_get_buffer(obj, &bufinfo, MP_BUFFER_READ)) { // supports the buffer protocol, return a pointer to the data return (mp_uint_t)bufinfo.buf; } else { diff --git a/tests/inlineasm/asmsum.py b/tests/inlineasm/asmsum.py index 07e71c7384..9cbd8418ea 100644 --- a/tests/inlineasm/asmsum.py +++ b/tests/inlineasm/asmsum.py @@ -55,3 +55,7 @@ print(b, n) b = array.array('b', (10, 20, 30, 40, 50, 60, 70, 80)) n = asm_sum_bytes(len(b), b) print(b, n) + +b = b'\x01\x02\x03\x04' +n = asm_sum_bytes(len(b), b) +print(b, n) diff --git a/tests/inlineasm/asmsum.py.exp b/tests/inlineasm/asmsum.py.exp index d50a94c8db..3c83da367a 100644 --- a/tests/inlineasm/asmsum.py.exp +++ b/tests/inlineasm/asmsum.py.exp @@ -1,2 +1,3 @@ array('l', [100, 200, 300, 400]) 1000 array('b', [10, 20, 30, 40, 50, 60, 70, 80]) 360 +b'\x01\x02\x03\x04' 10 diff --git a/tests/micropython/viper_addr.py b/tests/micropython/viper_addr.py index cd953ce07d..0d8efb90b6 100644 --- a/tests/micropython/viper_addr.py +++ b/tests/micropython/viper_addr.py @@ -9,6 +9,13 @@ def memset(dest:ptr8, c:int, n:int): for i in range(n): dest[i] = c +@micropython.viper +def memsum(src:ptr8, n:int) -> int: + s = 0 + for i in range(n): + s += src[i] + return s + # create array and get its address ar = bytearray('0000') addr = get_addr(ar) @@ -27,3 +34,6 @@ print(ar) # pass direct pointer to array buffer, with offset memset(addr + 2, ord('3'), len(ar) - 2) print(ar) + +# pass a read-only bytes object in +print(memsum(b'\x01\x02\x03\x04', 4)) diff --git a/tests/micropython/viper_addr.py.exp b/tests/micropython/viper_addr.py.exp index 87a18e1e2a..8e08db9a54 100644 --- a/tests/micropython/viper_addr.py.exp +++ b/tests/micropython/viper_addr.py.exp @@ -4,3 +4,4 @@ bytearray(b'0000') bytearray(b'1111') bytearray(b'2222') bytearray(b'2233') +10 From efdcd6baa710af11bdc2f4930e42e439cc1b2ff8 Mon Sep 17 00:00:00 2001 From: Milan Rossa Date: Mon, 5 Aug 2019 17:06:22 +0200 Subject: [PATCH 0590/1788] py/showbc: Fix off-by-one when showing address of unknown opcode. --- py/showbc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/showbc.c b/py/showbc.c index b9024b716d..8b97c8defa 100644 --- a/py/showbc.c +++ b/py/showbc.c @@ -540,7 +540,7 @@ const byte *mp_bytecode_print_str(const byte *ip) { mp_uint_t op = ip[-1] - MP_BC_BINARY_OP_MULTI; printf("BINARY_OP " UINT_FMT " %s", op, qstr_str(mp_binary_op_method_name[op])); } else { - printf("code %p, byte code 0x%02x not implemented\n", ip, ip[-1]); + printf("code %p, byte code 0x%02x not implemented\n", ip - 1, ip[-1]); assert(0); return ip; } From 3d02ebb4e8262b67433eadc80100155387c6f186 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 1 Aug 2019 19:54:32 -0700 Subject: [PATCH 0591/1788] stm32/sdcard: Support configuring the SD/MMC bus width to 1 or 4 bits. Some SD/MMC breakout boards don't support 4-bit bus mode. This adds a new macro MICROPY_HW_SDMMC_BUS_WIDTH that allows each board to define the width of the SD/MMC bus interface used on that board, defaulting to 4 bits. --- ports/stm32/mpconfigboard_common.h | 5 +++++ ports/stm32/sdcard.c | 16 ++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index 121b64d038..603215af4b 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -102,6 +102,11 @@ #define MICROPY_HW_ENABLE_MMCARD (0) #endif +// SD/MMC interface bus width (defaults to 4 bits) +#ifndef MICROPY_HW_SDMMC_BUS_WIDTH +#define MICROPY_HW_SDMMC_BUS_WIDTH (4) +#endif + // Whether to automatically mount (and boot from) the SD card if it's present #ifndef MICROPY_HW_SDCARD_MOUNT_AT_BOOT #define MICROPY_HW_SDCARD_MOUNT_AT_BOOT (MICROPY_HW_ENABLE_SDCARD) diff --git a/ports/stm32/sdcard.c b/ports/stm32/sdcard.c index 0cb09b8189..f54d67ea49 100644 --- a/ports/stm32/sdcard.c +++ b/ports/stm32/sdcard.c @@ -156,17 +156,21 @@ void sdcard_init(void) { mp_hal_pin_config_alt_static(MICROPY_HW_SDMMC2_CK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC2_CK); mp_hal_pin_config_alt_static(MICROPY_HW_SDMMC2_CMD, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC2_CMD); mp_hal_pin_config_alt_static(MICROPY_HW_SDMMC2_D0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC2_D0); + #if MICROPY_HW_SDMMC_BUS_WIDTH == 4 mp_hal_pin_config_alt_static(MICROPY_HW_SDMMC2_D1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC2_D1); mp_hal_pin_config_alt_static(MICROPY_HW_SDMMC2_D2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC2_D2); mp_hal_pin_config_alt_static(MICROPY_HW_SDMMC2_D3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC2_D3); + #endif #else // Default SDIO/SDMMC1 config + mp_hal_pin_config_alt_static(MICROPY_HW_SDMMC_CK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC_CK); + mp_hal_pin_config_alt_static(MICROPY_HW_SDMMC_CMD, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC_CMD); mp_hal_pin_config_alt_static(MICROPY_HW_SDMMC_D0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC_D0); + #if MICROPY_HW_SDMMC_BUS_WIDTH == 4 mp_hal_pin_config_alt_static(MICROPY_HW_SDMMC_D1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC_D1); mp_hal_pin_config_alt_static(MICROPY_HW_SDMMC_D2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC_D2); mp_hal_pin_config_alt_static(MICROPY_HW_SDMMC_D3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC_D3); - mp_hal_pin_config_alt_static(MICROPY_HW_SDMMC_CK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC_CK); - mp_hal_pin_config_alt_static(MICROPY_HW_SDMMC_CMD, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC_CMD); + #endif #endif // configure the SD card detect pin @@ -252,12 +256,14 @@ STATIC HAL_StatusTypeDef sdmmc_init_sd(void) { mp_hal_delay_ms(50); } - // configure the SD bus width for wide operation + #if MICROPY_HW_SDMMC_BUS_WIDTH == 4 + // configure the SD bus width for 4-bit wide operation status = HAL_SD_ConfigWideBusOperation(&sdmmc_handle.sd, SDIO_BUS_WIDE_4B); if (status != HAL_OK) { HAL_SD_DeInit(&sdmmc_handle.sd); return status; } + #endif return HAL_OK; } @@ -285,7 +291,8 @@ STATIC HAL_StatusTypeDef sdmmc_init_mmc(void) { // As this is an eMMC card, overwrite LogBlockNbr with actual value sdmmc_handle.mmc.MmcCard.LogBlockNbr = 7469056 + 2048; - // Configure the SDIO bus width for wide operation + #if MICROPY_HW_SDMMC_BUS_WIDTH == 4 + // Configure the SDIO bus width for 4-bit wide operation #ifdef STM32F7 sdmmc_handle.mmc.Init.ClockBypass = SDIO_CLOCK_BYPASS_ENABLE; #endif @@ -294,6 +301,7 @@ STATIC HAL_StatusTypeDef sdmmc_init_mmc(void) { HAL_MMC_DeInit(&sdmmc_handle.mmc); return status; } + #endif return HAL_OK; } From b6906fa573bb1fcde5004e83b40832ae9ba8b002 Mon Sep 17 00:00:00 2001 From: Kenta IDA Date: Wed, 10 Jul 2019 00:30:38 +0900 Subject: [PATCH 0592/1788] esp32/network_ppp: Add authentication support to the PPP interface. This commit adds the connect() method to the PPP interface and requires that connect() be called after active(1). This is a breaking change for the PPP API. With the connect() method it's now possible to pass in authentication information for PAP/CHAP, eg: ppp.active(1) ppp.connect(authmode=ppp.AUTH_PAP, username="user", "password="password") If no authentication is needed simply call connect() without any parameters. This will get the original behaviour of calling active(1). --- ports/esp32/network_ppp.c | 86 +++++++++++++++++++++++++++++++-------- 1 file changed, 70 insertions(+), 16 deletions(-) diff --git a/ports/esp32/network_ppp.c b/ports/esp32/network_ppp.c index aca4bbc1e9..1a14c09bf8 100644 --- a/ports/esp32/network_ppp.c +++ b/ports/esp32/network_ppp.c @@ -129,29 +129,26 @@ STATIC mp_obj_t ppp_active(size_t n_args, const mp_obj_t *args) { if (self->pcb == NULL) { mp_raise_msg(&mp_type_RuntimeError, "init failed"); } - pppapi_set_default(self->pcb); - ppp_set_usepeerdns(self->pcb, 1); - pppapi_connect(self->pcb, 0); - - xTaskCreatePinnedToCore(pppos_client_task, "ppp", 2048, self, 1, (TaskHandle_t*)&self->client_task_handle, MP_TASK_COREID); self->active = true; } else { if (!self->active) { return mp_const_false; } - // Wait for PPPERR_USER, with timeout - pppapi_close(self->pcb, 0); - uint32_t t0 = mp_hal_ticks_ms(); - while (!self->clean_close && mp_hal_ticks_ms() - t0 < PPP_CLOSE_TIMEOUT_MS) { - mp_hal_delay_ms(10); - } + if (self->client_task_handle != NULL) { // is connecting or connected? + // Wait for PPPERR_USER, with timeout + pppapi_close(self->pcb, 0); + uint32_t t0 = mp_hal_ticks_ms(); + while (!self->clean_close && mp_hal_ticks_ms() - t0 < PPP_CLOSE_TIMEOUT_MS) { + mp_hal_delay_ms(10); + } - // Shutdown task - xTaskNotifyGive(self->client_task_handle); - t0 = mp_hal_ticks_ms(); - while (self->client_task_handle != NULL && mp_hal_ticks_ms() - t0 < PPP_CLOSE_TIMEOUT_MS) { - mp_hal_delay_ms(10); + // Shutdown task + xTaskNotifyGive(self->client_task_handle); + t0 = mp_hal_ticks_ms(); + while (self->client_task_handle != NULL && mp_hal_ticks_ms() - t0 < PPP_CLOSE_TIMEOUT_MS) { + mp_hal_delay_ms(10); + } } // Release PPP @@ -166,6 +163,59 @@ STATIC mp_obj_t ppp_active(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ppp_active_obj, 1, 2, ppp_active); +STATIC mp_obj_t ppp_connect_py(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + enum { ARG_authmode, ARG_username, ARG_password }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_authmode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PPPAUTHTYPE_NONE} }, + { MP_QSTR_username, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_password, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + }; + + mp_arg_val_t parsed_args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, parsed_args); + + ppp_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); + + if (!self->active) { + mp_raise_msg(&mp_type_OSError, "must be active"); + } + + if (self->client_task_handle != NULL) { + mp_raise_OSError(MP_EALREADY); + } + + switch (parsed_args[ARG_authmode].u_int) { + case PPPAUTHTYPE_NONE: + case PPPAUTHTYPE_PAP: + case PPPAUTHTYPE_CHAP: + break; + default: + mp_raise_msg(&mp_type_ValueError, "invalid auth"); + } + + if (parsed_args[ARG_authmode].u_int != PPPAUTHTYPE_NONE) { + const char* username_str = mp_obj_str_get_str(parsed_args[ARG_username].u_obj); + const char* password_str = mp_obj_str_get_str(parsed_args[ARG_password].u_obj); + pppapi_set_auth(self->pcb, parsed_args[ARG_authmode].u_int, username_str, password_str); + } + if (pppapi_set_default(self->pcb) != ESP_OK) { + mp_raise_msg(&mp_type_OSError, "set default failed"); + } + + ppp_set_usepeerdns(self->pcb, true); + + if (pppapi_connect(self->pcb, 0) != ESP_OK) { + mp_raise_msg(&mp_type_OSError, "connect failed"); + } + + if (xTaskCreatePinnedToCore(pppos_client_task, "ppp", 2048, self, 1, (TaskHandle_t*)&self->client_task_handle, MP_TASK_COREID) != pdPASS) { + mp_raise_msg(&mp_type_RuntimeError, "failed to create worker task"); + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(ppp_connect_obj, 1, ppp_connect_py); + STATIC mp_obj_t ppp_delete(mp_obj_t self_in) { ppp_if_obj_t* self = MP_OBJ_TO_PTR(self_in); mp_obj_t args[] = {self, mp_const_false}; @@ -216,10 +266,14 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(ppp_isconnected_obj, ppp_isconnected); STATIC const mp_rom_map_elem_t ppp_if_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&ppp_active_obj) }, + { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&ppp_connect_obj) }, { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&ppp_isconnected_obj) }, { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&ppp_status_obj) }, { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&ppp_ifconfig_obj) }, { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&ppp_delete_obj) }, + { MP_ROM_QSTR(MP_QSTR_AUTH_NONE), MP_ROM_INT(PPPAUTHTYPE_NONE) }, + { MP_ROM_QSTR(MP_QSTR_AUTH_PAP), MP_ROM_INT(PPPAUTHTYPE_PAP) }, + { MP_ROM_QSTR(MP_QSTR_AUTH_CHAP), MP_ROM_INT(PPPAUTHTYPE_CHAP) }, }; STATIC MP_DEFINE_CONST_DICT(ppp_if_locals_dict, ppp_if_locals_dict_table); From ba607809f210ae9648709138623ddadbfb16fe57 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 15 Aug 2019 12:03:32 +1000 Subject: [PATCH 0593/1788] stm32/modpyb: Support building with PY_PYB_LEGACY on and HW_USB_HID off. --- ports/stm32/modpyb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/stm32/modpyb.c b/ports/stm32/modpyb.c index 139defc53b..1a1f567a5f 100644 --- a/ports/stm32/modpyb.c +++ b/ports/stm32/modpyb.c @@ -170,9 +170,11 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { #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) }, + #if MICROPY_HW_USB_HID { MP_ROM_QSTR(MP_QSTR_hid), MP_ROM_PTR(&pyb_hid_send_report_obj) }, #endif #endif + #endif #if MICROPY_PY_PYB_LEGACY { MP_ROM_QSTR(MP_QSTR_millis), MP_ROM_PTR(&mp_utime_ticks_ms_obj) }, From bf733c27bbfe40c2f35407a031a2900bc4eaeaba Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 15 Aug 2019 12:19:28 +1000 Subject: [PATCH 0594/1788] stm32/usbd: Introduce MICROPY_HW_USB_IS_MULTI_OTG to simplify USB config This is an internal config value that is enabled for MCUs that have multiple OTG instances, to simplify #if configuration of the USB code. --- ports/stm32/mpconfigboard_common.h | 7 +++++++ ports/stm32/usbd_cdc_interface.c | 4 ++-- ports/stm32/usbd_conf.c | 12 ++++++------ 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index 603215af4b..a7a48aabc4 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -287,6 +287,13 @@ #define MICROPY_HW_MAX_CAN (1) #endif +// Whether the USB peripheral is device-only, or multiple OTG +#if defined(STM32L0) || defined(STM32WB) +#define MICROPY_HW_USB_IS_MULTI_OTG (0) +#else +#define MICROPY_HW_USB_IS_MULTI_OTG (1) +#endif + // Configure maximum number of CDC VCP interfaces, and whether MSC/HID are supported #ifndef MICROPY_HW_USB_CDC_NUM #define MICROPY_HW_USB_CDC_NUM (1) diff --git a/ports/stm32/usbd_cdc_interface.c b/ports/stm32/usbd_cdc_interface.c index e234230196..51d29b30fe 100644 --- a/ports/stm32/usbd_cdc_interface.c +++ b/ports/stm32/usbd_cdc_interface.c @@ -142,7 +142,7 @@ int8_t usbd_cdc_control(usbd_cdc_state_t *cdc_in, uint8_t cmd, uint8_t* pbuf, ui // configure its serial port (in most cases to disable local echo) cdc->connect_state = USBD_CDC_CONNECT_STATE_CONNECTING; usbd_cdc_connect_tx_timer = 8; // wait for 8 SOF IRQs - #if defined(STM32L0) || defined(STM32WB) + #if !MICROPY_HW_USB_IS_MULTI_OTG USB->CNTR |= USB_CNTR_SOFM; #else PCD_HandleTypeDef *hpcd = cdc->base.usbd->pdev->pData; @@ -219,7 +219,7 @@ void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) { --usbd_cdc_connect_tx_timer; } else { usbd_cdc_msc_hid_state_t *usbd = ((USBD_HandleTypeDef*)hpcd->pData)->pClassData; - #if defined(STM32L0) || defined(STM32WB) + #if !MICROPY_HW_USB_IS_MULTI_OTG USB->CNTR &= ~USB_CNTR_SOFM; #else hpcd->Instance->GINTMSK &= ~USB_OTG_GINTMSK_SOFM; diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c index 437d96ae78..7577ee21b2 100644 --- a/ports/stm32/usbd_conf.c +++ b/ports/stm32/usbd_conf.c @@ -44,8 +44,8 @@ PCD_HandleTypeDef pcd_fs_handle; PCD_HandleTypeDef pcd_hs_handle; #endif -#if defined(STM32L0) || defined(STM32WB) -// The STM32L0xx has a single USB device-only instance +#if !MICROPY_HW_USB_IS_MULTI_OTG +// The MCU has a single USB device-only instance #define USB_OTG_FS USB #endif @@ -92,7 +92,7 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) { #endif // Enable USB FS Clocks - #if defined(STM32L0) || defined(STM32WB) + #if !MICROPY_HW_USB_IS_MULTI_OTG __HAL_RCC_USB_CLK_ENABLE(); #else __USB_OTG_FS_CLK_ENABLE(); @@ -195,7 +195,7 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) { * @retval None */ void HAL_PCD_MspDeInit(PCD_HandleTypeDef *hpcd) { - #if defined(STM32L0) || defined(STM32WB) + #if !MICROPY_HW_USB_IS_MULTI_OTG __HAL_RCC_USB_CLK_DISABLE(); #else @@ -379,7 +379,7 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { pcd_fs_handle.Init.lpm_enable = DISABLE; pcd_fs_handle.Init.battery_charging_enable = DISABLE; #endif - #if !defined(STM32L0) && !defined(STM32WB) + #if MICROPY_HW_USB_IS_MULTI_OTG pcd_fs_handle.Init.use_dedicated_ep1 = 0; pcd_fs_handle.Init.dma_enable = 0; #if !defined(MICROPY_HW_USB_VBUS_DETECT_PIN) @@ -396,7 +396,7 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { // Initialize LL Driver HAL_PCD_Init(&pcd_fs_handle); - #if defined(STM32L0) || defined(STM32WB) + #if !MICROPY_HW_USB_IS_MULTI_OTG // We have 512 16-bit words it total to use here (when using PCD_SNG_BUF) HAL_PCDEx_PMAConfig(&pcd_fs_handle, 0x00, PCD_SNG_BUF, 64); // EP0 HAL_PCDEx_PMAConfig(&pcd_fs_handle, 0x80, PCD_SNG_BUF, 128); // EP0 From 97e8e036c5e01666d210ae2bf8cf2eb7f65e83e8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 15 Aug 2019 12:46:04 +1000 Subject: [PATCH 0595/1788] stm32/usbd: Support USB device mode on STM32L432 MCUs. --- ports/stm32/mpconfigboard_common.h | 2 +- ports/stm32/stm32_it.c | 2 +- ports/stm32/usbd_conf.c | 5 +++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index a7a48aabc4..d353468f96 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -288,7 +288,7 @@ #endif // Whether the USB peripheral is device-only, or multiple OTG -#if defined(STM32L0) || defined(STM32WB) +#if defined(STM32L0) || defined(STM32L432xx) || defined(STM32WB) #define MICROPY_HW_USB_IS_MULTI_OTG (0) #else #define MICROPY_HW_USB_IS_MULTI_OTG (1) diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index 16db92d1d7..a2ebb6641a 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -298,7 +298,7 @@ void DebugMon_Handler(void) { /* file (startup_stm32f4xx.s). */ /******************************************************************************/ -#if defined(STM32L0) +#if defined(STM32L0) || defined(STM32L432xx) #if MICROPY_HW_USB_FS void USB_IRQHandler(void) { diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c index 7577ee21b2..275ec15aa6 100644 --- a/ports/stm32/usbd_conf.c +++ b/ports/stm32/usbd_conf.c @@ -64,6 +64,8 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) { const uint32_t otg_alt = GPIO_AF10_OTG1_FS; #elif defined(STM32L0) const uint32_t otg_alt = GPIO_AF0_USB; + #elif defined(STM32L432xx) + const uint32_t otg_alt = GPIO_AF10_USB_FS; #elif defined(STM32WB) const uint32_t otg_alt = GPIO_AF10_USB; #else @@ -113,6 +115,9 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) { #if defined(STM32L0) NVIC_SetPriority(USB_IRQn, IRQ_PRI_OTG_FS); HAL_NVIC_EnableIRQ(USB_IRQn); + #elif defined(STM32L432xx) + NVIC_SetPriority(USB_FS_IRQn, IRQ_PRI_OTG_FS); + HAL_NVIC_EnableIRQ(USB_FS_IRQn); #elif defined(STM32WB) NVIC_SetPriority(USB_LP_IRQn, IRQ_PRI_OTG_FS); HAL_NVIC_EnableIRQ(USB_LP_IRQn); From 8485b72d0d29b7985983a7328d2a84e87a4b47d5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 15 Aug 2019 12:46:34 +1000 Subject: [PATCH 0596/1788] stm32/boards/NUCLEO_L432KC: Add config for USB VCP support. --- ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h b/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h index 7f2ebbad55..60e053f44f 100644 --- a/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h @@ -14,6 +14,7 @@ #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_ADC (1) #define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_USB (0) // requires a custom USB connector on PA11/PA12 #define MICROPY_HW_ENABLE_TIMER (1) #define MICROPY_HW_HAS_SWITCH (0) @@ -57,4 +58,8 @@ #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config -#define MICROPY_HW_USB_FS (0) +#define MICROPY_HW_USB_FS (MICROPY_HW_ENABLE_USB) +#define MICROPY_HW_USB_MSC (0) +#define MICROPY_HW_USB_HID (0) +#define USBD_CDC_RX_DATA_SIZE (256) +#define USBD_CDC_TX_DATA_SIZE (256) From 25d3509986aadb8f2a0d4d87d75b64223087512a Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 1 Aug 2019 21:49:17 +1000 Subject: [PATCH 0597/1788] stm32/usbd: Make USB device FIFO sizes dynamically configurable. Allows to optimise and configure the FIFO sizes depending on the USB device configuration selected at runtime, eg VCP+MSC vs 3xVCP+MSC. --- ports/stm32/mboot/main.c | 9 +++- ports/stm32/usb.c | 58 ++++++++++++++++++++++- ports/stm32/usbd_conf.c | 62 +++++++------------------ ports/stm32/usbd_conf.h | 10 ++++ ports/stm32/usbdev/core/inc/usbd_core.h | 2 +- ports/stm32/usbdev/core/src/usbd_core.c | 2 + 6 files changed, 96 insertions(+), 47 deletions(-) diff --git a/ports/stm32/mboot/main.c b/ports/stm32/mboot/main.c index f6b89004d4..fcd43edc7f 100644 --- a/ports/stm32/mboot/main.c +++ b/ports/stm32/mboot/main.c @@ -1088,6 +1088,13 @@ typedef struct _pyb_usbdd_obj_t { #define MBOOT_USB_PID 0xDF11 #endif +static const uint8_t usbd_fifo_size[] = { + 32, 8, 16, 8, 16, 0, 0, // FS: RX, EP0(in), 5x IN endpoints + #if MICROPY_HW_USB_HS + 116, 8, 64, 4, 64, 0, 0, 0, 0, 0, // HS: RX, EP0(in), 8x IN endpoints + #endif +}; + __ALIGN_BEGIN static const uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END = { USB_LEN_LANGID_STR_DESC, USB_DESC_TYPE_STRING, @@ -1315,7 +1322,7 @@ static void pyb_usbdd_start(pyb_usbdd_obj_t *self) { while (!(PWR->CR3 & PWR_CR3_USB33RDY)) { } #endif - USBD_LL_Init(&self->hUSBDDevice, 0); + USBD_LL_Init(&self->hUSBDDevice, 0, usbd_fifo_size); USBD_LL_Start(&self->hUSBDDevice); self->started = true; } diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index 3308f07449..791a6472a5 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -75,6 +75,50 @@ typedef struct _usb_device_t { usb_device_t usb_device = {0}; pyb_usb_storage_medium_t pyb_usb_storage_medium = PYB_USB_STORAGE_MEDIUM_NONE; +#if !MICROPY_HW_USB_IS_MULTI_OTG + +// Units of FIFO size arrays below are 4x 16-bit words = 8 bytes +// There are 512x 16-bit words it total to use here (when using PCD_SNG_BUF) + +// EP0(out), EP0(in), MSC/HID(out), MSC/HID(in), unused, CDC_CMD(in), CDC_DATA(out), CDC_DATA(in) +STATIC const uint8_t usbd_fifo_size_cdc1[] = {16, 16, 16, 16, 0, 16, 16, 16}; + +#else + +// Units of FIFO size arrays below are 4x 32-bit words = 16 bytes +// FS: there are 320x 32-bit words in total to use here +// HS: there are 1024x 32-bit words in total to use here + +// RX; EP0(in), MSC/HID, CDC_CMD, CDC_DATA +STATIC const uint8_t usbd_fifo_size_cdc1[] = { + 32, 8, 16, 8, 16, 0, 0, // FS: RX, EP0(in), 5x IN endpoints + #if MICROPY_HW_USB_HS + 116, 8, 64, 4, 64, 0, 0, 0, 0, 0, // HS: RX, EP0(in), 8x IN endpoints + #endif +}; + +#if MICROPY_HW_USB_CDC_NUM >= 2 +// RX; EP0(in), MSC/HID, CDC_CMD, CDC_DATA, CDC2_CMD, CDC2_DATA +STATIC const uint8_t usbd_fifo_size_cdc2[] = { + 32, 8, 16, 4, 8, 4, 8, + #if MICROPY_HW_USB_HS + 116, 8, 64, 2, 32, 2, 32, 0, 0, 0, + #endif +}; +#endif + +#if MICROPY_HW_USB_CDC_NUM >= 3 +// RX; EP0(in), MSC/HID, CDC_CMD, CDC_DATA, CDC2_CMD, CDC2_DATA, CDC3_CMD, CDC3_DATA +STATIC const uint8_t usbd_fifo_size_cdc3[] = { + 0, 0, 0, 0, 0, 0, 0, // FS: can't support 3x VCP mode + #if MICROPY_HW_USB_HS + 82, 8, 64, 2, 32, 2, 32, 2, 32, 0, + #endif +}; +#endif + +#endif + #if MICROPY_HW_USB_HID // predefined hid mouse data STATIC const mp_obj_str_t pyb_usb_hid_mouse_desc_obj = { @@ -197,8 +241,20 @@ bool pyb_usb_dev_init(int dev_id, uint16_t vid, uint16_t pid, uint8_t mode, size USBD_MSC_RegisterStorage(&usb_dev->usbd_cdc_msc_hid_state, (USBD_StorageTypeDef*)&usbd_msc_fops); #endif + const uint8_t *fifo_size = usbd_fifo_size_cdc1; + #if MICROPY_HW_USB_CDC_NUM >= 3 + if (mode & USBD_MODE_IFACE_CDC(2)) { + fifo_size = usbd_fifo_size_cdc3; + } else + #endif + #if MICROPY_HW_USB_CDC_NUM >= 2 + if (mode & USBD_MODE_IFACE_CDC(1)) { + fifo_size = usbd_fifo_size_cdc2; + } + #endif + // start the USB device - USBD_LL_Init(usbd, (mode & USBD_MODE_HIGH_SPEED) != 0); + USBD_LL_Init(usbd, (mode & USBD_MODE_HIGH_SPEED) != 0, fifo_size); USBD_LL_Start(usbd); usb_dev->enabled = true; } diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c index 275ec15aa6..d30f28b2fc 100644 --- a/ports/stm32/usbd_conf.c +++ b/ports/stm32/usbd_conf.c @@ -361,7 +361,7 @@ void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd) { * @param pdev: Device handle * @retval USBD Status */ -USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { +USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed, const uint8_t *fifo_size) { #if MICROPY_HW_USB_FS if (pdev->id == USB_PHY_FS_ID) { #if defined(STM32WB) @@ -401,35 +401,19 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { // Initialize LL Driver HAL_PCD_Init(&pcd_fs_handle); + // Set FIFO buffer sizes #if !MICROPY_HW_USB_IS_MULTI_OTG - // We have 512 16-bit words it total to use here (when using PCD_SNG_BUF) - HAL_PCDEx_PMAConfig(&pcd_fs_handle, 0x00, PCD_SNG_BUF, 64); // EP0 - HAL_PCDEx_PMAConfig(&pcd_fs_handle, 0x80, PCD_SNG_BUF, 128); // EP0 - HAL_PCDEx_PMAConfig(&pcd_fs_handle, 0x01, PCD_SNG_BUF, 192); // MSC / HID - HAL_PCDEx_PMAConfig(&pcd_fs_handle, 0x81, PCD_SNG_BUF, 256); // MSC / HID - HAL_PCDEx_PMAConfig(&pcd_fs_handle, 0x02, PCD_SNG_BUF, 320); // unused - HAL_PCDEx_PMAConfig(&pcd_fs_handle, 0x82, PCD_SNG_BUF, 320); // CDC CMD - HAL_PCDEx_PMAConfig(&pcd_fs_handle, 0x03, PCD_SNG_BUF, 384); // CDC DATA - HAL_PCDEx_PMAConfig(&pcd_fs_handle, 0x83, PCD_SNG_BUF, 448); // CDC DATA + uint32_t fifo_offset = USBD_PMA_RESERVE; // need to reserve some data at start of FIFO + for (size_t i = 0; i < USBD_PMA_NUM_FIFO; ++i) { + uint16_t ep_addr = ((i & 1) * 0x80) | (i >> 1); + HAL_PCDEx_PMAConfig(&pcd_fs_handle, ep_addr, PCD_SNG_BUF, fifo_offset); + fifo_offset += fifo_size[i] * 4; + } #else - - // We have 320 32-bit words in total to use here - #if MICROPY_HW_USB_CDC_NUM == 2 - 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 - + HAL_PCD_SetRxFiFo(&pcd_fs_handle, fifo_size[0] * 4); + for (size_t i = 0; i < USBD_FS_NUM_TX_FIFO; ++i) { + HAL_PCD_SetTxFiFo(&pcd_fs_handle, i, fifo_size[1 + i] * 4); + } #endif } #endif @@ -486,22 +470,12 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { // Initialize LL Driver HAL_PCD_Init(&pcd_hs_handle); - // We have 1024 32-bit words in total to use here - #if MICROPY_HW_USB_CDC_NUM == 3 - HAL_PCD_SetRxFiFo(&pcd_hs_handle, 328); - #else - HAL_PCD_SetRxFiFo(&pcd_hs_handle, 464); - #endif - 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, 8); // CDC CMD - HAL_PCD_SetTxFiFo(&pcd_hs_handle, 3, 128); // CDC DATA - HAL_PCD_SetTxFiFo(&pcd_hs_handle, 4, 8); // CDC2 CMD - HAL_PCD_SetTxFiFo(&pcd_hs_handle, 5, 128); // CDC2 DATA - #if MICROPY_HW_USB_CDC_NUM == 3 - HAL_PCD_SetTxFiFo(&pcd_hs_handle, 6, 8); // CDC3 CMD - HAL_PCD_SetTxFiFo(&pcd_hs_handle, 7, 128); // CDC3 DATA - #endif + // Set FIFO buffer sizes + fifo_size += USBD_FS_NUM_FIFO; // skip over FS FIFO size values + HAL_PCD_SetRxFiFo(&pcd_hs_handle, fifo_size[0] * 4); + for (size_t i = 0; i < USBD_HS_NUM_TX_FIFO; ++i) { + HAL_PCD_SetTxFiFo(&pcd_hs_handle, i, fifo_size[1 + i] * 4); + } } #endif // MICROPY_HW_USB_HS diff --git a/ports/stm32/usbd_conf.h b/ports/stm32/usbd_conf.h index 639b54d9f3..83629bfc4f 100644 --- a/ports/stm32/usbd_conf.h +++ b/ports/stm32/usbd_conf.h @@ -49,6 +49,16 @@ #endif #define USBD_DEBUG_LEVEL 0 +// For MCUs with a device-only USB peripheral +#define USBD_PMA_RESERVE (64) +#define USBD_PMA_NUM_FIFO (8) + +// For MCUs with multiple OTG USB peripherals +#define USBD_FS_NUM_TX_FIFO (6) +#define USBD_FS_NUM_FIFO (1 + USBD_FS_NUM_TX_FIFO) +#define USBD_HS_NUM_TX_FIFO (9) +#define USBD_HS_NUM_FIFO (1 + USBD_HS_NUM_TX_FIFO) + #endif // MICROPY_INCLUDED_STM32_USBD_CONF_H /************************ (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 5494be3a22..d3925fc6b7 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, int high_speed); +USBD_StatusTypeDef USBD_LL_Init (USBD_HandleTypeDef *pdev, int high_speed, const uint8_t *fifo_size); 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 f235b24ee6..4c69a77eb6 100644 --- a/ports/stm32/usbdev/core/src/usbd_core.c +++ b/ports/stm32/usbdev/core/src/usbd_core.c @@ -85,6 +85,7 @@ * @{ */ +#if 0 /** * @brief USBD_Init * Initailizes the device stack and load the class driver @@ -122,6 +123,7 @@ USBD_StatusTypeDef USBD_Init(USBD_HandleTypeDef *pdev, USBD_DescriptorsTypeDef * return USBD_OK; } +#endif /** * @brief USBD_DeInit From 2ccf030fd1ee7ddf7c015217c7fbc9996c735fd1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 10 Jul 2019 15:38:48 +1000 Subject: [PATCH 0598/1788] esp32: Add support for mDNS queries and responder. They are both enabled by default, but can be disabled by defining MICROPY_HW_ENABLE_MDNS_QUERIES and/or MICROPY_HW_ENABLE_MDNS_RESPONDER to 0. The hostname for the responder is currently taken from tcpip_adapter_get_hostname() but should eventually be configurable. --- ports/esp32/Makefile | 6 ++++ ports/esp32/modnetwork.c | 20 +++++++++++++ ports/esp32/modsocket.c | 57 +++++++++++++++++++++++++++++++++++++- ports/esp32/mpconfigport.h | 8 ++++++ 4 files changed, 90 insertions(+), 1 deletion(-) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index c6ef04b465..f30a7cfadd 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -74,6 +74,7 @@ INC += -I$(BUILD) INC_ESPCOMP += -I$(ESPCOMP)/bootloader_support/include INC_ESPCOMP += -I$(ESPCOMP)/bootloader_support/include_bootloader +INC_ESPCOMP += -I$(ESPCOMP)/console INC_ESPCOMP += -I$(ESPCOMP)/driver/include INC_ESPCOMP += -I$(ESPCOMP)/driver/include/driver INC_ESPCOMP += -I$(ESPCOMP)/nghttp/port/include @@ -103,6 +104,8 @@ INC_ESPCOMP += -I$(ESPCOMP)/lwip/port/esp32/include INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/apps INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/mbedtls/include INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/port/include +INC_ESPCOMP += -I$(ESPCOMP)/mdns/include +INC_ESPCOMP += -I$(ESPCOMP)/mdns/private_include INC_ESPCOMP += -I$(ESPCOMP)/spi_flash/include INC_ESPCOMP += -I$(ESPCOMP)/ulp/include INC_ESPCOMP += -I$(ESPCOMP)/vfs/include @@ -346,6 +349,8 @@ ESPIDF_MBEDTLS_O = $(patsubst %.c,%.o,\ $(wildcard $(ESPCOMP)/mbedtls/port/*.c) \ ) +ESPIDF_MDNS_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/mdns/*.c)) + $(BUILD)/$(ESPCOMP)/wpa_supplicant/%.o: CFLAGS += -DEMBEDDED_SUPP -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_MSCHAPv2 -DEAP_TTLS -DEAP_TLS -DEAP_PEAP -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -DALLOW_EVEN_MOD -D__ets__ -Wno-strict-aliasing ESPIDF_WPA_SUPPLICANT_O = $(patsubst %.c,%.o,\ $(wildcard $(ESPCOMP)/wpa_supplicant/port/*.c) \ @@ -390,6 +395,7 @@ $(eval $(call gen_espidf_lib_rule,spi_flash,$(ESPIDF_SPI_FLASH_O))) $(eval $(call gen_espidf_lib_rule,ulp,$(ESPIDF_ULP_O))) $(eval $(call gen_espidf_lib_rule,lwip,$(ESPIDF_LWIP_O))) $(eval $(call gen_espidf_lib_rule,mbedtls,$(ESPIDF_MBEDTLS_O))) +$(eval $(call gen_espidf_lib_rule,mdns,$(ESPIDF_MDNS_O))) $(eval $(call gen_espidf_lib_rule,wpa_supplicant,$(ESPIDF_WPA_SUPPLICANT_O))) $(eval $(call gen_espidf_lib_rule,sdmmc,$(ESPIDF_SDMMC_O))) diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index 8462576058..3dfe3945bb 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -48,6 +48,7 @@ #include "esp_event_loop.h" #include "lwip/dns.h" #include "tcpip_adapter.h" +#include "mdns.h" #include "modnetwork.h" @@ -128,6 +129,11 @@ static bool wifi_sta_connected = false; // Store the current status. 0 means None here, safe to do so as first enum value is WIFI_REASON_UNSPECIFIED=1. static uint8_t wifi_sta_disconn_reason = 0; +#if MICROPY_HW_ENABLE_MDNS_QUERIES || MICROPY_HW_ENABLE_MDNS_RESPONDER +// Whether mDNS has been initialised or not +static bool mdns_initialised = false; +#endif + // 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) { @@ -142,6 +148,20 @@ static esp_err_t event_handler(void *ctx, system_event_t *event) { ESP_LOGI("network", "GOT_IP"); wifi_sta_connected = true; wifi_sta_disconn_reason = 0; // Success so clear error. (in case of new error will be replaced anyway) + #if MICROPY_HW_ENABLE_MDNS_QUERIES || MICROPY_HW_ENABLE_MDNS_RESPONDER + if (!mdns_initialised) { + mdns_init(); + #if MICROPY_HW_ENABLE_MDNS_RESPONDER + const char *hostname = NULL; + if (tcpip_adapter_get_hostname(WIFI_IF_STA, &hostname) != ESP_OK || hostname == NULL) { + hostname = "esp32"; + } + mdns_hostname_set(hostname); + mdns_instance_name_set(hostname); + #endif + mdns_initialised = true; + } + #endif break; case SYSTEM_EVENT_STA_DISCONNECTED: { // This is a workaround as ESP32 WiFi libs don't currently diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c index 8b80e631db..a6f29718d8 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 "mdns.h" #include "modnetwork.h" #include "lwip/sockets.h" @@ -56,6 +57,8 @@ #include "esp_log.h" #define SOCKET_POLL_US (100000) +#define MDNS_QUERY_TIMEOUT_MS (5000) +#define MDNS_LOCAL_SUFFIX ".local" typedef struct _socket_obj_t { mp_obj_base_t base; @@ -150,6 +153,58 @@ static inline void check_for_exceptions(void) { mp_handle_pending(); } +// This function mimics lwip_getaddrinfo, with added support for mDNS queries +static int _socket_getaddrinfo3(const char *nodename, const char *servname, + const struct addrinfo *hints, struct addrinfo **res) { + + #if MICROPY_HW_ENABLE_MDNS_QUERIES + int nodename_len = strlen(nodename); + const int local_len = sizeof(MDNS_LOCAL_SUFFIX) - 1; + if (nodename_len > local_len + && strcasecmp(nodename + nodename_len - local_len, MDNS_LOCAL_SUFFIX) == 0) { + // mDNS query + char nodename_no_local[nodename_len - local_len + 1]; + memcpy(nodename_no_local, nodename, nodename_len - local_len); + nodename_no_local[nodename_len - local_len] = '\0'; + + struct ip4_addr addr = {0}; + esp_err_t err = mdns_query_a(nodename_no_local, MDNS_QUERY_TIMEOUT_MS, &addr); + if (err != ESP_OK) { + if (err == ESP_ERR_NOT_FOUND){ + *res = NULL; + return 0; + } + *res = NULL; + return err; + } + + struct addrinfo *ai = memp_malloc(MEMP_NETDB); + if (ai == NULL) { + *res = NULL; + return EAI_MEMORY; + } + memset(ai, 0, sizeof(struct addrinfo) + sizeof(struct sockaddr_storage)); + + struct sockaddr_in *sa = (struct sockaddr_in*)((uint8_t*)ai + sizeof(struct addrinfo)); + inet_addr_from_ip4addr(&sa->sin_addr, &addr); + sa->sin_family = AF_INET; + sa->sin_len = sizeof(struct sockaddr_in); + sa->sin_port = lwip_htons((u16_t)atoi(servname)); + ai->ai_family = AF_INET; + ai->ai_canonname = ((char*)sa + sizeof(struct sockaddr_storage)); + memcpy(ai->ai_canonname, nodename, nodename_len + 1); + ai->ai_addrlen = sizeof(struct sockaddr_storage); + ai->ai_addr = (struct sockaddr*)sa; + + *res = ai; + return 0; + } + #endif + + // Normal query + return lwip_getaddrinfo(nodename, servname, hints, res); +} + 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, @@ -172,7 +227,7 @@ static int _socket_getaddrinfo2(const mp_obj_t host, const mp_obj_t portx, struc } MP_THREAD_GIL_EXIT(); - int res = lwip_getaddrinfo(host_str, port_str, &hints, resp); + int res = _socket_getaddrinfo3(host_str, port_str, &hints, resp); MP_THREAD_GIL_ENTER(); return res; diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 9ffe380fca..b5c7f50792 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -272,3 +272,11 @@ typedef long mp_off_t; #define MICROPY_HW_BOARD_NAME "ESP32 module" #define MICROPY_HW_MCU_NAME "ESP32" #define MICROPY_PY_SYS_PLATFORM "esp32" + +#ifndef MICROPY_HW_ENABLE_MDNS_QUERIES +#define MICROPY_HW_ENABLE_MDNS_QUERIES (1) +#endif + +#ifndef MICROPY_HW_ENABLE_MDNS_RESPONDER +#define MICROPY_HW_ENABLE_MDNS_RESPONDER (1) +#endif From cb3647004fbf7b069a3509a02b72420828369bd3 Mon Sep 17 00:00:00 2001 From: Milan Rossa Date: Mon, 5 Aug 2019 15:06:41 +0200 Subject: [PATCH 0599/1788] py: Implement new sys.atexit feature. This patch implements a new sys.atexit function which registers a function that is later executed when the main script ends. It is configurable via MICROPY_PY_SYS_ATEXIT, disabled by default. This is not compliant with CPython, rather it can be used to implement a CPython compatible "atexit" module if desired (similar to how sys.print_exception can be used to implement functionality of the "traceback" module). --- py/modsys.c | 13 +++++++++++++ py/mpconfig.h | 5 +++++ py/mpstate.h | 5 +++++ py/runtime.c | 4 ++++ 4 files changed, 27 insertions(+) diff --git a/py/modsys.c b/py/modsys.c index 3434517328..3a91393812 100644 --- a/py/modsys.c +++ b/py/modsys.c @@ -146,6 +146,16 @@ STATIC mp_obj_t mp_sys_getsizeof(mp_obj_t obj) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_sys_getsizeof_obj, mp_sys_getsizeof); #endif +#if MICROPY_PY_SYS_ATEXIT +// atexit(callback): Callback is called when sys.exit is called. +STATIC mp_obj_t mp_sys_atexit(mp_obj_t obj) { + mp_obj_t old = MP_STATE_VM(sys_exitfunc); + MP_STATE_VM(sys_exitfunc) = obj; + return old; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_sys_atexit_obj, mp_sys_atexit); +#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) }, @@ -201,6 +211,9 @@ STATIC const mp_rom_map_elem_t mp_module_sys_globals_table[] = { */ { MP_ROM_QSTR(MP_QSTR_print_exception), MP_ROM_PTR(&mp_sys_print_exception_obj) }, + #if MICROPY_PY_SYS_ATEXIT + { MP_ROM_QSTR(MP_QSTR_atexit), MP_ROM_PTR(&mp_sys_atexit_obj) }, + #endif }; STATIC MP_DEFINE_CONST_DICT(mp_module_sys_globals, mp_module_sys_globals_table); diff --git a/py/mpconfig.h b/py/mpconfig.h index a111b27aec..bded9da9fc 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -1161,6 +1161,11 @@ typedef double mp_float_t; #define MICROPY_PY_SYS_EXIT (1) #endif +// Whether to provide "sys.atexit" function (MicroPython extension) +#ifndef MICROPY_PY_SYS_ATEXIT +#define MICROPY_PY_SYS_ATEXIT (0) +#endif + // Whether to provide "sys.getsizeof" function #ifndef MICROPY_PY_SYS_GETSIZEOF #define MICROPY_PY_SYS_GETSIZEOF (0) diff --git a/py/mpstate.h b/py/mpstate.h index b7eb6bdeb1..1057cef041 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -149,6 +149,11 @@ typedef struct _mp_state_vm_t { mp_obj_base_t *cur_exception; #endif + #if MICROPY_PY_SYS_ATEXIT + // exposed through sys.atexit function + mp_obj_t sys_exitfunc; + #endif + // dictionary for the __main__ module mp_obj_dict_t dict_main; diff --git a/py/runtime.c b/py/runtime.c index 70d7957198..04f9442b7b 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -118,6 +118,10 @@ void mp_init(void) { MP_STATE_VM(vfs_mount_table) = NULL; #endif + #if MICROPY_PY_SYS_ATEXIT + MP_STATE_VM(sys_exitfunc) = mp_const_none; + #endif + #if MICROPY_PY_THREAD_GIL mp_thread_mutex_init(&MP_STATE_VM(gil_mutex)); #endif From 6f0c6bd77410ad25ade6a3999c62451ae76ea60a Mon Sep 17 00:00:00 2001 From: Milan Rossa Date: Mon, 5 Aug 2019 15:11:24 +0200 Subject: [PATCH 0600/1788] unix: Enable sys.atexit, triggered after the main script ends. --- ports/unix/main.c | 6 ++++++ ports/unix/mpconfigport.h | 1 + 2 files changed, 7 insertions(+) diff --git a/ports/unix/main.c b/ports/unix/main.c index cd2dc49a52..004d581bb2 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -642,6 +642,12 @@ MP_NOINLINE int main_(int argc, char **argv) { } } + #if MICROPY_PY_SYS_ATEXIT + if (mp_obj_is_callable(MP_STATE_VM(sys_exitfunc))) { + mp_call_function_0(MP_STATE_VM(sys_exitfunc)); + } + #endif + #if MICROPY_PY_MICROPYTHON_MEM_INFO if (mp_verbose_flag) { mp_micropython_mem_info(0, NULL); diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h index 97a9f49084..123cad2bc2 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -90,6 +90,7 @@ #define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) #define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) #define MICROPY_PY_SYS_EXIT (1) +#define MICROPY_PY_SYS_ATEXIT (1) #if defined(__APPLE__) && defined(__MACH__) #define MICROPY_PY_SYS_PLATFORM "darwin" #else From 28cb15d1313c77a04d1b119089dd1b4c7ac5ebb1 Mon Sep 17 00:00:00 2001 From: Milan Rossa Date: Mon, 5 Aug 2019 15:12:27 +0200 Subject: [PATCH 0601/1788] tests/misc/sys_atexit: Add test for new sys.atexit feature. --- tests/misc/sys_atexit.py | 18 ++++++++++++++++++ tests/misc/sys_atexit.py.exp | 2 ++ 2 files changed, 20 insertions(+) create mode 100644 tests/misc/sys_atexit.py create mode 100644 tests/misc/sys_atexit.py.exp diff --git a/tests/misc/sys_atexit.py b/tests/misc/sys_atexit.py new file mode 100644 index 0000000000..f5317953c2 --- /dev/null +++ b/tests/misc/sys_atexit.py @@ -0,0 +1,18 @@ +# test sys.atexit() function + +import sys +try: + sys.atexit +except AttributeError: + print('SKIP') + raise SystemExit + +some_var = None + +def do_at_exit(): + print("done at exit:", some_var) + +sys.atexit(do_at_exit) + +some_var = "ok" +print("done before exit") diff --git a/tests/misc/sys_atexit.py.exp b/tests/misc/sys_atexit.py.exp new file mode 100644 index 0000000000..3cbdae9a5a --- /dev/null +++ b/tests/misc/sys_atexit.py.exp @@ -0,0 +1,2 @@ +done before exit +done at exit: ok From ed9c0185d80514670244b0c2147958dea00159a9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 15 Aug 2019 17:42:38 +1000 Subject: [PATCH 0602/1788] docs/library/sys: Add documentation for sys.atexit function. --- docs/library/sys.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/library/sys.rst b/docs/library/sys.rst index f2d96cb8cc..aee2e54ee6 100644 --- a/docs/library/sys.rst +++ b/docs/library/sys.rst @@ -15,6 +15,19 @@ Functions function raise as `SystemExit` exception. If an argument is given, its value given as an argument to `SystemExit`. +.. function:: atexit(func) + + Register *func* to be called upon termination. *func* must be a callable + that takes no arguments, or ``None`` to disable the call. The ``atexit`` + function will return the previous value set by this function, which is + initially ``None``. + + .. admonition:: Difference to CPython + :class: attention + + This function is a MicroPython extension intended to provide similar + functionality to the :mod:`atexit` module in CPython. + .. function:: print_exception(exc, file=sys.stdout) Print exception with a traceback to a file-like object *file* (or From 57476a3c378940f72415c0093f1e24416132a817 Mon Sep 17 00:00:00 2001 From: Vicki Lowe Date: Tue, 6 Aug 2019 14:10:14 +1000 Subject: [PATCH 0603/1788] docs/pyboard: Update name of mounted volume to match code. --- docs/pyboard/tutorial/script.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pyboard/tutorial/script.rst b/docs/pyboard/tutorial/script.rst index 75dd324e3c..29a0370d8a 100644 --- a/docs/pyboard/tutorial/script.rst +++ b/docs/pyboard/tutorial/script.rst @@ -31,7 +31,7 @@ have as to what happens next: We will get the serial device working in the next tutorial. - **Mac**: Your pyboard will appear on the desktop as a removable disc. - It will probably be called "NONAME". Click on it to open the pyboard folder. + It will probably be called ``PYBFLASH``. Click on it to open the pyboard folder. - **Linux**: Your pyboard will appear as a removable medium. On Ubuntu it will mount automatically and pop-up a window with the pyboard folder. From 6592a30f4b6ed056411361d0c703fe814886e65b Mon Sep 17 00:00:00 2001 From: Vicki Lowe Date: Tue, 6 Aug 2019 15:46:29 +1000 Subject: [PATCH 0604/1788] docs/pyboard: Clarify initial files on pyboard and fix up formatting. --- docs/pyboard/tutorial/script.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/pyboard/tutorial/script.rst b/docs/pyboard/tutorial/script.rst index 29a0370d8a..2d44bbc885 100644 --- a/docs/pyboard/tutorial/script.rst +++ b/docs/pyboard/tutorial/script.rst @@ -46,17 +46,17 @@ a window (or command line) should be showing the files on the pyboard drive. The drive you are looking at is known as ``/flash`` by the pyboard, and should contain the following 4 files: -* `boot.py `_ -- this script is executed when the pyboard boots up. It sets - up various configuration options for the pyboard. +* `boot.py `_ -- the various configuration options for the pyboard. + It is executed when the pyboard boots up. -* `main.py `_ -- this is the main script that will contain your Python program. +* `main.py `_ -- the Python program to be run. It is executed after ``boot.py``. -* `README.txt `_ -- this contains some very basic information about getting - started with the pyboard. +* `README.txt `_ -- basic information about getting started with the pyboard. + This provides pointers for new users and can be safely deleted. -* `pybcdc.inf `_ -- this is a Windows driver file to configure the serial USB - device. More about this in the next tutorial. +* `pybcdc.inf `_ -- the Windows driver file to configure the serial USB device. + More about this in the next tutorial. Editing ``main.py`` ------------------- From d5a77416064f8155b0a0817211541c296b49d2c7 Mon Sep 17 00:00:00 2001 From: Tom McDermott Date: Tue, 6 Aug 2019 16:18:07 +1000 Subject: [PATCH 0605/1788] docs/library: Document that sys.version_info returns a 3-tuple only. See issue #4970. --- docs/library/sys.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/library/sys.rst b/docs/library/sys.rst index aee2e54ee6..d3cc308d89 100644 --- a/docs/library/sys.rst +++ b/docs/library/sys.rst @@ -134,3 +134,9 @@ Constants .. data:: version_info Python language version that this implementation conforms to, as a tuple of ints. + + .. admonition:: Difference to CPython + :class: attention + + Only the first three version numbers (major, minor, micro) are supported and + they can be referenced only by index, not by name. From afd10a45318443d67f37b2cc8fa158fe50e59f36 Mon Sep 17 00:00:00 2001 From: Vicki Lowe Date: Tue, 6 Aug 2019 17:34:34 +1000 Subject: [PATCH 0606/1788] docs/pyboard: Emphasize the instructions for making a USB mouse. It wasn't clear why that element was `10` instead of `0`. Also bumped the `10` to `100` to make the mouse movement more obvious. --- docs/pyboard/tutorial/usb_mouse.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/pyboard/tutorial/usb_mouse.rst b/docs/pyboard/tutorial/usb_mouse.rst index 6f8831edb4..8166946ecd 100644 --- a/docs/pyboard/tutorial/usb_mouse.rst +++ b/docs/pyboard/tutorial/usb_mouse.rst @@ -39,14 +39,15 @@ Sending mouse events by hand To get the py-mouse to do anything we need to send mouse events to the PC. We will first do this manually using the REPL prompt. Connect to your -pyboard using your serial program and type the following:: +pyboard using your serial program and type the following (no need to type +the ``#`` and text following it):: >>> hid = pyb.USB_HID() - >>> hid.send((0, 10, 0, 0)) + >>> hid.send((0, 100, 0, 0)) # (button status, x-direction, y-direction, scroll) -Your mouse should move 10 pixels to the right! In the command above you -are sending 4 pieces of information: button status, x, y and scroll. The -number 10 is telling the PC that the mouse moved 10 pixels in the x direction. +Your mouse should move 100 pixels to the right! In the command above you +are sending 4 pieces of information: **button status**, **x-direction**, **y-direction**, and **scroll**. The +number 100 is telling the PC that the mouse moved 100 pixels in the x direction. Let's make the mouse oscillate left and right:: From 64abc1f47a5274729b1e51b71f0691d60114242e Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 15 Aug 2019 18:56:01 +1000 Subject: [PATCH 0607/1788] tests/unix: Update extra_coverage expected output with new atexit func. --- tests/unix/extra_coverage.py.exp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index a9889c0e95..07fde6c09c 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -28,11 +28,11 @@ RuntimeError: # repl ame__ -__class__ __name__ argv byteorder -exc_info exit getsizeof implementation -maxsize modules path platform -print_exception stderr stdin -stdout version version_info +__class__ __name__ argv atexit +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 baeebc557c3132fa17f3c902e260d5049f7c7957 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 15 Aug 2019 22:03:09 +1000 Subject: [PATCH 0608/1788] esp32/modules: On initial setup mount internal flash at root. Like it's done on normal boot up. Fixes issue #5004. --- ports/esp32/modules/inisetup.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ports/esp32/modules/inisetup.py b/ports/esp32/modules/inisetup.py index 0e9c72fe86..00d9a4eab8 100644 --- a/ports/esp32/modules/inisetup.py +++ b/ports/esp32/modules/inisetup.py @@ -29,8 +29,7 @@ def setup(): print("Performing initial setup") uos.VfsFat.mkfs(bdev) vfs = uos.VfsFat(bdev) - uos.mount(vfs, '/flash') - uos.chdir('/flash') + uos.mount(vfs, '/') with open("boot.py", "w") as f: f.write("""\ # This file is executed on every boot (including wake-boot from deepsleep) From acfbb9febd024475bdcb4ebbe2ec8c0e9a652275 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 15 Aug 2019 23:02:04 +1000 Subject: [PATCH 0609/1788] py/objarray: Fix amount of free space in array when doing slice assign. Prior to this patch the amount of free space in an array (including bytearray) was not being maintained correctly for the case of slice assignment which changed the size of the array. Under certain cases (as encoded in the new test) it was possible that the array could grow beyond its allocated memory block and corrupt the heap. Fixes issue #4127. --- py/objarray.c | 3 ++- tests/basics/bytearray_slice_assign.py | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/py/objarray.c b/py/objarray.c index 4e58d8e5da..c19617d4e1 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -445,7 +445,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value if (len_adj > o->free) { // TODO: alloc policy; at the moment we go conservative o->items = m_renew(byte, o->items, (o->len + o->free) * item_sz, (o->len + len_adj) * item_sz); - o->free = 0; + o->free = len_adj; dest_items = o->items; } mp_seq_replace_slice_grow_inplace(dest_items, o->len, @@ -458,6 +458,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value mp_seq_clear(dest_items, o->len + len_adj, o->len, item_sz); // TODO: alloc policy after shrinking } + o->free -= len_adj; o->len += len_adj; return mp_const_none; #else diff --git a/tests/basics/bytearray_slice_assign.py b/tests/basics/bytearray_slice_assign.py index 7f7d1d119a..fa7878e10d 100644 --- a/tests/basics/bytearray_slice_assign.py +++ b/tests/basics/bytearray_slice_assign.py @@ -59,3 +59,10 @@ print(b) b = bytearray(2) b[1:1] = b"12345" print(b) + +# Growth of bytearray via slice extension +b = bytearray(b'12345678') +b.append(57) # expand and add a bit of unused space at end of the bytearray +for i in range(400): + b[-1:] = b'ab' # grow slowly into the unused space +print(len(b), b) From 497683b315c0fb842a6ce528f9c4ec88f4b8ff2a Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 16 Aug 2019 00:08:08 +1000 Subject: [PATCH 0610/1788] gitignore: Put build-*/ pattern in top-level gitignore file. --- .gitignore | 3 ++- ports/nrf/.gitignore | 5 ----- ports/stm32/.gitignore | 1 - ports/unix/.gitignore | 6 ------ 4 files changed, 2 insertions(+), 13 deletions(-) delete mode 100644 ports/stm32/.gitignore diff --git a/.gitignore b/.gitignore index 5e841a89c0..50bd30e877 100644 --- a/.gitignore +++ b/.gitignore @@ -20,9 +20,10 @@ ###################### *.swp -# Build directory +# Build directories ###################### build/ +build-*/ # Test failure outputs ###################### diff --git a/ports/nrf/.gitignore b/ports/nrf/.gitignore index ace93515a2..4b46e05865 100644 --- a/ports/nrf/.gitignore +++ b/ports/nrf/.gitignore @@ -1,8 +1,3 @@ # Nordic files ##################### drivers/bluetooth/s1*/ - -# Build files -##################### -build-*/ - diff --git a/ports/stm32/.gitignore b/ports/stm32/.gitignore deleted file mode 100644 index 414487d53e..0000000000 --- a/ports/stm32/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build-*/ diff --git a/ports/unix/.gitignore b/ports/unix/.gitignore index 706b7732dc..7179e7bde4 100644 --- a/ports/unix/.gitignore +++ b/ports/unix/.gitignore @@ -1,9 +1,3 @@ -build -build-fast -build-minimal -build-coverage -build-nanbox -build-freedos micropython micropython_fast micropython_minimal From 8db517f26d236023eeb04bf9af8b1e9f1c2ccec3 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Fri, 9 Aug 2019 18:07:50 +1000 Subject: [PATCH 0611/1788] esp32: Add per-board configs, following other ports. Replaces the `SDKCONFIG` makefile variable with `BOARD`. Defaults to BOARD=GENERIC. spiram can be enabled with `BOARD=GENERIC_SPIRAM` Add example definition for TINYPICO, currently identical to GENERIC_SPIRAM but with custom board/SoC names for the uPy banner. --- ports/esp32/Makefile | 45 ++++++++++++++++--- ports/esp32/README.md | 20 +++++---- ports/esp32/boards/GENERIC/mpconfigboard.h | 2 + ports/esp32/boards/GENERIC/mpconfigboard.mk | 1 + .../boards/GENERIC_SPIRAM/mpconfigboard.h | 2 + .../boards/GENERIC_SPIRAM/mpconfigboard.mk | 2 + ports/esp32/boards/TINYPICO/mpconfigboard.h | 2 + ports/esp32/boards/TINYPICO/mpconfigboard.mk | 2 + .../boards/{sdkconfig => sdkconfig.base} | 0 ports/esp32/boards/sdkconfig.spiram | 28 ------------ ports/esp32/mpconfigport.h | 6 +-- 11 files changed, 63 insertions(+), 47 deletions(-) create mode 100644 ports/esp32/boards/GENERIC/mpconfigboard.h create mode 100644 ports/esp32/boards/GENERIC/mpconfigboard.mk create mode 100644 ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.h create mode 100644 ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.mk create mode 100644 ports/esp32/boards/TINYPICO/mpconfigboard.h create mode 100644 ports/esp32/boards/TINYPICO/mpconfigboard.mk rename ports/esp32/boards/{sdkconfig => sdkconfig.base} (100%) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index f30a7cfadd..3802c2fc9c 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -1,7 +1,30 @@ +# Select the board to build for: if not given on the command line, +# then default to GENERIC. +BOARD ?= GENERIC + +# If the build directory is not given, make it reflect the board name. +BUILD ?= build-$(BOARD) + +BOARD_DIR ?= boards/$(BOARD) +ifeq ($(wildcard $(BOARD_DIR)/.),) +$(error Invalid BOARD specified: $(BOARD_DIR)) +endif + include ../../py/mkenv.mk +# Optional (not currently used for ESP32) +-include mpconfigport.mk + +ifneq ($(SDKCONFIG),) +$(error Use the BOARD variable instead of SDKCONFIG) +endif + +# Expected to set SDKCONFIG +include $(BOARD_DIR)/mpconfigboard.mk + # qstr definitions (must come before including py.mk) QSTR_DEFS = qstrdefsport.h +QSTR_GLOBAL_DEPENDENCIES = $(BOARD_DIR)/mpconfigboard.h MICROPY_PY_USSL = 0 MICROPY_SSL_AXTLS = 0 @@ -22,8 +45,7 @@ FLASH_SIZE ?= 4MB CROSS_COMPILE ?= xtensa-esp32-elf- OBJDUMP = $(CROSS_COMPILE)objdump -# SDKCONFIG should be overridden to get a different configuration -SDKCONFIG ?= boards/sdkconfig +SDKCONFIG_COMBINED = $(BUILD)/sdkconfig.combined SDKCONFIG_H = $(BUILD)/sdkconfig.h # the git hash of the currently supported ESP IDF version @@ -130,6 +152,7 @@ CFLAGS_BASE = -std=gnu99 $(CFLAGS_COMMON) -DMBEDTLS_CONFIG_FILE='"mbedtls/esp_co CFLAGS = $(CFLAGS_BASE) $(INC) $(INC_ESPCOMP) CFLAGS += -DIDF_VER=\"$(IDF_VER)\" CFLAGS += $(CFLAGS_MOD) $(CFLAGS_EXTRA) +CFLAGS += -I$(BOARD_DIR) # this is what ESPIDF uses for c++ compilation CXXFLAGS = -std=gnu++11 $(CFLAGS_COMMON) $(INC) $(INC_ESPCOMP) @@ -201,6 +224,7 @@ SRC_C = \ mpthreadport.c \ machine_rtc.c \ machine_sdcard.c \ + $(wildcard $(BOARD_DIR)/*.c) \ $(SRC_MOD) EXTMOD_SRC_C = $(addprefix extmod/,\ @@ -242,7 +266,11 @@ SRC_QSTR_AUTO_DEPS += ################################################################################ # Generate sdkconfig.h from sdkconfig -$(SDKCONFIG_H): $(SDKCONFIG) +$(SDKCONFIG_COMBINED): $(SDKCONFIG) + $(Q)$(MKDIR) -p $(dir $@) + $(Q)$(CAT) $^ > $@ + +$(SDKCONFIG_H): $(SDKCONFIG_COMBINED) $(ECHO) "GEN $@" $(Q)$(MKDIR) -p $(dir $@) $(Q)$(PYTHON) $(ESPIDF)/tools/kconfig_new/confgen.py \ @@ -255,7 +283,7 @@ $(SDKCONFIG_H): $(SDKCONFIG) --env "COMPONENT_KCONFIGS_PROJBUILD=$(ESPCOMP_KCONFIGS_PROJBUILD)" $(Q)touch $@ -$(HEADER_BUILD)/qstrdefs.generated.h: $(SDKCONFIG_H) +$(HEADER_BUILD)/qstrdefs.generated.h: $(SDKCONFIG_H) $(BOARD_DIR)/mpconfigboard.h ################################################################################ # List of object files from the ESP32 IDF components @@ -429,12 +457,12 @@ $(eval $(foreach lib,$(LIB_ESPIDF),$(eval $(call gen_sections_info_rule,$(BUILD_ $(LDGEN_SECTION_INFOS): $(LDGEN_SECTIONS_INFO) $(ESPIDF)/make/ldgen.mk $(Q)printf "$(foreach info,$(LDGEN_SECTIONS_INFO),$(info)\n)" > $@ -$(BUILD)/esp32.project.ld: $(ESPCOMP)/esp32/ld/esp32.project.ld.in $(LDGEN_FRAGMENTS) $(SDKCONFIG) $(LDGEN_SECTION_INFOS) +$(BUILD)/esp32.project.ld: $(ESPCOMP)/esp32/ld/esp32.project.ld.in $(LDGEN_FRAGMENTS) $(SDKCONFIG_COMBINED) $(LDGEN_SECTION_INFOS) $(ECHO) "GEN $@" $(Q)$(PYTHON) $(ESPIDF)/tools/ldgen/ldgen.py \ --input $< \ --output $@ \ - --config $(SDKCONFIG) \ + --config $(SDKCONFIG_COMBINED) \ --kconfig $(ESPIDF)/Kconfig \ --fragments $(LDGEN_FRAGMENTS) \ --sections $(LDGEN_SECTION_INFOS) \ @@ -472,6 +500,7 @@ OBJ = $(OBJ_MP) APP_LD_ARGS = APP_LD_ARGS += $(LDFLAGS_MOD) +APP_LD_ARGS += $(addprefix -T,$(LD_FILES)) APP_LD_ARGS += --start-group APP_LD_ARGS += -L$(dir $(LIBGCC_FILE_NAME)) -lgcc APP_LD_ARGS += -L$(dir $(LIBSTDCXX_FILE_NAME)) -lstdc++ @@ -653,7 +682,9 @@ $(BUILD)/bootloader.elf: $(BOOTLOADER_OBJ) $(addprefix $(BOOTLOADER_LIB_DIR)/lib # Declarations to build the partitions PYTHON2 ?= python2 -PART_SRC = partitions.csv + +# Can be overriden by mkconfigboard.mk. +PART_SRC ?= partitions.csv $(BUILD)/partitions.bin: $(PART_SRC) $(ECHO) "Create $@" diff --git a/ports/esp32/README.md b/ports/esp32/README.md index 12144d822d..31347b6a2a 100644 --- a/ports/esp32/README.md +++ b/ports/esp32/README.md @@ -74,11 +74,11 @@ 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 = +BOARD = GENERIC #PORT = /dev/ttyUSB0 #FLASH_MODE = qio #FLASH_SIZE = 4MB #CROSS_COMPILE = xtensa-esp32-elf- -#SDKCONFIG = boards/sdkconfig.spiram include Makefile ``` @@ -92,16 +92,18 @@ are `PORT` for the serial port of your esp32 module, and `FLASH_MODE` (which may need to be `dio` for some modules) and `FLASH_SIZE`. See the Makefile for further information. -The default ESP IDF configuration settings are provided in the file -`boards/sdkconfig`, and this file is specified in the build by the make -variable `SDKCONFIG`. To use a custom configuration either set `SDKCONFIG` -in your custom `makefile` (or `GNUmakefile`) or set this variable on the -command line: +The default ESP IDF configuration settings are provided by the `GENERIC` +board definition in the directory `boards/GENERIC`. For a custom configuration +you can define your own board directory. + +The `BOARD` variable can be set on the make command line: ```bash -$ make SDKCONFIG=sdkconfig.myboard +$ make BOARD=TINYPICO ``` -The file `boards/sdkconfig.spiram` is provided for ESP32 modules that have -external SPIRAM. +or added to your custom `makefile` (or `GNUmakefile`) described above. There +is also a `GENERIC_SPIRAM` board for for ESP32 modules that have external +SPIRAM, but prefer to use a specific board target (or define your own as +necessary). Building the firmware --------------------- diff --git a/ports/esp32/boards/GENERIC/mpconfigboard.h b/ports/esp32/boards/GENERIC/mpconfigboard.h new file mode 100644 index 0000000000..644807f78e --- /dev/null +++ b/ports/esp32/boards/GENERIC/mpconfigboard.h @@ -0,0 +1,2 @@ +#define MICROPY_HW_BOARD_NAME "ESP32 module" +#define MICROPY_HW_MCU_NAME "ESP32" diff --git a/ports/esp32/boards/GENERIC/mpconfigboard.mk b/ports/esp32/boards/GENERIC/mpconfigboard.mk new file mode 100644 index 0000000000..fc49d2a8c2 --- /dev/null +++ b/ports/esp32/boards/GENERIC/mpconfigboard.mk @@ -0,0 +1 @@ +SDKCONFIG += boards/sdkconfig.base diff --git a/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.h b/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.h new file mode 100644 index 0000000000..a5982e47e5 --- /dev/null +++ b/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.h @@ -0,0 +1,2 @@ +#define MICROPY_HW_BOARD_NAME "ESP32 module (spiram)" +#define MICROPY_HW_MCU_NAME "ESP32" diff --git a/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.mk b/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.mk new file mode 100644 index 0000000000..59aa75f857 --- /dev/null +++ b/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.mk @@ -0,0 +1,2 @@ +SDKCONFIG += boards/sdkconfig.base +SDKCONFIG += boards/sdkconfig.spiram diff --git a/ports/esp32/boards/TINYPICO/mpconfigboard.h b/ports/esp32/boards/TINYPICO/mpconfigboard.h new file mode 100644 index 0000000000..e63f43ed25 --- /dev/null +++ b/ports/esp32/boards/TINYPICO/mpconfigboard.h @@ -0,0 +1,2 @@ +#define MICROPY_HW_BOARD_NAME "TinyPICO" +#define MICROPY_HW_MCU_NAME "ESP32-PICO-D4" diff --git a/ports/esp32/boards/TINYPICO/mpconfigboard.mk b/ports/esp32/boards/TINYPICO/mpconfigboard.mk new file mode 100644 index 0000000000..59aa75f857 --- /dev/null +++ b/ports/esp32/boards/TINYPICO/mpconfigboard.mk @@ -0,0 +1,2 @@ +SDKCONFIG += boards/sdkconfig.base +SDKCONFIG += boards/sdkconfig.spiram diff --git a/ports/esp32/boards/sdkconfig b/ports/esp32/boards/sdkconfig.base similarity index 100% rename from ports/esp32/boards/sdkconfig rename to ports/esp32/boards/sdkconfig.base diff --git a/ports/esp32/boards/sdkconfig.spiram b/ports/esp32/boards/sdkconfig.spiram index 1467f3171b..53950e587c 100644 --- a/ports/esp32/boards/sdkconfig.spiram +++ b/ports/esp32/boards/sdkconfig.spiram @@ -1,33 +1,5 @@ # MicroPython on ESP32, ESP IDF configuration with SPIRAM support -# The following options override the defaults -CONFIG_IDF_TARGET="esp32" - -# Application manager -CONFIG_APP_EXCLUDE_PROJECT_VER_VAR=y -CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR=y - -# Bootloader config -CONFIG_LOG_BOOTLOADER_LEVEL_WARN=y - -# ESP32-specific -CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y CONFIG_SPIRAM_SUPPORT=y CONFIG_SPIRAM_IGNORE_NOTFOUND=y CONFIG_SPIRAM_USE_MEMMAP=y -CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=n -CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1=n -CONFIG_ESP32_XTAL_FREQ_AUTO=y - -# Power Management -CONFIG_PM_ENABLE=y - -# FreeRTOS -CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=2 -CONFIG_SUPPORT_STATIC_ALLOCATION=y -CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK=y - -# UDP -CONFIG_PPP_SUPPORT=y -CONFIG_PPP_PAP_SUPPORT=y -CONFIG_PPP_CHAP_SUPPORT=y diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index b5c7f50792..364b2de5c2 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -1,6 +1,9 @@ // Options to control how MicroPython is built for this port, // overriding defaults in py/mpconfig.h. +// Board-specific definitions +#include "mpconfigboard.h" + #include #include #include "rom/ets_sys.h" @@ -268,9 +271,6 @@ typedef long mp_off_t; #include // board specifics - -#define MICROPY_HW_BOARD_NAME "ESP32 module" -#define MICROPY_HW_MCU_NAME "ESP32" #define MICROPY_PY_SYS_PLATFORM "esp32" #ifndef MICROPY_HW_ENABLE_MDNS_QUERIES From a5d85d306c430e0dbf3871971f68ed920dda4ef7 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Sat, 10 Aug 2019 15:17:09 +1000 Subject: [PATCH 0612/1788] samd: Make common linker scripts, rename board.mk to mpconfigboard.mk. The rename matches other ports, e.g. stm32, and gives consistency with mpconfigboard.h. --- ports/samd/Makefile | 2 +- .../{board.mk => mpconfigboard.mk} | 2 +- .../boards/ADAFRUIT_TRINKET_M0/{board.mk => mpconfigboard.mk} | 2 +- .../samd/boards/{ADAFRUIT_TRINKET_M0/link.ld => samd21x18a.ld} | 0 .../{ADAFRUIT_ITSYBITSY_M4_EXPRESS/link.ld => samd51g19a.ld} | 0 5 files changed, 3 insertions(+), 3 deletions(-) rename ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/{board.mk => mpconfigboard.mk} (56%) rename ports/samd/boards/ADAFRUIT_TRINKET_M0/{board.mk => mpconfigboard.mk} (56%) rename ports/samd/boards/{ADAFRUIT_TRINKET_M0/link.ld => samd21x18a.ld} (100%) rename ports/samd/boards/{ADAFRUIT_ITSYBITSY_M4_EXPRESS/link.ld => samd51g19a.ld} (100%) diff --git a/ports/samd/Makefile b/ports/samd/Makefile index f4a09ad7c1..77a53bd486 100644 --- a/ports/samd/Makefile +++ b/ports/samd/Makefile @@ -10,7 +10,7 @@ $(error Invalid BOARD specified: $(BOARD_DIR)) endif include ../../py/mkenv.mk -include $(BOARD_DIR)/board.mk +include $(BOARD_DIR)/mpconfigboard.mk # Qstr definitions (must come before including py.mk) QSTR_DEFS = qstrdefsport.h diff --git a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.mk b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.mk similarity index 56% rename from ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.mk rename to ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.mk index 8cbd1885e4..2e5d7e68df 100644 --- a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.mk +++ b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.mk @@ -1,4 +1,4 @@ MCU_SERIES = SAMD51 CMSIS_MCU = SAMD51G19A -LD_FILES = $(BOARD_DIR)/link.ld sections.ld +LD_FILES = boards/samd51g19a.ld sections.ld TEXT0 = 0x4000 diff --git a/ports/samd/boards/ADAFRUIT_TRINKET_M0/board.mk b/ports/samd/boards/ADAFRUIT_TRINKET_M0/mpconfigboard.mk similarity index 56% rename from ports/samd/boards/ADAFRUIT_TRINKET_M0/board.mk rename to ports/samd/boards/ADAFRUIT_TRINKET_M0/mpconfigboard.mk index 3955a4f719..5b4d0b63e7 100644 --- a/ports/samd/boards/ADAFRUIT_TRINKET_M0/board.mk +++ b/ports/samd/boards/ADAFRUIT_TRINKET_M0/mpconfigboard.mk @@ -1,4 +1,4 @@ MCU_SERIES = SAMD21 CMSIS_MCU = SAMD21E18A -LD_FILES = $(BOARD_DIR)/link.ld sections.ld +LD_FILES = boards/samd21x18a.ld sections.ld TEXT0 = 0x2000 diff --git a/ports/samd/boards/ADAFRUIT_TRINKET_M0/link.ld b/ports/samd/boards/samd21x18a.ld similarity index 100% rename from ports/samd/boards/ADAFRUIT_TRINKET_M0/link.ld rename to ports/samd/boards/samd21x18a.ld diff --git a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/link.ld b/ports/samd/boards/samd51g19a.ld similarity index 100% rename from ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/link.ld rename to ports/samd/boards/samd51g19a.ld From 90188cc92beff545854e2ff55698494a175a34fc Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Sat, 10 Aug 2019 14:58:27 +1000 Subject: [PATCH 0613/1788] samd/boards: Add Adafruit Feather M0 Express board configuration. --- ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.h | 2 ++ .../samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.mk | 4 ++++ 2 files changed, 6 insertions(+) create mode 100644 ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.h create mode 100644 ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.mk diff --git a/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.h b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.h new file mode 100644 index 0000000000..cec9e9ccdd --- /dev/null +++ b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.h @@ -0,0 +1,2 @@ +#define MICROPY_HW_BOARD_NAME "Feather M0 Express" +#define MICROPY_HW_MCU_NAME "SAMD21G18A" diff --git a/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.mk b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.mk new file mode 100644 index 0000000000..8696c966bc --- /dev/null +++ b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.mk @@ -0,0 +1,4 @@ +MCU_SERIES = SAMD21 +CMSIS_MCU = SAMD21G18A +LD_FILES = boards/samd21x18a.ld sections.ld +TEXT0 = 0x2000 From eb7eed5d920748f8222efbd16bfb24c3d1798e83 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Sat, 10 Aug 2019 15:04:00 +1000 Subject: [PATCH 0614/1788] samd/boards: Add Mini SAM M4 board configuration. --- ports/samd/boards/MINISAM_M4/mpconfigboard.h | 7 +++++++ ports/samd/boards/MINISAM_M4/mpconfigboard.mk | 5 +++++ 2 files changed, 12 insertions(+) create mode 100644 ports/samd/boards/MINISAM_M4/mpconfigboard.h create mode 100644 ports/samd/boards/MINISAM_M4/mpconfigboard.mk diff --git a/ports/samd/boards/MINISAM_M4/mpconfigboard.h b/ports/samd/boards/MINISAM_M4/mpconfigboard.h new file mode 100644 index 0000000000..0847a45bf1 --- /dev/null +++ b/ports/samd/boards/MINISAM_M4/mpconfigboard.h @@ -0,0 +1,7 @@ +#define MICROPY_HW_BOARD_NAME "Mini SAM M4" +#define MICROPY_HW_MCU_NAME "SAMD51G19A" + +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) +#define MICROPY_PY_BUILTINS_COMPLEX (0) +#define MICROPY_PY_MATH (0) +#define MICROPY_PY_CMATH (0) diff --git a/ports/samd/boards/MINISAM_M4/mpconfigboard.mk b/ports/samd/boards/MINISAM_M4/mpconfigboard.mk new file mode 100644 index 0000000000..54ed3273d5 --- /dev/null +++ b/ports/samd/boards/MINISAM_M4/mpconfigboard.mk @@ -0,0 +1,5 @@ +# https://www.minifigboards.com/mini-sam-m4/mini-sam-m4-hardware/ +MCU_SERIES = SAMD51 +CMSIS_MCU = SAMD51G19A +LD_FILES = boards/samd51g19a.ld sections.ld +TEXT0 = 0x4000 From 3eff81288cb494c7d1a9fcf0a82d4e21bbd92dd8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 16 Aug 2019 13:34:04 +1000 Subject: [PATCH 0615/1788] stm32/i2c: Fix generation of restart condition for hw I2C on F0/F7. Before this patch I2C transactions using a hardware I2C peripheral on F0/F7 MCUs would not correctly generate the I2C restart condition, and instead would generate a stop followed by a start. This is because the CR2 AUTOEND bit was being set before CR2 START when the peripheral already had the I2C bus from a previous transaction that did not generate a stop. As a consequence all combined transactions, eg read-then-write for an I2C memory transfer, generated a stop condition after the first transaction and didn't generate a stop at the very end (but still released the bus). Some I2C devices require a repeated start to function correctly. This patch fixes this by making sure the CR2 AUTOEND bit is set after the start condition and slave address have been fully transferred out. --- ports/stm32/i2c.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ports/stm32/i2c.c b/ports/stm32/i2c.c index 06e26d9124..5981df11c5 100644 --- a/ports/stm32/i2c.c +++ b/ports/stm32/i2c.c @@ -340,8 +340,7 @@ STATIC int i2c_wait_isr_set(i2c_t *i2c, uint32_t mask) { 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 + i2c->CR2 = (len > 1) << I2C_CR2_RELOAD_Pos | (len > 0) << I2C_CR2_NBYTES_Pos | rd_wrn << I2C_CR2_RD_WRN_Pos | (addr & 0x7f) << 1; @@ -361,6 +360,11 @@ int i2c_start_addr(i2c_t *i2c, int rd_wrn, uint16_t addr, size_t len, bool stop) return -MP_ENODEV; } + // Configure automatic STOP if needed + if (stop) { + i2c->CR2 |= I2C_CR2_AUTOEND; + } + // Repurpose OAR1 to indicate that we loaded CR2 i2c->OAR1 = 1; From af5c998f37ddc62abfd36e0b8be511c392fc25d8 Mon Sep 17 00:00:00 2001 From: stijn Date: Tue, 2 Jul 2019 10:28:44 +0200 Subject: [PATCH 0616/1788] py/modmath: Implement math.isclose() for non-complex numbers. As per PEP 485, this function appeared in for Python 3.5. Configured via MICROPY_PY_MATH_ISCLOSE which is disabled by default, but enabled for the ports which already have MICROPY_PY_MATH_SPECIAL_FUNCTIONS enabled. --- ports/esp32/mpconfigport.h | 1 + ports/javascript/mpconfigport.h | 1 + ports/stm32/mpconfigport.h | 1 + ports/unix/mpconfigport.h | 1 + ports/windows/mpconfigport.h | 1 + py/modmath.c | 39 +++++++++++++++++++++++++++ py/mpconfig.h | 5 ++++ tests/float/math_isclose.py | 47 +++++++++++++++++++++++++++++++++ tests/float/math_isclose.py.exp | 27 +++++++++++++++++++ 9 files changed, 123 insertions(+) create mode 100644 tests/float/math_isclose.py create mode 100644 tests/float/math_isclose.py.exp diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 364b2de5c2..cba319245c 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -98,6 +98,7 @@ #define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) #define MICROPY_PY_MATH (1) #define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) +#define MICROPY_PY_MATH_ISCLOSE (1) #define MICROPY_PY_CMATH (1) #define MICROPY_PY_GC (1) #define MICROPY_PY_IO (1) diff --git a/ports/javascript/mpconfigport.h b/ports/javascript/mpconfigport.h index 228113c48e..02d83f402d 100644 --- a/ports/javascript/mpconfigport.h +++ b/ports/javascript/mpconfigport.h @@ -73,6 +73,7 @@ #define MICROPY_PY_COLLECTIONS (1) #define MICROPY_PY_MATH (1) #define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) +#define MICROPY_PY_MATH_ISCLOSE (1) #define MICROPY_PY_CMATH (1) #define MICROPY_PY_IO (1) #define MICROPY_PY_STRUCT (1) diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index dbb6fa2d50..5eb44bd46b 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -114,6 +114,7 @@ #define MICROPY_PY_COLLECTIONS_DEQUE (1) #define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) #define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) +#define MICROPY_PY_MATH_ISCLOSE (1) #define MICROPY_PY_MATH_FACTORIAL (1) #define MICROPY_PY_CMATH (1) #define MICROPY_PY_IO (1) diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h index 123cad2bc2..23c562e5aa 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -104,6 +104,7 @@ #ifndef MICROPY_PY_MATH_SPECIAL_FUNCTIONS #define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) #endif +#define MICROPY_PY_MATH_ISCLOSE (MICROPY_PY_MATH_SPECIAL_FUNCTIONS) #define MICROPY_PY_CMATH (1) #define MICROPY_PY_IO_IOBASE (1) #define MICROPY_PY_IO_FILEIO (1) diff --git a/ports/windows/mpconfigport.h b/ports/windows/mpconfigport.h index ffe7ae1443..1a9842609a 100644 --- a/ports/windows/mpconfigport.h +++ b/ports/windows/mpconfigport.h @@ -86,6 +86,7 @@ #define MICROPY_PY_COLLECTIONS_DEQUE (1) #define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) #define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) +#define MICROPY_PY_MATH_ISCLOSE (1) #define MICROPY_PY_CMATH (1) #define MICROPY_PY_IO_FILEIO (1) #define MICROPY_PY_GC_COLLECT_RETVAL (1) diff --git a/py/modmath.c b/py/modmath.c index d106f240c8..35bb44bea3 100644 --- a/py/modmath.c +++ b/py/modmath.c @@ -171,6 +171,42 @@ MATH_FUN_1(lgamma, lgamma) #endif //TODO: fsum +#if MICROPY_PY_MATH_ISCLOSE +STATIC mp_obj_t mp_math_isclose(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_a, ARG_b, ARG_rel_tol, ARG_abs_tol }; + static const mp_arg_t allowed_args[] = { + {MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ}, + {MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ}, + {MP_QSTR_rel_tol, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_abs_tol, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_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); + const mp_float_t a = mp_obj_get_float(args[ARG_a].u_obj); + const mp_float_t b = mp_obj_get_float(args[ARG_b].u_obj); + const mp_float_t rel_tol = args[ARG_rel_tol].u_obj == MP_OBJ_NULL + ? (mp_float_t)1e-9 : mp_obj_get_float(args[ARG_rel_tol].u_obj); + const mp_float_t abs_tol = mp_obj_get_float(args[ARG_abs_tol].u_obj); + if (rel_tol < (mp_float_t)0.0 || abs_tol < (mp_float_t)0.0) { + math_error(); + } + if (a == b) { + return mp_const_true; + } + const mp_float_t difference = MICROPY_FLOAT_C_FUN(fabs)(a - b); + if (isinf(difference)) { // Either a or b is inf + return mp_const_false; + } + if ((difference <= abs_tol) || + (difference <= MICROPY_FLOAT_C_FUN(fabs)(rel_tol * a)) || + (difference <= MICROPY_FLOAT_C_FUN(fabs)(rel_tol * b))) { + return mp_const_true; + } + return mp_const_false; +} +MP_DEFINE_CONST_FUN_OBJ_KW(mp_math_isclose_obj, 2, mp_math_isclose); +#endif + // Function that takes a variable number of arguments // log(x[, base]) @@ -335,6 +371,9 @@ STATIC const mp_rom_map_elem_t mp_module_math_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_isfinite), MP_ROM_PTR(&mp_math_isfinite_obj) }, { MP_ROM_QSTR(MP_QSTR_isinf), MP_ROM_PTR(&mp_math_isinf_obj) }, { MP_ROM_QSTR(MP_QSTR_isnan), MP_ROM_PTR(&mp_math_isnan_obj) }, + #if MICROPY_PY_MATH_ISCLOSE + { MP_ROM_QSTR(MP_QSTR_isclose), MP_ROM_PTR(&mp_math_isclose_obj) }, + #endif { MP_ROM_QSTR(MP_QSTR_trunc), MP_ROM_PTR(&mp_math_trunc_obj) }, { MP_ROM_QSTR(MP_QSTR_radians), MP_ROM_PTR(&mp_math_radians_obj) }, { MP_ROM_QSTR(MP_QSTR_degrees), MP_ROM_PTR(&mp_math_degrees_obj) }, diff --git a/py/mpconfig.h b/py/mpconfig.h index bded9da9fc..a21a6c7075 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -1079,6 +1079,11 @@ typedef double mp_float_t; #define MICROPY_PY_MATH_FACTORIAL (0) #endif +// Whether to provide math.isclose function +#ifndef MICROPY_PY_MATH_ISCLOSE +#define MICROPY_PY_MATH_ISCLOSE (0) +#endif + // Whether to provide "cmath" module #ifndef MICROPY_PY_CMATH #define MICROPY_PY_CMATH (0) diff --git a/tests/float/math_isclose.py b/tests/float/math_isclose.py new file mode 100644 index 0000000000..13dfff75fb --- /dev/null +++ b/tests/float/math_isclose.py @@ -0,0 +1,47 @@ +# test math.isclose (appeared in Python 3.5) + +try: + from math import isclose +except ImportError: + print("SKIP") + raise SystemExit + +def test(a, b, **kwargs): + print(isclose(a, b, **kwargs)) + +def test_combinations(a, b, **kwargs): + test(a, a, **kwargs) + test(a, b, **kwargs) + test(b, a, **kwargs) + test(b, b, **kwargs) + +# Special numbers +test_combinations(float('nan'), 1) +test_combinations(float('inf'), 1) +test_combinations(float('-inf'), 1) + +# Equality +test(1.0, 1.0, rel_tol=0.0, abs_tol=0.0) +test(2.35e-100, 2.35e-100, rel_tol=0.0, abs_tol=0.0) +test(2.1234e100, 2.1234e100, rel_tol=0.0, abs_tol=0.0) + +# Relative tolerance +test(1000.0, 1001.0, rel_tol=1e-3) +test(1000.0, 1001.0, rel_tol=1e-4) +test(1000, 1001, rel_tol=1e-3) +test(1000, 1001, rel_tol=1e-4) +test_combinations(0, 1, rel_tol=1.0) + +# Absolute tolerance +test(0.0, 1e-10, abs_tol=1e-10, rel_tol=0.1) +test(0.0, 1e-10, abs_tol=0.0, rel_tol=0.1) + +# Bad parameters +try: + isclose(0, 0, abs_tol=-1) +except ValueError: + print('ValueError') +try: + isclose(0, 0, rel_tol=-1) +except ValueError: + print('ValueError') diff --git a/tests/float/math_isclose.py.exp b/tests/float/math_isclose.py.exp new file mode 100644 index 0000000000..02974666c0 --- /dev/null +++ b/tests/float/math_isclose.py.exp @@ -0,0 +1,27 @@ +False +False +False +True +True +False +False +True +True +False +False +True +True +True +True +True +False +True +False +True +True +True +True +True +False +ValueError +ValueError From 0c80cb39af7a0f6b0ad73d38bf28a8fc1f50b3c7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 19 Aug 2019 15:50:02 +1000 Subject: [PATCH 0617/1788] py: Introduce MP_UNREACHABLE macro to annotate unreachable code. And use it to replace the same pattern at the end of nlrthumb.c:nlr_jump. --- py/mpconfig.h | 9 +++++++++ py/nlrthumb.c | 6 +----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/py/mpconfig.h b/py/mpconfig.h index a21a6c7075..e8f60bd77f 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -1527,6 +1527,15 @@ typedef double mp_float_t; #define MP_UNLIKELY(x) __builtin_expect((x), 0) #endif +// To annotate that code is unreachable +#ifndef MP_UNREACHABLE +#if defined(__GNUC__) +#define MP_UNREACHABLE __builtin_unreachable(); +#else +#define MP_UNREACHABLE for (;;); +#endif +#endif + #ifndef MP_HTOBE16 #if MP_ENDIANNESS_LITTLE # define MP_HTOBE16(x) ((uint16_t)( (((x) & 0xff) << 8) | (((x) >> 8) & 0xff) )) diff --git a/py/nlrthumb.c b/py/nlrthumb.c index eef05229d6..bc30388278 100644 --- a/py/nlrthumb.c +++ b/py/nlrthumb.c @@ -135,11 +135,7 @@ NORETURN void nlr_jump(void *val) { : // clobbered registers ); - #if defined(__GNUC__) - __builtin_unreachable(); - #else - for (;;); // needed to silence compiler warning - #endif + MP_UNREACHABLE } #endif // MICROPY_NLR_THUMB From 11ecdf2ec699c5f78ef7b2bc1bd34618394cc9fa Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 19 Aug 2019 15:51:40 +1000 Subject: [PATCH 0618/1788] py/nlr: Use MP_UNREACHABLE at the end of arch-specific nlr_jump funcs. Recent versions of gcc perform optimisations which can lead to the following code from the MP_NLR_JUMP_HEAD macro being omitted: top->ret_val = val; \ MP_NLR_RESTORE_PYSTACK(top); \ *_top_ptr = top->prev; \ This is noticeable (at least) in the unix coverage on x86-64 built with gcc 9.1.0. This is because the nlr_jump function is marked as no-return, so gcc deduces that the above code has no effect. Adding MP_UNREACHABLE tells the compiler that the asm code may branch elsewhere, and so it cannot optimise away the code. --- py/nlrx64.c | 2 +- py/nlrx86.c | 2 +- py/nlrxtensa.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/py/nlrx64.c b/py/nlrx64.c index a3a1cf341b..95496b3805 100644 --- a/py/nlrx64.c +++ b/py/nlrx64.c @@ -108,7 +108,7 @@ NORETURN void nlr_jump(void *val) { : // clobbered registers ); - for (;;); // needed to silence compiler warning + MP_UNREACHABLE } #endif // MICROPY_NLR_X64 diff --git a/py/nlrx86.c b/py/nlrx86.c index 59b97d8ee6..6195db63cd 100644 --- a/py/nlrx86.c +++ b/py/nlrx86.c @@ -100,7 +100,7 @@ NORETURN void nlr_jump(void *val) { : // clobbered registers ); - for (;;); // needed to silence compiler warning + MP_UNREACHABLE } #endif // MICROPY_NLR_X86 diff --git a/py/nlrxtensa.c b/py/nlrxtensa.c index cd3dee364c..895b2029e8 100644 --- a/py/nlrxtensa.c +++ b/py/nlrxtensa.c @@ -77,7 +77,7 @@ NORETURN void nlr_jump(void *val) { : // clobbered registers ); - for (;;); // needed to silence compiler warning + MP_UNREACHABLE } #endif // MICROPY_NLR_XTENSA From 3a679eaf00b909980ad38344ec0c7395adcd0564 Mon Sep 17 00:00:00 2001 From: Peter Hinch Date: Sat, 17 Aug 2019 13:50:21 +0100 Subject: [PATCH 0619/1788] docs/reference/speed_python: Update that read-only buffers are accepted. As allowed by recent cd35dd9d9a29836906acdce60c931f6352b536d0 --- docs/reference/speed_python.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/reference/speed_python.rst b/docs/reference/speed_python.rst index c5aa80c6e1..f2d7739fb0 100644 --- a/docs/reference/speed_python.rst +++ b/docs/reference/speed_python.rst @@ -293,10 +293,12 @@ microseconds. The rules for casting are as follows: * The argument to a bool cast must be integral type (boolean or integer); when used as a return type the viper function will return True or False objects. * If the argument is a Python object and the cast is ``ptr``, ``ptr``, ``ptr16`` or ``ptr32``, - then the Python object must either have the buffer protocol with read-write capabilities - (in which case a pointer to the start of the buffer is returned) or it must be of integral - type (in which case the value of that integral object is returned). - + then the Python object must either have the buffer protocol (in which case a pointer to the + start of the buffer is returned) or it must be of integral type (in which case the value of + that integral object is returned). + +Writing to a pointer which points to a read-only object will lead to undefined behaviour. + The following example illustrates the use of a ``ptr16`` cast to toggle pin X1 ``n`` times: .. code:: python From 7d851a27f146188752e89bb026021fb8d3985395 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 17 Aug 2019 23:50:19 +1000 Subject: [PATCH 0620/1788] extmod/modure: Make regex dump-code debugging feature optional. Enabled via MICROPY_PY_URE_DEBUG, disabled by default (but enabled on unix coverage build). This is a rarely used feature that costs a lot of code (500-800 bytes flash). Debugging of regular expressions can be done offline with other tools. --- extmod/modure.c | 9 +++++++++ ports/unix/mpconfigport_coverage.h | 1 + py/mpconfig.h | 4 ++++ tests/extmod/ure_debug.py | 3 ++- 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/extmod/modure.c b/extmod/modure.c index 0d5330cb54..8a60207053 100644 --- a/extmod/modure.c +++ b/extmod/modure.c @@ -382,6 +382,7 @@ STATIC const mp_obj_type_t re_type = { }; STATIC mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) { + (void)n_args; const char *re_str = mp_obj_str_get_str(args[0]); int size = re1_5_sizecode(re_str); if (size == -1) { @@ -389,18 +390,22 @@ STATIC mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) { } mp_obj_re_t *o = m_new_obj_var(mp_obj_re_t, char, size); o->base.type = &re_type; + #if MICROPY_PY_URE_DEBUG int flags = 0; if (n_args > 1) { flags = mp_obj_get_int(args[1]); } + #endif int error = re1_5_compilecode(&o->re, re_str); if (error != 0) { error: mp_raise_ValueError("Error in regex"); } + #if MICROPY_PY_URE_DEBUG if (flags & FLAG_DEBUG) { re1_5_dumpcode(&o->re); } + #endif return MP_OBJ_FROM_PTR(o); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_compile_obj, 1, 2, mod_re_compile); @@ -440,7 +445,9 @@ STATIC const mp_rom_map_elem_t mp_module_re_globals_table[] = { #if MICROPY_PY_URE_SUB { MP_ROM_QSTR(MP_QSTR_sub), MP_ROM_PTR(&mod_re_sub_obj) }, #endif + #if MICROPY_PY_URE_DEBUG { MP_ROM_QSTR(MP_QSTR_DEBUG), MP_ROM_INT(FLAG_DEBUG) }, + #endif }; STATIC MP_DEFINE_CONST_DICT(mp_module_re_globals, mp_module_re_globals_table); @@ -455,7 +462,9 @@ const mp_obj_module_t mp_module_ure = { #define re1_5_fatal(x) assert(!x) #include "re1.5/compilecode.c" +#if MICROPY_PY_URE_DEBUG #include "re1.5/dumpcode.c" +#endif #include "re1.5/recursiveloop.c" #include "re1.5/charclass.c" diff --git a/ports/unix/mpconfigport_coverage.h b/ports/unix/mpconfigport_coverage.h index b2f1d6e88e..afd3646490 100644 --- a/ports/unix/mpconfigport_coverage.h +++ b/ports/unix/mpconfigport_coverage.h @@ -50,6 +50,7 @@ #define MICROPY_PY_URANDOM_EXTRA_FUNCS (1) #define MICROPY_PY_IO_BUFFEREDWRITER (1) #define MICROPY_PY_IO_RESOURCE_STREAM (1) +#define MICROPY_PY_URE_DEBUG (1) #define MICROPY_PY_URE_MATCH_GROUPS (1) #define MICROPY_PY_URE_MATCH_SPAN_START_END (1) #define MICROPY_PY_URE_SUB (1) diff --git a/py/mpconfig.h b/py/mpconfig.h index e8f60bd77f..57dec3cf26 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -1259,6 +1259,10 @@ typedef double mp_float_t; #define MICROPY_PY_URE (0) #endif +#ifndef MICROPY_PY_URE_DEBUG +#define MICROPY_PY_URE_DEBUG (0) +#endif + #ifndef MICROPY_PY_URE_MATCH_GROUPS #define MICROPY_PY_URE_MATCH_GROUPS (0) #endif diff --git a/tests/extmod/ure_debug.py b/tests/extmod/ure_debug.py index cfb264bb6d..621fc8d50e 100644 --- a/tests/extmod/ure_debug.py +++ b/tests/extmod/ure_debug.py @@ -1,7 +1,8 @@ # test printing debugging info when compiling try: import ure -except ImportError: + ure.DEBUG +except (ImportError, AttributeError): print("SKIP") raise SystemExit From ae6fe8b43c08abe215dde355e04e561ad2dd1808 Mon Sep 17 00:00:00 2001 From: Milan Rossa Date: Mon, 19 Aug 2019 14:16:33 +0200 Subject: [PATCH 0621/1788] py/compile: Improve the line numbering precision for comprehensions. The line number for comprehensions is now always reported as the correct global location in the script, instead of just "line 1". --- py/compile.c | 3 +++ tests/cmdline/cmd_showbc.py.exp | 2 ++ 2 files changed, 5 insertions(+) diff --git a/py/compile.c b/py/compile.c index 27b706c8fe..c0ae3de114 100644 --- a/py/compile.c +++ b/py/compile.c @@ -3112,6 +3112,9 @@ STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) { scope->num_pos_args = 1; } + // Set the source line number for the start of the comprehension + EMIT_ARG(set_source_line, pns->source_line); + if (scope->kind == SCOPE_LIST_COMP) { EMIT_ARG(build, 0, MP_EMIT_BUILD_LIST); } else if (scope->kind == SCOPE_DICT_COMP) { diff --git a/tests/cmdline/cmd_showbc.py.exp b/tests/cmdline/cmd_showbc.py.exp index 8d36b89df7..8d5d2ffe30 100644 --- a/tests/cmdline/cmd_showbc.py.exp +++ b/tests/cmdline/cmd_showbc.py.exp @@ -449,6 +449,7 @@ arg names: * * * (N_STATE 9) (N_EXC_STACK 0) bc=-\\d\+ line=1 + bc=0 line=59 00 LOAD_NULL 01 LOAD_FAST 2 02 LOAD_NULL @@ -471,6 +472,7 @@ arg names: * * * (N_STATE 10) (N_EXC_STACK 0) bc=-\\d\+ line=1 + bc=0 line=60 00 BUILD_LIST 0 02 LOAD_FAST 2 03 GET_ITER_STACK From 4ab5156c01bfd4a6304e26b1dc2d34163b8637c0 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Sat, 17 Aug 2019 00:32:04 +1000 Subject: [PATCH 0622/1788] tools/mpy-tool.py: Force native func alignment to halfword/word on ARM. This is necessary for ARMV6 and V7. Without this change, calling a frozen native/viper function that is misaligned will crash. --- tools/mpy-tool.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index 648d56fe05..7938ea5dc8 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -471,6 +471,14 @@ class RawCodeNative(RawCode): else: self.fun_data_attributes = '__attribute__((section(".text,\\"ax\\",%progbits @ ")))' + # Allow single-byte alignment by default for x86/x64/xtensa, but on ARM we need halfword- or word- alignment. + if config.native_arch == MP_NATIVE_ARCH_ARMV6: + # ARMV6 -- four byte align. + self.fun_data_attributes += ' __attribute__ ((aligned (4)))' + elif MP_NATIVE_ARCH_ARMV6M <= config.native_arch <= MP_NATIVE_ARCH_ARMV7EMDP: + # ARMVxxM -- two byte align. + self.fun_data_attributes += ' __attribute__ ((aligned (2)))' + def _asm_thumb_rewrite_mov(self, pc, val): print(' (%u & 0xf0) | (%s >> 12),' % (self.bytecode[pc], val), end='') print(' (%u & 0xfb) | (%s >> 9 & 0x04),' % (self.bytecode[pc + 1], val), end='') From 0bd1eb80ff49dd0d4ad0c369a83a5aadea995944 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 19 Aug 2019 10:59:27 +1000 Subject: [PATCH 0623/1788] qemu-arm: Add testing of frozen native modules. - Split 'qemu-arm' from 'unix' for generating tests. - Add frozen module to the qemu-arm test build. - Add test that reproduces the requirement to half-word align native function data. --- ports/qemu-arm/Makefile | 8 ++++++ ports/qemu-arm/Makefile.test | 7 +++-- .../test-frzmpy/native_frozen_align.py | 13 +++++++++ tests/qemu-arm/native_test.py | 5 ++++ tests/qemu-arm/native_test.py.exp | 3 +++ tests/run-tests | 27 ++++++++++++------- tools/tinytest-codegen.py | 4 ++- 7 files changed, 54 insertions(+), 13 deletions(-) create mode 100644 ports/qemu-arm/test-frzmpy/native_frozen_align.py create mode 100644 tests/qemu-arm/native_test.py create mode 100644 tests/qemu-arm/native_test.py.exp diff --git a/ports/qemu-arm/Makefile b/ports/qemu-arm/Makefile index 03a8afe77e..c730c82975 100644 --- a/ports/qemu-arm/Makefile +++ b/ports/qemu-arm/Makefile @@ -114,6 +114,14 @@ OBJ = $(OBJ_COMMON) $(OBJ_RUN) $(OBJ_TEST) # List of sources for qstr extraction SRC_QSTR += $(SRC_COMMON_C) $(SRC_RUN_C) $(LIB_SRC_C) +ifneq ($(FROZEN_MPY_DIR),) +# To use frozen bytecode, put your .py files in a subdirectory (eg frozen/) and +# then invoke make with FROZEN_MPY_DIR=frozen (be sure to build from scratch). +CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool +CFLAGS += -DMICROPY_MODULE_FROZEN_MPY +MPY_CROSS_FLAGS += -march=armv7m +endif + all: run run: $(BUILD)/firmware.elf diff --git a/ports/qemu-arm/Makefile.test b/ports/qemu-arm/Makefile.test index 347c2fefd3..32ec95a4f3 100644 --- a/ports/qemu-arm/Makefile.test +++ b/ports/qemu-arm/Makefile.test @@ -1,5 +1,7 @@ LIB_SRC_C = lib/upytesthelper/upytesthelper.c +FROZEN_MPY_DIR ?= test-frzmpy + include Makefile CFLAGS += -DTEST @@ -8,7 +10,7 @@ CFLAGS += -DTEST $(BUILD)/test_main.o: $(BUILD)/genhdr/tests.h $(BUILD)/genhdr/tests.h: - (cd $(TOP)/tests; ./run-tests --write-exp) + (cd $(TOP)/tests; ./run-tests --target=qemu-arm --write-exp) $(Q)echo "Generating $@";(cd $(TOP)/tests; ../tools/tinytest-codegen.py) > $@ $(BUILD)/tinytest.o: @@ -18,7 +20,8 @@ $(BUILD)/firmware-test.elf: $(OBJ_COMMON) $(OBJ_TEST) $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS) $(Q)$(SIZE) $@ +# Note: Using timeout(1) to handle cases where qemu hangs (e.g. this can happen with alignment errors). test: $(BUILD)/firmware-test.elf - qemu-system-arm -machine $(BOARD) $(QEMU_EXTRA) -nographic -monitor null -semihosting -kernel $< > $(BUILD)/console.out + timeout --foreground -k 5s 30s qemu-system-arm -machine $(BOARD) $(QEMU_EXTRA) -nographic -monitor null -semihosting -kernel $< > $(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/test-frzmpy/native_frozen_align.py b/ports/qemu-arm/test-frzmpy/native_frozen_align.py new file mode 100644 index 0000000000..5c5c0e8d23 --- /dev/null +++ b/ports/qemu-arm/test-frzmpy/native_frozen_align.py @@ -0,0 +1,13 @@ +import micropython + +@micropython.native +def native_x(x): + print(x + 1) + +@micropython.native +def native_y(x): + print(x + 1) + +@micropython.native +def native_z(x): + print(x + 1) diff --git a/tests/qemu-arm/native_test.py b/tests/qemu-arm/native_test.py new file mode 100644 index 0000000000..0b58433d92 --- /dev/null +++ b/tests/qemu-arm/native_test.py @@ -0,0 +1,5 @@ +import native_frozen_align + +native_frozen_align.native_x(1) +native_frozen_align.native_y(2) +native_frozen_align.native_z(3) diff --git a/tests/qemu-arm/native_test.py.exp b/tests/qemu-arm/native_test.py.exp new file mode 100644 index 0000000000..dcf37cd5e2 --- /dev/null +++ b/tests/qemu-arm/native_test.py.exp @@ -0,0 +1,3 @@ +2 +3 +4 diff --git a/tests/run-tests b/tests/run-tests index 9f74c1cfcc..c45d2787e2 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -349,6 +349,8 @@ def run_tests(pyb, tests, args, base_path="."): for t in tests: if t.startswith('basics/io_'): skip_tests.add(t) + elif args.target == 'qemu-arm': + skip_tests.add('misc/print_exception.py') # requires sys stdfiles # Some tests are known to fail on 64-bit machines if pyb is None and platform.architecture()[0] == '64bit': @@ -527,8 +529,9 @@ the last matching regex is used: cmd_parser.add_argument('files', nargs='*', help='input test files') args = cmd_parser.parse_args() + LOCAL_TARGETS = ('unix', 'qemu-arm',) EXTERNAL_TARGETS = ('pyboard', 'wipy', 'esp8266', 'esp32', 'minimal', 'nrf') - if args.target == 'unix' or args.list_tests: + if args.target in LOCAL_TARGETS or args.list_tests: pyb = None elif args.target in EXTERNAL_TARGETS: global pyboard @@ -537,24 +540,28 @@ the last matching regex is used: pyb = pyboard.Pyboard(args.device, args.baudrate, args.user, args.password) pyb.enter_raw_repl() else: - raise ValueError('target must be either %s or unix' % ", ".join(EXTERNAL_TARGETS)) + raise ValueError('target must be one of %s' % ", ".join(LOCAL_TARGETS + EXTERNAL_TARGETS)) if len(args.files) == 0: if args.test_dirs is None: + test_dirs = ('basics', 'micropython', 'misc', 'extmod',) if args.target == 'pyboard': # run pyboard tests - test_dirs = ('basics', 'micropython', 'float', 'misc', 'stress', 'extmod', 'pyb', 'pybnative', 'inlineasm') + test_dirs += ('float', 'stress', 'pyb', 'pybnative', 'inlineasm') elif args.target in ('esp8266', 'esp32', 'minimal', 'nrf'): - test_dirs = ('basics', 'micropython', 'float', 'misc', 'extmod') + test_dirs += ('float',) elif args.target == 'wipy': # run WiPy tests - test_dirs = ('basics', 'micropython', 'misc', 'extmod', 'wipy') - else: + test_dirs += ('wipy',) + elif args.target == 'unix': # run PC tests - test_dirs = ( - 'basics', 'micropython', 'float', 'import', 'io', 'misc', - 'stress', 'unicode', 'extmod', 'unix', 'cmdline', - ) + test_dirs += ('float', 'import', 'io', 'stress', 'unicode', 'unix', 'cmdline',) + elif args.target == 'qemu-arm': + if not args.write_exp: + raise ValueError('--target=qemu-arm must be used with --write-exp') + # Generate expected output files for qemu run. + # This list should match the test_dirs tuple in tinytest-codegen.py. + test_dirs += ('float', 'inlineasm', 'qemu-arm',) else: # run tests from these directories test_dirs = args.test_dirs diff --git a/tools/tinytest-codegen.py b/tools/tinytest-codegen.py index ad3b3bbec9..bdace1c8b5 100755 --- a/tools/tinytest-codegen.py +++ b/tools/tinytest-codegen.py @@ -54,7 +54,7 @@ testgroup_member = ( ## XXX: may be we could have `--without ` argument... # currently these tests are selected because they pass on qemu-arm -test_dirs = ('basics', 'micropython', 'float', 'extmod', 'inlineasm') # 'import', 'io', 'misc') +test_dirs = ('basics', 'micropython', 'misc', 'extmod', 'float', 'inlineasm', 'qemu-arm',) # 'import', 'io',) exclude_tests = ( # pattern matching in .exp 'basics/bytes_compare3.py', @@ -81,6 +81,8 @@ exclude_tests = ( 'micropython/heapalloc_traceback.py', # pattern matching in .exp 'micropython/meminfo.py', + # needs sys stdfiles + 'misc/print_exception.py', ) output = [] From 3327dfc16edf5110370c53de38bb4941a12928a3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 19 Aug 2019 22:29:24 +1000 Subject: [PATCH 0624/1788] extmod/moducryptolib: Use "static" not "STATIC" for inline functions. --- extmod/moducryptolib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extmod/moducryptolib.c b/extmod/moducryptolib.c index 15cd4535f8..fd487a816c 100644 --- a/extmod/moducryptolib.c +++ b/extmod/moducryptolib.c @@ -89,7 +89,7 @@ typedef struct _mp_obj_aes_t { uint8_t key_type: 2; } mp_obj_aes_t; -STATIC inline bool is_ctr_mode(int block_mode) { +static inline bool is_ctr_mode(int block_mode) { #if MICROPY_PY_UCRYPTOLIB_CTR return block_mode == UCRYPTOLIB_MODE_CTR; #else @@ -97,7 +97,7 @@ STATIC inline bool is_ctr_mode(int block_mode) { #endif } -STATIC inline struct ctr_params *ctr_params_from_aes(mp_obj_aes_t *o) { +static inline struct ctr_params *ctr_params_from_aes(mp_obj_aes_t *o) { // ctr_params follows aes object struct return (struct ctr_params*)&o[1]; } From 0cc8910bc58c1a1f69a696f5efe4ccf0ffcf2984 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 19 Aug 2019 22:29:53 +1000 Subject: [PATCH 0625/1788] extmod: Give vars/funcs unique names so STATIC can be set to nothing. Fixes issue #5018. --- extmod/moduheapq.c | 20 ++++++++++---------- extmod/modussl_axtls.c | 26 +++++++++++++------------- extmod/modutimeq.c | 20 ++++++++++---------- extmod/vfs_fat_file.c | 16 ++++++++-------- extmod/vfs_posix_file.c | 16 ++++++++-------- 5 files changed, 49 insertions(+), 49 deletions(-) diff --git a/extmod/moduheapq.c b/extmod/moduheapq.c index bdaf191e94..1574eb8627 100644 --- a/extmod/moduheapq.c +++ b/extmod/moduheapq.c @@ -31,14 +31,14 @@ // the algorithm here is modelled on CPython's heapq.py -STATIC mp_obj_list_t *get_heap(mp_obj_t heap_in) { +STATIC mp_obj_list_t *uheapq_get_heap(mp_obj_t heap_in) { if (!mp_obj_is_type(heap_in, &mp_type_list)) { mp_raise_TypeError("heap must be a list"); } return MP_OBJ_TO_PTR(heap_in); } -STATIC void heap_siftdown(mp_obj_list_t *heap, mp_uint_t start_pos, mp_uint_t pos) { +STATIC void uheapq_heap_siftdown(mp_obj_list_t *heap, mp_uint_t start_pos, mp_uint_t pos) { mp_obj_t item = heap->items[pos]; while (pos > start_pos) { mp_uint_t parent_pos = (pos - 1) >> 1; @@ -53,7 +53,7 @@ STATIC void heap_siftdown(mp_obj_list_t *heap, mp_uint_t start_pos, mp_uint_t po heap->items[pos] = item; } -STATIC void heap_siftup(mp_obj_list_t *heap, mp_uint_t pos) { +STATIC void uheapq_heap_siftup(mp_obj_list_t *heap, mp_uint_t pos) { mp_uint_t start_pos = pos; mp_uint_t end_pos = heap->len; mp_obj_t item = heap->items[pos]; @@ -67,19 +67,19 @@ STATIC void heap_siftup(mp_obj_list_t *heap, mp_uint_t pos) { pos = child_pos; } heap->items[pos] = item; - heap_siftdown(heap, start_pos, pos); + uheapq_heap_siftdown(heap, start_pos, pos); } STATIC mp_obj_t mod_uheapq_heappush(mp_obj_t heap_in, mp_obj_t item) { - mp_obj_list_t *heap = get_heap(heap_in); + mp_obj_list_t *heap = uheapq_get_heap(heap_in); mp_obj_list_append(heap_in, item); - heap_siftdown(heap, 0, heap->len - 1); + uheapq_heap_siftdown(heap, 0, heap->len - 1); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_uheapq_heappush_obj, mod_uheapq_heappush); STATIC mp_obj_t mod_uheapq_heappop(mp_obj_t heap_in) { - mp_obj_list_t *heap = get_heap(heap_in); + mp_obj_list_t *heap = uheapq_get_heap(heap_in); if (heap->len == 0) { nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "empty heap")); } @@ -88,16 +88,16 @@ STATIC mp_obj_t mod_uheapq_heappop(mp_obj_t heap_in) { heap->items[0] = heap->items[heap->len]; heap->items[heap->len] = MP_OBJ_NULL; // so we don't retain a pointer if (heap->len) { - heap_siftup(heap, 0); + uheapq_heap_siftup(heap, 0); } return item; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_uheapq_heappop_obj, mod_uheapq_heappop); STATIC mp_obj_t mod_uheapq_heapify(mp_obj_t heap_in) { - mp_obj_list_t *heap = get_heap(heap_in); + mp_obj_list_t *heap = uheapq_get_heap(heap_in); for (mp_uint_t i = heap->len / 2; i > 0;) { - heap_siftup(heap, --i); + uheapq_heap_siftup(heap, --i); } return mp_const_none; } diff --git a/extmod/modussl_axtls.c b/extmod/modussl_axtls.c index b559b13580..2ea1757287 100644 --- a/extmod/modussl_axtls.c +++ b/extmod/modussl_axtls.c @@ -54,7 +54,7 @@ struct ssl_args { STATIC const mp_obj_type_t ussl_socket_type; -STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { +STATIC mp_obj_ssl_socket_t *ussl_socket_new(mp_obj_t sock, struct ssl_args *args) { #if MICROPY_PY_USSL_FINALISER mp_obj_ssl_socket_t *o = m_new_obj_with_finaliser(mp_obj_ssl_socket_t); #else @@ -118,13 +118,13 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { return o; } -STATIC void socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { +STATIC void ussl_socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in); mp_printf(print, "<_SSLSocket %p>", self->ssl_sock); } -STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { +STATIC mp_uint_t ussl_socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in); if (o->ssl_sock == NULL) { @@ -173,7 +173,7 @@ eagain: return size; } -STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) { +STATIC mp_uint_t ussl_socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) { mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in); if (o->ssl_sock == NULL) { @@ -189,7 +189,7 @@ 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) { +STATIC mp_uint_t ussl_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); if (request == MP_STREAM_CLOSE && self->ssl_sock != NULL) { ssl_free(self->ssl_sock); @@ -200,7 +200,7 @@ STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, i return mp_get_stream(self->sock)->ioctl(self->sock, request, arg, errcode); } -STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) { +STATIC mp_obj_t ussl_socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) { mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(self_in); mp_obj_t sock = o->sock; mp_obj_t dest[3]; @@ -210,14 +210,14 @@ STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) { o->blocking = mp_obj_is_true(flag_in); return res; } -STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(ussl_socket_setblocking_obj, ussl_socket_setblocking); 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_setblocking), MP_ROM_PTR(&ussl_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(&mp_stream_close_obj) }, @@ -227,16 +227,16 @@ STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = { STATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_table); STATIC const mp_stream_p_t ussl_socket_stream_p = { - .read = socket_read, - .write = socket_write, - .ioctl = socket_ioctl, + .read = ussl_socket_read, + .write = ussl_socket_write, + .ioctl = ussl_socket_ioctl, }; STATIC const mp_obj_type_t ussl_socket_type = { { &mp_type_type }, // Save on qstr's, reuse same as for module .name = MP_QSTR_ussl, - .print = socket_print, + .print = ussl_socket_print, .getiter = NULL, .iternext = NULL, .protocol = &ussl_socket_stream_p, @@ -260,7 +260,7 @@ STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args); - return MP_OBJ_FROM_PTR(socket_new(sock, &args)); + return MP_OBJ_FROM_PTR(ussl_socket_new(sock, &args)); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 1, mod_ssl_wrap_socket); diff --git a/extmod/modutimeq.c b/extmod/modutimeq.c index 26f5a78fae..28a2a70c5e 100644 --- a/extmod/modutimeq.c +++ b/extmod/modutimeq.c @@ -55,7 +55,7 @@ typedef struct _mp_obj_utimeq_t { STATIC mp_uint_t utimeq_id; -STATIC mp_obj_utimeq_t *get_heap(mp_obj_t heap_in) { +STATIC mp_obj_utimeq_t *utimeq_get_heap(mp_obj_t heap_in) { return MP_OBJ_TO_PTR(heap_in); } @@ -85,7 +85,7 @@ STATIC mp_obj_t utimeq_make_new(const mp_obj_type_t *type, size_t n_args, size_t return MP_OBJ_FROM_PTR(o); } -STATIC void heap_siftdown(mp_obj_utimeq_t *heap, mp_uint_t start_pos, mp_uint_t pos) { +STATIC void utimeq_heap_siftdown(mp_obj_utimeq_t *heap, mp_uint_t start_pos, mp_uint_t pos) { struct qentry item = heap->items[pos]; while (pos > start_pos) { mp_uint_t parent_pos = (pos - 1) >> 1; @@ -101,7 +101,7 @@ STATIC void heap_siftdown(mp_obj_utimeq_t *heap, mp_uint_t start_pos, mp_uint_t heap->items[pos] = item; } -STATIC void heap_siftup(mp_obj_utimeq_t *heap, mp_uint_t pos) { +STATIC void utimeq_heap_siftup(mp_obj_utimeq_t *heap, mp_uint_t pos) { mp_uint_t start_pos = pos; mp_uint_t end_pos = heap->len; struct qentry item = heap->items[pos]; @@ -118,13 +118,13 @@ STATIC void heap_siftup(mp_obj_utimeq_t *heap, mp_uint_t pos) { pos = child_pos; } heap->items[pos] = item; - heap_siftdown(heap, start_pos, pos); + utimeq_heap_siftdown(heap, start_pos, pos); } STATIC mp_obj_t mod_utimeq_heappush(size_t n_args, const mp_obj_t *args) { (void)n_args; mp_obj_t heap_in = args[0]; - mp_obj_utimeq_t *heap = get_heap(heap_in); + mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in); if (heap->len == heap->alloc) { mp_raise_msg(&mp_type_IndexError, "queue overflow"); } @@ -133,14 +133,14 @@ STATIC mp_obj_t mod_utimeq_heappush(size_t n_args, const mp_obj_t *args) { heap->items[l].id = utimeq_id++; heap->items[l].callback = args[2]; heap->items[l].args = args[3]; - heap_siftdown(heap, 0, heap->len); + utimeq_heap_siftdown(heap, 0, heap->len); heap->len++; return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_utimeq_heappush_obj, 4, 4, mod_utimeq_heappush); STATIC mp_obj_t mod_utimeq_heappop(mp_obj_t heap_in, mp_obj_t list_ref) { - mp_obj_utimeq_t *heap = get_heap(heap_in); + mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in); if (heap->len == 0) { nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "empty heap")); } @@ -158,14 +158,14 @@ STATIC mp_obj_t mod_utimeq_heappop(mp_obj_t heap_in, mp_obj_t list_ref) { heap->items[heap->len].callback = MP_OBJ_NULL; // so we don't retain a pointer heap->items[heap->len].args = MP_OBJ_NULL; if (heap->len) { - heap_siftup(heap, 0); + utimeq_heap_siftup(heap, 0); } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_utimeq_heappop_obj, mod_utimeq_heappop); STATIC mp_obj_t mod_utimeq_peektime(mp_obj_t heap_in) { - mp_obj_utimeq_t *heap = get_heap(heap_in); + mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in); if (heap->len == 0) { nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "empty heap")); } @@ -177,7 +177,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_utimeq_peektime_obj, mod_utimeq_peektime); #if DEBUG STATIC mp_obj_t mod_utimeq_dump(mp_obj_t heap_in) { - mp_obj_utimeq_t *heap = get_heap(heap_in); + mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in); for (int i = 0; i < heap->len; i++) { printf(UINT_FMT "\t%p\t%p\n", heap->items[i].time, MP_OBJ_TO_PTR(heap->items[i].callback), MP_OBJ_TO_PTR(heap->items[i].args)); diff --git a/extmod/vfs_fat_file.c b/extmod/vfs_fat_file.c index f7b9331b82..fb1e582f27 100644 --- a/extmod/vfs_fat_file.c +++ b/extmod/vfs_fat_file.c @@ -219,7 +219,7 @@ STATIC mp_obj_t file_obj_make_new(const mp_obj_type_t *type, size_t n_args, size // TODO gc hook to close the file if not already closed -STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = { +STATIC const mp_rom_map_elem_t vfs_fat_rawfile_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) }, @@ -234,10 +234,10 @@ STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&file_obj___exit___obj) }, }; -STATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict, rawfile_locals_dict_table); +STATIC MP_DEFINE_CONST_DICT(vfs_fat_rawfile_locals_dict, vfs_fat_rawfile_locals_dict_table); #if MICROPY_PY_IO_FILEIO -STATIC const mp_stream_p_t fileio_stream_p = { +STATIC const mp_stream_p_t vfs_fat_fileio_stream_p = { .read = file_obj_read, .write = file_obj_write, .ioctl = file_obj_ioctl, @@ -250,12 +250,12 @@ const mp_obj_type_t mp_type_vfs_fat_fileio = { .make_new = file_obj_make_new, .getiter = mp_identity_getiter, .iternext = mp_stream_unbuffered_iter, - .protocol = &fileio_stream_p, - .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict, + .protocol = &vfs_fat_fileio_stream_p, + .locals_dict = (mp_obj_dict_t*)&vfs_fat_rawfile_locals_dict, }; #endif -STATIC const mp_stream_p_t textio_stream_p = { +STATIC const mp_stream_p_t vfs_fat_textio_stream_p = { .read = file_obj_read, .write = file_obj_write, .ioctl = file_obj_ioctl, @@ -269,8 +269,8 @@ const mp_obj_type_t mp_type_vfs_fat_textio = { .make_new = file_obj_make_new, .getiter = mp_identity_getiter, .iternext = mp_stream_unbuffered_iter, - .protocol = &textio_stream_p, - .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict, + .protocol = &vfs_fat_textio_stream_p, + .locals_dict = (mp_obj_dict_t*)&vfs_fat_rawfile_locals_dict, }; // Factory function for I/O stream classes diff --git a/extmod/vfs_posix_file.c b/extmod/vfs_posix_file.c index 44cb85dcc7..6f7ce814f3 100644 --- a/extmod/vfs_posix_file.c +++ b/extmod/vfs_posix_file.c @@ -200,7 +200,7 @@ STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_ } } -STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = { +STATIC const mp_rom_map_elem_t vfs_posix_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) }, @@ -215,10 +215,10 @@ STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = { { 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); +STATIC MP_DEFINE_CONST_DICT(vfs_posix_rawfile_locals_dict, vfs_posix_rawfile_locals_dict_table); #if MICROPY_PY_IO_FILEIO -STATIC const mp_stream_p_t fileio_stream_p = { +STATIC const mp_stream_p_t vfs_posix_fileio_stream_p = { .read = vfs_posix_file_read, .write = vfs_posix_file_write, .ioctl = vfs_posix_file_ioctl, @@ -231,12 +231,12 @@ const mp_obj_type_t mp_type_vfs_posix_fileio = { .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, + .protocol = &vfs_posix_fileio_stream_p, + .locals_dict = (mp_obj_dict_t*)&vfs_posix_rawfile_locals_dict, }; #endif -STATIC const mp_stream_p_t textio_stream_p = { +STATIC const mp_stream_p_t vfs_posix_textio_stream_p = { .read = vfs_posix_file_read, .write = vfs_posix_file_write, .ioctl = vfs_posix_file_ioctl, @@ -250,8 +250,8 @@ const mp_obj_type_t mp_type_vfs_posix_textio = { .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, + .protocol = &vfs_posix_textio_stream_p, + .locals_dict = (mp_obj_dict_t*)&vfs_posix_rawfile_locals_dict, }; const mp_obj_vfs_posix_file_t mp_sys_stdin_obj = {{&mp_type_textio}, STDIN_FILENO}; From 05eb897d06cc4da04dd96f3b661b617b98cb6800 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 9 Jul 2019 15:08:52 +1000 Subject: [PATCH 0626/1788] esp32: Add esp32.Partition class to expose partition and OTA funcs. Partitions are exposed as a standard MicroPython block device. --- docs/library/esp32.rst | 45 +++++++ ports/esp32/Makefile | 7 ++ ports/esp32/esp32_partition.c | 223 ++++++++++++++++++++++++++++++++++ ports/esp32/modesp32.c | 1 + ports/esp32/modesp32.h | 1 + 5 files changed, 277 insertions(+) create mode 100644 ports/esp32/esp32_partition.c diff --git a/docs/library/esp32.rst b/docs/library/esp32.rst index c934ef0954..a593965ae2 100644 --- a/docs/library/esp32.rst +++ b/docs/library/esp32.rst @@ -36,6 +36,51 @@ Functions Read the raw value of the internal Hall sensor, returning an integer. +Flash partitions +---------------- + +This class gives access to the partitions in the device's flash memory. + +.. class:: Partition(id) + + Create an object representing a partition. *id* can be a string which is the label + of the partition to retrieve, or one of the constants: ``BOOT`` or ``RUNNING``. + +.. classmethod:: Partition.find(type=TYPE_APP, subtype=0xff, label=None) + + Find a partition specified by *type*, *subtype* and *label*. Returns a + (possibly empty) list of Partition objects. + +.. method:: Partition.info() + + Returns a 6-tuple ``(type, subtype, addr, size, label, encrypted)``. + +.. method:: Partition.readblocks(block_num, buf) +.. method:: Partition.writeblocks(block_num, buf) +.. method:: Partition.ioctl(cmd, arg) + + These methods implement the block protocol defined by :class:`uos.AbstractBlockDev`. + +.. method:: Partition.set_boot() + + Sets the partition as the boot partition. + +.. method:: Partition.get_next_update() + + Gets the next update partition after this one, and returns a new Partition object. + +Constants +~~~~~~~~~ + +.. data:: Partition.BOOT + Partition.RUNNING + + Used in the `Partition` constructor to fetch various partitions. + +.. data:: Partition.TYPE_APP + Partition.TYPE_DATA + + Used in `Partition.find` to specify the partition type. The Ultra-Low-Power co-processor -------------------------------- diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 3802c2fc9c..06cb553f4d 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -128,6 +128,7 @@ INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/mbedtls/include INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/port/include INC_ESPCOMP += -I$(ESPCOMP)/mdns/include INC_ESPCOMP += -I$(ESPCOMP)/mdns/private_include +INC_ESPCOMP += -I$(ESPCOMP)/micro-ecc/micro-ecc INC_ESPCOMP += -I$(ESPCOMP)/spi_flash/include INC_ESPCOMP += -I$(ESPCOMP)/ulp/include INC_ESPCOMP += -I$(ESPCOMP)/vfs/include @@ -216,6 +217,7 @@ SRC_C = \ network_ppp.c \ modsocket.c \ modesp.c \ + esp32_partition.c \ esp32_ulp.c \ modesp32.c \ espneopixel.c \ @@ -288,6 +290,10 @@ $(HEADER_BUILD)/qstrdefs.generated.h: $(SDKCONFIG_H) $(BOARD_DIR)/mpconfigboard. ################################################################################ # List of object files from the ESP32 IDF components +ESPIDF_BOOTLOADER_SUPPORT_O = $(subst .c,.o,\ + $(filter-out $(ESPCOMP)/bootloader_support/src/bootloader_init.c,\ + $(wildcard $(ESPCOMP)/bootloader_support/src/*.c))) + ESPIDF_DRIVER_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/driver/*.c)) ESPIDF_EFUSE_O = $(patsubst %.c,%.o,\ @@ -399,6 +405,7 @@ $(BUILD_ESPIDF_LIB)/$(1)/lib$(1).a: $(addprefix $$(BUILD)/,$(2)) $(Q)$(AR) cru $$@ $$^ endef +$(eval $(call gen_espidf_lib_rule,bootloader_support,$(ESPIDF_BOOTLOADER_SUPPORT_O))) $(eval $(call gen_espidf_lib_rule,driver,$(ESPIDF_DRIVER_O))) $(eval $(call gen_espidf_lib_rule,efuse,$(ESPIDF_EFUSE_O))) $(eval $(call gen_espidf_lib_rule,esp32,$(ESPIDF_ESP32_O))) diff --git a/ports/esp32/esp32_partition.c b/ports/esp32/esp32_partition.c new file mode 100644 index 0000000000..49bb0632e3 --- /dev/null +++ b/ports/esp32/esp32_partition.c @@ -0,0 +1,223 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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/mperrno.h" +#include "extmod/vfs.h" +#include "modesp32.h" +#include "esp_ota_ops.h" + +// esp_partition_read and esp_partition_write can operate on arbitrary bytes +// but esp_partition_erase_range operates on 4k blocks. But to make a partition +// implement the standard block protocol all operations are done on 4k blocks. +#define BLOCK_SIZE_BYTES (4096) + +enum { + ESP32_PARTITION_BOOT, + ESP32_PARTITION_RUNNING, +}; + +typedef struct _esp32_partition_obj_t { + mp_obj_base_t base; + const esp_partition_t *part; +} esp32_partition_obj_t; + +static inline void check_esp_err(esp_err_t e) { + if (e != ESP_OK) { + mp_raise_OSError(-e); + } +} + +STATIC esp32_partition_obj_t *esp32_partition_new(const esp_partition_t *part) { + if (part == NULL) { + mp_raise_OSError(MP_ENOENT); + } + esp32_partition_obj_t *self = m_new_obj(esp32_partition_obj_t); + self->base.type = &esp32_partition_type; + self->part = part; + return self; +} + +STATIC void esp32_partition_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + esp32_partition_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "", + self->part->type, self->part->subtype, + self->part->address, self->part->size, + &self->part->label[0], self->part->encrypted + ); +} + +STATIC mp_obj_t esp32_partition_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + // Check args + mp_arg_check_num(n_args, n_kw, 1, 1, false); + + // Get requested partition + const esp_partition_t *part; + if (mp_obj_is_int(all_args[0])) { + // Integer given, get that particular partition + switch (mp_obj_get_int(all_args[0])) { + case ESP32_PARTITION_BOOT: + part = esp_ota_get_boot_partition(); + break; + case ESP32_PARTITION_RUNNING: + part = esp_ota_get_running_partition(); + break; + default: + mp_raise_ValueError(NULL); + } + } else { + // String given, search for partition with that label + const char *label = mp_obj_str_get_str(all_args[0]); + part = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, label); + if (part == NULL) { + part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, label); + } + } + + // Return new object + return MP_OBJ_FROM_PTR(esp32_partition_new(part)); +} + +STATIC mp_obj_t esp32_partition_find(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // Parse args + enum { ARG_type, ARG_subtype, ARG_label }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_type, MP_ARG_INT, {.u_int = ESP_PARTITION_TYPE_APP} }, + { MP_QSTR_subtype, MP_ARG_INT, {.u_int = ESP_PARTITION_SUBTYPE_ANY} }, + { MP_QSTR_label, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + }; + 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); + + // Get optional label string + const char *label = NULL; + if (args[ARG_label].u_obj != mp_const_none) { + label = mp_obj_str_get_str(args[ARG_label].u_obj); + } + + // Build list of matching partitions + mp_obj_t list = mp_obj_new_list(0, NULL); + esp_partition_iterator_t iter = esp_partition_find(args[ARG_type].u_int, args[ARG_subtype].u_int, label); + while (iter != NULL) { + mp_obj_list_append(list, MP_OBJ_FROM_PTR(esp32_partition_new(esp_partition_get(iter)))); + iter = esp_partition_next(iter); + } + esp_partition_iterator_release(iter); + + return list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp32_partition_find_fun_obj, 0, esp32_partition_find); +STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(esp32_partition_find_obj, MP_ROM_PTR(&esp32_partition_find_fun_obj)); + +STATIC mp_obj_t esp32_partition_info(mp_obj_t self_in) { + esp32_partition_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t tuple[] = { + MP_OBJ_NEW_SMALL_INT(self->part->type), + MP_OBJ_NEW_SMALL_INT(self->part->subtype), + mp_obj_new_int_from_uint(self->part->address), + mp_obj_new_int_from_uint(self->part->size), + mp_obj_new_str(&self->part->label[0], strlen(&self->part->label[0])), + mp_obj_new_bool(self->part->encrypted), + }; + return mp_obj_new_tuple(6, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_partition_info_obj, esp32_partition_info); + +STATIC mp_obj_t esp32_partition_readblocks(mp_obj_t self_in, mp_obj_t block_num, mp_obj_t buf_in) { + esp32_partition_obj_t *self = MP_OBJ_TO_PTR(self_in); + uint32_t offset = mp_obj_get_int(block_num) * BLOCK_SIZE_BYTES; + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE); + check_esp_err(esp_partition_read(self->part, offset, bufinfo.buf, bufinfo.len)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp32_partition_readblocks_obj, esp32_partition_readblocks); + +STATIC mp_obj_t esp32_partition_writeblocks(mp_obj_t self_in, mp_obj_t block_num, mp_obj_t buf_in) { + esp32_partition_obj_t *self = MP_OBJ_TO_PTR(self_in); + uint32_t offset = mp_obj_get_int(block_num) * BLOCK_SIZE_BYTES; + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); + check_esp_err(esp_partition_erase_range(self->part, offset, bufinfo.len)); + check_esp_err(esp_partition_write(self->part, offset, bufinfo.buf, bufinfo.len)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp32_partition_writeblocks_obj, esp32_partition_writeblocks); + +STATIC mp_obj_t esp32_partition_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t arg_in) { + esp32_partition_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_int_t cmd = mp_obj_get_int(cmd_in); + switch (cmd) { + case BP_IOCTL_INIT: return MP_OBJ_NEW_SMALL_INT(0); + case BP_IOCTL_DEINIT: return MP_OBJ_NEW_SMALL_INT(0); + case BP_IOCTL_SYNC: return MP_OBJ_NEW_SMALL_INT(0); + case BP_IOCTL_SEC_COUNT: return MP_OBJ_NEW_SMALL_INT(self->part->size / BLOCK_SIZE_BYTES); + case BP_IOCTL_SEC_SIZE: return MP_OBJ_NEW_SMALL_INT(BLOCK_SIZE_BYTES); + default: return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp32_partition_ioctl_obj, esp32_partition_ioctl); + +STATIC mp_obj_t esp32_partition_set_boot(mp_obj_t self_in) { + esp32_partition_obj_t *self = MP_OBJ_TO_PTR(self_in); + esp_ota_set_boot_partition(self->part); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_partition_set_boot_obj, esp32_partition_set_boot); + +STATIC mp_obj_t esp32_partition_get_next_update(mp_obj_t self_in) { + esp32_partition_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_FROM_PTR(esp32_partition_new(esp_ota_get_next_update_partition(self->part))); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_partition_get_next_update_obj, esp32_partition_get_next_update); + +STATIC const mp_rom_map_elem_t esp32_partition_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_find), MP_ROM_PTR(&esp32_partition_find_obj) }, + + { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&esp32_partition_info_obj) }, + { MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&esp32_partition_readblocks_obj) }, + { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&esp32_partition_writeblocks_obj) }, + { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&esp32_partition_ioctl_obj) }, + + { MP_ROM_QSTR(MP_QSTR_set_boot), MP_ROM_PTR(&esp32_partition_set_boot_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_next_update), MP_ROM_PTR(&esp32_partition_get_next_update_obj) }, + + { MP_ROM_QSTR(MP_QSTR_BOOT), MP_ROM_INT(ESP32_PARTITION_BOOT) }, + { MP_ROM_QSTR(MP_QSTR_RUNNING), MP_ROM_INT(ESP32_PARTITION_RUNNING) }, + { MP_ROM_QSTR(MP_QSTR_TYPE_APP), MP_ROM_INT(ESP_PARTITION_TYPE_APP) }, + { MP_ROM_QSTR(MP_QSTR_TYPE_DATA), MP_ROM_INT(ESP_PARTITION_TYPE_DATA) }, +}; +STATIC MP_DEFINE_CONST_DICT(esp32_partition_locals_dict, esp32_partition_locals_dict_table); + +const mp_obj_type_t esp32_partition_type = { + { &mp_type_type }, + .name = MP_QSTR_Partition, + .print = esp32_partition_print, + .make_new = esp32_partition_make_new, + .locals_dict = (mp_obj_dict_t*)&esp32_partition_locals_dict, +}; diff --git a/ports/esp32/modesp32.c b/ports/esp32/modesp32.c index 2e2d8236cf..ada8811676 100644 --- a/ports/esp32/modesp32.c +++ b/ports/esp32/modesp32.c @@ -154,6 +154,7 @@ STATIC const mp_rom_map_elem_t esp32_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_raw_temperature), MP_ROM_PTR(&esp32_raw_temperature_obj) }, { MP_ROM_QSTR(MP_QSTR_hall_sensor), MP_ROM_PTR(&esp32_hall_sensor_obj) }, + { MP_ROM_QSTR(MP_QSTR_Partition), MP_ROM_PTR(&esp32_partition_type) }, { MP_ROM_QSTR(MP_QSTR_ULP), MP_ROM_PTR(&esp32_ulp_type) }, { MP_ROM_QSTR(MP_QSTR_WAKEUP_ALL_LOW), MP_ROM_PTR(&mp_const_false_obj) }, diff --git a/ports/esp32/modesp32.h b/ports/esp32/modesp32.h index 1d18cb41fb..26eec8ae69 100644 --- a/ports/esp32/modesp32.h +++ b/ports/esp32/modesp32.h @@ -26,6 +26,7 @@ #define RTC_LAST_EXT_PIN 39 #define RTC_IS_VALID_EXT_PIN(pin_id) ((1ll << (pin_id)) & RTC_VALID_EXT_PINS) +extern const mp_obj_type_t esp32_partition_type; extern const mp_obj_type_t esp32_ulp_type; #endif // MICROPY_INCLUDED_ESP32_MODESP32_H From fe3c064d42daeb02ee9a6ac91f657d397c0a20fa Mon Sep 17 00:00:00 2001 From: roland van straten Date: Fri, 16 Aug 2019 10:29:39 +0200 Subject: [PATCH 0627/1788] samd: Add minimum config for Atmel SAMD21-XPLAINED-PRO board. --- ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.h | 2 ++ ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.mk | 4 ++++ 2 files changed, 6 insertions(+) create mode 100644 ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.h create mode 100644 ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.mk diff --git a/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.h b/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.h new file mode 100644 index 0000000000..c69b5b4c14 --- /dev/null +++ b/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.h @@ -0,0 +1,2 @@ +#define MICROPY_HW_BOARD_NAME "SAMD21-XPLAINED-PRO" +#define MICROPY_HW_MCU_NAME "SAMD21J18A" diff --git a/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.mk b/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.mk new file mode 100644 index 0000000000..f95c654938 --- /dev/null +++ b/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.mk @@ -0,0 +1,4 @@ +MCU_SERIES = SAMD21 +CMSIS_MCU = SAMD21J18A +LD_FILES = boards/samd21x18a.ld sections.ld +TEXT0 = 0x2000 From 96ace8082e409c582911239ee913a95d955058bf Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 21 Aug 2019 21:16:40 +1000 Subject: [PATCH 0628/1788] esp8266/machine_uart: Allow remapping UART TX/RX pins from 1/3 to 15/13. Via the standard tx/rx arguments: UART(0, 115200, tx=Pin(15), rx=Pin(13)). Resolves issue #4718. --- ports/esp8266/machine_uart.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/ports/esp8266/machine_uart.c b/ports/esp8266/machine_uart.c index 21336c7fd4..9aaa160922 100644 --- a/ports/esp8266/machine_uart.c +++ b/ports/esp8266/machine_uart.c @@ -29,11 +29,13 @@ #include #include "ets_sys.h" +#include "user_interface.h" #include "uart.h" #include "py/runtime.h" #include "py/stream.h" #include "py/mperrno.h" +#include "py/mphal.h" #include "modmachine.h" // UartDev is defined and initialized in rom code. @@ -63,14 +65,14 @@ STATIC void pyb_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_k } STATIC void pyb_uart_init_helper(pyb_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_rxbuf, ARG_timeout, ARG_timeout_char }; + enum { ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_tx, ARG_rx, ARG_rxbuf, 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_OBJ, {.u_obj = MP_OBJ_NULL} }, - //{ MP_QSTR_rx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_tx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_rx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_rxbuf, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, { 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} }, @@ -128,6 +130,22 @@ STATIC void pyb_uart_init_helper(pyb_uart_obj_t *self, size_t n_args, const mp_o } } + // set tx/rx pins + mp_hal_pin_obj_t tx = 1, rx = 3; + if (args[ARG_tx].u_obj != MP_OBJ_NULL) { + tx = mp_hal_get_pin_obj(args[ARG_tx].u_obj); + } + if (args[ARG_rx].u_obj != MP_OBJ_NULL) { + rx = mp_hal_get_pin_obj(args[ARG_rx].u_obj); + } + if (tx == 1 && rx == 3) { + system_uart_de_swap(); + } else if (tx == 15 && rx == 13) { + system_uart_swap(); + } else { + mp_raise_ValueError("invalid tx/rx"); + } + // set stop bits switch (args[ARG_stop].u_int) { case 0: From 3d9bd80447c0834fae6746d45a0b45b3eb9cda6c Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 22 Aug 2019 14:36:27 +1000 Subject: [PATCH 0629/1788] py/emitbc: Rewrite switch in load_const_tok to reduce code size. --- py/emitbc.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/py/emitbc.c b/py/emitbc.c index 35eb6df9c0..bb05169da3 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -524,15 +524,13 @@ 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) { + MP_STATIC_ASSERT(MP_BC_LOAD_CONST_FALSE + (MP_TOKEN_KW_NONE - MP_TOKEN_KW_FALSE) == MP_BC_LOAD_CONST_NONE); + MP_STATIC_ASSERT(MP_BC_LOAD_CONST_FALSE + (MP_TOKEN_KW_TRUE - MP_TOKEN_KW_FALSE) == MP_BC_LOAD_CONST_TRUE); emit_bc_pre(emit, 1); - switch (tok) { - case MP_TOKEN_KW_FALSE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_FALSE); break; - case MP_TOKEN_KW_NONE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_NONE); break; - case MP_TOKEN_KW_TRUE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_TRUE); break; - default: - assert(tok == MP_TOKEN_ELLIPSIS); - emit_write_bytecode_byte_obj(emit, MP_BC_LOAD_CONST_OBJ, MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj)); - break; + if (tok == MP_TOKEN_ELLIPSIS) { + emit_write_bytecode_byte_obj(emit, MP_BC_LOAD_CONST_OBJ, MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj)); + } else { + emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_FALSE + (tok - MP_TOKEN_KW_FALSE)); } } From 8e7745eb315cdaf7dec033891f88e091ab4e016e Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 22 Aug 2019 14:55:16 +1000 Subject: [PATCH 0630/1788] py/emitbc: Make all emit_write_bytecode_* funcs take a stack_adj arg. This factoring of code gives significant code-size savings: bare-arm: -456 -0.682% minimal x86: -844 -0.547% unix x64: -472 -0.095% unix nanbox: -1348 -0.303% stm32: -472 -0.130% PYBV10 cc3200: -448 -0.242% esp8266: -708 -0.108% esp32: -400 -0.036% GENERIC nrf: -520 -0.356% pca10040 samd: -456 -0.448% ADAFRUIT_ITSYBITSY_M4_EXPRESS --- py/emitbc.c | 266 ++++++++++++++++++++++------------------------------ 1 file changed, 111 insertions(+), 155 deletions(-) diff --git a/py/emitbc.c b/py/emitbc.c index bb05169da3..fcbd979d27 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2013-2019 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 @@ -182,20 +182,27 @@ STATIC byte *emit_get_cur_to_write_bytecode(emit_t *emit, int num_bytes_to_write } } -STATIC void emit_write_bytecode_byte(emit_t *emit, byte b1) { +STATIC void emit_write_bytecode_raw_byte(emit_t *emit, byte b1) { byte *c = emit_get_cur_to_write_bytecode(emit, 1); c[0] = b1; } -STATIC void emit_write_bytecode_byte_byte(emit_t* emit, byte b1, byte b2) { +STATIC void emit_write_bytecode_byte(emit_t *emit, int stack_adj, byte b1) { + mp_emit_bc_adjust_stack_size(emit, stack_adj); + byte *c = emit_get_cur_to_write_bytecode(emit, 1); + c[0] = b1; +} + +STATIC void emit_write_bytecode_byte_byte(emit_t* emit, int stack_adj, byte b1, byte b2) { + mp_emit_bc_adjust_stack_size(emit, stack_adj); byte *c = emit_get_cur_to_write_bytecode(emit, 2); c[0] = b1; c[1] = b2; } // Similar to emit_write_bytecode_uint(), just some extra handling to encode sign -STATIC void emit_write_bytecode_byte_int(emit_t *emit, byte b1, mp_int_t num) { - emit_write_bytecode_byte(emit, b1); +STATIC void emit_write_bytecode_byte_int(emit_t *emit, int stack_adj, byte b1, mp_int_t num) { + emit_write_bytecode_byte(emit, stack_adj, b1); // We store each 7 bits in a separate byte, and that's how many bytes needed byte buf[BYTES_FOR_INT]; @@ -220,40 +227,41 @@ STATIC void emit_write_bytecode_byte_int(emit_t *emit, byte b1, mp_int_t num) { *c = *p; } -STATIC void emit_write_bytecode_byte_uint(emit_t *emit, byte b, mp_uint_t val) { - emit_write_bytecode_byte(emit, b); +STATIC void emit_write_bytecode_byte_uint(emit_t *emit, int stack_adj, byte b, mp_uint_t val) { + emit_write_bytecode_byte(emit, stack_adj, b); emit_write_uint(emit, emit_get_cur_to_write_bytecode, val); } #if MICROPY_PERSISTENT_CODE -STATIC void emit_write_bytecode_byte_const(emit_t *emit, byte b, mp_uint_t n, mp_uint_t c) { +STATIC void emit_write_bytecode_byte_const(emit_t *emit, int stack_adj, byte b, mp_uint_t n, mp_uint_t c) { if (emit->pass == MP_PASS_EMIT) { emit->const_table[n] = c; } - emit_write_bytecode_byte_uint(emit, b, n); + emit_write_bytecode_byte_uint(emit, stack_adj, b, n); } #endif -STATIC void emit_write_bytecode_byte_qstr(emit_t* emit, byte b, qstr qst) { +STATIC void emit_write_bytecode_byte_qstr(emit_t* emit, int stack_adj, byte b, qstr qst) { #if MICROPY_PERSISTENT_CODE assert((qst >> 16) == 0); + mp_emit_bc_adjust_stack_size(emit, stack_adj); byte *c = emit_get_cur_to_write_bytecode(emit, 3); c[0] = b; c[1] = qst; c[2] = qst >> 8; #else - emit_write_bytecode_byte_uint(emit, b, qst); + emit_write_bytecode_byte_uint(emit, stack_adj, b, qst); #endif } -STATIC void emit_write_bytecode_byte_obj(emit_t *emit, byte b, mp_obj_t obj) { +STATIC void emit_write_bytecode_byte_obj(emit_t *emit, int stack_adj, byte b, mp_obj_t obj) { #if MICROPY_PERSISTENT_CODE - emit_write_bytecode_byte_const(emit, b, + emit_write_bytecode_byte_const(emit, stack_adj, b, emit->scope->num_pos_args + emit->scope->num_kwonly_args + emit->ct_cur_obj++, (mp_uint_t)obj); #else // aligns the pointer so it is friendly to GC - emit_write_bytecode_byte(emit, b); + emit_write_bytecode_byte(emit, stack_adj, b); emit->bytecode_offset = (size_t)MP_ALIGN(emit->bytecode_offset, sizeof(mp_obj_t)); mp_obj_t *c = (mp_obj_t*)emit_get_cur_to_write_bytecode(emit, sizeof(mp_obj_t)); // Verify thar c is already uint-aligned @@ -262,14 +270,14 @@ STATIC void emit_write_bytecode_byte_obj(emit_t *emit, byte b, mp_obj_t obj) { #endif } -STATIC void emit_write_bytecode_byte_raw_code(emit_t *emit, byte b, mp_raw_code_t *rc) { +STATIC void emit_write_bytecode_byte_raw_code(emit_t *emit, int stack_adj, byte b, mp_raw_code_t *rc) { #if MICROPY_PERSISTENT_CODE - emit_write_bytecode_byte_const(emit, b, + emit_write_bytecode_byte_const(emit, stack_adj, b, emit->scope->num_pos_args + emit->scope->num_kwonly_args + emit->ct_num_obj + emit->ct_cur_raw_code++, (mp_uint_t)(uintptr_t)rc); #else // aligns the pointer so it is friendly to GC - emit_write_bytecode_byte(emit, b); + emit_write_bytecode_byte(emit, stack_adj, b); emit->bytecode_offset = (size_t)MP_ALIGN(emit->bytecode_offset, sizeof(void*)); void **c = (void**)emit_get_cur_to_write_bytecode(emit, sizeof(void*)); // Verify thar c is already uint-aligned @@ -279,7 +287,8 @@ STATIC void emit_write_bytecode_byte_raw_code(emit_t *emit, byte b, mp_raw_code_ } // unsigned labels are relative to ip following this instruction, stored as 16 bits -STATIC void emit_write_bytecode_byte_unsigned_label(emit_t *emit, byte b1, mp_uint_t label) { +STATIC void emit_write_bytecode_byte_unsigned_label(emit_t *emit, int stack_adj, byte b1, mp_uint_t label) { + mp_emit_bc_adjust_stack_size(emit, stack_adj); mp_uint_t bytecode_offset; if (emit->pass < MP_PASS_EMIT) { bytecode_offset = 0; @@ -293,7 +302,8 @@ STATIC void emit_write_bytecode_byte_unsigned_label(emit_t *emit, byte b1, mp_ui } // signed labels are relative to ip following this instruction, stored as 16 bits, in excess -STATIC void emit_write_bytecode_byte_signed_label(emit_t *emit, byte b1, mp_uint_t label) { +STATIC void emit_write_bytecode_byte_signed_label(emit_t *emit, int stack_adj, byte b1, mp_uint_t label) { + mp_emit_bc_adjust_stack_size(emit, stack_adj); int bytecode_offset; if (emit->pass < MP_PASS_EMIT) { bytecode_offset = 0; @@ -364,10 +374,10 @@ void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) { id_info_t *id = &scope->id_info[i]; if (id->kind == ID_INFO_KIND_CELL) { assert(id->local_num < 255); - emit_write_bytecode_byte(emit, id->local_num); // write the local which should be converted to a cell + emit_write_bytecode_raw_byte(emit, id->local_num); // write the local which should be converted to a cell } } - emit_write_bytecode_byte(emit, 255); // end of list sentinel + emit_write_bytecode_raw_byte(emit, 255); // end of list sentinel #if MICROPY_PERSISTENT_CODE emit->ct_cur_obj = 0; @@ -468,10 +478,6 @@ void mp_emit_bc_adjust_stack_size(emit_t *emit, mp_int_t delta) { emit->last_emit_was_return_value = false; } -static inline void emit_bc_pre(emit_t *emit, mp_int_t stack_size_delta) { - mp_emit_bc_adjust_stack_size(emit, stack_size_delta); -} - void mp_emit_bc_set_source_line(emit_t *emit, mp_uint_t source_line) { //printf("source: line %d -> %d offset %d -> %d\n", emit->last_source_line, source_line, emit->last_source_line_offset, emit->bytecode_offset); #if MICROPY_ENABLE_SOURCE_LINE @@ -493,7 +499,7 @@ void mp_emit_bc_set_source_line(emit_t *emit, mp_uint_t source_line) { } void mp_emit_bc_label_assign(emit_t *emit, mp_uint_t l) { - emit_bc_pre(emit, 0); + mp_emit_bc_adjust_stack_size(emit, 0); if (emit->pass == MP_PASS_SCOPE) { return; } @@ -511,62 +517,52 @@ void mp_emit_bc_label_assign(emit_t *emit, mp_uint_t l) { 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); - } + int stack_adj = kind == MP_EMIT_IMPORT_FROM ? 1 : -1; if (kind == MP_EMIT_IMPORT_STAR) { - emit_write_bytecode_byte(emit, MP_BC_IMPORT_STAR); + emit_write_bytecode_byte(emit, stack_adj, MP_BC_IMPORT_STAR); } else { - emit_write_bytecode_byte_qstr(emit, MP_BC_IMPORT_NAME + kind, qst); + emit_write_bytecode_byte_qstr(emit, stack_adj, MP_BC_IMPORT_NAME + kind, qst); } } void mp_emit_bc_load_const_tok(emit_t *emit, mp_token_kind_t tok) { MP_STATIC_ASSERT(MP_BC_LOAD_CONST_FALSE + (MP_TOKEN_KW_NONE - MP_TOKEN_KW_FALSE) == MP_BC_LOAD_CONST_NONE); MP_STATIC_ASSERT(MP_BC_LOAD_CONST_FALSE + (MP_TOKEN_KW_TRUE - MP_TOKEN_KW_FALSE) == MP_BC_LOAD_CONST_TRUE); - emit_bc_pre(emit, 1); if (tok == MP_TOKEN_ELLIPSIS) { - emit_write_bytecode_byte_obj(emit, MP_BC_LOAD_CONST_OBJ, MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj)); + emit_write_bytecode_byte_obj(emit, 1, MP_BC_LOAD_CONST_OBJ, MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj)); } else { - emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_FALSE + (tok - MP_TOKEN_KW_FALSE)); + emit_write_bytecode_byte(emit, 1, MP_BC_LOAD_CONST_FALSE + (tok - MP_TOKEN_KW_FALSE)); } } void mp_emit_bc_load_const_small_int(emit_t *emit, mp_int_t arg) { - emit_bc_pre(emit, 1); if (-16 <= arg && arg <= 47) { - emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_SMALL_INT_MULTI + 16 + arg); + emit_write_bytecode_byte(emit, 1, MP_BC_LOAD_CONST_SMALL_INT_MULTI + 16 + arg); } else { - emit_write_bytecode_byte_int(emit, MP_BC_LOAD_CONST_SMALL_INT, arg); + emit_write_bytecode_byte_int(emit, 1, MP_BC_LOAD_CONST_SMALL_INT, arg); } } void mp_emit_bc_load_const_str(emit_t *emit, qstr qst) { - emit_bc_pre(emit, 1); - emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_CONST_STRING, qst); + emit_write_bytecode_byte_qstr(emit, 1, MP_BC_LOAD_CONST_STRING, qst); } void mp_emit_bc_load_const_obj(emit_t *emit, mp_obj_t obj) { - emit_bc_pre(emit, 1); - emit_write_bytecode_byte_obj(emit, MP_BC_LOAD_CONST_OBJ, obj); + emit_write_bytecode_byte_obj(emit, 1, MP_BC_LOAD_CONST_OBJ, obj); } void mp_emit_bc_load_null(emit_t *emit) { - emit_bc_pre(emit, 1); - emit_write_bytecode_byte(emit, MP_BC_LOAD_NULL); + emit_write_bytecode_byte(emit, 1, MP_BC_LOAD_NULL); } 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 (kind == MP_EMIT_IDOP_LOCAL_FAST && local_num <= 15) { - emit_write_bytecode_byte(emit, MP_BC_LOAD_FAST_MULTI + local_num); + emit_write_bytecode_byte(emit, 1, MP_BC_LOAD_FAST_MULTI + local_num); } else { - emit_write_bytecode_byte_uint(emit, MP_BC_LOAD_FAST_N + kind, local_num); + emit_write_bytecode_byte_uint(emit, 1, MP_BC_LOAD_FAST_N + kind, local_num); } } @@ -574,51 +570,45 @@ 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 + kind, qst); + emit_write_bytecode_byte_qstr(emit, 1, MP_BC_LOAD_NAME + kind, qst); if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) { - emit_write_bytecode_byte(emit, 0); + emit_write_bytecode_raw_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); + int stack_adj = 1 - 2 * is_super; + emit_write_bytecode_byte_qstr(emit, stack_adj, is_super ? MP_BC_LOAD_SUPER_METHOD : MP_BC_LOAD_METHOD, qst); } void mp_emit_bc_load_build_class(emit_t *emit) { - emit_bc_pre(emit, 1); - emit_write_bytecode_byte(emit, MP_BC_LOAD_BUILD_CLASS); + emit_write_bytecode_byte(emit, 1, MP_BC_LOAD_BUILD_CLASS); } 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); + emit_write_bytecode_byte(emit, -1, 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); + emit_write_bytecode_byte(emit, -3, MP_BC_STORE_SUBSCR); } } 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); + emit_write_bytecode_byte_qstr(emit, 0, 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); + emit_write_bytecode_byte_qstr(emit, -2, MP_BC_STORE_ATTR, qst); } if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) { - emit_write_bytecode_byte(emit, 0); + emit_write_bytecode_raw_byte(emit, 0); } } @@ -626,98 +616,86 @@ void mp_emit_bc_store_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kin 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 (kind == MP_EMIT_IDOP_LOCAL_FAST && local_num <= 15) { - emit_write_bytecode_byte(emit, MP_BC_STORE_FAST_MULTI + local_num); + emit_write_bytecode_byte(emit, -1, MP_BC_STORE_FAST_MULTI + local_num); } else { - emit_write_bytecode_byte_uint(emit, MP_BC_STORE_FAST_N + kind, local_num); + emit_write_bytecode_byte_uint(emit, -1, MP_BC_STORE_FAST_N + kind, local_num); } } 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 + kind, qst); + emit_write_bytecode_byte_qstr(emit, -1, MP_BC_STORE_NAME + kind, qst); } 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 + kind, local_num); + emit_write_bytecode_byte_uint(emit, 0, MP_BC_DELETE_FAST + kind, local_num); } 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 + kind, qst); + emit_write_bytecode_byte_qstr(emit, 0, MP_BC_DELETE_NAME + kind, qst); } void mp_emit_bc_dup_top(emit_t *emit) { - emit_bc_pre(emit, 1); - emit_write_bytecode_byte(emit, MP_BC_DUP_TOP); + emit_write_bytecode_byte(emit, 1, MP_BC_DUP_TOP); } void mp_emit_bc_dup_top_two(emit_t *emit) { - emit_bc_pre(emit, 2); - emit_write_bytecode_byte(emit, MP_BC_DUP_TOP_TWO); + emit_write_bytecode_byte(emit, 2, MP_BC_DUP_TOP_TWO); } void mp_emit_bc_pop_top(emit_t *emit) { - emit_bc_pre(emit, -1); - emit_write_bytecode_byte(emit, MP_BC_POP_TOP); + emit_write_bytecode_byte(emit, -1, MP_BC_POP_TOP); } void mp_emit_bc_rot_two(emit_t *emit) { - emit_bc_pre(emit, 0); - emit_write_bytecode_byte(emit, MP_BC_ROT_TWO); + emit_write_bytecode_byte(emit, 0, MP_BC_ROT_TWO); } void mp_emit_bc_rot_three(emit_t *emit) { - emit_bc_pre(emit, 0); - emit_write_bytecode_byte(emit, MP_BC_ROT_THREE); + emit_write_bytecode_byte(emit, 0, MP_BC_ROT_THREE); } void mp_emit_bc_jump(emit_t *emit, mp_uint_t label) { - emit_bc_pre(emit, 0); - emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP, label); + emit_write_bytecode_byte_signed_label(emit, 0, MP_BC_JUMP, label); } void mp_emit_bc_pop_jump_if(emit_t *emit, bool cond, mp_uint_t label) { - emit_bc_pre(emit, -1); if (cond) { - emit_write_bytecode_byte_signed_label(emit, MP_BC_POP_JUMP_IF_TRUE, label); + emit_write_bytecode_byte_signed_label(emit, -1, MP_BC_POP_JUMP_IF_TRUE, label); } else { - emit_write_bytecode_byte_signed_label(emit, MP_BC_POP_JUMP_IF_FALSE, label); + emit_write_bytecode_byte_signed_label(emit, -1, MP_BC_POP_JUMP_IF_FALSE, label); } } void mp_emit_bc_jump_if_or_pop(emit_t *emit, bool cond, mp_uint_t label) { - emit_bc_pre(emit, -1); if (cond) { - emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP_IF_TRUE_OR_POP, label); + emit_write_bytecode_byte_signed_label(emit, -1, MP_BC_JUMP_IF_TRUE_OR_POP, label); } else { - emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP_IF_FALSE_OR_POP, label); + emit_write_bytecode_byte_signed_label(emit, -1, MP_BC_JUMP_IF_FALSE_OR_POP, label); } } void mp_emit_bc_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) { if (except_depth == 0) { - emit_bc_pre(emit, 0); if (label & MP_EMIT_BREAK_FROM_FOR) { // need to pop the iterator if we are breaking out of a for loop - emit_write_bytecode_byte(emit, MP_BC_POP_TOP); + emit_write_bytecode_raw_byte(emit, MP_BC_POP_TOP); // also pop the iter_buf for (size_t i = 0; i < MP_OBJ_ITER_BUF_NSLOTS - 1; ++i) { - emit_write_bytecode_byte(emit, MP_BC_POP_TOP); + emit_write_bytecode_raw_byte(emit, MP_BC_POP_TOP); } } - emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR); + emit_write_bytecode_byte_signed_label(emit, 0, MP_BC_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR); } else { - emit_write_bytecode_byte_signed_label(emit, MP_BC_UNWIND_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR); - emit_write_bytecode_byte(emit, ((label & MP_EMIT_BREAK_FROM_FOR) ? 0x80 : 0) | except_depth); + emit_write_bytecode_byte_signed_label(emit, 0, MP_BC_UNWIND_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR); + emit_write_bytecode_raw_byte(emit, ((label & MP_EMIT_BREAK_FROM_FOR) ? 0x80 : 0) | except_depth); } } @@ -725,52 +703,45 @@ 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); - } else { - emit_bc_pre(emit, 0); - } - emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_WITH + kind, label); + int stack_adj = kind == MP_EMIT_SETUP_BLOCK_WITH ? 2 : 0; + emit_write_bytecode_byte_unsigned_label(emit, stack_adj, MP_BC_SETUP_WITH + kind, label); } void mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label) { mp_emit_bc_load_const_tok(emit, MP_TOKEN_KW_NONE); 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_block(MP_EMIT_SETUP_BLOCK_WITH) + // The +2 is to ensure we have enough stack space to call the __exit__ method + emit_write_bytecode_byte(emit, 2, MP_BC_WITH_CLEANUP); + // Cancel the +2 above, plus the +2 from mp_emit_bc_setup_block(MP_EMIT_SETUP_BLOCK_WITH) + mp_emit_bc_adjust_stack_size(emit, -4); } void mp_emit_bc_end_finally(emit_t *emit) { - emit_bc_pre(emit, -1); - emit_write_bytecode_byte(emit, MP_BC_END_FINALLY); + emit_write_bytecode_byte(emit, -1, MP_BC_END_FINALLY); } void mp_emit_bc_get_iter(emit_t *emit, bool use_stack) { - emit_bc_pre(emit, use_stack ? MP_OBJ_ITER_BUF_NSLOTS - 1 : 0); - emit_write_bytecode_byte(emit, use_stack ? MP_BC_GET_ITER_STACK : MP_BC_GET_ITER); + int stack_adj = use_stack ? MP_OBJ_ITER_BUF_NSLOTS - 1 : 0; + emit_write_bytecode_byte(emit, stack_adj, use_stack ? MP_BC_GET_ITER_STACK : MP_BC_GET_ITER); } void mp_emit_bc_for_iter(emit_t *emit, mp_uint_t label) { - emit_bc_pre(emit, 1); - emit_write_bytecode_byte_unsigned_label(emit, MP_BC_FOR_ITER, label); + emit_write_bytecode_byte_unsigned_label(emit, 1, MP_BC_FOR_ITER, label); } void mp_emit_bc_for_iter_end(emit_t *emit) { - emit_bc_pre(emit, -MP_OBJ_ITER_BUF_NSLOTS); + mp_emit_bc_adjust_stack_size(emit, -MP_OBJ_ITER_BUF_NSLOTS); } void mp_emit_bc_pop_except_jump(emit_t *emit, mp_uint_t label, bool within_exc_handler) { (void)within_exc_handler; - emit_bc_pre(emit, 0); - emit_write_bytecode_byte_unsigned_label(emit, MP_BC_POP_EXCEPT_JUMP, label); + emit_write_bytecode_byte_unsigned_label(emit, 0, MP_BC_POP_EXCEPT_JUMP, label); } void mp_emit_bc_unary_op(emit_t *emit, mp_unary_op_t op) { - emit_bc_pre(emit, 0); - emit_write_bytecode_byte(emit, MP_BC_UNARY_OP_MULTI + op); + emit_write_bytecode_byte(emit, 0, MP_BC_UNARY_OP_MULTI + op); } void mp_emit_bc_binary_op(emit_t *emit, mp_binary_op_t op) { @@ -782,11 +753,9 @@ void mp_emit_bc_binary_op(emit_t *emit, mp_binary_op_t op) { invert = true; op = MP_BINARY_OP_IS; } - emit_bc_pre(emit, -1); - emit_write_bytecode_byte(emit, MP_BC_BINARY_OP_MULTI + op); + emit_write_bytecode_byte(emit, -1, MP_BC_BINARY_OP_MULTI + op); if (invert) { - emit_bc_pre(emit, 0); - emit_write_bytecode_byte(emit, MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NOT); + emit_write_bytecode_byte(emit, 0, MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NOT); } } @@ -796,17 +765,12 @@ 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_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 { - emit_bc_pre(emit, 1 - n_args); - } - emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_TUPLE + kind, n_args); + int stack_adj = kind == MP_EMIT_BUILD_MAP ? 1 : 1 - n_args; + emit_write_bytecode_byte_uint(emit, stack_adj, MP_BC_BUILD_TUPLE + kind, n_args); } void mp_emit_bc_store_map(emit_t *emit) { - emit_bc_pre(emit, -2); - emit_write_bytecode_byte(emit, MP_BC_STORE_MAP); + emit_write_bytecode_byte(emit, -2, MP_BC_STORE_MAP); } void mp_emit_bc_store_comp(emit_t *emit, scope_kind_t kind, mp_uint_t collection_stack_index) { @@ -822,51 +786,46 @@ void mp_emit_bc_store_comp(emit_t *emit, scope_kind_t kind, mp_uint_t collection n = 0; t = 2; } - emit_bc_pre(emit, -1 - n); // the lower 2 bits of the opcode argument indicate the collection type - emit_write_bytecode_byte_uint(emit, MP_BC_STORE_COMP, ((collection_stack_index + n) << 2) | t); + emit_write_bytecode_byte_uint(emit, -1 - n, MP_BC_STORE_COMP, ((collection_stack_index + n) << 2) | t); } void mp_emit_bc_unpack_sequence(emit_t *emit, mp_uint_t n_args) { - emit_bc_pre(emit, -1 + n_args); - emit_write_bytecode_byte_uint(emit, MP_BC_UNPACK_SEQUENCE, n_args); + emit_write_bytecode_byte_uint(emit, -1 + n_args, MP_BC_UNPACK_SEQUENCE, n_args); } void mp_emit_bc_unpack_ex(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right) { - emit_bc_pre(emit, -1 + n_left + n_right + 1); - emit_write_bytecode_byte_uint(emit, MP_BC_UNPACK_EX, n_left | (n_right << 8)); + emit_write_bytecode_byte_uint(emit, -1 + n_left + n_right + 1, MP_BC_UNPACK_EX, n_left | (n_right << 8)); } void mp_emit_bc_make_function(emit_t *emit, scope_t *scope, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) { if (n_pos_defaults == 0 && n_kw_defaults == 0) { - emit_bc_pre(emit, 1); - emit_write_bytecode_byte_raw_code(emit, MP_BC_MAKE_FUNCTION, scope->raw_code); + emit_write_bytecode_byte_raw_code(emit, 1, MP_BC_MAKE_FUNCTION, scope->raw_code); } else { - emit_bc_pre(emit, -1); - emit_write_bytecode_byte_raw_code(emit, MP_BC_MAKE_FUNCTION_DEFARGS, scope->raw_code); + emit_write_bytecode_byte_raw_code(emit, -1, MP_BC_MAKE_FUNCTION_DEFARGS, scope->raw_code); } } void mp_emit_bc_make_closure(emit_t *emit, scope_t *scope, mp_uint_t n_closed_over, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) { if (n_pos_defaults == 0 && n_kw_defaults == 0) { - emit_bc_pre(emit, -n_closed_over + 1); - emit_write_bytecode_byte_raw_code(emit, MP_BC_MAKE_CLOSURE, scope->raw_code); - emit_write_bytecode_byte(emit, n_closed_over); + int stack_adj = -n_closed_over + 1; + emit_write_bytecode_byte_raw_code(emit, stack_adj, MP_BC_MAKE_CLOSURE, scope->raw_code); + emit_write_bytecode_raw_byte(emit, n_closed_over); } else { assert(n_closed_over <= 255); - emit_bc_pre(emit, -2 - (mp_int_t)n_closed_over + 1); - emit_write_bytecode_byte_raw_code(emit, MP_BC_MAKE_CLOSURE_DEFARGS, scope->raw_code); - emit_write_bytecode_byte(emit, n_closed_over); + int stack_adj = -2 - (mp_int_t)n_closed_over + 1; + emit_write_bytecode_byte_raw_code(emit, stack_adj, MP_BC_MAKE_CLOSURE_DEFARGS, scope->raw_code); + emit_write_bytecode_raw_byte(emit, n_closed_over); } } -STATIC void emit_bc_call_function_method_helper(emit_t *emit, mp_int_t stack_adj, mp_uint_t bytecode_base, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) { +STATIC void emit_bc_call_function_method_helper(emit_t *emit, int stack_adj, mp_uint_t bytecode_base, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) { if (star_flags) { - emit_bc_pre(emit, stack_adj - (mp_int_t)n_positional - 2 * (mp_int_t)n_keyword - 2); - emit_write_bytecode_byte_uint(emit, bytecode_base + 1, (n_keyword << 8) | n_positional); // TODO make it 2 separate uints? + stack_adj -= (int)n_positional + 2 * (int)n_keyword + 2; + emit_write_bytecode_byte_uint(emit, stack_adj, bytecode_base + 1, (n_keyword << 8) | n_positional); // TODO make it 2 separate uints? } else { - emit_bc_pre(emit, stack_adj - (mp_int_t)n_positional - 2 * (mp_int_t)n_keyword); - emit_write_bytecode_byte_uint(emit, bytecode_base, (n_keyword << 8) | n_positional); // TODO make it 2 separate uints? + stack_adj -= (int)n_positional + 2 * (int)n_keyword; + emit_write_bytecode_byte_uint(emit, stack_adj, bytecode_base, (n_keyword << 8) | n_positional); // TODO make it 2 separate uints? } } @@ -879,22 +838,19 @@ void mp_emit_bc_call_method(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_ke } void mp_emit_bc_return_value(emit_t *emit) { - emit_bc_pre(emit, -1); + emit_write_bytecode_byte(emit, -1, MP_BC_RETURN_VALUE); emit->last_emit_was_return_value = true; - emit_write_bytecode_byte(emit, MP_BC_RETURN_VALUE); } void mp_emit_bc_raise_varargs(emit_t *emit, mp_uint_t n_args) { assert(n_args <= 2); - emit_bc_pre(emit, -n_args); - emit_write_bytecode_byte_byte(emit, MP_BC_RAISE_VARARGS, n_args); + emit_write_bytecode_byte_byte(emit, -n_args, MP_BC_RAISE_VARARGS, n_args); } 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_write_bytecode_byte(emit, -kind, MP_BC_YIELD_VALUE + kind); emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR; - emit_write_bytecode_byte(emit, MP_BC_YIELD_VALUE + kind); } void mp_emit_bc_start_except_handler(emit_t *emit) { From 2dfa69efbbae92faf21360edd5e60c5a9145a2dc Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 22 Aug 2019 15:22:42 +1000 Subject: [PATCH 0631/1788] extmod/modujson: Support passing bytes/bytearray to json.loads. CPython allows this, and it can be useful to reduce the number of memory allocations. Fixes issue #5031. --- extmod/modujson.c | 8 ++++---- tests/extmod/ujson_loads.py | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/extmod/modujson.c b/extmod/modujson.c index f5c6428ef9..15ed2f38d8 100644 --- a/extmod/modujson.c +++ b/extmod/modujson.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2014-2016 Damien P. George + * Copyright (c) 2014-2019 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 @@ -281,9 +281,9 @@ STATIC mp_obj_t mod_ujson_load(mp_obj_t stream_obj) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_load_obj, mod_ujson_load); STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) { - size_t len; - const char *buf = mp_obj_str_get_data(obj, &len); - vstr_t vstr = {len, len, (char*)buf, true}; + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(obj, &bufinfo, MP_BUFFER_READ); + vstr_t vstr = {bufinfo.len, bufinfo.len, (char*)bufinfo.buf, true}; mp_obj_stringio_t sio = {{&mp_type_stringio}, &vstr, 0, MP_OBJ_NULL}; return mod_ujson_load(MP_OBJ_FROM_PTR(&sio)); } diff --git a/tests/extmod/ujson_loads.py b/tests/extmod/ujson_loads.py index adba3c068d..43672d6505 100644 --- a/tests/extmod/ujson_loads.py +++ b/tests/extmod/ujson_loads.py @@ -37,6 +37,10 @@ my_print(json.loads('"abc\\uabcd"')) # whitespace handling my_print(json.loads('{\n\t"a":[]\r\n, "b":[1], "c":{"3":4} \n\r\t\r\r\r\n}')) +# loading from bytes and bytearray +my_print(json.loads(b'[1,2]')) +my_print(json.loads(bytearray(b'[null]'))) + # loading nothing should raise exception try: json.loads('') From 2eb88f5df74263cf4b458b135d16a100eb7a8bd2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 22 Aug 2019 15:45:13 +1000 Subject: [PATCH 0632/1788] tests/extmod: Split json.loads of bytes/bytearray into separate test. Because this functionality was introduced in Python 3.6. --- tests/extmod/ujson_loads.py | 4 ---- tests/extmod/ujson_loads_bytes.py | 13 +++++++++++++ tests/extmod/ujson_loads_bytes.py.exp | 2 ++ 3 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 tests/extmod/ujson_loads_bytes.py create mode 100644 tests/extmod/ujson_loads_bytes.py.exp diff --git a/tests/extmod/ujson_loads.py b/tests/extmod/ujson_loads.py index 43672d6505..adba3c068d 100644 --- a/tests/extmod/ujson_loads.py +++ b/tests/extmod/ujson_loads.py @@ -37,10 +37,6 @@ my_print(json.loads('"abc\\uabcd"')) # whitespace handling my_print(json.loads('{\n\t"a":[]\r\n, "b":[1], "c":{"3":4} \n\r\t\r\r\r\n}')) -# loading from bytes and bytearray -my_print(json.loads(b'[1,2]')) -my_print(json.loads(bytearray(b'[null]'))) - # loading nothing should raise exception try: json.loads('') diff --git a/tests/extmod/ujson_loads_bytes.py b/tests/extmod/ujson_loads_bytes.py new file mode 100644 index 0000000000..507e4ca885 --- /dev/null +++ b/tests/extmod/ujson_loads_bytes.py @@ -0,0 +1,13 @@ +# test loading from bytes and bytearray (introduced in Python 3.6) + +try: + import ujson as json +except ImportError: + try: + import json + except ImportError: + print("SKIP") + raise SystemExit + +print(json.loads(b'[1,2]')) +print(json.loads(bytearray(b'[null]'))) diff --git a/tests/extmod/ujson_loads_bytes.py.exp b/tests/extmod/ujson_loads_bytes.py.exp new file mode 100644 index 0000000000..c2735a9905 --- /dev/null +++ b/tests/extmod/ujson_loads_bytes.py.exp @@ -0,0 +1,2 @@ +[1, 2] +[None] From bc9b656f35ff484a86f0b209881d8551814da800 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 22 Aug 2019 15:59:14 +1000 Subject: [PATCH 0633/1788] py/runtime: Remove obsolete comment about mp_parse_compile_execute. mp_locals_get/set and mp_globals_get/set are now static-inline functions so this comment is no longer correct. --- py/runtime.c | 1 - 1 file changed, 1 deletion(-) diff --git a/py/runtime.c b/py/runtime.c index 04f9442b7b..9e60eb6263 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -1421,7 +1421,6 @@ void mp_import_all(mp_obj_t module) { #if MICROPY_ENABLE_COMPILER -// this is implemented in this file so it can optimise access to locals/globals mp_obj_t mp_parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t parse_input_kind, mp_obj_dict_t *globals, mp_obj_dict_t *locals) { // save context mp_obj_dict_t *volatile old_globals = mp_globals_get(); From 973c87d8fa41c3ae0c46be4f234726ecc3ac9d8a Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 22 Aug 2019 16:05:05 +1000 Subject: [PATCH 0634/1788] py/objgenerator: Move defn of mp_const_GeneratorExit_obj here. Because the mp_obj_exception_t type is now globally available. --- py/objexcept.c | 5 ----- py/objgenerator.c | 3 +++ 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/py/objexcept.c b/py/objexcept.c index 1fb636f666..7e3fdcc27c 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -100,11 +100,6 @@ mp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in) { #endif #endif // MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF -// Instance of GeneratorExit exception - needed by generator.close() -// This would belong to objgenerator.c, but to keep mp_obj_exception_t -// 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}; - 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; diff --git a/py/objgenerator.c b/py/objgenerator.c index b7186b8d0b..62e6446166 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -34,6 +34,9 @@ #include "py/objfun.h" #include "py/stackctrl.h" +// Instance of GeneratorExit exception - needed by generator.close() +const mp_obj_exception_t mp_const_GeneratorExit_obj = {{&mp_type_GeneratorExit}, 0, 0, NULL, (mp_obj_tuple_t*)&mp_const_empty_tuple_obj}; + /******************************************************************************/ /* generator wrapper */ From 53527138a938a5119f7294480567526ade646ba6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 22 Aug 2019 16:07:28 +1000 Subject: [PATCH 0635/1788] py/bc0.h: Add comment that MP_BC_MAKE_CLOSURE/_DEFARGS take extra byte. --- py/bc0.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/py/bc0.h b/py/bc0.h index 175ee263a0..fcb6eead5f 100644 --- a/py/bc0.h +++ b/py/bc0.h @@ -98,8 +98,8 @@ #define MP_BC_MAKE_FUNCTION (0x60) // uint #define MP_BC_MAKE_FUNCTION_DEFARGS (0x61) // uint -#define MP_BC_MAKE_CLOSURE (0x62) // uint -#define MP_BC_MAKE_CLOSURE_DEFARGS (0x63) // uint +#define MP_BC_MAKE_CLOSURE (0x62) // uint; byte +#define MP_BC_MAKE_CLOSURE_DEFARGS (0x63) // uint; byte #define MP_BC_CALL_FUNCTION (0x64) // uint #define MP_BC_CALL_FUNCTION_VAR_KW (0x65) // uint #define MP_BC_CALL_METHOD (0x66) // uint From 2fca0d7f18f8c31a6c85b598bb72f01725b26228 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 22 Aug 2019 16:13:05 +1000 Subject: [PATCH 0636/1788] py/vm: Shorten error message for not-implemented opcode. It's really an opcode that's not implemented, so use "opcode" instead of "byte code". And remove the redundant "not implemented" text because that is already implied by the exception type. There's no need to have a long error message for an exception that is almost never encountered. Saves about 20 bytes of code size on most ports. --- py/vm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/py/vm.c b/py/vm.c index 260a7f38ba..6a4634d006 100644 --- a/py/vm.c +++ b/py/vm.c @@ -1262,7 +1262,8 @@ yield: } else #endif { - mp_obj_t obj = mp_obj_new_exception_msg(&mp_type_NotImplementedError, "byte code not implemented"); + + mp_obj_t obj = mp_obj_new_exception_msg(&mp_type_NotImplementedError, "opcode"); nlr_pop(); code_state->state[0] = obj; return MP_VM_RETURN_EXCEPTION; From 519746cae4b1dd6e2d006f294961494ee949a2cc Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 22 Aug 2019 17:20:16 +1000 Subject: [PATCH 0637/1788] extmod/crypto-algorithms: Add source to header and populate copyright. As per the README.md of the upstream source at https://github.com/B-Con/crypto-algorithms, this source code was released into the public domain, so make that explicit in the copyright line in the header. --- extmod/crypto-algorithms/sha256.c | 3 ++- extmod/crypto-algorithms/sha256.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/extmod/crypto-algorithms/sha256.c b/extmod/crypto-algorithms/sha256.c index 276611cfd5..24e964749b 100644 --- a/extmod/crypto-algorithms/sha256.c +++ b/extmod/crypto-algorithms/sha256.c @@ -1,7 +1,8 @@ /********************************************************************* +* Source: https://github.com/B-Con/crypto-algorithms * Filename: sha256.c * Author: Brad Conte (brad AT bradconte.com) -* Copyright: +* Copyright: This code is released into the public domain. * Disclaimer: This code is presented "as is" without any guarantees. * Details: Implementation of the SHA-256 hashing algorithm. SHA-256 is one of the three algorithms in the SHA2 diff --git a/extmod/crypto-algorithms/sha256.h b/extmod/crypto-algorithms/sha256.h index caa1f81020..9c19472ea2 100644 --- a/extmod/crypto-algorithms/sha256.h +++ b/extmod/crypto-algorithms/sha256.h @@ -1,7 +1,8 @@ /********************************************************************* +* Source: https://github.com/B-Con/crypto-algorithms * Filename: sha256.h * Author: Brad Conte (brad AT bradconte.com) -* Copyright: +* Copyright: This code is released into the public domain. * Disclaimer: This code is presented "as is" without any guarantees. * Details: Defines the API for the corresponding SHA1 implementation. *********************************************************************/ From 3d7455a0bb4caa3e80e7594eaedd6e72c056ebe9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 27 Aug 2019 16:37:43 +1000 Subject: [PATCH 0638/1788] py/py.mk: Remove trailing spaces at end of line. --- py/py.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/py/py.mk b/py/py.mk index e649297e68..10beb29e45 100644 --- a/py/py.mk +++ b/py/py.mk @@ -21,9 +21,9 @@ CSUPEROPT = -O3 # External modules written in C. ifneq ($(USER_C_MODULES),) -# pre-define USERMOD variables as expanded so that variables are immediate +# pre-define USERMOD variables as expanded so that variables are immediate # expanded as they're added to them -SRC_USERMOD := +SRC_USERMOD := CFLAGS_USERMOD := LDFLAGS_USERMOD := $(foreach module, $(wildcard $(USER_C_MODULES)/*/micropython.mk), \ From 16f6169c88a5fd93b151149e561d177557fcc760 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 21 Aug 2019 16:07:12 +1000 Subject: [PATCH 0639/1788] py/vm: Don't add traceback info for exc's propagated through a finally. With this patch exception tracebacks that go through a finally are improved (less confusing, match CPython), and it makes finally's slightly more efficient (in time and RAM) because they no longer need to add a traceback. Partially fixes issue #2928. --- py/vm.c | 9 +++++---- tests/misc/print_exception.py | 10 ++++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/py/vm.c b/py/vm.c index 6a4634d006..64bddd6b5a 100644 --- a/py/vm.c +++ b/py/vm.c @@ -1359,10 +1359,11 @@ exception_handler: #if MICROPY_STACKLESS unwind_loop: #endif - // 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. - if (nlr.ret_val != &mp_const_GeneratorExit_obj) { + // Set traceback info (file and line number) where the exception occurred, but not for: + // - constant GeneratorExit object, because it's const + // - exceptions re-raised by END_FINALLY + if (nlr.ret_val != &mp_const_GeneratorExit_obj + && *code_state->ip != MP_BC_END_FINALLY) { 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 diff --git a/tests/misc/print_exception.py b/tests/misc/print_exception.py index 95431632f9..08b2e4bc48 100644 --- a/tests/misc/print_exception.py +++ b/tests/misc/print_exception.py @@ -47,6 +47,16 @@ except Exception as e: print('caught') print_exc(e) +# Test that an exception propagated through a finally doesn't have a traceback added there +try: + try: + f() + finally: + print('finally') +except Exception as e: + print('caught') + print_exc(e) + # Here we have a function with lots of bytecode generated for a single source-line, and # there is an error right at the end of the bytecode. It should report the correct line. def f(): From 08c1fe556915c912598d5a5d5db0f5942f3a333d Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 21 Aug 2019 16:08:43 +1000 Subject: [PATCH 0640/1788] py/vm: Don't add traceback info for exceptions that are re-raised. With this patch exceptions that are re-raised have improved tracebacks (less confusing, match CPython), and it makes re-raise slightly more efficient (in time and RAM) because they no longer need to add a traceback. Also general VM performance is not measurably affected. Partially fixes issue #2928. --- py/vm.c | 4 +++- tests/misc/print_exception.py | 12 ++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/py/vm.c b/py/vm.c index 64bddd6b5a..84296b463f 100644 --- a/py/vm.c +++ b/py/vm.c @@ -1362,8 +1362,10 @@ unwind_loop: // Set traceback info (file and line number) where the exception occurred, but not for: // - constant GeneratorExit object, because it's const // - exceptions re-raised by END_FINALLY + // - exceptions re-raised explicitly by "raise" if (nlr.ret_val != &mp_const_GeneratorExit_obj - && *code_state->ip != MP_BC_END_FINALLY) { + && *code_state->ip != MP_BC_END_FINALLY + && !(*code_state->ip == MP_BC_RAISE_VARARGS && code_state->ip[1] == 0)) { 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 diff --git a/tests/misc/print_exception.py b/tests/misc/print_exception.py index 08b2e4bc48..2067030bf9 100644 --- a/tests/misc/print_exception.py +++ b/tests/misc/print_exception.py @@ -57,6 +57,18 @@ except Exception as e: print('caught') print_exc(e) +# Test that re-raising an exception doesn't add traceback info +try: + try: + f() + except Exception as e: + print('reraise') + print_exc(e) + raise +except Exception as e: + print('caught') + print_exc(e) + # Here we have a function with lots of bytecode generated for a single source-line, and # there is an error right at the end of the bytecode. It should report the correct line. def f(): From b1e04848ef62d20db42b0b30f24304307c4e6765 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 21 Aug 2019 23:06:56 +1000 Subject: [PATCH 0641/1788] stm32/mphalport: Put PYBD specific MAC code in board specific file. --- ports/stm32/boards/PYBD_SF2/board_init.c | 26 +++++++++++++++++++++ ports/stm32/mphalport.c | 29 ++++++------------------ ports/stm32/mphalport.h | 1 + 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/ports/stm32/boards/PYBD_SF2/board_init.c b/ports/stm32/boards/PYBD_SF2/board_init.c index a8cf10f3a5..34f5e52a77 100644 --- a/ports/stm32/boards/PYBD_SF2/board_init.c +++ b/ports/stm32/boards/PYBD_SF2/board_init.c @@ -24,9 +24,23 @@ * THE SOFTWARE. */ +#include #include "py/mphal.h" #include "storage.h" +#if defined(STM32F722xx) || defined(STM32F723xx) || defined(STM32F732xx) || defined(STM32F733xx) +#define OTP_ADDR (0x1ff079e0) +#else +#define OTP_ADDR (0x1ff0f3c0) +#endif +#define OTP ((pyb_otp_t*)OTP_ADDR) + +typedef struct _pyb_otp_t { + uint16_t series; + uint16_t rev; + uint8_t mac[6]; +} pyb_otp_t; + void mboot_board_early_init(void) { // Enable 500mA on WBUS-DIP28 mp_hal_pin_config(pyb_pin_W23, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_UP, 0); @@ -44,3 +58,15 @@ void board_sleep(int value) { mp_spiflash_deepsleep(&spi_bdev.spiflash, value); mp_spiflash_deepsleep(&spi_bdev2.spiflash, value); } + +void mp_hal_get_mac(int idx, uint8_t buf[6]) { + // Check if OTP region has a valid MAC address, and use it if it does + if (OTP->series == 0x00d1 && OTP->mac[0] == 'H' && OTP->mac[1] == 'J' && OTP->mac[2] == '0') { + memcpy(buf, OTP->mac, 6); + buf[5] += idx; + return; + } + + // Generate a random locally administered MAC address (LAA) + mp_hal_generate_laa_mac(idx, buf); +} diff --git a/ports/stm32/mphalport.c b/ports/stm32/mphalport.c index ec4590b06b..aa5dc33975 100644 --- a/ports/stm32/mphalport.c +++ b/ports/stm32/mphalport.c @@ -168,28 +168,8 @@ void mp_hal_pin_config_speed(mp_hal_pin_obj_t pin_obj, uint32_t speed) { /*******************************************************************************/ // MAC address -typedef struct _pyb_otp_t { - uint16_t series; - uint16_t rev; - uint8_t mac[6]; -} pyb_otp_t; - -#if defined(STM32F722xx) || defined(STM32F723xx) || defined(STM32F732xx) || defined(STM32F733xx) -#define OTP_ADDR (0x1ff079e0) -#else -#define OTP_ADDR (0x1ff0f3c0) -#endif -#define OTP ((pyb_otp_t*)OTP_ADDR) - -MP_WEAK void mp_hal_get_mac(int idx, uint8_t buf[6]) { - // Check if OTP region has a valid MAC address, and use it if it does - if (OTP->series == 0x00d1 && OTP->mac[0] == 'H' && OTP->mac[1] == 'J' && OTP->mac[2] == '0') { - memcpy(buf, OTP->mac, 6); - buf[5] += idx; - return; - } - - // Generate a random locally administered MAC address (LAA) +// Generate a random locally administered MAC address (LAA) +void mp_hal_generate_laa_mac(int idx, uint8_t buf[6]) { uint8_t *id = (uint8_t *)MP_HAL_UNIQUE_ID_ADDRESS; buf[0] = 0x02; // LAA range buf[1] = (id[11] << 4) | (id[10] & 0xf); @@ -199,6 +179,11 @@ MP_WEAK void mp_hal_get_mac(int idx, uint8_t buf[6]) { buf[5] = (id[0] << 2) | idx; } +// A board can override this if needed +MP_WEAK void mp_hal_get_mac(int idx, uint8_t buf[6]) { + mp_hal_generate_laa_mac(idx, buf); +} + void mp_hal_get_mac_ascii(int idx, size_t chr_off, size_t chr_len, char *dest) { static const char hexchr[16] = "0123456789ABCDEF"; uint8_t mac[6]; diff --git a/ports/stm32/mphalport.h b/ports/stm32/mphalport.h index bd71adf77b..d73ff8bff3 100644 --- a/ports/stm32/mphalport.h +++ b/ports/stm32/mphalport.h @@ -82,5 +82,6 @@ enum { MP_HAL_MAC_ETH0, }; +void mp_hal_generate_laa_mac(int idx, uint8_t buf[6]); void mp_hal_get_mac(int idx, uint8_t buf[6]); void mp_hal_get_mac_ascii(int idx, size_t chr_off, size_t chr_len, char *dest); From 68d74b00743124ade07df0876bd93034d3542780 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 22 Aug 2019 11:16:01 +1000 Subject: [PATCH 0642/1788] stm32/mboot/Makefile: Define "BUILDING_MBOOT" when building mboot. So boards can configure their settings based on whether mboot or the main firmware is being built. --- ports/stm32/mboot/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/stm32/mboot/Makefile b/ports/stm32/mboot/Makefile index f2c3baecc1..19635b9183 100755 --- a/ports/stm32/mboot/Makefile +++ b/ports/stm32/mboot/Makefile @@ -63,6 +63,7 @@ CFLAGS += -DSTM32_HAL_H='' CFLAGS += -DBOARD_$(BOARD) CFLAGS += -DAPPLICATION_ADDR=$(TEXT0_ADDR) CFLAGS += -DFFCONF_H=\"ports/stm32/mboot/ffconf.h\" +CFLAGS += -DBUILDING_MBOOT=1 LDFLAGS = -nostdlib -L . -T stm32_generic.ld -Map=$(@:.elf=.map) --cref LIBS = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) From 5789558d60fb6dcf0537a4487444e6f84a408561 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 22 Aug 2019 11:17:10 +1000 Subject: [PATCH 0643/1788] stm32/boards/PYBD_SF2: Exclude certain things when building mboot. --- ports/stm32/boards/PYBD_SF2/board_init.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/stm32/boards/PYBD_SF2/board_init.c b/ports/stm32/boards/PYBD_SF2/board_init.c index 34f5e52a77..d1a0a09e7a 100644 --- a/ports/stm32/boards/PYBD_SF2/board_init.c +++ b/ports/stm32/boards/PYBD_SF2/board_init.c @@ -54,6 +54,8 @@ void board_early_init(void) { spi_bdev_ioctl(&spi_bdev2, BDEV_IOCTL_INIT, (uint32_t)&spiflash2_config); } +#if !BUILDING_MBOOT + void board_sleep(int value) { mp_spiflash_deepsleep(&spi_bdev.spiflash, value); mp_spiflash_deepsleep(&spi_bdev2.spiflash, value); @@ -70,3 +72,5 @@ void mp_hal_get_mac(int idx, uint8_t buf[6]) { // Generate a random locally administered MAC address (LAA) mp_hal_generate_laa_mac(idx, buf); } + +#endif From 15b36aa0af238b16d27a4d768d0d2dd462567665 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 23 Aug 2019 11:08:20 +1000 Subject: [PATCH 0644/1788] unix/main: Only accept full emit cmd-line options if native enabled. --- ports/unix/main.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ports/unix/main.c b/ports/unix/main.c index 004d581bb2..c8f0833503 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -313,7 +313,11 @@ STATIC int usage(char **argv) { int impl_opts_cnt = 0; printf( " compile-only -- parse and compile only\n" +#if MICROPY_EMIT_NATIVE " emit={bytecode,native,viper} -- set the default code emitter\n" +#else +" emit=bytecode -- set the default code emitter\n" +#endif ); impl_opts_cnt++; #if MICROPY_ENABLE_GC @@ -343,10 +347,12 @@ STATIC void pre_process_options(int argc, char **argv) { compile_only = true; } else if (strcmp(argv[a + 1], "emit=bytecode") == 0) { emit_opt = MP_EMIT_OPT_BYTECODE; + #if MICROPY_EMIT_NATIVE } else if (strcmp(argv[a + 1], "emit=native") == 0) { emit_opt = MP_EMIT_OPT_NATIVE_PYTHON; } else if (strcmp(argv[a + 1], "emit=viper") == 0) { emit_opt = MP_EMIT_OPT_VIPER; + #endif #if MICROPY_ENABLE_GC } else if (strncmp(argv[a + 1], "heapsize=", sizeof("heapsize=") - 1) == 0) { char *end; From 8e3e05761e1143a2502c7eca07c1b22bac192c84 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 23 Aug 2019 11:09:34 +1000 Subject: [PATCH 0645/1788] mpy-cross/main: Only accept full emit cmdline options if native enabled. --- mpy-cross/main.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mpy-cross/main.c b/mpy-cross/main.c index 970ad2d75f..6312a77469 100644 --- a/mpy-cross/main.c +++ b/mpy-cross/main.c @@ -115,7 +115,11 @@ STATIC int usage(char **argv) { ); int impl_opts_cnt = 0; printf( +#if MICROPY_EMIT_NATIVE " emit={bytecode,native,viper} -- set the default code emitter\n" +#else +" emit=bytecode -- set the default code emitter\n" +#endif ); impl_opts_cnt++; printf( @@ -140,10 +144,12 @@ STATIC void pre_process_options(int argc, char **argv) { } if (strcmp(argv[a + 1], "emit=bytecode") == 0) { emit_opt = MP_EMIT_OPT_BYTECODE; + #if MICROPY_EMIT_NATIVE } else if (strcmp(argv[a + 1], "emit=native") == 0) { emit_opt = MP_EMIT_OPT_NATIVE_PYTHON; } else if (strcmp(argv[a + 1], "emit=viper") == 0) { emit_opt = MP_EMIT_OPT_VIPER; + #endif } else if (strncmp(argv[a + 1], "heapsize=", sizeof("heapsize=") - 1) == 0) { char *end; heap_size = strtol(argv[a + 1] + sizeof("heapsize=") - 1, &end, 0); From af20c2ead3e9bb397fdf89e316aa78b56f165013 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 23 Aug 2019 11:20:50 +1000 Subject: [PATCH 0646/1788] py: Add global default_emit_opt variable to make emit kind persistent. mp_compile no longer takes an emit_opt argument, rather this setting is now provided by the global default_emit_opt variable. Now, when -X emit=native is passed as a command-line option, the emitter will be set for all compiled modules (included imports), not just the top-level script. In the future there could be a way to also set this variable from a script. Fixes issue #4267. --- examples/embedding/hello-embed.c | 2 +- lib/upytesthelper/upytesthelper.c | 2 +- lib/utils/pyexec.c | 2 +- mpy-cross/main.c | 9 ++++++++- ports/bare-arm/main.c | 2 +- ports/javascript/main.c | 2 +- ports/minimal/main.c | 2 +- ports/nrf/main.c | 2 +- ports/qemu-arm/main.c | 2 +- ports/unix/main.c | 9 ++++++++- py/compile.c | 11 ++++++++--- py/compile.h | 4 ++-- py/mpstate.h | 3 +++ py/runtime.c | 5 ++++- 14 files changed, 41 insertions(+), 16 deletions(-) diff --git a/examples/embedding/hello-embed.c b/examples/embedding/hello-embed.c index 9659630966..2000b703c1 100644 --- a/examples/embedding/hello-embed.c +++ b/examples/embedding/hello-embed.c @@ -41,7 +41,7 @@ mp_obj_t execute_from_str(const char *str) { qstr src_name = 1/*MP_QSTR_*/; mp_lexer_t *lex = mp_lexer_new_from_str_len(src_name, str, strlen(str), false); mp_parse_tree_t pt = mp_parse(lex, MP_PARSE_FILE_INPUT); - mp_obj_t module_fun = mp_compile(&pt, src_name, MP_EMIT_OPT_NONE, false); + mp_obj_t module_fun = mp_compile(&pt, src_name, false); mp_call_function_0(module_fun); nlr_pop(); return 0; diff --git a/lib/upytesthelper/upytesthelper.c b/lib/upytesthelper/upytesthelper.c index d28c5b9cc0..326172be65 100644 --- a/lib/upytesthelper/upytesthelper.c +++ b/lib/upytesthelper/upytesthelper.c @@ -101,7 +101,7 @@ void upytest_execute_test(const char *src) { 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_obj_t module_fun = mp_compile(&parse_tree, source_name, false); mp_call_function_0(module_fun); nlr_pop(); } else { diff --git a/lib/utils/pyexec.c b/lib/utils/pyexec.c index adb16937d0..851b026b6f 100644 --- a/lib/utils/pyexec.c +++ b/lib/utils/pyexec.c @@ -89,7 +89,7 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input // source is a lexer, parse and compile the script qstr source_name = lex->source_name; mp_parse_tree_t parse_tree = mp_parse(lex, input_kind); - module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, exec_flags & EXEC_FLAG_IS_REPL); + module_fun = mp_compile(&parse_tree, source_name, exec_flags & EXEC_FLAG_IS_REPL); #else mp_raise_msg(&mp_type_RuntimeError, "script compilation not supported"); #endif diff --git a/mpy-cross/main.c b/mpy-cross/main.c index 6312a77469..afd24ca9f7 100644 --- a/mpy-cross/main.c +++ b/mpy-cross/main.c @@ -72,7 +72,7 @@ STATIC int compile_and_save(const char *file, const char *output_file, const cha #endif mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT); - mp_raw_code_t *rc = mp_compile_to_raw_code(&parse_tree, source_name, emit_opt, false); + mp_raw_code_t *rc = mp_compile_to_raw_code(&parse_tree, source_name, false); vstr_t vstr; vstr_init(&vstr, 16); @@ -196,6 +196,13 @@ MP_NOINLINE int main_(int argc, char **argv) { mp_obj_list_init(mp_sys_path, 0); mp_obj_list_init(mp_sys_argv, 0); + #if MICROPY_EMIT_NATIVE + // Set default emitter options + MP_STATE_VM(default_emit_opt) = emit_opt; + #else + (void)emit_opt; + #endif + // set default compiler configuration mp_dynamic_compiler.small_int_bits = 31; mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode = 0; diff --git a/ports/bare-arm/main.c b/ports/bare-arm/main.c index b96fb47ace..4183944108 100644 --- a/ports/bare-arm/main.c +++ b/ports/bare-arm/main.c @@ -13,7 +13,7 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) { 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_obj_t module_fun = mp_compile(&parse_tree, source_name, true); mp_call_function_0(module_fun); nlr_pop(); } else { diff --git a/ports/javascript/main.c b/ports/javascript/main.c index f8ef0e7c55..77b8b873a5 100644 --- a/ports/javascript/main.c +++ b/ports/javascript/main.c @@ -46,7 +46,7 @@ int do_str(const char *src, mp_parse_input_kind_t input_kind) { 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, false); + mp_obj_t module_fun = mp_compile(&parse_tree, source_name, false); mp_call_function_0(module_fun); nlr_pop(); } else { diff --git a/ports/minimal/main.c b/ports/minimal/main.c index 5e145dc829..adc1dad0c6 100644 --- a/ports/minimal/main.c +++ b/ports/minimal/main.c @@ -16,7 +16,7 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) { 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_obj_t module_fun = mp_compile(&parse_tree, source_name, true); mp_call_function_0(module_fun); nlr_pop(); } else { diff --git a/ports/nrf/main.c b/ports/nrf/main.c index e1ffce9385..29dd34f69d 100644 --- a/ports/nrf/main.c +++ b/ports/nrf/main.c @@ -81,7 +81,7 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) { if (nlr_push(&nlr) == 0) { qstr source_name = lex->source_name; mp_parse_tree_t pn = mp_parse(lex, input_kind); - mp_obj_t module_fun = mp_compile(&pn, source_name, MP_EMIT_OPT_NONE, true); + mp_obj_t module_fun = mp_compile(&pn, source_name, true); mp_call_function_0(module_fun); nlr_pop(); } else { diff --git a/ports/qemu-arm/main.c b/ports/qemu-arm/main.c index 4cdd148287..41bf9457ba 100644 --- a/ports/qemu-arm/main.c +++ b/ports/qemu-arm/main.c @@ -18,7 +18,7 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) { 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_obj_t module_fun = mp_compile(&parse_tree, source_name, true); mp_call_function_0(module_fun); nlr_pop(); } else { diff --git a/ports/unix/main.c b/ports/unix/main.c index c8f0833503..65a4dd8a10 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -138,7 +138,7 @@ STATIC int execute_from_lexer(int source_kind, const void *source, mp_parse_inpu } #endif - mp_obj_t module_fun = mp_compile(&parse_tree, source_name, emit_opt, is_repl); + mp_obj_t module_fun = mp_compile(&parse_tree, source_name, is_repl); if (!compile_only) { // execute it @@ -456,6 +456,13 @@ MP_NOINLINE int main_(int argc, char **argv) { mp_init(); + #if MICROPY_EMIT_NATIVE + // Set default emitter options + MP_STATE_VM(default_emit_opt) = emit_opt; + #else + (void)emit_opt; + #endif + #if MICROPY_VFS_POSIX { // Mount the host FS at the root of our internal VFS diff --git a/py/compile.c b/py/compile.c index c0ae3de114..829472c0d7 100644 --- a/py/compile.c +++ b/py/compile.c @@ -3437,7 +3437,7 @@ STATIC void scope_compute_things(scope_t *scope) { #if !MICROPY_PERSISTENT_CODE_SAVE STATIC #endif -mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_file, uint emit_opt, bool is_repl) { +mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_file, bool is_repl) { // put compiler state on the stack, it's relatively small compiler_t comp_state = {0}; compiler_t *comp = &comp_state; @@ -3448,6 +3448,11 @@ mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_f comp->continue_label = INVALID_LABEL; // create the module scope + #if MICROPY_EMIT_NATIVE + const uint emit_opt = MP_STATE_VM(default_emit_opt); + #else + const uint emit_opt = MP_EMIT_OPT_NONE; + #endif scope_t *module_scope = scope_new_and_link(comp, SCOPE_MODULE, parse_tree->root, emit_opt); // create standard emitter; it's used at least for MP_PASS_SCOPE @@ -3602,8 +3607,8 @@ mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_f } } -mp_obj_t mp_compile(mp_parse_tree_t *parse_tree, qstr source_file, uint emit_opt, bool is_repl) { - mp_raw_code_t *rc = mp_compile_to_raw_code(parse_tree, source_file, emit_opt, is_repl); +mp_obj_t mp_compile(mp_parse_tree_t *parse_tree, qstr source_file, bool is_repl) { + mp_raw_code_t *rc = mp_compile_to_raw_code(parse_tree, source_file, is_repl); // return function that executes the outer module return mp_make_function_from_raw_code(rc, MP_OBJ_NULL, MP_OBJ_NULL); } diff --git a/py/compile.h b/py/compile.h index 99a17a8d1e..1ad1f5e9cd 100644 --- a/py/compile.h +++ b/py/compile.h @@ -32,11 +32,11 @@ // the compiler will raise an exception if an error occurred // the compiler will clear the parse tree before it returns -mp_obj_t mp_compile(mp_parse_tree_t *parse_tree, qstr source_file, uint emit_opt, bool is_repl); +mp_obj_t mp_compile(mp_parse_tree_t *parse_tree, qstr source_file, bool is_repl); #if MICROPY_PERSISTENT_CODE_SAVE // this has the same semantics as mp_compile -mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_file, uint emit_opt, bool is_repl); +mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_file, bool is_repl); #endif // this is implemented in runtime.c diff --git a/py/mpstate.h b/py/mpstate.h index 1057cef041..83fea3eb41 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -205,6 +205,9 @@ typedef struct _mp_state_vm_t { #if MICROPY_ENABLE_COMPILER mp_uint_t mp_optimise_value; + #if MICROPY_EMIT_NATIVE + uint8_t default_emit_opt; // one of MP_EMIT_OPT_xxx + #endif #endif // size of the emergency exception buf, if it's dynamically allocated diff --git a/py/runtime.c b/py/runtime.c index 9e60eb6263..d81321e862 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -88,6 +88,9 @@ void mp_init(void) { #if MICROPY_ENABLE_COMPILER // optimization disabled by default MP_STATE_VM(mp_optimise_value) = 0; + #if MICROPY_EMIT_NATIVE + MP_STATE_VM(default_emit_opt) = MP_EMIT_OPT_NONE; + #endif #endif // init global module dict @@ -1434,7 +1437,7 @@ mp_obj_t mp_parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t parse_i if (nlr_push(&nlr) == 0) { qstr source_name = lex->source_name; mp_parse_tree_t parse_tree = mp_parse(lex, parse_input_kind); - mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, false); + mp_obj_t module_fun = mp_compile(&parse_tree, source_name, false); mp_obj_t ret; if (MICROPY_PY_BUILTINS_COMPILE && globals == NULL) { From b3152b2de7115f5b2ca7a1b5240a33c0fb24bdc0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 23 Aug 2019 11:25:46 +1000 Subject: [PATCH 0647/1788] tests: Split out test for optimisation level and line-no printing. --- tests/micropython/opt_level.py | 5 ----- tests/micropython/opt_level.py.exp | 3 --- tests/micropython/opt_level_lineno.py | 6 ++++++ tests/micropython/opt_level_lineno.py.exp | 3 +++ tests/run-tests | 1 + 5 files changed, 10 insertions(+), 8 deletions(-) create mode 100644 tests/micropython/opt_level_lineno.py create mode 100644 tests/micropython/opt_level_lineno.py.exp diff --git a/tests/micropython/opt_level.py b/tests/micropython/opt_level.py index 5a10047f04..4e2f2f4ea3 100644 --- a/tests/micropython/opt_level.py +++ b/tests/micropython/opt_level.py @@ -12,8 +12,3 @@ exec('print(__debug__)') micropython.opt_level(1) exec('print(__debug__)') exec('assert 0') - -# check that level 3 doesn't store line numbers -# the expected output is that any line is printed as "line 1" -micropython.opt_level(3) -exec('try:\n xyz\nexcept NameError as er:\n import sys\n sys.print_exception(er)') diff --git a/tests/micropython/opt_level.py.exp b/tests/micropython/opt_level.py.exp index 6372f6c5d6..74b3dd74e8 100644 --- a/tests/micropython/opt_level.py.exp +++ b/tests/micropython/opt_level.py.exp @@ -2,6 +2,3 @@ 1 True False -Traceback (most recent call last): - File "", line 1, in -NameError: name 'xyz' isn't defined diff --git a/tests/micropython/opt_level_lineno.py b/tests/micropython/opt_level_lineno.py new file mode 100644 index 0000000000..00e5739605 --- /dev/null +++ b/tests/micropython/opt_level_lineno.py @@ -0,0 +1,6 @@ +import micropython as micropython + +# check that level 3 doesn't store line numbers +# the expected output is that any line is printed as "line 1" +micropython.opt_level(3) +exec('try:\n xyz\nexcept NameError as er:\n import sys\n sys.print_exception(er)') diff --git a/tests/micropython/opt_level_lineno.py.exp b/tests/micropython/opt_level_lineno.py.exp new file mode 100644 index 0000000000..469b90ba79 --- /dev/null +++ b/tests/micropython/opt_level_lineno.py.exp @@ -0,0 +1,3 @@ +Traceback (most recent call last): + File "", line 1, in +NameError: name 'xyz' isn't defined diff --git a/tests/run-tests b/tests/run-tests index c45d2787e2..b22d067192 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -377,6 +377,7 @@ def run_tests(pyb, tests, args, base_path="."): skip_tests.add('misc/sys_exc_info.py') # sys.exc_info() is not supported for native skip_tests.add('micropython/emg_exc.py') # because native doesn't have proper traceback info skip_tests.add('micropython/heapalloc_traceback.py') # because native doesn't have proper traceback info + skip_tests.add('micropython/opt_level_lineno.py') # native doesn't have proper traceback info skip_tests.add('micropython/schedule.py') # native code doesn't check pending events for test_file in tests: From 0bec07f32b04a8249e1c732acb7eeb56ac125398 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Fri, 23 Aug 2019 19:49:10 +0200 Subject: [PATCH 0648/1788] stm32/extint: Fix EXTI mapping of PVD and RTC events for H7 MCUs. --- ports/stm32/extint.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ports/stm32/extint.c b/ports/stm32/extint.c index 836b0c5954..c5b3b0c6a7 100644 --- a/ports/stm32/extint.c +++ b/ports/stm32/extint.c @@ -163,7 +163,12 @@ 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(STM32WB) + #if defined(STM32H7) + PVD_AVD_IRQn, + RTC_Alarm_IRQn, + TAMP_STAMP_IRQn, + RTC_WKUP_IRQn, + #elif defined(STM32WB) PVD_PVM_IRQn, RTC_Alarm_IRQn, TAMP_STAMP_LSECSS_IRQn, From afc8596c154f86b8d612a7ac28b999e8ea26df55 Mon Sep 17 00:00:00 2001 From: "Paul m. p. P" Date: Tue, 27 Aug 2019 01:20:43 +0200 Subject: [PATCH 0649/1788] docs/reference/speed_python: Add missing self to var caching example. --- docs/reference/speed_python.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/speed_python.rst b/docs/reference/speed_python.rst index f2d7739fb0..aa0b54cb50 100644 --- a/docs/reference/speed_python.rst +++ b/docs/reference/speed_python.rst @@ -165,7 +165,7 @@ by caching the object in a local variable: class foo(object): def __init__(self): - ba = bytearray(100) + self.ba = bytearray(100) def bar(self, obj_display): ba_ref = self.ba fb = obj_display.framebuffer From 5635b96461e7806c06fccfa237dae670cc2a1377 Mon Sep 17 00:00:00 2001 From: Eric Poulsen Date: Tue, 27 Aug 2019 10:11:03 -0700 Subject: [PATCH 0650/1788] esp32: Add 'config' function to network.LAN, reusing network.WLAN. --- ports/esp32/modnetwork.c | 48 +++++++++++++++++++++++++++------------ ports/esp32/modnetwork.h | 1 + ports/esp32/network_lan.c | 1 + 3 files changed, 36 insertions(+), 14 deletions(-) diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index 3dfe3945bb..45ea5139c6 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -550,17 +550,24 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); - // get the config for the interface + bool is_wifi = self->if_id == WIFI_IF_AP || self->if_id == WIFI_IF_STA; + wifi_config_t cfg; - ESP_EXCEPTIONS(esp_wifi_get_config(self->if_id, &cfg)); + if (is_wifi) { + ESP_EXCEPTIONS(esp_wifi_get_config(self->if_id, &cfg)); + } + + #define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x) if (kwargs->used != 0) { + if (!is_wifi) { + goto unknown; + } 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; @@ -612,7 +619,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) { @@ -633,20 +639,34 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs } int req_if = -1; - mp_obj_t val; + mp_obj_t val = mp_const_none; - #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)); + switch (self->if_id) { + case WIFI_IF_AP: // fallthrough intentional + case WIFI_IF_STA: + ESP_EXCEPTIONS(esp_wifi_get_mac(self->if_id, mac)); + return mp_obj_new_bytes(mac, sizeof(mac)); + + case ESP_IF_ETH: + esp_eth_get_mac(mac); + return mp_obj_new_bytes(mac, sizeof(mac)); + default: + goto unknown; + } } case QS(MP_QSTR_essid): - 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); + switch (self->if_id) { + case WIFI_IF_STA: + val = mp_obj_new_str((char*)cfg.sta.ssid, strlen((char*)cfg.sta.ssid)); + break; + case WIFI_IF_AP: + val = mp_obj_new_str((char*)cfg.ap.ssid, cfg.ap.ssid_len); + break; + default: + req_if = WIFI_IF_AP; } break; case QS(MP_QSTR_hidden): @@ -670,6 +690,7 @@ 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 @@ -682,8 +703,7 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs unknown: mp_raise_ValueError("unknown config param"); } - -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp_config_obj, 1, esp_config); +MP_DEFINE_CONST_FUN_OBJ_KW(esp_config_obj, 1, esp_config); STATIC const mp_rom_map_elem_t wlan_if_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&esp_active_obj) }, diff --git a/ports/esp32/modnetwork.h b/ports/esp32/modnetwork.h index f39a2919d7..64d2da018c 100644 --- a/ports/esp32/modnetwork.h +++ b/ports/esp32/modnetwork.h @@ -31,6 +31,7 @@ enum { PHY_LAN8720, PHY_TLK110 }; MP_DECLARE_CONST_FUN_OBJ_KW(get_lan_obj); MP_DECLARE_CONST_FUN_OBJ_1(ppp_make_new_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(esp_ifconfig_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(esp_config_obj); void usocket_events_deinit(void); diff --git a/ports/esp32/network_lan.c b/ports/esp32/network_lan.c index 10f17ebcf8..100894b2ee 100644 --- a/ports/esp32/network_lan.c +++ b/ports/esp32/network_lan.c @@ -205,6 +205,7 @@ 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_config), MP_ROM_PTR(&esp_config_obj) }, { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&esp_ifconfig_obj) }, }; From 1fe1ff935b258a79f42796bbdc8bb858f5bff462 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 28 Aug 2019 13:34:45 +1000 Subject: [PATCH 0651/1788] nrf: Clean up source by removing tabs, trailing spaces, non-ASCII chars. --- ports/nrf/boards/common.ld | 8 ++--- .../boards/microbit/modules/microbitdisplay.c | 20 ++++++------- .../boards/microbit/modules/microbitimage.c | 18 ++++++------ .../boards/microbit/modules/microbitimage.h | 6 ++-- ports/nrf/device/startup_nrf51822.c | 4 +-- ports/nrf/drivers/bluetooth/ble_drv.c | 2 +- ports/nrf/drivers/bluetooth/ble_uart.c | 4 +-- ports/nrf/drivers/ticker.h | 2 +- ports/nrf/fatfs_port.c | 2 +- ports/nrf/main.c | 29 +++++++++---------- ports/nrf/modules/ble/help_sd.h | 2 +- ports/nrf/modules/machine/pin.c | 12 ++++---- ports/nrf/modules/machine/pwm.c | 2 +- ports/nrf/modules/machine/spi.c | 10 +++---- ports/nrf/modules/machine/temp.c | 4 +-- ports/nrf/modules/random/modrandom.c | 2 +- ports/nrf/modules/ubluepy/ubluepy_delegate.c | 2 +- .../nrf/modules/ubluepy/ubluepy_peripheral.c | 2 +- ports/nrf/modules/ubluepy/ubluepy_service.c | 2 +- ports/nrf/mphalport.h | 2 +- ports/nrf/pin_defs_nrf5.h | 6 ++-- 21 files changed, 70 insertions(+), 71 deletions(-) diff --git a/ports/nrf/boards/common.ld b/ports/nrf/boards/common.ld index 2e1e6f7358..6edd33cf01 100644 --- a/ports/nrf/boards/common.ld +++ b/ports/nrf/boards/common.ld @@ -16,7 +16,7 @@ SECTIONS . = ALIGN(4); _etext = .; /* define a global symbol at end of code */ } >FLASH_TEXT - + /* .ARM.extab : { @@ -30,10 +30,10 @@ SECTIONS __exidx_end = .; } >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). @@ -49,7 +49,7 @@ 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_TEXT - + /* Uninitialized data section */ .bss : { diff --git a/ports/nrf/boards/microbit/modules/microbitdisplay.c b/ports/nrf/boards/microbit/modules/microbitdisplay.c index 936a3ec977..2d70817503 100644 --- a/ports/nrf/boards/microbit/modules/microbitdisplay.c +++ b/ports/nrf/boards/microbit/modules/microbitdisplay.c @@ -256,15 +256,15 @@ static const uint16_t render_timings[] = // The scale is (approximately) exponential, // each step is approx x1.9 greater than the previous. { 0, // Bright, Ticks Duration, Relative power - 2, // 1, 2, 32µs, inf - 2, // 2, 4, 64µs, 200% - 4, // 3, 8, 128µs, 200% - 7, // 4, 15, 240µs, 187% - 13, // 5, 28, 448µs, 187% - 25, // 6, 53, 848µs, 189% - 49, // 7, 102, 1632µs, 192% - 97, // 8, 199, 3184µs, 195% -// Always on 9, 375, 6000µs, 188% + 2, // 1, 2, 32us, inf + 2, // 2, 4, 64us, 200% + 4, // 3, 8, 128us, 200% + 7, // 4, 15, 240us, 187% + 13, // 5, 28, 448us, 187% + 25, // 6, 53, 848us, 189% + 49, // 7, 102, 1632us, 192% + 97, // 8, 199, 3184us, 195% +// Always on 9, 375, 6000us, 188% }; #define DISPLAY_TICKER_SLOT 1 @@ -281,7 +281,7 @@ static int32_t callback(void) { return -1; } display->previous_brightness = brightness; - // Return interval (in 16µs ticks) until next callback + // Return interval (in 16us ticks) until next callback return render_timings[brightness]; } diff --git a/ports/nrf/boards/microbit/modules/microbitimage.c b/ports/nrf/boards/microbit/modules/microbitimage.c index 9cba30f878..fca5075089 100644 --- a/ports/nrf/boards/microbit/modules/microbitimage.c +++ b/ports/nrf/boards/microbit/modules/microbitimage.c @@ -62,7 +62,7 @@ STATIC void microbit_image_print(const mp_print_t *print, mp_obj_t self_in, mp_p uint8_t monochromeGetPixelValue(monochrome_5by5_t * p_mono, mp_int_t x, mp_int_t y) { unsigned int index = y*5+x; - if (index == 24) + if (index == 24) return p_mono->pixel44; return (p_mono->bits24[index>>3] >> (index&7))&1; } @@ -380,7 +380,7 @@ mp_obj_t microbit_image_set_pixel(mp_uint_t n_args, const mp_obj_t *args) { mp_raise_ValueError("index cannot be negative"); } mp_int_t bright = mp_obj_get_int(args[3]); - if (bright < 0 || bright > MAX_BRIGHTNESS) + if (bright < 0 || bright > MAX_BRIGHTNESS) mp_raise_ValueError("brightness out of bounds."); if (x < imageWidth(self) && y < imageHeight(self)) { greyscaleSetPixelValue(&(self->greyscale), x, y, bright); @@ -610,7 +610,7 @@ microbit_image_obj_t *microbit_image_dim(microbit_image_obj_t *lhs, mp_float_t f #else microbit_image_obj_t *microbit_image_dim(microbit_image_obj_t *lhs, mp_int_t fval) { #endif - if (fval < 0) + if (fval < 0) mp_raise_ValueError("Brightness multiplier must not be negative."); greyscale_t *result = greyscale_new(imageWidth(lhs), imageHeight(lhs)); for (int x = 0; x < imageWidth(lhs); ++x) { @@ -639,7 +639,7 @@ microbit_image_obj_t *microbit_image_sum(microbit_image_obj_t *lhs, microbit_ima int val; int lval = imageGetPixelValue(lhs, x,y); int rval = imageGetPixelValue(rhs, x,y); - if (add) + if (add) val = min(lval + rval, MAX_BRIGHTNESS); else val = max(0, lval - rval); @@ -647,7 +647,7 @@ microbit_image_obj_t *microbit_image_sum(microbit_image_obj_t *lhs, microbit_ima } } return (microbit_image_obj_t *)result; -} +} STATIC mp_obj_t image_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { if (mp_obj_get_type(lhs_in) != µbit_image_type) { @@ -697,9 +697,9 @@ const mp_obj_type_t microbit_image_type = { .buffer_p = {NULL}, .locals_dict = (mp_obj_dict_t*)µbit_image_locals_dict, }; - + typedef struct _scrolling_string_t { - mp_obj_base_t base; + mp_obj_base_t base; char const *str; mp_uint_t len; mp_obj_t ref; @@ -708,7 +708,7 @@ typedef struct _scrolling_string_t { } scrolling_string_t; typedef struct _scrolling_string_iterator_t { - mp_obj_base_t base; + mp_obj_base_t base; mp_obj_t ref; greyscale_t *img; char const *next_char; @@ -962,7 +962,7 @@ const mp_obj_type_t microbit_facade_iterator_type = { }; mp_obj_t microbit_facade_iterator(mp_obj_t iterable_in, mp_obj_iter_buf_t *iter_buf) { - (void)iter_buf; + (void)iter_buf; facade_iterator_t *result = m_new_obj(facade_iterator_t); string_image_facade_t *iterable = (string_image_facade_t *)iterable_in; result->base.type = µbit_facade_iterator_type; diff --git a/ports/nrf/boards/microbit/modules/microbitimage.h b/ports/nrf/boards/microbit/modules/microbitimage.h index 23edbd6baa..41a6aff4cc 100644 --- a/ports/nrf/boards/microbit/modules/microbitimage.h +++ b/ports/nrf/boards/microbit/modules/microbitimage.h @@ -2,15 +2,15 @@ #define __MICROPY_INCLUDED_MICROBIT_IMAGE_H__ #include "py/runtime.h" - + #define MAX_BRIGHTNESS 9 -/** Monochrome images are immutable, which means that +/** Monochrome images are immutable, which means that * we only need one bit per pixel which saves quite a lot * of memory */ /* we reserve a couple of bits, so we won't need to modify the - * layout if we need to add more functionality or subtypes. */ + * layout if we need to add more functionality or subtypes. */ #define TYPE_AND_FLAGS \ mp_obj_base_t base; \ uint8_t five:1; \ diff --git a/ports/nrf/device/startup_nrf51822.c b/ports/nrf/device/startup_nrf51822.c index 2f15f0f49c..2063e27274 100644 --- a/ports/nrf/device/startup_nrf51822.c +++ b/ports/nrf/device/startup_nrf51822.c @@ -48,8 +48,8 @@ void Reset_Handler(void) { // RAM on in on-mode *ram_on_addr = 3; // block 0 and 1 *ram_on_b_addr = 3; // block 2 and 3 -#if 0 - // RAM on in off-mode +#if 0 + // RAM on in off-mode ram_on_addr = 1 << 16; ram_on_b_addr = 1 << 17; #endif diff --git a/ports/nrf/drivers/bluetooth/ble_drv.c b/ports/nrf/drivers/bluetooth/ble_drv.c index ff3c885c15..e01d118487 100644 --- a/ports/nrf/drivers/bluetooth/ble_drv.c +++ b/ports/nrf/drivers/bluetooth/ble_drv.c @@ -418,7 +418,7 @@ bool ble_drv_advertise_data(ubluepy_advertise_data_t * p_adv_params) { p_adv_params->p_device_name, p_adv_params->device_name_len) != 0) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - "Can not apply device name in the stack.")); + "Can not apply device name in the stack.")); } BLE_DRIVER_LOG("Device name applied\n"); diff --git a/ports/nrf/drivers/bluetooth/ble_uart.c b/ports/nrf/drivers/bluetooth/ble_uart.c index 4a23cd6d2c..b94780e260 100644 --- a/ports/nrf/drivers/bluetooth/ble_uart.c +++ b/ports/nrf/drivers/bluetooth/ble_uart.c @@ -190,7 +190,7 @@ void ble_uart_init0(void) { ble_uart_char_tx.service_handle = ble_uart_service.handle; bool retval = ble_drv_characteristic_add(&ble_uart_char_tx); if (retval) { - ble_uart_char_tx.p_service = &ble_uart_service; + ble_uart_char_tx.p_service = &ble_uart_service; } mp_obj_list_append(ble_uart_service.char_list, MP_OBJ_FROM_PTR(&ble_uart_char_tx)); @@ -198,7 +198,7 @@ void ble_uart_init0(void) { ble_uart_char_rx.service_handle = ble_uart_service.handle; retval = ble_drv_characteristic_add(&ble_uart_char_rx); if (retval) { - ble_uart_char_rx.p_service = &ble_uart_service; + ble_uart_char_rx.p_service = &ble_uart_service; } mp_obj_list_append(ble_uart_service.char_list, MP_OBJ_FROM_PTR(&ble_uart_char_rx)); diff --git a/ports/nrf/drivers/ticker.h b/ports/nrf/drivers/ticker.h index f6a95a9a25..86f1c24477 100644 --- a/ports/nrf/drivers/ticker.h +++ b/ports/nrf/drivers/ticker.h @@ -35,7 +35,7 @@ #define __MICROPY_INCLUDED_LIB_TICKER_H__ /************************************* - * 62.5kHz (16µs cycle time) ticker. + * 62.5kHz (16us cycle time) ticker. ************************************/ #include "nrf.h" diff --git a/ports/nrf/fatfs_port.c b/ports/nrf/fatfs_port.c index 13ac21fb1b..6a17f627bd 100644 --- a/ports/nrf/fatfs_port.c +++ b/ports/nrf/fatfs_port.c @@ -28,6 +28,6 @@ #include "lib/oofatfs/ff.h" DWORD get_fattime(void) { - // TODO: Implement this function. For now, fake it. + // TODO: Implement this function. For now, fake it. return ((2016 - 1980) << 25) | ((12) << 21) | ((4) << 16) | ((00) << 11) | ((18) << 5) | (23 / 2); } diff --git a/ports/nrf/main.c b/ports/nrf/main.c index 29dd34f69d..38d41bd8c5 100644 --- a/ports/nrf/main.c +++ b/ports/nrf/main.c @@ -94,7 +94,7 @@ extern uint32_t _heap_start; extern uint32_t _heap_end; int main(int argc, char **argv) { - + soft_reset: mp_stack_set_top(&_ram_end); @@ -185,8 +185,8 @@ pin_init0(); mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_sd)); mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_sd_slash_lib)); - // use SD card as current directory - f_chdrive("/sd"); + // use SD card as current directory + f_chdrive("/sd"); } no_mem_for_sd:; } @@ -293,18 +293,17 @@ MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open); void HardFault_Handler(void) { #if defined(NRF52_SERIES) - static volatile uint32_t reg; - static volatile uint32_t reg2; - static volatile uint32_t bfar; - reg = SCB->HFSR; - reg2 = SCB->CFSR; - bfar = SCB->BFAR; - for (int i = 0; i < 0; i++) - { - (void)reg; - (void)reg2; - (void)bfar; - } + static volatile uint32_t reg; + static volatile uint32_t reg2; + static volatile uint32_t bfar; + reg = SCB->HFSR; + reg2 = SCB->CFSR; + bfar = SCB->BFAR; + for (int i = 0; i < 0; i++) { + (void)reg; + (void)reg2; + (void)bfar; + } #endif } diff --git a/ports/nrf/modules/ble/help_sd.h b/ports/nrf/modules/ble/help_sd.h index 027bbdd513..69ee5a5381 100644 --- a/ports/nrf/modules/ble/help_sd.h +++ b/ports/nrf/modules/ble/help_sd.h @@ -39,7 +39,7 @@ " ble.enabled() -- check whether bluetooth stack is enabled\n" \ " ble.address() -- return device address as text string\n" \ "\n" - + #else #define HELP_TEXT_SD #endif // MICROPY_PY_BLE diff --git a/ports/nrf/modules/machine/pin.c b/ports/nrf/modules/machine/pin.c index d56abfd04e..4e5b3434f9 100644 --- a/ports/nrf/modules/machine/pin.c +++ b/ports/nrf/modules/machine/pin.c @@ -127,12 +127,12 @@ const pin_obj_t *pin_find(mp_obj_t user_obj) { const pin_obj_t *pin_obj; // If pin is SMALL_INT if (mp_obj_is_small_int(user_obj)) { - uint8_t value = MP_OBJ_SMALL_INT_VALUE(user_obj); + uint8_t value = MP_OBJ_SMALL_INT_VALUE(user_obj); for (uint8_t i = 0; i < machine_pin_num_of_pins; i++) { if (machine_pin_obj[i].pin == value) { return &machine_pin_obj[i]; - } - } + } + } } // If a pin was provided, then use it @@ -364,8 +364,8 @@ STATIC mp_obj_t pin_obj_init_helper(const pin_obj_t *self, mp_uint_t n_args, con nrf_gpio_pin_dir_t mode = (nrf_gpio_pin_dir_t)args[0].u_int; // Connect input or not - nrf_gpio_pin_input_t input = (mode == NRF_GPIO_PIN_DIR_INPUT) ? NRF_GPIO_PIN_INPUT_CONNECT - : NRF_GPIO_PIN_INPUT_DISCONNECT; + nrf_gpio_pin_input_t input = (mode == NRF_GPIO_PIN_DIR_INPUT) ? NRF_GPIO_PIN_INPUT_CONNECT + : NRF_GPIO_PIN_INPUT_DISCONNECT; if (mode == NRF_GPIO_PIN_DIR_OUTPUT || mode == NRF_GPIO_PIN_DIR_INPUT) { nrf_gpio_cfg(self->pin, @@ -496,7 +496,7 @@ STATIC void pin_common_irq_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t } STATIC mp_obj_t pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum {ARG_handler, ARG_trigger, ARG_wake}; + enum {ARG_handler, ARG_trigger, ARG_wake}; static const mp_arg_t allowed_args[] = { { MP_QSTR_handler, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = mp_const_none} }, { MP_QSTR_trigger, MP_ARG_INT, {.u_int = NRF_GPIOTE_POLARITY_LOTOHI | NRF_GPIOTE_POLARITY_HITOLO} }, diff --git a/ports/nrf/modules/machine/pwm.c b/ports/nrf/modules/machine/pwm.c index cf8749302b..195d47e6b1 100644 --- a/ports/nrf/modules/machine/pwm.c +++ b/ports/nrf/modules/machine/pwm.c @@ -269,7 +269,7 @@ STATIC mp_obj_t machine_hard_pwm_make_new(mp_arg_val_t *args) { } else { self->p_config->mode = MODE_HIGH_LOW; } - + return MP_OBJ_FROM_PTR(self); } diff --git a/ports/nrf/modules/machine/spi.c b/ports/nrf/modules/machine/spi.c index 1c401b76d2..4361a8f8f9 100644 --- a/ports/nrf/modules/machine/spi.c +++ b/ports/nrf/modules/machine/spi.c @@ -154,9 +154,9 @@ STATIC int spi_find(mp_obj_t id) { void spi_transfer(const machine_hard_spi_obj_t * self, size_t len, const void * src, void * dest) { nrfx_spi_xfer_desc_t xfer_desc = { .p_tx_buffer = src, - .tx_length = len, - .p_rx_buffer = dest, - .rx_length = len + .tx_length = len, + .p_rx_buffer = dest, + .rx_length = len }; nrfx_spi_xfer(self->p_spi, &xfer_desc, 0); @@ -340,7 +340,7 @@ STATIC void machine_hard_spi_init(mp_obj_t self_in, mp_arg_val_t *args) { // Active high if (args[ARG_INIT_polarity].u_int == 0) { - if (args[ARG_INIT_phase].u_int == 0) { + if (args[ARG_INIT_phase].u_int == 0) { // First clock edge self->p_config->mode = NRF_SPI_MODE_0; } else { @@ -349,7 +349,7 @@ STATIC void machine_hard_spi_init(mp_obj_t self_in, mp_arg_val_t *args) { } // Active low } else { - if (args[ARG_INIT_phase].u_int == 0) { + if (args[ARG_INIT_phase].u_int == 0) { // First clock edge self->p_config->mode = NRF_SPI_MODE_2; } else { diff --git a/ports/nrf/modules/machine/temp.c b/ports/nrf/modules/machine/temp.c index 361d988857..007a7e5fd8 100644 --- a/ports/nrf/modules/machine/temp.c +++ b/ports/nrf/modules/machine/temp.c @@ -67,9 +67,9 @@ STATIC mp_obj_t machine_temp_make_new(const mp_obj_type_t *type, size_t n_args, // parse args 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_temp_obj_t *self = m_new_obj(machine_temp_obj_t); - + self->base.type = &machine_temp_type; return MP_OBJ_FROM_PTR(self); diff --git a/ports/nrf/modules/random/modrandom.c b/ports/nrf/modules/random/modrandom.c index f67bffb277..a1395bce61 100644 --- a/ports/nrf/modules/random/modrandom.c +++ b/ports/nrf/modules/random/modrandom.c @@ -72,7 +72,7 @@ uint32_t machine_rng_generate_random_word(void) { status = sd_rand_application_vector_get((uint8_t *)&retval, 4); // Extract 4 bytes } while (status != 0); - return retval; + return retval; } #endif diff --git a/ports/nrf/modules/ubluepy/ubluepy_delegate.c b/ports/nrf/modules/ubluepy/ubluepy_delegate.c index 07bb7f4928..74ad52bbfa 100644 --- a/ports/nrf/modules/ubluepy/ubluepy_delegate.c +++ b/ports/nrf/modules/ubluepy/ubluepy_delegate.c @@ -72,7 +72,7 @@ STATIC const mp_rom_map_elem_t ubluepy_delegate_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_handleConnection), MP_ROM_PTR(&ubluepy_delegate_handle_conn_obj) }, { MP_ROM_QSTR(MP_QSTR_handleNotification), MP_ROM_PTR(&ubluepy_delegate_handle_notif_obj) }, #if 0 - { MP_ROM_QSTR(MP_QSTR_handleDiscovery), MP_ROM_PTR(&ubluepy_delegate_handle_disc_obj) }, + { MP_ROM_QSTR(MP_QSTR_handleDiscovery), MP_ROM_PTR(&ubluepy_delegate_handle_disc_obj) }, #endif }; diff --git a/ports/nrf/modules/ubluepy/ubluepy_peripheral.c b/ports/nrf/modules/ubluepy/ubluepy_peripheral.c index 3a45e56a07..8f07daa2a3 100644 --- a/ports/nrf/modules/ubluepy/ubluepy_peripheral.c +++ b/ports/nrf/modules/ubluepy/ubluepy_peripheral.c @@ -481,7 +481,7 @@ STATIC const mp_rom_map_elem_t ubluepy_peripheral_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_advertise), MP_ROM_PTR(&ubluepy_peripheral_advertise_obj) }, #endif #if MICROPY_PY_UBLUEPY_OBSERVER - // Nothing yet. + // Nothing yet. #endif }; diff --git a/ports/nrf/modules/ubluepy/ubluepy_service.c b/ports/nrf/modules/ubluepy/ubluepy_service.c index e5bf42a09f..a38136611f 100644 --- a/ports/nrf/modules/ubluepy/ubluepy_service.c +++ b/ports/nrf/modules/ubluepy/ubluepy_service.c @@ -162,7 +162,7 @@ STATIC const mp_rom_map_elem_t ubluepy_service_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_addCharacteristic), MP_ROM_PTR(&ubluepy_service_add_char_obj) }, { MP_ROM_QSTR(MP_QSTR_getCharacteristics), MP_ROM_PTR(&ubluepy_service_get_chars_obj) }, #if 0 - // Properties + // Properties { MP_ROM_QSTR(MP_QSTR_peripheral), MP_ROM_PTR(&ubluepy_service_get_peripheral_obj) }, #endif { MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&ubluepy_service_get_uuid_obj) }, diff --git a/ports/nrf/mphalport.h b/ports/nrf/mphalport.h index 18ff454fe6..b374da403c 100644 --- a/ports/nrf/mphalport.h +++ b/ports/nrf/mphalport.h @@ -42,7 +42,7 @@ typedef enum } HAL_StatusTypeDef; static inline uint32_t hal_tick_fake(void) { - return 0; + return 0; } #define mp_hal_ticks_ms hal_tick_fake // TODO: implement. Right now, return 0 always diff --git a/ports/nrf/pin_defs_nrf5.h b/ports/nrf/pin_defs_nrf5.h index c84d048a42..99020ded75 100644 --- a/ports/nrf/pin_defs_nrf5.h +++ b/ports/nrf/pin_defs_nrf5.h @@ -53,9 +53,9 @@ enum { }; #define PIN_DEFS_PORT_AF_UNION \ - NRF_UART_Type *UART; -// NRF_SPI_Type *SPIM; -// NRF_SPIS_Type *SPIS; + NRF_UART_Type *UART; +// NRF_SPI_Type *SPIM; +// NRF_SPIS_Type *SPIS; typedef NRF_GPIO_Type pin_gpio_t; From 400a128e11b94cc268685d1b7b26c613a34ca8c3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 29 Aug 2019 12:00:18 +1000 Subject: [PATCH 0652/1788] stm32/stm32_it: Include correct EXTI interrupt handlers for L0 MCUs. --- ports/stm32/stm32_it.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index a2ebb6641a..9f5a886f3d 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -531,7 +531,7 @@ void RTC_WKUP_IRQHandler(void) { IRQ_EXIT(RTC_WKUP_IRQn); } -#if defined(STM32F0) +#if defined(STM32F0) || defined(STM32L0) void RTC_IRQHandler(void) { IRQ_ENTER(RTC_IRQn); From c7c6703950ef14f04ff9ad9d6b61b4b0666144c0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 28 Aug 2019 11:37:43 +1000 Subject: [PATCH 0653/1788] py/compile: Improve the line numbering precision for lambdas. Prior to this patch the line number for a lambda would be "line 1" if the body of the lambda contained only a simple expression (with no line number stored in the parse node). Now the line number is always reported correctly. --- py/compile.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/py/compile.c b/py/compile.c index 829472c0d7..41ff66a8ca 100644 --- a/py/compile.c +++ b/py/compile.c @@ -3078,6 +3078,9 @@ STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) { mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)scope->pn; assert(MP_PARSE_NODE_STRUCT_NUM_NODES(pns) == 3); + // Set the source line number for the start of the lambda + EMIT_ARG(set_source_line, pns->source_line); + // work out number of parameters, keywords and default parameters, and add them to the id_info array // must be done before compiling the body so that arguments are numbered first (for LOAD_FAST etc) if (comp->pass == MP_PASS_SCOPE) { From dbf35d3da359a2ddbccb1ea2116da37e23ce46bf Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 30 Aug 2019 16:41:08 +1000 Subject: [PATCH 0654/1788] py/bc: Factor out code to get bytecode line number info into new func. --- py/bc.h | 27 +++++++++++++++++++++++++++ py/vm.c | 24 +----------------------- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/py/bc.h b/py/bc.h index 0aadfa8a30..bedffa795e 100644 --- a/py/bc.h +++ b/py/bc.h @@ -119,4 +119,31 @@ uint mp_opcode_format(const byte *ip, size_t *opcode_size, bool count_var_uint); #endif +static inline size_t mp_bytecode_get_source_line(const byte *line_info, size_t bc_offset) { + size_t source_line = 1; + size_t c; + while ((c = *line_info)) { + size_t b, l; + if ((c & 0x80) == 0) { + // 0b0LLBBBBB encoding + b = c & 0x1f; + l = c >> 5; + line_info += 1; + } else { + // 0b1LLLBBBB 0bLLLLLLLL encoding (l's LSB in second byte) + b = c & 0xf; + l = ((c << 4) & 0x700) | line_info[1]; + line_info += 2; + } + if (bc_offset >= b) { + bc_offset -= b; + source_line += l; + } else { + // found source line corresponding to bytecode offset + break; + } + } + return source_line; +} + #endif // MICROPY_INCLUDED_PY_BC_H diff --git a/py/vm.c b/py/vm.c index 84296b463f..0bc2034613 100644 --- a/py/vm.c +++ b/py/vm.c @@ -1387,29 +1387,7 @@ unwind_loop: qstr source_file = mp_decode_uint_value(ip); ip = mp_decode_uint_skip(ip); #endif - size_t source_line = 1; - size_t c; - while ((c = *ip)) { - size_t b, l; - if ((c & 0x80) == 0) { - // 0b0LLBBBBB encoding - b = c & 0x1f; - l = c >> 5; - ip += 1; - } else { - // 0b1LLLBBBB 0bLLLLLLLL encoding (l's LSB in second byte) - b = c & 0xf; - l = ((c << 4) & 0x700) | ip[1]; - ip += 2; - } - if (bc >= b) { - bc -= b; - source_line += l; - } else { - // found source line corresponding to bytecode offset - break; - } - } + size_t source_line = mp_bytecode_get_source_line(ip, bc); mp_obj_exception_add_traceback(MP_OBJ_FROM_PTR(nlr.ret_val), source_file, source_line, block_name); } From c96aedad4691d864c073890a7a20abc7ebd2de27 Mon Sep 17 00:00:00 2001 From: Milan Rossa Date: Wed, 14 Aug 2019 15:59:38 +0200 Subject: [PATCH 0655/1788] py/profile: Add initial implementation of sys.settrace feature. --- py/profile.c | 441 +++++++++++++++++++++++++++++++++++++++++++++++++++ py/profile.h | 69 ++++++++ 2 files changed, 510 insertions(+) create mode 100644 py/profile.c create mode 100644 py/profile.h diff --git a/py/profile.c b/py/profile.c new file mode 100644 index 0000000000..39578f6dcd --- /dev/null +++ b/py/profile.c @@ -0,0 +1,441 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) SatoshiLabs + * + * 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/profile.h" +#include "py/bc0.h" +#include "py/gc.h" + +#if MICROPY_PY_SYS_SETTRACE + +#define prof_trace_cb MP_STATE_THREAD(prof_trace_callback) + +STATIC uint mp_prof_bytecode_lineno(const mp_raw_code_t *rc, size_t bc) { + const mp_bytecode_prelude_t *prelude = &rc->prelude; + return mp_bytecode_get_source_line(prelude->line_info, bc + prelude->opcodes - prelude->locals); +} + +void mp_prof_extract_prelude(const byte *bytecode, mp_bytecode_prelude_t *prelude) { + const byte *ip = bytecode; + + prelude->n_state = mp_decode_uint(&ip); + prelude->n_exc_stack = mp_decode_uint(&ip); + prelude->scope_flags = *ip++; + prelude->n_pos_args = *ip++; + prelude->n_kwonly_args = *ip++; + prelude->n_def_pos_args = *ip++; + + const byte *code_info = ip; + size_t code_info_size = mp_decode_uint(&ip); + + qstr block_name = ip[0] | (ip[1] << 8); + qstr source_file = ip[2] | (ip[3] << 8); + ip += 4; + prelude->qstr_block_name = block_name; + prelude->qstr_source_file = source_file; + + prelude->line_info = ip; + prelude->locals = code_info + code_info_size; + + ip = prelude->locals; + while (*ip++ != 255) { + } + prelude->opcodes = ip; +} + +/******************************************************************************/ +// code object + +STATIC void code_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_code_t *o = MP_OBJ_TO_PTR(o_in); + const mp_raw_code_t *rc = o->rc; + const mp_bytecode_prelude_t *prelude = &rc->prelude; + mp_printf(print, + "", + prelude->qstr_block_name, + o, + prelude->qstr_source_file, + rc->line_of_definition + ); +} + +STATIC mp_obj_tuple_t* code_consts(const mp_raw_code_t *rc) { + const mp_bytecode_prelude_t *prelude = &rc->prelude; + int start = prelude->n_pos_args + prelude->n_kwonly_args + rc->n_obj; + int stop = prelude->n_pos_args + prelude->n_kwonly_args + rc->n_obj + rc->n_raw_code; + mp_obj_tuple_t *consts = MP_OBJ_TO_PTR(mp_obj_new_tuple(stop - start + 1, NULL)); + + size_t const_no = 0; + for (int i = start; i < stop; ++i) { + mp_obj_t code = mp_obj_new_code((const mp_raw_code_t*)MP_OBJ_TO_PTR(rc->const_table[i])); + if (code == MP_OBJ_NULL) { + m_malloc_fail(sizeof(mp_obj_code_t)); + } + consts->items[const_no++] = code; + } + consts->items[const_no++] = mp_const_none; + + return consts; +} + +STATIC mp_obj_t raw_code_lnotab(const mp_raw_code_t *rc) { + // const mp_bytecode_prelude_t *prelude = &rc->prelude; + uint start = 0; + uint stop = rc->fun_data_len - start; + + uint last_lineno = mp_prof_bytecode_lineno(rc, start); + uint lasti = 0; + + const uint buffer_chunk_size = (stop-start) >> 2; // heuristic magic + uint buffer_size = buffer_chunk_size; + byte *buffer = m_new(byte, buffer_size); + uint buffer_index = 0; + + for (uint i = start; i < stop; ++i) { + uint lineno = mp_prof_bytecode_lineno(rc, i); + size_t line_diff = lineno - last_lineno; + if (line_diff > 0) { + uint instr_diff = (i - start) - lasti; + + assert(instr_diff < 256); + assert(line_diff < 256); + + if (buffer_index + 2 > buffer_size) { + buffer = m_renew(byte, buffer, buffer_size, buffer_size + buffer_chunk_size); + buffer_size = buffer_size + buffer_chunk_size; + } + last_lineno = lineno; + lasti = i - start; + buffer[buffer_index++] = instr_diff; + buffer[buffer_index++] = line_diff; + } + } + + mp_obj_t o = mp_obj_new_bytes(buffer, buffer_index); + m_del(byte, buffer, buffer_size); + return o; +} + +STATIC void code_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + if (dest[0] != MP_OBJ_NULL) { + // not load attribute + return; + } + mp_obj_code_t *o = MP_OBJ_TO_PTR(self_in); + const mp_raw_code_t *rc = o->rc; + const mp_bytecode_prelude_t *prelude = &rc->prelude; + switch(attr) { + case MP_QSTR_co_code: + dest[0] = mp_obj_new_bytes( + (void*)prelude->opcodes, + rc->fun_data_len - (prelude->opcodes - (const byte*)rc->fun_data) + ); + break; + case MP_QSTR_co_consts: + dest[0] = MP_OBJ_FROM_PTR(code_consts(rc)); + break; + case MP_QSTR_co_filename: + dest[0] = MP_OBJ_NEW_QSTR(prelude->qstr_source_file); + break; + case MP_QSTR_co_firstlineno: + dest[0] = MP_OBJ_NEW_SMALL_INT(mp_prof_bytecode_lineno(rc, 0)); + break; + case MP_QSTR_co_name: + dest[0] = MP_OBJ_NEW_QSTR(prelude->qstr_block_name); + break; + case MP_QSTR_co_names: + dest[0] = MP_OBJ_FROM_PTR(o->dict_locals); + break; + case MP_QSTR_co_lnotab: + if (!o->lnotab) { + o->lnotab = raw_code_lnotab(rc); + } + dest[0] = o->lnotab; + break; + } +} + +const mp_obj_type_t mp_type_code = { + { &mp_type_type }, + .name = MP_QSTR_code, + .print = code_print, + .unary_op = mp_generic_unary_op, + .attr = code_attr, +}; + +mp_obj_t mp_obj_new_code(const mp_raw_code_t *rc) { + mp_obj_code_t *o = m_new_obj_maybe(mp_obj_code_t); + if (o == NULL) { + return MP_OBJ_NULL; + } + o->base.type = &mp_type_code; + o->rc = rc; + o->dict_locals = mp_locals_get(); // this is a wrong! how to do this properly? + o->lnotab = MP_OBJ_NULL; + return MP_OBJ_FROM_PTR(o); +} + +/******************************************************************************/ +// frame object + +STATIC void frame_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_frame_t *frame = MP_OBJ_TO_PTR(o_in); + mp_obj_code_t *code = frame->code; + const mp_raw_code_t *rc = code->rc; + const mp_bytecode_prelude_t *prelude = &rc->prelude; + mp_printf(print, + "", + frame, + prelude->qstr_source_file, + frame->lineno, + prelude->qstr_block_name + ); +} + +STATIC void frame_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + if (dest[0] != MP_OBJ_NULL) { + // not load attribute + return; + } + + mp_obj_frame_t *o = MP_OBJ_TO_PTR(self_in); + + switch(attr) { + case MP_QSTR_f_back: + dest[0] = mp_const_none; + if (o->code_state->prev_state) { + dest[0] = MP_OBJ_FROM_PTR(o->code_state->prev_state->frame); + } + break; + case MP_QSTR_f_code: + dest[0] = MP_OBJ_FROM_PTR(o->code); + break; + case MP_QSTR_f_globals: + dest[0] = MP_OBJ_FROM_PTR(o->code_state->fun_bc->globals); + break; + case MP_QSTR_f_lasti: + dest[0] = MP_OBJ_NEW_SMALL_INT(o->lasti); + break; + case MP_QSTR_f_lineno: + dest[0] = MP_OBJ_NEW_SMALL_INT(o->lineno); + break; + } +} + +const mp_obj_type_t mp_type_frame = { + { &mp_type_type }, + .name = MP_QSTR_frame, + .print = frame_print, + .unary_op = mp_generic_unary_op, + .attr = frame_attr, +}; + +mp_obj_t mp_obj_new_frame(const mp_code_state_t *code_state) { + if (gc_is_locked()) { + return MP_OBJ_NULL; + } + + mp_obj_frame_t *o = m_new_obj_maybe(mp_obj_frame_t); + if (o == NULL) { + return MP_OBJ_NULL; + } + + mp_obj_code_t *code = o->code = MP_OBJ_TO_PTR(mp_obj_new_code(code_state->fun_bc->rc)); + if (code == NULL) { + return MP_OBJ_NULL; + } + + const mp_raw_code_t *rc = code->rc; + const mp_bytecode_prelude_t *prelude = &rc->prelude; + o->code_state = code_state; + o->base.type = &mp_type_frame; + o->back = NULL; + o->code = code; + o->lasti = code_state->ip - prelude->opcodes; + o->lineno = mp_prof_bytecode_lineno(rc, o->lasti); + o->trace_opcodes = false; + o->callback = MP_OBJ_NULL; + + return MP_OBJ_FROM_PTR(o); +} + + +/******************************************************************************/ +// Trace logic + +typedef struct { + struct _mp_obj_frame_t * frame; + mp_obj_t event; + mp_obj_t arg; +} prof_callback_args_t; + +STATIC mp_obj_t mp_prof_callback_invoke(mp_obj_t callback, prof_callback_args_t *args) { + assert(mp_obj_is_callable(callback)); + + mp_prof_is_executing = true; + + mp_obj_t a[3] = {MP_OBJ_FROM_PTR(args->frame), args->event, args->arg}; + mp_obj_t top = mp_call_function_n_kw(callback, 3, 0, a); + + mp_prof_is_executing = false; + + 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); + } + return top; +} + +mp_obj_t mp_prof_settrace(mp_obj_t callback) { + if (mp_obj_is_callable(callback)) { + prof_trace_cb = callback; + } else { + prof_trace_cb = MP_OBJ_NULL; + } + return mp_const_none; +} + +mp_obj_t mp_prof_frame_enter(mp_code_state_t *code_state) { + assert(!mp_prof_is_executing); + + mp_obj_frame_t *frame = MP_OBJ_TO_PTR(mp_obj_new_frame(code_state)); + if (frame == NULL) { + // Couldn't allocate a frame object + return MP_OBJ_NULL; + } + + if (code_state->prev_state && code_state->frame == NULL) { + // We are entering not-yet-traced frame + // which means it's a CALL event (not a GENERATOR) + // so set the function definition line. + const mp_raw_code_t *rc = code_state->fun_bc->rc; + frame->lineno = rc->line_of_definition; + if (!rc->line_of_definition) { + frame->lineno = mp_prof_bytecode_lineno(rc, 0); + } + } + code_state->frame = frame; + + if (!prof_trace_cb) { + return MP_OBJ_NULL; + } + + mp_obj_t top; + prof_callback_args_t _args, *args=&_args; + args->frame = code_state->frame; + + // SETTRACE event CALL + args->event = MP_OBJ_NEW_QSTR(MP_QSTR_call); + args->arg = mp_const_none; + top = mp_prof_callback_invoke(prof_trace_cb, args); + + code_state->frame->callback = mp_obj_is_callable(top) ? top : MP_OBJ_NULL; + + // Invalidate the last executed line number so the LINE trace can trigger after this CALL. + frame->lineno = 0; + + return top; +} + +mp_obj_t mp_prof_frame_update(const mp_code_state_t *code_state) { + mp_obj_frame_t *frame = code_state->frame; + if (frame == NULL) { + // Frame was not allocated (eg because there was no memory available) + return MP_OBJ_NULL; + } + + mp_obj_frame_t *o = frame; + mp_obj_code_t *code = o->code; + const mp_raw_code_t *rc = code->rc; + const mp_bytecode_prelude_t *prelude = &rc->prelude; + + assert(o->code_state == code_state); + + o->lasti = code_state->ip - prelude->opcodes; + o->lineno = mp_prof_bytecode_lineno(rc, o->lasti); + + return MP_OBJ_FROM_PTR(o); +} + +mp_obj_t mp_prof_instr_tick(mp_code_state_t *code_state, bool is_exception) { + // Detect execution recursion + assert(!mp_prof_is_executing); + assert(code_state->frame); + assert(mp_obj_get_type(code_state->frame) == &mp_type_frame); + + // Detect data recursion + assert(code_state != code_state->prev_state); + + mp_obj_t top = mp_const_none; + mp_obj_t callback = code_state->frame->callback; + + prof_callback_args_t _args, *args=&_args; + args->frame = code_state->frame; + args->event = mp_const_none; + args->arg = mp_const_none; + + // Call event's are handled inside mp_prof_frame_enter + + // SETTRACE event EXCEPTION + if (is_exception) { + args->event = MP_OBJ_NEW_QSTR(MP_QSTR_exception); + top = mp_prof_callback_invoke(callback, args); + return top; + } + + // SETTRACE event LINE + const mp_raw_code_t *rc = code_state->fun_bc->rc; + const mp_bytecode_prelude_t *prelude = &rc->prelude; + size_t prev_line_no = args->frame->lineno; + size_t current_line_no = mp_prof_bytecode_lineno(rc, code_state->ip - prelude->opcodes); + if (prev_line_no != current_line_no) { + args->frame->lineno = current_line_no; + args->event = MP_OBJ_NEW_QSTR(MP_QSTR_line); + top = mp_prof_callback_invoke(callback, args); + } + + // SETTRACE event RETURN + const byte *ip = code_state->ip; + if (*ip == MP_BC_RETURN_VALUE || *ip == MP_BC_YIELD_VALUE) { + args->event = MP_OBJ_NEW_QSTR(MP_QSTR_return); + top = mp_prof_callback_invoke(callback, args); + if (code_state->prev_state && *ip == MP_BC_RETURN_VALUE) { + code_state->frame->callback = MP_OBJ_NULL; + } + } + + // SETTRACE event OPCODE + // TODO: frame.f_trace_opcodes=True + if (false) { + args->event = MP_OBJ_NEW_QSTR(MP_QSTR_opcode); + } + + return top; +} + +#endif // MICROPY_PY_SYS_SETTRACE diff --git a/py/profile.h b/py/profile.h new file mode 100644 index 0000000000..227634b564 --- /dev/null +++ b/py/profile.h @@ -0,0 +1,69 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) SatoshiLabs + * + * 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_PROFILING_H +#define MICROPY_INCLUDED_PY_PROFILING_H + +#include "py/emitglue.h" + +#if MICROPY_PY_SYS_SETTRACE + +#define mp_prof_is_executing MP_STATE_THREAD(prof_callback_is_executing) + +typedef struct _mp_obj_code_t { + mp_obj_base_t base; + const mp_raw_code_t *rc; + mp_obj_dict_t *dict_locals; + mp_obj_t lnotab; +} mp_obj_code_t; + +typedef struct _mp_obj_frame_t { + mp_obj_base_t base; + const mp_code_state_t *code_state; + struct _mp_obj_frame_t *back; + mp_obj_t callback; + mp_obj_code_t *code; + mp_uint_t lasti; + mp_uint_t lineno; + bool trace_opcodes; +} mp_obj_frame_t; + +void mp_prof_extract_prelude(const byte *bytecode, mp_bytecode_prelude_t *prelude); + +mp_obj_t mp_obj_new_code(const mp_raw_code_t *rc); +mp_obj_t mp_obj_new_frame(const mp_code_state_t *code_state); + +// This is the implementation for the sys.settrace +mp_obj_t mp_prof_settrace(mp_obj_t callback); + +mp_obj_t mp_prof_frame_enter(mp_code_state_t *code_state); +mp_obj_t mp_prof_frame_update(const mp_code_state_t *code_state); + +// For every VM instruction tick this function deduces events from the state +mp_obj_t mp_prof_instr_tick(mp_code_state_t *code_state, bool is_exception); + +#endif // MICROPY_PY_SYS_SETTRACE +#endif // MICROPY_INCLUDED_PY_PROFILING_H From 310b3d1b81d561e19d719acd89ee47b759e3795c Mon Sep 17 00:00:00 2001 From: Milan Rossa Date: Wed, 14 Aug 2019 16:09:36 +0200 Subject: [PATCH 0656/1788] py: Integrate sys.settrace feature into the VM and runtime. This commit adds support for sys.settrace, allowing to install Python handlers to trace execution of Python code. The interface follows CPython as closely as possible. The feature is disabled by default and can be enabled via MICROPY_PY_SYS_SETTRACE. --- ports/unix/main.c | 5 +++ ports/unix/mpconfigport.h | 4 ++ py/bc.c | 5 +++ py/bc.h | 18 ++++++++ py/compile.c | 6 +++ py/emitbc.c | 3 ++ py/emitglue.c | 15 +++++++ py/emitglue.h | 9 ++++ py/modsys.c | 17 ++++++++ py/mpconfig.h | 15 +++++++ py/mpstate.h | 6 +++ py/objfun.h | 3 ++ py/py.mk | 1 + py/runtime.c | 6 +++ py/vm.c | 89 ++++++++++++++++++++++++++++++++++++++- 15 files changed, 201 insertions(+), 1 deletion(-) diff --git a/ports/unix/main.c b/ports/unix/main.c index 65a4dd8a10..9147feb32d 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -655,7 +655,12 @@ MP_NOINLINE int main_(int argc, char **argv) { } } + #if MICROPY_PY_SYS_SETTRACE + MP_STATE_THREAD(prof_trace_callback) = MP_OBJ_NULL; + #endif + #if MICROPY_PY_SYS_ATEXIT + // Beware, the sys.settrace callback should be disabled before running sys.atexit. if (mp_obj_is_callable(MP_STATE_VM(sys_exitfunc))) { mp_call_function_0(MP_STATE_VM(sys_exitfunc)); } diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h index 23c562e5aa..0ff6b2b06d 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -91,6 +91,10 @@ #define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) #define MICROPY_PY_SYS_EXIT (1) #define MICROPY_PY_SYS_ATEXIT (1) +#if MICROPY_PY_SYS_SETTRACE +#define MICROPY_PERSISTENT_CODE_SAVE (1) +#define MICROPY_COMP_CONST (0) +#endif #if defined(__APPLE__) && defined(__MACH__) #define MICROPY_PY_SYS_PLATFORM "darwin" #else diff --git a/py/bc.c b/py/bc.c index b178e7c202..7d0b13bd74 100644 --- a/py/bc.c +++ b/py/bc.c @@ -119,6 +119,11 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw code_state->prev = NULL; #endif + #if MICROPY_PY_SYS_SETTRACE + code_state->prev_state = NULL; + code_state->frame = NULL; + #endif + // get params size_t n_state = mp_decode_uint(&code_state->ip); code_state->ip = mp_decode_uint_skip(code_state->ip); // skip n_exc_stack diff --git a/py/bc.h b/py/bc.h index bedffa795e..ac9105a553 100644 --- a/py/bc.h +++ b/py/bc.h @@ -60,6 +60,20 @@ // const0 : obj // constN : obj +typedef struct _mp_bytecode_prelude_t { + uint n_state; + uint n_exc_stack; + uint scope_flags; + uint n_pos_args; + uint n_kwonly_args; + uint n_def_pos_args; + qstr qstr_block_name; + qstr qstr_source_file; + const byte *line_info; + const byte *locals; + const byte *opcodes; +} mp_bytecode_prelude_t; + // Exception stack entry typedef struct _mp_exc_stack_t { const byte *handler; @@ -84,6 +98,10 @@ typedef struct _mp_code_state_t { #if MICROPY_STACKLESS struct _mp_code_state_t *prev; #endif + #if MICROPY_PY_SYS_SETTRACE + struct _mp_code_state_t *prev_state; + struct _mp_obj_frame_t *frame; + #endif // Variable-length mp_obj_t state[0]; // Variable-length, never accessed by name, only as (void*)(state + n_state) diff --git a/py/compile.c b/py/compile.c index 41ff66a8ca..8b2d820b3b 100644 --- a/py/compile.c +++ b/py/compile.c @@ -1608,6 +1608,9 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_ qstr qstr_exception_local = 0; uint end_finally_label = comp_next_label(comp); + #if MICROPY_PY_SYS_SETTRACE + EMIT_ARG(set_source_line, pns_except->source_line); + #endif if (MP_PARSE_NODE_IS_NULL(pns_except->nodes[0])) { // this is a catch all exception handler @@ -3157,6 +3160,9 @@ STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) { scope_find_or_add_id(scope, MP_QSTR___class__, ID_INFO_KIND_LOCAL); } + #if MICROPY_PY_SYS_SETTRACE + EMIT_ARG(set_source_line, pns->source_line); + #endif compile_load_id(comp, MP_QSTR___name__); compile_store_id(comp, MP_QSTR___module__); EMIT_ARG(load_const_str, MP_PARSE_NODE_LEAF_ARG(pns->nodes[0])); // 0 is class name diff --git a/py/emitbc.c b/py/emitbc.c index fcbd979d27..ef0d20a102 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -284,6 +284,9 @@ STATIC void emit_write_bytecode_byte_raw_code(emit_t *emit, int stack_adj, byte assert(c == MP_ALIGN(c, sizeof(void*))); *c = rc; #endif + #if MICROPY_PY_SYS_SETTRACE + rc->line_of_definition = emit->last_source_line; + #endif } // unsigned labels are relative to ip following this instruction, stored as 16 bits diff --git a/py/emitglue.c b/py/emitglue.c index 483a47025b..d30a1e6741 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -34,6 +34,7 @@ #include "py/emitglue.h" #include "py/runtime0.h" #include "py/bc.h" +#include "py/profile.h" #if MICROPY_DEBUG_VERBOSE // print debugging info #define DEBUG_PRINT (1) @@ -52,6 +53,9 @@ mp_uint_t mp_verbose_flag = 0; mp_raw_code_t *mp_emit_glue_new_raw_code(void) { mp_raw_code_t *rc = m_new0(mp_raw_code_t, 1); rc->kind = MP_CODE_RESERVED; + #if MICROPY_PY_SYS_SETTRACE + rc->line_of_definition = 0; + #endif return rc; } @@ -75,6 +79,11 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, rc->n_raw_code = n_raw_code; #endif + #if MICROPY_PY_SYS_SETTRACE + mp_bytecode_prelude_t *prelude = &rc->prelude; + mp_prof_extract_prelude(code, prelude); + #endif + #ifdef DEBUG_PRINT #if !MICROPY_DEBUG_PRINTERS const size_t len = 0; @@ -172,6 +181,12 @@ mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, mp_obj_t def_ar if ((rc->scope_flags & MP_SCOPE_FLAG_GENERATOR) != 0) { ((mp_obj_base_t*)MP_OBJ_TO_PTR(fun))->type = &mp_type_gen_wrap; } + + #if MICROPY_PY_SYS_SETTRACE + mp_obj_fun_bc_t *self_fun = (mp_obj_fun_bc_t *)MP_OBJ_TO_PTR(fun); + self_fun->rc = rc; + #endif + break; } diff --git a/py/emitglue.h b/py/emitglue.h index b67d49ed6d..a5411dc2e2 100644 --- a/py/emitglue.h +++ b/py/emitglue.h @@ -27,6 +27,7 @@ #define MICROPY_INCLUDED_PY_EMITGLUE_H #include "py/obj.h" +#include "py/bc.h" // These variables and functions glue the code emitters to the runtime. @@ -63,6 +64,14 @@ typedef struct _mp_raw_code_t { size_t fun_data_len; uint16_t n_obj; uint16_t n_raw_code; + #if MICROPY_PY_SYS_SETTRACE + mp_bytecode_prelude_t prelude; + // line_of_definition is a Python source line where the raw_code was + // created e.g. MP_BC_MAKE_FUNCTION. This is different from lineno info + // stored in prelude, which provides line number for first statement of + // a function. Required to properly implement "call" trace event. + mp_uint_t line_of_definition; + #endif #if MICROPY_EMIT_MACHINE_CODE uint16_t prelude_offset; uint16_t n_qstr; diff --git a/py/modsys.c b/py/modsys.c index 3a91393812..4886419d0e 100644 --- a/py/modsys.c +++ b/py/modsys.c @@ -35,6 +35,11 @@ #include "py/smallint.h" #include "py/runtime.h" +#if MICROPY_PY_SYS_SETTRACE +#include "py/objmodule.h" +#include "py/profile.h" +#endif + #if MICROPY_PY_SYS // defined per port; type of these is irrelevant, just need pointer @@ -156,6 +161,14 @@ STATIC mp_obj_t mp_sys_atexit(mp_obj_t obj) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_sys_atexit_obj, mp_sys_atexit); #endif +#if MICROPY_PY_SYS_SETTRACE +// settrace(tracefunc): Set the system’s trace function. +STATIC mp_obj_t mp_sys_settrace(mp_obj_t obj) { + return mp_prof_settrace(obj); +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_sys_settrace_obj, mp_sys_settrace); +#endif // MICROPY_PY_SYS_SETTRACE + STATIC const mp_rom_map_elem_t mp_module_sys_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sys) }, @@ -190,6 +203,10 @@ STATIC const mp_rom_map_elem_t mp_module_sys_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_exit), MP_ROM_PTR(&mp_sys_exit_obj) }, #endif + #if MICROPY_PY_SYS_SETTRACE + { MP_ROM_QSTR(MP_QSTR_settrace), MP_ROM_PTR(&mp_sys_settrace_obj) }, + #endif + #if MICROPY_PY_SYS_STDFILES { MP_ROM_QSTR(MP_QSTR_stdin), MP_ROM_PTR(&mp_sys_stdin_obj) }, { MP_ROM_QSTR(MP_QSTR_stdout), MP_ROM_PTR(&mp_sys_stdout_obj) }, diff --git a/py/mpconfig.h b/py/mpconfig.h index 57dec3cf26..64dadde92d 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -1171,6 +1171,11 @@ typedef double mp_float_t; #define MICROPY_PY_SYS_ATEXIT (0) #endif +// Whether to provide "sys.settrace" function +#ifndef MICROPY_PY_SYS_SETTRACE +#define MICROPY_PY_SYS_SETTRACE (0) +#endif + // Whether to provide "sys.getsizeof" function #ifndef MICROPY_PY_SYS_GETSIZEOF #define MICROPY_PY_SYS_GETSIZEOF (0) @@ -1571,4 +1576,14 @@ typedef double mp_float_t; # define MP_WARN_CAT(x) (NULL) #endif +// Feature dependency check. +#if MICROPY_PY_SYS_SETTRACE +#if !MICROPY_PERSISTENT_CODE_SAVE +#error "MICROPY_PY_SYS_SETTRACE requires MICROPY_PERSISTENT_CODE_SAVE to be enabled" +#endif +#if MICROPY_COMP_CONST +#error "MICROPY_PY_SYS_SETTRACE requires MICROPY_COMP_CONST to be disabled" +#endif +#endif + #endif // MICROPY_INCLUDED_PY_MPCONFIG_H diff --git a/py/mpstate.h b/py/mpstate.h index 83fea3eb41..aba32084d5 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -253,6 +253,12 @@ typedef struct _mp_state_thread_t { mp_obj_dict_t *dict_globals; nlr_buf_t *nlr_top; + + #if MICROPY_PY_SYS_SETTRACE + mp_obj_t prof_trace_callback; + bool prof_callback_is_executing; + struct _mp_code_state_t *current_code_state; + #endif } mp_state_thread_t; // This structure combines the above 3 structures. diff --git a/py/objfun.h b/py/objfun.h index 257b8a65a7..905b5dbca6 100644 --- a/py/objfun.h +++ b/py/objfun.h @@ -33,6 +33,9 @@ typedef struct _mp_obj_fun_bc_t { mp_obj_dict_t *globals; // the context within which this function was defined const byte *bytecode; // bytecode for the function const mp_uint_t *const_table; // constant table + #if MICROPY_PY_SYS_SETTRACE + const struct _mp_raw_code_t *rc; + #endif // the following extra_args array is allocated space to take (in order): // - values of positional default args (if any) // - a single slot for default kw args dict (if it has them) diff --git a/py/py.mk b/py/py.mk index 10beb29e45..d60e694ec2 100644 --- a/py/py.mk +++ b/py/py.mk @@ -86,6 +86,7 @@ PY_CORE_O_BASENAME = $(addprefix py/,\ stackctrl.o \ argcheck.o \ warning.o \ + profile.o \ map.o \ obj.o \ objarray.o \ diff --git a/py/runtime.c b/py/runtime.c index d81321e862..ecbdff2bab 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -125,6 +125,12 @@ void mp_init(void) { MP_STATE_VM(sys_exitfunc) = mp_const_none; #endif + #if MICROPY_PY_SYS_SETTRACE + MP_STATE_THREAD(prof_trace_callback) = MP_OBJ_NULL; + MP_STATE_THREAD(prof_callback_is_executing) = false; + MP_STATE_THREAD(current_code_state) = NULL; + #endif + #if MICROPY_PY_THREAD_GIL mp_thread_mutex_init(&MP_STATE_VM(gil_mutex)); #endif diff --git a/py/vm.c b/py/vm.c index 0bc2034613..9abad8d83f 100644 --- a/py/vm.c +++ b/py/vm.c @@ -34,6 +34,7 @@ #include "py/runtime.h" #include "py/bc0.h" #include "py/bc.h" +#include "py/profile.h" #if 0 #define TRACE(ip) printf("sp=%d ", (int)(sp - &code_state->state[0] + 1)); mp_bytecode_print2(ip, 1, code_state->fun_bc->const_table); @@ -108,6 +109,55 @@ exc_sp--; /* pop back to previous exception handler */ \ CLEAR_SYS_EXC_INFO() /* just clear sys.exc_info(), not compliant, but it shouldn't be used in 1st place */ +#if MICROPY_PY_SYS_SETTRACE + +#define FRAME_SETUP() do { \ + assert(code_state != code_state->prev_state); \ + MP_STATE_THREAD(current_code_state) = code_state; \ + assert(code_state != code_state->prev_state); \ +} while(0) + +#define FRAME_ENTER() do { \ + assert(code_state != code_state->prev_state); \ + code_state->prev_state = MP_STATE_THREAD(current_code_state); \ + assert(code_state != code_state->prev_state); \ + if (!mp_prof_is_executing) { \ + mp_prof_frame_enter(code_state); \ + } \ +} while(0) + +#define FRAME_LEAVE() do { \ + assert(code_state != code_state->prev_state); \ + MP_STATE_THREAD(current_code_state) = code_state->prev_state; \ + assert(code_state != code_state->prev_state); \ +} while(0) + +#define FRAME_UPDATE() do { \ + assert(MP_STATE_THREAD(current_code_state) == code_state); \ + if (!mp_prof_is_executing) { \ + code_state->frame = MP_OBJ_TO_PTR(mp_prof_frame_update(code_state)); \ + } \ +} while(0) + +#define TRACE_TICK(current_ip, current_sp, is_exception) do { \ + assert(code_state != code_state->prev_state); \ + assert(MP_STATE_THREAD(current_code_state) == code_state); \ + if (!mp_prof_is_executing && code_state->frame && MP_STATE_THREAD(prof_trace_callback)) { \ + MP_PROF_INSTR_DEBUG_PRINT(code_state->ip); \ + } \ + if (!mp_prof_is_executing && code_state->frame && code_state->frame->callback) { \ + mp_prof_instr_tick(code_state, is_exception); \ + } \ +} while(0) + +#else // MICROPY_PY_SYS_SETTRACE +#define FRAME_SETUP() +#define FRAME_ENTER() +#define FRAME_LEAVE() +#define FRAME_UPDATE() +#define TRACE_TICK(current_ip, current_sp, is_exception) +#endif // MICROPY_PY_SYS_SETTRACE + // fastn has items in reverse order (fastn[0] is local[0], fastn[-1] is local[1], etc) // sp points to bottom of stack which grows up // returns: @@ -128,6 +178,7 @@ mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp #define DISPATCH() do { \ TRACE(ip); \ MARK_EXC_IP_GLOBAL(); \ + TRACE_TICK(ip, sp, false); \ goto *entry_table[*ip++]; \ } while (0) #define DISPATCH_WITH_PEND_EXC_CHECK() goto pending_exception_check @@ -149,6 +200,13 @@ mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp #if MICROPY_STACKLESS run_code_state: ; #endif +FRAME_ENTER(); + +#if MICROPY_STACKLESS +run_code_state_from_return: ; +#endif +FRAME_SETUP(); + // Pointers which are constant for particular invocation of mp_execute_bytecode() mp_obj_t * /*const*/ fastn; mp_exc_stack_t * /*const*/ exc_stack; @@ -198,6 +256,7 @@ dispatch_loop: #else TRACE(ip); MARK_EXC_IP_GLOBAL(); + TRACE_TICK(ip, sp, false); switch (*ip++) { #endif @@ -323,6 +382,7 @@ dispatch_loop: #if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE ENTRY(MP_BC_LOAD_ATTR): { + FRAME_UPDATE(); MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; SET_TOP(mp_load_attr(TOP(), qst)); @@ -330,6 +390,7 @@ dispatch_loop: } #else ENTRY(MP_BC_LOAD_ATTR): { + FRAME_UPDATE(); MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_obj_t top = TOP(); @@ -415,6 +476,7 @@ dispatch_loop: #if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE ENTRY(MP_BC_STORE_ATTR): { + FRAME_UPDATE(); MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_store_attr(sp[0], qst, sp[-1]); @@ -428,6 +490,7 @@ dispatch_loop: // consequence of this is that we can't use MP_MAP_LOOKUP_ADD_IF_NOT_FOUND // in the fast-path below, because that store could override a property. ENTRY(MP_BC_STORE_ATTR): { + FRAME_UPDATE(); MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_obj_t top = TOP(); @@ -738,6 +801,7 @@ unwind_jump:; } ENTRY(MP_BC_FOR_ITER): { + FRAME_UPDATE(); MARK_EXC_IP_SELECTIVE(); DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward code_state->sp = sp; @@ -753,6 +817,12 @@ unwind_jump:; ip += ulab; // jump to after for-block } else { PUSH(value); // push the next iteration value + #if MICROPY_PY_SYS_SETTRACE + // LINE event should trigger for every iteration so invalidate last trigger + if (code_state->frame) { + code_state->frame->lineno = 0; + } + #endif } DISPATCH(); } @@ -887,6 +957,7 @@ unwind_jump:; } ENTRY(MP_BC_CALL_FUNCTION): { + FRAME_UPDATE(); MARK_EXC_IP_SELECTIVE(); DECODE_UINT; // unum & 0xff == n_positional @@ -921,6 +992,7 @@ unwind_jump:; } ENTRY(MP_BC_CALL_FUNCTION_VAR_KW): { + FRAME_UPDATE(); MARK_EXC_IP_SELECTIVE(); DECODE_UINT; // unum & 0xff == n_positional @@ -966,6 +1038,7 @@ unwind_jump:; } ENTRY(MP_BC_CALL_METHOD): { + FRAME_UPDATE(); MARK_EXC_IP_SELECTIVE(); DECODE_UINT; // unum & 0xff == n_positional @@ -1004,6 +1077,7 @@ unwind_jump:; } ENTRY(MP_BC_CALL_METHOD_VAR_KW): { + FRAME_UPDATE(); MARK_EXC_IP_SELECTIVE(); DECODE_UINT; // unum & 0xff == n_positional @@ -1096,9 +1170,10 @@ unwind_return: #endif code_state = new_code_state; *code_state->sp = res; - goto run_code_state; + goto run_code_state_from_return; } #endif + FRAME_LEAVE(); return MP_VM_RETURN_NORMAL; ENTRY(MP_BC_RAISE_VARARGS): { @@ -1136,6 +1211,7 @@ yield: code_state->ip = ip; code_state->sp = sp; code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, 0); + FRAME_LEAVE(); return MP_VM_RETURN_YIELD; ENTRY(MP_BC_YIELD_FROM): { @@ -1192,6 +1268,7 @@ yield: } ENTRY(MP_BC_IMPORT_NAME): { + FRAME_UPDATE(); MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_obj_t obj = POP(); @@ -1200,6 +1277,7 @@ yield: } ENTRY(MP_BC_IMPORT_FROM): { + FRAME_UPDATE(); MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_obj_t obj = mp_import_from(TOP(), qst); @@ -1266,6 +1344,7 @@ yield: mp_obj_t obj = mp_obj_new_exception_msg(&mp_type_NotImplementedError, "opcode"); nlr_pop(); code_state->state[0] = obj; + FRAME_LEAVE(); return MP_VM_RETURN_EXCEPTION; } @@ -1356,6 +1435,13 @@ exception_handler: } } + #if MICROPY_PY_SYS_SETTRACE + // Exceptions are traced here + if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t*)nlr.ret_val)->type), MP_OBJ_FROM_PTR(&mp_type_Exception))) { + TRACE_TICK(code_state->ip, code_state->sp, true /* yes, it's an exception */); + } + #endif + #if MICROPY_STACKLESS unwind_loop: #endif @@ -1438,6 +1524,7 @@ unwind_loop: // propagate exception to higher level // Note: ip and sp don't have usable values at this point code_state->state[0] = MP_OBJ_FROM_PTR(nlr.ret_val); // put exception here because sp is invalid + FRAME_LEAVE(); return MP_VM_RETURN_EXCEPTION; } } From 498e35219e1f54243ff6d650781c525e20cad9b1 Mon Sep 17 00:00:00 2001 From: Milan Rossa Date: Wed, 14 Aug 2019 16:11:25 +0200 Subject: [PATCH 0657/1788] tests: Add tests for sys.settrace feature. --- tests/cmdline/cmd_showbc.py.exp | 3 + tests/misc/sys_settrace_features.py | 91 ++++++++ tests/misc/sys_settrace_generator.py | 62 ++++++ tests/misc/sys_settrace_generator.py.exp | 195 ++++++++++++++++++ tests/misc/sys_settrace_loop.py | 51 +++++ tests/misc/sys_settrace_loop.py.exp | 72 +++++++ .../misc/sys_settrace_subdir/trace_generic.py | 82 ++++++++ .../sys_settrace_subdir/trace_importme.py | 24 +++ tools/tinytest-codegen.py | 4 + 9 files changed, 584 insertions(+) create mode 100644 tests/misc/sys_settrace_features.py create mode 100644 tests/misc/sys_settrace_generator.py create mode 100644 tests/misc/sys_settrace_generator.py.exp create mode 100644 tests/misc/sys_settrace_loop.py create mode 100644 tests/misc/sys_settrace_loop.py.exp create mode 100644 tests/misc/sys_settrace_subdir/trace_generic.py create mode 100644 tests/misc/sys_settrace_subdir/trace_importme.py diff --git a/tests/cmdline/cmd_showbc.py.exp b/tests/cmdline/cmd_showbc.py.exp index 8d5d2ffe30..36f0404388 100644 --- a/tests/cmdline/cmd_showbc.py.exp +++ b/tests/cmdline/cmd_showbc.py.exp @@ -417,6 +417,7 @@ arg names: (N_STATE 1) (N_EXC_STACK 0) bc=-1 line=1 +######## bc=13 line=149 00 LOAD_NAME __name__ (cache=0) 04 STORE_NAME __module__ @@ -450,6 +451,7 @@ arg names: * * * (N_EXC_STACK 0) bc=-\\d\+ line=1 bc=0 line=59 +######## 00 LOAD_NULL 01 LOAD_FAST 2 02 LOAD_NULL @@ -473,6 +475,7 @@ arg names: * * * (N_EXC_STACK 0) bc=-\\d\+ line=1 bc=0 line=60 +######## 00 BUILD_LIST 0 02 LOAD_FAST 2 03 GET_ITER_STACK diff --git a/tests/misc/sys_settrace_features.py b/tests/misc/sys_settrace_features.py new file mode 100644 index 0000000000..932e430de7 --- /dev/null +++ b/tests/misc/sys_settrace_features.py @@ -0,0 +1,91 @@ +import sys + +try: + sys.settrace +except AttributeError: + print("SKIP") + raise SystemExit + +def print_stacktrace(frame, level=0): + # Ignore CPython specific helpers. + if frame.f_globals['__name__'].find('importlib') != -1: + print_stacktrace(frame.f_back, level) + return + + print("%2d: %s@%s:%s => %s:%d" % ( + level, " ", + frame.f_globals['__name__'], + frame.f_code.co_name, + # reduce full path to some pseudo-relative + 'misc' + ''.join(frame.f_code.co_filename.split('tests/misc')[-1:]), + frame.f_lineno, + )) + + if frame.f_back: + print_stacktrace(frame.f_back, level + 1) + +class _Prof: + trace_count = 0; + + def trace_tick(self, frame, event, arg): + self.trace_count += 1 + print_stacktrace(frame) + +__prof__ = _Prof() + +alice_handler_set = False +def trace_tick_handler_alice(frame, event, arg): + print("### trace_handler::Alice event:", event) + __prof__.trace_tick(frame, event, arg) + return trace_tick_handler_alice + +bob_handler_set = False +def trace_tick_handler_bob(frame, event, arg): + print("### trace_handler::Bob event:", event) + __prof__.trace_tick(frame, event, arg) + return trace_tick_handler_bob + +def trace_tick_handler(frame, event, arg): + # Ignore CPython specific helpers. + if frame.f_globals['__name__'].find('importlib') != -1: + return + + print("### trace_handler::main event:", event) + __prof__.trace_tick(frame, event, arg) + + if frame.f_code.co_name != 'factorial': + return trace_tick_handler + + global alice_handler_set + if event == 'call' and not alice_handler_set: + alice_handler_set = True + return trace_tick_handler_alice + + global bob_handler_set + if event == 'call' and not bob_handler_set: + bob_handler_set = True + return trace_tick_handler_bob + + return trace_tick_handler + +def factorial(n): + if n == 0: + return 1 + else: + return n * factorial(n - 1) + +def do_tests(): + # These commands are here to demonstrate some execution being traced. + print("Who loves the sun?") + print("Not every-", factorial(3)) + + from sys_settrace_subdir import trace_generic + trace_generic.run_tests() + return + +sys.settrace(trace_tick_handler) +do_tests() +sys.settrace(None) + +print("\n------------------ script exited ------------------") +print("Total traces executed: ", __prof__.trace_count) diff --git a/tests/misc/sys_settrace_generator.py b/tests/misc/sys_settrace_generator.py new file mode 100644 index 0000000000..e955d6b626 --- /dev/null +++ b/tests/misc/sys_settrace_generator.py @@ -0,0 +1,62 @@ +# test sys.settrace with generators + +import sys + +try: + sys.settrace +except AttributeError: + print("SKIP") + raise SystemExit + +def print_stacktrace(frame, level=0): + print("%2d: %s@%s:%s => %s:%d" % ( + level, " ", + frame.f_globals['__name__'], + frame.f_code.co_name, + # reduce full path to some pseudo-relative + 'misc' + ''.join(frame.f_code.co_filename.split('tests/misc')[-1:]), + frame.f_lineno, + )) + + if frame.f_back: + print_stacktrace(frame.f_back, level + 1) + +trace_count = 0 + +def trace_tick_handler(frame, event, arg): + global trace_count + print("### trace_handler::main event:", event) + trace_count += 1 + print_stacktrace(frame) + return trace_tick_handler + +def test_generator(): + def make_gen(): + yield 1<<0 + yield 1<<1 + yield 1<<2 + return 1<<3 + + gen = make_gen() + r = 0 + try: + + r += gen.send(None) + + while True: + + r += gen.send(None) + + except StopIteration as e: + print("test_generator", r, e) + + gen = make_gen() + r = 0 + for i in gen: + r += i + print(r) + +sys.settrace(trace_tick_handler) +test_generator() +sys.settrace(None) +print("Total traces executed: ", trace_count) diff --git a/tests/misc/sys_settrace_generator.py.exp b/tests/misc/sys_settrace_generator.py.exp new file mode 100644 index 0000000000..5329cdfe71 --- /dev/null +++ b/tests/misc/sys_settrace_generator.py.exp @@ -0,0 +1,195 @@ +### trace_handler::main event: call + 0: @__main__:test_generator => miscmisc/sys_settrace_generator.py:33 + 1: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:test_generator => miscmisc/sys_settrace_generator.py:34 + 1: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:test_generator => miscmisc/sys_settrace_generator.py:40 + 1: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:test_generator => miscmisc/sys_settrace_generator.py:41 + 1: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:test_generator => miscmisc/sys_settrace_generator.py:42 + 1: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:test_generator => miscmisc/sys_settrace_generator.py:44 + 1: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: call + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:34 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:44 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:35 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:44 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: return + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:35 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:44 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:test_generator => miscmisc/sys_settrace_generator.py:48 + 1: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: call + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:35 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:48 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:35 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:48 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:36 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:48 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: return + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:36 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:48 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: call + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:36 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:48 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:36 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:48 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:37 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:48 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: return + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:37 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:48 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: call + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:37 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:48 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:37 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:48 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:38 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:48 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: return + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:38 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:48 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: exception + 0: @__main__:test_generator => miscmisc/sys_settrace_generator.py:48 + 1: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:test_generator => miscmisc/sys_settrace_generator.py:50 + 1: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:test_generator => miscmisc/sys_settrace_generator.py:51 + 1: @__main__: => miscmisc/sys_settrace_generator.py:60 +test_generator 7 8 +### trace_handler::main event: line + 0: @__main__:test_generator => miscmisc/sys_settrace_generator.py:53 + 1: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:test_generator => miscmisc/sys_settrace_generator.py:54 + 1: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:test_generator => miscmisc/sys_settrace_generator.py:55 + 1: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: call + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:34 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:55 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:35 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:55 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: return + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:35 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:55 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:test_generator => miscmisc/sys_settrace_generator.py:55 + 1: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:test_generator => miscmisc/sys_settrace_generator.py:56 + 1: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:test_generator => miscmisc/sys_settrace_generator.py:55 + 1: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: call + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:35 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:55 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:35 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:55 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:36 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:55 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: return + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:36 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:55 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:test_generator => miscmisc/sys_settrace_generator.py:55 + 1: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:test_generator => miscmisc/sys_settrace_generator.py:56 + 1: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:test_generator => miscmisc/sys_settrace_generator.py:55 + 1: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: call + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:36 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:55 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:36 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:55 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:37 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:55 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: return + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:37 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:55 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:test_generator => miscmisc/sys_settrace_generator.py:55 + 1: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:test_generator => miscmisc/sys_settrace_generator.py:56 + 1: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:test_generator => miscmisc/sys_settrace_generator.py:55 + 1: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: call + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:37 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:55 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:37 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:55 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:38 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:55 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: return + 0: @__main__:make_gen => miscmisc/sys_settrace_generator.py:38 + 1: @__main__:test_generator => miscmisc/sys_settrace_generator.py:55 + 2: @__main__: => miscmisc/sys_settrace_generator.py:60 +### trace_handler::main event: line + 0: @__main__:test_generator => miscmisc/sys_settrace_generator.py:57 + 1: @__main__: => miscmisc/sys_settrace_generator.py:60 +7 +### trace_handler::main event: return + 0: @__main__:test_generator => miscmisc/sys_settrace_generator.py:57 + 1: @__main__: => miscmisc/sys_settrace_generator.py:60 +Total traces executed: 54 diff --git a/tests/misc/sys_settrace_loop.py b/tests/misc/sys_settrace_loop.py new file mode 100644 index 0000000000..9ae0f41a1d --- /dev/null +++ b/tests/misc/sys_settrace_loop.py @@ -0,0 +1,51 @@ +# test sys.settrace with while and for loops + +import sys + +try: + sys.settrace +except AttributeError: + print("SKIP") + raise SystemExit + +def print_stacktrace(frame, level=0): + print("%2d: %s@%s:%s => %s:%d" % ( + level, " ", + frame.f_globals['__name__'], + frame.f_code.co_name, + # reduce full path to some pseudo-relative + 'misc' + ''.join(frame.f_code.co_filename.split('tests/misc')[-1:]), + frame.f_lineno, + )) + + if frame.f_back: + print_stacktrace(frame.f_back, level + 1) + +trace_count = 0 + +def trace_tick_handler(frame, event, arg): + global trace_count + print("### trace_handler::main event:", event) + trace_count += 1 + print_stacktrace(frame) + return trace_tick_handler + +def test_loop(): + # for loop + r = 0 + for i in range(3): + r += i + print("test_for_loop", r) + + # while loop + r = 0 + i = 0 + while i < 3: + r += i + i += 1 + print("test_while_loop", i) + +sys.settrace(trace_tick_handler) +test_loop() +sys.settrace(None) +print("Total traces executed: ", trace_count) diff --git a/tests/misc/sys_settrace_loop.py.exp b/tests/misc/sys_settrace_loop.py.exp new file mode 100644 index 0000000000..3d3da5b6f7 --- /dev/null +++ b/tests/misc/sys_settrace_loop.py.exp @@ -0,0 +1,72 @@ +### trace_handler::main event: call + 0: @__main__:test_loop => miscmisc/sys_settrace_loop.py:33 + 1: @__main__: => miscmisc/sys_settrace_loop.py:49 +### trace_handler::main event: line + 0: @__main__:test_loop => miscmisc/sys_settrace_loop.py:35 + 1: @__main__: => miscmisc/sys_settrace_loop.py:49 +### trace_handler::main event: line + 0: @__main__:test_loop => miscmisc/sys_settrace_loop.py:36 + 1: @__main__: => miscmisc/sys_settrace_loop.py:49 +### trace_handler::main event: line + 0: @__main__:test_loop => miscmisc/sys_settrace_loop.py:37 + 1: @__main__: => miscmisc/sys_settrace_loop.py:49 +### trace_handler::main event: line + 0: @__main__:test_loop => miscmisc/sys_settrace_loop.py:36 + 1: @__main__: => miscmisc/sys_settrace_loop.py:49 +### trace_handler::main event: line + 0: @__main__:test_loop => miscmisc/sys_settrace_loop.py:37 + 1: @__main__: => miscmisc/sys_settrace_loop.py:49 +### trace_handler::main event: line + 0: @__main__:test_loop => miscmisc/sys_settrace_loop.py:36 + 1: @__main__: => miscmisc/sys_settrace_loop.py:49 +### trace_handler::main event: line + 0: @__main__:test_loop => miscmisc/sys_settrace_loop.py:37 + 1: @__main__: => miscmisc/sys_settrace_loop.py:49 +### trace_handler::main event: line + 0: @__main__:test_loop => miscmisc/sys_settrace_loop.py:36 + 1: @__main__: => miscmisc/sys_settrace_loop.py:49 +### trace_handler::main event: line + 0: @__main__:test_loop => miscmisc/sys_settrace_loop.py:37 + 1: @__main__: => miscmisc/sys_settrace_loop.py:49 +### trace_handler::main event: line + 0: @__main__:test_loop => miscmisc/sys_settrace_loop.py:38 + 1: @__main__: => miscmisc/sys_settrace_loop.py:49 +test_for_loop 3 +### trace_handler::main event: line + 0: @__main__:test_loop => miscmisc/sys_settrace_loop.py:41 + 1: @__main__: => miscmisc/sys_settrace_loop.py:49 +### trace_handler::main event: line + 0: @__main__:test_loop => miscmisc/sys_settrace_loop.py:42 + 1: @__main__: => miscmisc/sys_settrace_loop.py:49 +### trace_handler::main event: line + 0: @__main__:test_loop => miscmisc/sys_settrace_loop.py:43 + 1: @__main__: => miscmisc/sys_settrace_loop.py:49 +### trace_handler::main event: line + 0: @__main__:test_loop => miscmisc/sys_settrace_loop.py:45 + 1: @__main__: => miscmisc/sys_settrace_loop.py:49 +### trace_handler::main event: line + 0: @__main__:test_loop => miscmisc/sys_settrace_loop.py:44 + 1: @__main__: => miscmisc/sys_settrace_loop.py:49 +### trace_handler::main event: line + 0: @__main__:test_loop => miscmisc/sys_settrace_loop.py:45 + 1: @__main__: => miscmisc/sys_settrace_loop.py:49 +### trace_handler::main event: line + 0: @__main__:test_loop => miscmisc/sys_settrace_loop.py:44 + 1: @__main__: => miscmisc/sys_settrace_loop.py:49 +### trace_handler::main event: line + 0: @__main__:test_loop => miscmisc/sys_settrace_loop.py:45 + 1: @__main__: => miscmisc/sys_settrace_loop.py:49 +### trace_handler::main event: line + 0: @__main__:test_loop => miscmisc/sys_settrace_loop.py:44 + 1: @__main__: => miscmisc/sys_settrace_loop.py:49 +### trace_handler::main event: line + 0: @__main__:test_loop => miscmisc/sys_settrace_loop.py:45 + 1: @__main__: => miscmisc/sys_settrace_loop.py:49 +### trace_handler::main event: line + 0: @__main__:test_loop => miscmisc/sys_settrace_loop.py:46 + 1: @__main__: => miscmisc/sys_settrace_loop.py:49 +test_while_loop 3 +### trace_handler::main event: return + 0: @__main__:test_loop => miscmisc/sys_settrace_loop.py:46 + 1: @__main__: => miscmisc/sys_settrace_loop.py:49 +Total traces executed: 23 diff --git a/tests/misc/sys_settrace_subdir/trace_generic.py b/tests/misc/sys_settrace_subdir/trace_generic.py new file mode 100644 index 0000000000..3239a019c7 --- /dev/null +++ b/tests/misc/sys_settrace_subdir/trace_generic.py @@ -0,0 +1,82 @@ +print("Now comes the language constructions tests.") + +# function +def test_func(): + def test_sub_func(): + print("test_function") + + test_sub_func() + +# closure +def test_closure(msg): + + def make_closure(): + print(msg) + + return make_closure + +# exception +def test_exception(): + try: + raise Exception("test_exception") + + except Exception: + pass + + finally: + pass + +# listcomp +def test_listcomp(): + print("test_listcomp", [x for x in range(3)]) + +# lambda +def test_lambda(): + func_obj_1 = lambda a, b: a + b + print(func_obj_1(10, 20)) + +# import +def test_import(): + from sys_settrace_subdir import trace_importme + trace_importme.dummy() + trace_importme.saysomething() + +# class +class TLClass(): + def method(): + pass + pass + +def test_class(): + class TestClass: + __anynum = -9 + def method(self): + print("test_class_method") + self.__anynum += 1 + + def prprty_getter(self): + return self.__anynum + + def prprty_setter(self, what): + self.__anynum = what + + prprty = property(prprty_getter, prprty_setter) + + cls = TestClass() + cls.method() + print("test_class_property", cls.prprty) + cls.prprty = 12 + print("test_class_property", cls.prprty) + + +def run_tests(): + test_func() + test_closure_inst = test_closure("test_closure") + test_closure_inst() + test_exception() + test_listcomp() + test_lambda() + test_class() + test_import() + +print("And it's done!") diff --git a/tests/misc/sys_settrace_subdir/trace_importme.py b/tests/misc/sys_settrace_subdir/trace_importme.py new file mode 100644 index 0000000000..0ff7c6d5bb --- /dev/null +++ b/tests/misc/sys_settrace_subdir/trace_importme.py @@ -0,0 +1,24 @@ +print("Yep, I got imported.") + +try: + x = const(1) +except NameError: + print('const not defined') + +const = lambda x: x + +_CNT01 = "CONST01" +_CNT02 = const(123) +A123 = const(123) +a123 = const(123) + +def dummy(): + return False + +def saysomething(): + print("There, I said it.") + +def neverexecuted(): + print("Never got here!") + +print("Yep, got here") diff --git a/tools/tinytest-codegen.py b/tools/tinytest-codegen.py index bdace1c8b5..7580522ee6 100755 --- a/tools/tinytest-codegen.py +++ b/tools/tinytest-codegen.py @@ -83,6 +83,10 @@ exclude_tests = ( 'micropython/meminfo.py', # needs sys stdfiles 'misc/print_exception.py', + # settrace .exp files are too large + 'misc/sys_settrace_loop.py', + 'misc/sys_settrace_generator.py', + 'misc/sys_settrace_features.py', ) output = [] From b295df4b081dbe6f8aee2e54d1bea019a1b97236 Mon Sep 17 00:00:00 2001 From: Milan Rossa Date: Wed, 14 Aug 2019 16:12:54 +0200 Subject: [PATCH 0658/1788] py/profile: Add debugging for sys.settrace feature. --- py/profile.c | 543 +++++++++++++++++++++++++++++++++++++++++++++++++++ py/profile.h | 10 + 2 files changed, 553 insertions(+) diff --git a/py/profile.c b/py/profile.c index 39578f6dcd..8c4feaa11c 100644 --- a/py/profile.c +++ b/py/profile.c @@ -438,4 +438,547 @@ mp_obj_t mp_prof_instr_tick(mp_code_state_t *code_state, bool is_exception) { return top; } +/******************************************************************************/ +// DEBUG + +// This section is for debugging the settrace feature itself, and is not intended +// to be included in production/release builds. The code structure for this block +// was taken from py/showbc.c and should not be used as a reference. To enable +// this debug feature enable MICROPY_PROF_INSTR_DEBUG_PRINT_ENABLE in py/profile.h. +#if MICROPY_PROF_INSTR_DEBUG_PRINT_ENABLE + +#include "runtime0.h" + +#define DECODE_UINT { \ + unum = 0; \ + do { \ + unum = (unum << 7) + (*ip & 0x7f); \ + } while ((*ip++ & 0x80) != 0); \ +} +#define DECODE_ULABEL do { unum = (ip[0] | (ip[1] << 8)); ip += 2; } while (0) +#define DECODE_SLABEL do { unum = (ip[0] | (ip[1] << 8)) - 0x8000; ip += 2; } while (0) + +#define DECODE_QSTR \ + qst = ip[0] | ip[1] << 8; \ + ip += 2; +#define DECODE_PTR \ + DECODE_UINT; \ + ptr = (const byte*)const_table[unum] +#define DECODE_OBJ \ + DECODE_UINT; \ + obj = (mp_obj_t)const_table[unum] + +typedef struct _mp_dis_instruction_t { + mp_uint_t qstr_opname; + mp_uint_t arg; + mp_obj_t argobj; + mp_obj_t argobjex_cache; +} mp_dis_instruction_t; + +STATIC const byte *mp_prof_opcode_decode(const byte *ip, const mp_uint_t *const_table, mp_dis_instruction_t *instruction) { + mp_uint_t unum; + const byte* ptr; + mp_obj_t obj; + qstr qst; + + instruction->qstr_opname = MP_QSTR_; + instruction->arg = 0; + instruction->argobj= mp_const_none; + instruction->argobjex_cache = mp_const_none; + + switch (*ip++) { + case MP_BC_LOAD_CONST_FALSE: + instruction->qstr_opname = MP_QSTR_LOAD_CONST_FALSE; + break; + + case MP_BC_LOAD_CONST_NONE: + instruction->qstr_opname = MP_QSTR_LOAD_CONST_NONE; + break; + + case MP_BC_LOAD_CONST_TRUE: + instruction->qstr_opname = MP_QSTR_LOAD_CONST_TRUE; + break; + + case MP_BC_LOAD_CONST_SMALL_INT: { + mp_int_t num = 0; + if ((ip[0] & 0x40) != 0) { + // Number is negative + num--; + } + do { + num = (num << 7) | (*ip & 0x7f); + } while ((*ip++ & 0x80) != 0); + instruction->qstr_opname = MP_QSTR_LOAD_CONST_SMALL_INT; + instruction->arg = num; + break; + } + + case MP_BC_LOAD_CONST_STRING: + DECODE_QSTR; + instruction->qstr_opname = MP_QSTR_LOAD_CONST_STRING; + instruction->arg = qst; + instruction->argobj= MP_OBJ_NEW_QSTR(qst); + break; + + case MP_BC_LOAD_CONST_OBJ: + DECODE_OBJ; + instruction->qstr_opname = MP_QSTR_LOAD_CONST_OBJ; + instruction->arg = unum; + instruction->argobj= obj; + break; + + case MP_BC_LOAD_NULL: + instruction->qstr_opname = MP_QSTR_LOAD_NULL; + break; + + case MP_BC_LOAD_FAST_N: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_LOAD_FAST_N; + instruction->arg = unum; + break; + + case MP_BC_LOAD_DEREF: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_LOAD_DEREF; + instruction->arg = unum; + break; + + case MP_BC_LOAD_NAME: + DECODE_QSTR; + instruction->qstr_opname = MP_QSTR_LOAD_NAME; + instruction->arg = qst; + instruction->argobj= MP_OBJ_NEW_QSTR(qst); + if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) { + instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(*ip++); + } + break; + + case MP_BC_LOAD_GLOBAL: + DECODE_QSTR; + instruction->qstr_opname = MP_QSTR_LOAD_GLOBAL; + instruction->arg = qst; + instruction->argobj= MP_OBJ_NEW_QSTR(qst); + if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) { + instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(*ip++); + } + break; + + case MP_BC_LOAD_ATTR: + DECODE_QSTR; + instruction->qstr_opname = MP_QSTR_LOAD_ATTR; + instruction->arg = qst; + instruction->argobj= MP_OBJ_NEW_QSTR(qst); + if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) { + instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(*ip++); + } + break; + + case MP_BC_LOAD_METHOD: + DECODE_QSTR; + instruction->qstr_opname = MP_QSTR_LOAD_METHOD; + instruction->arg = qst; + instruction->argobj= MP_OBJ_NEW_QSTR(qst); + break; + + case MP_BC_LOAD_SUPER_METHOD: + DECODE_QSTR; + instruction->qstr_opname = MP_QSTR_LOAD_SUPER_METHOD; + instruction->arg = qst; + instruction->argobj= MP_OBJ_NEW_QSTR(qst); + break; + + case MP_BC_LOAD_BUILD_CLASS: + instruction->qstr_opname = MP_QSTR_LOAD_BUILD_CLASS; + break; + + case MP_BC_LOAD_SUBSCR: + instruction->qstr_opname = MP_QSTR_LOAD_SUBSCR; + break; + + case MP_BC_STORE_FAST_N: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_STORE_FAST_N; + instruction->arg = unum; + break; + + case MP_BC_STORE_DEREF: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_STORE_DEREF; + instruction->arg = unum; + break; + + case MP_BC_STORE_NAME: + DECODE_QSTR; + instruction->qstr_opname = MP_QSTR_STORE_NAME; + instruction->arg = qst; + instruction->argobj= MP_OBJ_NEW_QSTR(qst); + break; + + case MP_BC_STORE_GLOBAL: + DECODE_QSTR; + instruction->qstr_opname = MP_QSTR_STORE_GLOBAL; + instruction->arg = qst; + instruction->argobj= MP_OBJ_NEW_QSTR(qst); + break; + + case MP_BC_STORE_ATTR: + DECODE_QSTR; + instruction->qstr_opname = MP_QSTR_STORE_ATTR; + instruction->arg = qst; + instruction->argobj= MP_OBJ_NEW_QSTR(qst); + if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) { + instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(*ip++); + } + break; + + case MP_BC_STORE_SUBSCR: + instruction->qstr_opname = MP_QSTR_STORE_SUBSCR; + break; + + case MP_BC_DELETE_FAST: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_DELETE_FAST; + instruction->arg = unum; + break; + + case MP_BC_DELETE_DEREF: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_DELETE_DEREF; + instruction->arg = unum; + break; + + case MP_BC_DELETE_NAME: + DECODE_QSTR; + instruction->qstr_opname = MP_QSTR_DELETE_NAME; + instruction->arg = qst; + instruction->argobj= MP_OBJ_NEW_QSTR(qst); + break; + + case MP_BC_DELETE_GLOBAL: + DECODE_QSTR; + instruction->qstr_opname = MP_QSTR_DELETE_GLOBAL; + instruction->arg = qst; + instruction->argobj= MP_OBJ_NEW_QSTR(qst); + break; + + case MP_BC_DUP_TOP: + instruction->qstr_opname = MP_QSTR_DUP_TOP; + break; + + case MP_BC_DUP_TOP_TWO: + instruction->qstr_opname = MP_QSTR_DUP_TOP_TWO; + break; + + case MP_BC_POP_TOP: + instruction->qstr_opname = MP_QSTR_POP_TOP; + break; + + case MP_BC_ROT_TWO: + instruction->qstr_opname = MP_QSTR_ROT_TWO; + break; + + case MP_BC_ROT_THREE: + instruction->qstr_opname = MP_QSTR_ROT_THREE; + break; + + case MP_BC_JUMP: + DECODE_SLABEL; + instruction->qstr_opname = MP_QSTR_JUMP; + instruction->arg = unum; + break; + + case MP_BC_POP_JUMP_IF_TRUE: + DECODE_SLABEL; + instruction->qstr_opname = MP_QSTR_POP_JUMP_IF_TRUE; + instruction->arg = unum; + break; + + case MP_BC_POP_JUMP_IF_FALSE: + DECODE_SLABEL; + instruction->qstr_opname = MP_QSTR_POP_JUMP_IF_FALSE; + instruction->arg = unum; + break; + + case MP_BC_JUMP_IF_TRUE_OR_POP: + DECODE_SLABEL; + instruction->qstr_opname = MP_QSTR_JUMP_IF_TRUE_OR_POP; + instruction->arg = unum; + break; + + case MP_BC_JUMP_IF_FALSE_OR_POP: + DECODE_SLABEL; + instruction->qstr_opname = MP_QSTR_JUMP_IF_FALSE_OR_POP; + instruction->arg = unum; + break; + + case MP_BC_SETUP_WITH: + DECODE_ULABEL; // loop-like labels are always forward + instruction->qstr_opname = MP_QSTR_SETUP_WITH; + instruction->arg = unum; + break; + + case MP_BC_WITH_CLEANUP: + instruction->qstr_opname = MP_QSTR_WITH_CLEANUP; + break; + + case MP_BC_UNWIND_JUMP: + DECODE_SLABEL; + instruction->qstr_opname = MP_QSTR_UNWIND_JUMP; + instruction->arg = unum; + break; + + case MP_BC_SETUP_EXCEPT: + DECODE_ULABEL; // except labels are always forward + instruction->qstr_opname = MP_QSTR_SETUP_EXCEPT; + instruction->arg = unum; + break; + + case MP_BC_SETUP_FINALLY: + DECODE_ULABEL; // except labels are always forward + instruction->qstr_opname = MP_QSTR_SETUP_FINALLY; + instruction->arg = unum; + break; + + case MP_BC_END_FINALLY: + // if TOS is an exception, reraises the exception (3 values on TOS) + // if TOS is an integer, does something else + // if TOS is None, just pops it and continues + // else error + instruction->qstr_opname = MP_QSTR_END_FINALLY; + break; + + case MP_BC_GET_ITER: + instruction->qstr_opname = MP_QSTR_GET_ITER; + break; + + case MP_BC_GET_ITER_STACK: + instruction->qstr_opname = MP_QSTR_GET_ITER_STACK; + break; + + case MP_BC_FOR_ITER: + DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward + instruction->qstr_opname = MP_QSTR_FOR_ITER; + instruction->arg = unum; + break; + + case MP_BC_BUILD_TUPLE: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_BUILD_TUPLE; + instruction->arg = unum; + break; + + case MP_BC_BUILD_LIST: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_BUILD_LIST; + instruction->arg = unum; + break; + + case MP_BC_BUILD_MAP: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_BUILD_MAP; + instruction->arg = unum; + break; + + case MP_BC_STORE_MAP: + instruction->qstr_opname = MP_QSTR_STORE_MAP; + break; + + case MP_BC_BUILD_SET: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_BUILD_SET; + instruction->arg = unum; + break; + + #if MICROPY_PY_BUILTINS_SLICE + case MP_BC_BUILD_SLICE: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_BUILD_SLICE; + instruction->arg = unum; + break; + #endif + + case MP_BC_STORE_COMP: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_STORE_COMP; + instruction->arg = unum; + break; + + case MP_BC_UNPACK_SEQUENCE: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_UNPACK_SEQUENCE; + instruction->arg = unum; + break; + + case MP_BC_UNPACK_EX: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_UNPACK_EX; + instruction->arg = unum; + break; + + case MP_BC_MAKE_FUNCTION: + DECODE_PTR; + instruction->qstr_opname = MP_QSTR_MAKE_FUNCTION; + instruction->arg = unum; + instruction->argobj= mp_obj_new_int_from_ull((uint64_t)ptr); + break; + + case MP_BC_MAKE_FUNCTION_DEFARGS: + DECODE_PTR; + instruction->qstr_opname = MP_QSTR_MAKE_FUNCTION_DEFARGS; + instruction->arg = unum; + instruction->argobj= mp_obj_new_int_from_ull((uint64_t)ptr); + break; + + case MP_BC_MAKE_CLOSURE: { + DECODE_PTR; + mp_uint_t n_closed_over = *ip++; + instruction->qstr_opname = MP_QSTR_MAKE_CLOSURE; + instruction->arg = unum; + instruction->argobj= mp_obj_new_int_from_ull((uint64_t)ptr); + instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(n_closed_over); + break; + } + + case MP_BC_MAKE_CLOSURE_DEFARGS: { + DECODE_PTR; + mp_uint_t n_closed_over = *ip++; + instruction->qstr_opname = MP_QSTR_MAKE_CLOSURE_DEFARGS; + instruction->arg = unum; + instruction->argobj= mp_obj_new_int_from_ull((uint64_t)ptr); + instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(n_closed_over); + break; + } + + case MP_BC_CALL_FUNCTION: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_CALL_FUNCTION; + instruction->arg = unum & 0xff; + instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT((unum >> 8) & 0xff); + break; + + case MP_BC_CALL_FUNCTION_VAR_KW: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_CALL_FUNCTION_VAR_KW; + instruction->arg = unum & 0xff; + instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT((unum >> 8) & 0xff); + break; + + case MP_BC_CALL_METHOD: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_CALL_METHOD; + instruction->arg = unum & 0xff; + instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT((unum >> 8) & 0xff); + break; + + case MP_BC_CALL_METHOD_VAR_KW: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_CALL_METHOD_VAR_KW; + instruction->arg = unum & 0xff; + instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT((unum >> 8) & 0xff); + break; + + case MP_BC_RETURN_VALUE: + instruction->qstr_opname = MP_QSTR_RETURN_VALUE; + break; + + case MP_BC_RAISE_VARARGS: + unum = *ip++; + instruction->qstr_opname = MP_QSTR_RAISE_VARARGS; + instruction->arg = unum; + break; + + case MP_BC_YIELD_VALUE: + instruction->qstr_opname = MP_QSTR_YIELD_VALUE; + break; + + case MP_BC_YIELD_FROM: + instruction->qstr_opname = MP_QSTR_YIELD_FROM; + break; + + case MP_BC_IMPORT_NAME: + DECODE_QSTR; + instruction->qstr_opname = MP_QSTR_IMPORT_NAME; + instruction->arg = qst; + instruction->argobj= MP_OBJ_NEW_QSTR(qst); + break; + + case MP_BC_IMPORT_FROM: + DECODE_QSTR; + instruction->qstr_opname = MP_QSTR_IMPORT_FROM; + instruction->arg = qst; + instruction->argobj= MP_OBJ_NEW_QSTR(qst); + break; + + case MP_BC_IMPORT_STAR: + instruction->qstr_opname = MP_QSTR_IMPORT_STAR; + break; + + default: + if (ip[-1] < MP_BC_LOAD_CONST_SMALL_INT_MULTI + 64) { + instruction->qstr_opname = MP_QSTR_LOAD_CONST_SMALL_INT; + instruction->arg = (mp_int_t)ip[-1] - MP_BC_LOAD_CONST_SMALL_INT_MULTI - 16; + } else if (ip[-1] < MP_BC_LOAD_FAST_MULTI + 16) { + instruction->qstr_opname = MP_QSTR_LOAD_FAST; + instruction->arg = (mp_uint_t)ip[-1] - MP_BC_LOAD_FAST_MULTI; + } else if (ip[-1] < MP_BC_STORE_FAST_MULTI + 16) { + instruction->qstr_opname = MP_QSTR_STORE_FAST; + instruction->arg = (mp_uint_t)ip[-1] - MP_BC_STORE_FAST_MULTI; + } else if (ip[-1] < MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NUM_BYTECODE) { + instruction->qstr_opname = MP_QSTR_UNARY_OP; + instruction->arg = (mp_uint_t)ip[-1] - MP_BC_UNARY_OP_MULTI; + } else if (ip[-1] < MP_BC_BINARY_OP_MULTI + MP_BINARY_OP_NUM_BYTECODE) { + mp_uint_t op = ip[-1] - MP_BC_BINARY_OP_MULTI; + instruction->qstr_opname = MP_QSTR_BINARY_OP; + instruction->arg = op; + } else { + mp_printf(&mp_plat_print, "code %p, opcode 0x%02x not implemented\n", ip-1, ip[-1]); + assert(0); + return ip; + } + break; + } + + return ip; +} + +void mp_prof_print_instr(const byte* ip, mp_code_state_t *code_state) { + mp_dis_instruction_t _instruction, *instruction = &_instruction; + mp_prof_opcode_decode(ip, code_state->fun_bc->rc->const_table, instruction); + const mp_raw_code_t *rc = code_state->fun_bc->rc; + const mp_bytecode_prelude_t *prelude = &rc->prelude; + + mp_uint_t offset = ip - prelude->opcodes; + mp_printf(&mp_plat_print, "instr"); + + /* long path */ if (1) { + mp_printf(&mp_plat_print, + "@0x%p:%q:%q+0x%04x:%d", + ip, + prelude->qstr_source_file, + prelude->qstr_block_name, + offset, + mp_prof_bytecode_lineno(rc, offset) + ); + } + + /* bytecode */ if (0) { + mp_printf(&mp_plat_print, " %02x %02x %02x %02x", ip[0], ip[1], ip[2], ip[3]); + } + + mp_printf(&mp_plat_print, " 0x%02x %q [%d]", *ip, instruction->qstr_opname, instruction->arg); + + if (instruction->argobj != mp_const_none) { + mp_printf(&mp_plat_print, " $"); + mp_obj_print_helper(&mp_plat_print, instruction->argobj, PRINT_REPR); + } + if (instruction->argobjex_cache != mp_const_none) { + mp_printf(&mp_plat_print, " #"); + mp_obj_print_helper(&mp_plat_print, instruction->argobjex_cache, PRINT_REPR); + } + + mp_printf(&mp_plat_print, "\n"); +} + +#endif // MICROPY_PROF_INSTR_DEBUG_PRINT_ENABLE + #endif // MICROPY_PY_SYS_SETTRACE diff --git a/py/profile.h b/py/profile.h index 227634b564..0293e262f0 100644 --- a/py/profile.h +++ b/py/profile.h @@ -65,5 +65,15 @@ mp_obj_t mp_prof_frame_update(const mp_code_state_t *code_state); // For every VM instruction tick this function deduces events from the state mp_obj_t mp_prof_instr_tick(mp_code_state_t *code_state, bool is_exception); +// This section is for debugging the settrace feature itself, and is not intended +// to be included in production/release builds. +#define MICROPY_PROF_INSTR_DEBUG_PRINT_ENABLE 0 +#if MICROPY_PROF_INSTR_DEBUG_PRINT_ENABLE +void mp_prof_print_instr(const byte* ip, mp_code_state_t *code_state); +#define MP_PROF_INSTR_DEBUG_PRINT(current_ip) mp_prof_print_instr((current_ip), code_state) +#else +#define MP_PROF_INSTR_DEBUG_PRINT(current_ip) +#endif + #endif // MICROPY_PY_SYS_SETTRACE #endif // MICROPY_INCLUDED_PY_PROFILING_H From 060209240ba3a7fcf6338221417e363c10d6e147 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 20 Aug 2019 14:15:50 +1000 Subject: [PATCH 0659/1788] esp8266: Put new profile code in iROM. --- ports/esp8266/esp8266_common.ld | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/esp8266/esp8266_common.ld b/ports/esp8266/esp8266_common.ld index f4b4207f27..bbbb1325e1 100644 --- a/ports/esp8266/esp8266_common.ld +++ b/ports/esp8266/esp8266_common.ld @@ -110,6 +110,7 @@ SECTIONS *py/obj*.o*(.literal* .text*) *py/opmethods.o*(.literal* .text*) *py/parse*.o*(.literal* .text*) + *py/profile*.o*(.literal* .text*) *py/qstr.o*(.literal* .text*) *py/repl.o*(.literal* .text*) *py/runtime.o*(.literal* .text*) From 4691b43c8a245451c1f6eab2261a9433d694ef3e Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 24 Aug 2019 00:16:49 +1000 Subject: [PATCH 0660/1788] tools/mpy-tool.py: Add initial support for frozen with settrace. --- tools/mpy-tool.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index 7938ea5dc8..3d2a8fb7c6 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -410,6 +410,22 @@ class RawCode(object): print(' .fun_data_len = %u,' % len(self.bytecode)) print(' .n_obj = %u,' % len(self.objs)) print(' .n_raw_code = %u,' % len(self.raw_codes)) + print(' #if MICROPY_PY_SYS_SETTRACE') + print(' .prelude = {') + print(' .n_state = %u,' % self.prelude[0]) + print(' .n_exc_stack = %u,' % self.prelude[1]) + print(' .scope_flags = %u,' % self.prelude[2]) + print(' .n_pos_args = %u,' % self.prelude[3]) + print(' .n_kwonly_args = %u,' % self.prelude[4]) + print(' .n_def_pos_args = %u,' % self.prelude[5]) + print(' .qstr_block_name = %s,' % self.simple_name.qstr_id) + print(' .qstr_source_file = %s,' % self.source_file.qstr_id) + print(' .line_info = fun_data_%s + %u,' % (self.escaped_name, 0)) # TODO + print(' .locals = fun_data_%s + %u,' % (self.escaped_name, 0)) # TODO + print(' .opcodes = fun_data_%s + %u,' % (self.escaped_name, self.ip)) + print(' },') + print(' .line_of_definition = %u,' % 0) # TODO + print(' #endif') print(' #if MICROPY_EMIT_MACHINE_CODE') print(' .prelude_offset = %u,' % self.prelude_offset) print(' .n_qstr = %u,' % len(qstr_links)) From 0b85b5b8b3357860c426cede526f48fdd84b56fd Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 27 Aug 2019 15:43:10 +1000 Subject: [PATCH 0661/1788] travis: Add new job to test unix port with sys.settrace enabled. --- .travis.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.travis.yml b/.travis.yml index e319f095b1..72dbe138f7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -115,6 +115,17 @@ jobs: - make ${MAKEOPTS} -C ports/unix CC=clang CFLAGS_EXTRA="-DMICROPY_STACKLESS=1 -DMICROPY_STACKLESS_STRICT=1" - make ${MAKEOPTS} -C ports/unix CC=clang test + # unix with sys.settrace + - stage: test + env: NAME="unix port with sys.settrace build and tests" + script: + - make ${MAKEOPTS} -C mpy-cross + - make ${MAKEOPTS} -C ports/unix MICROPY_PY_BTREE=0 MICROPY_PY_FFI=0 MICROPY_PY_USSL=0 CFLAGS_EXTRA="-DMICROPY_PY_SYS_SETTRACE=1" test + - make ${MAKEOPTS} -C ports/unix clean + - make ${MAKEOPTS} -C ports/unix MICROPY_PY_BTREE=0 MICROPY_PY_FFI=0 MICROPY_PY_USSL=0 CFLAGS_EXTRA="-DMICROPY_STACKLESS=1 -DMICROPY_STACKLESS_STRICT=1 -DMICROPY_PY_SYS_SETTRACE=1" test + after_failure: + - (cd tests && for exp in *.exp; do testbase=$(basename $exp .exp); echo -e "\nFAILURE $testbase"; diff -u $testbase.exp $testbase.out; done) + # windows port via mingw - stage: test env: NAME="windows port build via mingw" From 12f13ee6346d8fd029fc2ecec06d50b5f7f6b252 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 13 Aug 2019 07:07:49 -0500 Subject: [PATCH 0662/1788] py/objtuple: Allow compatible subclasses of tuple in mp_obj_tuple_get. As part of this patch a private macro mp_obj_is_tuple_compatible is introduced to encapsulate the check, which is used in two locations. Fixes #5005. --- py/objtuple.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/py/objtuple.c b/py/objtuple.c index 39eb940236..740e0795b3 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -31,6 +31,9 @@ #include "py/objtuple.h" #include "py/runtime.h" +// type check is done on getiter method to allow tuple, namedtuple, attrtuple +#define mp_obj_is_tuple_compatible(o) (mp_obj_get_type(o)->getiter == mp_obj_tuple_getiter) + /******************************************************************************/ /* tuple */ @@ -101,8 +104,7 @@ STATIC mp_obj_t mp_obj_tuple_make_new(const mp_obj_type_t *type_in, size_t n_arg // Don't pass MP_BINARY_OP_NOT_EQUAL here STATIC mp_obj_t tuple_cmp_helper(mp_uint_t op, mp_obj_t self_in, mp_obj_t another_in) { - // type check is done on getiter method to allow tuple, namedtuple, attrtuple - mp_check_self(mp_obj_get_type(self_in)->getiter == mp_obj_tuple_getiter); + mp_check_self(mp_obj_is_tuple_compatible(self_in)); mp_obj_type_t *another_type = mp_obj_get_type(another_in); mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); if (another_type->getiter != mp_obj_tuple_getiter) { @@ -249,7 +251,7 @@ mp_obj_t mp_obj_new_tuple(size_t n, const mp_obj_t *items) { } void mp_obj_tuple_get(mp_obj_t self_in, size_t *len, mp_obj_t **items) { - assert(mp_obj_is_type(self_in, &mp_type_tuple)); + assert(mp_obj_is_tuple_compatible(self_in)); mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); *len = self->len; *items = &self->items[0]; From 1022f9cc35564b216a4bcd7c65e8243c810a0ca9 Mon Sep 17 00:00:00 2001 From: Tom McDermott Date: Mon, 5 Aug 2019 15:15:28 +1000 Subject: [PATCH 0663/1788] py/modstruct: Fix struct.unpack with unaligned offset of native type. With this patch alignment is done relative to the start of the buffer that is being unpacked, not the raw pointer value, as per CPython. Fixes issue #3314. --- extmod/moductypes.c | 2 +- py/binary.c | 6 +++--- py/binary.h | 2 +- py/modstruct.c | 3 ++- tests/basics/struct_endian.py | 17 +++++++++++++++++ 5 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 tests/basics/struct_endian.py diff --git a/extmod/moductypes.c b/extmod/moductypes.c index 9b46371f36..d4c7611dfe 100644 --- a/extmod/moductypes.c +++ b/extmod/moductypes.c @@ -299,7 +299,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(uctypes_struct_sizeof_obj, 1, 2, ucty static inline mp_obj_t get_unaligned(uint val_type, byte *p, int big_endian) { char struct_type = big_endian ? '>' : '<'; static const char type2char[16] = "BbHhIiQq------fd"; - return mp_binary_get_val(struct_type, type2char[val_type], &p); + return mp_binary_get_val(struct_type, type2char[val_type], p, &p); } static inline void set_unaligned(uint val_type, byte *p, int big_endian, mp_obj_t val) { diff --git a/py/binary.c b/py/binary.c index a142776c37..9810e46600 100644 --- a/py/binary.c +++ b/py/binary.c @@ -185,14 +185,14 @@ long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, con } #define is_signed(typecode) (typecode > 'Z') -mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) { +mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte *p_base, byte **ptr) { byte *p = *ptr; mp_uint_t align; size_t size = mp_binary_get_size(struct_type, val_type, &align); if (struct_type == '@') { - // Make pointer aligned - p = (byte*)MP_ALIGN(p, (size_t)align); + // Align p relative to p_base + p = p_base + (uintptr_t)MP_ALIGN(p - p_base, (size_t)align); #if MP_ENDIANNESS_LITTLE struct_type = '<'; #else diff --git a/py/binary.h b/py/binary.h index 71182042f9..092b722886 100644 --- a/py/binary.h +++ b/py/binary.h @@ -38,7 +38,7 @@ size_t mp_binary_get_size(char struct_type, char val_type, mp_uint_t *palign); mp_obj_t mp_binary_get_val_array(char typecode, void *p, mp_uint_t index); void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t val_in); void mp_binary_set_val_array_from_int(char typecode, void *p, mp_uint_t index, mp_int_t val); -mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr); +mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte *p_base, byte **ptr); void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr); long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, const byte *src); void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *dest, mp_uint_t val); diff --git a/py/modstruct.c b/py/modstruct.c index 8617a8e0d3..957e4917b6 100644 --- a/py/modstruct.c +++ b/py/modstruct.c @@ -146,6 +146,7 @@ STATIC mp_obj_t struct_unpack_from(size_t n_args, const mp_obj_t *args) { } p += offset; } + byte *p_base = p; // Check that the input buffer is big enough to unpack all the values if (p + total_sz > end_p) { @@ -164,7 +165,7 @@ STATIC mp_obj_t struct_unpack_from(size_t n_args, const mp_obj_t *args) { res->items[i++] = item; } else { while (cnt--) { - item = mp_binary_get_val(fmt_type, *fmt, &p); + item = mp_binary_get_val(fmt_type, *fmt, p_base, &p); res->items[i++] = item; } } diff --git a/tests/basics/struct_endian.py b/tests/basics/struct_endian.py new file mode 100644 index 0000000000..ae32438245 --- /dev/null +++ b/tests/basics/struct_endian.py @@ -0,0 +1,17 @@ +# test ustruct and endian specific things + +try: + import ustruct as struct +except: + try: + import struct + except ImportError: + print("SKIP") + raise SystemExit + +# unpack/unpack_from with unaligned native type +buf = b'0123456789' +print(struct.unpack('h', memoryview(buf)[1:3])) +print(struct.unpack_from('i', buf, 1)) +print(struct.unpack_from('@i', buf, 1)) +print(struct.unpack_from('@ii', buf, 1)) From 24c3e9b283da26093ca653fc6b441042fedec135 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 2 Sep 2019 12:57:51 +1000 Subject: [PATCH 0664/1788] py/modstruct: Fix struct.pack_into with unaligned offset of native type. Following the same fix for unpack. --- extmod/moductypes.c | 2 +- py/binary.c | 6 +++--- py/binary.h | 2 +- py/modstruct.c | 3 ++- tests/basics/struct_endian.py | 7 +++++++ 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/extmod/moductypes.c b/extmod/moductypes.c index d4c7611dfe..cf83f43e33 100644 --- a/extmod/moductypes.c +++ b/extmod/moductypes.c @@ -305,7 +305,7 @@ static inline mp_obj_t get_unaligned(uint val_type, byte *p, int big_endian) { static inline void set_unaligned(uint val_type, byte *p, int big_endian, mp_obj_t val) { char struct_type = big_endian ? '>' : '<'; static const char type2char[16] = "BbHhIiQq------fd"; - mp_binary_set_val(struct_type, type2char[val_type], val, &p); + mp_binary_set_val(struct_type, type2char[val_type], val, p, &p); } static inline mp_uint_t get_aligned_basic(uint val_type, void *p) { diff --git a/py/binary.c b/py/binary.c index 9810e46600..dfd25018c1 100644 --- a/py/binary.c +++ b/py/binary.c @@ -250,14 +250,14 @@ void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *dest, mp_uint_t } } -void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr) { +void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte *p_base, byte **ptr) { byte *p = *ptr; mp_uint_t align; size_t size = mp_binary_get_size(struct_type, val_type, &align); if (struct_type == '@') { - // Make pointer aligned - p = (byte*)MP_ALIGN(p, (size_t)align); + // Align p relative to p_base + p = p_base + (uintptr_t)MP_ALIGN(p - p_base, (size_t)align); if (MP_ENDIANNESS_LITTLE) { struct_type = '<'; } else { diff --git a/py/binary.h b/py/binary.h index 092b722886..ac24378d2c 100644 --- a/py/binary.h +++ b/py/binary.h @@ -39,7 +39,7 @@ mp_obj_t mp_binary_get_val_array(char typecode, void *p, mp_uint_t index); void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t val_in); void mp_binary_set_val_array_from_int(char typecode, void *p, mp_uint_t index, mp_int_t val); mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte *p_base, byte **ptr); -void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr); +void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte *p_base, byte **ptr); long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, const byte *src); void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *dest, mp_uint_t val); diff --git a/py/modstruct.c b/py/modstruct.c index 957e4917b6..3e7d90ec13 100644 --- a/py/modstruct.c +++ b/py/modstruct.c @@ -180,6 +180,7 @@ STATIC void struct_pack_into_internal(mp_obj_t fmt_in, byte *p, size_t n_args, c const char *fmt = mp_obj_str_get_str(fmt_in); char fmt_type = get_fmt_type(&fmt); + byte *p_base = p; size_t i; for (i = 0; i < n_args;) { mp_uint_t cnt = 1; @@ -204,7 +205,7 @@ STATIC void struct_pack_into_internal(mp_obj_t fmt_in, byte *p, size_t n_args, c } else { // If we run out of args then we just finish; CPython would raise struct.error while (cnt-- && i < n_args) { - mp_binary_set_val(fmt_type, *fmt, args[i++], &p); + mp_binary_set_val(fmt_type, *fmt, args[i++], p_base, &p); } } fmt++; diff --git a/tests/basics/struct_endian.py b/tests/basics/struct_endian.py index ae32438245..91f5539c15 100644 --- a/tests/basics/struct_endian.py +++ b/tests/basics/struct_endian.py @@ -15,3 +15,10 @@ print(struct.unpack('h', memoryview(buf)[1:3])) print(struct.unpack_from('i', buf, 1)) print(struct.unpack_from('@i', buf, 1)) print(struct.unpack_from('@ii', buf, 1)) + +# pack_into with unaligned native type +buf = bytearray(b'>----<<<<<<<') +struct.pack_into('i', buf, 1, 0x30313233) +print(buf) +struct.pack_into('@ii', buf, 3, 0x34353637, 0x41424344) +print(buf) From c348e791879e8615347403f541717eb9386fe4ee Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 2 Sep 2019 13:09:44 +1000 Subject: [PATCH 0665/1788] py/binary: Change mp_uint_t to size_t for index, size, align args. Reduces code size for nan-box builds, otherwise changes nothing. --- py/binary.c | 20 ++++++++++---------- py/binary.h | 12 ++++++------ py/modstruct.c | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/py/binary.c b/py/binary.c index dfd25018c1..83f28db91a 100644 --- a/py/binary.c +++ b/py/binary.c @@ -42,7 +42,7 @@ #define alignof(type) offsetof(struct { char c; type t; }, t) #endif -size_t mp_binary_get_size(char struct_type, char val_type, mp_uint_t *palign) { +size_t mp_binary_get_size(char struct_type, char val_type, size_t *palign) { size_t size = 0; int align = 1; switch (struct_type) { @@ -113,7 +113,7 @@ size_t mp_binary_get_size(char struct_type, char val_type, mp_uint_t *palign) { return size; } -mp_obj_t mp_binary_get_val_array(char typecode, void *p, mp_uint_t index) { +mp_obj_t mp_binary_get_val_array(char typecode, void *p, size_t index) { mp_int_t val = 0; switch (typecode) { case 'b': @@ -162,7 +162,7 @@ mp_obj_t mp_binary_get_val_array(char typecode, void *p, mp_uint_t index) { // The long long type is guaranteed to hold at least 64 bits, and size is at // most 8 (for q and Q), so we will always be able to parse the given data // and fit it into a long long. -long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, const byte *src) { +long long mp_binary_get_int(size_t size, bool is_signed, bool big_endian, const byte *src) { int delta; if (!big_endian) { delta = -1; @@ -187,12 +187,12 @@ long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, con #define is_signed(typecode) (typecode > 'Z') mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte *p_base, byte **ptr) { byte *p = *ptr; - mp_uint_t align; + size_t align; size_t size = mp_binary_get_size(struct_type, val_type, &align); if (struct_type == '@') { // Align p relative to p_base - p = p_base + (uintptr_t)MP_ALIGN(p - p_base, (size_t)align); + p = p_base + (uintptr_t)MP_ALIGN(p - p_base, align); #if MP_ENDIANNESS_LITTLE struct_type = '<'; #else @@ -231,7 +231,7 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte *p_base, byte * } } -void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *dest, mp_uint_t val) { +void mp_binary_set_int(size_t val_sz, bool big_endian, byte *dest, mp_uint_t val) { if (MP_ENDIANNESS_LITTLE && !big_endian) { memcpy(dest, &val, val_sz); } else if (MP_ENDIANNESS_BIG && big_endian) { @@ -252,12 +252,12 @@ void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *dest, mp_uint_t void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte *p_base, byte **ptr) { byte *p = *ptr; - mp_uint_t align; + size_t align; size_t size = mp_binary_get_size(struct_type, val_type, &align); if (struct_type == '@') { // Align p relative to p_base - p = p_base + (uintptr_t)MP_ALIGN(p - p_base, (size_t)align); + p = p_base + (uintptr_t)MP_ALIGN(p - p_base, align); if (MP_ENDIANNESS_LITTLE) { struct_type = '<'; } else { @@ -315,7 +315,7 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte *p mp_binary_set_int(MIN((size_t)size, sizeof(val)), struct_type == '>', p, val); } -void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t val_in) { +void mp_binary_set_val_array(char typecode, void *p, size_t index, mp_obj_t val_in) { switch (typecode) { #if MICROPY_PY_BUILTINS_FLOAT case 'f': @@ -342,7 +342,7 @@ void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t v } } -void mp_binary_set_val_array_from_int(char typecode, void *p, mp_uint_t index, mp_int_t val) { +void mp_binary_set_val_array_from_int(char typecode, void *p, size_t index, mp_int_t val) { switch (typecode) { case 'b': ((signed char*)p)[index] = val; diff --git a/py/binary.h b/py/binary.h index ac24378d2c..5c645bcaaa 100644 --- a/py/binary.h +++ b/py/binary.h @@ -34,13 +34,13 @@ // type-specification errors due to end-of-string. #define BYTEARRAY_TYPECODE 1 -size_t mp_binary_get_size(char struct_type, char val_type, mp_uint_t *palign); -mp_obj_t mp_binary_get_val_array(char typecode, void *p, mp_uint_t index); -void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t val_in); -void mp_binary_set_val_array_from_int(char typecode, void *p, mp_uint_t index, mp_int_t val); +size_t mp_binary_get_size(char struct_type, char val_type, size_t *palign); +mp_obj_t mp_binary_get_val_array(char typecode, void *p, size_t index); +void mp_binary_set_val_array(char typecode, void *p, size_t index, mp_obj_t val_in); +void mp_binary_set_val_array_from_int(char typecode, void *p, size_t index, mp_int_t val); mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte *p_base, byte **ptr); void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte *p_base, byte **ptr); -long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, const byte *src); -void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *dest, mp_uint_t val); +long long mp_binary_get_int(size_t size, bool is_signed, bool big_endian, const byte *src); +void mp_binary_set_int(size_t val_sz, bool big_endian, byte *dest, mp_uint_t val); #endif // MICROPY_INCLUDED_PY_BINARY_H diff --git a/py/modstruct.c b/py/modstruct.c index 3e7d90ec13..36af4260ee 100644 --- a/py/modstruct.c +++ b/py/modstruct.c @@ -97,7 +97,7 @@ STATIC size_t calc_size_items(const char *fmt, size_t *total_sz) { size += cnt; } else { total_cnt += cnt; - mp_uint_t align; + size_t align; size_t sz = mp_binary_get_size(fmt_type, *fmt, &align); while (cnt--) { // Apply alignment From b29fae0c564bae271f3659563a2a61230dab5def Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 2 Sep 2019 13:30:16 +1000 Subject: [PATCH 0666/1788] py/bc: Fix size calculation of UNWIND_JUMP opcode in mp_opcode_format. Prior to this patch mp_opcode_format would calculate the incorrect size of the MP_BC_UNWIND_JUMP opcode, missing the additional byte. But, because opcodes below 0x10 are unused and treated as bytes in the .mpy load/save and freezing code, this bug did not show any symptoms, since nested unwind jumps would rarely (if ever) reach a depth of 16 (so the extra byte of this opcode would be between 0x01 and 0x0f and be correctly loaded/saved/frozen simply as an undefined opcode). This patch fixes this bug by correctly accounting for the additional byte. . --- py/bc.c | 6 ++- tests/basics/try_except_break.py | 73 ++++++++++++++++++++++++++++ tests/basics/try_except_break.py.exp | 3 ++ tools/mpy-tool.py | 4 +- 4 files changed, 83 insertions(+), 3 deletions(-) create mode 100644 tests/basics/try_except_break.py create mode 100644 tests/basics/try_except_break.py.exp diff --git a/py/bc.c b/py/bc.c index 7d0b13bd74..5625da8cf3 100644 --- a/py/bc.c +++ b/py/bc.c @@ -292,7 +292,8 @@ continue2:; #if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE // The following table encodes the number of bytes that a specific opcode -// takes up. There are 3 special opcodes that always have an extra byte: +// takes up. There are 4 special opcodes that always have an extra byte: +// MP_BC_UNWIND_JUMP // MP_BC_MAKE_CLOSURE // MP_BC_MAKE_CLOSURE_DEFARGS // MP_BC_RAISE_VARARGS @@ -402,7 +403,8 @@ uint mp_opcode_format(const byte *ip, size_t *opcode_size, bool count_var_uint) ip += 3; } else { int extra_byte = ( - *ip == MP_BC_RAISE_VARARGS + *ip == MP_BC_UNWIND_JUMP + || *ip == MP_BC_RAISE_VARARGS || *ip == MP_BC_MAKE_CLOSURE || *ip == MP_BC_MAKE_CLOSURE_DEFARGS ); diff --git a/tests/basics/try_except_break.py b/tests/basics/try_except_break.py new file mode 100644 index 0000000000..a7683f2185 --- /dev/null +++ b/tests/basics/try_except_break.py @@ -0,0 +1,73 @@ +# test deep unwind via break from nested try-except (22 of them) +while True: + print(1) + try: + try: + try: + try: + try: + try: + try: + try: + try: + try: + try: + try: + try: + try: + try: + try: + try: + try: + try: + try: + try: + try: + print(2) + break + print(3) + except: + pass + except: + pass + except: + pass + except: + pass + except: + pass + except: + pass + except: + pass + except: + pass + except: + pass + except: + pass + except: + pass + except: + pass + except: + pass + except: + pass + except: + pass + except: + pass + except: + pass + except: + pass + except: + pass + except: + pass + except: + pass + except: + pass +print(4) diff --git a/tests/basics/try_except_break.py.exp b/tests/basics/try_except_break.py.exp new file mode 100644 index 0000000000..e8a01cd985 --- /dev/null +++ b/tests/basics/try_except_break.py.exp @@ -0,0 +1,3 @@ +1 +2 +4 diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index 3d2a8fb7c6..e5c8f09597 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -109,6 +109,7 @@ MP_OPCODE_VAR_UINT = 2 MP_OPCODE_OFFSET = 3 # extra bytes: +MP_BC_UNWIND_JUMP = 0x46 MP_BC_MAKE_CLOSURE = 0x62 MP_BC_MAKE_CLOSURE_DEFARGS = 0x63 MP_BC_RAISE_VARARGS = 0x5c @@ -215,7 +216,8 @@ def mp_opcode_format(bytecode, ip, count_var_uint, opcode_format=make_opcode_for ip += 3 else: extra_byte = ( - opcode == MP_BC_RAISE_VARARGS + opcode == MP_BC_UNWIND_JUMP + or opcode == MP_BC_RAISE_VARARGS or opcode == MP_BC_MAKE_CLOSURE or opcode == MP_BC_MAKE_CLOSURE_DEFARGS ) From 50482cdc0c50c53f43953cf101e586c34f5588ad Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 3 Sep 2019 12:27:01 +1000 Subject: [PATCH 0667/1788] esp32/Makefile: Fix subst->patsubst in ESPIDF_BOOTLOADER_SUPPORT_O. --- ports/esp32/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 06cb553f4d..cf1b24bfc8 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -290,7 +290,7 @@ $(HEADER_BUILD)/qstrdefs.generated.h: $(SDKCONFIG_H) $(BOARD_DIR)/mpconfigboard. ################################################################################ # List of object files from the ESP32 IDF components -ESPIDF_BOOTLOADER_SUPPORT_O = $(subst .c,.o,\ +ESPIDF_BOOTLOADER_SUPPORT_O = $(patsubst %.c,%.o,\ $(filter-out $(ESPCOMP)/bootloader_support/src/bootloader_init.c,\ $(wildcard $(ESPCOMP)/bootloader_support/src/*.c))) From 74fe8414499c9a156dfcf348c091b3bcef4caac3 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 3 Sep 2019 13:05:10 +1000 Subject: [PATCH 0668/1788] docs/library/pyb.DAC.rst: Correct frequency for triangle mode output. Also correct comments in related code. --- docs/library/pyb.DAC.rst | 6 +++--- ports/stm32/dac.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/library/pyb.DAC.rst b/docs/library/pyb.DAC.rst index c67603a710..9a465b9ce2 100644 --- a/docs/library/pyb.DAC.rst +++ b/docs/library/pyb.DAC.rst @@ -93,9 +93,9 @@ Methods .. method:: DAC.triangle(freq) - Generate a triangle wave. The value on the DAC output changes at - the given frequency, and the frequency of the repeating triangle wave - itself is 2048 times smaller. + Generate a triangle wave. The value on the DAC output changes at the given + frequency and ramps through the full 12-bit range (up and down). Therefore + the frequency of the repeating triangle wave itself is 8192 times smaller. .. method:: DAC.write(value) diff --git a/ports/stm32/dac.c b/ports/stm32/dac.c index f3dcccb3da..485829c59c 100644 --- a/ports/stm32/dac.c +++ b/ports/stm32/dac.c @@ -373,15 +373,15 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_dac_noise_obj, pyb_dac_noise); #if defined(TIM6) /// \method triangle(freq) /// Generate a triangle wave. The value on the DAC output changes at -/// the given frequency, and the frequence of the repeating triangle wave -/// itself is 256 (or 1024, need to check) times smaller. +/// the given frequency, and the frequency of the repeating triangle wave +/// itself is 8192 times smaller. STATIC mp_obj_t pyb_dac_triangle(mp_obj_t self_in, mp_obj_t freq) { pyb_dac_obj_t *self = MP_OBJ_TO_PTR(self_in); // set TIM6 to trigger the DAC at the given frequency TIM6_Config(mp_obj_get_int(freq)); - // Configure DAC in triangle mode with trigger via TIM6 + // Configure DAC in full-scale triangle mode with trigger via TIM6 uint32_t cr = DAC_TRIANGLEAMPLITUDE_4095 | DAC_CR_WAVE1_1 | DAC_TRIGGER_T6_TRGO; pyb_dac_reconfigure(self, cr, self->outbuf_waveform, 0); From 4beb6c21caaed38cee3278e3bbab437eccdb2169 Mon Sep 17 00:00:00 2001 From: stijn Date: Tue, 3 Sep 2019 10:08:03 +0200 Subject: [PATCH 0669/1788] windows/msvc: Treat compiler warnings as errors. This is consistent with the other ports and helps catching problems early. --- ports/windows/msvc/common.props | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/windows/msvc/common.props b/ports/windows/msvc/common.props index 26ea78e7e5..5fe1b45fef 100644 --- a/ports/windows/msvc/common.props +++ b/ports/windows/msvc/common.props @@ -18,6 +18,7 @@ false true false + true true From 8fc00928ea0ec2dd9ab88037105aaaf7dbf128c3 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 3 Sep 2019 16:08:37 +1000 Subject: [PATCH 0670/1788] stm32/dma: Fix DMA config for L0 MCUs. --- ports/stm32/dma.c | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c index 3d275684d2..734cf2e980 100644 --- a/ports/stm32/dma.c +++ b/ports/stm32/dma.c @@ -97,7 +97,7 @@ struct _dma_descr_t { static const DMA_InitTypeDef dma_init_struct_spi_i2c = { #if defined(STM32F4) || defined(STM32F7) .Channel = 0, - #elif defined(STM32H7) || defined(STM32L4) + #elif defined(STM32H7) || defined(STM32L0) || defined(STM32L4) .Request = 0, #endif .Direction = 0, @@ -120,7 +120,7 @@ static const DMA_InitTypeDef dma_init_struct_spi_i2c = { static const DMA_InitTypeDef dma_init_struct_sdio = { #if defined(STM32F4) || defined(STM32F7) .Channel = 0, - #elif defined(STM32L4) + #elif defined(STM32L0) || defined(STM32L4) .Request = 0, #endif .Direction = 0, @@ -130,7 +130,7 @@ static const DMA_InitTypeDef dma_init_struct_sdio = { .MemDataAlignment = DMA_MDATAALIGN_WORD, #if defined(STM32F4) || defined(STM32F7) .Mode = DMA_PFCTRL, - #elif defined(STM32L4) + #elif defined(STM32L0) || defined(STM32L4) .Mode = DMA_NORMAL, #endif .Priority = DMA_PRIORITY_VERY_HIGH, @@ -148,7 +148,7 @@ static const DMA_InitTypeDef dma_init_struct_sdio = { static const DMA_InitTypeDef dma_init_struct_dac = { #if defined(STM32F4) || defined(STM32F7) .Channel = 0, - #elif defined(STM32H7) || defined(STM32L4) + #elif defined(STM32H7) || defined(STM32L0) || defined(STM32L4) .Request = 0, #endif .Direction = 0, @@ -336,31 +336,31 @@ static const uint8_t dma_irqn[NSTREAM] = { // number. The duplicate streams are ok as long as they aren't used at the same time. // DMA1 streams -const dma_descr_t dma_SPI_1_RX = { DMA1_Channel2, DMA_REQUEST_1, dma_id_1, &dma_init_struct_spi_i2c }; -const dma_descr_t dma_I2C_3_TX = { DMA1_Channel2, DMA_REQUEST_3, dma_id_1, &dma_init_struct_spi_i2c }; -const dma_descr_t dma_SPI_1_TX = { DMA1_Channel3, DMA_REQUEST_1, dma_id_2, &dma_init_struct_spi_i2c }; -const dma_descr_t dma_I2C_3_RX = { DMA1_Channel3, DMA_REQUEST_3, dma_id_2, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_1_RX = { DMA1_Channel2, DMA_REQUEST_1, dma_id_1, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_3_TX = { DMA1_Channel2, DMA_REQUEST_14, dma_id_1, &dma_init_struct_spi_i2c }; #if MICROPY_HW_ENABLE_DAC -const dma_descr_t dma_DAC_1_TX = { DMA1_Channel3, DMA_REQUEST_6, dma_id_2, &dma_init_struct_dac }; +const dma_descr_t dma_DAC_1_TX = { DMA1_Channel2, DMA_REQUEST_9, dma_id_1, &dma_init_struct_dac }; #endif -const dma_descr_t dma_SPI_2_RX = { DMA1_Channel4, DMA_REQUEST_1, dma_id_3, &dma_init_struct_spi_i2c }; -const dma_descr_t dma_I2C_2_TX = { DMA1_Channel4, DMA_REQUEST_3, dma_id_3, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_1_TX = { DMA1_Channel3, DMA_REQUEST_1, dma_id_2, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_3_RX = { DMA1_Channel3, DMA_REQUEST_14, dma_id_2, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_2_RX = { DMA1_Channel4, DMA_REQUEST_2, dma_id_3, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_2_TX = { DMA1_Channel4, DMA_REQUEST_7, dma_id_3, &dma_init_struct_spi_i2c }; #if MICROPY_HW_ENABLE_DAC -const dma_descr_t dma_DAC_2_TX = { DMA1_Channel4, DMA_REQUEST_5, dma_id_3, &dma_init_struct_dac }; +const dma_descr_t dma_DAC_2_TX = { DMA1_Channel4, DMA_REQUEST_15, dma_id_3, &dma_init_struct_dac }; #endif -const dma_descr_t dma_SPI_2_TX = { DMA1_Channel5, DMA_REQUEST_1, dma_id_4, &dma_init_struct_spi_i2c }; -const dma_descr_t dma_I2C_2_RX = { DMA1_Channel5, DMA_REQUEST_3, dma_id_4, &dma_init_struct_spi_i2c }; -const dma_descr_t dma_I2C_1_TX = { DMA1_Channel6, DMA_REQUEST_3, dma_id_5, &dma_init_struct_spi_i2c }; -const dma_descr_t dma_I2C_1_RX = { DMA1_Channel7, DMA_REQUEST_3, dma_id_6, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_2_TX = { DMA1_Channel5, DMA_REQUEST_2, dma_id_4, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_2_RX = { DMA1_Channel5, DMA_REQUEST_7, dma_id_4, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_1_TX = { DMA1_Channel6, DMA_REQUEST_6, dma_id_5, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_1_RX = { DMA1_Channel7, DMA_REQUEST_6, dma_id_6, &dma_init_struct_spi_i2c }; static const uint8_t dma_irqn[NSTREAM] = { DMA1_Channel1_IRQn, DMA1_Channel2_3_IRQn, + DMA1_Channel2_3_IRQn, + DMA1_Channel4_5_6_7_IRQn, + DMA1_Channel4_5_6_7_IRQn, + DMA1_Channel4_5_6_7_IRQn, DMA1_Channel4_5_6_7_IRQn, - 0, - 0, - 0, - 0, }; #elif defined(STM32L4) @@ -724,10 +724,10 @@ void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint32_t dir dma_enable_clock(dma_id); - #if defined(STM32H7) || defined(STM32L4) - // Always reset and configure the H7 and L4 DMA peripheral + #if defined(STM32H7) || defined(STM32L0) || defined(STM32L4) + // Always reset and configure the H7 and L0/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 + // TODO: understand how L0/L4 DMA works so this is not needed HAL_DMA_DeInit(dma); HAL_DMA_Init(dma); NVIC_SetPriority(IRQn_NONNEG(dma_irqn[dma_id]), IRQ_PRI_DMA); From 06661890de479ac1846772567f341f0707b339a7 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Wed, 4 Sep 2019 10:17:32 +1000 Subject: [PATCH 0671/1788] stm32/powerctrl: Fix machine.bootloader() for L0 MCUs. --- ports/stm32/powerctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c index 68a8bfdaf3..dfd9e8262d 100644 --- a/ports/stm32/powerctrl.c +++ b/ports/stm32/powerctrl.c @@ -76,7 +76,7 @@ void powerctrl_check_enter_bootloader(void) { if ((bl_addr & 0xfff) == 0 && (RCC->RCC_SR & RCC_SR_SFTRSTF)) { // Reset by NVIC_SystemReset with bootloader data set -> branch to bootloader RCC->RCC_SR = RCC_SR_RMVF; - #if defined(STM32F0) || defined(STM32F4) || defined(STM32L4) || defined(STM32WB) + #if defined(STM32F0) || defined(STM32F4) || defined(STM32L0) || defined(STM32L4) || defined(STM32WB) __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH(); #endif uint32_t r0 = BL_STATE[0]; From 8a237237a3889036e1a612237b0e585fa0713a66 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 4 Sep 2019 15:05:03 +1000 Subject: [PATCH 0672/1788] docs: Rename machine.ADC docs to machine.ADCWiPy. To signify that this ADC documentation is specific to the WiPy, and to make way for a standardised ADC documentation. --- docs/library/index.rst | 1 + .../{machine.ADC.rst => machine.ADCWiPy.rst} | 21 ++++++++++++------- docs/wipy/quickref.rst | 2 +- 3 files changed, 16 insertions(+), 8 deletions(-) rename docs/library/{machine.ADC.rst => machine.ADCWiPy.rst} (77%) diff --git a/docs/library/index.rst b/docs/library/index.rst index b464e85fa2..4e23e6e01d 100644 --- a/docs/library/index.rst +++ b/docs/library/index.rst @@ -136,6 +136,7 @@ The following libraries and classes are specific to the WiPy. :maxdepth: 2 wipy.rst + machine.ADCWiPy.rst machine.TimerWiPy.rst diff --git a/docs/library/machine.ADC.rst b/docs/library/machine.ADCWiPy.rst similarity index 77% rename from docs/library/machine.ADC.rst rename to docs/library/machine.ADCWiPy.rst index 4c7a04d74f..4a4f0524c8 100644 --- a/docs/library/machine.ADC.rst +++ b/docs/library/machine.ADCWiPy.rst @@ -1,8 +1,15 @@ .. currentmodule:: machine -.. _machine.ADC: +.. _machine.ADCWiPy: -class ADC -- analog to digital conversion -========================================= +class ADCWiPy -- analog to digital conversion +============================================= + +.. note:: + + This class is a non-standard ADC implementation for the WiPy. + It is available simply as ``machine.ADC`` on the WiPy but is named in the + documentation below as ``machine.ADCWiPy`` to distinguish it from the + more general :ref:`machine.ADC ` class. Usage:: @@ -15,7 +22,7 @@ Usage:: Constructors ------------ -.. class:: ADC(id=0, \*, bits=12) +.. class:: ADCWiPy(id=0, \*, bits=12) Create an ADC object associated with the given pin. This allows you to then read analog values on that pin. @@ -32,7 +39,7 @@ Constructors Methods ------- -.. method:: ADC.channel(id, \*, pin) +.. method:: ADCWiPy.channel(id, \*, pin) Create an analog pin. If only channel ID is given, the correct pin will be selected. Alternatively, only the pin can be passed and the correct @@ -43,11 +50,11 @@ Methods apin = adc.channel(pin='GP3') apin = adc.channel(id=1, pin='GP3') -.. method:: ADC.init() +.. method:: ADCWiPy.init() Enable the ADC block. -.. method:: ADC.deinit() +.. method:: ADCWiPy.deinit() Disable the ADC block. diff --git a/docs/wipy/quickref.rst b/docs/wipy/quickref.rst index 7aa832fd25..6349676cf7 100644 --- a/docs/wipy/quickref.rst +++ b/docs/wipy/quickref.rst @@ -82,7 +82,7 @@ See :ref:`machine.Pin ` and :ref:`machine.Timer `. : ADC (analog to digital conversion) ---------------------------------- -See :ref:`machine.ADC `. :: +See :ref:`machine.ADCWiPy `. :: from machine import ADC From e509da22df8cd337c1cc8dd531c6150e6fdb4ee0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 4 Sep 2019 15:33:40 +1000 Subject: [PATCH 0673/1788] docs/library: Specify new machine.ADC class. This initial specification is only for the ADC constructor and read_u16() method. --- docs/library/machine.ADC.rst | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 docs/library/machine.ADC.rst diff --git a/docs/library/machine.ADC.rst b/docs/library/machine.ADC.rst new file mode 100644 index 0000000000..1404b454ae --- /dev/null +++ b/docs/library/machine.ADC.rst @@ -0,0 +1,35 @@ +.. currentmodule:: machine +.. _machine.ADC: + +class ADC -- analog to digital conversion +========================================= + +The ADC class provides an interface to analog-to-digital convertors, and +represents a single endpoint that can sample a continuous voltage and +convert it to a discretised value. + +Example usage:: + + import machine + + adc = machine.ADC(pin) # create an ADC object acting on a pin + val = adc.read_u16() # read a raw analog value in the range 0-65535 + +Constructors +------------ + +.. class:: ADC(id) + + Access the ADC associated with a source identified by *id*. This + *id* may be an integer (usually specifying a channel number), a + :ref:`Pin ` object, or other value supported by the + underlying machine. + +Methods +------- + +.. method:: ADC.read_u16() + + Take an analog reading and return an integer in the range 0-65535. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 65535. From ebacdfabb6e2ac695d6660f2a6420ab84db76d39 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 20 Jul 2019 12:37:58 +1000 Subject: [PATCH 0674/1788] stm32/machine_adc: Add machine.ADC class. --- ports/stm32/Makefile | 1 + ports/stm32/machine_adc.c | 409 ++++++++++++++++++++++++++++++++++++++ ports/stm32/modmachine.c | 4 +- ports/stm32/modmachine.h | 2 + 4 files changed, 413 insertions(+), 3 deletions(-) create mode 100644 ports/stm32/machine_adc.c diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index e868d6de1b..6c0c29572e 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -261,6 +261,7 @@ SRC_C = \ eth.c \ gccollect.c \ help.c \ + machine_adc.c \ machine_i2c.c \ machine_spi.c \ machine_uart.c \ diff --git a/ports/stm32/machine_adc.c b/ports/stm32/machine_adc.c new file mode 100644 index 0000000000..58c0133595 --- /dev/null +++ b/ports/stm32/machine_adc.c @@ -0,0 +1,409 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/mphal.h" + +#if defined(STM32F0) || defined(STM32H7) || defined(STM32L0) || defined(STM32L4) || defined(STM32WB) +#define ADC_V2 (1) +#else +#define ADC_V2 (0) +#endif + +#if defined(STM32F0) || defined(STM32L0) +#define ADC_STAB_DELAY_US (1) +#define ADC_TEMPSENSOR_DELAY_US (10) +#elif defined(STM32L4) +#define ADC_STAB_DELAY_US (10) +#elif defined(STM32WB) +#define ADC_STAB_DELAY_US (1) +#endif + +#if defined(STM32F0) +#define ADC_SAMPLETIME_DEFAULT ADC_SAMPLETIME_71CYCLES_5 +#define ADC_SAMPLETIME_DEFAULT_INT ADC_SAMPLETIME_239CYCLES_5 +#elif defined(STM32F4) || defined(STM32F7) +#define ADC_SAMPLETIME_DEFAULT ADC_SAMPLETIME_15CYCLES +#define ADC_SAMPLETIME_DEFAULT_INT ADC_SAMPLETIME_480CYCLES +#elif defined(STM32H7) +#define ADC_SAMPLETIME_DEFAULT ADC_SAMPLETIME_8CYCLES_5 +#define ADC_SAMPLETIME_DEFAULT_INT ADC_SAMPLETIME_387CYCLES_5 +#elif defined(STM32L0) +#define ADC_SAMPLETIME_DEFAULT ADC_SAMPLETIME_12CYCLES_5 +#define ADC_SAMPLETIME_DEFAULT_INT ADC_SAMPLETIME_160CYCLES_5 +#elif defined(STM32L4) || defined(STM32WB) +#define ADC_SAMPLETIME_DEFAULT ADC_SAMPLETIME_12CYCLES_5 +#define ADC_SAMPLETIME_DEFAULT_INT ADC_SAMPLETIME_247CYCLES_5 +#endif + +// Timeout for waiting for end-of-conversion +#define ADC_EOC_TIMEOUT_MS (10) + +// This is a synthesised channel representing the maximum ADC reading (useful to scale other channels) +#define ADC_CHANNEL_VREF (0xffff) + +static inline void adc_stabilisation_delay_us(uint32_t us) { + mp_hal_delay_us(us + 1); +} + +STATIC void adc_wait_eoc(ADC_TypeDef *adc, int32_t timeout_ms) { + uint32_t t0 = mp_hal_ticks_ms(); + #if ADC_V2 + while (!(adc->ISR & ADC_FLAG_EOC)) + #else + while (!(adc->SR & ADC_FLAG_EOC)) + #endif + { + if (mp_hal_ticks_ms() - t0 > timeout_ms) { + break; // timeout + } + } +} + +#if defined(STM32H7) +STATIC const uint8_t adc_cr_to_bits_table[] = {16, 14, 12, 10, 8, 8, 8, 8}; +#else +STATIC const uint8_t adc_cr_to_bits_table[] = {12, 10, 8, 6}; +#endif + +STATIC void adc_config(ADC_TypeDef *adc, uint32_t bits) { + #if defined(STM32L4) || defined(STM32WB) + __HAL_RCC_ADC_CLK_ENABLE(); + #else + if (adc == ADC1) { + #if defined(STM32H7) + __HAL_RCC_ADC12_CLK_ENABLE(); + #else + __HAL_RCC_ADC1_CLK_ENABLE(); + #endif + } + #if defined(ADC2) + if (adc == ADC2) { + #if defined(STM32H7) + __HAL_RCC_ADC12_CLK_ENABLE(); + #else + __HAL_RCC_ADC2_CLK_ENABLE(); + #endif + } + #endif + #if defined(ADC3) + if (adc == ADC3) { + __HAL_RCC_ADC3_CLK_ENABLE(); + } + #endif + #endif + + #if ADC_V2 + if (adc->CR & ADC_CR_ADEN) { + // ADC enabled, need to disable it to change configuration + if (adc->CR & ADC_CR_ADSTART) { + adc->CR |= ADC_CR_ADSTP; + while (adc->CR & ADC_CR_ADSTP) { + } + } + adc->CR |= ADC_CR_ADDIS; + while (adc->CR & ADC_CR_ADDIS) { + } + } + #endif + + // TODO check all these + #if defined(STM32F0) + adc->CFGR2 = 1 << ADC_CFGR2_CKMODE_Pos; // PCLK/2 (synchronous clock mode) + #elif defined(STM32F4) || defined(STM32F7) || defined(STM32L4) + ADC123_COMMON->CCR = 0; // ADCPR=PCLK/2 + #elif defined(STM32H7) + __HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_CLKP); + #elif defined(STM32L0) || defined(STM32WB) + ADC1_COMMON->CCR = 0; // ADCPR=PCLK/2 + #endif + + // Find resolution, defaulting to last element in table + uint32_t res; + for (res = 0; res <= MP_ARRAY_SIZE(adc_cr_to_bits_table); ++res) { + if (adc_cr_to_bits_table[res] == bits) { + break; + } + } + + #if defined(STM32F0) || defined(STM32L0) + + uint32_t cfgr1_clr = ADC_CFGR1_CONT | ADC_CFGR1_EXTEN | ADC_CFGR1_ALIGN | ADC_CFGR1_RES | ADC_CFGR1_DMAEN; + uint32_t cfgr1 = res << ADC_CFGR1_RES_Pos; + adc->CFGR1 = (adc->CFGR1 & ~cfgr1_clr) | cfgr1; + + #elif defined(STM32F4) || defined(STM32F7) + + uint32_t cr1_clr = ADC_CR1_RES; + uint32_t cr1 = res << ADC_CR1_RES_Pos; + adc->CR1 = (adc->CR1 & ~cr1_clr) | cr1; + uint32_t cr2_clr = ADC_CR2_EXTEN | ADC_CR2_ALIGN | ADC_CR2_DMA | ADC_CR2_CONT; + uint32_t cr2 = 0; + adc->CR2 = (adc->CR2 & ~cr2_clr) | cr2; + adc->SQR1 = 1 << ADC_SQR1_L_Pos; // 1 conversion in regular sequence + + #elif defined(STM32H7) || defined(STM32L4) || defined(STM32WB) + + uint32_t cfgr_clr = ADC_CFGR_CONT | ADC_CFGR_EXTEN | ADC_CFGR_RES; + #if defined(STM32H7) + cfgr_clr |= ADC_CFGR_DMNGT; + #else + cfgr_clr |= ADC_CFGR_ALIGN | ADC_CFGR_DMAEN; + #endif + uint32_t cfgr = res << ADC_CFGR_RES_Pos; + adc->CFGR = (adc->CFGR & ~cfgr_clr) | cfgr; + + #endif +} + +STATIC int adc_get_bits(ADC_TypeDef *adc) { + #if defined(STM32F0) || defined(STM32L0) + uint32_t res = (adc->CFGR1 & ADC_CFGR1_RES) >> ADC_CFGR1_RES_Pos; + #elif defined(STM32F4) || defined(STM32F7) + uint32_t res = (adc->CR1 & ADC_CR1_RES) >> ADC_CR1_RES_Pos; + #elif defined(STM32H7) || defined(STM32L4) || defined(STM32WB) + uint32_t res = (adc->CFGR & ADC_CFGR_RES) >> ADC_CFGR_RES_Pos; + #endif + return adc_cr_to_bits_table[res]; +} + +STATIC void adc_config_channel(ADC_TypeDef *adc, uint32_t channel, uint32_t sample_time) { + #if ADC_V2 + if (!(adc->CR & ADC_CR_ADEN)) { + if (adc->CR) { + // Cannot enable ADC with CR!=0 + return; + } + adc->CR |= ADC_CR_ADEN; + adc_stabilisation_delay_us(ADC_STAB_DELAY_US); + while (!(adc->ISR & ADC_ISR_ADRDY)) { + } + } + #else + if (!(adc->CR2 & ADC_CR2_ADON)) { + adc->CR2 |= ADC_CR2_ADON; + adc_stabilisation_delay_us(ADC_STAB_DELAY_US); + } + #endif + + #if defined(STM32F0) || defined(STM32L0) + + if (channel == ADC_CHANNEL_VREFINT) { + ADC1_COMMON->CCR |= ADC_CCR_VREFEN; + } else if (channel == ADC_CHANNEL_TEMPSENSOR) { + ADC1_COMMON->CCR |= ADC_CCR_TSEN; + adc_stabilisation_delay_us(ADC_TEMPSENSOR_DELAY_US); + #if defined(ADC_CHANNEL_VBAT) + } else if (channel == ADC_CHANNEL_VBAT) { + ADC1_COMMON->CCR |= ADC_CCR_VBATEN; + #endif + } + adc->SMPR = sample_time << ADC_SMPR_SMP_Pos; // select sample time + adc->CHSELR = 1 << channel; // select channel for conversion + + #elif defined(STM32F4) || defined(STM32F7) + + if (channel == ADC_CHANNEL_VREFINT || channel == ADC_CHANNEL_TEMPSENSOR) { + ADC123_COMMON->CCR = (ADC123_COMMON->CCR & ~ADC_CCR_VBATE) | ADC_CCR_TSVREFE; + if (channel == ADC_CHANNEL_TEMPSENSOR) { + adc_stabilisation_delay_us(ADC_TEMPSENSOR_DELAY_US); + } + } else if (channel == ADC_CHANNEL_VBAT) { + ADC123_COMMON->CCR |= ADC_CCR_VBATE; + } + + adc->SQR3 = (channel & 0x1f) << ADC_SQR3_SQ1_Pos; // select channel for first conversion + + __IO uint32_t *smpr; + if (channel <= 9) { + smpr = &adc->SMPR2; + } else { + smpr = &adc->SMPR1; + channel -= 10; + } + *smpr = (*smpr & ~(7 << (channel * 3))) | sample_time << (channel * 3); // select sample time + + #elif defined(STM32H7) || defined(STM32L4) || defined(STM32WB) + + #if defined(STM32H7) + ADC_Common_TypeDef *adc_common = adc == ADC3 ? ADC3_COMMON : ADC12_COMMON; + #elif defined(STM32L4) + ADC_Common_TypeDef *adc_common = ADC123_COMMON; + #elif defined(STM32WB) + ADC_Common_TypeDef *adc_common = ADC1_COMMON; + #endif + if (channel == ADC_CHANNEL_VREFINT) { + adc_common->CCR |= ADC_CCR_VREFEN; + } else if (channel == ADC_CHANNEL_TEMPSENSOR) { + adc_common->CCR |= ADC_CCR_TSEN; + adc_stabilisation_delay_us(ADC_TEMPSENSOR_DELAY_US); + } else if (channel == ADC_CHANNEL_VBAT) { + adc_common->CCR |= ADC_CCR_VBATEN; + } + adc->SQR1 = (channel & 0x1f) << ADC_SQR1_SQ1_Pos | 1 << ADC_SQR1_L_Pos; + __IO uint32_t *smpr; + if (channel <= 9) { + smpr = &adc->SMPR1; + } else { + smpr = &adc->SMPR2; + channel -= 10; + } + *smpr = (*smpr & ~(7 << (channel * 3))) | sample_time << (channel * 3); // select sample time + + #endif +} + +STATIC uint32_t adc_read_channel(ADC_TypeDef *adc) { + #if ADC_V2 + adc->CR |= ADC_CR_ADSTART; + #else + adc->CR2 |= ADC_CR2_SWSTART; + #endif + adc_wait_eoc(adc, ADC_EOC_TIMEOUT_MS); + uint32_t value = adc->DR; + return value; +} + +STATIC uint32_t adc_config_and_read_u16(ADC_TypeDef *adc, uint32_t channel, uint32_t sample_time) { + if (channel == ADC_CHANNEL_VREF) { + return 0xffff; + } + + adc_config_channel(adc, channel, sample_time); + uint32_t raw = adc_read_channel(adc); + uint32_t bits = adc_get_bits(adc); + // Scale raw reading to 16 bit value using a Taylor expansion (for 8 <= bits <= 16) + #if defined(STM32H7) + if (bits < 8) { + // For 6 and 7 bits + return raw << (16 - bits) | raw << (16 - 2 * bits) | raw >> (3 * bits - 16); + } + #endif + return raw << (16 - bits) | raw >> (2 * bits - 16); +} + +/******************************************************************************/ +// MicroPython bindings for machine.ADC + +const mp_obj_type_t machine_adc_type; + +typedef struct _machine_adc_obj_t { + mp_obj_base_t base; + ADC_TypeDef *adc; + uint32_t channel; + uint32_t sample_time; +} machine_adc_obj_t; + +STATIC void machine_adc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_adc_obj_t *self = MP_OBJ_TO_PTR(self_in); + #if defined(STM32F0) || defined(STM32L0) || defined(STM32WB) + unsigned adc_id = 1; + #else + unsigned adc_id = (self->adc - ADC1) / (ADC2 - ADC1) + 1; + #endif + mp_printf(print, "", adc_id, self->channel); +} + +// ADC(id) +STATIC mp_obj_t machine_adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + // Check number of arguments + mp_arg_check_num(n_args, n_kw, 1, 1, false); + + mp_obj_t source = all_args[0]; + + uint32_t channel; + uint32_t sample_time = ADC_SAMPLETIME_DEFAULT; + ADC_TypeDef *adc; + if (mp_obj_is_int(source)) { + adc = ADC1; + channel = mp_obj_get_int(source); + if (channel == ADC_CHANNEL_VREFINT + || channel == ADC_CHANNEL_TEMPSENSOR + #if defined(ADC_CHANNEL_VBAT) + || channel == ADC_CHANNEL_VBAT + #endif + ) { + sample_time = ADC_SAMPLETIME_DEFAULT_INT; + } + } else { + const pin_obj_t *pin = pin_find(source); + if (pin->adc_num & PIN_ADC1) { + adc = ADC1; + #if defined(ADC2) + } else if (pin->adc_num & PIN_ADC2) { + adc = ADC2; + #endif + #if defined(ADC2) + } else if (pin->adc_num & PIN_ADC3) { + adc = ADC3; + #endif + } else { + // No ADC function on given pin + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Pin(%q) does not have ADC capabilities", pin->name)); + } + channel = pin->adc_channel; + + // Configure the GPIO pin in ADC mode + mp_hal_pin_config(pin, MP_HAL_PIN_MODE_ADC, MP_HAL_PIN_PULL_NONE, 0); + } + + adc_config(adc, 12); + + machine_adc_obj_t *o = m_new_obj(machine_adc_obj_t); + o->base.type = &machine_adc_type; + o->adc = adc; + o->channel = channel; + o->sample_time = sample_time; + + return MP_OBJ_FROM_PTR(o); +} + +// read_u16() +STATIC mp_obj_t machine_adc_read_u16(mp_obj_t self_in) { + machine_adc_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT(adc_config_and_read_u16(self->adc, self->channel, self->sample_time)); +} +MP_DEFINE_CONST_FUN_OBJ_1(machine_adc_read_u16_obj, machine_adc_read_u16); + +STATIC const mp_rom_map_elem_t machine_adc_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_read_u16), MP_ROM_PTR(&machine_adc_read_u16_obj) }, + + { MP_ROM_QSTR(MP_QSTR_VREF), MP_ROM_INT(ADC_CHANNEL_VREF) }, + { MP_ROM_QSTR(MP_QSTR_CORE_VREF), MP_ROM_INT(ADC_CHANNEL_VREFINT) }, + { MP_ROM_QSTR(MP_QSTR_CORE_TEMP), MP_ROM_INT(ADC_CHANNEL_TEMPSENSOR) }, + #if defined(ADC_CHANNEL_VBAT) + { MP_ROM_QSTR(MP_QSTR_CORE_VBAT), MP_ROM_INT(ADC_CHANNEL_VBAT) }, + #endif +}; +STATIC MP_DEFINE_CONST_DICT(machine_adc_locals_dict, machine_adc_locals_dict_table); + +const mp_obj_type_t machine_adc_type = { + { &mp_type_type }, + .name = MP_QSTR_ADC, + .print = machine_adc_print, + .make_new = machine_adc_make_new, + .locals_dict = (mp_obj_dict_t*)&machine_adc_locals_dict, +}; diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index e45f81479b..eaa536a1db 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -392,9 +392,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) }, { MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&pyb_rtc_type) }, -#if 0 - { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pyb_adc_type) }, -#endif + { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&machine_adc_type) }, #if MICROPY_PY_MACHINE_I2C { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) }, #endif diff --git a/ports/stm32/modmachine.h b/ports/stm32/modmachine.h index 414e5b37c7..4b727d3cb9 100644 --- a/ports/stm32/modmachine.h +++ b/ports/stm32/modmachine.h @@ -28,6 +28,8 @@ #include "py/obj.h" +extern const mp_obj_type_t machine_adc_type; + void machine_init(void); void machine_deinit(void); From 625609a7378ab6ee92855e031335cc1a915a99c8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 20 Jul 2019 12:41:20 +1000 Subject: [PATCH 0675/1788] esp8266/machine_adc: Rename pyb_adc_* to machine_adc_*. --- ports/esp8266/machine_adc.c | 34 +++++++++++++++++----------------- ports/esp8266/modmachine.c | 2 +- ports/esp8266/modmachine.h | 2 +- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/ports/esp8266/machine_adc.c b/ports/esp8266/machine_adc.c index b422f0f9ec..13fbd53056 100644 --- a/ports/esp8266/machine_adc.c +++ b/ports/esp8266/machine_adc.c @@ -30,17 +30,17 @@ #include "py/runtime.h" #include "user_interface.h" -const mp_obj_type_t pyb_adc_type; +const mp_obj_type_t machine_adc_type; -typedef struct _pyb_adc_obj_t { +typedef struct _machine_adc_obj_t { mp_obj_base_t base; bool isvdd; -} pyb_adc_obj_t; +} machine_adc_obj_t; -STATIC pyb_adc_obj_t pyb_adc_vdd3 = {{&pyb_adc_type}, true}; -STATIC pyb_adc_obj_t pyb_adc_adc = {{&pyb_adc_type}, false}; +STATIC machine_adc_obj_t machine_adc_vdd3 = {{&machine_adc_type}, true}; +STATIC machine_adc_obj_t machine_adc_adc = {{&machine_adc_type}, false}; -STATIC mp_obj_t pyb_adc_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, +STATIC mp_obj_t machine_adc_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, 1, 1, false); @@ -48,17 +48,17 @@ STATIC mp_obj_t pyb_adc_make_new(const mp_obj_type_t *type_in, size_t n_args, si switch (chn) { case 0: - return &pyb_adc_adc; + return &machine_adc_adc; case 1: - return &pyb_adc_vdd3; + return &machine_adc_vdd3; default: nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "not a valid ADC Channel: %d", chn)); } } -STATIC mp_obj_t pyb_adc_read(mp_obj_t self_in) { - pyb_adc_obj_t *adc = self_in; +STATIC mp_obj_t machine_adc_read(mp_obj_t self_in) { + machine_adc_obj_t *adc = self_in; if (adc->isvdd) { return mp_obj_new_int(system_get_vdd33()); @@ -66,16 +66,16 @@ STATIC mp_obj_t pyb_adc_read(mp_obj_t self_in) { return mp_obj_new_int(system_adc_read()); } } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_adc_read_obj, pyb_adc_read); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_adc_read_obj, machine_adc_read); -STATIC const mp_rom_map_elem_t pyb_adc_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&pyb_adc_read_obj) } +STATIC const mp_rom_map_elem_t machine_adc_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&machine_adc_read_obj) } }; -STATIC MP_DEFINE_CONST_DICT(pyb_adc_locals_dict, pyb_adc_locals_dict_table); +STATIC MP_DEFINE_CONST_DICT(machine_adc_locals_dict, machine_adc_locals_dict_table); -const mp_obj_type_t pyb_adc_type = { +const mp_obj_type_t machine_adc_type = { { &mp_type_type }, .name = MP_QSTR_ADC, - .make_new = pyb_adc_make_new, - .locals_dict = (mp_obj_dict_t*)&pyb_adc_locals_dict, + .make_new = machine_adc_make_new, + .locals_dict = (mp_obj_dict_t*)&machine_adc_locals_dict, }; diff --git a/ports/esp8266/modmachine.c b/ports/esp8266/modmachine.c index e20e8cb757..35d4918bd3 100644 --- a/ports/esp8266/modmachine.c +++ b/ports/esp8266/modmachine.c @@ -410,7 +410,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pyb_pin_type) }, { MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) }, { 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_ADC), MP_ROM_PTR(&machine_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) }, diff --git a/ports/esp8266/modmachine.h b/ports/esp8266/modmachine.h index eae351f68d..cea382d24b 100644 --- a/ports/esp8266/modmachine.h +++ b/ports/esp8266/modmachine.h @@ -5,7 +5,7 @@ extern const mp_obj_type_t pyb_pin_type; extern const mp_obj_type_t pyb_pwm_type; -extern const mp_obj_type_t pyb_adc_type; +extern const mp_obj_type_t machine_adc_type; extern const mp_obj_type_t pyb_rtc_type; extern const mp_obj_type_t pyb_uart_type; extern const mp_obj_type_t pyb_i2c_type; From 0e72cc90291d254014edee7be66b066c73d1fc71 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 20 Jul 2019 12:42:08 +1000 Subject: [PATCH 0676/1788] esp8266/machine_adc: Add read_u16 method and refactor. --- ports/esp8266/machine_adc.c | 43 ++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/ports/esp8266/machine_adc.c b/ports/esp8266/machine_adc.c index 13fbd53056..932e5782f4 100644 --- a/ports/esp8266/machine_adc.c +++ b/ports/esp8266/machine_adc.c @@ -28,20 +28,32 @@ #include #include "py/runtime.h" +#include "py/mphal.h" #include "user_interface.h" -const mp_obj_type_t machine_adc_type; - typedef struct _machine_adc_obj_t { mp_obj_base_t base; bool isvdd; } machine_adc_obj_t; +extern const mp_obj_type_t machine_adc_type; + STATIC machine_adc_obj_t machine_adc_vdd3 = {{&machine_adc_type}, true}; STATIC machine_adc_obj_t machine_adc_adc = {{&machine_adc_type}, false}; -STATIC mp_obj_t machine_adc_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, - const mp_obj_t *args) { +STATIC uint16_t adc_read(machine_adc_obj_t *self) { + if (self->isvdd) { + return system_get_vdd33(); + } else { + return system_adc_read(); + } +} +void machine_adc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_adc_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "ADC(%u)", self->isvdd); +} + +mp_obj_t machine_adc_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, 1, 1, false); mp_int_t chn = mp_obj_get_int(args[0]); @@ -52,23 +64,27 @@ STATIC mp_obj_t machine_adc_make_new(const mp_obj_type_t *type_in, size_t n_args case 1: return &machine_adc_vdd3; default: - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - "not a valid ADC Channel: %d", chn)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "ADC(%d) doesn't exist", chn)); } } -STATIC mp_obj_t machine_adc_read(mp_obj_t self_in) { - machine_adc_obj_t *adc = self_in; +// read_u16() +STATIC mp_obj_t machine_adc_read_u16(mp_obj_t self_in) { + machine_adc_obj_t *self = MP_OBJ_TO_PTR(self_in); + uint32_t value = adc_read(self); + return MP_OBJ_NEW_SMALL_INT(value * 65535 / 1024); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_adc_read_u16_obj, machine_adc_read_u16); - if (adc->isvdd) { - return mp_obj_new_int(system_get_vdd33()); - } else { - return mp_obj_new_int(system_adc_read()); - } +// Legacy method +STATIC mp_obj_t machine_adc_read(mp_obj_t self_in) { + machine_adc_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_int(adc_read(self)); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_adc_read_obj, machine_adc_read); STATIC const mp_rom_map_elem_t machine_adc_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_read_u16), MP_ROM_PTR(&machine_adc_read_u16_obj) }, { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&machine_adc_read_obj) } }; STATIC MP_DEFINE_CONST_DICT(machine_adc_locals_dict, machine_adc_locals_dict_table); @@ -76,6 +92,7 @@ STATIC MP_DEFINE_CONST_DICT(machine_adc_locals_dict, machine_adc_locals_dict_tab const mp_obj_type_t machine_adc_type = { { &mp_type_type }, .name = MP_QSTR_ADC, + .print = machine_adc_print, .make_new = machine_adc_make_new, .locals_dict = (mp_obj_dict_t*)&machine_adc_locals_dict, }; From 983283a8cd504e2f9438a836effa9e862f19ec97 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 20 Jul 2019 12:42:35 +1000 Subject: [PATCH 0677/1788] esp32/machine_adc: Add ADC.read_u16() method. --- ports/esp32/machine_adc.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/ports/esp32/machine_adc.c b/ports/esp32/machine_adc.c index d62f362e96..63e40448b4 100644 --- a/ports/esp32/machine_adc.c +++ b/ports/esp32/machine_adc.c @@ -53,12 +53,15 @@ STATIC const madc_obj_t madc_obj[] = { {{&machine_adc_type}, GPIO_NUM_35, ADC1_CHANNEL_7}, }; +STATIC uint8_t adc_bit_width; + 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); + adc_bit_width = 12; initialized = 1; } @@ -79,6 +82,17 @@ STATIC void madc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_ mp_printf(print, "ADC(Pin(%u))", self->gpio_id); } +// read_u16() +STATIC mp_obj_t madc_read_u16(mp_obj_t self_in) { + madc_obj_t *self = MP_OBJ_TO_PTR(self_in); + uint32_t raw = adc1_get_raw(self->adc1_id); + // Scale raw reading to 16 bit value using a Taylor expansion (for 8 <= bits <= 16) + uint32_t u16 = raw << (16 - adc_bit_width) | raw >> (2 * adc_bit_width - 16); + return MP_OBJ_NEW_SMALL_INT(u16); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(madc_read_u16_obj, madc_read_u16); + +// Legacy method 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); @@ -99,13 +113,24 @@ 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"); + if (err != ESP_OK) { + mp_raise_ValueError("Parameter Error"); + } + switch (width) { + case ADC_WIDTH_9Bit: adc_bit_width = 9; break; + case ADC_WIDTH_10Bit: adc_bit_width = 10; break; + case ADC_WIDTH_11Bit: adc_bit_width = 11; break; + case ADC_WIDTH_12Bit: adc_bit_width = 12; break; + default: break; + } + return mp_const_none; } 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_u16), MP_ROM_PTR(&madc_read_u16_obj) }, + { 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) }, From 9cad134a2f861a0f8864b70ab80c9d6cc61c2932 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 25 Jul 2019 18:22:54 +1000 Subject: [PATCH 0678/1788] nrf/machine/adc: Add ADC.read_u16() method. --- ports/nrf/modules/machine/adc.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ports/nrf/modules/machine/adc.c b/ports/nrf/modules/machine/adc.c index 55b68c6b80..b543c94f39 100644 --- a/ports/nrf/modules/machine/adc.c +++ b/ports/nrf/modules/machine/adc.c @@ -169,6 +169,20 @@ int16_t machine_adc_value_read(machine_adc_obj_t * adc_obj) { return value; } +// read_u16() +STATIC mp_obj_t machine_adc_read_u16(mp_obj_t self_in) { + machine_adc_obj_t *self = self_in; + int16_t raw = machine_adc_value_read(self); + #if defined(NRF52_SERIES) + // raw is signed but the channel is in single-ended mode and this method cannot return negative values + if (raw < 0) { + raw = 0; + } + #endif + // raw is an 8-bit value + return MP_OBJ_NEW_SMALL_INT(raw << 8 | raw); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_machine_adc_read_u16_obj, machine_adc_read_u16); /// \method value() /// Read adc level. @@ -263,6 +277,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_machine_adc_battery_level_obj, machine_adc_b STATIC const mp_rom_map_elem_t machine_adc_locals_dict_table[] = { // instance methods + { MP_ROM_QSTR(MP_QSTR_read_u16), MP_ROM_PTR(&mp_machine_adc_read_u16_obj) }, { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&mp_machine_adc_value_obj) }, // class methods From b766a6971eaa377ceb7d5a308b0cd4219e313ad3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 5 Sep 2019 19:19:01 +1000 Subject: [PATCH 0679/1788] nrf: Add ADC channel mapping to alt function table. --- ports/nrf/nrf52_af.csv | 16 ++++++++-------- ports/nrf/pin_defs_nrf5.h | 3 +++ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/ports/nrf/nrf52_af.csv b/ports/nrf/nrf52_af.csv index 59686ff901..bcb05c227f 100644 --- a/ports/nrf/nrf52_af.csv +++ b/ports/nrf/nrf52_af.csv @@ -1,9 +1,9 @@ P0,P0 P1,P1 -P2,P2 -P3,P3 -P4,P4 -P5,P5 +P2,P2,ADC1_CH0 +P3,P3,ADC1_CH1 +P4,P4,ADC1_CH2 +P5,P5,ADC1_CH3 P6,P6 P7,P7 P8,P8 @@ -26,10 +26,10 @@ P24,P24 P25,P25 P26,P26 P27,P27 -P28,P28 -P29,P29 -P30,P30 -P31,P31 +P28,P28,ADC1_CH4 +P29,P29,ADC1_CH5 +P30,P30,ADC1_CH6 +P31,P31,ADC1_CH7 P32,P32 P33,P33 P34,P34 diff --git a/ports/nrf/pin_defs_nrf5.h b/ports/nrf/pin_defs_nrf5.h index 99020ded75..db05aef995 100644 --- a/ports/nrf/pin_defs_nrf5.h +++ b/ports/nrf/pin_defs_nrf5.h @@ -57,5 +57,8 @@ enum { // NRF_SPI_Type *SPIM; // NRF_SPIS_Type *SPIS; +enum { + PIN_ADC1 = (1 << 0), +}; typedef NRF_GPIO_Type pin_gpio_t; From c7fb93b844f474ff9a063c55f81f6e324a180da1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 5 Sep 2019 19:19:44 +1000 Subject: [PATCH 0680/1788] nrf/machine/adc: Allow to pass a Pin object in to ADC constructor. --- ports/nrf/modules/machine/adc.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/ports/nrf/modules/machine/adc.c b/ports/nrf/modules/machine/adc.c index b543c94f39..e4885dd097 100644 --- a/ports/nrf/modules/machine/adc.c +++ b/ports/nrf/modules/machine/adc.c @@ -91,10 +91,19 @@ void adc_init0(void) { } STATIC int adc_find(mp_obj_t id) { - // given an integer id - int adc_id = mp_obj_get_int(id); - - int adc_idx = adc_id; + int adc_idx; + if (mp_obj_is_int(id)) { + // Given an integer id + adc_idx = mp_obj_get_int(id); + } else { + // Assume it's a pin-compatible object and convert it to an ADC channel number + mp_hal_pin_obj_t pin = mp_hal_get_pin_obj(id); + if (pin->adc_num & PIN_ADC1) { + adc_idx = pin->adc_channel; + } else { + mp_raise_ValueError("invalid Pin for ADC"); + } + } if (adc_idx >= 0 && adc_idx < MP_ARRAY_SIZE(machine_adc_obj) && machine_adc_obj[adc_idx].id != (uint8_t)-1) { From 9e90e2528b94f8e964d350cba7e7d2e050c06be5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 5 Sep 2019 19:20:04 +1000 Subject: [PATCH 0681/1788] nrf/machine/adc: Fix mapping of ADC channel to pin. --- ports/nrf/modules/machine/adc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/nrf/modules/machine/adc.c b/ports/nrf/modules/machine/adc.c index e4885dd097..fc5305e524 100644 --- a/ports/nrf/modules/machine/adc.c +++ b/ports/nrf/modules/machine/adc.c @@ -146,7 +146,7 @@ STATIC mp_obj_t machine_adc_make_new(const mp_obj_type_t *type, size_t n_args, s .acq_time = NRF_SAADC_ACQTIME_3US, .mode = NRF_SAADC_MODE_SINGLE_ENDED, .burst = NRF_SAADC_BURST_DISABLED, - .pin_p = self->id, // 0 - 7 + .pin_p = 1 + self->id, // pin_p=0 is AIN0, pin_p=8 is AIN7 .pin_n = NRF_SAADC_INPUT_DISABLED }; From 353ed7705f36e1f88b02c170cb2c578d80e2c622 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Fri, 23 Aug 2019 23:31:40 +1000 Subject: [PATCH 0682/1788] nrf/boards/make-pins.py: Fix gen of board pins to use correct index. It was previously not taking into account that the list of pins was sparse, so using the wrong index. The boards/X/pins.csv was generating the wrong data for machine.Pin.board. As part of this fix rename the variables to make it more clear what the list contains (only board pins). --- ports/nrf/boards/make-pins.py | 18 +++++++++++++----- ports/nrf/modules/machine/pin.c | 10 +++++----- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/ports/nrf/boards/make-pins.py b/ports/nrf/boards/make-pins.py index 023b2161c8..1844a06783 100644 --- a/ports/nrf/boards/make-pins.py +++ b/ports/nrf/boards/make-pins.py @@ -93,6 +93,7 @@ class Pin(object): self.adc_num = 0 self.adc_channel = 0 self.board_pin = False + self.board_index = None def cpu_pin_name(self): return '{:s}{:d}'.format("P", self.pin) @@ -103,6 +104,9 @@ class Pin(object): def set_is_board_pin(self): self.board_pin = True + def set_board_index(self, index): + self.board_index = index + def parse_adc(self, adc_str): if (adc_str[:3] != 'ADC'): return @@ -233,20 +237,24 @@ class Pins(object): def print_named(self, label, named_pins): print('STATIC const mp_rom_map_elem_t pin_{:s}_pins_locals_dict_table[] = {{'.format(label)) - index = 0 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(&machine_pin_obj[{:d}]) }},'.format(named_pin.name(), index)) - index += 1 + print(' {{ MP_ROM_QSTR(MP_QSTR_{:s}), MP_ROM_PTR(&machine_board_pin_obj[{:d}]) }},'.format(named_pin.name(), pin.board_index)) print('};') print('MP_DEFINE_CONST_DICT(pin_{:s}_pins_locals_dict, pin_{:s}_pins_locals_dict_table);'.format(label, label)); def print_const_table(self): + num_board_pins = 0 + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if pin.is_board_pin(): + pin.set_board_index(num_board_pins) + num_board_pins += 1 print('') - print('const uint8_t machine_pin_num_of_pins = {:d};'.format(len(self.board_pins))) + print('const uint8_t machine_pin_num_of_board_pins = {:d};'.format(num_board_pins)) print('') - print('const pin_obj_t machine_pin_obj[{:d}] = {{'.format(len(self.board_pins))) + print('const pin_obj_t machine_board_pin_obj[{:d}] = {{'.format(num_board_pins)) for named_pin in self.cpu_pins: pin = named_pin.pin() if pin.is_board_pin(): diff --git a/ports/nrf/modules/machine/pin.c b/ports/nrf/modules/machine/pin.c index 4e5b3434f9..f3a0bf07a6 100644 --- a/ports/nrf/modules/machine/pin.c +++ b/ports/nrf/modules/machine/pin.c @@ -37,8 +37,8 @@ #include "nrf_gpio.h" #include "nrfx_gpiote.h" -extern const pin_obj_t machine_pin_obj[]; -extern const uint8_t machine_pin_num_of_pins; +extern const pin_obj_t machine_board_pin_obj[]; +extern const uint8_t machine_pin_num_of_board_pins; /// \moduleref machine /// \class Pin - control I/O pins @@ -128,9 +128,9 @@ const pin_obj_t *pin_find(mp_obj_t user_obj) { // If pin is SMALL_INT if (mp_obj_is_small_int(user_obj)) { uint8_t value = MP_OBJ_SMALL_INT_VALUE(user_obj); - for (uint8_t i = 0; i < machine_pin_num_of_pins; i++) { - if (machine_pin_obj[i].pin == value) { - return &machine_pin_obj[i]; + for (uint8_t i = 0; i < machine_pin_num_of_board_pins; i++) { + if (machine_board_pin_obj[i].pin == value) { + return &machine_board_pin_obj[i]; } } } From d36fc4682ebd8409bbcba00948da74b55bdeb3ce Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Fri, 23 Aug 2019 22:23:11 +1000 Subject: [PATCH 0683/1788] nrf/Makefile: Add support for flashing with a Black Magic Probe. Also rename "flash" target to "deploy" to match other ports (but provide "flash" as an alias for backwards compatibility). --- ports/nrf/Makefile | 43 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index cc7b4f1260..c02109a156 100644 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -101,7 +101,7 @@ LDFLAGS += -Wl,--gc-sections endif -CFLAGS += $(CFLAGS_MCU_$(MCU_SERIES)) +CFLAGS += $(CFLAGS_MCU_$(MCU_SERIES)) CFLAGS += $(INC) -Wall -Werror -g -ansi -std=c11 -nostdlib $(COPT) $(NRF_DEFINES) $(CFLAGS_MOD) CFLAGS += -fno-strict-aliasing CFLAGS += -Iboards/$(BOARD) @@ -254,7 +254,7 @@ OBJ += $(BUILD)/pins_gen.o $(BUILD)/$(FATFS_DIR)/ff.o: COPT += -Os $(filter $(PY_BUILD)/../extmod/vfs_fat_%.o, $(PY_O)): COPT += -Os -.PHONY: all flash sd binary hex +.PHONY: all flash deploy sd binary hex all: binary hex @@ -276,7 +276,7 @@ FLASHER ?= ifeq ($(FLASHER),) -flash: $(BUILD)/$(OUTPUT_FILENAME).hex +deploy: $(BUILD)/$(OUTPUT_FILENAME).hex nrfjprog --program $< --sectorerase -f $(MCU_VARIANT) nrfjprog --reset -f $(MCU_VARIANT) @@ -288,7 +288,7 @@ sd: $(BUILD)/$(OUTPUT_FILENAME).hex else ifeq ($(FLASHER), pyocd) -flash: $(BUILD)/$(OUTPUT_FILENAME).hex +deploy: $(BUILD)/$(OUTPUT_FILENAME).hex pyocd-flashtool -t $(MCU_VARIANT) $< sd: $(BUILD)/$(OUTPUT_FILENAME).hex @@ -298,14 +298,47 @@ sd: $(BUILD)/$(OUTPUT_FILENAME).hex else ifeq ($(FLASHER), idap) -flash: $(BUILD)/$(OUTPUT_FILENAME).hex +deploy: $(BUILD)/$(OUTPUT_FILENAME).hex IDAPnRFPRog $< sd: $(BUILD)/$(OUTPUT_FILENAME).hex IDAPnRFPRog $(SOFTDEV_HEX) $< +else ifeq ($(FLASHER), bmp) + +BMP_PORT ?= /dev/ttyACM0 + +deploy: $(BUILD)/$(OUTPUT_FILENAME).elf + $(Q)$(GDB) \ + -ex 'target extended-remote $(BMP_PORT)' \ + -ex 'monitor tpwr enable' \ + -ex 'monitor swdp_scan' \ + -ex 'attach 1' \ + -ex 'set mem inaccessible-by-default off' \ + -ex 'load' \ + -ex 'kill' \ + -ex 'quit' \ + $< + +sd: $(BUILD)/$(OUTPUT_FILENAME).elf + $(Q)$(GDB) \ + -ex 'target extended-remote $(BMP_PORT)' \ + -ex 'monitor tpwr enable' \ + -ex 'monitor swdp_scan' \ + -ex 'attach 1' \ + -ex 'set mem inaccessible-by-default off' \ + -ex 'monitor erase_mass' \ + -ex 'load' \ + -ex 'file $(SOFTDEV_HEX)' \ + -ex 'load' \ + -ex 'kill' \ + -ex 'quit' \ + $< + endif +flash: deploy + $(BUILD)/$(OUTPUT_FILENAME).elf: $(OBJ) $(ECHO) "LINK $@" $(Q)$(CC) $(LDFLAGS) -o $@ $(OBJ) $(LIBS) From 1f52a6f8e4f0438c09081b930178df0b585f9eb1 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Fri, 23 Aug 2019 23:30:58 +1000 Subject: [PATCH 0684/1788] nrf/boards: Add Particle Xenon board configuration (an nRF52840). --- ports/nrf/README.md | 14 +++- .../nrf/boards/particle_xenon/mpconfigboard.h | 70 +++++++++++++++++++ .../boards/particle_xenon/mpconfigboard.mk | 7 ++ ports/nrf/boards/particle_xenon/pins.csv | 38 ++++++++++ 4 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 ports/nrf/boards/particle_xenon/mpconfigboard.h create mode 100644 ports/nrf/boards/particle_xenon/mpconfigboard.mk create mode 100644 ports/nrf/boards/particle_xenon/pins.csv diff --git a/ports/nrf/README.md b/ports/nrf/README.md index 2a1667a3eb..df5904eb61 100644 --- a/ports/nrf/README.md +++ b/ports/nrf/README.md @@ -30,7 +30,7 @@ This is a port of MicroPython to the Nordic Semiconductor nRF series of chips. * PCA10031 (dongle) * [WT51822-S4AT](http://www.wireless-tag.com/wireless_module/BLE/WT51822-S4AT.html) * nRF52832 - * [PCA10040](http://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.nrf52%2Fdita%2Fnrf52%2Fdevelopment%2Fnrf52_dev_kit.html) + * [PCA10040](http://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.nrf52%2Fdita%2Fnrf52%2Fdevelopment%2Fnrf52_dev_kit.html) * [Adafruit Feather nRF52](https://www.adafruit.com/product/3406) * [Thingy:52](http://www.nordicsemi.com/eng/Products/Nordic-Thingy-52) * [Arduino Primo](http://www.arduino.org/products/boards/arduino-primo) @@ -38,6 +38,7 @@ This is a port of MicroPython to the Nordic Semiconductor nRF series of chips. * [BLUEIO-TAG-EVIM BLYST Nano Sensor board](https://www.crowdsupply.com/i-syst/blyst-nano) * nRF52840 * [PCA10056](http://www.nordicsemi.com/eng/Products/nRF52840-Preview-DK) + * [Particle Xenon](https://docs.particle.io/xenon/) ## Compile and Flash @@ -71,7 +72,7 @@ the compilation: GNU ARM Embedded Toolchain 7.2.1/4Q17. It's recommended to use a toolchain after this release, for example 7.3.1/2Q18 or 8.2.1/4Q18. The alternative would be to build the target using the LTO=0 as described above. - + ## Compile and Flash with Bluetooth Stack First prepare the bluetooth folder by downloading Bluetooth LE stacks and headers: @@ -126,6 +127,7 @@ ibk_blyst_nano | s132 | Peripheral and Central | [IDAP] idk_blyst_nano | s132 | Peripheral and Central | [IDAP](#idap-midap-link-targets) blueio_tag_evim | s132 | Peripheral and Central | [IDAP](#idap-midap-link-targets) pca10056 | s140 | Peripheral and Central | [Segger](#segger-targets) +particle_xenon | s140 | Peripheral and Central | [Black Magic Probe](#black-magic-probe-targets) ## IDAP-M/IDAP-Link Targets @@ -153,6 +155,14 @@ Install the necessary tools to flash and debug using OpenOCD: sudo apt-get install openocd sudo pip install pyOCD +## Black Magic Probe Targets + +This requires no further dependencies other than `arm-none-eabi-gdb`. + +`make deploy` will use gdb to load and run new firmware. See +[this guide](https://github.com/blacksphere/blackmagic/wiki/Useful-GDB-commands) +for more tips about using the BMP with GDB. + ## Bluetooth LE REPL The port also implements a BLE REPL driver. This feature is disabled by default, as it will deactivate the UART REPL when activated. As some of the nRF devices only have one UART, using the BLE REPL free's the UART instance such that it can be used as a general UART peripheral not bound to REPL. diff --git a/ports/nrf/boards/particle_xenon/mpconfigboard.h b/ports/nrf/boards/particle_xenon/mpconfigboard.h new file mode 100644 index 0000000000..c2aabce48d --- /dev/null +++ b/ports/nrf/boards/particle_xenon/mpconfigboard.h @@ -0,0 +1,70 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Jim Mussared + * + * 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. + */ + +#define MICROPY_HW_BOARD_NAME "XENON" +#define MICROPY_HW_MCU_NAME "NRF52840" +#define MICROPY_PY_SYS_PLATFORM "PARTICLE-XENON" + +#define MICROPY_PY_MACHINE_UART (1) +#define MICROPY_PY_MACHINE_HW_PWM (1) +#define MICROPY_PY_MACHINE_HW_SPI (1) +#define MICROPY_PY_MACHINE_TIMER (1) +#define MICROPY_PY_MACHINE_RTCOUNTER (1) +#define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_ADC (1) +#define MICROPY_PY_MACHINE_TEMP (1) +#define MICROPY_PY_RANDOM_HW_RNG (1) + +#define MICROPY_HW_HAS_LED (1) +#define MICROPY_HW_LED_TRICOLOR (1) +#define MICROPY_HW_LED_PULLUP (1) + +#define MICROPY_HW_LED_RED (13) // LED1 +#define MICROPY_HW_LED_GREEN (14) // LED2 +#define MICROPY_HW_LED_BLUE (15) // LED3 + +// UART config +#define MICROPY_HW_UART1_RX (8) +#define MICROPY_HW_UART1_TX (6) +#define MICROPY_HW_UART1_CTS (32+2) +#define MICROPY_HW_UART1_RTS (32+1) +#define MICROPY_HW_UART1_HWFC (0) + +// SPI0 config +#define MICROPY_HW_SPI0_NAME "SPI0" + +#define MICROPY_HW_SPI0_SCK (32+15) +#define MICROPY_HW_SPI0_MOSI (32+13) +#define MICROPY_HW_SPI0_MISO (32+14) + +#define MICROPY_HW_PWM0_NAME "PWM0" +#define MICROPY_HW_PWM1_NAME "PWM1" +#define MICROPY_HW_PWM2_NAME "PWM2" +#if 0 +#define MICROPY_HW_PWM3_NAME "PWM3" +#endif + +#define HELP_TEXT_BOARD_LED "1,2,3" diff --git a/ports/nrf/boards/particle_xenon/mpconfigboard.mk b/ports/nrf/boards/particle_xenon/mpconfigboard.mk new file mode 100644 index 0000000000..ca555d3932 --- /dev/null +++ b/ports/nrf/boards/particle_xenon/mpconfigboard.mk @@ -0,0 +1,7 @@ +MCU_SERIES = m4 +MCU_VARIANT = nrf52 +MCU_SUB_VARIANT = nrf52840 +SOFTDEV_VERSION = 6.1.1 +LD_FILES += boards/nrf52840_1M_256k.ld + +NRF_DEFINES += -DNRF52840_XXAA diff --git a/ports/nrf/boards/particle_xenon/pins.csv b/ports/nrf/boards/particle_xenon/pins.csv new file mode 100644 index 0000000000..30f05c5564 --- /dev/null +++ b/ports/nrf/boards/particle_xenon/pins.csv @@ -0,0 +1,38 @@ +LED1,P13 +LED2,P14 +LED3,P15 +A0,P3,ADC0_IN1 +A1,P4,ADC0_IN2 +A2,P28,ADC0_IN4 +A3,P29,ADC0_IN5 +A4,P30,ADC0_IN6 +A5,P31,ADC0_IN7 +SPI_SS,P31 +SPI_SCK,P47 +SPI_MOSI,P45 +SPI_MISO,P46 +SPI1_SCK,P33 +SPI1_MOSI,P34 +SPI1_MISO,P40 +UART1_RX,P8 +UART1_TX,P6 +UART2_RX,P42 +UART2_TX,P40 +SDA,P26 +SCL,P27 +SDA1,P33 +SCL1,P34 +D0,P26 +D1,P27 +D2,P33 +D3,P34 +D4,P40 +D5,P42 +D6,P43 +D7,P44 +D8,P35 +D9,P6 +D10,P8 +D11,P46 +D12,P45 +D13,P47 From fb73bdae6256451838ef48565030f181077584fe Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 5 Sep 2019 22:59:06 +1000 Subject: [PATCH 0685/1788] py/mkenv.mk: Add GDB variable. --- py/mkenv.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/py/mkenv.mk b/py/mkenv.mk index 46eedf988a..0a59c2ac74 100644 --- a/py/mkenv.mk +++ b/py/mkenv.mk @@ -49,6 +49,7 @@ PYTHON = python3 AS = $(CROSS_COMPILE)as CC = $(CROSS_COMPILE)gcc CXX = $(CROSS_COMPILE)g++ +GDB = $(CROSS_COMPILE)gdb LD = $(CROSS_COMPILE)ld OBJCOPY = $(CROSS_COMPILE)objcopy SIZE = $(CROSS_COMPILE)size From 62fe013a5f0d0719cfebd503c818dee2438778cc Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 6 Sep 2019 17:55:12 +1000 Subject: [PATCH 0686/1788] stm32/machine_adc: Improve operation of ADC for H7, L4 and WB MCUs. --- ports/stm32/machine_adc.c | 64 ++++++++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 15 deletions(-) diff --git a/ports/stm32/machine_adc.c b/ports/stm32/machine_adc.c index 58c0133595..416beeca4c 100644 --- a/ports/stm32/machine_adc.c +++ b/ports/stm32/machine_adc.c @@ -72,9 +72,9 @@ static inline void adc_stabilisation_delay_us(uint32_t us) { STATIC void adc_wait_eoc(ADC_TypeDef *adc, int32_t timeout_ms) { uint32_t t0 = mp_hal_ticks_ms(); #if ADC_V2 - while (!(adc->ISR & ADC_FLAG_EOC)) + while (!(adc->ISR & ADC_ISR_EOC)) #else - while (!(adc->SR & ADC_FLAG_EOC)) + while (!(adc->SR & ADC_SR_EOC)) #endif { if (mp_hal_ticks_ms() - t0 > timeout_ms) { @@ -90,7 +90,9 @@ STATIC const uint8_t adc_cr_to_bits_table[] = {12, 10, 8, 6}; #endif STATIC void adc_config(ADC_TypeDef *adc, uint32_t bits) { + // Configure ADC clock source and enable ADC clock #if defined(STM32L4) || defined(STM32WB) + __HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_SYSCLK); __HAL_RCC_ADC_CLK_ENABLE(); #else if (adc == ADC1) { @@ -116,7 +118,43 @@ STATIC void adc_config(ADC_TypeDef *adc, uint32_t bits) { #endif #endif + // Configure clock mode + #if defined(STM32F0) + adc->CFGR2 = 1 << ADC_CFGR2_CKMODE_Pos; // PCLK/2 (synchronous clock mode) + #elif defined(STM32F4) || defined(STM32F7) || defined(STM32L4) + ADC123_COMMON->CCR = 0; // ADCPR=PCLK/2 + #elif defined(STM32H7) + ADC12_COMMON->CCR = 3 << ADC_CCR_CKMODE_Pos; + ADC3_COMMON->CCR = 3 << ADC_CCR_CKMODE_Pos; + #elif defined(STM32L0) || defined(STM32WB) + ADC1_COMMON->CCR = 0; // ADCPR=PCLK/2 + #endif + + #if defined(STM32H7) || defined(STM32L4) || defined(STM32WB) + if (adc->CR & ADC_CR_DEEPPWD) { + adc->CR = 0; // disable deep powerdown + } + #endif + + #if defined(STM32H7) || defined(STM32L0) || defined(STM32L4) || defined(STM32WB) + if (!(adc->CR & ADC_CR_ADVREGEN)) { + adc->CR = ADC_CR_ADVREGEN; // enable VREG + #if defined(STM32H7) + mp_hal_delay_us(10); // T_ADCVREG_STUP + #elif defined(STM32L4) || defined(STM32WB) + mp_hal_delay_us(20); // T_ADCVREG_STUP + #endif + } + #endif + #if ADC_V2 + if (adc->CR == 0) { + // ADC hasn't been enabled so calibrate it + adc->CR |= ADC_CR_ADCAL; + while (adc->CR & ADC_CR_ADCAL) { + } + } + if (adc->CR & ADC_CR_ADEN) { // ADC enabled, need to disable it to change configuration if (adc->CR & ADC_CR_ADSTART) { @@ -130,17 +168,6 @@ STATIC void adc_config(ADC_TypeDef *adc, uint32_t bits) { } #endif - // TODO check all these - #if defined(STM32F0) - adc->CFGR2 = 1 << ADC_CFGR2_CKMODE_Pos; // PCLK/2 (synchronous clock mode) - #elif defined(STM32F4) || defined(STM32F7) || defined(STM32L4) - ADC123_COMMON->CCR = 0; // ADCPR=PCLK/2 - #elif defined(STM32H7) - __HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_CLKP); - #elif defined(STM32L0) || defined(STM32WB) - ADC1_COMMON->CCR = 0; // ADCPR=PCLK/2 - #endif - // Find resolution, defaulting to last element in table uint32_t res; for (res = 0; res <= MP_ARRAY_SIZE(adc_cr_to_bits_table); ++res) { @@ -193,10 +220,11 @@ STATIC int adc_get_bits(ADC_TypeDef *adc) { STATIC void adc_config_channel(ADC_TypeDef *adc, uint32_t channel, uint32_t sample_time) { #if ADC_V2 if (!(adc->CR & ADC_CR_ADEN)) { - if (adc->CR) { + if (adc->CR & 0x3f) { // Cannot enable ADC with CR!=0 return; } + adc->ISR = ADC_ISR_ADRDY; // clear ADRDY adc->CR |= ADC_CR_ADEN; adc_stabilisation_delay_us(ADC_STAB_DELAY_US); while (!(adc->ISR & ADC_ISR_ADRDY)) { @@ -249,6 +277,7 @@ STATIC void adc_config_channel(ADC_TypeDef *adc, uint32_t channel, uint32_t samp #elif defined(STM32H7) || defined(STM32L4) || defined(STM32WB) #if defined(STM32H7) + adc->PCSEL |= 1 << channel; ADC_Common_TypeDef *adc_common = adc == ADC3 ? ADC3_COMMON : ADC12_COMMON; #elif defined(STM32L4) ADC_Common_TypeDef *adc_common = ADC123_COMMON; @@ -263,7 +292,7 @@ STATIC void adc_config_channel(ADC_TypeDef *adc, uint32_t channel, uint32_t samp } else if (channel == ADC_CHANNEL_VBAT) { adc_common->CCR |= ADC_CCR_VBATEN; } - adc->SQR1 = (channel & 0x1f) << ADC_SQR1_SQ1_Pos | 1 << ADC_SQR1_L_Pos; + adc->SQR1 = (channel & 0x1f) << ADC_SQR1_SQ1_Pos | (1 - 1) << ADC_SQR1_L_Pos; __IO uint32_t *smpr; if (channel <= 9) { smpr = &adc->SMPR1; @@ -323,6 +352,11 @@ STATIC void machine_adc_print(const mp_print_t *print, mp_obj_t self_in, mp_prin unsigned adc_id = 1; #else unsigned adc_id = (self->adc - ADC1) / (ADC2 - ADC1) + 1; + #if defined(STM32H7) + if (self->adc == ADC3) { + adc_id = 3; + } + #endif #endif mp_printf(print, "", adc_id, self->channel); } From bd2e46e0a575029367caed118c15a73a5f9851b5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 6 Sep 2019 17:56:34 +1000 Subject: [PATCH 0687/1788] stm32/boards/stm32wb55_af.csv: Fix ADC pin-channel function mapping. --- ports/stm32/boards/stm32wb55_af.csv | 36 ++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/ports/stm32/boards/stm32wb55_af.csv b/ports/stm32/boards/stm32wb55_af.csv index 6e4ddd9608..074c330892 100644 --- a/ports/stm32/boards/stm32wb55_af.csv +++ b/ports/stm32/boards/stm32wb55_af.csv @@ -1,23 +1,23 @@ Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15, ,,SYS_AF,TIM1/TIM2/LPTIM1,TIM1/TIM2,SPI2/SAI1/TIM1,I2C1/I2C3,SPI1/SPI2,RF,USART1,LPUART1,TSC,USB/QUADSPI,LCD,COMP1/COMP2/TIM1,SAI1,TIM2/TIM16/TIM17/LPTIM2,EVENTOUT,ADC -PortA,PA0,,TIM2_CH1,,,,,,,,,,,COMP1_OUT,SAI1_EXTCLK,TIM2_ETR,EVENTOUT,ADC123_IN0 -PortA,PA1,,TIM2_CH2,,,I2C1_SMBA,SPI1_SCK,,,,,,LCD_SEG0,,,,EVENTOUT,ADC123_IN1 -PortA,PA2,LSCO,TIM2_CH3,,,,,,,LPUART1_TX,,QUADSPI_BK1_NCS,LCD_SEG1,COMP2_OUT,,,EVENTOUT,ADC123_IN2 -PortA,PA3,,TIM2_CH4,,SAI1_PDM_CK1,,,,,LPUART1_RX,,QUADSPI_CLK,LCD_SEG2,,SAI1_MCLK_A,,EVENTOUT,ADC123_IN3 -PortA,PA4,,,,,,SPI1_NSS,,,,,,LCD_SEG5,,SAI1_FS_B,LPTIM2_OUT,EVENTOUT,ADC12_IN4 -PortA,PA5,,TIM2_CH1,TIM2_ETR,,,SPI1_SCK,,,,,,,,SAI1_SD_B,LPTIM2_ETR,EVENTOUT,ADC12_IN5 -PortA,PA6,,TIM1_BKIN,,,,SPI1_MISO,,,LPUART1_CTS,,QUADSPI_BK1_IO3,LCD_SEG3,TIM1_BKIN,,TIM16_CH1,EVENTOUT,ADC12_IN6 -PortA,PA7,,TIM1_CH1N,,,I2C3_SCL,SPI1_MOSI,,,,,QUADSPI_BK1_IO2,LCD_SEG4,COMP2_OUT,,TIM17_CH1,EVENTOUT,ADC12_IN7 -PortA,PA8,MCO,TIM1_CH1,,SAI1_PDM_CK2,,,,USART1_CK,,,,LCD_COM0,,SAI1_SCK_A,LPTIM2_OUT,EVENTOUT, -PortA,PA9,,TIM1_CH2,,SAI1_PDM_DI2,I2C1_SCL,SPI2_SCK,,USART1_TX,,,,LCD_COM1,,SAI1_FS_A,,EVENTOUT, +PortA,PA0,,TIM2_CH1,,,,,,,,,,,COMP1_OUT,SAI1_EXTCLK,TIM2_ETR,EVENTOUT,ADC1_IN5 +PortA,PA1,,TIM2_CH2,,,I2C1_SMBA,SPI1_SCK,,,,,,LCD_SEG0,,,,EVENTOUT,ADC1_IN6 +PortA,PA2,LSCO,TIM2_CH3,,,,,,,LPUART1_TX,,QUADSPI_BK1_NCS,LCD_SEG1,COMP2_OUT,,,EVENTOUT,ADC1_IN7 +PortA,PA3,,TIM2_CH4,,SAI1_PDM_CK1,,,,,LPUART1_RX,,QUADSPI_CLK,LCD_SEG2,,SAI1_MCLK_A,,EVENTOUT,ADC1_IN8 +PortA,PA4,,,,,,SPI1_NSS,,,,,,LCD_SEG5,,SAI1_FS_B,LPTIM2_OUT,EVENTOUT,ADC1_IN9 +PortA,PA5,,TIM2_CH1,TIM2_ETR,,,SPI1_SCK,,,,,,,,SAI1_SD_B,LPTIM2_ETR,EVENTOUT,ADC1_IN10 +PortA,PA6,,TIM1_BKIN,,,,SPI1_MISO,,,LPUART1_CTS,,QUADSPI_BK1_IO3,LCD_SEG3,TIM1_BKIN,,TIM16_CH1,EVENTOUT,ADC1_IN11 +PortA,PA7,,TIM1_CH1N,,,I2C3_SCL,SPI1_MOSI,,,,,QUADSPI_BK1_IO2,LCD_SEG4,COMP2_OUT,,TIM17_CH1,EVENTOUT,ADC1_IN12 +PortA,PA8,MCO,TIM1_CH1,,SAI1_PDM_CK2,,,,USART1_CK,,,,LCD_COM0,,SAI1_SCK_A,LPTIM2_OUT,EVENTOUT,ADC1_IN15 +PortA,PA9,,TIM1_CH2,,SAI1_PDM_DI2,I2C1_SCL,SPI2_SCK,,USART1_TX,,,,LCD_COM1,,SAI1_FS_A,,EVENTOUT,ADC1_IN16 PortA,PA10,,TIM1_CH3,,SAI1_PDM_DI1,I2C1_SDA,,,USART1_RX,,,USB_CRS_SYNC,LCD_COM2,,SAI1_SD_A,TIM17_BKIN,EVENTOUT, PortA,PA11,,TIM1_CH4,TIM1_BKIN2,,,SPI1_MISO,,USART1_CTS,,,USB_DM,,TIM1_BKIN2,,,EVENTOUT, PortA,PA12,,TIM1_ETR,,,,SPI1_MOSI,,USART1_RTS_DE,LPUART1_RX,,USB_DP,,,,,EVENTOUT, PortA,PA13,JTMS/SWDIO,,,,,,,,IR_OUT,,USB_NOE,,,SAI1_SD_B,,EVENTOUT, PortA,PA14,JTCK/SWCLK,LPTIM1_OUT,,,I2C1_SMBA,,,,,,,LCD_SEG5,,SAI1_FS_B,,EVENTOUT, PortA,PA15,JTDI,TIM2_CH1,TIM2_ETR,,,SPI1_NSS,,,,TSC_G3_IO1,,LCD_SEG17,,,,EVENTOUT, -PortB,PB0,,,,,,,EXT_PA_TX,,,,,,COMP1_OUT,,,EVENTOUT,ADC12_IN8 -PortB,PB1,,,,,,,,,LPUART1_RTS_DE,,,,,,LPTIM2_IN1,EVENTOUT,ADC12_IN9 +PortB,PB0,,,,,,,EXT_PA_TX,,,,,,COMP1_OUT,,,EVENTOUT, +PortB,PB1,,,,,,,,,LPUART1_RTS_DE,,,,,,LPTIM2_IN1,EVENTOUT, PortB,PB2,RTC_OUT,LPTIM1_OUT,,,I2C3_SMBA,SPI1_NSS,,,,,,LCD_VLCD,,SAI1_EXTCLK,,EVENTOUT, PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,,USART1_RTS_DE,,,,LCD_SEG7,,SAI1_SCK_B,,EVENTOUT, PortB,PB4,NJTRST,,,,I2C3_SDA,SPI1_MISO,,USART1_CTS,,TSC_G2_IO1,,LCD_SEG8,,SAI1_MCLK_B,TIM17_BKIN,EVENTOUT, @@ -32,12 +32,12 @@ PortB,PB12,,TIM1_BKIN,,TIM1_BKIN,I2C3_SMBA,SPI2_NSS,,,LPUART1_RTS,TSC_G1_IO1,,LC PortB,PB13,,TIM1_CH1N,,,I2C3_SCL,SPI2_SCK,,,LPUART1_CTS,TSC_G1_IO2,,LCD_SEG13,,SAI1_SCK_A,,EVENTOUT, PortB,PB14,,TIM1_CH2N,,,I2C3_SDA,SPI2_MISO,,,,TSC_G1_IO3,,LCD_SEG14,,SAI1_MCLK_A,,EVENTOUT, PortB,PB15,RTC_REFIN,TIM1_CH3N,,,,SPI2_MOSI,,,,TSC_G1_IO4,,LCD_SEG15,,SAI1_SD_A,,EVENTOUT, -PortC,PC0,,LPTIM1_IN1,,,I2C3_SCL,,,,LPUART1_RX,,,LCD_SEG18,,,LPTIM2_IN1,EVENTOUT,ADC123_IN10 -PortC,PC1,,LPTIM1_OUT,,SPI2_MOSI,I2C3_SDA,,,,LPUART1_TX,,,LCD_SEG19,,,,EVENTOUT,ADC123_IN11 -PortC,PC2,,LPTIM1_IN2,,,,SPI2_MISO,,,,,,LCD_SEG20,,,,EVENTOUT,ADC123_IN12 -PortC,PC3,,LPTIM1_ETR,,SAI1_PDM_DI1,,SPI2_MOSI,,,,,,LCD_VLCD,,SAI1_SD_A,LPTIM2_ETR,EVENTOUT,ADC123_IN13 -PortC,PC4,,,,,,,,,,,,LCD_SEG22,,,,EVENTOUT,ADC12_IN14 -PortC,PC5,,,,SAI1_PDM_DI3,,,,,,,,LCD_SEG23,,,,EVENTOUT,ADC12_IN15 +PortC,PC0,,LPTIM1_IN1,,,I2C3_SCL,,,,LPUART1_RX,,,LCD_SEG18,,,LPTIM2_IN1,EVENTOUT,ADC1_IN1 +PortC,PC1,,LPTIM1_OUT,,SPI2_MOSI,I2C3_SDA,,,,LPUART1_TX,,,LCD_SEG19,,,,EVENTOUT,ADC1_IN2 +PortC,PC2,,LPTIM1_IN2,,,,SPI2_MISO,,,,,,LCD_SEG20,,,,EVENTOUT,ADC1_IN3 +PortC,PC3,,LPTIM1_ETR,,SAI1_PDM_DI1,,SPI2_MOSI,,,,,,LCD_VLCD,,SAI1_SD_A,LPTIM2_ETR,EVENTOUT,ADC1_IN4 +PortC,PC4,,,,,,,,,,,,LCD_SEG22,,,,EVENTOUT,ADC1_IN13 +PortC,PC5,,,,SAI1_PDM_DI3,,,,,,,,LCD_SEG23,,,,EVENTOUT,ADC1_IN14 PortC,PC6,,,,,,,,,,TSC_G4_IO1,,LCD_SEG24,,,,EVENTOUT, PortC,PC7,,,,,,,,,,TSC_G4_IO2,,LCD_SEG25,,,,EVENTOUT, PortC,PC8,,,,,,,,,,TSC_G4_IO3,,LCD_SEG26,,,,EVENTOUT, From c69f58e6b97b954d06734797f06feeab4e510855 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 6 Sep 2019 23:55:15 +1000 Subject: [PATCH 0688/1788] tools/mpy-tool.py: Fix freezing of non-bytecode funcs with settrace. Only bytecode functions can be profiled at this stage. Native functions (eg inline assembler) may not even have a valid prelude. Fixes issue #5075. --- tools/mpy-tool.py | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index e5c8f09597..e159165f14 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -412,22 +412,23 @@ class RawCode(object): print(' .fun_data_len = %u,' % len(self.bytecode)) print(' .n_obj = %u,' % len(self.objs)) print(' .n_raw_code = %u,' % len(self.raw_codes)) - print(' #if MICROPY_PY_SYS_SETTRACE') - print(' .prelude = {') - print(' .n_state = %u,' % self.prelude[0]) - print(' .n_exc_stack = %u,' % self.prelude[1]) - print(' .scope_flags = %u,' % self.prelude[2]) - print(' .n_pos_args = %u,' % self.prelude[3]) - print(' .n_kwonly_args = %u,' % self.prelude[4]) - print(' .n_def_pos_args = %u,' % self.prelude[5]) - print(' .qstr_block_name = %s,' % self.simple_name.qstr_id) - print(' .qstr_source_file = %s,' % self.source_file.qstr_id) - print(' .line_info = fun_data_%s + %u,' % (self.escaped_name, 0)) # TODO - print(' .locals = fun_data_%s + %u,' % (self.escaped_name, 0)) # TODO - print(' .opcodes = fun_data_%s + %u,' % (self.escaped_name, self.ip)) - print(' },') - print(' .line_of_definition = %u,' % 0) # TODO - print(' #endif') + if self.code_kind == MP_CODE_BYTECODE: + print(' #if MICROPY_PY_SYS_SETTRACE') + print(' .prelude = {') + print(' .n_state = %u,' % self.prelude[0]) + print(' .n_exc_stack = %u,' % self.prelude[1]) + print(' .scope_flags = %u,' % self.prelude[2]) + print(' .n_pos_args = %u,' % self.prelude[3]) + print(' .n_kwonly_args = %u,' % self.prelude[4]) + print(' .n_def_pos_args = %u,' % self.prelude[5]) + print(' .qstr_block_name = %s,' % self.simple_name.qstr_id) + print(' .qstr_source_file = %s,' % self.source_file.qstr_id) + print(' .line_info = fun_data_%s + %u,' % (self.escaped_name, 0)) # TODO + print(' .locals = fun_data_%s + %u,' % (self.escaped_name, 0)) # TODO + print(' .opcodes = fun_data_%s + %u,' % (self.escaped_name, self.ip)) + print(' },') + print(' .line_of_definition = %u,' % 0) # TODO + print(' #endif') print(' #if MICROPY_EMIT_MACHINE_CODE') print(' .prelude_offset = %u,' % self.prelude_offset) print(' .n_qstr = %u,' % len(qstr_links)) From 5641aa55dddbdf312a1e8dbb8c3936115683840a Mon Sep 17 00:00:00 2001 From: Braden Mars Date: Sat, 7 Sep 2019 01:28:11 -0500 Subject: [PATCH 0689/1788] esp32: Update to use ESP IDF v3.3 Includes patches for CVE-2019-12586 & CVE-2019-12587 --- ports/esp32/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index cf1b24bfc8..1e02984520 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -49,7 +49,7 @@ SDKCONFIG_COMBINED = $(BUILD)/sdkconfig.combined SDKCONFIG_H = $(BUILD)/sdkconfig.h # the git hash of the currently supported ESP IDF version -ESPIDF_SUPHASH := 6b3da6b1882f3b72e904cc90be67e9c4e3f369a9 +ESPIDF_SUPHASH := 6ccb4cf5b7d1fdddb8c2492f9cbc926abaf230df # paths to ESP IDF and its components ifeq ($(ESPIDF),) From e9af6f5f886337d0a366ac4d7f4a03ee1117cde0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 30 Aug 2019 17:15:01 +1000 Subject: [PATCH 0690/1788] esp32/boards/TINYPICO: Switch to use QIO and 80MHz for SPI interface. --- ports/esp32/boards/TINYPICO/mpconfigboard.mk | 3 +++ ports/esp32/boards/TINYPICO/sdkconfig.board | 3 +++ 2 files changed, 6 insertions(+) create mode 100644 ports/esp32/boards/TINYPICO/sdkconfig.board diff --git a/ports/esp32/boards/TINYPICO/mpconfigboard.mk b/ports/esp32/boards/TINYPICO/mpconfigboard.mk index 59aa75f857..2efdba0f39 100644 --- a/ports/esp32/boards/TINYPICO/mpconfigboard.mk +++ b/ports/esp32/boards/TINYPICO/mpconfigboard.mk @@ -1,2 +1,5 @@ +FLASH_FREQ = 80m + SDKCONFIG += boards/sdkconfig.base SDKCONFIG += boards/sdkconfig.spiram +SDKCONFIG += boards/TINYPICO/sdkconfig.board diff --git a/ports/esp32/boards/TINYPICO/sdkconfig.board b/ports/esp32/boards/TINYPICO/sdkconfig.board new file mode 100644 index 0000000000..ea4fc9b5cd --- /dev/null +++ b/ports/esp32/boards/TINYPICO/sdkconfig.board @@ -0,0 +1,3 @@ +CONFIG_FLASHMODE_QIO=y +CONFIG_ESPTOOLPY_FLASHFREQ_80M=y +CONFIG_SPIRAM_SPEED_80M=y From 380048df64255e869d168b0bf4ebc4b6138a6eb2 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Fri, 6 Sep 2019 10:56:03 +1000 Subject: [PATCH 0691/1788] windows/Makefile: Make use of CFLAGS_EXTRA, LDFLAGS_EXTRA and SRC_MOD. To be consistent with the unix port. --- ports/windows/Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ports/windows/Makefile b/ports/windows/Makefile index 88d103e7b0..e65c09c53a 100644 --- a/ports/windows/Makefile +++ b/ports/windows/Makefile @@ -15,8 +15,8 @@ INC += -I$(TOP) INC += -I$(BUILD) # compiler settings -CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 -DUNIX -D__USE_MINGW_ANSI_STDIO=1 $(CFLAGS_MOD) $(COPT) -LDFLAGS = $(LDFLAGS_MOD) -lm +CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 -DUNIX -D__USE_MINGW_ANSI_STDIO=1 $(CFLAGS_MOD) $(COPT) $(CFLAGS_EXTRA) +LDFLAGS = $(LDFLAGS_MOD) -lm $(LDFLAGS_EXTRA) # Debugging/Optimization ifdef DEBUG @@ -40,6 +40,7 @@ SRC_C = \ realpath.c \ init.c \ sleep.c \ + $(SRC_MOD) OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) From ea060a42e9e00052564eb27bd9aa474b01fac9ae Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 7 Sep 2019 12:42:11 +1000 Subject: [PATCH 0692/1788] py/vm: Factor cached map lookup code to inline function. To reduce code duplication and allow to more easily modify this function. --- py/vm.c | 104 ++++++++++++++++++++++++-------------------------------- 1 file changed, 45 insertions(+), 59 deletions(-) diff --git a/py/vm.c b/py/vm.c index 9abad8d83f..63869d9265 100644 --- a/py/vm.c +++ b/py/vm.c @@ -158,6 +158,23 @@ #define TRACE_TICK(current_ip, current_sp, is_exception) #endif // MICROPY_PY_SYS_SETTRACE +#if MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE +static inline mp_map_elem_t *mp_map_cached_lookup(mp_map_t *map, qstr qst, uint8_t *idx_cache) { + size_t idx = *idx_cache; + mp_obj_t key = MP_OBJ_NEW_QSTR(qst); + mp_map_elem_t *elem = NULL; + if (idx < map->alloc && map->table[idx].key == key) { + elem = &map->table[idx]; + } else { + elem = mp_map_lookup(map, key, MP_MAP_LOOKUP); + if (elem != NULL) { + *idx_cache = (elem - &map->table[0]) & 0xff; + } + } + return elem; +} +#endif + // fastn has items in reverse order (fastn[0] is local[0], fastn[-1] is local[1], etc) // sp points to bottom of stack which grows up // returns: @@ -333,19 +350,14 @@ dispatch_loop: ENTRY(MP_BC_LOAD_NAME): { MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; - mp_obj_t key = MP_OBJ_NEW_QSTR(qst); - mp_uint_t x = *ip; - if (x < mp_locals_get()->map.alloc && mp_locals_get()->map.table[x].key == key) { - PUSH(mp_locals_get()->map.table[x].value); + mp_map_elem_t *elem = mp_map_cached_lookup(&mp_locals_get()->map, qst, (uint8_t*)ip); + mp_obj_t obj; + if (elem != NULL) { + obj = elem->value; } else { - mp_map_elem_t *elem = mp_map_lookup(&mp_locals_get()->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); - if (elem != NULL) { - *(byte*)ip = (elem - &mp_locals_get()->map.table[0]) & 0xff; - PUSH(elem->value); - } else { - PUSH(mp_load_name(MP_OBJ_QSTR_VALUE(key))); - } + obj = mp_load_name(qst); } + PUSH(obj); ip++; DISPATCH(); } @@ -362,19 +374,14 @@ dispatch_loop: ENTRY(MP_BC_LOAD_GLOBAL): { MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; - mp_obj_t key = MP_OBJ_NEW_QSTR(qst); - mp_uint_t x = *ip; - if (x < mp_globals_get()->map.alloc && mp_globals_get()->map.table[x].key == key) { - PUSH(mp_globals_get()->map.table[x].value); + mp_map_elem_t *elem = mp_map_cached_lookup(&mp_globals_get()->map, qst, (uint8_t*)ip); + mp_obj_t obj; + if (elem != NULL) { + obj = elem->value; } else { - mp_map_elem_t *elem = mp_map_lookup(&mp_globals_get()->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); - if (elem != NULL) { - *(byte*)ip = (elem - &mp_globals_get()->map.table[0]) & 0xff; - PUSH(elem->value); - } else { - PUSH(mp_load_global(MP_OBJ_QSTR_VALUE(key))); - } + obj = mp_load_global(qst); } + PUSH(obj); ip++; DISPATCH(); } @@ -394,27 +401,18 @@ dispatch_loop: MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_obj_t top = TOP(); + mp_map_elem_t *elem = NULL; 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); - mp_map_elem_t *elem; - if (x < self->members.alloc && self->members.table[x].key == key) { - elem = &self->members.table[x]; - } else { - elem = mp_map_lookup(&self->members, key, MP_MAP_LOOKUP); - if (elem != NULL) { - *(byte*)ip = elem - &self->members.table[0]; - } else { - goto load_attr_cache_fail; - } - } - SET_TOP(elem->value); - ip++; - DISPATCH(); + elem = mp_map_cached_lookup(&self->members, qst, (uint8_t*)ip); } - load_attr_cache_fail: - SET_TOP(mp_load_attr(top, qst)); + mp_obj_t obj; + if (elem != NULL) { + obj = elem->value; + } else { + obj = mp_load_attr(top, qst); + } + SET_TOP(obj); ip++; DISPATCH(); } @@ -493,29 +491,17 @@ dispatch_loop: FRAME_UPDATE(); MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; + mp_map_elem_t *elem = NULL; mp_obj_t top = TOP(); 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); - mp_map_elem_t *elem; - if (x < self->members.alloc && self->members.table[x].key == key) { - elem = &self->members.table[x]; - } else { - elem = mp_map_lookup(&self->members, key, MP_MAP_LOOKUP); - if (elem != NULL) { - *(byte*)ip = elem - &self->members.table[0]; - } else { - goto store_attr_cache_fail; - } - } - elem->value = sp[-1]; - sp -= 2; - ip++; - DISPATCH(); + elem = mp_map_cached_lookup(&self->members, qst, (uint8_t*)ip); + } + if (elem != NULL) { + elem->value = sp[-1]; + } else { + mp_store_attr(sp[0], qst, sp[-1]); } - store_attr_cache_fail: - mp_store_attr(sp[0], qst, sp[-1]); sp -= 2; ip++; DISPATCH(); From a605b537024c54a41717552155b977f5bcf7b5e5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 8 Sep 2019 15:51:31 -0700 Subject: [PATCH 0693/1788] stm32/mboot: Support boards with only two LEDs. Mboot currently requires at least three LEDs to display each of the four states. However, since there are only four possible states, the states can be displayed via binary counting on only 2 LEDs (if only 2 are available). The existing patterns are still used for 3 or 4 LEDs. --- ports/stm32/mboot/main.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ports/stm32/mboot/main.c b/ports/stm32/mboot/main.c index fcd43edc7f..a0f1f1eace 100644 --- a/ports/stm32/mboot/main.c +++ b/ports/stm32/mboot/main.c @@ -408,7 +408,9 @@ void mp_hal_pin_config_speed(uint32_t port_pin, uint32_t speed) { #define LED0 MICROPY_HW_LED1 #define LED1 MICROPY_HW_LED2 +#ifdef MICROPY_HW_LED3 #define LED2 MICROPY_HW_LED3 +#endif #ifdef MICROPY_HW_LED4 #define LED3 MICROPY_HW_LED4 #endif @@ -416,7 +418,9 @@ void mp_hal_pin_config_speed(uint32_t port_pin, uint32_t speed) { void led_init(void) { mp_hal_pin_output(LED0); mp_hal_pin_output(LED1); + #ifdef LED2 mp_hal_pin_output(LED2); + #endif #ifdef LED3 mp_hal_pin_output(LED3); #endif @@ -436,7 +440,9 @@ void led_state(int led, int val) { void led_state_all(unsigned int mask) { led_state(LED0, mask & 1); led_state(LED1, mask & 2); + #ifdef LED2 led_state(LED2, mask & 4); + #endif #ifdef LED3 led_state(LED3, mask & 8); #endif @@ -1345,11 +1351,15 @@ static int pyb_usbdd_shutdown(void) { #define RESET_MODE_NUM_STATES (4) #define RESET_MODE_TIMEOUT_CYCLES (8) +#ifdef LED2 #ifdef LED3 #define RESET_MODE_LED_STATES 0x8421 #else #define RESET_MODE_LED_STATES 0x7421 #endif +#else +#define RESET_MODE_LED_STATES 0x3210 +#endif static int get_reset_mode(void) { usrbtn_init(); From 2b07f56c2b6fecb4074d461f7ec50e6e9975fcbe Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 10 Sep 2019 11:53:00 +1000 Subject: [PATCH 0694/1788] stm32/boards/NUCLEO_L073RZ: Fix typo in MCU name. --- ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.h b/ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.h index ff4be4a277..e20dff6771 100644 --- a/ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.h @@ -3,7 +3,7 @@ */ #define MICROPY_HW_BOARD_NAME "NUCLEO-L073RZ" -#define MICROPY_HW_MCU_NAME "STM32F073RZT6" +#define MICROPY_HW_MCU_NAME "STM32L073RZT6" #define MICROPY_EMIT_THUMB (0) #define MICROPY_EMIT_INLINE_THUMB (0) From 50636e5296c2eb837a5c29941b392adeaab60d94 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 10 Sep 2019 13:22:35 +1000 Subject: [PATCH 0695/1788] docs/library/pyb.rst: Update docs for pyb.usb_mode() function. --- docs/library/pyb.rst | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/docs/library/pyb.rst b/docs/library/pyb.rst index 1e1e9ffaab..acb8fe450e 100644 --- a/docs/library/pyb.rst +++ b/docs/library/pyb.rst @@ -259,14 +259,12 @@ Miscellaneous functions Returns a string of 12 bytes (96 bits), which is the unique ID of the MCU. -.. function:: usb_mode([modestr], vid=0xf055, pid=0x9801, hid=pyb.hid_mouse) +.. function:: usb_mode([modestr], port=-1, vid=0xf055, pid=-1, msc=(), hid=pyb.hid_mouse, high_speed=False) If called with no arguments, return the current USB mode as a string. - If called with ``modestr`` provided, attempts to set USB mode. - This can only be done when called from ``boot.py`` before - :meth:`pyb.main()` has been called. The following values of - ``modestr`` are understood: + If called with *modestr* provided, attempts to configure the USB mode. + The following values of *modestr* are understood: - ``None``: disables USB - ``'VCP'``: enable with VCP (Virtual COM Port) interface @@ -277,16 +275,28 @@ Miscellaneous functions For backwards compatibility, ``'CDC'`` is understood to mean ``'VCP'`` (and similarly for ``'CDC+MSC'`` and ``'CDC+HID'``). - The ``vid`` and ``pid`` parameters allow you to specify the VID - (vendor id) and PID (product id). + The *port* parameter should be an integer (0, 1, ...) and selects which + USB port to use if the board supports multiple ports. A value of -1 uses + the default or automatically selected port. + + The *vid* and *pid* parameters allow you to specify the VID (vendor id) + and PID (product id). A *pid* value of -1 will select a PID based on the + value of *modestr*. + + If enabling MSC mode, the *msc* parameter can be used to specify a list + of SCSI LUNs to expose on the mass storage interface. For example + ``msc=(pyb.Flash(), pyb.SDCard())``. If enabling HID mode, you may also specify the HID details by - passing the ``hid`` keyword parameter. It takes a tuple of + passing the *hid* keyword parameter. It takes a tuple of (subclass, protocol, max packet length, polling interval, report descriptor). By default it will set appropriate values for a USB mouse. There is also a ``pyb.hid_keyboard`` constant, which is an appropriate tuple for a USB keyboard. + The *high_speed* parameter, when set to ``True``, enables USB HS mode if + it is supported by the hardware. + Classes ------- From f9d142523c48af1cb9c83d1dfbc320cb9c2000c6 Mon Sep 17 00:00:00 2001 From: Christopher Wilson Date: Mon, 22 Jul 2019 09:05:31 -0700 Subject: [PATCH 0696/1788] stm32/boards/MIKROE_CLICKER2_STM32: Add MikroElektronika Clicker2 board. - STM32F407VGT6 (1MB of Flash, 192+4 Kbytes of SRAM) - 5V (via USB) or Li-Polymer Battery (3.7V) power input - 2 x LEDs - 2 x user switches - 2 x mikroBUS sockets - 2 x 1x26 mikromedia-compatible headers (52 pins) https://www.mikroe.com/clicker-2-stm32f4 --- .../MIKROE_CLICKER2_STM32/mpconfigboard.h | 85 ++++++++++++++++++ .../MIKROE_CLICKER2_STM32/mpconfigboard.mk | 13 +++ .../boards/MIKROE_CLICKER2_STM32/pins.csv | 88 +++++++++++++++++++ .../stm32f4xx_hal_conf.h | 19 ++++ 4 files changed, 205 insertions(+) create mode 100644 ports/stm32/boards/MIKROE_CLICKER2_STM32/mpconfigboard.h create mode 100644 ports/stm32/boards/MIKROE_CLICKER2_STM32/mpconfigboard.mk create mode 100644 ports/stm32/boards/MIKROE_CLICKER2_STM32/pins.csv create mode 100644 ports/stm32/boards/MIKROE_CLICKER2_STM32/stm32f4xx_hal_conf.h diff --git a/ports/stm32/boards/MIKROE_CLICKER2_STM32/mpconfigboard.h b/ports/stm32/boards/MIKROE_CLICKER2_STM32/mpconfigboard.h new file mode 100644 index 0000000000..eb622cd296 --- /dev/null +++ b/ports/stm32/boards/MIKROE_CLICKER2_STM32/mpconfigboard.h @@ -0,0 +1,85 @@ +#define MICROPY_HW_BOARD_NAME "MIKROE_CLICKER2_STM32" +#define MICROPY_HW_MCU_NAME "STM32F407" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_USB (1) + +// HSE is 25MHz +#define MICROPY_HW_CLK_PLLM (25) +#define MICROPY_HW_CLK_PLLN (336) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (7) +#define MICROPY_HW_CLK_LAST_FREQ (1) + +// The board has a 32kHz crystal for the RTC +#define MICROPY_HW_RTC_USE_LSE (1) +#define MICROPY_HW_RTC_USE_US (0) +#define MICROPY_HW_RTC_USE_CALOUT (0) // turn on/off PC13 512Hz output + +// UART config +// mikroBUS slot 1 +#define MICROPY_HW_UART2_NAME "SLOT1" +#define MICROPY_HW_UART2_TX (pin_D5) +#define MICROPY_HW_UART2_RX (pin_D6) +// mikroBUS slot 2 +#define MICROPY_HW_UART3_NAME "SLOT2" +#define MICROPY_HW_UART3_TX (pin_D8) +#define MICROPY_HW_UART3_RX (pin_D9) +// HDR2 +#define MICROPY_HW_UART4_NAME "HDR2" +#define MICROPY_HW_UART4_TX (pin_A0) +#define MICROPY_HW_UART4_RX (pin_A1) + +// I2C buses +// mikroBUS slot 2 / HDR2 +#define MICROPY_HW_I2C2_NAME "SLOT2" +#define MICROPY_HW_I2C2_SCL (pin_B10) +#define MICROPY_HW_I2C2_SDA (pin_B11) +// mikroBUS slot 1 +#define MICROPY_HW_I2C3_NAME "SLOT1" +#define MICROPY_HW_I2C3_SCL (pin_A8) +#define MICROPY_HW_I2C3_SDA (pin_C9) + +// SPI buses +// mikroBUS slot 2 / HDR1 +#define MICROPY_HW_SPI2_NAME "SLOT2" +#define MICROPY_HW_SPI2_NSS (pin_E11) +#define MICROPY_HW_SPI2_SCK (pin_B13) +#define MICROPY_HW_SPI2_MISO (pin_B14) +#define MICROPY_HW_SPI2_MOSI (pin_B15) +// mikroBUS slot 1 +#define MICROPY_HW_SPI3_NAME "SLOT1" +#define MICROPY_HW_SPI3_NSS (pin_E8) +#define MICROPY_HW_SPI3_SCK (pin_C10) +#define MICROPY_HW_SPI3_MISO (pin_C11) +#define MICROPY_HW_SPI3_MOSI (pin_C12) + +// USRSW is pulled high; pressing the button makes the input go low +#define MICROPY_HW_USRSW_PIN (pin_E0) +#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_FALLING) +#define MICROPY_HW_USRSW_PRESSED (0) + +// LEDs +#define MICROPY_HW_LED1 (pin_E12) // red +#define MICROPY_HW_LED2 (pin_E15) // 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) + +// Bootloader configuration (only needed if Mboot is used) +#define MBOOT_I2C_PERIPH_ID 2 +#define MBOOT_I2C_SCL (pin_B10) +#define MBOOT_I2C_SDA (pin_B11) +#define MBOOT_I2C_ALTFUNC (4) +#define MBOOT_BOOTPIN_PIN (pin_A10) +#define MBOOT_BOOTPIN_PULL (MP_HAL_PIN_PULL_NONE) +#define MBOOT_BOOTPIN_ACTIVE (0) +#define MBOOT_FSLOAD (1) diff --git a/ports/stm32/boards/MIKROE_CLICKER2_STM32/mpconfigboard.mk b/ports/stm32/boards/MIKROE_CLICKER2_STM32/mpconfigboard.mk new file mode 100644 index 0000000000..aa52f21162 --- /dev/null +++ b/ports/stm32/boards/MIKROE_CLICKER2_STM32/mpconfigboard.mk @@ -0,0 +1,13 @@ +MCU_SERIES = f4 +CMSIS_MCU = STM32F407xx +AF_FILE = boards/stm32f405_af.csv +ifeq ($(USE_MBOOT),1) +# When using Mboot all the text goes together after the filesystem +LD_FILES = boards/stm32f405.ld boards/common_blifs.ld +TEXT0_ADDR = 0x08020000 +else +# When not using Mboot the ISR text goes first, then the rest after the filesystem +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 +endif diff --git a/ports/stm32/boards/MIKROE_CLICKER2_STM32/pins.csv b/ports/stm32/boards/MIKROE_CLICKER2_STM32/pins.csv new file mode 100644 index 0000000000..09e1ccfb4b --- /dev/null +++ b/ports/stm32/boards/MIKROE_CLICKER2_STM32/pins.csv @@ -0,0 +1,88 @@ +MB1_AN,PA2 +MB1_RST,PE7 +MB1_CS,PE8 +MB1_SCK,PC10 +MB1_MISO,PC11 +MB1_MOSI,PC12 +MB1_PWM,PE9 +MB1_INT,PE10 +MB1_RX,PD6 +MB1_TX,PD5 +MB1_SCL,PA8 +MB1_SDA,PC9 +MB2_AN,PA3 +MB2_RST,PE13 +MB2_CS,PE11 +MB2_SCK,PB13 +MB2_MISO,PB14 +MB2_MOSI,PB15 +MB2_PWM,PD12 +MB2_INT,PE14 +MB2_RX,PD9 +MB2_TX,PD8 +MB2_SCL,PB10 +MB2_SDA,PB11 +PIN1,VSYS +PIN2,GND +PIN3,PC0 +PIN4,PC1 +PIN5,PC2 +PIN6,PC3 +PIN7,PB1 +PIN8,PA4 +PIN9,PC4 +PIN10,PD3 +PIN11,PD1 +PIN12,PD2 +PIN13,PD0 +PIN14,PC8 +PIN15,PD15 +PIN16,PD14 +PIN17,PD13 +PIN18,PB7 +PIN19,PC7 +PIN20,PD11 +PIN21,PD10 +PIN22,PB13 +PIN23,PB14 +PIN24,PB15 +PIN25,3.3V +PIN26,GND +PIN27,RST +PIN28,GND +PIN30,NC +PIN31,PB9 +PIN32,PB8 +PIN33,PE5 +PIN34,PB0 +PIN35,PA5 +PIN36,PA6 +PIN37,PA7 +PIN38,PE1 +PIN39,PE2 +PIN40,PE3 +PIN41,PE4 +PIN42,PE6 +PIN43,PB6 +PIN44,PB5 +PIN45,PD7 +PIN46,PC13 +PIN47,PA1 +PIN48,PA0 +PIN49,PB10 +PIN50,PB11 +PIN51,3.3V +PIN52,GND +OSC32_OUT,PC15 +OSC32_IN,PC14 +VSENSE,PC5 +SENSEL,PB12 +FAULT,PC6 +BATSTAT,PD4 +LD1,PE12 +LD2,PE15 +T2,PE0 +T3,PA10 +USB_VBUS,PA9 +USB_DM,PA11 +USB_DP,PA12 \ No newline at end of file diff --git a/ports/stm32/boards/MIKROE_CLICKER2_STM32/stm32f4xx_hal_conf.h b/ports/stm32/boards/MIKROE_CLICKER2_STM32/stm32f4xx_hal_conf.h new file mode 100644 index 0000000000..f186d5a292 --- /dev/null +++ b/ports/stm32/boards/MIKROE_CLICKER2_STM32/stm32f4xx_hal_conf.h @@ -0,0 +1,19 @@ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H + +#include "boards/stm32f4xx_hal_conf_base.h" + +// Oscillator values in Hz +#define HSE_VALUE (25000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) + +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) + +#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H From 31de44775c0ed2fa451e578dd0594d13f11459e9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 20 Aug 2019 16:52:36 +1000 Subject: [PATCH 0697/1788] esp32: Add VFS FAT partition to partitions.csv and mount it as the FS. This patch uses the newly-added esp32.Partition class to replace the existing FlashBdev class. Partition objects implement the block protocol so can be directly mounted via uos.mount(). This has the following benefits: - allows the filesystem partition location and size to be specified in partitions.csv, and overridden by a particular board - very easily allows to have multiple filesystems by simply adding extra entries to partitions.csv - improves efficiency/speed of filesystem operations because the block device is implemented fully in C - opens the possibility to have encrypted flash storage (since Partitions can be encrypted) Note that this patch is fully backwards compatible: existing filesystems remain untouched and work with this new code. --- ports/esp32/modules/flashbdev.py | 36 +++----------------------------- ports/esp32/partitions.csv | 1 + 2 files changed, 4 insertions(+), 33 deletions(-) diff --git a/ports/esp32/modules/flashbdev.py b/ports/esp32/modules/flashbdev.py index 935f5342fc..45b8686c55 100644 --- a/ports/esp32/modules/flashbdev.py +++ b/ports/esp32/modules/flashbdev.py @@ -1,34 +1,4 @@ -import esp +from esp32 import Partition -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) +bdev = Partition.find(Partition.TYPE_DATA, label='vfs') +bdev = bdev[0] if bdev else None diff --git a/ports/esp32/partitions.csv b/ports/esp32/partitions.csv index 98adcd20a7..55c225759e 100644 --- a/ports/esp32/partitions.csv +++ b/ports/esp32/partitions.csv @@ -3,3 +3,4 @@ nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 0x180000, +vfs, data, fat, 0x200000, 0x200000, From 80d37d936c9832dc4b69ad631ad07697e26764d9 Mon Sep 17 00:00:00 2001 From: Alex Albino Date: Wed, 7 Aug 2019 07:22:15 -0700 Subject: [PATCH 0698/1788] esp32: Add support for ESP32-D2WD with 2MiB internal flash. This patch adds a partitions file for the D2WD and a new board GENERIC_D2WD which runs on these chip variants. Resolves issue #4986. --- ports/esp32/boards/GENERIC_D2WD/mpconfigboard.h | 2 ++ ports/esp32/boards/GENERIC_D2WD/mpconfigboard.mk | 5 +++++ ports/esp32/partitions-2MiB.csv | 6 ++++++ 3 files changed, 13 insertions(+) create mode 100644 ports/esp32/boards/GENERIC_D2WD/mpconfigboard.h create mode 100644 ports/esp32/boards/GENERIC_D2WD/mpconfigboard.mk create mode 100644 ports/esp32/partitions-2MiB.csv diff --git a/ports/esp32/boards/GENERIC_D2WD/mpconfigboard.h b/ports/esp32/boards/GENERIC_D2WD/mpconfigboard.h new file mode 100644 index 0000000000..8923d46fd1 --- /dev/null +++ b/ports/esp32/boards/GENERIC_D2WD/mpconfigboard.h @@ -0,0 +1,2 @@ +#define MICROPY_HW_BOARD_NAME "Generic ESP32-D2WD module" +#define MICROPY_HW_MCU_NAME "ESP32-D2WD" diff --git a/ports/esp32/boards/GENERIC_D2WD/mpconfigboard.mk b/ports/esp32/boards/GENERIC_D2WD/mpconfigboard.mk new file mode 100644 index 0000000000..65de5dcd08 --- /dev/null +++ b/ports/esp32/boards/GENERIC_D2WD/mpconfigboard.mk @@ -0,0 +1,5 @@ +SDKCONFIG += boards/sdkconfig.base +PART_SRC = partitions-2MiB.csv +FLASH_SIZE = 2MB +FLASH_MODE = dio +FLASH_FREQ = 40m diff --git a/ports/esp32/partitions-2MiB.csv b/ports/esp32/partitions-2MiB.csv new file mode 100644 index 0000000000..84bc53782d --- /dev/null +++ b/ports/esp32/partitions-2MiB.csv @@ -0,0 +1,6 @@ +# 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, 0x110000, +vfs, data, fat, 0x120000, 0xA0000, From bd1d27f00f43bb44fca806cd0c53fa7196a1ea04 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 10 Sep 2019 22:41:50 +1000 Subject: [PATCH 0699/1788] esp32/modules/inisetup.py: Use bdev.ioctl instead of bdev.SEC_SIZE. Since the bdev is now a Partition it doesn't have SEC_SIZE. --- ports/esp32/modules/inisetup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/esp32/modules/inisetup.py b/ports/esp32/modules/inisetup.py index 00d9a4eab8..3196f0c6f3 100644 --- a/ports/esp32/modules/inisetup.py +++ b/ports/esp32/modules/inisetup.py @@ -2,7 +2,7 @@ import uos from flashbdev import bdev def check_bootsec(): - buf = bytearray(bdev.SEC_SIZE) + buf = bytearray(bdev.ioctl(5, 0)) # 5 is SEC_SIZE bdev.readblocks(0, buf) empty = True for b in buf: From c8c37ca4076f72b79d5ec65c22a3e3bc0c71f583 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 10 Sep 2019 21:31:53 +1000 Subject: [PATCH 0700/1788] stm32/boards/STM32F769DISC: Fix number of SDRAM row bits. According to the schematic, the SDRAM part on this board is a MT48LC4M32B2B5-6A, with "Row addressing 4K A[11:0]" (per datasheet). This commit updates mpconfigboard.h from 13 to 12 to match. --- ports/stm32/boards/STM32F769DISC/mpconfigboard.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h index 9a700d8e42..a34b58e1b2 100644 --- a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h @@ -100,7 +100,14 @@ void board_early_init(void); #define MICROPY_HW_ETH_RMII_TXD1 (pin_G14) #if 0 -// Optional SDRAM configuration; requires SYSCLK <= 200MHz +// Optional SDRAM configuration. + +// Note: This requires SYSCLK <= 200MHz. 192MHz example below: +// #define MICROPY_HW_CLK_PLLM (25) +// #define MICROPY_HW_CLK_PLLN (384) +// #define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +// #define MICROPY_HW_CLK_PLLQ (8) + #define MICROPY_HW_SDRAM_SIZE (128 * 1024 * 1024 / 8) // 128 Mbit #define MICROPY_HW_SDRAM_STARTUP_TEST (0) #define MICROPY_HEAP_START sdram_start() @@ -119,7 +126,7 @@ void board_early_init(void); #define MICROPY_HW_SDRAM_BURST_LENGTH 1 #define MICROPY_HW_SDRAM_CAS_LATENCY 2 #define MICROPY_HW_SDRAM_COLUMN_BITS_NUM 8 -#define MICROPY_HW_SDRAM_ROW_BITS_NUM 13 +#define MICROPY_HW_SDRAM_ROW_BITS_NUM 12 #define MICROPY_HW_SDRAM_MEM_BUS_WIDTH 32 #define MICROPY_HW_SDRAM_INTERN_BANKS_NUM 4 #define MICROPY_HW_SDRAM_CLOCK_PERIOD 2 From cfec0540732b6ce3e21d3a81f088dc6a328ff4d7 Mon Sep 17 00:00:00 2001 From: cristian Date: Fri, 6 Sep 2019 15:50:24 -0500 Subject: [PATCH 0701/1788] stm32/board/NUCLEO_F746ZG: Enable Ethernet periph, lwip and ussl. --- ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h | 11 +++++++++++ ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk | 5 +++++ ports/stm32/boards/NUCLEO_F746ZG/pins.csv | 9 +++++++++ 3 files changed, 25 insertions(+) diff --git a/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h index a9fbea5766..c9b0c60f27 100644 --- a/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h @@ -75,3 +75,14 @@ #define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) + +// Ethernet via RMII +#define MICROPY_HW_ETH_MDC (pin_C1) +#define MICROPY_HW_ETH_MDIO (pin_A2) +#define MICROPY_HW_ETH_RMII_REF_CLK (pin_A1) +#define MICROPY_HW_ETH_RMII_CRS_DV (pin_A7) +#define MICROPY_HW_ETH_RMII_RXD0 (pin_C4) +#define MICROPY_HW_ETH_RMII_RXD1 (pin_C5) +#define MICROPY_HW_ETH_RMII_TX_EN (pin_G11) +#define MICROPY_HW_ETH_RMII_TXD0 (pin_G13) +#define MICROPY_HW_ETH_RMII_TXD1 (pin_B13) diff --git a/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk index 160218fd33..8b54dc84e1 100644 --- a/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk @@ -4,3 +4,8 @@ AF_FILE = boards/stm32f746_af.csv LD_FILES = boards/stm32f746.ld boards/common_ifs.ld TEXT0_ADDR = 0x08000000 TEXT1_ADDR = 0x08020000 + +# MicroPython settings +MICROPY_PY_LWIP = 1 +MICROPY_PY_USSL = 1 +MICROPY_SSL_MBEDTLS = 1 diff --git a/ports/stm32/boards/NUCLEO_F746ZG/pins.csv b/ports/stm32/boards/NUCLEO_F746ZG/pins.csv index aa5143e8c5..c129f7417b 100644 --- a/ports/stm32/boards/NUCLEO_F746ZG/pins.csv +++ b/ports/stm32/boards/NUCLEO_F746ZG/pins.csv @@ -66,3 +66,12 @@ UART6_RX,PG9 SPI_B_NSS,PA4 SPI_B_SCK,PB3 SPI_B_MOSI,PB5 +ETH_MDC,PC1 +ETH_MDIO,PA2 +ETH_RMII_REF_CLK,PA1 +ETH_RMII_CRS_DV,PA7 +ETH_RMII_RXD0,PC4 +ETH_RMII_RXD1,PC5 +ETH_RMII_TX_EN,PG11 +ETH_RMII_TXD0,PG13 +ETH_RMII_TXD1,PB13 From 6705767da1f7dba7a04e1d16c380a650f1f1074f Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 6 Jul 2019 00:19:45 +1000 Subject: [PATCH 0702/1788] stm32/usb: Add support for VCP+MSC+HID mode, incl 2xVCP and 3xVCP. --- ports/stm32/usb.c | 56 +++++++++++++- ports/stm32/usb.h | 3 + ports/stm32/usbd_conf.h | 2 +- .../stm32/usbdev/class/inc/usbd_cdc_msc_hid.h | 14 +--- .../usbdev/class/inc/usbd_cdc_msc_hid0.h | 3 + .../stm32/usbdev/class/src/usbd_cdc_msc_hid.c | 75 ++++++++++++++++++- 6 files changed, 137 insertions(+), 16 deletions(-) diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index 791a6472a5..8b80629815 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -97,6 +97,14 @@ STATIC const uint8_t usbd_fifo_size_cdc1[] = { #endif }; +// RX; EP0(in), MSC/HID, CDC_CMD, CDC_DATA, HID +STATIC const uint8_t usbd_fifo_size_cdc1_msc_hid[] = { + 32, 8, 16, 4, 12, 8, 0, + #if MICROPY_HW_USB_HS + 116, 8, 64, 4, 56, 8, 0, 0, 0, 0, + #endif +}; + #if MICROPY_HW_USB_CDC_NUM >= 2 // RX; EP0(in), MSC/HID, CDC_CMD, CDC_DATA, CDC2_CMD, CDC2_DATA STATIC const uint8_t usbd_fifo_size_cdc2[] = { @@ -105,6 +113,14 @@ STATIC const uint8_t usbd_fifo_size_cdc2[] = { 116, 8, 64, 2, 32, 2, 32, 0, 0, 0, #endif }; + +// RX; EP0(in), MSC/HID, CDC_CMD, CDC_DATA, CDC2_CMD/HID, CDC2_DATA, HID +STATIC const uint8_t usbd_fifo_size_cdc2_msc_hid[] = { + 0, 0, 0, 0, 0, 0, 0, // FS: can't support 2xVCP+MSC+HID + #if MICROPY_HW_USB_HS + 102, 8, 64, 2, 32, 8, 32, 8, 0, 0, + #endif +}; #endif #if MICROPY_HW_USB_CDC_NUM >= 3 @@ -115,6 +131,14 @@ STATIC const uint8_t usbd_fifo_size_cdc3[] = { 82, 8, 64, 2, 32, 2, 32, 2, 32, 0, #endif }; + +// RX; EP0(in), MSC/HID, CDC_CMD, CDC_DATA, CDC2_CMD/HID, CDC2_DATA, CDC3_CMD/HID, CDC3_DATA, HID +STATIC const uint8_t usbd_fifo_size_cdc3_msc_hid[] = { + 0, 0, 0, 0, 0, 0, 0, // FS: can't support 3x VCP mode + #if MICROPY_HW_USB_HS + 82, 8, 64, 2, 25, 8, 25, 8, 25, 8, + #endif +}; #endif #endif @@ -242,14 +266,27 @@ bool pyb_usb_dev_init(int dev_id, uint16_t vid, uint16_t pid, uint8_t mode, size #endif const uint8_t *fifo_size = usbd_fifo_size_cdc1; + #if MICROPY_HW_USB_IS_MULTI_OTG + if ((mode & USBD_MODE_MSC_HID) == USBD_MODE_MSC_HID) { + fifo_size = usbd_fifo_size_cdc1_msc_hid; + } + #endif #if MICROPY_HW_USB_CDC_NUM >= 3 if (mode & USBD_MODE_IFACE_CDC(2)) { - fifo_size = usbd_fifo_size_cdc3; + if ((mode & USBD_MODE_MSC_HID) == USBD_MODE_MSC_HID) { + fifo_size = usbd_fifo_size_cdc3_msc_hid; + } else { + fifo_size = usbd_fifo_size_cdc3; + } } else #endif #if MICROPY_HW_USB_CDC_NUM >= 2 if (mode & USBD_MODE_IFACE_CDC(1)) { - fifo_size = usbd_fifo_size_cdc2; + if ((mode & USBD_MODE_MSC_HID) == USBD_MODE_MSC_HID) { + fifo_size = usbd_fifo_size_cdc2_msc_hid; + } else { + fifo_size = usbd_fifo_size_cdc2; + } } #endif @@ -414,6 +451,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_MSC; } mode = USBD_MODE_CDC_MSC; + } else if (strcmp(mode_str, "VCP+MSC+HID") == 0) { + if (pid == -1) { + pid = USBD_PID_CDC_MSC_HID; + } + mode = USBD_MODE_CDC_MSC_HID; #if MICROPY_HW_USB_CDC_NUM >= 2 } else if (strcmp(mode_str, "VCP+VCP") == 0) { if (pid == -1) { @@ -425,6 +467,11 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * pid = USBD_PID_CDC2_MSC; } mode = USBD_MODE_CDC2_MSC; + } else if (strcmp(mode_str, "2xVCP+MSC+HID") == 0) { + if (pid == -1) { + pid = USBD_PID_CDC2_MSC_HID; + } + mode = USBD_MODE_CDC2_MSC_HID; #endif #if MICROPY_HW_USB_CDC_NUM >= 3 } else if (strcmp(mode_str, "3xVCP") == 0) { @@ -437,6 +484,11 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * pid = USBD_PID_CDC3_MSC; } mode = USBD_MODE_CDC3_MSC; + } else if (strcmp(mode_str, "3xVCP+MSC+HID") == 0) { + if (pid == -1) { + pid = USBD_PID_CDC3_MSC_HID; + } + mode = USBD_MODE_CDC3_MSC_HID; #endif } else if (strcmp(mode_str, "CDC+HID") == 0 || strcmp(mode_str, "VCP+HID") == 0) { if (pid == -1) { diff --git a/ports/stm32/usb.h b/ports/stm32/usb.h index cb017902ec..457c7313c4 100644 --- a/ports/stm32/usb.h +++ b/ports/stm32/usb.h @@ -40,6 +40,9 @@ #define USBD_PID_CDC2 (0x9805) #define USBD_PID_CDC3 (0x9806) #define USBD_PID_CDC3_MSC (0x9807) +#define USBD_PID_CDC_MSC_HID (0x9808) +#define USBD_PID_CDC2_MSC_HID (0x9809) +#define USBD_PID_CDC3_MSC_HID (0x980a) typedef enum { PYB_USB_STORAGE_MEDIUM_NONE = 0, diff --git a/ports/stm32/usbd_conf.h b/ports/stm32/usbd_conf.h index 83629bfc4f..5237ba3a96 100644 --- a/ports/stm32/usbd_conf.h +++ b/ports/stm32/usbd_conf.h @@ -39,7 +39,7 @@ #include "py/mpconfig.h" -#define USBD_MAX_NUM_INTERFACES 5 +#define USBD_MAX_NUM_INTERFACES 8 #define USBD_MAX_NUM_CONFIGURATION 1 #define USBD_MAX_STR_DESC_SIZ 0x100 #if MICROPY_HW_USB_SELF_POWERED 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 a01e75bed5..f3edc4dcb4 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h @@ -18,16 +18,8 @@ #endif // Should be maximum of possible config descriptors that might be configured -#if MICROPY_HW_USB_CDC_NUM == 3 -// Maximum is MSC+CDC+CDC+CDC -#define MAX_TEMPLATE_CONFIG_DESC_SIZE (9 + 23 + (8 + 58) + (8 + 58) + (8 + 58)) -#elif MICROPY_HW_USB_CDC_NUM == 2 -// Maximum is MSC+CDC+CDC -#define MAX_TEMPLATE_CONFIG_DESC_SIZE (9 + 23 + (8 + 58) + (8 + 58)) -#else -// Maximum is HID+CDC -#define MAX_TEMPLATE_CONFIG_DESC_SIZE (9 + 32 + (8 + 58)) -#endif +// Maximum is: 9 + MSC + NxCDC + HID +#define MAX_TEMPLATE_CONFIG_DESC_SIZE (9 + (23) + MICROPY_HW_USB_CDC_NUM * (8 + 58) + (9 + 9 + 7 + 7)) // CDC, MSC and HID packet sizes #define MSC_FS_MAX_PACKET (64) @@ -118,7 +110,7 @@ typedef struct _usbd_cdc_msc_hid_state_t { USBD_HandleTypeDef *pdev; uint8_t usbd_mode; - uint8_t usbd_config_desc_size; + uint16_t usbd_config_desc_size; #if MICROPY_HW_USB_MSC USBD_MSC_BOT_HandleTypeDef MSC_BOT_ClassData; 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 63fe8ecefc..7614dde691 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h @@ -44,6 +44,9 @@ #define USBD_MODE_CDC_MSC (USBD_MODE_IFACE_CDC(0) | USBD_MODE_IFACE_MSC) #define USBD_MODE_CDC2_MSC (USBD_MODE_IFACE_CDC(0) | USBD_MODE_IFACE_CDC(1) | USBD_MODE_IFACE_MSC) #define USBD_MODE_CDC3_MSC (USBD_MODE_IFACE_CDC(0) | USBD_MODE_IFACE_CDC(1) | USBD_MODE_IFACE_CDC(2) | USBD_MODE_IFACE_MSC) +#define USBD_MODE_CDC_MSC_HID (USBD_MODE_IFACE_CDC(0) | USBD_MODE_IFACE_MSC | USBD_MODE_IFACE_HID) +#define USBD_MODE_CDC2_MSC_HID (USBD_MODE_IFACE_CDC(0) | USBD_MODE_IFACE_CDC(1) | USBD_MODE_IFACE_MSC | USBD_MODE_IFACE_HID) +#define USBD_MODE_CDC3_MSC_HID (USBD_MODE_IFACE_CDC(0) | USBD_MODE_IFACE_CDC(1) | USBD_MODE_IFACE_CDC(2) | USBD_MODE_IFACE_MSC | USBD_MODE_IFACE_HID) #define USBD_MODE_HID (USBD_MODE_IFACE_HID) #define USBD_MODE_MSC (USBD_MODE_IFACE_MSC) #define USBD_MODE_MSC_HID (USBD_MODE_IFACE_MSC | USBD_MODE_IFACE_HID) 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 e13a93ddbc..938c8e7115 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -61,9 +61,11 @@ #define HID_DESC_OFFSET_PROTOCOL (7) #define HID_DESC_OFFSET_SUBDESC (9) #define HID_DESC_OFFSET_REPORT_DESC_LEN (16) +#define HID_DESC_OFFSET_IN_EP (20) #define HID_DESC_OFFSET_MAX_PACKET_LO (22) #define HID_DESC_OFFSET_MAX_PACKET_HI (23) #define HID_DESC_OFFSET_POLLING_INTERVAL (24) +#define HID_DESC_OFFSET_OUT_EP (27) #define HID_DESC_OFFSET_MAX_PACKET_OUT_LO (29) #define HID_DESC_OFFSET_MAX_PACKET_OUT_HI (30) #define HID_DESC_OFFSET_POLLING_INTERVAL_OUT (31) @@ -79,6 +81,9 @@ #define MSC_IFACE_NUM_WITH_CDC (0) #define HID_IFACE_NUM_WITH_CDC (0) #define HID_IFACE_NUM_WITH_MSC (1) +#define HID_IFACE_NUM_WITH_CDC_MSC (3) +#define HID_IFACE_NUM_WITH_CDC2_MSC (5) +#define HID_IFACE_NUM_WITH_CDC3_MSC (7) #define CDC_IN_EP(i) (0x83 + 2 * (i)) #define CDC_OUT_EP(i) (0x03 + 2 * (i)) @@ -88,6 +93,12 @@ #define HID_OUT_EP_WITH_CDC (0x01) #define HID_IN_EP_WITH_MSC (0x83) #define HID_OUT_EP_WITH_MSC (0x03) +#define HID_IN_EP_WITH_CDC_MSC (0x84) +#define HID_OUT_EP_WITH_CDC_MSC (0x04) +#define HID_IN_EP_WITH_CDC2_MSC (0x86) +#define HID_OUT_EP_WITH_CDC2_MSC (0x06) +#define HID_IN_EP_WITH_CDC3_MSC (0x88) +#define HID_OUT_EP_WITH_CDC3_MSC (0x08) #define USB_DESC_TYPE_ASSOCIATION (0x0b) @@ -448,8 +459,9 @@ static size_t make_cdc_desc_ep(uint8_t *dest, int need_iad, uint8_t iface_num, u #endif #if MICROPY_HW_USB_HID -static size_t make_hid_desc(uint8_t *dest, USBD_HID_ModeInfoTypeDef *hid_info) { +static size_t make_hid_desc(uint8_t *dest, USBD_HID_ModeInfoTypeDef *hid_info, uint8_t iface_num) { memcpy(dest, hid_class_desc_data, sizeof(hid_class_desc_data)); + dest[2] = iface_num; dest[HID_DESC_OFFSET_SUBCLASS] = hid_info->subclass; dest[HID_DESC_OFFSET_PROTOCOL] = hid_info->protocol; dest[HID_DESC_OFFSET_REPORT_DESC_LEN] = hid_info->report_desc_len; @@ -461,6 +473,15 @@ static size_t make_hid_desc(uint8_t *dest, USBD_HID_ModeInfoTypeDef *hid_info) { dest[HID_DESC_OFFSET_POLLING_INTERVAL_OUT] = hid_info->polling_interval; return sizeof(hid_class_desc_data); } + +#if MICROPY_HW_USB_MSC +static size_t make_hid_desc_ep(uint8_t *dest, USBD_HID_ModeInfoTypeDef *hid_info, uint8_t iface_num, uint8_t in_ep, uint8_t out_ep) { + size_t n = make_hid_desc(dest, hid_info, iface_num); + dest[HID_DESC_OFFSET_IN_EP] = in_ep; + dest[HID_DESC_OFFSET_OUT_EP] = out_ep; + return n; +} +#endif #endif // return the saved usb mode @@ -489,6 +510,21 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode usbd->cdc[0]->iface_num = CDC_IFACE_NUM_WITH_MSC; num_itf = 3; break; + + #if MICROPY_HW_USB_HID + case USBD_MODE_CDC_MSC_HID: + n += make_msc_desc(d + n); + n += make_cdc_desc(d + n, 1, CDC_IFACE_NUM_WITH_MSC); + usbd->hid->desc = d + n; + n += make_hid_desc_ep(d + n, hid_info, HID_IFACE_NUM_WITH_CDC_MSC, HID_IN_EP_WITH_CDC_MSC, HID_OUT_EP_WITH_CDC_MSC); + usbd->cdc[0]->iface_num = CDC_IFACE_NUM_WITH_MSC; + usbd->hid->in_ep = HID_IN_EP_WITH_CDC_MSC; + usbd->hid->out_ep = HID_OUT_EP_WITH_CDC_MSC; + usbd->hid->iface_num = HID_IFACE_NUM_WITH_CDC_MSC; + usbd->hid->report_desc = hid_info->report_desc; + num_itf = 4; + break; + #endif #endif #if MICROPY_HW_USB_CDC_NUM >= 2 @@ -511,6 +547,23 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode num_itf = 5; break; } + + case USBD_MODE_CDC2_MSC_HID: { + n += make_msc_desc(d + n); + n += make_cdc_desc(d + n, 1, CDC_IFACE_NUM_WITH_MSC); + n += make_cdc_desc_ep(d + n, 1, CDC2_IFACE_NUM_WITH_MSC, CDC_CMD_EP(1), CDC_OUT_EP(1), CDC_IN_EP(1)); + usbd->hid->desc = d + n; + n += make_hid_desc_ep(d + n, hid_info, HID_IFACE_NUM_WITH_CDC2_MSC, HID_IN_EP_WITH_CDC2_MSC, HID_OUT_EP_WITH_CDC2_MSC); + usbd->cdc[0]->iface_num = CDC_IFACE_NUM_WITH_MSC; + usbd->cdc[1]->iface_num = CDC2_IFACE_NUM_WITH_MSC; + usbd->cdc[2]->iface_num = CDC3_IFACE_NUM_WITH_MSC; + usbd->hid->in_ep = HID_IN_EP_WITH_CDC2_MSC; + usbd->hid->out_ep = HID_OUT_EP_WITH_CDC2_MSC; + usbd->hid->iface_num = HID_IFACE_NUM_WITH_CDC2_MSC; + usbd->hid->report_desc = hid_info->report_desc; + num_itf = 6; + break; + } #endif #endif @@ -538,13 +591,31 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode num_itf = 7; break; } + + case USBD_MODE_CDC3_MSC_HID: { + n += make_msc_desc(d + n); + n += make_cdc_desc(d + n, 1, CDC_IFACE_NUM_WITH_MSC); + n += make_cdc_desc_ep(d + n, 1, CDC2_IFACE_NUM_WITH_MSC, CDC_CMD_EP(1), CDC_OUT_EP(1), CDC_IN_EP(1)); + n += make_cdc_desc_ep(d + n, 1, CDC3_IFACE_NUM_WITH_MSC, CDC_CMD_EP(2), CDC_OUT_EP(2), CDC_IN_EP(2)); + usbd->hid->desc = d + n; + n += make_hid_desc_ep(d + n, hid_info, HID_IFACE_NUM_WITH_CDC3_MSC, HID_IN_EP_WITH_CDC3_MSC, HID_OUT_EP_WITH_CDC3_MSC); + usbd->cdc[0]->iface_num = CDC_IFACE_NUM_WITH_MSC; + usbd->cdc[1]->iface_num = CDC2_IFACE_NUM_WITH_MSC; + usbd->cdc[2]->iface_num = CDC3_IFACE_NUM_WITH_MSC; + usbd->hid->in_ep = HID_IN_EP_WITH_CDC3_MSC; + usbd->hid->out_ep = HID_OUT_EP_WITH_CDC3_MSC; + usbd->hid->iface_num = HID_IFACE_NUM_WITH_CDC3_MSC; + usbd->hid->report_desc = hid_info->report_desc; + num_itf = 8; + break; + } #endif #endif #if MICROPY_HW_USB_HID case USBD_MODE_CDC_HID: usbd->hid->desc = d + n; - n += make_hid_desc(d + n, hid_info); + n += make_hid_desc(d + n, hid_info, HID_IFACE_NUM_WITH_CDC); n += make_cdc_desc(d + n, 1, CDC_IFACE_NUM_WITH_HID); usbd->cdc[0]->iface_num = CDC_IFACE_NUM_WITH_HID; usbd->hid->in_ep = HID_IN_EP_WITH_CDC; From bcaafa382323c5d15988f20782c2737f05a4c002 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 11 Sep 2019 14:59:02 +1000 Subject: [PATCH 0703/1788] stm32/usb: Verify number of used endpoints doesn't exceed maximum. --- ports/stm32/usb.c | 15 ++++++++++++++- ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h | 2 +- ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c | 13 ++++++++++++- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index 8b80629815..ca5cc682ec 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -57,6 +57,19 @@ #endif #endif +// Maximum number of endpoints (excluding EP0) +#if defined(STM32L0) || defined(STM32WB) +#define MAX_ENDPOINT(dev_id) (7) +#elif defined(STM32L4) +#define MAX_ENDPOINT(dev_id) (5) +#elif defined(STM32F4) +#define MAX_ENDPOINT(dev_id) ((dev_id) == USB_PHY_FS_ID ? 3 : 5) +#elif defined(STM32F7) +#define MAX_ENDPOINT(dev_id) ((dev_id) == USB_PHY_FS_ID ? 5 : 8) +#elif defined(STM32H7) +#define MAX_ENDPOINT(dev_id) (8) +#endif + STATIC void pyb_usb_vcp_init0(void); // this will be persistent across a soft-reset @@ -240,7 +253,7 @@ bool pyb_usb_dev_init(int dev_id, uint16_t vid, uint16_t pid, uint8_t mode, size // configure the VID, PID and the USBD mode (interfaces it will expose) int cdc_only = (mode & USBD_MODE_IFACE_MASK) == USBD_MODE_CDC; USBD_SetVIDPIDRelease(&usb_dev->usbd_cdc_msc_hid_state, vid, pid, 0x0200, cdc_only); - if (USBD_SelectMode(&usb_dev->usbd_cdc_msc_hid_state, mode, hid_info) != 0) { + if (USBD_SelectMode(&usb_dev->usbd_cdc_msc_hid_state, mode, hid_info, MAX_ENDPOINT(dev_id)) != 0) { return false; } 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 f3edc4dcb4..d934f4676c 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h @@ -165,7 +165,7 @@ static inline uint32_t usbd_cdc_max_packet(USBD_HandleTypeDef *pdev) { } // 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); +int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_ModeInfoTypeDef *hid_info, uint8_t max_endpoint); // returns the current usb mode uint8_t USBD_GetMode(usbd_cdc_msc_hid_state_t *usbd); 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 938c8e7115..0b94076543 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -489,7 +489,7 @@ uint8_t USBD_GetMode(usbd_cdc_msc_hid_state_t *usbd) { return usbd->usbd_mode; } -int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_ModeInfoTypeDef *hid_info) { +int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_ModeInfoTypeDef *hid_info, uint8_t max_endpoint) { // save mode usbd->usbd_mode = mode; @@ -656,6 +656,17 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode } } + // Verify that the endpoints that are used fit within the maximum number + d = usbd->usbd_config_desc; + const uint8_t *d_top = d + n; + while (d < d_top) { + if (d[0] == 7 && d[1] == USB_DESC_TYPE_ENDPOINT && (d[2] & 0x7f) > max_endpoint) { + // Endpoint out of range of hardware + return -1; + } + d += d[0]; + } + return 0; } From cb84e22ac6b1356986f63f5b6db95493da81fa5f Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 11 Sep 2019 15:16:19 +1000 Subject: [PATCH 0704/1788] docs/library/pyb.rst: Update pyb.usb_mode() to mention VCP+MSC+HID. --- docs/library/pyb.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/library/pyb.rst b/docs/library/pyb.rst index acb8fe450e..9ba7e991e5 100644 --- a/docs/library/pyb.rst +++ b/docs/library/pyb.rst @@ -271,6 +271,7 @@ Miscellaneous functions - ``'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) + - ``'VCP+MSC+HID'``: enabled with VCP, MSC and HID (only available on PYBD boards) For backwards compatibility, ``'CDC'`` is understood to mean ``'VCP'`` (and similarly for ``'CDC+MSC'`` and ``'CDC+HID'``). From b0e17bbb9d804b04a566b809c19acd5128f972e5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 12 Sep 2019 18:05:27 +1000 Subject: [PATCH 0705/1788] stm32/lwip_inc: Allocate additional MEMP_SYS_TIMEOUT when mDNS enabled. Since v2.1 of lwIP mDNS uses a MEMP_SYS_TIMEOUT slot, so allocate an extra one when this feature is enabled. --- ports/stm32/lwip_inc/lwipopts.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ports/stm32/lwip_inc/lwipopts.h b/ports/stm32/lwip_inc/lwipopts.h index c9bbde92f7..4ad1ae0083 100644 --- a/ports/stm32/lwip_inc/lwipopts.h +++ b/ports/stm32/lwip_inc/lwipopts.h @@ -32,8 +32,9 @@ #define LWIP_MDNS_RESPONDER 1 #define LWIP_IGMP 1 -#define LWIP_NUM_NETIF_CLIENT_DATA 1 // mDNS responder requires 1 -#define MEMP_NUM_UDP_PCB 5 // mDNS responder requires 1 +#define LWIP_NUM_NETIF_CLIENT_DATA LWIP_MDNS_RESPONDER +#define MEMP_NUM_UDP_PCB (4 + LWIP_MDNS_RESPONDER) +#define MEMP_NUM_SYS_TIMEOUT (LWIP_NUM_SYS_TIMEOUT_INTERNAL + LWIP_MDNS_RESPONDER) #define SO_REUSE 1 #define TCP_LISTEN_BACKLOG 1 From f66616556db608d8ca89889340283c532d5c4da0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 12 Sep 2019 18:08:50 +1000 Subject: [PATCH 0706/1788] stm32/lwip_inc: Enable LWIP_NETIF_EXT_STATUS_CALLBACK for mDNS. This feature makes sure that mDNS is automatically restarted when there is any change event on a netif. --- ports/stm32/lwip_inc/lwipopts.h | 1 + ports/stm32/modnetwork.c | 7 ------- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/ports/stm32/lwip_inc/lwipopts.h b/ports/stm32/lwip_inc/lwipopts.h index 4ad1ae0083..7b2460fa80 100644 --- a/ports/stm32/lwip_inc/lwipopts.h +++ b/ports/stm32/lwip_inc/lwipopts.h @@ -22,6 +22,7 @@ #define LWIP_SOCKET 0 #define LWIP_STATS 0 #define LWIP_NETIF_HOSTNAME 1 +#define LWIP_NETIF_EXT_STATUS_CALLBACK 1 #define LWIP_IPV6 0 #define LWIP_DHCP 1 diff --git a/ports/stm32/modnetwork.c b/ports/stm32/modnetwork.c index 80e5a5a162..13ecf444f0 100644 --- a/ports/stm32/modnetwork.c +++ b/ports/stm32/modnetwork.c @@ -189,10 +189,6 @@ mp_obj_t mod_network_nic_ifconfig(struct netif *netif, size_t n_args, const mp_o mp_hal_delay_ms(100); } - #if LWIP_MDNS_RESPONDER - mdns_resp_netif_settings_changed(netif); - #endif - return mp_const_none; } else { // Release and stop any existing DHCP @@ -207,9 +203,6 @@ mp_obj_t mod_network_nic_ifconfig(struct netif *netif, size_t n_args, const mp_o ip_addr_t dns; netutils_parse_ipv4_addr(items[3], (uint8_t*)&dns, NETUTILS_BIG); dns_setserver(0, &dns); - #if LWIP_MDNS_RESPONDER - mdns_resp_netif_settings_changed(netif); - #endif return mp_const_none; } } From 6e07fde895ba84281f2e3efd82145a4e1b8a4a1d Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 11 Sep 2019 15:47:52 +1000 Subject: [PATCH 0707/1788] py/mkrules.mk: Add QSTR_GLOBAL_REQUIREMENTS variable for qstr auto-gen. --- py/mkrules.mk | 2 +- py/py.mk | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/py/mkrules.mk b/py/mkrules.mk index 7690c54092..b74dd45495 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -70,7 +70,7 @@ $(OBJ): | $(HEADER_BUILD)/qstrdefs.generated.h $(HEADER_BUILD)/mpversion.h # - 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 +$(HEADER_BUILD)/qstr.i.last: $(SRC_QSTR) $(QSTR_GLOBAL_DEPENDENCIES) | $(QSTR_GLOBAL_REQUIREMENTS) $(ECHO) "GEN $@" $(Q)$(CPP) $(QSTR_GEN_EXTRA_CFLAGS) $(CFLAGS) $(if $(filter $?,$(QSTR_GLOBAL_DEPENDENCIES)),$^,$(if $?,$?,$^)) >$(HEADER_BUILD)/qstr.i.last diff --git a/py/py.mk b/py/py.mk index d60e694ec2..a3d9e790fc 100644 --- a/py/py.mk +++ b/py/py.mk @@ -13,8 +13,10 @@ 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 +# Any files listed by these variables will cause a full regeneration of qstrs +# DEPENDENCIES: included in qstr processing; REQUIREMENTS: not included QSTR_GLOBAL_DEPENDENCIES += $(PY_SRC)/mpconfig.h mpconfigport.h +QSTR_GLOBAL_REQUIREMENTS += $(HEADER_BUILD)/mpversion.h # some code is performance bottleneck and compiled with other optimization options CSUPEROPT = -O3 From 356a728bd0819de503c892a8f1ba55d0bea43a23 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 11 Sep 2019 15:49:24 +1000 Subject: [PATCH 0708/1788] esp32/Makefile: Add SDKCONFIG_H to QSTR_GLOBAL_REQUIREMENTS. Fixes issue #5091. --- ports/esp32/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 1e02984520..3e48febf0e 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -25,6 +25,7 @@ include $(BOARD_DIR)/mpconfigboard.mk # qstr definitions (must come before including py.mk) QSTR_DEFS = qstrdefsport.h QSTR_GLOBAL_DEPENDENCIES = $(BOARD_DIR)/mpconfigboard.h +QSTR_GLOBAL_REQUIREMENTS = $(SDKCONFIG_H) MICROPY_PY_USSL = 0 MICROPY_SSL_AXTLS = 0 From 22099ab88fe054c41090634d096fef7949af2971 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 12 Sep 2019 19:10:12 +1000 Subject: [PATCH 0709/1788] stm32/machine_adc: Fix build for F4 and L4 MCUs that only have ADC1. --- ports/stm32/machine_adc.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/ports/stm32/machine_adc.c b/ports/stm32/machine_adc.c index 416beeca4c..3aacae77ba 100644 --- a/ports/stm32/machine_adc.c +++ b/ports/stm32/machine_adc.c @@ -33,6 +33,12 @@ #define ADC_V2 (0) #endif +#if defined(STM32F4) || defined(STM32L4) +#define ADCx_COMMON ADC_COMMON_REGISTER(0) +#elif defined(STM32F7) +#define ADCx_COMMON ADC123_COMMON +#endif + #if defined(STM32F0) || defined(STM32L0) #define ADC_STAB_DELAY_US (1) #define ADC_TEMPSENSOR_DELAY_US (10) @@ -122,7 +128,7 @@ STATIC void adc_config(ADC_TypeDef *adc, uint32_t bits) { #if defined(STM32F0) adc->CFGR2 = 1 << ADC_CFGR2_CKMODE_Pos; // PCLK/2 (synchronous clock mode) #elif defined(STM32F4) || defined(STM32F7) || defined(STM32L4) - ADC123_COMMON->CCR = 0; // ADCPR=PCLK/2 + ADCx_COMMON->CCR = 0; // ADCPR=PCLK/2 #elif defined(STM32H7) ADC12_COMMON->CCR = 3 << ADC_CCR_CKMODE_Pos; ADC3_COMMON->CCR = 3 << ADC_CCR_CKMODE_Pos; @@ -255,12 +261,12 @@ STATIC void adc_config_channel(ADC_TypeDef *adc, uint32_t channel, uint32_t samp #elif defined(STM32F4) || defined(STM32F7) if (channel == ADC_CHANNEL_VREFINT || channel == ADC_CHANNEL_TEMPSENSOR) { - ADC123_COMMON->CCR = (ADC123_COMMON->CCR & ~ADC_CCR_VBATE) | ADC_CCR_TSVREFE; + ADCx_COMMON->CCR = (ADCx_COMMON->CCR & ~ADC_CCR_VBATE) | ADC_CCR_TSVREFE; if (channel == ADC_CHANNEL_TEMPSENSOR) { adc_stabilisation_delay_us(ADC_TEMPSENSOR_DELAY_US); } } else if (channel == ADC_CHANNEL_VBAT) { - ADC123_COMMON->CCR |= ADC_CCR_VBATE; + ADCx_COMMON->CCR |= ADC_CCR_VBATE; } adc->SQR3 = (channel & 0x1f) << ADC_SQR3_SQ1_Pos; // select channel for first conversion @@ -280,7 +286,7 @@ STATIC void adc_config_channel(ADC_TypeDef *adc, uint32_t channel, uint32_t samp adc->PCSEL |= 1 << channel; ADC_Common_TypeDef *adc_common = adc == ADC3 ? ADC3_COMMON : ADC12_COMMON; #elif defined(STM32L4) - ADC_Common_TypeDef *adc_common = ADC123_COMMON; + ADC_Common_TypeDef *adc_common = ADCx_COMMON; #elif defined(STM32WB) ADC_Common_TypeDef *adc_common = ADC1_COMMON; #endif @@ -348,16 +354,17 @@ typedef struct _machine_adc_obj_t { STATIC void machine_adc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { machine_adc_obj_t *self = MP_OBJ_TO_PTR(self_in); - #if defined(STM32F0) || defined(STM32L0) || defined(STM32WB) unsigned adc_id = 1; - #else - unsigned adc_id = (self->adc - ADC1) / (ADC2 - ADC1) + 1; - #if defined(STM32H7) + #if defined(ADC2) + if (self->adc == ADC2) { + adc_id = 2; + } + #endif + #if defined(ADC3) if (self->adc == ADC3) { adc_id = 3; } #endif - #endif mp_printf(print, "", adc_id, self->channel); } From ac112f88d0496d33a9195ace02ed3928fcb015d3 Mon Sep 17 00:00:00 2001 From: roland van straten Date: Tue, 10 Sep 2019 23:01:27 +0200 Subject: [PATCH 0710/1788] nrf/boards: Add board definition for uBlox Nina B1 series BLE modules. --- ports/nrf/README.md | 2 + ports/nrf/boards/evk_nina_b1/mpconfigboard.h | 72 +++++++++++++++++++ ports/nrf/boards/evk_nina_b1/mpconfigboard.mk | 7 ++ ports/nrf/boards/evk_nina_b1/pins.csv | 41 +++++++++++ 4 files changed, 122 insertions(+) create mode 100644 ports/nrf/boards/evk_nina_b1/mpconfigboard.h create mode 100644 ports/nrf/boards/evk_nina_b1/mpconfigboard.mk create mode 100644 ports/nrf/boards/evk_nina_b1/pins.csv diff --git a/ports/nrf/README.md b/ports/nrf/README.md index df5904eb61..49642f00e9 100644 --- a/ports/nrf/README.md +++ b/ports/nrf/README.md @@ -36,6 +36,7 @@ This is a port of MicroPython to the Nordic Semiconductor nRF series of chips. * [Arduino Primo](http://www.arduino.org/products/boards/arduino-primo) * [IBK-BLYST-NANO breakout board](https://www.crowdsupply.com/i-syst/blyst-nano) * [BLUEIO-TAG-EVIM BLYST Nano Sensor board](https://www.crowdsupply.com/i-syst/blyst-nano) + * [uBlox EVK-NINA-B1](https://www.u-blox.com/en/product/evk-nina-b1) * nRF52840 * [PCA10056](http://www.nordicsemi.com/eng/Products/nRF52840-Preview-DK) * [Particle Xenon](https://docs.particle.io/xenon/) @@ -126,6 +127,7 @@ arduino_primo | s132 | Peripheral and Central | [PyOCD ibk_blyst_nano | s132 | Peripheral and Central | [IDAP](#idap-midap-link-targets) idk_blyst_nano | s132 | Peripheral and Central | [IDAP](#idap-midap-link-targets) blueio_tag_evim | s132 | Peripheral and Central | [IDAP](#idap-midap-link-targets) +evk_nina_b1 | s132 | Peripheral and Central | [Segger](#segger-targets) pca10056 | s140 | Peripheral and Central | [Segger](#segger-targets) particle_xenon | s140 | Peripheral and Central | [Black Magic Probe](#black-magic-probe-targets) diff --git a/ports/nrf/boards/evk_nina_b1/mpconfigboard.h b/ports/nrf/boards/evk_nina_b1/mpconfigboard.h new file mode 100644 index 0000000000..ced6b8cb1f --- /dev/null +++ b/ports/nrf/boards/evk_nina_b1/mpconfigboard.h @@ -0,0 +1,72 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Roland van Straten + * + * 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. + */ + +// Datasheet for board: +// https://www.u-blox.com/sites/default/files/EVK-NINA-B1_UserGuide_%28UBX-15028120%29.pdf +#define MICROPY_HW_BOARD_NAME "EVK_NINA_B1" +#define MICROPY_HW_MCU_NAME "NRF52832" +#define MICROPY_PY_SYS_PLATFORM "nrf52" + +#define MICROPY_PY_MACHINE_UART (1) +#define MICROPY_PY_MACHINE_HW_SPI (1) +#define MICROPY_PY_MACHINE_TIMER (1) +#define MICROPY_PY_MACHINE_RTCOUNTER (1) +#define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_ADC (1) +#define MICROPY_PY_MACHINE_TEMP (1) +#define MICROPY_PY_RANDOM_HW_RNG (1) + +#define MICROPY_HW_HAS_LED (1) +#define MICROPY_HW_LED_TRICOLOR (1) +#define MICROPY_HW_LED_PULLUP (1) + +#define MICROPY_HW_LED_RED (8) // LED1 DS8 Red +#define MICROPY_HW_LED_GREEN (16) // LED2 DS8 Green +#define MICROPY_HW_LED_BLUE (18) // LED3 DS8 Blue +// LEDs conflict with UART +//#define MICROPY_HW_LED4 (7) // DS1 Green +//#define MICROPY_HW_LED5 (31) // DS2 Orange +//#define MICROPY_HW_LED6 (5) // DS7 Green +//#define MICROPY_HW_LED7 (6) // DS8 Orange + +// UART config +#define MICROPY_HW_UART1_RX (5) +#define MICROPY_HW_UART1_TX (6) +#define MICROPY_HW_UART1_CTS (7) +#define MICROPY_HW_UART1_RTS (31) +#define MICROPY_HW_UART1_HWFC (1) + +// SPI0 config +#define MICROPY_HW_SPI0_NAME "SPI0" +#define MICROPY_HW_SPI0_SCK (14) +#define MICROPY_HW_SPI0_MOSI (13) +#define MICROPY_HW_SPI0_MISO (12) + +#define MICROPY_HW_PWM0_NAME "PWM0" +#define MICROPY_HW_PWM1_NAME "PWM1" +#define MICROPY_HW_PWM2_NAME "PWM2" + +#define HELP_TEXT_BOARD_LED "1,2,3" diff --git a/ports/nrf/boards/evk_nina_b1/mpconfigboard.mk b/ports/nrf/boards/evk_nina_b1/mpconfigboard.mk new file mode 100644 index 0000000000..db64a60dd3 --- /dev/null +++ b/ports/nrf/boards/evk_nina_b1/mpconfigboard.mk @@ -0,0 +1,7 @@ +MCU_SERIES = m4 +MCU_VARIANT = nrf52 +MCU_SUB_VARIANT = nrf52832 +SOFTDEV_VERSION = 6.1.1 +LD_FILES += boards/nrf52832_512k_64k.ld + +NRF_DEFINES += -DNRF52832_XXAA diff --git a/ports/nrf/boards/evk_nina_b1/pins.csv b/ports/nrf/boards/evk_nina_b1/pins.csv new file mode 100644 index 0000000000..876c7ddc1a --- /dev/null +++ b/ports/nrf/boards/evk_nina_b1/pins.csv @@ -0,0 +1,41 @@ +A0,P3,ADC0_IN1 +A1,P2,ADC0_IN0 +A2,P4,ADC0_IN2 +A3,P30,ADC0_IN6 +A4,P29,ADC0_IN5 +A5,P28,ADC0_IN4 +LED1,P8 +LED2,P16 +LED3,P18 +SW2,P30 +UART1_RX,P5 +UART1_TX,P6 +UART1_CTS,P7 +UART1_RTS,P8 +SDA,P2 +SCL,P3 +NFC1,P9 +NFC2,P10 +D0,P5 +D1,P6 +D2,P7 +D3,P31 +D4,P18 +D6,P9 +D7,P10 +D9,P8 +D10,P11 +D11,P13 +D12,P12 +D13,P14 +P15,P15 +P17,P17 +P19,P19 +P20,P20 +P21,P21 +P22,P22 +P23,P23 +P24,P24 +P25,P25 +P26,P26 +P27,P27 From b45f9de8096f37a5f588f833e6b6a00b59e67e3f Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 12 Sep 2019 22:14:51 +1000 Subject: [PATCH 0711/1788] bare-arm, minimal: Set CSUPEROPT=-Os to get minimal firmware size. This option affects py/vm.c and py/gc.c and using -Os gets them compiling a bit smaller, and small firmware is the aim of these two ports. Also, having these files compiled with -Os on these ports, and -O3 as the default on other ports, gives a better understanding of code-size changes when making changes to these files. --- ports/bare-arm/Makefile | 1 + ports/minimal/Makefile | 2 ++ 2 files changed, 3 insertions(+) diff --git a/ports/bare-arm/Makefile b/ports/bare-arm/Makefile index a515db80e0..7cb3432819 100644 --- a/ports/bare-arm/Makefile +++ b/ports/bare-arm/Makefile @@ -14,6 +14,7 @@ INC += -I$(BUILD) CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -mabi=aapcs-linux -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -fsingle-precision-constant -Wdouble-promotion CFLAGS = $(INC) -Wall -Werror -std=c99 -nostdlib $(CFLAGS_CORTEX_M4) $(COPT) +CSUPEROPT = -Os # save some code space #Debugging/Optimization ifeq ($(DEBUG), 1) diff --git a/ports/minimal/Makefile b/ports/minimal/Makefile index b3e27509f1..f26a7ec97d 100644 --- a/ports/minimal/Makefile +++ b/ports/minimal/Makefile @@ -28,6 +28,8 @@ CFLAGS = -m32 $(INC) -Wall -Werror -std=c99 $(COPT) LDFLAGS = -m32 -Wl,-Map=$@.map,--cref -Wl,--gc-sections endif +CSUPEROPT = -Os # save some code space + # Tune for Debugging or Optimization ifeq ($(DEBUG), 1) CFLAGS += -O0 -ggdb From 96008ff59a8af9883af17d01b951029d9d02eec9 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Fri, 13 Sep 2019 23:04:13 +1000 Subject: [PATCH 0712/1788] esp32: Support building with ESP IDF 4.0-beta1. This commit adds support for a second supported hash (currently set to the 4.0-beta1 tag). When this hash is detected, the relevant changes are applied. This allows to start using v4 features (e.g. BLE with Nimble), and also start doing testing, while still supporting the original, stable, v3.3 IDF. Note: this feature is experimental, not well tested, and network.LAN and network.PPP are currently unsupported. --- ports/esp32/Makefile | 198 +++++++++++++++++--- ports/esp32/boards/TINYPICO/sdkconfig.board | 1 + ports/esp32/boards/sdkconfig.base | 11 +- ports/esp32/boards/sdkconfig.spiram | 6 +- ports/esp32/esp32_ulp.c | 4 + ports/esp32/main.c | 12 +- ports/esp32/modesp.c | 2 + ports/esp32/modmachine.c | 6 + ports/esp32/modnetwork.c | 18 +- ports/esp32/modsocket.c | 48 +++-- ports/esp32/mpconfigport.h | 3 + ports/esp32/mphalport.c | 5 + ports/esp32/mpthreadport.c | 3 + ports/esp32/network_lan.c | 3 + ports/esp32/network_ppp.c | 3 + 15 files changed, 266 insertions(+), 57 deletions(-) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 3e48febf0e..25001643ee 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -50,7 +50,13 @@ SDKCONFIG_COMBINED = $(BUILD)/sdkconfig.combined SDKCONFIG_H = $(BUILD)/sdkconfig.h # the git hash of the currently supported ESP IDF version -ESPIDF_SUPHASH := 6ccb4cf5b7d1fdddb8c2492f9cbc926abaf230df +ESPIDF_SUPHASH_V3 := 6ccb4cf5b7d1fdddb8c2492f9cbc926abaf230df +ESPIDF_SUPHASH_V4 := 310beae373446ceb9a4ad9b36b5428d7fdf2705f + +define print_supported_git_hash +$(info Supported git hash (v3.3): $(ESPIDF_SUPHASH_V3)) +$(info Supported git hash (v4.0-beta1) (experimental): $(ESPIDF_SUPHASH_V4)) +endef # paths to ESP IDF and its components ifeq ($(ESPIDF),) @@ -59,10 +65,11 @@ ESPIDF = $(IDF_PATH) else $(info The ESPIDF variable has not been set, please set it to the root of the esp-idf repository.) $(info See README.md for installation instructions.) -$(info Supported git hash: $(ESPIDF_SUPHASH)) $(error ESPIDF not set) +print_supported_git_hash endif endif + ESPCOMP = $(ESPIDF)/components ESPTOOL ?= $(ESPCOMP)/esptool_py/esptool/esptool.py ESPCOMP_KCONFIGS = $(shell find $(ESPCOMP) -name Kconfig) @@ -70,13 +77,18 @@ ESPCOMP_KCONFIGS_PROJBUILD = $(shell find $(ESPCOMP) -name Kconfig.projbuild) # verify the ESP IDF version ESPIDF_CURHASH := $(shell git -C $(ESPIDF) show -s --pretty=format:'%H') -ifneq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH)) + +ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V3)) +$(info Building with ESP IDF v3) +else ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) +$(info Building with ESP IDF v4) +else $(info ** WARNING **) $(info The git hash of ESP IDF does not match the supported version) $(info The build may complete and the firmware may work but it is not guaranteed) $(info ESP IDF path: $(ESPIDF)) $(info Current git hash: $(ESPIDF_CURHASH)) -$(info Supported git hash: $(ESPIDF_SUPHASH)) +print_supported_git_hash endif # pretty format of ESP IDF version, used internally by the IDF @@ -100,20 +112,13 @@ INC_ESPCOMP += -I$(ESPCOMP)/bootloader_support/include_bootloader INC_ESPCOMP += -I$(ESPCOMP)/console INC_ESPCOMP += -I$(ESPCOMP)/driver/include INC_ESPCOMP += -I$(ESPCOMP)/driver/include/driver -INC_ESPCOMP += -I$(ESPCOMP)/nghttp/port/include -INC_ESPCOMP += -I$(ESPCOMP)/nghttp/nghttp2/lib/includes INC_ESPCOMP += -I$(ESPCOMP)/efuse/include INC_ESPCOMP += -I$(ESPCOMP)/efuse/esp32/include INC_ESPCOMP += -I$(ESPCOMP)/esp32/include INC_ESPCOMP += -I$(ESPCOMP)/espcoredump/include INC_ESPCOMP += -I$(ESPCOMP)/soc/include INC_ESPCOMP += -I$(ESPCOMP)/soc/esp32/include -INC_ESPCOMP += -I$(ESPCOMP)/ethernet/include -INC_ESPCOMP += -I$(ESPCOMP)/expat/expat/expat/lib -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/platform_include INC_ESPCOMP += -I$(ESPCOMP)/newlib/include @@ -129,20 +134,41 @@ INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/mbedtls/include INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/port/include INC_ESPCOMP += -I$(ESPCOMP)/mdns/include INC_ESPCOMP += -I$(ESPCOMP)/mdns/private_include -INC_ESPCOMP += -I$(ESPCOMP)/micro-ecc/micro-ecc INC_ESPCOMP += -I$(ESPCOMP)/spi_flash/include INC_ESPCOMP += -I$(ESPCOMP)/ulp/include INC_ESPCOMP += -I$(ESPCOMP)/vfs/include INC_ESPCOMP += -I$(ESPCOMP)/xtensa-debug-module/include INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/include INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/port/include -INC_ESPCOMP += -I$(ESPCOMP)/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 INC_ESPCOMP += -I$(ESPCOMP)/sdmmc/include +ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) +INC_ESPCOMP += -I$(ESPCOMP)/esp_common/include +INC_ESPCOMP += -I$(ESPCOMP)/esp_eth/include +INC_ESPCOMP += -I$(ESPCOMP)/esp_event/private_include +INC_ESPCOMP += -I$(ESPCOMP)/esp_rom/include +INC_ESPCOMP += -I$(ESPCOMP)/esp_wifi/include +INC_ESPCOMP += -I$(ESPCOMP)/esp_wifi/esp32/include +INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/apps/sntp +INC_ESPCOMP += -I$(ESPCOMP)/spi_flash/private_include +INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/include/esp_supplicant +INC_ESPCOMP += -I$(ESPCOMP)/xtensa/include +INC_ESPCOMP += -I$(ESPCOMP)/xtensa/esp32/include +else +INC_ESPCOMP += -I$(ESPCOMP)/ethernet/include +INC_ESPCOMP += -I$(ESPCOMP)/expat/expat/expat/lib +INC_ESPCOMP += -I$(ESPCOMP)/expat/port/include +INC_ESPCOMP += -I$(ESPCOMP)/json/include +INC_ESPCOMP += -I$(ESPCOMP)/json/port/include +INC_ESPCOMP += -I$(ESPCOMP)/micro-ecc/micro-ecc +INC_ESPCOMP += -I$(ESPCOMP)/nghttp/port/include +INC_ESPCOMP += -I$(ESPCOMP)/nghttp/nghttp2/lib/includes +endif + # these flags are common to C and C++ compilation CFLAGS_COMMON = -Os -ffunction-sections -fdata-sections -fstrict-volatile-bitfields \ -mlongcalls -nostdlib \ @@ -156,6 +182,10 @@ CFLAGS += -DIDF_VER=\"$(IDF_VER)\" CFLAGS += $(CFLAGS_MOD) $(CFLAGS_EXTRA) CFLAGS += -I$(BOARD_DIR) +ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) +CFLAGS += -DMICROPY_ESP_IDF_4=1 +endif + # this is what ESPIDF uses for c++ compilation CXXFLAGS = -std=gnu++11 $(CFLAGS_COMMON) $(INC) $(INC_ESPCOMP) @@ -164,6 +194,7 @@ LDFLAGS += --gc-sections -static -EL LDFLAGS += -u call_user_start_cpu0 -u uxTopUsedPriority -u ld_include_panic_highint_hdl LDFLAGS += -u __cxa_guard_dummy # so that implementation of static guards is taken from cxx_guards.o instead of libstdc++.a LDFLAGS += -L$(ESPCOMP)/esp32/ld +LDFLAGS += -L$(ESPCOMP)/esp_rom/esp32/ld LDFLAGS += -T $(BUILD)/esp32_out.ld LDFLAGS += -T $(BUILD)/esp32.project.ld LDFLAGS += -T esp32.rom.ld @@ -183,12 +214,19 @@ COPT += -Os -DNDEBUG #LDFLAGS += --gc-sections endif -# Enable SPIRAM support if CONFIG_SPIRAM_SUPPORT=y in sdkconfig -ifeq ($(CONFIG_SPIRAM_SUPPORT),y) +# Enable SPIRAM support if CONFIG_ESP32_SPIRAM_SUPPORT=y in sdkconfig +ifeq ($(CONFIG_ESP32_SPIRAM_SUPPORT),y) CFLAGS_COMMON += -mfix-esp32-psram-cache-issue LIBC_LIBM = $(ESPCOMP)/newlib/lib/libc-psram-workaround.a $(ESPCOMP)/newlib/lib/libm-psram-workaround.a else +# Additional newlib symbols that can only be used with spiram disabled. +ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) +LDFLAGS += -T esp32.rom.newlib-funcs.ld +LDFLAGS += -T esp32.rom.newlib-locale.ld +LDFLAGS += -T esp32.rom.newlib-data.ld +else LDFLAGS += -T esp32.rom.spiram_incompatible_fns.ld +endif LIBC_LIBM = $(ESPCOMP)/newlib/lib/libc.a $(ESPCOMP)/newlib/lib/libm.a endif @@ -283,7 +321,8 @@ $(SDKCONFIG_H): $(SDKCONFIG_COMBINED) --env "IDF_TARGET=esp32" \ --env "IDF_CMAKE=n" \ --env "COMPONENT_KCONFIGS=$(ESPCOMP_KCONFIGS)" \ - --env "COMPONENT_KCONFIGS_PROJBUILD=$(ESPCOMP_KCONFIGS_PROJBUILD)" + --env "COMPONENT_KCONFIGS_PROJBUILD=$(ESPCOMP_KCONFIGS_PROJBUILD)" \ + --env "IDF_PATH=$(ESPIDF)" $(Q)touch $@ $(HEADER_BUILD)/qstrdefs.generated.h: $(SDKCONFIG_H) $(BOARD_DIR)/mpconfigboard.h @@ -293,7 +332,9 @@ $(HEADER_BUILD)/qstrdefs.generated.h: $(SDKCONFIG_H) $(BOARD_DIR)/mpconfigboard. ESPIDF_BOOTLOADER_SUPPORT_O = $(patsubst %.c,%.o,\ $(filter-out $(ESPCOMP)/bootloader_support/src/bootloader_init.c,\ - $(wildcard $(ESPCOMP)/bootloader_support/src/*.c))) + $(wildcard $(ESPCOMP)/bootloader_support/src/*.c) \ + $(wildcard $(ESPCOMP)/bootloader_support/src/idf/*.c) \ + )) ESPIDF_DRIVER_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/driver/*.c)) @@ -315,22 +356,22 @@ ESPIDF_HEAP_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/heap/*.c)) ESPIDF_SOC_O = $(patsubst %.c,%.o,\ $(wildcard $(ESPCOMP)/soc/esp32/*.c) \ $(wildcard $(ESPCOMP)/soc/src/*.c) \ + $(wildcard $(ESPCOMP)/soc/src/hal/*.c) \ ) ESPIDF_CXX_O = $(patsubst %.cpp,%.o,$(wildcard $(ESPCOMP)/cxx/*.cpp)) -ESPIDF_ETHERNET_O = $(patsubst %.c,%.o,\ - $(wildcard $(ESPCOMP)/ethernet/*.c) \ - $(wildcard $(ESPCOMP)/ethernet/eth_phy/*.c) \ - ) - ESPIDF_PTHREAD_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/pthread/*.c)) # Assembler .S files need only basic flags, and in particular should not have # -Os because that generates subtly different code. # We also need custom CFLAGS for .c files because FreeRTOS has headers with # generic names (eg queue.h) which can clash with other files in the port. +ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) +CFLAGS_ASM = -I$(BUILD) -I$(ESPCOMP)/esp32/include -I$(ESPCOMP)/soc/esp32/include -I$(ESPCOMP)/freertos/include/freertos -I. -I$(ESPCOMP)/xtensa/include -I$(ESPCOMP)/xtensa/esp32/include -I$(ESPCOMP)/esp_common/include +else CFLAGS_ASM = -I$(BUILD) -I$(ESPCOMP)/esp32/include -I$(ESPCOMP)/soc/esp32/include -I$(ESPCOMP)/freertos/include/freertos -I. +endif $(BUILD)/$(ESPCOMP)/freertos/portasm.o: CFLAGS = $(CFLAGS_ASM) $(BUILD)/$(ESPCOMP)/freertos/xtensa_context.o: CFLAGS = $(CFLAGS_ASM) $(BUILD)/$(ESPCOMP)/freertos/xtensa_intr_asm.o: CFLAGS = $(CFLAGS_ASM) @@ -343,8 +384,6 @@ ESPIDF_FREERTOS_O = \ ESPIDF_VFS_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/vfs/*.c)) -ESPIDF_JSON_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/json/cJSON/cJSON*.c)) - ESPIDF_LOG_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/log/*.c)) ESPIDF_XTENSA_DEBUG_MODULE_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/xtensa-debug-module/*.c)) @@ -382,11 +421,16 @@ ESPIDF_LWIP_O = $(patsubst %.c,%.o,\ ESPIDF_MBEDTLS_O = $(patsubst %.c,%.o,\ $(wildcard $(ESPCOMP)/mbedtls/mbedtls/library/*.c) \ $(wildcard $(ESPCOMP)/mbedtls/port/*.c) \ + $(wildcard $(ESPCOMP)/mbedtls/port/esp32/*.c) \ ) ESPIDF_MDNS_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/mdns/*.c)) +ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) +$(BUILD)/$(ESPCOMP)/wpa_supplicant/%.o: CFLAGS += -DESP_SUPPLICANT -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_TLS -DEAP_TTLS -DEAP_PEAP -DEAP_MSCHAPv2 -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -DCONFIG_ECC -D__ets__ -Wno-strict-aliasing -I$(ESPCOMP)/wpa_supplicant/src -Wno-implicit-function-declaration +else $(BUILD)/$(ESPCOMP)/wpa_supplicant/%.o: CFLAGS += -DEMBEDDED_SUPP -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_MSCHAPv2 -DEAP_TTLS -DEAP_TLS -DEAP_PEAP -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -DALLOW_EVEN_MOD -D__ets__ -Wno-strict-aliasing +endif ESPIDF_WPA_SUPPLICANT_O = $(patsubst %.c,%.o,\ $(wildcard $(ESPCOMP)/wpa_supplicant/port/*.c) \ $(wildcard $(ESPCOMP)/wpa_supplicant/src/*/*.c) \ @@ -394,6 +438,29 @@ ESPIDF_WPA_SUPPLICANT_O = $(patsubst %.c,%.o,\ ESPIDF_SDMMC_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/sdmmc/*.c)) +ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) +ESPIDF_ESP_COMMON_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/esp_common/src/*.c)) + +ESPIDF_ESP_EVENT_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/esp_event/*.c)) + +ESPIDF_ESP_WIFI_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/esp_wifi/src/*.c)) + +$(BUILD)/$(ESPCOMP)/esp_eth/src/esp_eth_mac_dm9051.o: CFLAGS += -fno-strict-aliasing +ESPIDF_ESP_ETH_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/esp_eth/src/*.c)) + +ESPIDF_XTENSA_O = $(patsubst %.c,%.o,\ + $(wildcard $(ESPCOMP)/xtensa/*.c) \ + $(wildcard $(ESPCOMP)/xtensa/esp32/*.c) \ + ) +else +ESPIDF_JSON_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/json/cJSON/cJSON*.c)) + +ESPIDF_ETHERNET_O = $(patsubst %.c,%.o,\ + $(wildcard $(ESPCOMP)/ethernet/*.c) \ + $(wildcard $(ESPCOMP)/ethernet/eth_phy/*.c) \ + ) +endif + OBJ_ESPIDF = LIB_ESPIDF = BUILD_ESPIDF_LIB = $(BUILD)/esp-idf @@ -414,7 +481,6 @@ $(eval $(call gen_espidf_lib_rule,esp_ringbuf,$(ESPIDF_ESP_RINGBUF_O))) $(eval $(call gen_espidf_lib_rule,heap,$(ESPIDF_HEAP_O))) $(eval $(call gen_espidf_lib_rule,soc,$(ESPIDF_SOC_O))) $(eval $(call gen_espidf_lib_rule,cxx,$(ESPIDF_CXX_O))) -$(eval $(call gen_espidf_lib_rule,ethernet,$(ESPIDF_ETHERNET_O))) $(eval $(call gen_espidf_lib_rule,pthread,$(ESPIDF_PTHREAD_O))) $(eval $(call gen_espidf_lib_rule,freertos,$(ESPIDF_FREERTOS_O))) $(eval $(call gen_espidf_lib_rule,vfs,$(ESPIDF_VFS_O))) @@ -435,6 +501,16 @@ $(eval $(call gen_espidf_lib_rule,mdns,$(ESPIDF_MDNS_O))) $(eval $(call gen_espidf_lib_rule,wpa_supplicant,$(ESPIDF_WPA_SUPPLICANT_O))) $(eval $(call gen_espidf_lib_rule,sdmmc,$(ESPIDF_SDMMC_O))) +ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) +$(eval $(call gen_espidf_lib_rule,esp_common,$(ESPIDF_ESP_COMMON_O))) +$(eval $(call gen_espidf_lib_rule,esp_event,$(ESPIDF_ESP_EVENT_O))) +$(eval $(call gen_espidf_lib_rule,esp_wifi,$(ESPIDF_ESP_WIFI_O))) +$(eval $(call gen_espidf_lib_rule,esp_eth,$(ESPIDF_ESP_ETH_O))) +$(eval $(call gen_espidf_lib_rule,xtensa,$(ESPIDF_XTENSA_O))) +else +$(eval $(call gen_espidf_lib_rule,ethernet,$(ESPIDF_ETHERNET_O))) +endif + # Create all destination build dirs before compiling IDF source OBJ_ESPIDF_DIRS = $(sort $(dir $(OBJ_ESPIDF))) $(BUILD_ESPIDF_LIB) $(addprefix $(BUILD_ESPIDF_LIB)/,$(LIB_ESPIDF)) $(OBJ_ESPIDF): | $(OBJ_ESPIDF_DIRS) @@ -451,6 +527,32 @@ LIB = $(foreach lib,$(LIB_ESPIDF),$(BUILD_ESPIDF_LIB)/$(lib)/lib$(lib).a) # ESP IDF ldgen LDGEN_FRAGMENTS = $(shell find $(ESPCOMP) -name "*.lf") + +ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) + +LDGEN_LIBRARIES=$(foreach lib,$(LIB_ESPIDF),$(BUILD_ESPIDF_LIB)/$(lib)/lib$(lib).a) + +$(BUILD_ESPIDF_LIB)/ldgen_libraries: $(LDGEN_LIBRARIES) $(ESPIDF)/make/ldgen.mk + printf "$(foreach library,$(LDGEN_LIBRARIES),$(library)\n)" > $(BUILD_ESPIDF_LIB)/ldgen_libraries + +$(BUILD)/esp32.project.ld: $(ESPCOMP)/esp32/ld/esp32.project.ld.in $(LDGEN_FRAGMENTS) $(SDKCONFIG_COMBINED) $(BUILD_ESPIDF_LIB)/ldgen_libraries + $(ECHO) "GEN $@" + $(Q)$(PYTHON) $(ESPIDF)/tools/ldgen/ldgen.py \ + --input $< \ + --output $@ \ + --config $(SDKCONFIG_COMBINED) \ + --kconfig $(ESPIDF)/Kconfig \ + --fragments $(LDGEN_FRAGMENTS) \ + --libraries-file $(BUILD_ESPIDF_LIB)/ldgen_libraries \ + --env "IDF_TARGET=esp32" \ + --env "IDF_CMAKE=n" \ + --env "COMPONENT_KCONFIGS=$(ESPCOMP_KCONFIGS)" \ + --env "COMPONENT_KCONFIGS_PROJBUILD=$(ESPCOMP_KCONFIGS_PROJBUILD)" \ + --env "IDF_PATH=$(ESPIDF)" \ + --objdump $(OBJDUMP) + +else + LDGEN_SECTIONS_INFO = $(foreach lib,$(LIB_ESPIDF),$(BUILD_ESPIDF_LIB)/$(lib)/lib$(lib).a.sections_info) LDGEN_SECTION_INFOS = $(BUILD_ESPIDF_LIB)/ldgen.section_infos @@ -477,7 +579,10 @@ $(BUILD)/esp32.project.ld: $(ESPCOMP)/esp32/ld/esp32.project.ld.in $(LDGEN_FRAGM --env "IDF_TARGET=esp32" \ --env "IDF_CMAKE=n" \ --env "COMPONENT_KCONFIGS=$(ESPCOMP_KCONFIGS)" \ - --env "COMPONENT_KCONFIGS_PROJBUILD=$(ESPCOMP_KCONFIGS_PROJBUILD)" + --env "COMPONENT_KCONFIGS_PROJBUILD=$(ESPCOMP_KCONFIGS_PROJBUILD)" \ + --env "IDF_PATH=$(ESPIDF)" + +endif ################################################################################ # Main targets @@ -513,8 +618,13 @@ APP_LD_ARGS += --start-group APP_LD_ARGS += -L$(dir $(LIBGCC_FILE_NAME)) -lgcc APP_LD_ARGS += -L$(dir $(LIBSTDCXX_FILE_NAME)) -lstdc++ APP_LD_ARGS += $(LIBC_LIBM) +ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) +APP_LD_ARGS += -L$(ESPCOMP)/xtensa/esp32 -lhal +APP_LD_ARGS += -L$(ESPCOMP)/esp_wifi/lib_esp32 -lcore -lmesh -lnet80211 -lphy -lrtc -lpp -lsmartconfig -lcoexist +else APP_LD_ARGS += $(ESPCOMP)/esp32/libhal.a APP_LD_ARGS += -L$(ESPCOMP)/esp32/lib -lcore -lmesh -lnet80211 -lphy -lrtc -lpp -lwpa -lsmartconfig -lcoexist -lwps -lwpa2 +endif APP_LD_ARGS += $(OBJ) APP_LD_ARGS += $(LIB) APP_LD_ARGS += --end-group @@ -553,7 +663,14 @@ $(BUILD)/%.o: %.cpp BOOTLOADER_LIB_DIR = $(BUILD)/bootloader BOOTLOADER_LIB_ALL = +ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) +$(BUILD)/bootloader/$(ESPCOMP)/%.o: CFLAGS += -DBOOTLOADER_BUILD=1 -I$(ESPCOMP)/bootloader_support/include_priv -I$(ESPCOMP)/bootloader_support/include -I$(ESPCOMP)/efuse/include -I$(ESPCOMP)/esp_rom/include -Wno-error=format \ + -I$(ESPCOMP)/esp_common/include \ + -I$(ESPCOMP)/xtensa/include \ + -I$(ESPCOMP)/xtensa/esp32/include +else $(BUILD)/bootloader/$(ESPCOMP)/%.o: CFLAGS += -DBOOTLOADER_BUILD=1 -I$(ESPCOMP)/bootloader_support/include_priv -I$(ESPCOMP)/bootloader_support/include -I$(ESPCOMP)/micro-ecc/micro-ecc -I$(ESPCOMP)/efuse/include -I$(ESPCOMP)/esp32 -Wno-error=format +endif # libbootloader_support.a BOOTLOADER_LIB_ALL += bootloader_support @@ -563,15 +680,27 @@ BOOTLOADER_LIB_BOOTLOADER_SUPPORT_OBJ = $(addprefix $(BUILD)/bootloader/$(ESPCOM 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/flash_qio_mode.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 \ ) + +ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) +BOOTLOADER_LIB_BOOTLOADER_SUPPORT_OBJ += $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/,\ + bootloader_support/src/esp32/bootloader_sha.o \ + bootloader_support/src/bootloader_flash_config.o \ + bootloader_support/src/esp32/secure_boot.o \ + ) +else +BOOTLOADER_LIB_BOOTLOADER_SUPPORT_OBJ += $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/,\ + bootloader_support/src/bootloader_sha.o \ + bootloader_support/src/secure_boot_signatures.o \ + bootloader_support/src/secure_boot.o \ + ) +endif + $(BOOTLOADER_LIB_DIR)/libbootloader_support.a: $(BOOTLOADER_LIB_BOOTLOADER_SUPPORT_OBJ) $(ECHO) "AR $@" $(Q)$(AR) cr $@ $^ @@ -594,6 +723,7 @@ $(BOOTLOADER_LIB_DIR)/libspi_flash.a: $(BOOTLOADER_LIB_SPI_FLASH_OBJ) $(ECHO) "AR $@" $(Q)$(AR) cr $@ $^ +ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V3)) # libmicro-ecc.a BOOTLOADER_LIB_ALL += micro-ecc BOOTLOADER_LIB_MICRO_ECC_OBJ = $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/,\ @@ -602,6 +732,7 @@ BOOTLOADER_LIB_MICRO_ECC_OBJ = $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/,\ $(BOOTLOADER_LIB_DIR)/libmicro-ecc.a: $(BOOTLOADER_LIB_MICRO_ECC_OBJ) $(ECHO) "AR $@" $(Q)$(AR) cr $@ $^ +endif # libsoc.a $(BUILD)/bootloader/$(ESPCOMP)/soc/esp32/rtc_clk.o: CFLAGS += -fno-jump-tables -fno-tree-switch-conversion @@ -651,7 +782,11 @@ BOOTLOADER_LIBS = BOOTLOADER_LIBS += -Wl,--start-group BOOTLOADER_LIBS += $(BOOTLOADER_OBJ) BOOTLOADER_LIBS += -L$(BUILD)/bootloader $(addprefix -l,$(BOOTLOADER_LIB_ALL)) +ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) +BOOTLOADER_LIBS += -L$(ESPCOMP)/esp_wifi/lib_esp32 -lrtc +else BOOTLOADER_LIBS += -L$(ESPCOMP)/esp32/lib -lrtc +endif BOOTLOADER_LIBS += -L$(dir $(LIBGCC_FILE_NAME)) -lgcc BOOTLOADER_LIBS += -Wl,--end-group @@ -666,8 +801,13 @@ BOOTLOADER_LDFLAGS += -Wl,-EL BOOTLOADER_LDFLAGS += -Wl,-Map=$(@:.elf=.map) -Wl,--cref BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/bootloader/subproject/main/esp32.bootloader.ld BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/bootloader/subproject/main/esp32.bootloader.rom.ld +ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) +BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/esp_rom/esp32/ld/esp32.rom.ld +BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/esp_rom/esp32/ld/esp32.rom.newlib-funcs.ld +else BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/esp32/ld/esp32.rom.ld BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/esp32/ld/esp32.rom.spiram_incompatible_fns.ld +endif BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/esp32/ld/esp32.peripherals.ld BOOTLOADER_OBJ_DIRS = $(sort $(dir $(BOOTLOADER_OBJ_ALL))) diff --git a/ports/esp32/boards/TINYPICO/sdkconfig.board b/ports/esp32/boards/TINYPICO/sdkconfig.board index ea4fc9b5cd..dc2c23f674 100644 --- a/ports/esp32/boards/TINYPICO/sdkconfig.board +++ b/ports/esp32/boards/TINYPICO/sdkconfig.board @@ -1,3 +1,4 @@ CONFIG_FLASHMODE_QIO=y CONFIG_ESPTOOLPY_FLASHFREQ_80M=y CONFIG_SPIRAM_SPEED_80M=y +CONFIG_ESP32_REV_MIN_1=y diff --git a/ports/esp32/boards/sdkconfig.base b/ports/esp32/boards/sdkconfig.base index 7bd731a66b..d44a97e138 100644 --- a/ports/esp32/boards/sdkconfig.base +++ b/ports/esp32/boards/sdkconfig.base @@ -8,7 +8,7 @@ CONFIG_APP_EXCLUDE_PROJECT_VER_VAR=y CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR=y # Bootloader config -CONFIG_LOG_BOOTLOADER_LEVEL_WARN=y +CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y # ESP32-specific CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y @@ -21,10 +21,15 @@ CONFIG_PM_ENABLE=y # FreeRTOS CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=2 -CONFIG_SUPPORT_STATIC_ALLOCATION=y -CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK=y +CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y +CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP=y # UDP CONFIG_PPP_SUPPORT=y CONFIG_PPP_PAP_SUPPORT=y CONFIG_PPP_CHAP_SUPPORT=y + +# v3.3-only (renamed in 4.0) +CONFIG_LOG_BOOTLOADER_LEVEL_WARN=y +CONFIG_SUPPORT_STATIC_ALLOCATION=y +CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK=y diff --git a/ports/esp32/boards/sdkconfig.spiram b/ports/esp32/boards/sdkconfig.spiram index 53950e587c..db1a83af8c 100644 --- a/ports/esp32/boards/sdkconfig.spiram +++ b/ports/esp32/boards/sdkconfig.spiram @@ -1,5 +1,9 @@ # MicroPython on ESP32, ESP IDF configuration with SPIRAM support -CONFIG_SPIRAM_SUPPORT=y +CONFIG_ESP32_SPIRAM_SUPPORT=y +CONFIG_SPIRAM_CACHE_WORKAROUND=y CONFIG_SPIRAM_IGNORE_NOTFOUND=y CONFIG_SPIRAM_USE_MEMMAP=y + +# v3.3-only (renamed in 4.0) +CONFIG_SPIRAM_SUPPORT=y diff --git a/ports/esp32/esp32_ulp.c b/ports/esp32/esp32_ulp.c index 3772639f44..bf11de330f 100644 --- a/ports/esp32/esp32_ulp.c +++ b/ports/esp32/esp32_ulp.c @@ -85,7 +85,11 @@ STATIC const mp_rom_map_elem_t esp32_ulp_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_set_wakeup_period), MP_ROM_PTR(&esp32_ulp_set_wakeup_period_obj) }, { MP_ROM_QSTR(MP_QSTR_load_binary), MP_ROM_PTR(&esp32_ulp_load_binary_obj) }, { MP_ROM_QSTR(MP_QSTR_run), MP_ROM_PTR(&esp32_ulp_run_obj) }, + #if !MICROPY_ESP_IDF_4 { MP_ROM_QSTR(MP_QSTR_RESERVE_MEM), MP_ROM_INT(CONFIG_ULP_COPROC_RESERVE_MEM) }, + #else + { MP_ROM_QSTR(MP_QSTR_RESERVE_MEM), MP_ROM_INT(CONFIG_ESP32_ULP_COPROC_RESERVE_MEM) }, + #endif }; STATIC MP_DEFINE_CONST_DICT(esp32_ulp_locals_dict, esp32_ulp_locals_dict_table); diff --git a/ports/esp32/main.c b/ports/esp32/main.c index c8dde337c5..4d25cf0b3a 100644 --- a/ports/esp32/main.c +++ b/ports/esp32/main.c @@ -37,7 +37,11 @@ #include "esp_task.h" #include "soc/cpu.h" #include "esp_log.h" +#if MICROPY_ESP_IDF_4 +#include "esp32/spiram.h" +#else #include "esp_spiram.h" +#endif #include "py/stackctrl.h" #include "py/nlr.h" @@ -70,7 +74,7 @@ void mp_task(void *pvParameter) { #endif uart_init(); - #if CONFIG_SPIRAM_SUPPORT + #if CONFIG_ESP32_SPIRAM_SUPPORT // Try to use the entire external SPIRAM directly for the heap size_t mp_task_heap_size; void *mp_task_heap = (void*)0x3f800000; @@ -150,7 +154,11 @@ soft_reset: } void app_main(void) { - nvs_flash_init(); + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + nvs_flash_erase(); + nvs_flash_init(); + } xTaskCreatePinnedToCore(mp_task, "mp_task", MP_TASK_STACK_LEN, NULL, MP_TASK_PRIORITY, &mp_main_task_handle, MP_TASK_COREID); } diff --git a/ports/esp32/modesp.c b/ports/esp32/modesp.c index e614f77a6a..9584b789dc 100644 --- a/ports/esp32/modesp.c +++ b/ports/esp32/modesp.c @@ -29,7 +29,9 @@ #include +#if !MICROPY_ESP_IDF_4 #include "rom/gpio.h" +#endif #include "esp_log.h" #include "esp_spi_flash.h" diff --git a/ports/esp32/modmachine.c b/ports/esp32/modmachine.c index fb864947d2..0c803d0960 100644 --- a/ports/esp32/modmachine.c +++ b/ports/esp32/modmachine.c @@ -32,9 +32,15 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#if MICROPY_ESP_IDF_4 +#include "esp32/rom/rtc.h" +#include "esp32/clk.h" +#include "esp_sleep.h" +#else #include "rom/ets_sys.h" #include "rom/rtc.h" #include "esp_clk.h" +#endif #include "esp_pm.h" #include "driver/touch_pad.h" diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index 45ea5139c6..012dc5bce8 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -43,20 +43,23 @@ #include "netutils.h" #include "esp_eth.h" #include "esp_wifi.h" -#include "esp_wifi_types.h" #include "esp_log.h" -#include "esp_event_loop.h" #include "lwip/dns.h" #include "tcpip_adapter.h" #include "mdns.h" +#if !MICROPY_ESP_IDF_4 +#include "esp_wifi_types.h" +#include "esp_event_loop.h" +#endif + #include "modnetwork.h" #define MODNETWORK_INCLUDE_CONSTANTS (1) NORETURN void _esp_exceptions(esp_err_t e) { switch (e) { - case ESP_ERR_WIFI_NOT_INIT: + 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"); @@ -93,7 +96,7 @@ NORETURN void _esp_exceptions(esp_err_t e) { case ESP_ERR_TCPIP_ADAPTER_DHCPC_START_FAILED: mp_raise_msg(&mp_type_OSError, "TCP/IP DHCP Client Start Failed"); case ESP_ERR_TCPIP_ADAPTER_NO_MEM: - mp_raise_OSError(MP_ENOMEM); + mp_raise_OSError(MP_ENOMEM); default: nlr_raise(mp_obj_new_exception_msg_varg( &mp_type_RuntimeError, "Wifi Unknown Error 0x%04x", e @@ -650,9 +653,12 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs ESP_EXCEPTIONS(esp_wifi_get_mac(self->if_id, mac)); return mp_obj_new_bytes(mac, sizeof(mac)); + #if !MICROPY_ESP_IDF_4 case ESP_IF_ETH: esp_eth_get_mac(mac); return mp_obj_new_bytes(mac, sizeof(mac)); + #endif + default: goto unknown; } @@ -734,8 +740,10 @@ 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) }, + #if !MICROPY_ESP_IDF_4 { MP_ROM_QSTR(MP_QSTR_LAN), MP_ROM_PTR(&get_lan_obj) }, { MP_ROM_QSTR(MP_QSTR_PPP), MP_ROM_PTR(&ppp_make_new_obj) }, + #endif { MP_ROM_QSTR(MP_QSTR_phy_mode), MP_ROM_PTR(&esp_phy_mode_obj) }, #if MODNETWORK_INCLUDE_CONSTANTS @@ -757,12 +765,14 @@ STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_PHY_TLK110), MP_ROM_INT(PHY_TLK110) }, // ETH Clock modes from ESP-IDF + #if !MICROPY_ESP_IDF_4 { MP_ROM_QSTR(MP_QSTR_ETH_CLOCK_GPIO0_IN), MP_ROM_INT(ETH_CLOCK_GPIO0_IN) }, // Disabled at Aug 22nd 2018, reenabled Jan 28th 2019 in ESP-IDF // Because we use older SDK, it's currently disabled //{ MP_ROM_QSTR(MP_QSTR_ETH_CLOCK_GPIO0_OUT), MP_ROM_INT(ETH_CLOCK_GPIO0_OUT) }, { MP_ROM_QSTR(MP_QSTR_ETH_CLOCK_GPIO16_OUT), MP_ROM_INT(ETH_CLOCK_GPIO16_OUT) }, { MP_ROM_QSTR(MP_QSTR_ETH_CLOCK_GPIO17_OUT), MP_ROM_INT(ETH_CLOCK_GPIO17_OUT) }, + #endif { MP_ROM_QSTR(MP_QSTR_STAT_IDLE), MP_ROM_INT(STAT_IDLE)}, { MP_ROM_QSTR(MP_QSTR_STAT_CONNECTING), MP_ROM_INT(STAT_CONNECTING)}, diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c index a6f29718d8..e11af60e2e 100644 --- a/ports/esp32/modsocket.c +++ b/ports/esp32/modsocket.c @@ -56,6 +56,18 @@ #include "lwip/igmp.h" #include "esp_log.h" +#if !MICROPY_ESP_IDF_4 +#define lwip_bind lwip_bind_r +#define lwip_listen lwip_listen_r +#define lwip_accept lwip_accept_r +#define lwip_setsockopt lwip_setsockopt_r +#define lwip_fnctl lwip_fnctl_r +#define lwip_recvfrom lwip_recvfrom_r +#define lwip_write lwip_write_r +#define lwip_sendto lwip_sendto_r +#define lwip_close lwip_close_r +#endif + #define SOCKET_POLL_US (100000) #define MDNS_QUERY_TIMEOUT_MS (5000) #define MDNS_LOCAL_SUFFIX ".local" @@ -277,17 +289,17 @@ 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); + int r = lwip_bind(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); + int r = lwip_listen(self->fd, backlog); if (r < 0) exception_from_errno(errno); return mp_const_none; } @@ -302,7 +314,7 @@ STATIC mp_obj_t socket_accept(const mp_obj_t arg0) { 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); + new_fd = lwip_accept(self->fd, &addr, &addr_len); MP_THREAD_GIL_ENTER(); if (new_fd >= 0) break; if (errno != EAGAIN) exception_from_errno(errno); @@ -342,7 +354,7 @@ STATIC mp_obj_t socket_connect(const mp_obj_t arg0, const mp_obj_t arg1) { struct addrinfo *res; _socket_getaddrinfo(arg1, &res); MP_THREAD_GIL_EXIT(); - int r = lwip_connect_r(self->fd, res->ai_addr, res->ai_addrlen); + int r = lwip_connect(self->fd, res->ai_addr, res->ai_addrlen); MP_THREAD_GIL_ENTER(); lwip_freeaddrinfo(res); if (r != 0) { @@ -363,7 +375,7 @@ STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) { // 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)); + int ret = lwip_setsockopt(self->fd, SOL_SOCKET, opt, &val, sizeof(int)); if (ret != 0) { exception_from_errno(errno); } @@ -424,9 +436,9 @@ void _socket_settimeout(socket_obj_t *sock, uint64_t timeout_ms) { .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); + lwip_setsockopt(sock->fd, SOL_SOCKET, SO_SNDTIMEO, (const void *)&timeout, sizeof(timeout)); + lwip_setsockopt(sock->fd, SOL_SOCKET, SO_RCVTIMEO, (const void *)&timeout, sizeof(timeout)); + lwip_fcntl(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) { @@ -459,7 +471,7 @@ STATIC mp_uint_t _socket_read_data(mp_obj_t self_in, void *buf, size_t size, 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, + // from lwip_recvfrom and then block on subsequent calls. To emulate POSIX behaviour, // which continues to return "0" for each call on a closed socket, we set a flag when // the peer closed the socket. if (sock->peer_closed) { @@ -482,7 +494,7 @@ STATIC mp_uint_t _socket_read_data(mp_obj_t self_in, void *buf, size_t size, if (release_gil) { MP_THREAD_GIL_EXIT(); } - int r = lwip_recvfrom_r(sock->fd, buf, size, 0, from, from_len); + int r = lwip_recvfrom(sock->fd, buf, size, 0, from, from_len); if (release_gil) { MP_THREAD_GIL_ENTER(); } @@ -543,13 +555,13 @@ 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); + int r = lwip_write(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); + if (sentlen == 0) mp_raise_OSError(MP_ETIMEDOUT); return sentlen; } @@ -590,7 +602,7 @@ STATIC mp_obj_t socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_ // 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)); + int ret = lwip_sendto(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) { @@ -598,7 +610,7 @@ STATIC mp_obj_t socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_ } check_for_exceptions(); } - mp_raise_OSError(MP_ETIMEDOUT); + mp_raise_OSError(MP_ETIMEDOUT); } STATIC MP_DEFINE_CONST_FUN_OBJ_3(socket_sendto_obj, socket_sendto); @@ -622,7 +634,7 @@ STATIC mp_uint_t socket_stream_write(mp_obj_t self_in, const void *buf, mp_uint_ 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); + int r = lwip_write(sock->fd, buf, size); MP_THREAD_GIL_ENTER(); if (r > 0) return r; if (r < 0 && errno != EWOULDBLOCK) { *errcode = errno; return MP_STREAM_ERROR; } @@ -663,7 +675,7 @@ STATIC mp_uint_t socket_stream_ioctl(mp_obj_t self_in, mp_uint_t request, uintpt socket->events_callback = MP_OBJ_NULL; } #endif - int ret = lwip_close_r(socket->fd); + int ret = lwip_close(socket->fd); if (ret != 0) { *errcode = errno; return MP_STREAM_ERROR; @@ -731,7 +743,7 @@ STATIC mp_obj_t esp_socket_getaddrinfo(size_t n_args, const mp_obj_t *args) { 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 diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index cba319245c..1c0d8700fa 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -6,7 +6,10 @@ #include #include + +#if !MICROPY_ESP_IDF_4 #include "rom/ets_sys.h" +#endif // object representation and NLR handling #define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_A) diff --git a/ports/esp32/mphalport.c b/ports/esp32/mphalport.c index 0d1ea74d6b..305e87593e 100644 --- a/ports/esp32/mphalport.c +++ b/ports/esp32/mphalport.c @@ -31,7 +31,12 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" + +#if MICROPY_ESP_IDF_4 +#include "esp32/rom/uart.h" +#else #include "rom/uart.h" +#endif #include "py/obj.h" #include "py/stream.h" diff --git a/ports/esp32/mpthreadport.c b/ports/esp32/mpthreadport.c index 9557d40714..1c0d889e98 100644 --- a/ports/esp32/mpthreadport.c +++ b/ports/esp32/mpthreadport.c @@ -33,6 +33,9 @@ #include "mpthreadport.h" #include "esp_task.h" +#if !MICROPY_ESP_IDF_4 +#include "freertos/semphr.h" +#endif #if MICROPY_PY_THREAD diff --git a/ports/esp32/network_lan.c b/ports/esp32/network_lan.c index 100894b2ee..2910407973 100644 --- a/ports/esp32/network_lan.c +++ b/ports/esp32/network_lan.c @@ -26,6 +26,7 @@ * THE SOFTWARE. */ +#if !MICROPY_ESP_IDF_4 #include "py/runtime.h" #include "py/mphal.h" @@ -216,3 +217,5 @@ const mp_obj_type_t lan_if_type = { .name = MP_QSTR_LAN, .locals_dict = (mp_obj_dict_t*)&lan_if_locals_dict, }; + +#endif // !MICROPY_ESP_IDF_4 diff --git a/ports/esp32/network_ppp.c b/ports/esp32/network_ppp.c index 1a14c09bf8..d868450fd0 100644 --- a/ports/esp32/network_ppp.c +++ b/ports/esp32/network_ppp.c @@ -26,6 +26,7 @@ * THE SOFTWARE. */ +#if !MICROPY_ESP_IDF_4 #include "py/runtime.h" #include "py/mphal.h" #include "py/objtype.h" @@ -282,3 +283,5 @@ const mp_obj_type_t ppp_if_type = { .name = MP_QSTR_PPP, .locals_dict = (mp_obj_dict_t*)&ppp_if_locals_dict, }; + +#endif // !MICROPY_ESP_IDF_4 From b1505541da5d079fdc47f58d3c7b232b46ae77fc Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Fri, 13 Sep 2019 23:48:28 +1000 Subject: [PATCH 0713/1788] travis: Add ESP32 build with IDF v4. --- .travis.yml | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 72dbe138f7..788bf7d574 100644 --- a/.travis.yml +++ b/.travis.yml @@ -140,17 +140,26 @@ jobs: env: NAME="esp32 port build" install: - sudo apt-get install python3-pip - - sudo pip3 install pyparsing + - sudo pip3 install 'pyparsing<2.4' - wget https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz - zcat xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz | tar x - export PATH=$(pwd)/xtensa-esp32-elf/bin:$PATH - git clone https://github.com/espressif/esp-idf.git - - git -C esp-idf checkout $(grep "ESPIDF_SUPHASH :=" ports/esp32/Makefile | cut -d " " -f 3) - - git -C esp-idf submodule update --init components/json/cJSON components/esp32/lib components/esptool_py/esptool components/expat/expat components/lwip/lwip components/mbedtls/mbedtls components/micro-ecc/micro-ecc components/nghttp/nghttp2 + - export IDF_PATH=$(pwd)/esp-idf script: - git submodule update --init lib/berkeley-db-1.xx - make ${MAKEOPTS} -C mpy-cross - - make ${MAKEOPTS} -C ports/esp32 ESPIDF=$(pwd)/esp-idf + # IDF v3 build + - git -C esp-idf checkout $(grep "ESPIDF_SUPHASH_V3 :=" ports/esp32/Makefile | cut -d " " -f 3) + - git -C esp-idf submodule update --init components/json/cJSON components/esp32/lib components/esptool_py/esptool components/expat/expat components/lwip/lwip components/mbedtls/mbedtls components/micro-ecc/micro-ecc components/nghttp/nghttp2 + - make ${MAKEOPTS} -C ports/esp32 + # clean + - git -C esp-idf clean -f -f -d components/json/cJSON components/esp32/lib components/expat/expat components/micro-ecc/micro-ecc components/nghttp/nghttp2 + - make ${MAKEOPTS} -C ports/esp32 clean + # IDF v4 build + - git -C esp-idf checkout $(grep "ESPIDF_SUPHASH_V4 :=" ports/esp32/Makefile | cut -d " " -f 3) + - git -C esp-idf submodule update --init components/esp_wifi/lib_esp32 components/esptool_py/esptool components/lwip/lwip components/mbedtls/mbedtls + - make ${MAKEOPTS} -C ports/esp32 # esp8266 port - stage: test From 970f798ea9730298f9a690cf5472839158acea4b Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 17 Sep 2019 11:50:09 +1000 Subject: [PATCH 0714/1788] esp32: Add check to Makefile for pyparsing version. --- ports/esp32/Makefile | 9 +++++++++ ports/esp32/README.md | 15 +++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 25001643ee..bb25477444 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -82,6 +82,15 @@ ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V3)) $(info Building with ESP IDF v3) else ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) $(info Building with ESP IDF v4) + +PYPARSING_VERSION = $(shell python3 -c 'import pyparsing; print(pyparsing.__version__)') +ifneq ($(PYPARSING_VERSION),2.3.1) +$(info ** ERROR **) +$(info EDP IDF requires pyparsing version less than 2.4) +$(info You will need to set up a Python virtual environment with pyparsing 2.3.1) +$(info Please see README.md for more information) +$(error Incorrect pyparsing version) +endif else $(info ** WARNING **) $(info The git hash of ESP IDF does not match the supported version) diff --git a/ports/esp32/README.md b/ports/esp32/README.md index 31347b6a2a..2c7351ee53 100644 --- a/ports/esp32/README.md +++ b/ports/esp32/README.md @@ -26,14 +26,17 @@ 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) -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: +The ESP-IDF changes quickly and MicroPython only supports certain versions. The +git hash of these versions (one for 3.x, one for 4.x) can be found by running +`make` without a configured `ESPIDF`. Then you can fetch only the given esp-idf +using the following command: $ git clone https://github.com/espressif/esp-idf.git $ git checkout $ git submodule update --init --recursive +Note: The ESP IDF v4.x support is currently experimental. + The binary toolchain (binutils, gcc, etc.) can be installed using the following guides: @@ -53,9 +56,13 @@ You will also need either Python 2 or Python 3, along with the `pyserial` and (when building you can use, eg, `make PYTHON=python2` to specify the version used). To install the required packages do: ```bash -$ pip install pyserial pyparsing +$ pip install pyserial 'pyparsing<2.4' ``` +It is recommended to use a Python virtual environment if your system package +manager already provides these libraries, especially as the IDF v4.x is +currently incompatible with pyparsing 2.4 and higher. + 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 will need to update your `PATH` From f469634c0c72abb1af790b4ed43aae756d333412 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 17 Sep 2019 11:50:31 +1000 Subject: [PATCH 0715/1788] esp32: Add check to Makefile that the toolchain is in PATH. --- ports/esp32/Makefile | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index bb25477444..85eebb3f54 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -103,6 +103,13 @@ endif # pretty format of ESP IDF version, used internally by the IDF IDF_VER := $(shell git -C $(ESPIDF) describe) +ifeq ($(shell which $(CC) 2> /dev/null),) +$(info ** ERROR **) +$(info Cannot find C compiler $(CC)) +$(info Add the xtensa toolchain to your PATH. See README.md) +$(error C compiler missing) +endif + # include sdkconfig to get needed configuration values include $(SDKCONFIG) From 73c94bbbd45c01c3236282e7b334e4539ca043d4 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Fri, 13 Sep 2019 19:57:23 +0200 Subject: [PATCH 0716/1788] stm32/modusocket: Fix NULL deref when accept() an unbound socket. --- ports/stm32/modusocket.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ports/stm32/modusocket.c b/ports/stm32/modusocket.c index 7503ecbd68..5a16331137 100644 --- a/ports/stm32/modusocket.c +++ b/ports/stm32/modusocket.c @@ -125,6 +125,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_listen_obj, socket_listen); STATIC mp_obj_t socket_accept(mp_obj_t self_in) { mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->nic == MP_OBJ_NULL) { + // not bound + mp_raise_OSError(MP_EINVAL); + } + // create new socket object // starts with empty NIC so that finaliser doesn't run close() method if accept() fails mod_network_socket_obj_t *socket2 = m_new_obj_with_finaliser(mod_network_socket_obj_t); From 62d78e231ceb41eecdc3180cae6f07d790cd33d8 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Wed, 18 Sep 2019 10:44:16 +1000 Subject: [PATCH 0717/1788] esp32/main: Use both 3.3 and 4.0 config vars to enable SPIRAM. --- ports/esp32/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ports/esp32/main.c b/ports/esp32/main.c index 4d25cf0b3a..7106e0bf5e 100644 --- a/ports/esp32/main.c +++ b/ports/esp32/main.c @@ -74,7 +74,8 @@ void mp_task(void *pvParameter) { #endif uart_init(); - #if CONFIG_ESP32_SPIRAM_SUPPORT + // TODO: CONFIG_SPIRAM_SUPPORT is for 3.3 compatibility, remove after move to 4.0. + #if CONFIG_ESP32_SPIRAM_SUPPORT || CONFIG_SPIRAM_SUPPORT // Try to use the entire external SPIRAM directly for the heap size_t mp_task_heap_size; void *mp_task_heap = (void*)0x3f800000; From b2b21839d374e480b900e102cfd0010233b43543 Mon Sep 17 00:00:00 2001 From: stijn Date: Wed, 29 May 2019 17:14:45 +0200 Subject: [PATCH 0718/1788] windows/msvc: Remove unneeded definitions for qstr generation. These were probably added to detect more qstrs but as long as the micropython executable itself doesn't use the same build options the qstrs would be unused anyway. Furthermore these definitions are for internal use and get enabled when corresponding MICROPY_EMIT_XXX are defined, in which case the compiler would warn about symbol redefinitions since they'd be defined both here and in the source. --- ports/windows/msvc/genhdr.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/windows/msvc/genhdr.targets b/ports/windows/msvc/genhdr.targets index db8cfea7d7..5382b79d92 100644 --- a/ports/windows/msvc/genhdr.targets +++ b/ports/windows/msvc/genhdr.targets @@ -54,7 +54,7 @@ using(var outFile = System.IO.File.CreateText(OutputFile)) { - + $([System.String]::new('%(FullPath)').Replace('$(PyBaseDir)', '$(DestDir)qstr\')) From 94873a48263d5923ba0640900b801b13fcd309d7 Mon Sep 17 00:00:00 2001 From: stijn Date: Fri, 11 Aug 2017 15:33:39 +0200 Subject: [PATCH 0719/1788] windows/msvc: Move build options from .vcxproj to .props files. We want the .vcxproj to be just a container with the minimum content for making it work as a project file for Visual Studio and MSBuild, whereas the actual build options and actions get placed in separate reusable files. This was roughly the case already except some compiler options were overlooked; fix this here: we'll need those common options when adding a project file for building mpy-cross. --- ports/windows/micropython.vcxproj | 10 ---------- ports/windows/msvc/common.props | 1 + ports/windows/msvc/debug.props | 2 ++ ports/windows/msvc/release.props | 5 ++++- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/ports/windows/micropython.vcxproj b/ports/windows/micropython.vcxproj index ee0b98abba..e468cfdae8 100644 --- a/ports/windows/micropython.vcxproj +++ b/ports/windows/micropython.vcxproj @@ -25,29 +25,19 @@ Application - true $(DefaultPlatformToolset) - MultiByte Application - false $(DefaultPlatformToolset) - true - MultiByte Application - true $(DefaultPlatformToolset) - MultiByte Application - false $(DefaultPlatformToolset) - true - MultiByte diff --git a/ports/windows/msvc/common.props b/ports/windows/msvc/common.props index 5fe1b45fef..6735f96d70 100644 --- a/ports/windows/msvc/common.props +++ b/ports/windows/msvc/common.props @@ -8,6 +8,7 @@ $(PyOutDir) $(PyIntDir) $(PyBuildDir)copycookie$(Configuration)$(Platform) + MultiByte
diff --git a/ports/windows/msvc/debug.props b/ports/windows/msvc/debug.props index fa1ca4fcbc..5ae9d64fcd 100644 --- a/ports/windows/msvc/debug.props +++ b/ports/windows/msvc/debug.props @@ -3,6 +3,8 @@ + true + false diff --git a/ports/windows/msvc/release.props b/ports/windows/msvc/release.props index ea0bf433d3..a3fbe2494f 100644 --- a/ports/windows/msvc/release.props +++ b/ports/windows/msvc/release.props @@ -2,7 +2,10 @@ - + + false + true + true From 146c32a14196356fbf3c3b5f2a7c6e41e3b59389 Mon Sep 17 00:00:00 2001 From: stijn Date: Mon, 14 Aug 2017 12:12:30 +0200 Subject: [PATCH 0720/1788] windows/msvc: Enable overriding directories used in the build. Append to PyIncDirs, used to define include directories specific to MicroPython, instead of just overwriting it so project files importing this file can define additional directories. And allow defining the target directory for the executable instead of hardcoding it to the windows directory. Main reason for this change is that it will allow building mpy-cross with msvc. --- ports/windows/msvc/common.props | 2 +- ports/windows/msvc/paths.props | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ports/windows/msvc/common.props b/ports/windows/msvc/common.props index 6735f96d70..2545a36469 100644 --- a/ports/windows/msvc/common.props +++ b/ports/windows/msvc/common.props @@ -28,7 +28,7 @@ - $(PyWinDir)%(FileName)%(Extension) + $(PyTargetDir)%(FileName)%(Extension) diff --git a/ports/windows/msvc/paths.props b/ports/windows/msvc/paths.props index db3af4c0fa..cfd43b708c 100644 --- a/ports/windows/msvc/paths.props +++ b/ports/windows/msvc/paths.props @@ -26,9 +26,10 @@ $([System.IO.Path]::GetFullPath(`$(MSBuildThisFileDirectory)..\..\..`))\ $(PyBaseDir)ports\windows\ $(PyWinDir)build\ + $(PyWinDir) - $(PyBaseDir);$(PyWinDir);$(PyBuildDir);$(PyWinDir)msvc + $(PyIncDirs);$(PyBaseDir);$(PyWinDir);$(PyBuildDir);$(PyWinDir)msvc already in queue\n"); + return; + } + if (ev2->next == NULL) { + break; + } + DEBUG_EVENT_printf(" --> %p\n", ev2->next); + ev2 = ev2->next; + } + ev2->next = ev; + ev->prev = ev2; + } +} + +void ble_npl_event_init(struct ble_npl_event *ev, ble_npl_event_fn *fn, void *arg) { + DEBUG_EVENT_printf("ble_npl_event_init(%p, %p, %p)\n", ev, fn, arg); + ev->fn = fn; + ev->arg = arg; + ev->next = NULL; +} + +void *ble_npl_event_get_arg(struct ble_npl_event *ev) { + DEBUG_EVENT_printf("ble_npl_event_get_arg(%p) -> %p\n", ev, ev->arg); + return ev->arg; +} + +void ble_npl_event_set_arg(struct ble_npl_event *ev, void *arg) { + DEBUG_EVENT_printf("ble_npl_event_set_arg(%p, %p)\n", ev, arg); + ev->arg = arg; +} + +/******************************************************************************/ +// MUTEX + +ble_npl_error_t ble_npl_mutex_init(struct ble_npl_mutex *mu) { + DEBUG_MUTEX_printf("ble_npl_mutex_init(%p)\n", mu); + mu->locked = 0; + return BLE_NPL_OK; +} + +ble_npl_error_t ble_npl_mutex_pend(struct ble_npl_mutex *mu, ble_npl_time_t timeout) { + DEBUG_MUTEX_printf("ble_npl_mutex_pend(%p, %u) locked=%u\n", mu, (uint)timeout, (uint)mu->locked); + mu->locked = 1; + return BLE_NPL_OK; +} + +ble_npl_error_t ble_npl_mutex_release(struct ble_npl_mutex *mu) { + DEBUG_MUTEX_printf("ble_npl_mutex_release(%p) locked=%u\n", mu, (uint)mu->locked); + mu->locked = 0; + return BLE_NPL_OK; +} + +/******************************************************************************/ +// SEM + +ble_npl_error_t ble_npl_sem_init(struct ble_npl_sem *sem, uint16_t tokens) { + DEBUG_SEM_printf("ble_npl_sem_init(%p, %u)\n", sem, (uint)tokens); + sem->count = tokens; + return BLE_NPL_OK; +} + +ble_npl_error_t ble_npl_sem_pend(struct ble_npl_sem *sem, ble_npl_time_t timeout) { + DEBUG_SEM_printf("ble_npl_sem_pend(%p, %u) count=%u\n", sem, (uint)timeout, (uint)sem->count); + if (sem->count == 0) { + uint32_t t0 = mp_hal_ticks_ms(); + while (sem->count == 0 && mp_hal_ticks_ms() - t0 < timeout) { + extern void nimble_uart_process(void); + nimble_uart_process(); + if (sem->count != 0) { + break; + } + __WFI(); + } + if (sem->count == 0) { + printf("timeout\n"); + return BLE_NPL_TIMEOUT; + } + DEBUG_SEM_printf("got response in %u ms\n", (int)(mp_hal_ticks_ms() - t0)); + } + sem->count -= 1; + return BLE_NPL_OK; +} + +ble_npl_error_t ble_npl_sem_release(struct ble_npl_sem *sem) { + DEBUG_SEM_printf("ble_npl_sem_release(%p)\n", sem); + sem->count += 1; + return BLE_NPL_OK; +} + +uint16_t ble_npl_sem_get_count(struct ble_npl_sem *sem) { + DEBUG_SEM_printf("ble_npl_sem_get_count(%p)\n", sem); + return sem->count; +} + +/******************************************************************************/ +// CALLOUT + +static struct ble_npl_callout *global_callout = NULL; + +void os_callout_process(void) { + uint32_t tnow = mp_hal_ticks_ms(); + for (struct ble_npl_callout *c = global_callout; c != NULL; c = c->nextc) { + if (!c->active) { + continue; + } + if ((int32_t)(tnow - c->ticks) >= 0) { + DEBUG_CALLOUT_printf("callout_run(%p) tnow=%u ticks=%u evq=%p\n", c, (uint)tnow, (uint)c->ticks, c->evq); + c->active = false; + if (c->evq) { + ble_npl_eventq_put(c->evq, &c->ev); + } else { + c->ev.fn(&c->ev); + } + DEBUG_CALLOUT_printf("callout_run(%p) done\n", c); + } + } +} + +void ble_npl_callout_init(struct ble_npl_callout *c, struct ble_npl_eventq *evq, ble_npl_event_fn *ev_cb, void *ev_arg) { + DEBUG_CALLOUT_printf("ble_npl_callout_init(%p, %p, %p, %p)\n", c, evq, ev_cb, ev_arg); + c->active = false; + c->ticks = 0; + c->evq = evq; + ble_npl_event_init(&c->ev, ev_cb, ev_arg); + + struct ble_npl_callout **c2; + for (c2 = &global_callout; *c2 != NULL; c2 = &(*c2)->nextc) { + if (c == *c2) { + // callout already in linked list so don't link it in again + return; + } + } + *c2 = c; + c->nextc = NULL; +} + +ble_npl_error_t ble_npl_callout_reset(struct ble_npl_callout *c, ble_npl_time_t ticks) { + DEBUG_CALLOUT_printf("ble_npl_callout_reset(%p, %u) tnow=%u\n", c, (uint)ticks, (uint)mp_hal_ticks_ms()); + c->active = true; + c->ticks = ble_npl_time_get() + ticks; + return BLE_NPL_OK; +} + +void ble_npl_callout_stop(struct ble_npl_callout *c) { + DEBUG_CALLOUT_printf("ble_npl_callout_stop(%p)\n", c); + c->active = false; +} + +bool ble_npl_callout_is_active(struct ble_npl_callout *c) { + DEBUG_CALLOUT_printf("ble_npl_callout_is_active(%p)\n", c); + return c->active; +} + +ble_npl_time_t ble_npl_callout_get_ticks(struct ble_npl_callout *c) { + DEBUG_CALLOUT_printf("ble_npl_callout_get_ticks(%p)\n", c); + return c->ticks; +} + +ble_npl_time_t ble_npl_callout_remaining_ticks(struct ble_npl_callout *c, ble_npl_time_t now) { + DEBUG_CALLOUT_printf("ble_npl_callout_remaining_ticks(%p, %u)\n", c, (uint)now); + if (c->ticks > now) { + return c->ticks - now; + } else { + return 0; + } +} + +void *ble_npl_callout_get_arg(struct ble_npl_callout *c) { + DEBUG_CALLOUT_printf("ble_npl_callout_get_arg(%p)\n", c); + return ble_npl_event_get_arg(&c->ev); +} + +void ble_npl_callout_set_arg(struct ble_npl_callout *c, void *arg) { + DEBUG_CALLOUT_printf("ble_npl_callout_set_arg(%p, %p)\n", c, arg); + ble_npl_event_set_arg(&c->ev, arg); +} + +/******************************************************************************/ +// TIME + +uint32_t ble_npl_time_get(void) { + DEBUG_TIME_printf("ble_npl_time_get -> %u\n", (uint)mp_hal_ticks_ms()); + return mp_hal_ticks_ms(); +} + +ble_npl_error_t ble_npl_time_ms_to_ticks(uint32_t ms, ble_npl_time_t *out_ticks) { + DEBUG_TIME_printf("ble_npl_time_ms_to_ticks(%u)\n", (uint)ms); + *out_ticks = ms; + return BLE_NPL_OK; +} + +ble_npl_time_t ble_npl_time_ms_to_ticks32(uint32_t ms) { + DEBUG_TIME_printf("ble_npl_time_ms_to_ticks32(%u)\n", (uint)ms); + return ms; +} + +uint32_t ble_npl_time_ticks_to_ms32(ble_npl_time_t ticks) { + DEBUG_TIME_printf("ble_npl_time_ticks_to_ms32(%u)\n", (uint)ticks); + return ticks; +} + +void ble_npl_time_delay(ble_npl_time_t ticks) { + mp_hal_delay_ms(ticks + 1); +} + +/******************************************************************************/ +// CRITICAL + +uint32_t ble_npl_hw_enter_critical(void) { + DEBUG_CRIT_printf("ble_npl_hw_enter_critical()\n"); + return raise_irq_pri(15); +} + +void ble_npl_hw_exit_critical(uint32_t ctx) { + DEBUG_CRIT_printf("ble_npl_hw_exit_critical(%u)\n", (uint)ctx); + restore_irq_pri(ctx); +} diff --git a/extmod/nimble/syscfg/syscfg.h b/extmod/nimble/syscfg/syscfg.h new file mode 100644 index 0000000000..0d3acf9a76 --- /dev/null +++ b/extmod/nimble/syscfg/syscfg.h @@ -0,0 +1,160 @@ +#ifndef MICROPY_INCLUDED_EXTMOD_NIMBLE_SYSCFG_H +#define MICROPY_INCLUDED_EXTMOD_NIMBLE_SYSCFG_H + +#include "py/mphal.h" +#include "uart.h" + +void *nimble_malloc(size_t size); +void nimble_free(void *ptr); +void *nimble_realloc(void *ptr, size_t size); + +#define malloc(size) nimble_malloc(size) +#define free(ptr) nimble_free(ptr) +#define realloc(ptr, size) nimble_realloc(ptr, size) + +int nimble_sprintf(char *str, const char *fmt, ...); +#define sprintf(str, fmt, ...) nimble_sprintf(str, fmt, __VA_ARGS__) + +#define MYNEWT_VAL(x) MYNEWT_VAL_ ## x + +#define MYNEWT_VAL_LOG_LEVEL (255) + +/*** compiler/arm-none-eabi-m4 */ +#define MYNEWT_VAL_HARDFLOAT (1) + +/*** kernel/os */ +#define MYNEWT_VAL_FLOAT_USER (0) +#define MYNEWT_VAL_MSYS_1_BLOCK_COUNT (12) +#define MYNEWT_VAL_MSYS_1_BLOCK_SIZE (292) +#define MYNEWT_VAL_MSYS_2_BLOCK_COUNT (0) +#define MYNEWT_VAL_MSYS_2_BLOCK_SIZE (0) +#define MYNEWT_VAL_OS_CPUTIME_FREQ (1000000) +#define MYNEWT_VAL_OS_CPUTIME_TIMER_NUM (0) +#define MYNEWT_VAL_OS_CTX_SW_STACK_CHECK (0) +#define MYNEWT_VAL_OS_CTX_SW_STACK_GUARD (4) +#define MYNEWT_VAL_OS_MAIN_STACK_SIZE (1024) +#define MYNEWT_VAL_OS_MAIN_TASK_PRIO (127) +#define MYNEWT_VAL_OS_MEMPOOL_CHECK (0) +#define MYNEWT_VAL_OS_MEMPOOL_POISON (0) + +/*** nimble */ +#define MYNEWT_VAL_BLE_EXT_ADV (0) +#define MYNEWT_VAL_BLE_EXT_ADV_MAX_SIZE (31) +#define MYNEWT_VAL_BLE_MAX_CONNECTIONS (1) +#define MYNEWT_VAL_BLE_MULTI_ADV_INSTANCES (0) +#define MYNEWT_VAL_BLE_ROLE_BROADCASTER (1) +#define MYNEWT_VAL_BLE_ROLE_CENTRAL (1) +#define MYNEWT_VAL_BLE_ROLE_OBSERVER (1) +#define MYNEWT_VAL_BLE_ROLE_PERIPHERAL (1) +#define MYNEWT_VAL_BLE_WHITELIST (1) + +/*** nimble/host */ +#define MYNEWT_VAL_BLE_ATT_PREFERRED_MTU (256) +#define MYNEWT_VAL_BLE_ATT_SVR_FIND_INFO (1) +#define MYNEWT_VAL_BLE_ATT_SVR_FIND_TYPE (1) +#define MYNEWT_VAL_BLE_ATT_SVR_INDICATE (1) +#define MYNEWT_VAL_BLE_ATT_SVR_MAX_PREP_ENTRIES (64) +#define MYNEWT_VAL_BLE_ATT_SVR_NOTIFY (1) +#define MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE (1) +#define MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE_TMO (30000) +#define MYNEWT_VAL_BLE_ATT_SVR_READ (1) +#define MYNEWT_VAL_BLE_ATT_SVR_READ_BLOB (1) +#define MYNEWT_VAL_BLE_ATT_SVR_READ_GROUP_TYPE (1) +#define MYNEWT_VAL_BLE_ATT_SVR_READ_MULT (1) +#define MYNEWT_VAL_BLE_ATT_SVR_READ_TYPE (1) +#define MYNEWT_VAL_BLE_ATT_SVR_SIGNED_WRITE (1) +#define MYNEWT_VAL_BLE_ATT_SVR_WRITE (1) +#define MYNEWT_VAL_BLE_ATT_SVR_WRITE_NO_RSP (1) +#define MYNEWT_VAL_BLE_GAP_MAX_PENDING_CONN_PARAM_UPDATE (1) +#define MYNEWT_VAL_BLE_GATT_DISC_ALL_CHRS (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#define MYNEWT_VAL_BLE_GATT_DISC_ALL_DSCS (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#define MYNEWT_VAL_BLE_GATT_DISC_ALL_SVCS (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#define MYNEWT_VAL_BLE_GATT_DISC_CHR_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#define MYNEWT_VAL_BLE_GATT_DISC_SVC_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#define MYNEWT_VAL_BLE_GATT_FIND_INC_SVCS (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#define MYNEWT_VAL_BLE_GATT_INDICATE (1) +#define MYNEWT_VAL_BLE_GATT_MAX_PROCS (4) +#define MYNEWT_VAL_BLE_GATT_NOTIFY (1) +#define MYNEWT_VAL_BLE_GATT_READ (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#define MYNEWT_VAL_BLE_GATT_READ_LONG (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#define MYNEWT_VAL_BLE_GATT_READ_MAX_ATTRS (8) +#define MYNEWT_VAL_BLE_GATT_READ_MULT (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#define MYNEWT_VAL_BLE_GATT_READ_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#define MYNEWT_VAL_BLE_GATT_RESUME_RATE (1000) +#define MYNEWT_VAL_BLE_GATT_SIGNED_WRITE (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#define MYNEWT_VAL_BLE_GATT_WRITE (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#define MYNEWT_VAL_BLE_GATT_WRITE_LONG (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#define MYNEWT_VAL_BLE_GATT_WRITE_MAX_ATTRS (4) +#define MYNEWT_VAL_BLE_GATT_WRITE_NO_RSP (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#define MYNEWT_VAL_BLE_GATT_WRITE_RELIABLE (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#define MYNEWT_VAL_BLE_HOST (1) +#define MYNEWT_VAL_BLE_HS_DEBUG (0) +#define MYNEWT_VAL_BLE_HS_FLOW_CTRL (0) +#define MYNEWT_VAL_BLE_HS_FLOW_CTRL_ITVL (1000) +#define MYNEWT_VAL_BLE_HS_FLOW_CTRL_THRESH (2) +#define MYNEWT_VAL_BLE_HS_FLOW_CTRL_TX_ON_DISCONNECT (0) +#define MYNEWT_VAL_BLE_HS_PHONY_HCI_ACKS (0) +#define MYNEWT_VAL_BLE_HS_REQUIRE_OS (1) +#define MYNEWT_VAL_BLE_L2CAP_COC_MAX_NUM (0) +#define MYNEWT_VAL_BLE_L2CAP_JOIN_RX_FRAGS (1) +#define MYNEWT_VAL_BLE_L2CAP_MAX_CHANS (3*MYNEWT_VAL_BLE_MAX_CONNECTIONS) +#define MYNEWT_VAL_BLE_L2CAP_RX_FRAG_TIMEOUT (30000) +#define MYNEWT_VAL_BLE_L2CAP_SIG_MAX_PROCS (1) +#define MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE (128) +#define MYNEWT_VAL_BLE_MONITOR_RTT (0) +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED (1) +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME ("monitor") +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE (256) +#define MYNEWT_VAL_BLE_MONITOR_UART (0) +#define MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE (1000000) +#define MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE (64) +#define MYNEWT_VAL_BLE_MONITOR_UART_DEV ("uart0") +#define MYNEWT_VAL_BLE_RPA_TIMEOUT (300) +#define MYNEWT_VAL_BLE_SM_BONDING (0) +#define MYNEWT_VAL_BLE_SM_IO_CAP (BLE_HS_IO_NO_INPUT_OUTPUT) +#define MYNEWT_VAL_BLE_SM_KEYPRESS (0) +#define MYNEWT_VAL_BLE_SM_LEGACY (1) +#define MYNEWT_VAL_BLE_SM_MAX_PROCS (1) +#define MYNEWT_VAL_BLE_SM_MITM (0) +#define MYNEWT_VAL_BLE_SM_OOB_DATA_FLAG (0) +#define MYNEWT_VAL_BLE_SM_OUR_KEY_DIST (0) +#define MYNEWT_VAL_BLE_SM_SC (1) +#define MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST (0) +#define MYNEWT_VAL_BLE_STORE_MAX_BONDS (3) +#define MYNEWT_VAL_BLE_STORE_MAX_CCCDS (8) + +/*** nimble/host/services/gap */ +#define MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE (0) +#define MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE_WRITE_PERM (-1) +#define MYNEWT_VAL_BLE_SVC_GAP_CENTRAL_ADDRESS_RESOLUTION (-1) +#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME ("pybd") +#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH (31) +#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME_WRITE_PERM (-1) +#define MYNEWT_VAL_BLE_SVC_GAP_PPCP_MAX_CONN_INTERVAL (0) +#define MYNEWT_VAL_BLE_SVC_GAP_PPCP_MIN_CONN_INTERVAL (0) +#define MYNEWT_VAL_BLE_SVC_GAP_PPCP_SLAVE_LATENCY (0) +#define MYNEWT_VAL_BLE_SVC_GAP_PPCP_SUPERVISION_TMO (0) + +/* Overridden by targets/porting-nimble (defined by nimble/transport) */ +#define MYNEWT_VAL_BLE_HCI_TRANSPORT_NIMBLE_BUILTIN (0) +#define MYNEWT_VAL_BLE_HCI_TRANSPORT_RAM (0) +#define MYNEWT_VAL_BLE_HCI_TRANSPORT_SOCKET (0) +#define MYNEWT_VAL_BLE_HCI_TRANSPORT_UART (1) + +/*** nimble/transport/uart */ +#define MYNEWT_VAL_BLE_ACL_BUF_COUNT (12) +#define MYNEWT_VAL_BLE_ACL_BUF_SIZE (255) +#define MYNEWT_VAL_BLE_HCI_ACL_OUT_COUNT (12) +#define MYNEWT_VAL_BLE_HCI_EVT_BUF_SIZE (70) +#define MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT (8) +#define MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT (8) + +/* Overridden by targets/porting-nimble (defined by nimble/transport/uart) */ +#define MYNEWT_VAL_BLE_HCI_UART_BAUD (MICROPY_HW_BLE_UART_BAUDRATE) +#define MYNEWT_VAL_BLE_HCI_UART_DATA_BITS (8) +#define MYNEWT_VAL_BLE_HCI_UART_FLOW_CTRL (1) +#define MYNEWT_VAL_BLE_HCI_UART_PARITY (HAL_UART_PARITY_NONE) +#define MYNEWT_VAL_BLE_HCI_UART_PORT (MICROPY_HW_BLE_UART_ID) +#define MYNEWT_VAL_BLE_HCI_UART_STOP_BITS (1) + +#endif // MICROPY_INCLUDED_EXTMOD_NIMBLE_SYSCFG_H From d72dbb822c96c003a202565006a97a2bfdff9210 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Sun, 29 Sep 2019 23:04:58 +1000 Subject: [PATCH 0762/1788] stm32: Provide port-specific implementation for Nimble on STM32. --- .travis.yml | 2 +- ports/stm32/Makefile | 9 ++++ ports/stm32/main.c | 11 ++++ ports/stm32/modnetwork.c | 5 ++ ports/stm32/mpconfigport.h | 9 +++- ports/stm32/nimble_hci_uart.c | 96 +++++++++++++++++++++++++++++++++++ ports/stm32/pendsv.h | 5 +- ports/stm32/systick.h | 3 ++ 8 files changed, 137 insertions(+), 3 deletions(-) create mode 100644 ports/stm32/nimble_hci_uart.c diff --git a/.travis.yml b/.travis.yml index 708329aa12..a72f3bc1a3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,7 +32,7 @@ jobs: - sudo apt-get install libnewlib-arm-none-eabi - arm-none-eabi-gcc --version script: - - git submodule update --init lib/lwip lib/mbedtls lib/stm32lib + - git submodule update --init lib/lwip lib/mbedtls lib/stm32lib lib/mynewt-nimble - make ${MAKEOPTS} -C mpy-cross - make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_F091RC - make ${MAKEOPTS} -C ports/stm32 BOARD=PYBV11 MICROPY_PY_WIZNET5K=5200 MICROPY_PY_CC3K=1 diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 8dde851297..0e3b4f8e33 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -428,6 +428,15 @@ CFLAGS_MOD += -DMBEDTLS_CONFIG_FILE='"mbedtls/mbedtls_config.h"' SRC_MOD += mbedtls/mbedtls_port.c endif +ifeq ($(MICROPY_BLUETOOTH_NIMBLE),1) +include $(TOP)/extmod/nimble/nimble.mk +SRC_C += nimble_hci_uart.c +EXTMOD_SRC_C += extmod/modbluetooth_nimble.c +ifeq ($(MICROPY_PY_NETWORK_CYW43),1) +DRIVERS_SRC_C += drivers/cyw43/cywbt.c +endif +endif + OBJ = OBJ += $(PY_O) OBJ += $(addprefix $(BUILD)/, $(SRC_LIB:.c=.o)) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 48ad3b8be4..2da3626f12 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -43,6 +43,10 @@ #include "drivers/cyw43/cyw43.h" #endif +#if MICROPY_BLUETOOTH_NIMBLE +#include "extmod/modbluetooth.h" +#endif + #include "mpu.h" #include "systick.h" #include "pendsv.h" @@ -500,6 +504,10 @@ void stm32_main(uint32_t reset_mode) { #endif systick_enable_dispatch(SYSTICK_DISPATCH_LWIP, mod_network_lwip_poll_wrapper); #endif + #if MICROPY_BLUETOOTH_NIMBLE + extern void mod_bluetooth_nimble_poll_wrapper(uint32_t ticks_ms); + systick_enable_dispatch(SYSTICK_DISPATCH_NIMBLE, mod_bluetooth_nimble_poll_wrapper); + #endif #if MICROPY_PY_NETWORK_CYW43 { @@ -729,6 +737,9 @@ soft_reset_exit: #endif printf("MPY: soft reboot\n"); + #if MICROPY_BLUETOOTH_NIMBLE + mp_bluetooth_deinit(); + #endif #if MICROPY_PY_NETWORK mod_network_deinit(); #endif diff --git a/ports/stm32/modnetwork.c b/ports/stm32/modnetwork.c index 13ecf444f0..19a60103f8 100644 --- a/ports/stm32/modnetwork.c +++ b/ports/stm32/modnetwork.c @@ -63,6 +63,11 @@ STATIC void pyb_lwip_poll(void) { // Run the lwIP internal updates sys_check_timeouts(); + + #if MICROPY_BLUETOOTH_NIMBLE + extern void nimble_poll(void); + nimble_poll(); + #endif } void mod_network_lwip_poll_wrapper(uint32_t ticks_ms) { diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 20554d9e62..b9c6cdedd7 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -289,6 +289,12 @@ extern const struct _mp_obj_module_t mp_module_onewire; #define MICROPY_PORT_ROOT_POINTER_MBEDTLS #endif +#if MICROPY_BLUETOOTH_NIMBLE +#define MICROPY_PORT_ROOT_POINTER_BLUETOOTH_NIMBLE void **bluetooth_nimble_memory; +#else +#define MICROPY_PORT_ROOT_POINTER_BLUETOOTH_NIMBLE +#endif + #define MICROPY_PORT_ROOT_POINTERS \ const char *readline_hist[8]; \ \ @@ -318,7 +324,8 @@ extern const struct _mp_obj_module_t mp_module_onewire; /* list of registered NICs */ \ mp_obj_list_t mod_network_nic_list; \ \ - MICROPY_PORT_ROOT_POINTER_MBEDTLS + MICROPY_PORT_ROOT_POINTER_MBEDTLS \ + MICROPY_PORT_ROOT_POINTER_BLUETOOTH_NIMBLE \ // type definitions for the specific machine diff --git a/ports/stm32/nimble_hci_uart.c b/ports/stm32/nimble_hci_uart.c new file mode 100644 index 0000000000..104a64b732 --- /dev/null +++ b/ports/stm32/nimble_hci_uart.c @@ -0,0 +1,96 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2019 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/mphal.h" +#include "uart.h" +#include "pendsv.h" +#include "drivers/cyw43/cywbt.h" + +#if MICROPY_BLUETOOTH_NIMBLE + +/******************************************************************************/ +// UART +pyb_uart_obj_t bt_hci_uart_obj; +static uint8_t hci_uart_rxbuf[512]; + +extern void nimble_poll(void); + +mp_obj_t mp_uart_interrupt(mp_obj_t self_in) { + pendsv_schedule_dispatch(PENDSV_DISPATCH_NIMBLE, nimble_poll); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_uart_interrupt_obj, mp_uart_interrupt); + +int nimble_hci_uart_set_baudrate(uint32_t baudrate) { + uart_init(&bt_hci_uart_obj, baudrate, UART_WORDLENGTH_8B, UART_PARITY_NONE, UART_STOPBITS_1, UART_HWCONTROL_RTS | UART_HWCONTROL_CTS); + uart_set_rxbuf(&bt_hci_uart_obj, sizeof(hci_uart_rxbuf), hci_uart_rxbuf); + return 0; +} + +int nimble_hci_uart_configure(uint32_t port) { + // bits (8), stop (1), parity (none) and flow (rts/cts) are assumed to match MYNEWT_VAL_BLE_HCI_UART_ constants in syscfg.h. + bt_hci_uart_obj.base.type = &pyb_uart_type; + bt_hci_uart_obj.uart_id = port; + bt_hci_uart_obj.is_static = true; + bt_hci_uart_obj.timeout = 2; + bt_hci_uart_obj.timeout_char = 2; + MP_STATE_PORT(pyb_uart_obj_all)[bt_hci_uart_obj.uart_id - 1] = &bt_hci_uart_obj; + return 0; +} + +int nimble_hci_uart_activate(void) { + // Interrupt on RX chunk received (idle) + // Trigger nimble poll when this happens + mp_obj_t uart_irq_fn = mp_load_attr(&bt_hci_uart_obj, MP_QSTR_irq); + mp_obj_t uargs[] = { + MP_OBJ_FROM_PTR(&mp_uart_interrupt_obj), + MP_OBJ_NEW_SMALL_INT(UART_FLAG_IDLE), + mp_const_true, + }; + mp_call_function_n_kw(uart_irq_fn, 3, 0, uargs); + + #if MICROPY_PY_NETWORK_CYW43 + cywbt_init(); + cywbt_activate(); + #endif + + return 0; +} + +mp_uint_t nimble_hci_uart_rx_any() { + return uart_rx_any(&bt_hci_uart_obj); +} + +int nimble_hci_uart_rx_char() { + return uart_rx_char(&bt_hci_uart_obj); +} + +void nimble_hci_uart_tx_strn(const char *str, uint len) { + uart_tx_strn(&bt_hci_uart_obj, str, len); +} + +#endif // MICROPY_BLUETOOTH_NIMBLE diff --git a/ports/stm32/pendsv.h b/ports/stm32/pendsv.h index 6cbfe8b2ec..9851a5ece7 100644 --- a/ports/stm32/pendsv.h +++ b/ports/stm32/pendsv.h @@ -33,10 +33,13 @@ enum { PENDSV_DISPATCH_CYW43, #endif #endif + #if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE + PENDSV_DISPATCH_NIMBLE, + #endif PENDSV_DISPATCH_MAX }; -#if MICROPY_PY_NETWORK && MICROPY_PY_LWIP +#if (MICROPY_PY_NETWORK && MICROPY_PY_LWIP) || (MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE) #define PENDSV_DISPATCH_NUM_SLOTS PENDSV_DISPATCH_MAX #endif diff --git a/ports/stm32/systick.h b/ports/stm32/systick.h index 6a05a4990a..a70f03e176 100644 --- a/ports/stm32/systick.h +++ b/ports/stm32/systick.h @@ -37,6 +37,9 @@ enum { #if MICROPY_PY_NETWORK && MICROPY_PY_LWIP SYSTICK_DISPATCH_LWIP, #endif + #if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE + SYSTICK_DISPATCH_NIMBLE, + #endif SYSTICK_DISPATCH_MAX }; From 42e9bdf19b417e46e957b6f0c5592bb316ceeca2 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 27 Aug 2019 16:35:02 +1000 Subject: [PATCH 0763/1788] py/ringbuf: Add helpers for put16/get16. --- py/py.mk | 1 + py/ringbuf.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++ py/ringbuf.h | 17 +++++++++++++- 3 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 py/ringbuf.c diff --git a/py/py.mk b/py/py.mk index a3d9e790fc..d30ee81bc1 100644 --- a/py/py.mk +++ b/py/py.mk @@ -85,6 +85,7 @@ PY_CORE_O_BASENAME = $(addprefix py/,\ runtime_utils.o \ scheduler.o \ nativeglue.o \ + ringbuf.o \ stackctrl.o \ argcheck.o \ warning.o \ diff --git a/py/ringbuf.c b/py/ringbuf.c new file mode 100644 index 0000000000..8795e1eda9 --- /dev/null +++ b/py/ringbuf.c @@ -0,0 +1,66 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Jim Mussared + * + * 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 "ringbuf.h" + +int ringbuf_get16(ringbuf_t *r) { + if (r->iget == r->iput) { + return -1; + } + uint32_t iget_a = r->iget + 1; + if (iget_a == r->size) { + iget_a = 0; + } + if (iget_a == r->iput) { + return -1; + } + uint16_t v = (r->buf[r->iget] << 8) | (r->buf[iget_a]); + r->iget = iget_a + 1; + if (r->iget == r->size) { + r->iget = 0; + } + return v; +} + +int ringbuf_put16(ringbuf_t *r, uint16_t v) { + uint32_t iput_a = r->iput + 1; + if (iput_a == r->size) { + iput_a = 0; + } + if (iput_a == r->iget) { + return -1; + } + uint32_t iput_b = iput_a + 1; + if (iput_b == r->size) { + iput_b = 0; + } + if (iput_b == r->iget) { + return -1; + } + r->buf[r->iput] = (v >> 8) & 0xff; + r->buf[iput_a] = v & 0xff; + r->iput = iput_b; + return 0; +} diff --git a/py/ringbuf.h b/py/ringbuf.h index b416927060..6b0d209bd1 100644 --- a/py/ringbuf.h +++ b/py/ringbuf.h @@ -26,6 +26,9 @@ #ifndef MICROPY_INCLUDED_PY_RINGBUF_H #define MICROPY_INCLUDED_PY_RINGBUF_H +#include +#include + typedef struct _ringbuf_t { uint8_t *buf; uint16_t size; @@ -37,7 +40,7 @@ typedef struct _ringbuf_t { // byte buf_array[N]; // ringbuf_t buf = {buf_array, sizeof(buf_array)}; -// Dynamic initialization. This creates root pointer! +// Dynamic initialization. This needs to become findable as a root pointer! #define ringbuf_alloc(r, sz) \ { \ (r)->buf = m_new(uint8_t, sz); \ @@ -69,4 +72,16 @@ static inline int ringbuf_put(ringbuf_t *r, uint8_t v) { return 0; } +static inline size_t ringbuf_free(ringbuf_t *r) { + return (r->size + r->iget - r->iput - 1) % r->size; +} + +static inline size_t ringbuf_avail(ringbuf_t *r) { + return (r->size + r->iput - r->iget) % r->size; +} + +// Note: big-endian. No-op if not enough room available for both bytes. +int ringbuf_get16(ringbuf_t *r); +int ringbuf_put16(ringbuf_t *r, uint16_t v); + #endif // MICROPY_INCLUDED_PY_RINGBUF_H From f67fd95f8d412e1ee17b36861aa12e02c30939fa Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 30 Sep 2019 11:29:52 +1000 Subject: [PATCH 0764/1788] unix/coverage: Add coverage tests for ringbuf. --- ports/unix/coverage.c | 72 ++++++++++++++++++++++++++++++++ tests/unix/extra_coverage.py.exp | 22 ++++++++++ 2 files changed, 94 insertions(+) diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index 538c32d614..b6ebc9fb7e 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -10,6 +10,7 @@ #include "py/builtin.h" #include "py/emit.h" #include "py/formatfloat.h" +#include "py/ringbuf.h" #include "py/stream.h" #include "py/binary.h" #include "py/bc.h" @@ -419,6 +420,77 @@ STATIC mp_obj_t extra_coverage(void) { } } + // ringbuf + { + byte buf[100]; + ringbuf_t ringbuf = {buf, sizeof(buf), 0, 0}; + + mp_printf(&mp_plat_print, "# ringbuf\n"); + + // Single-byte put/get with empty ringbuf. + mp_printf(&mp_plat_print, "%d %d\n", ringbuf_free(&ringbuf), ringbuf_avail(&ringbuf)); + ringbuf_put(&ringbuf, 22); + mp_printf(&mp_plat_print, "%d %d\n", ringbuf_free(&ringbuf), ringbuf_avail(&ringbuf)); + mp_printf(&mp_plat_print, "%d\n", ringbuf_get(&ringbuf)); + mp_printf(&mp_plat_print, "%d %d\n", ringbuf_free(&ringbuf), ringbuf_avail(&ringbuf)); + + // Two-byte put/get with empty ringbuf. + ringbuf_put16(&ringbuf, 0xaa55); + mp_printf(&mp_plat_print, "%d %d\n", ringbuf_free(&ringbuf), ringbuf_avail(&ringbuf)); + mp_printf(&mp_plat_print, "%04x\n", ringbuf_get16(&ringbuf)); + mp_printf(&mp_plat_print, "%d %d\n", ringbuf_free(&ringbuf), ringbuf_avail(&ringbuf)); + + // Two-byte put with full ringbuf. + for (int i = 0; i < 99; ++i) { + ringbuf_put(&ringbuf, i); + } + mp_printf(&mp_plat_print, "%d %d\n", ringbuf_free(&ringbuf), ringbuf_avail(&ringbuf)); + mp_printf(&mp_plat_print, "%d\n", ringbuf_put16(&ringbuf, 0x11bb)); + // Two-byte put with one byte free. + ringbuf_get(&ringbuf); + mp_printf(&mp_plat_print, "%d %d\n", ringbuf_free(&ringbuf), ringbuf_avail(&ringbuf)); + mp_printf(&mp_plat_print, "%d\n", ringbuf_put16(&ringbuf, 0x3377)); + ringbuf_get(&ringbuf); + mp_printf(&mp_plat_print, "%d %d\n", ringbuf_free(&ringbuf), ringbuf_avail(&ringbuf)); + mp_printf(&mp_plat_print, "%d\n", ringbuf_put16(&ringbuf, 0xcc99)); + for (int i = 0; i < 97; ++i) { + ringbuf_get(&ringbuf); + } + mp_printf(&mp_plat_print, "%04x\n", ringbuf_get16(&ringbuf)); + mp_printf(&mp_plat_print, "%d %d\n", ringbuf_free(&ringbuf), ringbuf_avail(&ringbuf)); + + // Two-byte put with wrap around on first byte: + ringbuf.iput = 0; + ringbuf.iget = 0; + for (int i = 0; i < 99; ++i) { + ringbuf_put(&ringbuf, i); + ringbuf_get(&ringbuf); + } + mp_printf(&mp_plat_print, "%d\n", ringbuf_put16(&ringbuf, 0x11bb)); + mp_printf(&mp_plat_print, "%04x\n", ringbuf_get16(&ringbuf)); + + // Two-byte put with wrap around on second byte: + ringbuf.iput = 0; + ringbuf.iget = 0; + for (int i = 0; i < 98; ++i) { + ringbuf_put(&ringbuf, i); + ringbuf_get(&ringbuf); + } + mp_printf(&mp_plat_print, "%d\n", ringbuf_put16(&ringbuf, 0x22ff)); + mp_printf(&mp_plat_print, "%04x\n", ringbuf_get16(&ringbuf)); + + // Two-byte get from empty ringbuf. + ringbuf.iput = 0; + ringbuf.iget = 0; + mp_printf(&mp_plat_print, "%d\n", ringbuf_get16(&ringbuf)); + + // Two-byte get from ringbuf with one byte available. + ringbuf.iput = 0; + ringbuf.iget = 0; + ringbuf_put(&ringbuf, 0xaa); + mp_printf(&mp_plat_print, "%d\n", ringbuf_get16(&ringbuf)); + } + mp_obj_streamtest_t *s = m_new_obj(mp_obj_streamtest_t); s->base.type = &mp_type_stest_fileio; s->buf = NULL; diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index 54c5b63e2b..8922f96162 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -75,6 +75,28 @@ unlocked 1 2 3 +# ringbuf +99 0 +98 1 +22 +99 0 +97 2 +aa55 +99 0 +0 99 +-1 +1 98 +-1 +2 97 +0 +cc99 +99 0 +0 +11bb +0 +22ff +-1 +-1 0123456789 b'0123456789' 7300 7300 From 16f8ceeaaa8262e9483226b18a61da233f257974 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Wed, 24 Jul 2019 00:49:06 +1000 Subject: [PATCH 0765/1788] extmod/modbluetooth: Add low-level Python BLE API. --- extmod/modbluetooth.c | 967 ++++++++++++++++++++++++++++++++++++++++++ extmod/modbluetooth.h | 248 +++++++++++ py/mpstate.h | 4 + py/py.mk | 1 + py/runtime.c | 4 + 5 files changed, 1224 insertions(+) create mode 100644 extmod/modbluetooth.c create mode 100644 extmod/modbluetooth.h diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c new file mode 100644 index 0000000000..f4996f7e88 --- /dev/null +++ b/extmod/modbluetooth.c @@ -0,0 +1,967 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Ayke van Laethem + * Copyright (c) 2019 Jim Mussared + * + * 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/binary.h" +#include "py/misc.h" +#include "py/obj.h" +#include "py/objstr.h" +#include "py/objarray.h" +#include "py/qstr.h" +#include "py/runtime.h" +#include "extmod/modbluetooth.h" +#include + +#if MICROPY_PY_BLUETOOTH + +#if !MICROPY_ENABLE_SCHEDULER +#error modbluetooth requires MICROPY_ENABLE_SCHEDULER +#endif + +// This is used to protect the ringbuffer. +#ifndef MICROPY_PY_BLUETOOTH_ENTER +#define MICROPY_PY_BLUETOOTH_ENTER mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); +#define MICROPY_PY_BLUETOOTH_EXIT MICROPY_END_ATOMIC_SECTION(atomic_state); +#endif + +#define MP_BLUETOOTH_CONNECT_DEFAULT_SCAN_DURATION_MS 2000 + +#define MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_TUPLE_LEN 5 +#define MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN (MICROPY_PY_BLUETOOTH_RINGBUF_SIZE / 2) + +STATIC const mp_obj_type_t bluetooth_ble_type; +STATIC const mp_obj_type_t bluetooth_uuid_type; + +typedef struct { + mp_obj_base_t base; + mp_obj_t irq_handler; + mp_obj_t irq_data_tuple; + uint8_t irq_data_bytes[MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN]; + mp_obj_t irq_data_uuid; + uint16_t irq_trigger; + ringbuf_t ringbuf; +} mp_obj_bluetooth_ble_t; + +// TODO: this seems like it could be generic? +STATIC mp_obj_t bluetooth_handle_errno(int err) { + if (err != 0) { + mp_raise_OSError(err); + } + return mp_const_none; +} + +// ---------------------------------------------------------------------------- +// UUID object +// ---------------------------------------------------------------------------- + +// Parse string UUIDs, which are expected to be 128-bit UUIDs. +STATIC void mp_bluetooth_parse_uuid_128bit_str(mp_obj_t obj, uint8_t *uuid) { + size_t str_len; + const char *str_data = mp_obj_str_get_data(obj, &str_len); + int uuid_i = 32; + for (int i = 0; i < str_len; i++) { + char c = str_data[i]; + if (c == '-') { + continue; + } + if (!unichar_isxdigit(c)) { + mp_raise_ValueError("invalid char in UUID"); + } + c = unichar_xdigit_value(c); + uuid_i--; + if (uuid_i < 0) { + mp_raise_ValueError("UUID too long"); + } + if (uuid_i % 2 == 0) { + // lower nibble + uuid[uuid_i/2] |= c; + } else { + // upper nibble + uuid[uuid_i/2] = c << 4; + } + } + if (uuid_i > 0) { + mp_raise_ValueError("UUID too short"); + } +} + +STATIC mp_obj_t bluetooth_uuid_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + mp_arg_check_num(n_args, n_kw, 1, 1, false); + + mp_obj_bluetooth_uuid_t *self = m_new_obj(mp_obj_bluetooth_uuid_t); + self->base.type = &bluetooth_uuid_type; + + if (mp_obj_is_int(all_args[0])) { + self->type = MP_BLUETOOTH_UUID_TYPE_16; + mp_int_t value = mp_obj_get_int(all_args[0]); + if (value > 65535) { + mp_raise_ValueError("invalid UUID"); + } + self->uuid._16 = value; + } else { + self->type = MP_BLUETOOTH_UUID_TYPE_128; + mp_bluetooth_parse_uuid_128bit_str(all_args[0], self->uuid._128); + } + + return self; +} + +STATIC mp_obj_t bluetooth_uuid_unary_op(mp_unary_op_t op, mp_obj_t self_in) { + mp_obj_bluetooth_uuid_t *self = MP_OBJ_TO_PTR(self_in); + switch (op) { + case MP_UNARY_OP_HASH: { + if (self->type == MP_BLUETOOTH_UUID_TYPE_16) { + return mp_unary_op(MP_UNARY_OP_HASH, MP_OBJ_NEW_SMALL_INT(self->uuid._16)); + + } else if (self->type == MP_BLUETOOTH_UUID_TYPE_32) { + return mp_unary_op(MP_UNARY_OP_HASH, MP_OBJ_NEW_SMALL_INT(self->uuid._32)); + + } else if (self->type == MP_BLUETOOTH_UUID_TYPE_128) { + return MP_OBJ_NEW_SMALL_INT(qstr_compute_hash(self->uuid._128, sizeof(self->uuid._128))); + } + return MP_OBJ_NULL; + } + default: return MP_OBJ_NULL; // op not supported + } +} + + +STATIC void bluetooth_uuid_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + mp_obj_bluetooth_uuid_t *self = MP_OBJ_TO_PTR(self_in); + + if (self->type == MP_BLUETOOTH_UUID_TYPE_16) { + mp_printf(print, "UUID16(0x%04x)", self->uuid._16); + } else if (self->type == MP_BLUETOOTH_UUID_TYPE_32) { + mp_printf(print, "UUID32(0x%08x)", self->uuid._32); + } else if (self->type == MP_BLUETOOTH_UUID_TYPE_128) { + mp_printf(print, "UUID128('"); + for (int i = 0; i < 16; ++i) { + mp_printf(print, "%02x", self->uuid._128[15-i]); + if (i == 3 || i == 5 || i == 7 || i == 9) { + mp_printf(print, "-"); + } + } + mp_printf(print, "')"); + } else { + mp_printf(print, "UUID?(%d)", self->type); + } +} + +#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE + +STATIC void ringbuf_put_uuid(ringbuf_t *ringbuf, mp_obj_bluetooth_uuid_t *uuid) { + assert(ringbuf_free(ringbuf) >= uuid->type + 1); + ringbuf_put(ringbuf, uuid->type); + switch (uuid->type) { + case MP_BLUETOOTH_UUID_TYPE_16: + ringbuf_put16(ringbuf, uuid->uuid._16); + break; + case MP_BLUETOOTH_UUID_TYPE_32: + ringbuf_put16(ringbuf, uuid->uuid._32 >> 16); + ringbuf_put16(ringbuf, uuid->uuid._32 & 0xffff); + break; + case MP_BLUETOOTH_UUID_TYPE_128: + for (int i = 0; i < 16; ++i) { + ringbuf_put(ringbuf, uuid->uuid._128[i]); + } + break; + } +} + +STATIC void ringbuf_get_uuid(ringbuf_t *ringbuf, mp_obj_bluetooth_uuid_t *uuid) { + assert(ringbuf_avail(ringbuf) >= 1); + uuid->type = ringbuf_get(ringbuf); + assert(ringbuf_avail(ringbuf) >= uuid->type); + uint16_t h, l; + switch (uuid->type) { + case MP_BLUETOOTH_UUID_TYPE_16: + uuid->uuid._16 = ringbuf_get16(ringbuf); + break; + case MP_BLUETOOTH_UUID_TYPE_32: + h = ringbuf_get16(ringbuf); + l = ringbuf_get16(ringbuf); + uuid->uuid._32 = (h << 16) | l; + break; + case MP_BLUETOOTH_UUID_TYPE_128: + for (int i = 0; i < 16; ++i) { + uuid->uuid._128[i] = ringbuf_get(ringbuf); + } + break; + } +} +#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE + +STATIC const mp_obj_type_t bluetooth_uuid_type = { + { &mp_type_type }, + .name = MP_QSTR_UUID, + .make_new = bluetooth_uuid_make_new, + .unary_op = bluetooth_uuid_unary_op, + .locals_dict = NULL, + .print = bluetooth_uuid_print, +}; + +// ---------------------------------------------------------------------------- +// Bluetooth object: General +// ---------------------------------------------------------------------------- + +STATIC mp_obj_t bluetooth_ble_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + if (MP_STATE_VM(bluetooth) == MP_OBJ_NULL) { + mp_obj_bluetooth_ble_t *o = m_new_obj(mp_obj_bluetooth_ble_t); + o->base.type = &bluetooth_ble_type; + o->irq_handler = mp_const_none; + // Pre-allocated the event data tuple to prevent needing to allocate in the IRQ handler. + o->irq_data_tuple = mp_obj_new_tuple(MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_TUPLE_LEN, NULL); + mp_obj_bluetooth_uuid_t *uuid = m_new_obj(mp_obj_bluetooth_uuid_t); + uuid->base.type = &bluetooth_uuid_type; + o->irq_data_uuid = MP_OBJ_FROM_PTR(uuid); + o->irq_trigger = 0; + ringbuf_alloc(&o->ringbuf, MICROPY_PY_BLUETOOTH_RINGBUF_SIZE); + MP_STATE_VM(bluetooth) = MP_OBJ_FROM_PTR(o); + } + return MP_STATE_VM(bluetooth); +} + +STATIC mp_obj_t bluetooth_ble_active(size_t n_args, const mp_obj_t *args) { + if (n_args == 2) { + // Boolean enable/disable argument supplied, set current state. + if (mp_obj_is_true(args[1])) { + int err = mp_bluetooth_init(); + if (err != 0) { + mp_raise_OSError(err); + } + } else { + mp_bluetooth_deinit(); + } + } + // Return current state. + return mp_obj_new_bool(mp_bluetooth_is_enabled()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_active_obj, 1, 2, bluetooth_ble_active); + +STATIC mp_obj_t bluetooth_ble_config(mp_obj_t self_in, mp_obj_t param) { + if (param == MP_OBJ_NEW_QSTR(MP_QSTR_mac)) { + uint8_t addr[6]; + mp_bluetooth_get_device_addr(addr); + return mp_obj_new_bytes(addr, MP_ARRAY_SIZE(addr)); + } else { + mp_raise_ValueError("unknown config param"); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(bluetooth_ble_config_obj, bluetooth_ble_config); + +STATIC mp_obj_t bluetooth_ble_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_handler, ARG_trigger }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_handler, MP_ARG_OBJ|MP_ARG_REQUIRED, {.u_obj = mp_const_none} }, + { MP_QSTR_trigger, MP_ARG_INT, {.u_int = MP_BLUETOOTH_IRQ_ALL} }, + }; + 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); + mp_obj_t callback = args[ARG_handler].u_obj; + if (callback != mp_const_none && !mp_obj_is_callable(callback)) { + mp_raise_ValueError("invalid callback"); + } + + // Update the callback. + MICROPY_PY_BLUETOOTH_ENTER + mp_obj_bluetooth_ble_t* bt = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); + bt->irq_handler = callback; + bt->irq_trigger = args[ARG_trigger].u_int; + MICROPY_PY_BLUETOOTH_EXIT + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bluetooth_ble_irq_obj, 1, bluetooth_ble_irq); + +// ---------------------------------------------------------------------------- +// Bluetooth object: GAP +// ---------------------------------------------------------------------------- + +STATIC mp_obj_t bluetooth_ble_gap_advertise(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_interval_ms, ARG_adv_data, ARG_resp_data, ARG_connectable }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_interval_ms, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(100)} }, + { MP_QSTR_adv_data, MP_ARG_OBJ, {.u_obj = mp_const_none } }, + { MP_QSTR_resp_data, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none } }, + { MP_QSTR_connectable, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_true } }, + }; + 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); + + mp_int_t interval_ms; + if (args[ARG_interval_ms].u_obj == mp_const_none || (interval_ms = mp_obj_get_int(args[ARG_interval_ms].u_obj)) == 0) { + mp_bluetooth_gap_advertise_stop(); + return mp_const_none; + } + + bool connectable = mp_obj_is_true(args[ARG_connectable].u_obj); + + mp_buffer_info_t adv_bufinfo = {0}; + if (args[ARG_adv_data].u_obj != mp_const_none) { + mp_get_buffer_raise(args[ARG_adv_data].u_obj, &adv_bufinfo, MP_BUFFER_READ); + } + + mp_buffer_info_t resp_bufinfo = {0}; + if (args[ARG_resp_data].u_obj != mp_const_none) { + mp_get_buffer_raise(args[ARG_resp_data].u_obj, &resp_bufinfo, MP_BUFFER_READ); + } + + return bluetooth_handle_errno(mp_bluetooth_gap_advertise_start(connectable, interval_ms, adv_bufinfo.buf, adv_bufinfo.len, resp_bufinfo.buf, resp_bufinfo.len)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bluetooth_ble_gap_advertise_obj, 1, bluetooth_ble_gap_advertise); + +STATIC int bluetooth_gatts_register_service(mp_obj_t uuid_in, mp_obj_t characteristics_in, uint16_t **handles, size_t *num_handles) { + if (!mp_obj_is_type(uuid_in, &bluetooth_uuid_type)) { + mp_raise_ValueError("invalid service UUID"); + } + mp_obj_bluetooth_uuid_t *service_uuid = MP_OBJ_TO_PTR(uuid_in); + + mp_obj_t len_in = mp_obj_len(characteristics_in); + size_t len = mp_obj_get_int(len_in); + mp_obj_iter_buf_t iter_buf; + mp_obj_t iterable = mp_getiter(characteristics_in, &iter_buf); + mp_obj_t characteristic_obj; + + // Lists of characteristic uuids and flags. + mp_obj_bluetooth_uuid_t **characteristic_uuids = m_new(mp_obj_bluetooth_uuid_t*, len); + uint8_t *characteristic_flags = m_new(uint8_t, len); + + // Flattened list of descriptor uuids and flags. Grows (realloc) as more descriptors are encountered. + mp_obj_bluetooth_uuid_t **descriptor_uuids = NULL; + uint8_t *descriptor_flags = NULL; + // How many descriptors in the flattened list per characteristic. + uint8_t *num_descriptors = m_new(uint8_t, len); + + // Inititally allocate enough room for the number of characteristics. + // Will be grown to accommodate descriptors as necessary. + *num_handles = len; + *handles = m_new(uint16_t, *num_handles); + + // Extract out characteristic uuids & flags. + + int characteristic_index = 0; // characteristic index. + int handle_index = 0; // handle index. + int descriptor_index = 0; // descriptor index. + while ((characteristic_obj = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + // (uuid, flags, (optional descriptors),) + size_t characteristic_len; + mp_obj_t *characteristic_items; + mp_obj_get_array(characteristic_obj, &characteristic_len, &characteristic_items); + + if (characteristic_len < 2 || characteristic_len > 3) { + mp_raise_ValueError("invalid characteristic tuple"); + } + mp_obj_t uuid_obj = characteristic_items[0]; + if (!mp_obj_is_type(uuid_obj, &bluetooth_uuid_type)) { + mp_raise_ValueError("invalid characteristic UUID"); + } + + (*handles)[handle_index++] = 0xffff; + + // Optional third element, iterable of descriptors. + if (characteristic_len >= 3) { + mp_obj_t descriptors_len_in = mp_obj_len(characteristic_items[2]); + num_descriptors[characteristic_index] = mp_obj_get_int(descriptors_len_in); + + if (num_descriptors[characteristic_index] == 0) { + continue; + } + + // Grow the flattened uuids and flags arrays with this many more descriptors. + descriptor_uuids = m_renew(mp_obj_bluetooth_uuid_t*, descriptor_uuids, descriptor_index, descriptor_index + num_descriptors[characteristic_index]); + descriptor_flags = m_renew(uint8_t, descriptor_flags, descriptor_index, descriptor_index + num_descriptors[characteristic_index]); + + // Also grow the handles array. + *handles = m_renew(uint16_t, *handles, *num_handles, *num_handles + num_descriptors[characteristic_index]); + + mp_obj_iter_buf_t iter_buf_desc; + mp_obj_t iterable_desc = mp_getiter(characteristic_items[2], &iter_buf_desc); + mp_obj_t descriptor_obj; + + // Extract out descriptors for this characteristic. + while ((descriptor_obj = mp_iternext(iterable_desc)) != MP_OBJ_STOP_ITERATION) { + // (uuid, flags,) + mp_obj_t *descriptor_items; + mp_obj_get_array_fixed_n(descriptor_obj, 2, &descriptor_items); + mp_obj_t desc_uuid_obj = descriptor_items[0]; + if (!mp_obj_is_type(desc_uuid_obj, &bluetooth_uuid_type)) { + mp_raise_ValueError("invalid descriptor UUID"); + } + + descriptor_uuids[descriptor_index] = MP_OBJ_TO_PTR(desc_uuid_obj); + descriptor_flags[descriptor_index] = mp_obj_get_int(descriptor_items[1]); + ++descriptor_index; + + (*handles)[handle_index++] = 0xffff; + } + + // Reflect that we've grown the handles array. + *num_handles += num_descriptors[characteristic_index]; + } + + characteristic_uuids[characteristic_index] = MP_OBJ_TO_PTR(uuid_obj); + characteristic_flags[characteristic_index] = mp_obj_get_int(characteristic_items[1]); + ++characteristic_index; + } + + // Add service. + return mp_bluetooth_gatts_register_service(service_uuid, characteristic_uuids, characteristic_flags, descriptor_uuids, descriptor_flags, num_descriptors, *handles, len); +} + +STATIC mp_obj_t bluetooth_ble_gatts_register_services(mp_obj_t self_in, mp_obj_t services_in) { + mp_obj_t len_in = mp_obj_len(services_in); + size_t len = mp_obj_get_int(len_in); + mp_obj_iter_buf_t iter_buf; + mp_obj_t iterable = mp_getiter(services_in, &iter_buf); + mp_obj_t service_tuple_obj; + + mp_obj_tuple_t *result = mp_obj_new_tuple(len, NULL); + + uint16_t **handles = m_new0(uint16_t*, len); + size_t *num_handles = m_new0(size_t, len); + + // We always reset the service list, as Nimble has no other option. + // TODO: Add a `reset` or `clear` kwarg (defaulting to True) to make this behavior optional. + int err = mp_bluetooth_gatts_register_service_begin(true); + if (err != 0) { + return bluetooth_handle_errno(err); + } + + int i = 0; + while ((service_tuple_obj = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + // (uuid, chars) + mp_obj_t *service_items; + mp_obj_get_array_fixed_n(service_tuple_obj, 2, &service_items); + err = bluetooth_gatts_register_service(service_items[0], service_items[1], &handles[i], &num_handles[i]); + if (err != 0) { + return bluetooth_handle_errno(err); + } + + ++i; + } + + // On Nimble, this will actually perform the registration, making the handles valid. + err = mp_bluetooth_gatts_register_service_end(); + if (err != 0) { + return bluetooth_handle_errno(err); + } + + // Return tuple of tuple of value handles. + // TODO: Also the Generic Access service characteristics? + for (i = 0; i < len; ++i) { + mp_obj_tuple_t *service_handles = mp_obj_new_tuple(num_handles[i], NULL); + for (int j = 0; j < num_handles[i]; ++j) { + service_handles->items[j] = MP_OBJ_NEW_SMALL_INT(handles[i][j]); + } + result->items[i] = MP_OBJ_FROM_PTR(service_handles); + } + return MP_OBJ_FROM_PTR(result); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(bluetooth_ble_gatts_register_services_obj, bluetooth_ble_gatts_register_services); + +#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE +STATIC mp_obj_t bluetooth_ble_gap_connect(size_t n_args, const mp_obj_t *args) { + uint8_t addr_type = mp_obj_get_int(args[1]); + mp_buffer_info_t bufinfo = {0}; + mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ); + if (bufinfo.len != 6) { + mp_raise_ValueError("invalid addr"); + } + mp_int_t scan_duration_ms = MP_BLUETOOTH_CONNECT_DEFAULT_SCAN_DURATION_MS; + if (n_args == 4) { + scan_duration_ms = mp_obj_get_int(args[3]); + } + + int err = mp_bluetooth_gap_peripheral_connect(addr_type, bufinfo.buf, scan_duration_ms); + return bluetooth_handle_errno(err); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gap_connect_obj, 3, 4, bluetooth_ble_gap_connect); + +STATIC mp_obj_t bluetooth_ble_gap_scan(size_t n_args, const mp_obj_t *args) { + if (n_args == 2 && args[1] == mp_const_none) { + int err = mp_bluetooth_gap_scan_stop(); + return bluetooth_handle_errno(err); + } else { + mp_int_t duration_ms = 0; + if (n_args == 2) { + if (!mp_obj_is_int(args[1])) { + mp_raise_ValueError("invalid duration"); + } + duration_ms = mp_obj_get_int(args[1]); + } + + int err = mp_bluetooth_gap_scan_start(duration_ms); + return bluetooth_handle_errno(err); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gap_scan_obj, 1, 2, bluetooth_ble_gap_scan); +#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE + +STATIC mp_obj_t bluetooth_ble_gap_disconnect(mp_obj_t self_in, mp_obj_t conn_handle_in) { + uint16_t conn_handle = mp_obj_get_int(conn_handle_in); + int err = mp_bluetooth_gap_disconnect(conn_handle); + return bluetooth_handle_errno(err); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(bluetooth_ble_gap_disconnect_obj, bluetooth_ble_gap_disconnect); + +// ---------------------------------------------------------------------------- +// Bluetooth object: GATTS (Peripheral/Advertiser role) +// ---------------------------------------------------------------------------- + +STATIC mp_obj_t bluetooth_ble_gatts_read(mp_obj_t self_in, mp_obj_t value_handle_in) { + size_t len = 0; + uint8_t* buf; + mp_bluetooth_gatts_read(mp_obj_get_int(value_handle_in), &buf, &len); + return mp_obj_new_bytes(buf, len); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(bluetooth_ble_gatts_read_obj, bluetooth_ble_gatts_read); + +STATIC mp_obj_t bluetooth_ble_gatts_write(mp_obj_t self_in, mp_obj_t value_handle_in, mp_obj_t data) { + mp_buffer_info_t bufinfo = {0}; + mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ); + int err = mp_bluetooth_gatts_write(mp_obj_get_int(value_handle_in), bufinfo.buf, bufinfo.len); + if (err != 0) { + mp_raise_OSError(err); + } + return MP_OBJ_NEW_SMALL_INT(bufinfo.len); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(bluetooth_ble_gatts_write_obj, bluetooth_ble_gatts_write); + +STATIC mp_obj_t bluetooth_ble_gatts_notify(size_t n_args, const mp_obj_t *args) { + mp_int_t conn_handle = mp_obj_get_int(args[1]); + mp_int_t value_handle = mp_obj_get_int(args[2]); + + if (n_args == 4) { + mp_buffer_info_t bufinfo = {0}; + mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); + size_t len = bufinfo.len; + int err = mp_bluetooth_gatts_notify_send(conn_handle, value_handle, bufinfo.buf, &len); + if (err != 0) { + mp_raise_OSError(err); + } + return MP_OBJ_NEW_SMALL_INT(len); + } else { + int err = mp_bluetooth_gatts_notify(conn_handle, value_handle); + return bluetooth_handle_errno(err); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gatts_notify_obj, 3, 4, bluetooth_ble_gatts_notify); + +// ---------------------------------------------------------------------------- +// Bluetooth object: GATTC (Central/Scanner role) +// ---------------------------------------------------------------------------- + +#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE + +STATIC mp_obj_t bluetooth_ble_gattc_discover_services(mp_obj_t self_in, mp_obj_t conn_handle_in) { + mp_int_t conn_handle = mp_obj_get_int(conn_handle_in); + return bluetooth_handle_errno(mp_bluetooth_gattc_discover_primary_services(conn_handle)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(bluetooth_ble_gattc_discover_services_obj, bluetooth_ble_gattc_discover_services); + +STATIC mp_obj_t bluetooth_ble_gattc_discover_characteristics(size_t n_args, const mp_obj_t *args) { + mp_int_t conn_handle = mp_obj_get_int(args[1]); + mp_int_t start_handle = mp_obj_get_int(args[2]); + mp_int_t end_handle = mp_obj_get_int(args[3]); + return bluetooth_handle_errno(mp_bluetooth_gattc_discover_characteristics(conn_handle, start_handle, end_handle)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gattc_discover_characteristics_obj, 4, 4, bluetooth_ble_gattc_discover_characteristics); + +STATIC mp_obj_t bluetooth_ble_gattc_discover_descriptors(size_t n_args, const mp_obj_t *args) { + mp_int_t conn_handle = mp_obj_get_int(args[1]); + mp_int_t start_handle = mp_obj_get_int(args[2]); + mp_int_t end_handle = mp_obj_get_int(args[3]); + return bluetooth_handle_errno(mp_bluetooth_gattc_discover_descriptors(conn_handle, start_handle, end_handle)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gattc_discover_descriptors_obj, 4, 4, bluetooth_ble_gattc_discover_descriptors); + +STATIC mp_obj_t bluetooth_ble_gattc_read(mp_obj_t self_in, mp_obj_t conn_handle_in, mp_obj_t value_handle_in) { + mp_int_t conn_handle = mp_obj_get_int(conn_handle_in); + mp_int_t value_handle = mp_obj_get_int(value_handle_in); + return bluetooth_handle_errno(mp_bluetooth_gattc_read(conn_handle, value_handle)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(bluetooth_ble_gattc_read_obj, bluetooth_ble_gattc_read); + +STATIC mp_obj_t bluetooth_ble_gattc_write(size_t n_args, const mp_obj_t *args) { + mp_int_t conn_handle = mp_obj_get_int(args[1]); + mp_int_t value_handle = mp_obj_get_int(args[2]); + mp_obj_t data = args[3]; + mp_buffer_info_t bufinfo = {0}; + mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ); + size_t len = bufinfo.len; + return bluetooth_handle_errno(mp_bluetooth_gattc_write(conn_handle, value_handle, bufinfo.buf, &len)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gattc_write_obj, 4, 4, bluetooth_ble_gattc_write); + +#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE + +// ---------------------------------------------------------------------------- +// Bluetooth object: Definition +// ---------------------------------------------------------------------------- + +STATIC const mp_rom_map_elem_t bluetooth_ble_locals_dict_table[] = { + // General + { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&bluetooth_ble_active_obj) }, + { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&bluetooth_ble_config_obj) }, + { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&bluetooth_ble_irq_obj) }, + // GAP + { MP_ROM_QSTR(MP_QSTR_gap_advertise), MP_ROM_PTR(&bluetooth_ble_gap_advertise_obj) }, + #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE + { MP_ROM_QSTR(MP_QSTR_gap_connect), MP_ROM_PTR(&bluetooth_ble_gap_connect_obj) }, + { MP_ROM_QSTR(MP_QSTR_gap_scan), MP_ROM_PTR(&bluetooth_ble_gap_scan_obj) }, + #endif + { MP_ROM_QSTR(MP_QSTR_gap_disconnect), MP_ROM_PTR(&bluetooth_ble_gap_disconnect_obj) }, + // GATT Server (i.e. peripheral/advertiser role) + { MP_ROM_QSTR(MP_QSTR_gatts_register_services), MP_ROM_PTR(&bluetooth_ble_gatts_register_services_obj) }, + { MP_ROM_QSTR(MP_QSTR_gatts_read), MP_ROM_PTR(&bluetooth_ble_gatts_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_gatts_write), MP_ROM_PTR(&bluetooth_ble_gatts_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_gatts_notify), MP_ROM_PTR(&bluetooth_ble_gatts_notify_obj) }, + #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE + // GATT Client (i.e. central/scanner role) + { MP_ROM_QSTR(MP_QSTR_gattc_discover_services), MP_ROM_PTR(&bluetooth_ble_gattc_discover_services_obj) }, + { MP_ROM_QSTR(MP_QSTR_gattc_discover_characteristics), MP_ROM_PTR(&bluetooth_ble_gattc_discover_characteristics_obj) }, + { MP_ROM_QSTR(MP_QSTR_gattc_discover_descriptors), MP_ROM_PTR(&bluetooth_ble_gattc_discover_descriptors_obj) }, + { MP_ROM_QSTR(MP_QSTR_gattc_read), MP_ROM_PTR(&bluetooth_ble_gattc_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_gattc_write), MP_ROM_PTR(&bluetooth_ble_gattc_write_obj) }, + #endif +}; +STATIC MP_DEFINE_CONST_DICT(bluetooth_ble_locals_dict, bluetooth_ble_locals_dict_table); + +STATIC const mp_obj_type_t bluetooth_ble_type = { + { &mp_type_type }, + .name = MP_QSTR_BLE, + .make_new = bluetooth_ble_make_new, + .locals_dict = (void*)&bluetooth_ble_locals_dict, +}; + +STATIC const mp_rom_map_elem_t mp_module_bluetooth_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bluetooth) }, + { MP_ROM_QSTR(MP_QSTR_BLE), MP_ROM_PTR(&bluetooth_ble_type) }, + { MP_ROM_QSTR(MP_QSTR_UUID), MP_ROM_PTR(&bluetooth_uuid_type) }, + { MP_ROM_QSTR(MP_QSTR_FLAG_READ), MP_ROM_INT(MP_BLUETOOTH_CHARACTERISTIC_FLAG_READ) }, + { MP_ROM_QSTR(MP_QSTR_FLAG_WRITE), MP_ROM_INT(MP_BLUETOOTH_CHARACTERISTIC_FLAG_WRITE) }, + { MP_ROM_QSTR(MP_QSTR_FLAG_NOTIFY), MP_ROM_INT(MP_BLUETOOTH_CHARACTERISTIC_FLAG_NOTIFY) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_bluetooth_globals, mp_module_bluetooth_globals_table); + +const mp_obj_module_t mp_module_bluetooth = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_bluetooth_globals, +}; + +// Helpers + +#include + +STATIC void ringbuf_extract(ringbuf_t* ringbuf, mp_obj_tuple_t *data_tuple, size_t n_u16, size_t n_u8, mp_obj_str_t *bytes_addr, size_t n_b, size_t n_i8, mp_obj_bluetooth_uuid_t *uuid, mp_obj_str_t *bytes_data) { + assert(ringbuf_avail(ringbuf) >= n_u16 * 2 + n_u8 + (bytes_addr ? 6 : 0) + n_b + n_i8 + (uuid ? 1 : 0) + (bytes_data ? 1 : 0)); + int j = 0; + + for (int i = 0; i < n_u16; ++i) { + data_tuple->items[j++] = MP_OBJ_NEW_SMALL_INT(ringbuf_get16(ringbuf)); + } + if (n_u8) { + data_tuple->items[j++] = MP_OBJ_NEW_SMALL_INT(ringbuf_get(ringbuf)); + } + if (bytes_addr) { + bytes_addr->len = 6; + for (int i = 0; i < bytes_addr->len; ++i) { + // cast away const, this is actually bt->irq_data_bytes. + ((uint8_t*)bytes_addr->data)[i] = ringbuf_get(ringbuf); + } + data_tuple->items[j++] = MP_OBJ_FROM_PTR(bytes_addr); + } + if (n_b) { + data_tuple->items[j++] = mp_obj_new_bool(ringbuf_get(ringbuf)); + } + if (n_i8) { + // Note the int8_t got packed into the ringbuf as a uint8_t. + data_tuple->items[j++] = MP_OBJ_NEW_SMALL_INT((int8_t)ringbuf_get(ringbuf)); + } + if (uuid) { + ringbuf_get_uuid(ringbuf, uuid); + data_tuple->items[j++] = MP_OBJ_FROM_PTR(uuid); + } + // The code that enqueues into the ringbuf should ensure that it doesn't + // put more than MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN bytes into + // the ringbuf. + if (bytes_data) { + bytes_data->len = ringbuf_get(ringbuf); + for (int i = 0; i < bytes_data->len; ++i) { + // cast away const, this is actually bt->irq_data_bytes + 6. + ((uint8_t*)bytes_data->data)[i] = ringbuf_get(ringbuf); + } + data_tuple->items[j++] = MP_OBJ_FROM_PTR(bytes_data); + } + + data_tuple->len = j; +} + +STATIC mp_obj_t bluetooth_ble_invoke_irq(mp_obj_t none_in) { + // This is always executing in schedule context. + for (;;) { + MICROPY_PY_BLUETOOTH_ENTER + mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); + + mp_int_t event = event = ringbuf_get16(&o->ringbuf); + if (event < 0) { + // Nothing available in ringbuf. + MICROPY_PY_BLUETOOTH_EXIT + break; + } + + // Although we're in schedule context, this code still avoids using any allocations: + // - IRQs are disabled (to protect the ringbuf), and we need to avoid triggering GC + // - The user's handler might not alloc, so we shouldn't either. + + mp_obj_t handler = handler = o->irq_handler; + mp_obj_tuple_t *data_tuple = MP_OBJ_TO_PTR(o->irq_data_tuple); + + // Some events need to pass bytes objects to their handler, using the + // pre-allocated bytes array. + mp_obj_str_t irq_data_bytes_addr = {{&mp_type_bytes}, 0, 6, o->irq_data_bytes}; + mp_obj_str_t irq_data_bytes_data = {{&mp_type_bytes}, 0, 0, o->irq_data_bytes + 6}; + + if (event == MP_BLUETOOTH_IRQ_CENTRAL_CONNECT || event == MP_BLUETOOTH_IRQ_PERIPHERAL_CONNECT || event == MP_BLUETOOTH_IRQ_CENTRAL_DISCONNECT || event == MP_BLUETOOTH_IRQ_PERIPHERAL_DISCONNECT) { + // conn_handle, addr_type, addr + ringbuf_extract(&o->ringbuf, data_tuple, 1, 1, &irq_data_bytes_addr, 0, 0, NULL, NULL); + } else if (event == MP_BLUETOOTH_IRQ_GATTS_WRITE) { + // conn_handle, value_handle + ringbuf_extract(&o->ringbuf, data_tuple, 2, 0, NULL, 0, 0, NULL, NULL); + #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE + } else if (event == MP_BLUETOOTH_IRQ_SCAN_RESULT) { + // addr_type, addr, connectable, rssi, adv_data + ringbuf_extract(&o->ringbuf, data_tuple, 0, 1, &irq_data_bytes_addr, 1, 1, NULL, &irq_data_bytes_data); + } else if (event == MP_BLUETOOTH_IRQ_SCAN_COMPLETE) { + // No params required. + data_tuple->len = 0; + } else if (event == MP_BLUETOOTH_IRQ_GATTC_SERVICE_RESULT) { + // conn_handle, start_handle, end_handle, uuid + ringbuf_extract(&o->ringbuf, data_tuple, 3, 0, NULL, 0, 0, MP_OBJ_TO_PTR(o->irq_data_uuid), NULL); + } else if (event == MP_BLUETOOTH_IRQ_GATTC_CHARACTERISTIC_RESULT) { + // conn_handle, def_handle, value_handle, properties, uuid + ringbuf_extract(&o->ringbuf, data_tuple, 3, 1, NULL, 0, 0, MP_OBJ_TO_PTR(o->irq_data_uuid), NULL); + } else if (event == MP_BLUETOOTH_IRQ_GATTC_DESCRIPTOR_RESULT) { + // conn_handle, handle, uuid + ringbuf_extract(&o->ringbuf, data_tuple, 2, 0, NULL, 0, 0, MP_OBJ_TO_PTR(o->irq_data_uuid), NULL); + } else if (event == MP_BLUETOOTH_IRQ_GATTC_READ_RESULT || event == MP_BLUETOOTH_IRQ_GATTC_NOTIFY || event == MP_BLUETOOTH_IRQ_GATTC_INDICATE) { + // conn_handle, value_handle, data + ringbuf_extract(&o->ringbuf, data_tuple, 2, 0, NULL, 0, 0, NULL, &irq_data_bytes_data); + } else if (event == MP_BLUETOOTH_IRQ_GATTC_WRITE_STATUS) { + // conn_handle, value_handle, status + ringbuf_extract(&o->ringbuf, data_tuple, 3, 0, NULL, 0, 0, NULL, NULL); + #endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE + } + + MICROPY_PY_BLUETOOTH_EXIT + + mp_call_function_2(handler, MP_OBJ_NEW_SMALL_INT(event), MP_OBJ_FROM_PTR(data_tuple)); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bluetooth_ble_invoke_irq_obj, bluetooth_ble_invoke_irq); + +// ---------------------------------------------------------------------------- +// Port API +// ---------------------------------------------------------------------------- + +// Callbacks are called in interrupt context (i.e. can't allocate), so we need to push the data +// into the ringbuf and schedule the callback via mp_sched_schedule. + +STATIC bool enqueue_irq(mp_obj_bluetooth_ble_t *o, size_t len, uint16_t event, bool *sched) { + *sched = false; + + if (ringbuf_free(&o->ringbuf) >= len + 2 && (o->irq_trigger & event) && o->irq_handler != mp_const_none) { + *sched = ringbuf_avail(&o->ringbuf) == 0; + ringbuf_put16(&o->ringbuf, event); + return true; + } else { + return false; + } +} + +STATIC void schedule_ringbuf(bool sched) { + if (sched) { + mp_sched_schedule(MP_OBJ_FROM_PTR(MP_ROM_PTR(&bluetooth_ble_invoke_irq_obj)), mp_const_none); + } +} + +void mp_bluetooth_gap_on_connected_disconnected(uint16_t event, uint16_t conn_handle, uint8_t addr_type, const uint8_t *addr) { + MICROPY_PY_BLUETOOTH_ENTER + mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); + bool sched; + if (enqueue_irq(o, 9, event, &sched)) { + ringbuf_put16(&o->ringbuf, conn_handle); + ringbuf_put(&o->ringbuf, addr_type); + for (int i = 0; i < 6; ++i) { + ringbuf_put(&o->ringbuf, addr[i]); + } + } + MICROPY_PY_BLUETOOTH_EXIT + schedule_ringbuf(sched); +} + +void mp_bluetooth_gatts_on_write(uint16_t value_handle, uint16_t conn_handle) { + MICROPY_PY_BLUETOOTH_ENTER + mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); + bool sched; + if (enqueue_irq(o, 4, MP_BLUETOOTH_IRQ_GATTS_WRITE, &sched)) { + ringbuf_put16(&o->ringbuf, conn_handle); + ringbuf_put16(&o->ringbuf, value_handle); + } + MICROPY_PY_BLUETOOTH_EXIT + schedule_ringbuf(sched); +} + +#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE +void mp_bluetooth_gap_on_scan_complete(void) { + MICROPY_PY_BLUETOOTH_ENTER + mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); + bool sched; + if (enqueue_irq(o, 0, MP_BLUETOOTH_IRQ_SCAN_COMPLETE, &sched)) { + } + MICROPY_PY_BLUETOOTH_EXIT + schedule_ringbuf(sched); +} + +void mp_bluetooth_gap_on_scan_result(uint8_t addr_type, const uint8_t *addr, bool connectable, const int8_t rssi, const uint8_t *data, size_t data_len) { + MICROPY_PY_BLUETOOTH_ENTER + mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); + bool sched; + if (enqueue_irq(o, 1 + 6 + 1 + 1 + data_len, MP_BLUETOOTH_IRQ_SCAN_RESULT, &sched)) { + ringbuf_put(&o->ringbuf, addr_type); + for (int i = 0; i < 6; ++i) { + ringbuf_put(&o->ringbuf, addr[i]); + } + ringbuf_put(&o->ringbuf, connectable ? 1 : 0); + // Note conversion of int8_t rssi to uint8_t. Must un-convert on the way out. + ringbuf_put(&o->ringbuf, (uint8_t)rssi); + data_len = MIN(MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN, data_len); + ringbuf_put(&o->ringbuf, data_len); + for (int i = 0; i < data_len; ++i) { + ringbuf_put(&o->ringbuf, data[i]); + } + } + MICROPY_PY_BLUETOOTH_EXIT + schedule_ringbuf(sched); +} + +void mp_bluetooth_gattc_on_primary_service_result(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, mp_obj_bluetooth_uuid_t *service_uuid) { + MICROPY_PY_BLUETOOTH_ENTER + mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); + bool sched; + if (enqueue_irq(o, 2 + 2 + 2 + 1 + service_uuid->type, MP_BLUETOOTH_IRQ_GATTC_SERVICE_RESULT, &sched)) { + ringbuf_put16(&o->ringbuf, conn_handle); + ringbuf_put16(&o->ringbuf, start_handle); + ringbuf_put16(&o->ringbuf, end_handle); + ringbuf_put_uuid(&o->ringbuf, service_uuid); + } + MICROPY_PY_BLUETOOTH_EXIT + schedule_ringbuf(sched); +} + +void mp_bluetooth_gattc_on_characteristic_result(uint16_t conn_handle, uint16_t def_handle, uint16_t value_handle, uint8_t properties, mp_obj_bluetooth_uuid_t *characteristic_uuid) { + MICROPY_PY_BLUETOOTH_ENTER + mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); + bool sched; + if (enqueue_irq(o, 2 + 2 + 2 + 1 + characteristic_uuid->type, MP_BLUETOOTH_IRQ_GATTC_CHARACTERISTIC_RESULT, &sched)) { + ringbuf_put16(&o->ringbuf, conn_handle); + ringbuf_put16(&o->ringbuf, def_handle); + ringbuf_put16(&o->ringbuf, value_handle); + ringbuf_put(&o->ringbuf, properties); + ringbuf_put_uuid(&o->ringbuf, characteristic_uuid); + } + MICROPY_PY_BLUETOOTH_EXIT + schedule_ringbuf(sched); +} + +void mp_bluetooth_gattc_on_descriptor_result(uint16_t conn_handle, uint16_t handle, mp_obj_bluetooth_uuid_t *descriptor_uuid) { + MICROPY_PY_BLUETOOTH_ENTER + mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); + bool sched; + if (enqueue_irq(o, 2 + 2 + 1 + descriptor_uuid->type, MP_BLUETOOTH_IRQ_GATTC_DESCRIPTOR_RESULT, &sched)) { + ringbuf_put16(&o->ringbuf, conn_handle); + ringbuf_put16(&o->ringbuf, handle); + ringbuf_put_uuid(&o->ringbuf, descriptor_uuid); + } + MICROPY_PY_BLUETOOTH_EXIT + schedule_ringbuf(sched); +} + +void mp_bluetooth_gattc_on_data_available(uint16_t event, uint16_t conn_handle, uint16_t value_handle, const uint8_t *data, size_t data_len) { + MICROPY_PY_BLUETOOTH_ENTER + mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); + bool sched; + if (enqueue_irq(o, 2 + 2 + 1 + data_len, event, &sched)) { + ringbuf_put16(&o->ringbuf, conn_handle); + ringbuf_put16(&o->ringbuf, value_handle); + data_len = MIN(MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN, data_len); + ringbuf_put(&o->ringbuf, data_len); + for (int i = 0; i < data_len; ++i) { + ringbuf_put(&o->ringbuf, data[i]); + } + } + MICROPY_PY_BLUETOOTH_EXIT + schedule_ringbuf(sched); +} + +void mp_bluetooth_gattc_on_write_status(uint16_t conn_handle, uint16_t value_handle, uint16_t status) { + MICROPY_PY_BLUETOOTH_ENTER + mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); + bool sched; + if (enqueue_irq(o, 2 + 2 + 2, MP_BLUETOOTH_IRQ_GATTC_WRITE_STATUS, &sched)) { + ringbuf_put16(&o->ringbuf, conn_handle); + ringbuf_put16(&o->ringbuf, value_handle); + ringbuf_put16(&o->ringbuf, status); + } + MICROPY_PY_BLUETOOTH_EXIT + schedule_ringbuf(sched); +} + +#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE + +#if MICROPY_PY_BLUETOOTH_GATTS_ON_READ_CALLBACK +bool mp_bluetooth_gatts_on_read_request(uint16_t conn_handle, uint16_t value_handle) { + mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); + if ((o->irq_trigger & MP_BLUETOOTH_IRQ_GATTS_READ_REQUEST) && o->irq_handler != mp_const_none) { + // Use pre-allocated tuple because this is a hard IRQ. + mp_obj_tuple_t *data = MP_OBJ_FROM_PTR(o->irq_data_tuple); + data->items[0] = MP_OBJ_NEW_SMALL_INT(conn_handle); + data->items[1] = MP_OBJ_NEW_SMALL_INT(value_handle); + data->len = 2; + mp_obj_t irq_ret = mp_call_function_2_protected(o->irq_handler, MP_OBJ_NEW_SMALL_INT(MP_BLUETOOTH_IRQ_GATTS_READ_REQUEST), o->irq_data_tuple); + // If the IRQ handler explicitly returned false, then deny the read. Otherwise if it returns None/True, allow it. + return irq_ret != MP_OBJ_NULL && (irq_ret == mp_const_none || mp_obj_is_true(irq_ret)); + } else { + // No IRQ handler, allow the read. + return true; + } +} +#endif + +#endif // MICROPY_PY_BLUETOOTH diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h new file mode 100644 index 0000000000..1b1318dec5 --- /dev/null +++ b/extmod/modbluetooth.h @@ -0,0 +1,248 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Ayke van Laethem + * Copyright (c) 2019 Jim Mussared + * + * 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_MODBLUETOOTH_H +#define MICROPY_INCLUDED_EXTMOD_MODBLUETOOTH_H + +#include + +#include "py/obj.h" +#include "py/objlist.h" +#include "py/ringbuf.h" + +// Port specific configuration. +#ifndef MICROPY_PY_BLUETOOTH_RINGBUF_SIZE +#define MICROPY_PY_BLUETOOTH_RINGBUF_SIZE (128) +#endif + +#ifndef MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE +#define MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE (0) +#endif + +#ifndef MICROPY_PY_BLUETOOTH_GATTS_ON_READ_CALLBACK +#define MICROPY_PY_BLUETOOTH_GATTS_ON_READ_CALLBACK (0) +#endif + +// Common constants. +#define MP_BLUETOOTH_MAX_ATTR_SIZE (20) + +// Advertisement packet lengths +#define MP_BLUETOOTH_GAP_ADV_MAX_LEN (32) + +#define MP_BLUETOOTH_CHARACTERISTIC_FLAG_READ (1 << 1) +#define MP_BLUETOOTH_CHARACTERISTIC_FLAG_WRITE (1 << 3) +#define MP_BLUETOOTH_CHARACTERISTIC_FLAG_NOTIFY (1 << 4) + +// Type value also doubles as length. +#define MP_BLUETOOTH_UUID_TYPE_16 (2) +#define MP_BLUETOOTH_UUID_TYPE_32 (4) +#define MP_BLUETOOTH_UUID_TYPE_128 (16) + +// Address types (for the addr_type params). +// Ports will need to map these to their own values. +#define MP_BLUETOOTH_ADDR_PUBLIC (0x00) // Public (identity) address. (Same as NimBLE and NRF SD) +#define MP_BLUETOOTH_ADDR_RANDOM_STATIC (0x01) // Random static (identity) address. (Same as NimBLE and NRF SD) +#define MP_BLUETOOTH_ADDR_PUBLIC_ID (0x02) // (Same as NimBLE) +#define MP_BLUETOOTH_ADDR_RANDOM_ID (0x03) // (Same as NimBLE) +#define MP_BLUETOOTH_ADDR_RANDOM_PRIVATE_RESOLVABLE (0x12) // Random private resolvable address. (NRF SD 0x02) +#define MP_BLUETOOTH_ADDR_RANDOM_PRIVATE_NON_RESOLVABLE (0x13) // Random private non-resolvable address. (NRF SD 0x03) + +// Event codes for the IRQ handler. +// Can also be combined to pass to the trigger param to select which events you +// are interested in. +// Note this is currently stored in a uint16_t (in irq_trigger, and the event +// arg to the irq handler), so one spare value remaining. +#define MP_BLUETOOTH_IRQ_CENTRAL_CONNECT (1 << 0) +#define MP_BLUETOOTH_IRQ_CENTRAL_DISCONNECT (1 << 1) +#define MP_BLUETOOTH_IRQ_GATTS_WRITE (1 << 2) +#define MP_BLUETOOTH_IRQ_GATTS_READ_REQUEST (1 << 3) +#define MP_BLUETOOTH_IRQ_SCAN_RESULT (1 << 4) +#define MP_BLUETOOTH_IRQ_SCAN_COMPLETE (1 << 5) +#define MP_BLUETOOTH_IRQ_PERIPHERAL_CONNECT (1 << 6) +#define MP_BLUETOOTH_IRQ_PERIPHERAL_DISCONNECT (1 << 7) +#define MP_BLUETOOTH_IRQ_GATTC_SERVICE_RESULT (1 << 8) +#define MP_BLUETOOTH_IRQ_GATTC_CHARACTERISTIC_RESULT (1 << 9) +#define MP_BLUETOOTH_IRQ_GATTC_DESCRIPTOR_RESULT (1 << 10) +#define MP_BLUETOOTH_IRQ_GATTC_READ_RESULT (1 << 11) +#define MP_BLUETOOTH_IRQ_GATTC_WRITE_STATUS (1 << 12) +#define MP_BLUETOOTH_IRQ_GATTC_NOTIFY (1 << 13) +#define MP_BLUETOOTH_IRQ_GATTC_INDICATE (1 << 14) +#define MP_BLUETOOTH_IRQ_ALL (0xffff) + +/* +These aren't included in the module for space reasons, but can be used +in your Python code if necessary. + +from micropython import const +_IRQ_CENTRAL_CONNECT = const(1 << 0) +_IRQ_CENTRAL_DISCONNECT = const(1 << 1) +_IRQ_GATTS_WRITE = const(1 << 2) +_IRQ_GATTS_READ_REQUEST = const(1 << 3) +_IRQ_SCAN_RESULT = const(1 << 4) +_IRQ_SCAN_COMPLETE = const(1 << 5) +_IRQ_PERIPHERAL_CONNECT = const(1 << 6) +_IRQ_PERIPHERAL_DISCONNECT = const(1 << 7) +_IRQ_GATTC_SERVICE_RESULT = const(1 << 8) +_IRQ_GATTC_CHARACTERISTIC_RESULT = const(1 << 9) +_IRQ_GATTC_DESCRIPTOR_RESULT = const(1 << 10) +_IRQ_GATTC_READ_RESULT = const(1 << 11) +_IRQ_GATTC_WRITE_STATUS = const(1 << 12) +_IRQ_GATTC_NOTIFY = const(1 << 13) +_IRQ_GATTC_INDICATE = const(1 << 14) +_IRQ_ALL = const(0xffff) +*/ + +// Common UUID type. +// Ports are expected to map this to their own internal UUID types. +typedef struct { + mp_obj_base_t base; + uint8_t type; + union { + uint16_t _16; + uint32_t _32; + uint8_t _128[16]; + } uuid; +} mp_obj_bluetooth_uuid_t; + +////////////////////////////////////////////////////////////// +// API implemented by ports (i.e. called from modbluetooth.c): + +// TODO: At the moment this only allows for a single `Bluetooth` instance to be created. +// Ideally in the future we'd be able to have multiple instances or to select a specific BT driver or HCI UART. +// So these global methods should be replaced with a struct of function pointers (like the machine.I2C implementations). + +// Any method returning an int returns errno on failure, otherwise zero. + +// Note: All methods dealing with addresses (as 6-byte uint8 pointers) are in big-endian format. +// (i.e. the same way they would be printed on a device sticker or in a UI). +// This means that the lower level implementation might need to reorder them (e.g. Nimble works in little-endian) + +// Enables the Bluetooth stack. +int mp_bluetooth_init(void); + +// Disables the Bluetooth stack. Is a no-op when not enabled. +void mp_bluetooth_deinit(void); + +// Returns true when the Bluetooth stack is enabled. +bool mp_bluetooth_is_enabled(void); + +// Gets the MAC addr of this device in big-endian format. +void mp_bluetooth_get_device_addr(uint8_t *addr); + +// Start advertisement. Will re-start advertisement when already enabled. +// Returns errno on failure. +int mp_bluetooth_gap_advertise_start(bool connectable, uint16_t interval_ms, const uint8_t *adv_data, size_t adv_data_len, const uint8_t *sr_data, size_t sr_data_len); + +// Stop advertisement. No-op when already stopped. +void mp_bluetooth_gap_advertise_stop(void); + +// Start adding services. Must be called before mp_bluetooth_register_service. +int mp_bluetooth_gatts_register_service_begin(bool reset); +// // Add a service with the given list of characteristics to the queue to be registered. +// The value_handles won't be valid until after mp_bluetooth_register_service_end is called. +int mp_bluetooth_gatts_register_service(mp_obj_bluetooth_uuid_t *service_uuid, mp_obj_bluetooth_uuid_t **characteristic_uuids, uint8_t *characteristic_flags, mp_obj_bluetooth_uuid_t **descriptor_uuids, uint8_t *descriptor_flags, uint8_t *num_descriptors, uint16_t *handles, size_t num_characteristics); +// Register any queued services. +int mp_bluetooth_gatts_register_service_end(); + +// Read the value from the local gatts db (likely this has been written by a central). +int mp_bluetooth_gatts_read(uint16_t value_handle, uint8_t **value, size_t *value_len); +// Write a value to the local gatts db (ready to be queried by a central). +int mp_bluetooth_gatts_write(uint16_t value_handle, const uint8_t *value, size_t value_len); +// Notify the central that it should do a read. +int mp_bluetooth_gatts_notify(uint16_t conn_handle, uint16_t value_handle); +// Notify the central, including a data payload. (Note: does not set the gatts db value). +int mp_bluetooth_gatts_notify_send(uint16_t conn_handle, uint16_t value_handle, const uint8_t *value, size_t *value_len); +// Indicate the central. +int mp_bluetooth_gatts_indicate(uint16_t conn_handle, uint16_t value_handle); + +// Disconnect from a central or peripheral. +int mp_bluetooth_gap_disconnect(uint16_t conn_handle); + +#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE +// Start a discovery (scan). Set duration to zero to run continuously. +int mp_bluetooth_gap_scan_start(int32_t duration_ms); + +// Stop discovery (if currently active). +int mp_bluetooth_gap_scan_stop(void); + +// Connect to a found peripheral. +int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, int32_t duration_ms); + +// Find all primary services on the connected peripheral. +int mp_bluetooth_gattc_discover_primary_services(uint16_t conn_handle); + +// Find all characteristics on the specified service on a connected peripheral. +int mp_bluetooth_gattc_discover_characteristics(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle); + +// Find all descriptors on the specified characteristic on a connected peripheral. +int mp_bluetooth_gattc_discover_descriptors(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle); + +// Initiate read of a value from the remote peripheral. +int mp_bluetooth_gattc_read(uint16_t conn_handle, uint16_t value_handle); + +// Write the value to the remote peripheral. +int mp_bluetooth_gattc_write(uint16_t conn_handle, uint16_t value_handle, const uint8_t *value, size_t *value_len); +#endif + +///////////////////////////////////////////////////////////////////////////// +// API implemented by modbluetooth (called by port-specific implementations): + +// Notify modbluetooth that a connection/disconnection event has occurred. +void mp_bluetooth_gap_on_connected_disconnected(uint16_t event, uint16_t conn_handle, uint8_t addr_type, const uint8_t *addr); + +// Call this when a characteristic is written to. +void mp_bluetooth_gatts_on_write(uint16_t conn_handle, uint16_t value_handle); + +#if MICROPY_PY_BLUETOOTH_GATTS_ON_READ_CALLBACK +// Call this when a characteristic is read from. Return false to deny the read. +bool mp_bluetooth_gatts_on_read_request(uint16_t conn_handle, uint16_t value_handle); +#endif + +#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE +// Notify modbluetooth that scan has finished, either timeout, manually, or by some other action (e.g. connecting). +void mp_bluetooth_gap_on_scan_complete(void); + +// Notify modbluetooth of a scan result. +void mp_bluetooth_gap_on_scan_result(uint8_t addr_type, const uint8_t *addr, bool connectable, const int8_t rssi, const uint8_t *data, size_t data_len); + +// Notify modbluetooth that a service was found (either by discover-all, or discover-by-uuid). +void mp_bluetooth_gattc_on_primary_service_result(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, mp_obj_bluetooth_uuid_t *service_uuid); + +// Notify modbluetooth that a characteristic was found (either by discover-all-on-service, or discover-by-uuid-on-service). +void mp_bluetooth_gattc_on_characteristic_result(uint16_t conn_handle, uint16_t def_handle, uint16_t value_handle, uint8_t properties, mp_obj_bluetooth_uuid_t *characteristic_uuid); + +// Notify modbluetooth that a descriptor was found. +void mp_bluetooth_gattc_on_descriptor_result(uint16_t conn_handle, uint16_t handle, mp_obj_bluetooth_uuid_t *descriptor_uuid); + +// Notify modbluetooth that a read has completed with data (or notify/indicate data available, use `event` to disambiguate). +void mp_bluetooth_gattc_on_data_available(uint16_t event, uint16_t conn_handle, uint16_t value_handle, const uint8_t *data, size_t data_len); + +// Notify modbluetooth that a write has completed. +void mp_bluetooth_gattc_on_write_status(uint16_t conn_handle, uint16_t value_handle, uint16_t status); +#endif + +#endif // MICROPY_INCLUDED_EXTMOD_MODBLUETOOTH_H diff --git a/py/mpstate.h b/py/mpstate.h index 0f9c56d2c7..ab7d8c51b9 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -189,6 +189,10 @@ typedef struct _mp_state_vm_t { struct _mp_vfs_mount_t *vfs_mount_table; #endif + #if MICROPY_PY_BLUETOOTH + mp_obj_t bluetooth; + #endif + // // END ROOT POINTER SECTION //////////////////////////////////////////////////////////// diff --git a/py/py.mk b/py/py.mk index d30ee81bc1..ba3a8639bf 100644 --- a/py/py.mk +++ b/py/py.mk @@ -174,6 +174,7 @@ PY_EXTMOD_O_BASENAME = \ extmod/machine_pulse.o \ extmod/machine_i2c.o \ extmod/machine_spi.o \ + extmod/modbluetooth.o \ extmod/modussl_axtls.o \ extmod/modussl_mbedtls.o \ extmod/modurandom.o \ diff --git a/py/runtime.c b/py/runtime.c index ecbdff2bab..2657e7cc25 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -131,6 +131,10 @@ void mp_init(void) { MP_STATE_THREAD(current_code_state) = NULL; #endif + #if MICROPY_PY_BLUETOOTH + MP_STATE_VM(bluetooth) = MP_OBJ_NULL; + #endif + #if MICROPY_PY_THREAD_GIL mp_thread_mutex_init(&MP_STATE_VM(gil_mutex)); #endif From 497dae45e713921bb8b017e92657eaa0dcd6f0fd Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Sun, 29 Sep 2019 23:05:15 +1000 Subject: [PATCH 0766/1788] extmod/modbluetooth_nimble: Implement modbluetooth API with Nimble. --- extmod/modbluetooth_nimble.c | 854 +++++++++++++++++++++++++++++++++++ 1 file changed, 854 insertions(+) create mode 100644 extmod/modbluetooth_nimble.c diff --git a/extmod/modbluetooth_nimble.c b/extmod/modbluetooth_nimble.c new file mode 100644 index 0000000000..3a6d1cba43 --- /dev/null +++ b/extmod/modbluetooth_nimble.c @@ -0,0 +1,854 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Damien P. George + * Copyright (c) 2019 Jim Mussared + * + * 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 "py/mphal.h" +#include "systick.h" +#include "pendsv.h" + +#if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE + +#ifndef MICROPY_PY_BLUETOOTH_DEFAULT_NAME +#define MICROPY_PY_BLUETOOTH_DEFAULT_NAME "PYBD" +#endif + +#include "extmod/modbluetooth.h" + +#include "host/ble_hs.h" +#include "host/util/util.h" +#include "nimble/ble.h" +#include "nimble/nimble_port.h" +#include "services/gap/ble_svc_gap.h" +#include "transport/uart/ble_hci_uart.h" + +#define DEBUG_MALLOC_printf(...) //printf(__VA_ARGS__) +#define DEBUG_EVENT_printf(...) //printf(__VA_ARGS__) + +STATIC int8_t ble_hs_err_to_errno_table[] = { + [BLE_HS_EAGAIN] = MP_EAGAIN, + [BLE_HS_EALREADY] = MP_EALREADY, + [BLE_HS_EINVAL] = MP_EINVAL, + [BLE_HS_EMSGSIZE] = MP_EIO, + [BLE_HS_ENOENT] = MP_ENOENT, + [BLE_HS_ENOMEM] = MP_ENOMEM, + [BLE_HS_ENOTCONN] = MP_ENOTCONN, + [BLE_HS_ENOTSUP] = MP_EOPNOTSUPP, + [BLE_HS_EAPP] = MP_EIO, + [BLE_HS_EBADDATA] = MP_EIO, + [BLE_HS_EOS] = MP_EIO, + [BLE_HS_ECONTROLLER] = MP_EIO, + [BLE_HS_ETIMEOUT] = MP_ETIMEDOUT, + [BLE_HS_EDONE] = MP_EIO, // TODO: Maybe should be MP_EISCONN (connect uses this for "already connected"). + [BLE_HS_EBUSY] = MP_EBUSY, + [BLE_HS_EREJECT] = MP_EIO, + [BLE_HS_EUNKNOWN] = MP_EIO, + [BLE_HS_EROLE] = MP_EIO, + [BLE_HS_ETIMEOUT_HCI] = MP_EIO, + [BLE_HS_ENOMEM_EVT] = MP_EIO, + [BLE_HS_ENOADDR] = MP_EIO, + [BLE_HS_ENOTSYNCED] = MP_EIO, + [BLE_HS_EAUTHEN] = MP_EIO, + [BLE_HS_EAUTHOR] = MP_EIO, + [BLE_HS_EENCRYPT] = MP_EIO, + [BLE_HS_EENCRYPT_KEY_SZ] = MP_EIO, + [BLE_HS_ESTORE_CAP] = MP_EIO, + [BLE_HS_ESTORE_FAIL] = MP_EIO, + [BLE_HS_EPREEMPTED] = MP_EIO, + [BLE_HS_EDISABLED] = MP_EIO, +}; + +STATIC int ble_hs_err_to_errno(int err) { + if (0 <= err && err < MP_ARRAY_SIZE(ble_hs_err_to_errno_table)) { + return ble_hs_err_to_errno_table[err]; + } else { + return MP_EIO; + } +} + +// Maintain a linked list of heap memory that we've passed to Nimble, +// discoverable via the bluetooth_nimble_memory root pointer. + +// MP_STATE_PORT(bluetooth_nimble_memory) is a pointer to [next, prev, data...]. + +// TODO: This is duplicated from mbedtls. Perhaps make this a generic feature? +void *m_malloc_bluetooth(size_t size) { + void **ptr = m_malloc0(size + 2 * sizeof(uintptr_t)); + if (MP_STATE_PORT(bluetooth_nimble_memory) != NULL) { + MP_STATE_PORT(bluetooth_nimble_memory)[0] = ptr; + } + ptr[0] = NULL; + ptr[1] = MP_STATE_PORT(bluetooth_nimble_memory); + MP_STATE_PORT(bluetooth_nimble_memory) = ptr; + return &ptr[2]; +} + +#define m_new_bluetooth(type, num) ((type*)m_malloc_bluetooth(sizeof(type) * (num))) + +void m_free_bluetooth(void *ptr_in) { + void **ptr = &((void**)ptr_in)[-2]; + if (ptr[1] != NULL) { + ((void**)ptr[1])[0] = ptr[0]; + } + if (ptr[0] != NULL) { + ((void**)ptr[0])[1] = ptr[1]; + } else { + MP_STATE_PORT(bluetooth_nimble_memory) = ptr[1]; + } + m_free(ptr); +} + +// Check if a nimble ptr is tracked. +// If it isn't, that means that it's from a previous soft-reset cycle. +STATIC bool is_valid_nimble_malloc(void *ptr) { + DEBUG_MALLOC_printf("NIMBLE is_valid_nimble_malloc(%p)\n", ptr); + void** search = MP_STATE_PORT(bluetooth_nimble_memory); + while (search) { + if (&search[2] == ptr) { + return true; + } + + search = (void**)search[1]; + } + return false; +} + +void *nimble_malloc(size_t size) { + DEBUG_MALLOC_printf("NIMBLE malloc(%u)\n", (uint)size); + void* ptr = m_malloc_bluetooth(size); + DEBUG_MALLOC_printf(" --> %p\n", ptr); + return ptr; +} + +// Only free if it's still a valid pointer. +void nimble_free(void *ptr) { + DEBUG_MALLOC_printf("NIMBLE free(%p)\n", ptr); + if (ptr && is_valid_nimble_malloc(ptr)) { + m_free_bluetooth(ptr); + } +} + +// Only realloc if it's still a valid pointer. Otherwise just malloc. +void *nimble_realloc(void *ptr, size_t size) { + // This is only used by ble_gatts.c to grow the queue of pending services to be registered. + DEBUG_MALLOC_printf("NIMBLE realloc(%p, %u)\n", ptr, (uint)size); + void *ptr2 = nimble_malloc(size); + if (ptr && is_valid_nimble_malloc(ptr)) { + // If it's a realloc and we still have the old data, then copy it. + // This will happen as we add services. + memcpy(ptr2, ptr, size); + m_free_bluetooth(ptr); + } + return ptr2; +} + +STATIC ble_uuid_t* create_nimble_uuid(const mp_obj_bluetooth_uuid_t *uuid) { + if (uuid->type == MP_BLUETOOTH_UUID_TYPE_16) { + ble_uuid16_t *result = m_new(ble_uuid16_t, 1); + result->u.type = BLE_UUID_TYPE_16; + result->value = uuid->uuid._16; + return (ble_uuid_t*)result; + } else if (uuid->type == MP_BLUETOOTH_UUID_TYPE_32) { + ble_uuid32_t *result = m_new(ble_uuid32_t, 1); + result->u.type = BLE_UUID_TYPE_32; + result->value = uuid->uuid._32; + return (ble_uuid_t*)result; + } else if (uuid->type == MP_BLUETOOTH_UUID_TYPE_128) { + ble_uuid128_t *result = m_new(ble_uuid128_t, 1); + result->u.type = BLE_UUID_TYPE_128; + memcpy(result->value, uuid->uuid._128, 16); + return (ble_uuid_t*)result; + } else { + return NULL; + } +} + +#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE + +STATIC mp_obj_bluetooth_uuid_t create_mp_uuid(const ble_uuid_any_t *uuid) { + mp_obj_bluetooth_uuid_t result; + switch (uuid->u.type) { + case BLE_UUID_TYPE_16: + result.type = MP_BLUETOOTH_UUID_TYPE_16; + result.uuid._16 = uuid->u16.value; + break; + case BLE_UUID_TYPE_32: + result.type = MP_BLUETOOTH_UUID_TYPE_32; + result.uuid._32 = uuid->u32.value; + break; + case BLE_UUID_TYPE_128: + result.type = MP_BLUETOOTH_UUID_TYPE_128; + memcpy(result.uuid._128, uuid->u128.value, 16); + break; + default: + assert(false); + } + return result; +} + +// modbluetooth (and the layers above it) work in BE addresses, Nimble works in LE. +STATIC void reverse_addr_byte_order(uint8_t *addr_out, const uint8_t *addr_in) { + for (int i = 0; i < 6; ++i) { + addr_out[i] = addr_in[5-i]; + } +} + +STATIC ble_addr_t create_nimble_addr(uint8_t addr_type, const uint8_t *addr) { + ble_addr_t addr_nimble; + addr_nimble.type = addr_type; + // Incoming addr is from modbluetooth (BE), so copy and convert to LE for Nimble. + reverse_addr_byte_order(addr_nimble.val, addr); + return addr_nimble; +} + +#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE + +STATIC mp_map_t *gatts_db = MP_OBJ_NULL; + +typedef struct { + uint8_t *data; + size_t data_alloc; + size_t data_len; +} gatts_db_entry_t; + +/******************************************************************************/ +// RUN LOOP + +enum { + BLE_STATE_OFF, + BLE_STATE_STARTING, + BLE_STATE_ACTIVE, +}; + +static volatile int ble_state = BLE_STATE_OFF; + +extern void nimble_uart_process(void); +extern void os_eventq_run_all(void); +extern void os_callout_process(void); + +// Hook for pendsv poller to run this periodically every 128ms +#define NIMBLE_TICK(tick) (((tick) & ~(SYSTICK_DISPATCH_NUM_SLOTS - 1) & 0x7f) == 0) + +void nimble_poll(void) { + if (ble_state == BLE_STATE_OFF) { + return; + } + + nimble_uart_process(); + os_callout_process(); + os_eventq_run_all(); +} + +void mod_bluetooth_nimble_poll_wrapper(uint32_t ticks_ms) { + if (NIMBLE_TICK(ticks_ms)) { + pendsv_schedule_dispatch(PENDSV_DISPATCH_NIMBLE, nimble_poll); + } +} + +/******************************************************************************/ +// BINDINGS + +STATIC void reset_cb(int reason) { + (void)reason; +} + +STATIC void sync_cb(void) { + ble_hs_util_ensure_addr(0); // prefer public address + ble_svc_gap_device_name_set(MICROPY_PY_BLUETOOTH_DEFAULT_NAME); + + ble_state = BLE_STATE_ACTIVE; +} + +STATIC void create_gatts_db_entry(uint16_t handle) { + mp_map_elem_t *elem = mp_map_lookup(gatts_db, MP_OBJ_NEW_SMALL_INT(handle), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); + gatts_db_entry_t *entry = m_new(gatts_db_entry_t, 1); + entry->data = m_new(uint8_t, MP_BLUETOOTH_MAX_ATTR_SIZE); + entry->data_alloc = MP_BLUETOOTH_MAX_ATTR_SIZE; + entry->data_len = 0; + elem->value = MP_OBJ_FROM_PTR(entry); +} + +STATIC void gatts_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) { + switch (ctxt->op) { + case BLE_GATT_REGISTER_OP_SVC: + // Called when a service is successfully registered. + DEBUG_EVENT_printf("gatts_register_cb: svc uuid=%p handle=%d\n", &ctxt->svc.svc_def->uuid, ctxt->svc.handle); + break; + + case BLE_GATT_REGISTER_OP_CHR: + // Called when a characteristic is successfully registered. + DEBUG_EVENT_printf("gatts_register_cb: chr uuid=%p def_handle=%d val_handle=%d\n", &ctxt->chr.chr_def->uuid, ctxt->chr.def_handle, ctxt->chr.val_handle); + + // Note: We will get this event for the default GAP Service, meaning that we allocate storage for the + // "device name" and "appearance" characteristics, even though we never see the reads for them. + // TODO: Possibly check if the service UUID is 0x1801 and ignore? + + // Allocate the gatts_db storage for this characteristic. + // Although this function is a callback, it's called synchronously from ble_hs_sched_start/ble_gatts_start, so safe to allocate. + create_gatts_db_entry(ctxt->chr.val_handle); + break; + + case BLE_GATT_REGISTER_OP_DSC: + // Called when a descriptor is successfully registered. + // Note: This is event is not called for the CCCD. + DEBUG_EVENT_printf("gatts_register_cb: dsc uuid=%p handle=%d\n", &ctxt->dsc.dsc_def->uuid, ctxt->dsc.handle); + + // See above, safe to alloc. + create_gatts_db_entry(ctxt->dsc.handle); + + // Unlike characteristics, we have to manually provide a way to get the handle back to the register method. + *((uint16_t*)ctxt->dsc.dsc_def->arg) = ctxt->dsc.handle; + break; + + default: + DEBUG_EVENT_printf("gatts_register_cb: unknown op %d\n", ctxt->op); + break; + } +} + +STATIC int gap_event_cb(struct ble_gap_event *event, void *arg) { + DEBUG_EVENT_printf("gap_event_cb: type=%d\n", event->type); + struct ble_gap_conn_desc desc; + uint8_t addr[6] = {0}; + + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + if (event->connect.status == 0) { + // Connection established. + ble_gap_conn_find(event->connect.conn_handle, &desc); + reverse_addr_byte_order(addr, desc.peer_id_addr.val); + mp_bluetooth_gap_on_connected_disconnected(MP_BLUETOOTH_IRQ_CENTRAL_CONNECT, event->connect.conn_handle, desc.peer_id_addr.type, addr); + } else { + // Connection failed. + mp_bluetooth_gap_on_connected_disconnected(MP_BLUETOOTH_IRQ_CENTRAL_DISCONNECT, event->connect.conn_handle, 0xff, addr); + } + break; + + case BLE_GAP_EVENT_DISCONNECT: + // Disconnect. + reverse_addr_byte_order(addr, event->disconnect.conn.peer_id_addr.val); + mp_bluetooth_gap_on_connected_disconnected(MP_BLUETOOTH_IRQ_CENTRAL_DISCONNECT, event->disconnect.conn.conn_handle, event->disconnect.conn.peer_id_addr.type, addr); + break; + } + + return 0; +} + +int mp_bluetooth_init(void) { + // Clean up if necessary. + mp_bluetooth_deinit(); + + MP_STATE_PORT(bluetooth_nimble_memory) = NULL; + + ble_hs_cfg.reset_cb = reset_cb; + ble_hs_cfg.sync_cb = sync_cb; + ble_hs_cfg.gatts_register_cb = gatts_register_cb; + ble_hs_cfg.store_status_cb = ble_store_util_status_rr; + + gatts_db = m_new_bluetooth(mp_map_t, 1); + + ble_hci_uart_init(); + nimble_port_init(); + + // By default, just register the default gap service. + ble_svc_gap_init(); + + ble_state = BLE_STATE_STARTING; + + ble_hs_start(); + + // Wait for sync callback + while (ble_state != BLE_STATE_ACTIVE) { + MICROPY_EVENT_POLL_HOOK + } + + return 0; +} + +// Called when the host stop procedure has completed. +STATIC void ble_hs_shutdown_stop_cb(int status, void *arg) { + ble_state = BLE_STATE_OFF; +} + +STATIC struct ble_hs_stop_listener ble_hs_shutdown_stop_listener; + +void mp_bluetooth_deinit(void) { + if (ble_state == BLE_STATE_OFF) { + return; + } + + mp_bluetooth_gap_advertise_stop(); + #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE + mp_bluetooth_gap_scan_stop(); + #endif + + ble_hs_stop(&ble_hs_shutdown_stop_listener, ble_hs_shutdown_stop_cb, + NULL); + + while (ble_state != BLE_STATE_OFF) { + MICROPY_EVENT_POLL_HOOK + } + + // TODO: This should be a port-specific hook. + #ifdef pyb_pin_BT_REG_ON + mp_hal_pin_low(pyb_pin_BT_REG_ON); + #endif +} + +bool mp_bluetooth_is_enabled(void) { + return ble_state == BLE_STATE_ACTIVE; +} + +void mp_bluetooth_get_device_addr(uint8_t *addr) { + mp_hal_get_mac(MP_HAL_MAC_BDADDR, addr); +} + +int mp_bluetooth_gap_advertise_start(bool connectable, uint16_t interval_ms, const uint8_t *adv_data, size_t adv_data_len, const uint8_t *sr_data, size_t sr_data_len) { + int ret; + + mp_bluetooth_gap_advertise_stop(); + + if ((adv_data != NULL) && (adv_data_len > 0)) { + ret = ble_gap_adv_set_data(adv_data, adv_data_len); + if (ret != 0) { + return ble_hs_err_to_errno(ret); + } + } + + if ((sr_data != NULL) && (sr_data_len > 0)) { + ret = ble_gap_adv_rsp_set_data(sr_data, sr_data_len); + if (ret != 0) { + return ble_hs_err_to_errno(ret); + } + } + + // Convert from 1ms to 0.625ms units. + interval_ms = interval_ms * 8 / 5; + if (interval_ms < 0x20 || interval_ms > 0x4000) { + return MP_EINVAL; + } + + struct ble_gap_adv_params adv_params = { + .conn_mode = connectable ? BLE_GAP_CONN_MODE_UND : BLE_GAP_CONN_MODE_NON, + .disc_mode = BLE_GAP_DISC_MODE_GEN, + .itvl_min = interval_ms, + .itvl_max = interval_ms, + .channel_map = 7, // all 3 channels + }; + + ret = ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER, &adv_params, gap_event_cb, NULL); + if (ret != 0) { + return ble_hs_err_to_errno(ret); + } + + return 0; +} + +void mp_bluetooth_gap_advertise_stop(void) { + if (ble_gap_adv_active()) { + ble_gap_adv_stop(); + } +} + +static int characteristic_access_cb(uint16_t conn_handle, uint16_t value_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { + DEBUG_EVENT_printf("characteristic_access_cb: conn_handle=%u value_handle=%u op=%u\n", conn_handle, value_handle, ctxt->op); + mp_map_elem_t *elem; + gatts_db_entry_t *entry; + switch (ctxt->op) { + case BLE_GATT_ACCESS_OP_READ_CHR: + case BLE_GATT_ACCESS_OP_READ_DSC: + #if MICROPY_PY_BLUETOOTH_GATTS_ON_READ_CALLBACK + // Allow Python code to override (by using gatts_write), or deny (by returning false) the read. + if (!mp_bluetooth_gatts_on_read_request(conn_handle, value_handle)) { + return BLE_ATT_ERR_READ_NOT_PERMITTED; + } + #endif + + elem = mp_map_lookup(gatts_db, MP_OBJ_NEW_SMALL_INT(value_handle), MP_MAP_LOOKUP); + if (!elem) { + return BLE_ATT_ERR_ATTR_NOT_FOUND; + } + entry = MP_OBJ_TO_PTR(elem->value); + + os_mbuf_append(ctxt->om, entry->data, entry->data_len); + + return 0; + case BLE_GATT_ACCESS_OP_WRITE_CHR: + case BLE_GATT_ACCESS_OP_WRITE_DSC: + elem = mp_map_lookup(gatts_db, MP_OBJ_NEW_SMALL_INT(value_handle), MP_MAP_LOOKUP); + if (!elem) { + return BLE_ATT_ERR_ATTR_NOT_FOUND; + } + entry = MP_OBJ_TO_PTR(elem->value); + entry->data_len = MIN(MP_BLUETOOTH_MAX_ATTR_SIZE, OS_MBUF_PKTLEN(ctxt->om)); + os_mbuf_copydata(ctxt->om, 0, entry->data_len, entry->data); + + mp_bluetooth_gatts_on_write(conn_handle, value_handle); + + return 0; + } + return BLE_ATT_ERR_UNLIKELY; +} + +int mp_bluetooth_gatts_register_service_begin(bool reset) { + int ret = ble_gatts_reset(); + if (ret != 0) { + return ble_hs_err_to_errno(ret); + } + + // Reset the gatt characteristic value db. + mp_map_init(gatts_db, 0); + + // By default, just register the default gap service. + ble_svc_gap_init(); + + return 0; +} + +int mp_bluetooth_gatts_register_service_end() { + int ret = ble_gatts_start(); + if (ret != 0) { + return ble_hs_err_to_errno(ret); + } + + return 0; +} + +int mp_bluetooth_gatts_register_service(mp_obj_bluetooth_uuid_t *service_uuid, mp_obj_bluetooth_uuid_t **characteristic_uuids, uint8_t *characteristic_flags, mp_obj_bluetooth_uuid_t **descriptor_uuids, uint8_t *descriptor_flags, uint8_t *num_descriptors, uint16_t *handles, size_t num_characteristics) { + // TODO: These allocs need to last until mp_bluetooth_gatts_register_service_end. + // Using m_new_bluetooth means they get leaked, but m_new would mean that they wouldn't be findable by GC. + size_t handle_index = 0; + size_t descriptor_index = 0; + + struct ble_gatt_chr_def *characteristics = m_new_bluetooth(struct ble_gatt_chr_def, num_characteristics + 1); + for (size_t i = 0; i < num_characteristics; ++i) { + characteristics[i].uuid = create_nimble_uuid(characteristic_uuids[i]); + characteristics[i].access_cb = characteristic_access_cb; + characteristics[i].arg = NULL; + characteristics[i].flags = characteristic_flags[i]; + characteristics[i].min_key_size = 0; + characteristics[i].val_handle = &handles[handle_index]; + ++handle_index; + + if (num_descriptors[i] == 0) { + characteristics[i].descriptors = NULL; + } else { + struct ble_gatt_dsc_def *descriptors = m_new_bluetooth(struct ble_gatt_dsc_def, num_descriptors[i] + 1); + + for (size_t j = 0; j < num_descriptors[i]; ++j) { + descriptors[j].uuid = create_nimble_uuid(descriptor_uuids[descriptor_index]); + descriptors[j].access_cb = characteristic_access_cb; + descriptors[j].att_flags = descriptor_flags[i]; + descriptors[j].min_key_size = 0; + // Unlike characteristic, Nimble doesn't provide an automatic way to remember the handle, so use the arg. + descriptors[j].arg = &handles[handle_index]; + ++descriptor_index; + ++handle_index; + } + descriptors[num_descriptors[i]].uuid = NULL; // no more descriptors + + characteristics[i].descriptors = descriptors; + } + } + characteristics[num_characteristics].uuid = NULL; // no more characteristics + + struct ble_gatt_svc_def *service = m_new_bluetooth(struct ble_gatt_svc_def, 2); + service[0].type = BLE_GATT_SVC_TYPE_PRIMARY; + service[0].uuid = create_nimble_uuid(service_uuid); + service[0].includes = NULL; + service[0].characteristics = characteristics; + service[1].type = 0; // no more services + + // Note: advertising must be stopped for gatts registration to work + + int ret = ble_gatts_count_cfg(service); + if (ret != 0) { + return ble_hs_err_to_errno(ret); + } + + ret = ble_gatts_add_svcs(service); + if (ret != 0) { + return ble_hs_err_to_errno(ret); + } + + return 0; +} + +int mp_bluetooth_gap_disconnect(uint16_t conn_handle) { + return ble_hs_err_to_errno(ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM)); +} + +int mp_bluetooth_gatts_read(uint16_t value_handle, uint8_t **value, size_t *value_len) { + mp_map_elem_t *elem = mp_map_lookup(gatts_db, MP_OBJ_NEW_SMALL_INT(value_handle), MP_MAP_LOOKUP); + if (!elem) { + return MP_EINVAL; + } + gatts_db_entry_t *entry = MP_OBJ_TO_PTR(elem->value); + *value = entry->data; + *value_len = entry->data_len; + return 0; +} + +int mp_bluetooth_gatts_write(uint16_t value_handle, const uint8_t *value, size_t value_len) { + mp_map_elem_t *elem = mp_map_lookup(gatts_db, MP_OBJ_NEW_SMALL_INT(value_handle), MP_MAP_LOOKUP); + if (!elem) { + return MP_EINVAL; + } + gatts_db_entry_t *entry = MP_OBJ_TO_PTR(elem->value); + if (value_len > entry->data_alloc) { + entry->data = m_new(uint8_t, value_len); + entry->data_alloc = value_len; + } + + memcpy(entry->data, value, value_len); + entry->data_len = value_len; + return 0; +} + +// TODO: Could use ble_gatts_chr_updated to send to all subscribed centrals. + +int mp_bluetooth_gatts_notify(uint16_t conn_handle, uint16_t value_handle) { + // Confusingly, notify/notify_custom/indicate are "gattc" function (even though they're used by peripherals (i.e. gatt servers)). + // See https://www.mail-archive.com/dev@mynewt.apache.org/msg01293.html + return ble_hs_err_to_errno(ble_gattc_notify(conn_handle, value_handle)); +} + +int mp_bluetooth_gatts_notify_send(uint16_t conn_handle, uint16_t value_handle, const uint8_t *value, size_t *value_len) { + struct os_mbuf *om = ble_hs_mbuf_from_flat(value, *value_len); + if (om == NULL) { + return -1; + } + // TODO: check that notify_custom takes ownership of om, if not os_mbuf_free_chain(om). + return ble_hs_err_to_errno(ble_gattc_notify_custom(conn_handle, value_handle, om)); +} + +int mp_bluetooth_gatts_indicate(uint16_t conn_handle, uint16_t value_handle) { + return ble_hs_err_to_errno(ble_gattc_indicate(conn_handle, value_handle)); +} + +#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE + +STATIC int gap_scan_cb(struct ble_gap_event *event, void *arg) { + DEBUG_EVENT_printf("gap_scan_cb: event=%d\n", event->type); + + if (event->type == BLE_GAP_EVENT_DISC_COMPLETE) { + mp_bluetooth_gap_on_scan_complete(); + return 0; + } + + if (event->type != BLE_GAP_EVENT_DISC) { + return 0; + } + + DEBUG_EVENT_printf(" --> type %d\n", event->disc.event_type); + + + if (event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_ADV_IND || event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_NONCONN_IND) { + bool connectable = event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_ADV_IND; + uint8_t addr[6]; + reverse_addr_byte_order(addr, event->disc.addr.val); + mp_bluetooth_gap_on_scan_result(event->disc.addr.type, addr, connectable, event->disc.rssi, event->disc.data, event->disc.length_data); + } else if (event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) { + // TODO + } else if (event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_IND) { + // TODO + } + + return 0; +} + +int mp_bluetooth_gap_scan_start(int32_t duration_ms) { + if (duration_ms == 0) { + duration_ms = BLE_HS_FOREVER; + } + STATIC const struct ble_gap_disc_params discover_params = { + .itvl = BLE_GAP_SCAN_SLOW_INTERVAL1, + .window = BLE_GAP_SCAN_SLOW_WINDOW1, + .filter_policy = BLE_HCI_CONN_FILT_NO_WL, + .limited = 0, + .passive = 0, + .filter_duplicates = 0, + }; + int err = ble_gap_disc(BLE_OWN_ADDR_PUBLIC, duration_ms, &discover_params, gap_scan_cb, NULL); + return ble_hs_err_to_errno(err); +} + +int mp_bluetooth_gap_scan_stop(void) { + int err = ble_gap_disc_cancel(); + if (err == 0) { + mp_bluetooth_gap_on_scan_complete(); + return 0; + } + return ble_hs_err_to_errno(err); +} + +// Central role: GAP events for a connected peripheral. +STATIC int peripheral_gap_event_cb(struct ble_gap_event *event, void *arg) { + DEBUG_EVENT_printf("peripheral_gap_event_cb: event=%d\n", event->type); + struct ble_gap_conn_desc desc; + uint8_t buf[MP_BLUETOOTH_MAX_ATTR_SIZE]; + size_t len; + uint8_t addr[6] = {0}; + + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + if (event->connect.status == 0) { + // Connection established. + ble_gap_conn_find(event->connect.conn_handle, &desc); + reverse_addr_byte_order(addr, desc.peer_id_addr.val); + mp_bluetooth_gap_on_connected_disconnected(MP_BLUETOOTH_IRQ_PERIPHERAL_CONNECT, event->connect.conn_handle, desc.peer_id_addr.type, addr); + } else { + // Connection failed. + mp_bluetooth_gap_on_connected_disconnected(MP_BLUETOOTH_IRQ_PERIPHERAL_DISCONNECT, event->connect.conn_handle, 0xff, addr); + } + break; + + case BLE_GAP_EVENT_DISCONNECT: + // Disconnect. + reverse_addr_byte_order(addr, event->disconnect.conn.peer_id_addr.val); + mp_bluetooth_gap_on_connected_disconnected(MP_BLUETOOTH_IRQ_PERIPHERAL_DISCONNECT, event->disconnect.conn.conn_handle, event->disconnect.conn.peer_id_addr.type, addr); + + break; + + case BLE_GAP_EVENT_NOTIFY_RX: + len = MIN(MP_BLUETOOTH_MAX_ATTR_SIZE, OS_MBUF_PKTLEN(event->notify_rx.om)); + os_mbuf_copydata(event->notify_rx.om, 0, len, buf); + if (event->notify_rx.indication == 0) { + mp_bluetooth_gattc_on_data_available(MP_BLUETOOTH_IRQ_GATTC_NOTIFY, event->notify_rx.conn_handle, event->notify_rx.attr_handle, buf, len); + } else { + mp_bluetooth_gattc_on_data_available(MP_BLUETOOTH_IRQ_GATTC_INDICATE, event->notify_rx.conn_handle, event->notify_rx.attr_handle, buf, len); + } + break; + + case BLE_GAP_EVENT_CONN_UPDATE: + // TODO + break; + + case BLE_GAP_EVENT_CONN_UPDATE_REQ: + // TODO + break; + + default: + break; + } + return 0; +} + +int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, int32_t duration_ms) { + if (ble_gap_disc_active()) { + mp_bluetooth_gap_scan_stop(); + } + + // TODO: This is the same as ble_gap_conn_params_dflt (i.e. passing NULL). + STATIC const struct ble_gap_conn_params params = { + .scan_itvl = 0x0010, + .scan_window = 0x0010, + .itvl_min = BLE_GAP_INITIAL_CONN_ITVL_MIN, + .itvl_max = BLE_GAP_INITIAL_CONN_ITVL_MAX, + .latency = BLE_GAP_INITIAL_CONN_LATENCY, + .supervision_timeout = BLE_GAP_INITIAL_SUPERVISION_TIMEOUT, + .min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN, + .max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN, + }; + + ble_addr_t addr_nimble = create_nimble_addr(addr_type, addr); + int err = ble_gap_connect(BLE_OWN_ADDR_PUBLIC, &addr_nimble, duration_ms, ¶ms, &peripheral_gap_event_cb, NULL); + return ble_hs_err_to_errno(err); +} + +STATIC int peripheral_discover_service_cb(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *service, void *arg) { + DEBUG_EVENT_printf("peripheral_discover_service_cb: conn_handle=%d status=%d start_handle=%d\n", conn_handle, error->status, service->start_handle); + // TODO: Find out what error->status == 14 means (probably "end of services"). + if (error->status == 0) { + mp_obj_bluetooth_uuid_t service_uuid = create_mp_uuid(&service->uuid); + mp_bluetooth_gattc_on_primary_service_result(conn_handle, service->start_handle, service->end_handle, &service_uuid); + } + return 0; +} + +int mp_bluetooth_gattc_discover_primary_services(uint16_t conn_handle) { + int err = ble_gattc_disc_all_svcs(conn_handle, &peripheral_discover_service_cb, NULL); + return ble_hs_err_to_errno(err); +} + +STATIC int ble_gatt_characteristic_cb(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_chr *characteristic, void *arg) { + if (error->status == 0) { + mp_obj_bluetooth_uuid_t characteristic_uuid = create_mp_uuid(&characteristic->uuid); + mp_bluetooth_gattc_on_characteristic_result(conn_handle, characteristic->def_handle, characteristic->val_handle, characteristic->properties, &characteristic_uuid); + } + return 0; +} + +int mp_bluetooth_gattc_discover_characteristics(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle) { + int err = ble_gattc_disc_all_chrs(conn_handle, start_handle, end_handle, &ble_gatt_characteristic_cb, NULL); + return ble_hs_err_to_errno(err); +} + +STATIC int ble_gatt_descriptor_cb(uint16_t conn_handle, const struct ble_gatt_error *error, uint16_t characteristic_val_handle, const struct ble_gatt_dsc *descriptor, void *arg) { + if (error->status == 0) { + mp_obj_bluetooth_uuid_t descriptor_uuid = create_mp_uuid(&descriptor->uuid); + mp_bluetooth_gattc_on_descriptor_result(conn_handle, descriptor->handle, &descriptor_uuid); + } + return 0; +} + +int mp_bluetooth_gattc_discover_descriptors(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle) { + int err = ble_gattc_disc_all_dscs(conn_handle, start_handle, end_handle, &ble_gatt_descriptor_cb, NULL); + return ble_hs_err_to_errno(err); +} + +STATIC int ble_gatt_attr_read_cb(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) { + // TODO: Maybe send NULL if error->status non-zero. + if (error->status == 0) { + uint8_t buf[MP_BLUETOOTH_MAX_ATTR_SIZE]; + size_t len = MIN(MP_BLUETOOTH_MAX_ATTR_SIZE, OS_MBUF_PKTLEN(attr->om)); + os_mbuf_copydata(attr->om, 0, len, buf); + mp_bluetooth_gattc_on_data_available(MP_BLUETOOTH_IRQ_GATTC_READ_RESULT, conn_handle, attr->handle, buf, len); + } + return 0; +} + +// Initiate read of a value from the remote peripheral. +int mp_bluetooth_gattc_read(uint16_t conn_handle, uint16_t value_handle) { + int err = ble_gattc_read(conn_handle, value_handle, &ble_gatt_attr_read_cb, NULL); + return ble_hs_err_to_errno(err); +} + +STATIC int ble_gatt_attr_write_cb(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) { + mp_bluetooth_gattc_on_write_status(conn_handle, attr->handle, error->status); + return 0; +} + +// Write the value to the remote peripheral. +int mp_bluetooth_gattc_write(uint16_t conn_handle, uint16_t value_handle, const uint8_t *value, size_t *value_len) { + int err = ble_gattc_write_flat(conn_handle, value_handle, value, *value_len, &ble_gatt_attr_write_cb, NULL); + return ble_hs_err_to_errno(err); +} + +#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE + +#endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE From 5dc592d117b68455e8b1c1ef9230090c143358dc Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Sun, 1 Sep 2019 19:08:16 +1000 Subject: [PATCH 0767/1788] extmod/modbluetooth_nimble: Use random addr if public isn't available. --- extmod/modbluetooth_nimble.c | 43 ++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/extmod/modbluetooth_nimble.c b/extmod/modbluetooth_nimble.c index 3a6d1cba43..21d71e3c96 100644 --- a/extmod/modbluetooth_nimble.c +++ b/extmod/modbluetooth_nimble.c @@ -277,7 +277,30 @@ STATIC void reset_cb(int reason) { } STATIC void sync_cb(void) { - ble_hs_util_ensure_addr(0); // prefer public address + int rc; + ble_addr_t addr; + + rc = ble_hs_util_ensure_addr(0); // prefer public address + if (rc != 0) { + // https://mynewt.apache.org/latest/tutorials/ble/eddystone.html#configure-the-nimble-stack-with-an-address + #if MICROPY_PY_BLUETOOTH_RANDOM_ADDR + rc = ble_hs_id_gen_rnd(1, &addr); + assert(rc == 0); + rc = ble_hs_id_set_rnd(addr.val); + assert(rc == 0); + #else + uint8_t addr_be[6]; + mp_hal_get_mac(MP_HAL_MAC_BDADDR, addr_be); + reverse_addr_byte_order(addr.val, addr_be); + // ble_hs_id_set_pub(addr.val); + rc = ble_hs_id_set_rnd(addr.val); + assert(rc == 0); + #endif + + rc = ble_hs_util_ensure_addr(0); // prefer public address + assert(rc == 0); + } + ble_svc_gap_device_name_set(MICROPY_PY_BLUETOOTH_DEFAULT_NAME); ble_state = BLE_STATE_ACTIVE; @@ -461,11 +484,23 @@ int mp_bluetooth_gap_advertise_start(bool connectable, uint16_t interval_ms, con }; ret = ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER, &adv_params, gap_event_cb, NULL); - if (ret != 0) { - return ble_hs_err_to_errno(ret); + if (ret == 0) { + return 0; + } + ret = ble_gap_adv_start(BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT, NULL, BLE_HS_FOREVER, &adv_params, gap_event_cb, NULL); + if (ret == 0) { + return 0; + } + ret = ble_gap_adv_start(BLE_OWN_ADDR_RPA_RANDOM_DEFAULT, NULL, BLE_HS_FOREVER, &adv_params, gap_event_cb, NULL); + if (ret == 0) { + return 0; + } + ret = ble_gap_adv_start(BLE_OWN_ADDR_RANDOM, NULL, BLE_HS_FOREVER, &adv_params, gap_event_cb, NULL); + if (ret == 0) { + return 0; } - return 0; + return ble_hs_err_to_errno(ret); } void mp_bluetooth_gap_advertise_stop(void) { From eb1b6858a2c5454f84ab4bb0b854b96d234995c8 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Mon, 2 Sep 2019 15:40:31 +1000 Subject: [PATCH 0768/1788] extmod/modbluetooth: Allow MP_BLUETOOTH_MAX_ATTR_SIZE in board config. --- extmod/modbluetooth.h | 2 ++ extmod/modbluetooth_nimble.c | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h index 1b1318dec5..9db3bed6cd 100644 --- a/extmod/modbluetooth.h +++ b/extmod/modbluetooth.h @@ -48,7 +48,9 @@ #endif // Common constants. +#ifndef MP_BLUETOOTH_MAX_ATTR_SIZE #define MP_BLUETOOTH_MAX_ATTR_SIZE (20) +#endif // Advertisement packet lengths #define MP_BLUETOOTH_GAP_ADV_MAX_LEN (32) diff --git a/extmod/modbluetooth_nimble.c b/extmod/modbluetooth_nimble.c index 21d71e3c96..959360cee7 100644 --- a/extmod/modbluetooth_nimble.c +++ b/extmod/modbluetooth_nimble.c @@ -301,6 +301,11 @@ STATIC void sync_cb(void) { assert(rc == 0); } + if (MP_BLUETOOTH_MAX_ATTR_SIZE > 20) { + rc = ble_att_set_preferred_mtu(MP_BLUETOOTH_MAX_ATTR_SIZE+3); + assert(rc == 0); + } + ble_svc_gap_device_name_set(MICROPY_PY_BLUETOOTH_DEFAULT_NAME); ble_state = BLE_STATE_ACTIVE; From 6f35f214d36ac9a58a069d163e3ab9ba05d650dd Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 30 Sep 2019 12:23:00 +1000 Subject: [PATCH 0769/1788] stm32/mpconfigport.h: Add modbluetooth module to stm32. --- ports/stm32/Makefile | 6 ++++++ ports/stm32/mpconfigport.h | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 0e3b4f8e33..40db2f7560 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -379,6 +379,12 @@ SRC_USBDEV = $(addprefix $(USBDEV_DIR)/,\ class/src/usbd_msc_scsi.c \ ) +ifeq ($(MICROPY_PY_BLUETOOTH),1) +CFLAGS_MOD += -DMICROPY_PY_BLUETOOTH=1 +CFLAGS_MOD += -DMICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE=1 +CFLAGS_MOD += -DMICROPY_PY_BLUETOOTH_GATTS_ON_READ_CALLBACK=1 +endif + ifeq ($(MICROPY_PY_NETWORK_CYW43),1) CFLAGS_MOD += -DMICROPY_PY_NETWORK_CYW43=1 SRC_C += sdio.c diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index b9c6cdedd7..54e1c503c4 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -211,6 +211,7 @@ extern const struct _mp_obj_module_t mp_module_uos; extern const struct _mp_obj_module_t mp_module_utime; 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_bluetooth; extern const struct _mp_obj_module_t mp_module_onewire; #if MICROPY_PY_STM @@ -245,6 +246,12 @@ extern const struct _mp_obj_module_t mp_module_onewire; #define NETWORK_BUILTIN_MODULE #endif +#if MICROPY_PY_BLUETOOTH +#define BLUETOOTH_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_bluetooth), MP_ROM_PTR(&mp_module_bluetooth) }, +#else +#define BLUETOOTH_BUILTIN_MODULE +#endif + #define MICROPY_PORT_BUILTIN_MODULES \ { MP_ROM_QSTR(MP_QSTR_umachine), MP_ROM_PTR(&machine_module) }, \ { MP_ROM_QSTR(MP_QSTR_pyb), MP_ROM_PTR(&pyb_module) }, \ @@ -253,6 +260,7 @@ extern const struct _mp_obj_module_t mp_module_onewire; { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_utime) }, \ SOCKET_BUILTIN_MODULE \ NETWORK_BUILTIN_MODULE \ + BLUETOOTH_BUILTIN_MODULE \ { MP_ROM_QSTR(MP_QSTR__onewire), MP_ROM_PTR(&mp_module_onewire) }, \ #define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \ From fafa9d35ddf90d35e14f32e736ac824631b09b38 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 27 Aug 2019 15:57:24 +1000 Subject: [PATCH 0770/1788] stm32/boards/PYBD: Enable BLE for Pyboard D. --- ports/stm32/boards/PYBD_SF2/mpconfigboard.h | 4 ++++ ports/stm32/boards/PYBD_SF2/mpconfigboard.mk | 2 ++ ports/stm32/boards/PYBD_SF3/mpconfigboard.mk | 2 ++ ports/stm32/boards/PYBD_SF6/mpconfigboard.mk | 2 ++ 4 files changed, 10 insertions(+) diff --git a/ports/stm32/boards/PYBD_SF2/mpconfigboard.h b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h index 215b3f4016..8926ec081b 100644 --- a/ports/stm32/boards/PYBD_SF2/mpconfigboard.h +++ b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h @@ -177,6 +177,10 @@ extern struct _spi_bdev_t spi_bdev2; #define MICROPY_HW_USB_HS_IN_FS (1) #define MICROPY_HW_USB_MAIN_DEV (USB_PHY_HS_ID) +// Bluetooth config +#define MICROPY_HW_BLE_UART_ID (PYB_UART_6) +#define MICROPY_HW_BLE_UART_BAUDRATE (115200) + /******************************************************************************/ // Bootloader configuration diff --git a/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk b/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk index 489d2f893a..834a60b029 100644 --- a/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk +++ b/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk @@ -10,6 +10,8 @@ TEXT0_SECTIONS = .isr_vector .text .data TEXT1_SECTIONS = .text_ext # MicroPython settings +MICROPY_PY_BLUETOOTH = 1 +MICROPY_BLUETOOTH_NIMBLE = 1 MICROPY_PY_LWIP = 1 MICROPY_PY_NETWORK_CYW43 = 1 MICROPY_PY_USSL = 1 diff --git a/ports/stm32/boards/PYBD_SF3/mpconfigboard.mk b/ports/stm32/boards/PYBD_SF3/mpconfigboard.mk index 368adcf39a..7bef5651dd 100644 --- a/ports/stm32/boards/PYBD_SF3/mpconfigboard.mk +++ b/ports/stm32/boards/PYBD_SF3/mpconfigboard.mk @@ -10,6 +10,8 @@ TEXT0_SECTIONS = .isr_vector .text .data TEXT1_SECTIONS = .text_ext # MicroPython settings +MICROPY_PY_BLUETOOTH = 1 +MICROPY_BLUETOOTH_NIMBLE = 1 MICROPY_PY_LWIP = 1 MICROPY_PY_NETWORK_CYW43 = 1 MICROPY_PY_USSL = 1 diff --git a/ports/stm32/boards/PYBD_SF6/mpconfigboard.mk b/ports/stm32/boards/PYBD_SF6/mpconfigboard.mk index 97c854ae77..f85d9c9973 100644 --- a/ports/stm32/boards/PYBD_SF6/mpconfigboard.mk +++ b/ports/stm32/boards/PYBD_SF6/mpconfigboard.mk @@ -7,6 +7,8 @@ LD_FILES = boards/PYBD_SF6/f767.ld TEXT0_ADDR = 0x08008000 # MicroPython settings +MICROPY_PY_BLUETOOTH = 1 +MICROPY_BLUETOOTH_NIMBLE = 1 MICROPY_PY_LWIP = 1 MICROPY_PY_NETWORK_CYW43 = 1 MICROPY_PY_USSL = 1 From 1d7afcce49366c11f67561019a5adf5e60c450f5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 23 Sep 2019 23:32:31 +1000 Subject: [PATCH 0771/1788] py/bc: Remove comments referring to obsolete currently_in_except_block. It was made obsolete in 6f9e3ff719917616f163d3d671d6abe9472ba6ff --- py/bc.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/py/bc.h b/py/bc.h index e1b39c03d8..dafd743760 100644 --- a/py/bc.h +++ b/py/bc.h @@ -77,10 +77,10 @@ typedef struct _mp_bytecode_prelude_t { // Exception stack entry typedef struct _mp_exc_stack_t { const byte *handler; - // bit 0 is saved currently_in_except_block value + // bit 0 is currently unused // bit 1 is whether the opcode was SETUP_WITH or SETUP_FINALLY mp_obj_t *val_sp; - // Saved exception, valid if currently_in_except_block bit is 1 + // Saved exception mp_obj_base_t *prev_exc; } mp_exc_stack_t; @@ -92,7 +92,6 @@ typedef struct _mp_code_state_t { mp_obj_fun_bc_t *fun_bc; const byte *ip; mp_obj_t *sp; - // bit 0 is saved currently_in_except_block value mp_exc_stack_t *exc_sp; mp_obj_dict_t *old_globals; #if MICROPY_STACKLESS From 4c5e1a036831a3ac36866e4daab3a50c772b4443 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 23 Sep 2019 23:37:01 +1000 Subject: [PATCH 0772/1788] py/bc: Change mp_code_state_t.exc_sp to exc_sp_idx. Change from a pointer to an index, to make space in mp_code_state_t. --- ports/unix/coverage.c | 2 +- py/bc.c | 2 +- py/bc.h | 9 ++++++++- py/objgenerator.c | 4 ++-- py/vm.c | 14 +++++++------- 5 files changed, 19 insertions(+), 12 deletions(-) diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index b6ebc9fb7e..6623cb4642 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -385,7 +385,7 @@ STATIC mp_obj_t extra_coverage(void) { 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->exc_sp_idx = 0; 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); diff --git a/py/bc.c b/py/bc.c index 6887dc4380..c32d5c415e 100644 --- a/py/bc.c +++ b/py/bc.c @@ -133,7 +133,7 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw size_t n_def_pos_args = *code_state->ip++; code_state->sp = &code_state->state[0] - 1; - code_state->exc_sp = (mp_exc_stack_t*)(code_state->state + n_state) - 1; + code_state->exc_sp_idx = 0; // zero out the local stack to begin with memset(code_state->state, 0, n_state * sizeof(*code_state->state)); diff --git a/py/bc.h b/py/bc.h index dafd743760..1d28dcc4f9 100644 --- a/py/bc.h +++ b/py/bc.h @@ -60,6 +60,13 @@ // const0 : obj // constN : obj +// Sentinel value for mp_code_state_t.exc_sp_idx +#define MP_CODE_STATE_EXC_SP_IDX_SENTINEL ((uint16_t)-1) + +// To convert mp_code_state_t.exc_sp_idx to/from a pointer to mp_exc_stack_t +#define MP_CODE_STATE_EXC_SP_IDX_FROM_PTR(exc_stack, exc_sp) ((exc_sp) + 1 - (exc_stack)) +#define MP_CODE_STATE_EXC_SP_IDX_TO_PTR(exc_stack, exc_sp_idx) ((exc_stack) + (exc_sp_idx) - 1) + typedef struct _mp_bytecode_prelude_t { uint n_state; uint n_exc_stack; @@ -92,7 +99,7 @@ typedef struct _mp_code_state_t { mp_obj_fun_bc_t *fun_bc; const byte *ip; mp_obj_t *sp; - mp_exc_stack_t *exc_sp; + uint16_t exc_sp_idx; mp_obj_dict_t *old_globals; #if MICROPY_STACKLESS struct _mp_code_state_t *prev; diff --git a/py/objgenerator.c b/py/objgenerator.c index 62e6446166..d32a74f3fb 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -102,7 +102,7 @@ STATIC mp_obj_t native_gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_k mp_setup_code_state(&o->code_state, n_args, n_kw, args); // Indicate we are a native function, which doesn't use this variable - o->code_state.exc_sp = NULL; + o->code_state.exc_sp_idx = MP_CODE_STATE_EXC_SP_IDX_SENTINEL; // Prepare the generator instance for execution uintptr_t start_offset = ((uintptr_t*)self_fun->bytecode)[1]; @@ -172,7 +172,7 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ mp_vm_return_kind_t ret_kind; #if MICROPY_EMIT_NATIVE - if (self->code_state.exc_sp == NULL) { + if (self->code_state.exc_sp_idx == MP_CODE_STATE_EXC_SP_IDX_SENTINEL) { // A native generator, with entry point 2 words into the "bytecode" pointer typedef uintptr_t (*mp_fun_native_gen_t)(void*, mp_obj_t); mp_fun_native_gen_t fun = MICROPY_MAKE_POINTER_CALLABLE((const void*)(self->code_state.fun_bc->bytecode + 2 * sizeof(uintptr_t))); diff --git a/py/vm.c b/py/vm.c index 16b1348b40..c0cd9ffbf8 100644 --- a/py/vm.c +++ b/py/vm.c @@ -234,7 +234,7 @@ FRAME_SETUP(); } // variables that are visible to the exception handler (declared volatile) - mp_exc_stack_t *volatile exc_sp = MP_TAGPTR_PTR(code_state->exc_sp); // stack grows up, exc_sp points to top of stack + mp_exc_stack_t *volatile exc_sp = MP_CODE_STATE_EXC_SP_IDX_TO_PTR(exc_stack, code_state->exc_sp_idx); // stack grows up, exc_sp points to top of stack #if MICROPY_PY_THREAD_GIL && MICROPY_PY_THREAD_GIL_VM_DIVISOR // This needs to be volatile and outside the VM loop so it persists across handling @@ -953,7 +953,7 @@ unwind_jump:; if (mp_obj_get_type(*sp) == &mp_type_fun_bc) { code_state->ip = ip; code_state->sp = sp; - code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, 0); + code_state->exc_sp_idx = MP_CODE_STATE_EXC_SP_IDX_FROM_PTR(exc_stack, exc_sp); mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1); #if !MICROPY_ENABLE_PYSTACK if (new_state == NULL) { @@ -990,7 +990,7 @@ unwind_jump:; if (mp_obj_get_type(*sp) == &mp_type_fun_bc) { code_state->ip = ip; code_state->sp = sp; - code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, 0); + code_state->exc_sp_idx = MP_CODE_STATE_EXC_SP_IDX_FROM_PTR(exc_stack, exc_sp); mp_call_args_t out_args; mp_call_prepare_args_n_kw_var(false, unum, sp, &out_args); @@ -1034,7 +1034,7 @@ unwind_jump:; if (mp_obj_get_type(*sp) == &mp_type_fun_bc) { code_state->ip = ip; code_state->sp = sp; - code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, 0); + code_state->exc_sp_idx = MP_CODE_STATE_EXC_SP_IDX_FROM_PTR(exc_stack, exc_sp); size_t n_args = unum & 0xff; size_t n_kw = (unum >> 8) & 0xff; @@ -1075,7 +1075,7 @@ unwind_jump:; if (mp_obj_get_type(*sp) == &mp_type_fun_bc) { code_state->ip = ip; code_state->sp = sp; - code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, 0); + code_state->exc_sp_idx = MP_CODE_STATE_EXC_SP_IDX_FROM_PTR(exc_stack, exc_sp); mp_call_args_t out_args; mp_call_prepare_args_n_kw_var(true, unum, sp, &out_args); @@ -1197,7 +1197,7 @@ yield: nlr_pop(); code_state->ip = ip; code_state->sp = sp; - code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, 0); + code_state->exc_sp_idx = MP_CODE_STATE_EXC_SP_IDX_FROM_PTR(exc_stack, exc_sp); FRAME_LEAVE(); return MP_VM_RETURN_YIELD; @@ -1503,7 +1503,7 @@ unwind_loop: fastn = &code_state->state[n_state - 1]; exc_stack = (mp_exc_stack_t*)(code_state->state + n_state); // variables that are visible to the exception handler (declared volatile) - exc_sp = MP_TAGPTR_PTR(code_state->exc_sp); // stack grows up, exc_sp points to top of stack + exc_sp = MP_CODE_STATE_EXC_SP_IDX_TO_PTR(exc_stack, code_state->exc_sp_idx); // stack grows up, exc_sp points to top of stack goto unwind_loop; #endif From 81d04a0200e0d4038c011e4946bfae5707ef9d9c Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 24 Sep 2019 15:57:08 +1000 Subject: [PATCH 0773/1788] py: Add n_state to mp_code_state_t struct. This value is used often enough that it is better to cache it instead of decode it each time. --- py/bc.h | 1 + py/emitnative.c | 3 +++ py/objfun.c | 7 ++++--- py/objgenerator.c | 2 ++ py/vm.c | 4 ++-- 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/py/bc.h b/py/bc.h index 1d28dcc4f9..69bce89028 100644 --- a/py/bc.h +++ b/py/bc.h @@ -99,6 +99,7 @@ typedef struct _mp_code_state_t { mp_obj_fun_bc_t *fun_bc; const byte *ip; mp_obj_t *sp; + uint16_t n_state; uint16_t exc_sp_idx; mp_obj_dict_t *old_globals; #if MICROPY_STACKLESS diff --git a/py/emitnative.c b/py/emitnative.c index 760c7fb0c1..f5a18c987a 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -521,6 +521,9 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop // TODO this encoding may change size in the final pass, need to make it fixed emit_native_mov_state_imm_via(emit, emit->code_state_start + OFFSETOF_CODE_STATE_IP, emit->prelude_offset, REG_ARG_1); + // Set code_state.n_state (only works on little endian targets due to n_state being uint16_t) + emit_native_mov_state_imm_via(emit, emit->code_state_start + offsetof(mp_code_state_t, n_state) / sizeof(uintptr_t), emit->n_state, REG_ARG_1); + // Put address of code_state into first arg ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, emit->code_state_start); diff --git a/py/objfun.c b/py/objfun.c index e0c6fb9271..114367b4e0 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -206,9 +206,10 @@ STATIC void dump_args(const mp_obj_t *a, size_t sz) { + n_exc_stack * sizeof(mp_exc_stack_t); \ } -#define INIT_CODESTATE(code_state, _fun_bc, n_args, n_kw, args) \ +#define INIT_CODESTATE(code_state, _fun_bc, _n_state, n_args, n_kw, args) \ code_state->fun_bc = _fun_bc; \ code_state->ip = 0; \ + code_state->n_state = _n_state; \ mp_setup_code_state(code_state, n_args, n_kw, args); \ code_state->old_globals = mp_globals_get(); @@ -235,7 +236,7 @@ mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, size_t n_args } #endif - INIT_CODESTATE(code_state, self, n_args, n_kw, args); + INIT_CODESTATE(code_state, self, n_state, n_args, n_kw, args); // execute the byte code with the correct globals context mp_globals_set(self->globals); @@ -280,7 +281,7 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const } #endif - INIT_CODESTATE(code_state, self, n_args, n_kw, args); + INIT_CODESTATE(code_state, self, n_state, n_args, n_kw, args); // execute the byte code with the correct globals context mp_globals_set(self->globals); diff --git a/py/objgenerator.c b/py/objgenerator.c index d32a74f3fb..39dcbefb92 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -62,6 +62,7 @@ STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_kw, cons o->globals = self_fun->globals; o->code_state.fun_bc = self_fun; o->code_state.ip = 0; + o->code_state.n_state = n_state; mp_setup_code_state(&o->code_state, n_args, n_kw, args); return MP_OBJ_FROM_PTR(o); } @@ -99,6 +100,7 @@ STATIC mp_obj_t native_gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_k o->globals = self_fun->globals; o->code_state.fun_bc = self_fun; o->code_state.ip = (const byte*)prelude_offset; + o->code_state.n_state = n_state; mp_setup_code_state(&o->code_state, n_args, n_kw, args); // Indicate we are a native function, which doesn't use this variable diff --git a/py/vm.c b/py/vm.c index c0cd9ffbf8..d59771b6e8 100644 --- a/py/vm.c +++ b/py/vm.c @@ -228,7 +228,7 @@ FRAME_SETUP(); mp_obj_t * /*const*/ fastn; mp_exc_stack_t * /*const*/ exc_stack; { - size_t n_state = mp_decode_uint_value(code_state->fun_bc->bytecode); + size_t n_state = code_state->n_state; fastn = &code_state->state[n_state - 1]; exc_stack = (mp_exc_stack_t*)(code_state->state + n_state); } @@ -1499,7 +1499,7 @@ unwind_loop: 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); + size_t n_state = code_state->n_state; fastn = &code_state->state[n_state - 1]; exc_stack = (mp_exc_stack_t*)(code_state->state + n_state); // variables that are visible to the exception handler (declared volatile) From b5ebfadbd615de42c43851f27a062bacd9147996 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 16 Sep 2019 22:12:59 +1000 Subject: [PATCH 0774/1788] py: Compress first part of bytecode prelude. The start of the bytecode prelude contains 6 numbers telling the amount of stack needed for the Python values and exceptions, and the signature of the function. Prior to this patch these numbers were all encoded one after the other (2x variable unsigned integers, then 4x bytes), but using so many bytes is unnecessary. An entropy analysis of around 150,000 bytecode functions from the CPython standard library showed that the optimal Shannon coding would need about 7.1 bits on average to encode these 6 numbers, compared to the existing 48 bits. This patch attempts to get close to this optimal value by packing the 6 numbers into a single, varible-length unsigned integer via bit-wise interleaving. The interleaving scheme is chosen to minimise the average number of bytes needed, and at the same time keep the scheme simple enough so it can be implemented without too much overhead in code size or speed. The scheme requires about 10.5 bits on average to store the 6 numbers. As a result most functions which originally took 6 bytes to encode these 6 numbers now need only 1 byte (in 80% of cases). --- py/bc.c | 15 ++++--- py/bc.h | 74 +++++++++++++++++++++++++++++--- py/emitbc.c | 14 ++---- py/emitnative.c | 15 ++++--- py/objfun.c | 23 +++++----- py/objgenerator.c | 8 ++-- py/persistentcode.c | 41 ++++++++---------- py/profile.c | 13 +++--- py/runtime0.h | 4 +- py/showbc.c | 13 ++---- py/vm.c | 7 +-- tests/cmdline/cmd_verbose.py.exp | 2 +- tests/import/mpy_native.py | 4 +- tools/mpy-tool.py | 44 +++++++++++++------ 14 files changed, 171 insertions(+), 106 deletions(-) diff --git a/py/bc.c b/py/bc.c index c32d5c415e..7544ffc5f2 100644 --- a/py/bc.c +++ b/py/bc.c @@ -124,13 +124,14 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw code_state->frame = NULL; #endif - // get params - size_t n_state = mp_decode_uint(&code_state->ip); - code_state->ip = mp_decode_uint_skip(code_state->ip); // skip n_exc_stack - size_t scope_flags = *code_state->ip++; - size_t n_pos_args = *code_state->ip++; - size_t n_kwonly_args = *code_state->ip++; - size_t n_def_pos_args = *code_state->ip++; + // Get cached n_state (rather than decode it again) + size_t n_state = code_state->n_state; + + // Decode prelude + size_t n_state_unused, n_exc_stack_unused, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args; + MP_BC_PRELUDE_SIG_DECODE_INTO(code_state->ip, n_state_unused, n_exc_stack_unused, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args); + (void)n_state_unused; + (void)n_exc_stack_unused; code_state->sp = &code_state->state[0] - 1; code_state->exc_sp_idx = 0; diff --git a/py/bc.h b/py/bc.h index 69bce89028..1ae8c99258 100644 --- a/py/bc.h +++ b/py/bc.h @@ -32,12 +32,15 @@ // bytecode layout: // -// n_state : var uint -// n_exc_stack : var uint -// scope_flags : byte -// n_pos_args : byte number of arguments this function takes -// n_kwonly_args : byte number of keyword-only arguments this function takes -// n_def_pos_args : byte number of default positional arguments +// func signature : var uint +// contains six values interleaved bit-wise as: xSSSSEAA [xFSSKAED repeated] +// x = extension another byte follows +// S = n_state - 1 number of entries in Python value stack +// E = n_exc_stack number of entries in exception stack +// F = scope_flags four bits of flags, MP_SCOPE_FLAG_xxx +// A = n_pos_args number of arguments this function takes +// K = n_kwonly_args number of keyword-only arguments this function takes +// D = n_def_pos_args number of default positional arguments // // code_info_size : var uint | code_info_size counts bytes in this chunk // simple_name : var qstr | @@ -60,6 +63,65 @@ // const0 : obj // constN : obj +#define MP_BC_PRELUDE_SIG_ENCODE(S, E, scope, out_byte, out_env) \ +do { \ + /*// Get values to store in prelude */ \ + size_t F = scope->scope_flags & 0x0f; /* only need to store lower 4 flag bits */ \ + size_t A = scope->num_pos_args; \ + size_t K = scope->num_kwonly_args; \ + size_t D = scope->num_def_pos_args; \ + \ + /* Adjust S to shrink range, to compress better */ \ + S -= 1; \ + \ + /* Encode prelude */ \ + /* xSSSSEAA */ \ + uint8_t z = (S & 0xf) << 3 | (E & 1) << 2 | (A & 3); \ + S >>= 4; \ + E >>= 1; \ + A >>= 2; \ + while (S | E | F | A | K | D) { \ + out_byte(out_env, 0x80 | z); \ + /* xFSSKAED */ \ + z = (F & 1) << 6 | (S & 3) << 4 | (K & 1) << 3 \ + | (A & 1) << 2 | (E & 1) << 1 | (D & 1); \ + S >>= 2; \ + E >>= 1; \ + F >>= 1; \ + A >>= 1; \ + K >>= 1; \ + D >>= 1; \ + } \ + out_byte(out_env, z); \ +} while (0) + +#define MP_BC_PRELUDE_SIG_DECODE_INTO(ip, S, E, F, A, K, D) \ +do { \ + uint8_t z = *(ip)++; \ + /* xSSSSEAA */ \ + S = (z >> 3) & 0xf; \ + E = (z >> 2) & 0x1; \ + F = 0; \ + A = z & 0x3; \ + K = 0; \ + D = 0; \ + for (unsigned n = 0; z & 0x80; ++n) { \ + z = *(ip)++; \ + /* xFSSKAED */ \ + S |= (z & 0x30) << (2 * n); \ + E |= (z & 0x02) << n; \ + F |= ((z & 0x40) >> 6) << n; \ + A |= (z & 0x4) << n; \ + K |= ((z & 0x08) >> 3) << n; \ + D |= (z & 0x1) << n; \ + } \ + S += 1; \ +} while (0) + +#define MP_BC_PRELUDE_SIG_DECODE(ip) \ + size_t n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args; \ + MP_BC_PRELUDE_SIG_DECODE_INTO(ip, n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args) + // Sentinel value for mp_code_state_t.exc_sp_idx #define MP_CODE_STATE_EXC_SP_IDX_SENTINEL ((uint16_t)-1) diff --git a/py/emitbc.c b/py/emitbc.c index a8d57d27b0..1aa219ca88 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -328,7 +328,7 @@ void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) { emit->bytecode_offset = 0; emit->code_info_offset = 0; - // Write local state size and exception stack size. + // Write local state size, exception stack size, scope flags and number of arguments { mp_uint_t n_state = scope->num_locals + scope->stack_size; if (n_state == 0) { @@ -341,16 +341,10 @@ void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) { // An extra slot in the stack is needed to detect VM stack overflow n_state += 1; #endif - emit_write_code_info_uint(emit, n_state); - emit_write_code_info_uint(emit, scope->exc_stack_size); - } - // Write scope flags and number of arguments. - // TODO check that num args all fit in a byte - emit_write_code_info_byte(emit, emit->scope->scope_flags); - emit_write_code_info_byte(emit, emit->scope->num_pos_args); - emit_write_code_info_byte(emit, emit->scope->num_kwonly_args); - emit_write_code_info_byte(emit, emit->scope->num_def_pos_args); + size_t n_exc_stack = scope->exc_stack_size; + MP_BC_PRELUDE_SIG_ENCODE(n_state, n_exc_stack, scope, emit_write_code_info_byte, emit); + } // Write size of the rest of the code info. We don't know how big this // variable uint will be on the MP_PASS_CODE_SIZE pass so we reserve 2 bytes diff --git a/py/emitnative.c b/py/emitnative.c index f5a18c987a..d0e758f56c 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -573,18 +573,19 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop } +static inline void emit_native_write_code_info_byte(emit_t *emit, byte val) { + mp_asm_base_data(&emit->as->base, 1, val); +} + STATIC void emit_native_end_pass(emit_t *emit) { emit_native_global_exc_exit(emit); if (!emit->do_viper_types) { emit->prelude_offset = mp_asm_base_get_code_pos(&emit->as->base); - mp_asm_base_data(&emit->as->base, 1, 0x80 | ((emit->n_state >> 7) & 0x7f)); - mp_asm_base_data(&emit->as->base, 1, emit->n_state & 0x7f); - mp_asm_base_data(&emit->as->base, 1, 0); // n_exc_stack - mp_asm_base_data(&emit->as->base, 1, emit->scope->scope_flags); - mp_asm_base_data(&emit->as->base, 1, emit->scope->num_pos_args); - mp_asm_base_data(&emit->as->base, 1, emit->scope->num_kwonly_args); - mp_asm_base_data(&emit->as->base, 1, emit->scope->num_def_pos_args); + + size_t n_state = emit->n_state; + size_t n_exc_stack = 0; // exc-stack not needed for native code + MP_BC_PRELUDE_SIG_ENCODE(n_state, n_exc_stack, emit->scope, emit_native_write_code_info_byte, emit); // write code info #if MICROPY_PERSISTENT_CODE diff --git a/py/objfun.c b/py/objfun.c index 114367b4e0..053fe46b78 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -161,12 +161,7 @@ qstr mp_obj_fun_get_name(mp_const_obj_t fun_in) { #endif const byte *bc = fun->bytecode; - bc = mp_decode_uint_skip(bc); // skip n_state - bc = mp_decode_uint_skip(bc); // skip n_exc_stack - bc++; // skip scope_params - bc++; // skip n_pos_args - bc++; // skip n_kwonly_args - bc++; // skip n_def_pos_args + MP_BC_PRELUDE_SIG_DECODE(bc); return mp_obj_code_get_name(bc); } @@ -197,10 +192,10 @@ STATIC void dump_args(const mp_obj_t *a, size_t sz) { #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)); \ - \ + const uint8_t *ip = bytecode; \ + size_t n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_args; \ + MP_BC_PRELUDE_SIG_DECODE_INTO(ip, n_state_out_var, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_args); \ + \ /* state size in bytes */ \ state_size_out_var = n_state_out_var * sizeof(mp_obj_t) \ + n_exc_stack * sizeof(mp_exc_stack_t); \ @@ -295,9 +290,11 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const assert(0); } } - const byte *bytecode_ptr = mp_decode_uint_skip(mp_decode_uint_skip(self->bytecode)); - size_t n_pos_args = bytecode_ptr[1]; - size_t n_kwonly_args = bytecode_ptr[2]; + const byte *bytecode_ptr = self->bytecode; + size_t n_state_unused, n_exc_stack_unused, scope_flags_unused; + size_t n_pos_args, n_kwonly_args, n_def_args_unused; + MP_BC_PRELUDE_SIG_DECODE_INTO(bytecode_ptr, n_state_unused, n_exc_stack_unused, + scope_flags_unused, n_pos_args, n_kwonly_args, n_def_args_unused); // We can't check the case when an exception is returned in state[0] // and there are no arguments, because in this case our detection slot may have // been overwritten by the returned exception (which is allowed). diff --git a/py/objgenerator.c b/py/objgenerator.c index 39dcbefb92..359dade888 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -51,8 +51,8 @@ STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_kw, cons mp_obj_fun_bc_t *self_fun = MP_OBJ_TO_PTR(self_in); // bytecode prelude: get state size and exception stack size - size_t n_state = mp_decode_uint_value(self_fun->bytecode); - size_t n_exc_stack = mp_decode_uint_value(mp_decode_uint_skip(self_fun->bytecode)); + const uint8_t *ip = self_fun->bytecode; + MP_BC_PRELUDE_SIG_DECODE(ip); // allocate the generator object, with room for local stack and exception stack mp_obj_gen_instance_t *o = m_new_obj_var(mp_obj_gen_instance_t, byte, @@ -88,7 +88,9 @@ STATIC mp_obj_t native_gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_k // Determine start of prelude, and extract n_state from it uintptr_t prelude_offset = ((uintptr_t*)self_fun->bytecode)[0]; - size_t n_state = mp_decode_uint_value(self_fun->bytecode + prelude_offset); + const uint8_t *ip = self_fun->bytecode + prelude_offset; + size_t n_state, n_exc_stack_unused, scope_flags, n_pos_args, n_kwonly_args, n_def_args; + MP_BC_PRELUDE_SIG_DECODE_INTO(ip, n_state, n_exc_stack_unused, scope_flags, n_pos_args, n_kwonly_args, n_def_args); size_t n_exc_stack = 0; // Allocate the generator object, with room for local stack and exception stack diff --git a/py/persistentcode.c b/py/persistentcode.c index 3b59746ba7..9776acb1e1 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -157,17 +157,16 @@ typedef struct _bytecode_prelude_t { uint code_info_size; } bytecode_prelude_t; -#if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_EMIT_MACHINE_CODE - // ip will point to start of opcodes // ip2 will point to simple_name, source_file qstrs STATIC void extract_prelude(const byte **ip, const byte **ip2, bytecode_prelude_t *prelude) { - prelude->n_state = mp_decode_uint(ip); - prelude->n_exc_stack = mp_decode_uint(ip); - prelude->scope_flags = *(*ip)++; - prelude->n_pos_args = *(*ip)++; - prelude->n_kwonly_args = *(*ip)++; - prelude->n_def_pos_args = *(*ip)++; + MP_BC_PRELUDE_SIG_DECODE(*ip); + prelude->n_state = n_state; + prelude->n_exc_stack = n_exc_stack; + prelude->scope_flags = scope_flags; + prelude->n_pos_args = n_pos_args; + prelude->n_kwonly_args = n_kwonly_args; + prelude->n_def_pos_args = n_def_pos_args; *ip2 = *ip; prelude->code_info_size = mp_decode_uint(ip2); *ip += prelude->code_info_size; @@ -175,8 +174,6 @@ STATIC void extract_prelude(const byte **ip, const byte **ip2, bytecode_prelude_ } } -#endif - #endif // MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE #if MICROPY_PERSISTENT_CODE_LOAD @@ -285,19 +282,19 @@ STATIC mp_obj_t load_obj(mp_reader_t *reader) { } STATIC void load_prelude(mp_reader_t *reader, byte **ip, byte **ip2, bytecode_prelude_t *prelude) { - prelude->n_state = read_uint(reader, ip); - prelude->n_exc_stack = read_uint(reader, ip); - read_bytes(reader, *ip, 4); - prelude->scope_flags = *(*ip)++; - prelude->n_pos_args = *(*ip)++; - prelude->n_kwonly_args = *(*ip)++; - prelude->n_def_pos_args = *(*ip)++; - *ip2 = *ip; - prelude->code_info_size = read_uint(reader, ip2); - read_bytes(reader, *ip2, prelude->code_info_size - (*ip2 - *ip)); - *ip += prelude->code_info_size; - while ((*(*ip)++ = read_byte(reader)) != 255) { + // Read in the prelude + byte *ip_read = *ip; + read_uint(reader, &ip_read); // read in n_state/etc (is effectively a var-uint) + byte *ip_read_save = ip_read; + size_t code_info_size = read_uint(reader, &ip_read); // read in code_info_size + code_info_size -= ip_read - ip_read_save; // subtract bytes taken by code_info_size itself + read_bytes(reader, ip_read, code_info_size); // read remaining code info + ip_read += code_info_size; + while ((*ip_read++ = read_byte(reader)) != 255) { } + + // Entire prelude has been read into *ip, now decode and extract values from it + extract_prelude((const byte**)ip, (const byte**)ip2, prelude); } STATIC void load_bytecode(mp_reader_t *reader, qstr_window_t *qw, byte *ip, byte *ip_top) { diff --git a/py/profile.c b/py/profile.c index 8c4feaa11c..230bb7cc24 100644 --- a/py/profile.c +++ b/py/profile.c @@ -40,12 +40,13 @@ STATIC uint mp_prof_bytecode_lineno(const mp_raw_code_t *rc, size_t bc) { void mp_prof_extract_prelude(const byte *bytecode, mp_bytecode_prelude_t *prelude) { const byte *ip = bytecode; - prelude->n_state = mp_decode_uint(&ip); - prelude->n_exc_stack = mp_decode_uint(&ip); - prelude->scope_flags = *ip++; - prelude->n_pos_args = *ip++; - prelude->n_kwonly_args = *ip++; - prelude->n_def_pos_args = *ip++; + MP_BC_PRELUDE_SIG_DECODE(ip); + prelude->n_state = n_state; + prelude->n_exc_stack = n_exc_stack; + prelude->scope_flags = scope_flags; + prelude->n_pos_args = n_pos_args; + prelude->n_kwonly_args = n_kwonly_args; + prelude->n_def_pos_args = n_def_pos_args; const byte *code_info = ip; size_t code_info_size = mp_decode_uint(&ip); diff --git a/py/runtime0.h b/py/runtime0.h index fd284d47b3..1df6d0d583 100644 --- a/py/runtime0.h +++ b/py/runtime0.h @@ -28,9 +28,9 @@ // The first four must fit in 8 bits, see emitbc.c // The remaining must fit in 16 bits, see scope.h -#define MP_SCOPE_FLAG_VARARGS (0x01) +#define MP_SCOPE_FLAG_GENERATOR (0x01) #define MP_SCOPE_FLAG_VARKEYWORDS (0x02) -#define MP_SCOPE_FLAG_GENERATOR (0x04) +#define MP_SCOPE_FLAG_VARARGS (0x04) #define MP_SCOPE_FLAG_DEFKWARGS (0x08) #define MP_SCOPE_FLAG_REFGLOBALS (0x10) // used only if native emitter enabled #define MP_SCOPE_FLAG_HASCONSTS (0x20) // used only if native emitter enabled diff --git a/py/showbc.c b/py/showbc.c index 78b5b0141a..216f352664 100644 --- a/py/showbc.c +++ b/py/showbc.c @@ -83,13 +83,8 @@ const mp_uint_t *mp_showbc_const_table; void mp_bytecode_print(const void *descr, const byte *ip, mp_uint_t len, const mp_uint_t *const_table) { mp_showbc_code_start = ip; - // get bytecode parameters - mp_uint_t n_state = mp_decode_uint(&ip); - mp_uint_t n_exc_stack = mp_decode_uint(&ip); - /*mp_uint_t scope_flags =*/ ip++; - mp_uint_t n_pos_args = *ip++; - mp_uint_t n_kwonly_args = *ip++; - /*mp_uint_t n_def_pos_args =*/ ip++; + // Decode prelude + MP_BC_PRELUDE_SIG_DECODE(ip); const byte *code_info = ip; mp_uint_t code_info_size = mp_decode_uint(&code_info); @@ -123,8 +118,8 @@ void mp_bytecode_print(const void *descr, const byte *ip, mp_uint_t len, const m } printf("\n"); - printf("(N_STATE " UINT_FMT ")\n", n_state); - printf("(N_EXC_STACK " UINT_FMT ")\n", n_exc_stack); + printf("(N_STATE %u)\n", (unsigned)n_state); + printf("(N_EXC_STACK %u)\n", (unsigned)n_exc_stack); // for printing line number info const byte *bytecode_start = ip; diff --git a/py/vm.c b/py/vm.c index d59771b6e8..82218fd971 100644 --- a/py/vm.c +++ b/py/vm.c @@ -1440,12 +1440,7 @@ unwind_loop: && *code_state->ip != MP_BC_END_FINALLY && *code_state->ip != MP_BC_RAISE_LAST) { 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 - ip++; // skip scope_params - ip++; // skip n_pos_args - ip++; // skip n_kwonly_args - ip++; // skip n_def_pos_args + MP_BC_PRELUDE_SIG_DECODE(ip); size_t bc = code_state->ip - ip; size_t code_info_size = mp_decode_uint_value(ip); ip = mp_decode_uint_skip(ip); // skip code_info_size diff --git a/tests/cmdline/cmd_verbose.py.exp b/tests/cmdline/cmd_verbose.py.exp index 371c8c4b53..60b499c264 100644 --- a/tests/cmdline/cmd_verbose.py.exp +++ b/tests/cmdline/cmd_verbose.py.exp @@ -1,6 +1,6 @@ File cmdline/cmd_verbose.py, code block '' (descriptor: \.\+, bytecode \.\+ bytes) Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): - 02 \.\+ + 08 \.\+ ######## \.\+63 arg names: diff --git a/tests/import/mpy_native.py b/tests/import/mpy_native.py index 25fceb9bb6..03abab349e 100644 --- a/tests/import/mpy_native.py +++ b/tests/import/mpy_native.py @@ -56,8 +56,8 @@ user_files = { '/mod1.mpy': ( b'M\x05\x0b\x1f\x20' # header - b'\x38' # n bytes, bytecode - b'\x01\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\xff' # prelude + b'\x24' # n bytes, bytecode + b'\x00\x05\x00\x00\x00\x00\xff' # prelude b'\x51' # LOAD_CONST_NONE b'\x63' # RETURN_VALUE diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index 4f8e965d79..8671a2395d 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -152,13 +152,38 @@ def decode_uint(bytecode, ip): break return ip, unum +def read_prelude_sig(read_byte): + z = read_byte() + # xSSSSEAA + S = (z >> 3) & 0xf + E = (z >> 2) & 0x1 + F = 0 + A = z & 0x3 + K = 0 + D = 0 + n = 0 + while z & 0x80: + z = read_byte() + # xFSSKAED + S |= (z & 0x30) << (2 * n) + E |= (z & 0x02) << n + F |= ((z & 0x40) >> 6) << n + A |= (z & 0x4) << n + K |= ((z & 0x08) >> 3) << n + D |= (z & 0x1) << n + n += 1 + S += 1 + return S, E, F, A, K, D + def extract_prelude(bytecode, ip): - ip, n_state = decode_uint(bytecode, ip) - ip, n_exc_stack = decode_uint(bytecode, ip) - scope_flags = bytecode[ip]; ip += 1 - n_pos_args = bytecode[ip]; ip += 1 - n_kwonly_args = bytecode[ip]; ip += 1 - n_def_pos_args = bytecode[ip]; ip += 1 + def local_read_byte(): + b = bytecode[ip_ref[0]] + ip_ref[0] += 1 + return b + ip_ref = [ip] # to close over ip in Python 2 and 3 + n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args = read_prelude_sig(local_read_byte) + ip = ip_ref[0] + ip2, code_info_size = decode_uint(bytecode, ip) ip += code_info_size while bytecode[ip] != 0xff: @@ -557,12 +582,7 @@ def read_obj(f): assert 0 def read_prelude(f, bytecode): - n_state = read_uint(f, bytecode) - n_exc_stack = read_uint(f, bytecode) - scope_flags = read_byte(f, bytecode) - n_pos_args = read_byte(f, bytecode) - n_kwonly_args = read_byte(f, bytecode) - n_def_pos_args = read_byte(f, bytecode) + n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args = read_prelude_sig(lambda: read_byte(f, bytecode)) l1 = bytecode.idx code_info_size = read_uint(f, bytecode) l2 = bytecode.idx From c8c0fd4ca39fbdcf9ca5f2fc99ca4d6b81a28b65 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 25 Sep 2019 15:45:47 +1000 Subject: [PATCH 0775/1788] py: Rework and compress second part of bytecode prelude. This patch compresses the second part of the bytecode prelude which contains the source file name, function name, source-line-number mapping and cell closure information. This part of the prelude now begins with a single varible length unsigned integer which encodes 2 numbers, being the byte-size of the following 2 sections in the header: the "source info section" and the "closure section". After decoding this variable unsigned integer it's possible to skip over one or both of these sections very easily. This scheme saves about 2 bytes for most functions compared to the original format: one in the case that there are no closure cells, and one because padding was eliminated. --- py/bc.c | 14 +++++-- py/bc.h | 64 +++++++++++++++++++++++++----- py/emitbc.c | 43 ++++++++++---------- py/emitnative.c | 15 +++++-- py/objfun.c | 2 +- py/persistentcode.c | 16 +++----- py/profile.c | 17 +++----- py/showbc.c | 25 +++++------- py/vm.c | 11 +++-- tests/cmdline/cmd_parsetree.py.exp | 2 +- tests/cmdline/cmd_showbc.py.exp | 22 +++++----- tests/cmdline/cmd_verbose.py.exp | 2 +- tests/import/mpy_native.py | 4 +- tools/mpy-tool.py | 44 ++++++++++---------- 14 files changed, 162 insertions(+), 119 deletions(-) diff --git a/py/bc.c b/py/bc.c index 7544ffc5f2..d671b64f92 100644 --- a/py/bc.c +++ b/py/bc.c @@ -269,19 +269,25 @@ continue2:; } } - // get the ip and skip argument names + // read the size part of the prelude const byte *ip = code_state->ip; + MP_BC_PRELUDE_SIZE_DECODE(ip); // jump over code info (source file and line-number mapping) - ip += mp_decode_uint_value(ip); + ip += n_info; // bytecode prelude: initialise closed over variables - size_t local_num; - while ((local_num = *ip++) != 255) { + for (; n_cell; --n_cell) { + size_t local_num = *ip++; code_state->state[n_state - 1 - local_num] = mp_obj_new_cell(code_state->state[n_state - 1 - local_num]); } + #if !MICROPY_PERSISTENT_CODE + // so bytecode is aligned + ip = MP_ALIGN(ip, sizeof(mp_uint_t)); + #endif + // now that we skipped over the prelude, set the ip for the VM code_state->ip = ip; diff --git a/py/bc.h b/py/bc.h index 1ae8c99258..fd52571fda 100644 --- a/py/bc.h +++ b/py/bc.h @@ -42,17 +42,25 @@ // K = n_kwonly_args number of keyword-only arguments this function takes // D = n_def_pos_args number of default positional arguments // -// code_info_size : var uint | code_info_size counts bytes in this chunk -// simple_name : var qstr | -// source_file : var qstr | -// | -// | only needed if bytecode contains pointers +// prelude size : var uint +// contains two values interleaved bit-wise as: xIIIIIIC repeated +// x = extension another byte follows +// I = n_info number of bytes in source info section +// C = n_cells number of bytes/cells in closure section // -// local_num0 : byte | -// ... : byte | -// local_numN : byte | N = num_cells -// 255 : byte | end of list sentinel -// | +// source info section: +// simple_name : var qstr +// source_file : var qstr +// +// +// closure section: +// local_num0 : byte +// ... : byte +// local_numN : byte N = n_cells-1 +// +// only needed if bytecode contains pointers +// +// // // // constant table layout: @@ -122,6 +130,41 @@ do { \ size_t n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args; \ MP_BC_PRELUDE_SIG_DECODE_INTO(ip, n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args) +#define MP_BC_PRELUDE_SIZE_ENCODE(I, C, out_byte, out_env) \ +do { \ + /* Encode bit-wise as: xIIIIIIC */ \ + uint8_t z = 0; \ + do { \ + z = (I & 0x3f) << 1 | (C & 1); \ + C >>= 1; \ + I >>= 6; \ + if (C | I) { \ + z |= 0x80; \ + } \ + out_byte(out_env, z); \ + } while (C | I); \ +} while (0) + +#define MP_BC_PRELUDE_SIZE_DECODE_INTO(ip, I, C) \ +do { \ + uint8_t z; \ + C = 0; \ + I = 0; \ + for (unsigned n = 0;; ++n) { \ + z = *(ip)++; \ + /* xIIIIIIC */ \ + C |= (z & 1) << n; \ + I |= ((z & 0x7e) >> 1) << (6 * n); \ + if (!(z & 0x80)) { \ + break; \ + } \ + } \ +} while (0) + +#define MP_BC_PRELUDE_SIZE_DECODE(ip) \ + size_t n_info, n_cell; \ + MP_BC_PRELUDE_SIZE_DECODE_INTO(ip, n_info, n_cell) + // Sentinel value for mp_code_state_t.exc_sp_idx #define MP_CODE_STATE_EXC_SP_IDX_SENTINEL ((uint16_t)-1) @@ -139,7 +182,6 @@ typedef struct _mp_bytecode_prelude_t { qstr qstr_block_name; qstr qstr_source_file; const byte *line_info; - const byte *locals; const byte *opcodes; } mp_bytecode_prelude_t; diff --git a/py/emitbc.c b/py/emitbc.c index 1aa219ca88..34f6362ff0 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -64,6 +64,9 @@ struct _emit_t { size_t bytecode_size; byte *code_base; // stores both byte code and code info + size_t n_info; + size_t n_cell; + #if MICROPY_PERSISTENT_CODE uint16_t ct_cur_obj; uint16_t ct_num_obj; @@ -123,10 +126,6 @@ STATIC void emit_write_code_info_byte(emit_t* emit, byte val) { *emit_get_cur_to_write_code_info(emit, 1) = val; } -STATIC void emit_write_code_info_uint(emit_t* emit, mp_uint_t val) { - emit_write_uint(emit, emit_get_cur_to_write_code_info, val); -} - STATIC void emit_write_code_info_qstr(emit_t *emit, qstr qst) { #if MICROPY_PERSISTENT_CODE assert((qst >> 16) == 0); @@ -346,29 +345,17 @@ void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) { MP_BC_PRELUDE_SIG_ENCODE(n_state, n_exc_stack, scope, emit_write_code_info_byte, emit); } - // Write size of the rest of the code info. We don't know how big this - // variable uint will be on the MP_PASS_CODE_SIZE pass so we reserve 2 bytes - // for it and hope that is enough! TODO assert this or something. - if (pass == MP_PASS_EMIT) { - emit_write_code_info_uint(emit, emit->code_info_size - emit->code_info_offset); - } else { - emit_get_cur_to_write_code_info(emit, 2); + // Write number of cells and size of the source code info + if (pass >= MP_PASS_CODE_SIZE) { + MP_BC_PRELUDE_SIZE_ENCODE(emit->n_info, emit->n_cell, emit_write_code_info_byte, emit); } + emit->n_info = emit->code_info_offset; + // Write the name and source file of this function. emit_write_code_info_qstr(emit, scope->simple_name); emit_write_code_info_qstr(emit, scope->source_file); - // bytecode prelude: initialise closed over variables - for (int i = 0; i < scope->id_info_len; i++) { - id_info_t *id = &scope->id_info[i]; - if (id->kind == ID_INFO_KIND_CELL) { - assert(id->local_num < 255); - emit_write_bytecode_raw_byte(emit, id->local_num); // write the local which should be converted to a cell - } - } - emit_write_bytecode_raw_byte(emit, 255); // end of list sentinel - #if MICROPY_PERSISTENT_CODE emit->ct_cur_obj = 0; emit->ct_cur_raw_code = 0; @@ -414,6 +401,20 @@ void mp_emit_bc_end_pass(emit_t *emit) { emit_write_code_info_byte(emit, 0); // end of line number info + // Calculate size of source code info section + emit->n_info = emit->code_info_offset - emit->n_info; + + // Emit closure section of prelude + emit->n_cell = 0; + for (size_t i = 0; i < emit->scope->id_info_len; ++i) { + id_info_t *id = &emit->scope->id_info[i]; + if (id->kind == ID_INFO_KIND_CELL) { + assert(id->local_num <= 255); + emit_write_code_info_byte(emit, id->local_num); // write the local which should be converted to a cell + ++emit->n_cell; + } + } + #if MICROPY_PERSISTENT_CODE assert(emit->pass <= MP_PASS_STACK_SIZE || (emit->ct_num_obj == emit->ct_cur_obj)); emit->ct_num_obj = emit->ct_cur_obj; diff --git a/py/emitnative.c b/py/emitnative.c index d0e758f56c..2c976606c7 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -208,6 +208,7 @@ struct _emit_t { uint16_t code_state_start; uint16_t stack_start; int stack_size; + uint16_t n_cell; uint16_t const_table_cur_obj; uint16_t const_table_num_obj; @@ -587,9 +588,14 @@ STATIC void emit_native_end_pass(emit_t *emit) { size_t n_exc_stack = 0; // exc-stack not needed for native code MP_BC_PRELUDE_SIG_ENCODE(n_state, n_exc_stack, emit->scope, emit_native_write_code_info_byte, emit); - // write code info #if MICROPY_PERSISTENT_CODE - mp_asm_base_data(&emit->as->base, 1, 5); + size_t n_info = 4; + #else + size_t n_info = 1; + #endif + MP_BC_PRELUDE_SIZE_ENCODE(n_info, emit->n_cell, emit_native_write_code_info_byte, emit); + + #if MICROPY_PERSISTENT_CODE mp_asm_base_data(&emit->as->base, 1, emit->scope->simple_name); mp_asm_base_data(&emit->as->base, 1, emit->scope->simple_name >> 8); mp_asm_base_data(&emit->as->base, 1, emit->scope->source_file); @@ -599,14 +605,15 @@ STATIC void emit_native_end_pass(emit_t *emit) { #endif // bytecode prelude: initialise closed over variables + size_t cell_start = mp_asm_base_get_code_pos(&emit->as->base); for (int i = 0; i < emit->scope->id_info_len; i++) { id_info_t *id = &emit->scope->id_info[i]; if (id->kind == ID_INFO_KIND_CELL) { - assert(id->local_num < 255); + assert(id->local_num <= 255); mp_asm_base_data(&emit->as->base, 1, id->local_num); // write the local which should be converted to a cell } } - mp_asm_base_data(&emit->as->base, 1, 255); // end of list sentinel + emit->n_cell = mp_asm_base_get_code_pos(&emit->as->base) - cell_start; } ASM_END_PASS(emit->as); diff --git a/py/objfun.c b/py/objfun.c index 053fe46b78..7051f3476d 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -139,7 +139,7 @@ const mp_obj_type_t mp_type_fun_builtin_var = { /* byte code functions */ qstr mp_obj_code_get_name(const byte *code_info) { - code_info = mp_decode_uint_skip(code_info); // skip code_info_size entry + MP_BC_PRELUDE_SIZE_DECODE(code_info); #if MICROPY_PERSISTENT_CODE return code_info[0] | (code_info[1] << 8); #else diff --git a/py/persistentcode.c b/py/persistentcode.c index 9776acb1e1..2109d93798 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -167,11 +167,10 @@ STATIC void extract_prelude(const byte **ip, const byte **ip2, bytecode_prelude_ prelude->n_pos_args = n_pos_args; prelude->n_kwonly_args = n_kwonly_args; prelude->n_def_pos_args = n_def_pos_args; + MP_BC_PRELUDE_SIZE_DECODE(*ip); *ip2 = *ip; - prelude->code_info_size = mp_decode_uint(ip2); - *ip += prelude->code_info_size; - while (*(*ip)++ != 255) { - } + *ip += n_info; + *ip += n_cell; } #endif // MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE @@ -286,12 +285,9 @@ STATIC void load_prelude(mp_reader_t *reader, byte **ip, byte **ip2, bytecode_pr byte *ip_read = *ip; read_uint(reader, &ip_read); // read in n_state/etc (is effectively a var-uint) byte *ip_read_save = ip_read; - size_t code_info_size = read_uint(reader, &ip_read); // read in code_info_size - code_info_size -= ip_read - ip_read_save; // subtract bytes taken by code_info_size itself - read_bytes(reader, ip_read, code_info_size); // read remaining code info - ip_read += code_info_size; - while ((*ip_read++ = read_byte(reader)) != 255) { - } + read_uint(reader, &ip_read); // read in n_info/n_cell (is effectively a var-uint) + MP_BC_PRELUDE_SIZE_DECODE(ip_read_save); + read_bytes(reader, ip_read, n_info + n_cell); // read remaining code info // Entire prelude has been read into *ip, now decode and extract values from it extract_prelude((const byte**)ip, (const byte**)ip2, prelude); diff --git a/py/profile.c b/py/profile.c index 230bb7cc24..f16d4d701e 100644 --- a/py/profile.c +++ b/py/profile.c @@ -34,7 +34,7 @@ STATIC uint mp_prof_bytecode_lineno(const mp_raw_code_t *rc, size_t bc) { const mp_bytecode_prelude_t *prelude = &rc->prelude; - return mp_bytecode_get_source_line(prelude->line_info, bc + prelude->opcodes - prelude->locals); + return mp_bytecode_get_source_line(prelude->line_info, bc); } void mp_prof_extract_prelude(const byte *bytecode, mp_bytecode_prelude_t *prelude) { @@ -48,22 +48,15 @@ void mp_prof_extract_prelude(const byte *bytecode, mp_bytecode_prelude_t *prelud prelude->n_kwonly_args = n_kwonly_args; prelude->n_def_pos_args = n_def_pos_args; - const byte *code_info = ip; - size_t code_info_size = mp_decode_uint(&ip); + MP_BC_PRELUDE_SIZE_DECODE(ip); + + prelude->line_info = ip + 4; + prelude->opcodes = ip + n_info + n_cell; qstr block_name = ip[0] | (ip[1] << 8); qstr source_file = ip[2] | (ip[3] << 8); - ip += 4; prelude->qstr_block_name = block_name; prelude->qstr_source_file = source_file; - - prelude->line_info = ip; - prelude->locals = code_info + code_info_size; - - ip = prelude->locals; - while (*ip++ != 255) { - } - prelude->opcodes = ip; } /******************************************************************************/ diff --git a/py/showbc.c b/py/showbc.c index 216f352664..d154511dce 100644 --- a/py/showbc.c +++ b/py/showbc.c @@ -85,10 +85,8 @@ void mp_bytecode_print(const void *descr, const byte *ip, mp_uint_t len, const m // Decode prelude MP_BC_PRELUDE_SIG_DECODE(ip); - + MP_BC_PRELUDE_SIZE_DECODE(ip); const byte *code_info = ip; - mp_uint_t code_info_size = mp_decode_uint(&code_info); - ip += code_info_size; #if MICROPY_PERSISTENT_CODE qstr block_name = code_info[0] | (code_info[1] << 8); @@ -102,7 +100,9 @@ void mp_bytecode_print(const void *descr, const byte *ip, mp_uint_t len, const m qstr_str(source_file), qstr_str(block_name), descr, mp_showbc_code_start, len); // raw bytecode dump - printf("Raw bytecode (code_info_size=" UINT_FMT ", bytecode_size=" UINT_FMT "):\n", code_info_size, len - code_info_size); + size_t prelude_size = ip - mp_showbc_code_start + n_info + n_cell; + printf("Raw bytecode (code_info_size=" UINT_FMT ", bytecode_size=" UINT_FMT "):\n", + prelude_size, len - prelude_size); for (mp_uint_t i = 0; i < len; i++) { if (i > 0 && i % 16 == 0) { printf("\n"); @@ -121,21 +121,18 @@ void mp_bytecode_print(const void *descr, const byte *ip, mp_uint_t len, const m printf("(N_STATE %u)\n", (unsigned)n_state); printf("(N_EXC_STACK %u)\n", (unsigned)n_exc_stack); - // for printing line number info - const byte *bytecode_start = ip; + // skip over code_info + ip += n_info; // bytecode prelude: initialise closed over variables - { - uint local_num; - while ((local_num = *ip++) != 255) { - printf("(INIT_CELL %u)\n", local_num); - } - len -= ip - mp_showbc_code_start; + for (size_t i = 0; i < n_cell; ++i) { + uint local_num = *ip++; + printf("(INIT_CELL %u)\n", local_num); } // print out line number info { - mp_int_t bc = bytecode_start - ip; + mp_int_t bc = 0; mp_uint_t source_line = 1; printf(" bc=" INT_FMT " line=" UINT_FMT "\n", bc, source_line); for (const byte* ci = code_info; *ci;) { @@ -153,7 +150,7 @@ void mp_bytecode_print(const void *descr, const byte *ip, mp_uint_t len, const m printf(" bc=" INT_FMT " line=" UINT_FMT "\n", bc, source_line); } } - mp_bytecode_print2(ip, len - 0, const_table); + mp_bytecode_print2(ip, len - prelude_size, const_table); } const byte *mp_bytecode_print_str(const byte *ip) { diff --git a/py/vm.c b/py/vm.c index 82218fd971..7487ff61b4 100644 --- a/py/vm.c +++ b/py/vm.c @@ -1441,10 +1441,13 @@ unwind_loop: && *code_state->ip != MP_BC_RAISE_LAST) { const byte *ip = code_state->fun_bc->bytecode; MP_BC_PRELUDE_SIG_DECODE(ip); - size_t bc = code_state->ip - ip; - size_t code_info_size = mp_decode_uint_value(ip); - ip = mp_decode_uint_skip(ip); // skip code_info_size - bc -= code_info_size; + MP_BC_PRELUDE_SIZE_DECODE(ip); + const byte *bytecode_start = ip + n_info + n_cell; + #if !MICROPY_PERSISTENT_CODE + // so bytecode is aligned + bytecode_start = MP_ALIGN(bytecode_start, sizeof(mp_uint_t)); + #endif + size_t bc = code_state->ip - bytecode_start; #if MICROPY_PERSISTENT_CODE qstr block_name = ip[0] | (ip[1] << 8); qstr source_file = ip[2] | (ip[3] << 8); diff --git a/tests/cmdline/cmd_parsetree.py.exp b/tests/cmdline/cmd_parsetree.py.exp index 58d419dc46..18986318a0 100644 --- a/tests/cmdline/cmd_parsetree.py.exp +++ b/tests/cmdline/cmd_parsetree.py.exp @@ -36,7 +36,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): arg names: (N_STATE 5) (N_EXC_STACK 0) - bc=-1 line=1 + bc=0 line=1 bc=0 line=4 bc=9 line=5 bc=12 line=6 diff --git a/tests/cmdline/cmd_showbc.py.exp b/tests/cmdline/cmd_showbc.py.exp index 839034a69f..b0a9016c51 100644 --- a/tests/cmdline/cmd_showbc.py.exp +++ b/tests/cmdline/cmd_showbc.py.exp @@ -5,7 +5,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): arg names: (N_STATE 3) (N_EXC_STACK 0) - bc=-1 line=1 + bc=0 line=1 ######## bc=\\d\+ line=155 00 MAKE_FUNCTION \.\+ @@ -38,7 +38,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): (INIT_CELL 14) (INIT_CELL 15) (INIT_CELL 16) - bc=-4 line=1 + bc=0 line=1 ######## bc=\\d\+ line=126 00 LOAD_CONST_NONE @@ -318,7 +318,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): \.\+rg names: (N_STATE 22) (N_EXC_STACK 0) - bc=-1 line=1 + bc=0 line=1 ######## bc=\\d\+ line=132 00 LOAD_CONST_SMALL_INT 1 @@ -392,7 +392,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): arg names: (N_STATE 2) (N_EXC_STACK 0) - bc=-1 line=1 + bc=0 line=1 bc=0 line=143 bc=3 line=144 bc=6 line=145 @@ -416,7 +416,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): arg names: (N_STATE 1) (N_EXC_STACK 0) - bc=-1 line=1 + bc=0 line=1 ######## bc=13 line=149 00 LOAD_NAME __name__ (cache=0) @@ -432,7 +432,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): arg names: self (N_STATE 4) (N_EXC_STACK 0) - bc=-1 line=1 + bc=0 line=1 bc=0 line=156 00 LOAD_GLOBAL super (cache=0) \\d\+ LOAD_GLOBAL __class__ (cache=0) @@ -449,7 +449,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): arg names: * * * (N_STATE 9) (N_EXC_STACK 0) - bc=-\\d\+ line=1 + bc=0 line=1 bc=0 line=59 ######## 00 LOAD_NULL @@ -473,7 +473,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): arg names: * * * (N_STATE 10) (N_EXC_STACK 0) - bc=-\\d\+ line=1 + bc=0 line=1 bc=0 line=60 ######## 00 BUILD_LIST 0 @@ -494,7 +494,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): arg names: * * * (N_STATE 11) (N_EXC_STACK 0) - bc=-\\d\+ line=1 + bc=0 line=1 ######## 00 BUILD_MAP 0 02 LOAD_FAST 2 @@ -515,7 +515,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): arg names: * (N_STATE 4) (N_EXC_STACK 0) - bc=-\\d\+ line=1 + bc=0 line=1 ######## bc=\\d\+ line=113 00 LOAD_DEREF 0 @@ -534,7 +534,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): arg names: * b (N_STATE 4) (N_EXC_STACK 0) - bc=-\\d\+ line=1 + bc=0 line=1 ######## bc=\\d\+ line=139 00 LOAD_FAST 1 diff --git a/tests/cmdline/cmd_verbose.py.exp b/tests/cmdline/cmd_verbose.py.exp index 60b499c264..a2fdf1f00d 100644 --- a/tests/cmdline/cmd_verbose.py.exp +++ b/tests/cmdline/cmd_verbose.py.exp @@ -6,7 +6,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): arg names: (N_STATE 2) (N_EXC_STACK 0) - bc=-1 line=1 + bc=0 line=1 bc=0 line=3 00 LOAD_NAME print (cache=0) 04 LOAD_CONST_SMALL_INT 1 diff --git a/tests/import/mpy_native.py b/tests/import/mpy_native.py index 03abab349e..749320dbbe 100644 --- a/tests/import/mpy_native.py +++ b/tests/import/mpy_native.py @@ -56,8 +56,8 @@ user_files = { '/mod1.mpy': ( b'M\x05\x0b\x1f\x20' # header - b'\x24' # n bytes, bytecode - b'\x00\x05\x00\x00\x00\x00\xff' # prelude + b'\x20' # n bytes, bytecode + b'\x00\x08\x00\x00\x00\x00' # prelude b'\x51' # LOAD_CONST_NONE b'\x63' # RETURN_VALUE diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index 8671a2395d..8c0f5db18a 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -142,16 +142,6 @@ def mp_opcode_format(bytecode, ip, count_var_uint): ip += extra_byte return f, ip - ip_start -def decode_uint(bytecode, ip): - unum = 0 - while True: - val = bytecode[ip] - ip += 1 - unum = (unum << 7) | (val & 0x7f) - if not (val & 0x80): - break - return ip, unum - def read_prelude_sig(read_byte): z = read_byte() # xSSSSEAA @@ -175,6 +165,20 @@ def read_prelude_sig(read_byte): S += 1 return S, E, F, A, K, D +def read_prelude_size(read_byte): + I = 0 + C = 0 + n = 0 + while True: + z = read_byte() + # xIIIIIIC + I |= ((z & 0x7e) >> 1) << (6 * n) + C |= (z & 1) << n + if not (z & 0x80): + break + n += 1 + return I, C + def extract_prelude(bytecode, ip): def local_read_byte(): b = bytecode[ip_ref[0]] @@ -182,16 +186,14 @@ def extract_prelude(bytecode, ip): return b ip_ref = [ip] # to close over ip in Python 2 and 3 n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args = read_prelude_sig(local_read_byte) + n_info, n_cell = read_prelude_size(local_read_byte) ip = ip_ref[0] - ip2, code_info_size = decode_uint(bytecode, ip) - ip += code_info_size - while bytecode[ip] != 0xff: - ip += 1 - ip += 1 + ip2 = ip + ip = ip2 + n_info + n_cell # ip now points to first opcode # ip2 points to simple_name qstr - return ip, ip2, (n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args, code_info_size) + return ip, ip2, (n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args) class MPFunTable: pass @@ -359,7 +361,6 @@ class RawCode(object): print(' .qstr_block_name = %s,' % self.simple_name.qstr_id) print(' .qstr_source_file = %s,' % self.source_file.qstr_id) print(' .line_info = fun_data_%s + %u,' % (self.escaped_name, 0)) # TODO - print(' .locals = fun_data_%s + %u,' % (self.escaped_name, 0)) # TODO print(' .opcodes = fun_data_%s + %u,' % (self.escaped_name, self.ip)) print(' },') print(' .line_of_definition = %u,' % 0) # TODO @@ -583,14 +584,11 @@ def read_obj(f): def read_prelude(f, bytecode): n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args = read_prelude_sig(lambda: read_byte(f, bytecode)) - l1 = bytecode.idx - code_info_size = read_uint(f, bytecode) + n_info, n_cell = read_prelude_size(lambda: read_byte(f, bytecode)) l2 = bytecode.idx - for _ in range(code_info_size - (l2 - l1)): + for _ in range(n_info + n_cell): read_byte(f, bytecode) - while read_byte(f, bytecode) != 255: - pass - return l2, (n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args, code_info_size) + return l2, (n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args) def read_qstr_and_pack(f, bytecode, qstr_win): qst = read_qstr(f, qstr_win) From fd9b7efe3957f2f0b24d9cec2fe38ddaccf0539d Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 25 Sep 2019 16:19:29 +1000 Subject: [PATCH 0776/1788] minimal/frozentest.mpy: Update due to change in bytecode. --- ports/minimal/frozentest.mpy | Bin 207 -> 200 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/ports/minimal/frozentest.mpy b/ports/minimal/frozentest.mpy index f1cebe3fed8875321215ad4e8ea485fc381112fa..178b811ba0924a78ea825c22983ebbd9c597c2ff 100644 GIT binary patch delta 28 jcmX@lc!E*Hmz7Cgp(#W_jGZBnQBy-hLtBGkqVyI3SZ@XD delta 35 ocmX@Xc%D((mz7Cgp{anG0R(v283Gx#G&D4{H5eHFPZZe#0CwjF@Bjb+ From 1d0423419b6da1f865ad73e1a95f26e724770ab7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 26 Sep 2019 11:48:07 +1000 Subject: [PATCH 0777/1788] py/bc: Don't include mp_decode_uint funcs when not needed. These are now only needed when persistent code is disabled. --- py/bc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/py/bc.c b/py/bc.c index d671b64f92..7dd4b2246a 100644 --- a/py/bc.c +++ b/py/bc.c @@ -40,6 +40,8 @@ #define DEBUG_printf(...) (void)0 #endif +#if !MICROPY_PERSISTENT_CODE + mp_uint_t mp_decode_uint(const byte **ptr) { mp_uint_t unum = 0; byte val; @@ -70,6 +72,8 @@ const byte *mp_decode_uint_skip(const byte *ptr) { return ptr; } +#endif + STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, size_t expected, size_t given) { #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE // generic message, used also for other argument issues From 4102320e908dfa6e2fc320d73f118670ad5b1501 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 26 Sep 2019 11:48:39 +1000 Subject: [PATCH 0778/1788] tests/basics: Add test for getting name of func with closed over locals. Tests correct decoding of the prelude to get the function name. --- tests/basics/fun_name.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/basics/fun_name.py b/tests/basics/fun_name.py index 53ca935616..bb1f14992f 100644 --- a/tests/basics/fun_name.py +++ b/tests/basics/fun_name.py @@ -22,3 +22,11 @@ try: str((1).to_bytes.__name__) except AttributeError: pass + +# name of a function that has closed over variables +def outer(): + x = 1 + def inner(): + return x + return inner +print(outer.__name__) From d2e730b727fe5522e8b70b3af48bc4504545eb3b Mon Sep 17 00:00:00 2001 From: Glenn Ruben Bakke Date: Sun, 23 Dec 2018 16:22:00 +0100 Subject: [PATCH 0779/1788] nrf/i2c: Add support for TWIM (EasyDMA). --- ports/nrf/modules/machine/i2c.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/ports/nrf/modules/machine/i2c.c b/ports/nrf/modules/machine/i2c.c index 1d89716121..6ec902a833 100644 --- a/ports/nrf/modules/machine/i2c.c +++ b/ports/nrf/modules/machine/i2c.c @@ -31,12 +31,34 @@ #include "py/runtime.h" #include "py/mperrno.h" #include "py/mphal.h" -#include "extmod/machine_i2c.h" -#include "i2c.h" -#include "nrfx_twi.h" #if MICROPY_PY_MACHINE_I2C +#include "extmod/machine_i2c.h" +#include "i2c.h" +#if NRFX_TWI_ENABLED +#include "nrfx_twi.h" +#else +#include "nrfx_twim.h" +#endif + +#if NRFX_TWIM_ENABLED + +#define nrfx_twi_t nrfx_twim_t +#define nrfx_twi_config_t nrfx_twim_config_t + +#define nrfx_twi_init nrfx_twim_init +#define nrfx_twi_enable nrfx_twim_enable +#define nrfx_twi_rx nrfx_twim_rx +#define nrfx_twi_tx nrfx_twim_tx +#define nrfx_twi_disable nrfx_twim_disable + +#define NRFX_TWI_INSTANCE NRFX_TWIM_INSTANCE + +#define NRF_TWI_FREQ_400K NRF_TWIM_FREQ_400K + +#endif + STATIC const mp_obj_type_t machine_hard_i2c_type; typedef struct _machine_hard_i2c_obj_t { From 02a8c31eef3778941da378b315033d6fde19c73c Mon Sep 17 00:00:00 2001 From: Glenn Ruben Bakke Date: Sun, 23 Dec 2018 16:23:32 +0100 Subject: [PATCH 0780/1788] nrf/temp: Move module configuration guard. This patch moves the check for MICROPY_PY_MACHINE_TEMP to come before the inclusion of nrf_temp.h. The nrf_temp.h depends on the NRF_TEMP_Type which might not be defined for all nRF devices. --- ports/nrf/modules/machine/temp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ports/nrf/modules/machine/temp.c b/ports/nrf/modules/machine/temp.c index 007a7e5fd8..047514967f 100644 --- a/ports/nrf/modules/machine/temp.c +++ b/ports/nrf/modules/machine/temp.c @@ -30,6 +30,9 @@ #include "py/nlr.h" #include "py/runtime.h" #include "py/mphal.h" + +#if MICROPY_PY_MACHINE_TEMP + #include "temp.h" #include "nrf_temp.h" @@ -40,8 +43,6 @@ #define BLUETOOTH_STACK_ENABLED() (ble_drv_stack_enabled()) #endif // BLUETOOTH_SD -#if MICROPY_PY_MACHINE_TEMP - typedef struct _machine_temp_obj_t { mp_obj_base_t base; } machine_temp_obj_t; From c561ae61a11afd22379bfd5f688cd4d8c9292ba7 Mon Sep 17 00:00:00 2001 From: Glenn Ruben Bakke Date: Sun, 23 Dec 2018 16:31:23 +0100 Subject: [PATCH 0781/1788] nrf/uart: Add support for UARTE (EasyDMA). --- ports/nrf/modules/machine/uart.c | 42 ++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/ports/nrf/modules/machine/uart.c b/ports/nrf/modules/machine/uart.c index b9c018fc84..5f7daa91e9 100644 --- a/ports/nrf/modules/machine/uart.c +++ b/ports/nrf/modules/machine/uart.c @@ -44,7 +44,12 @@ #include "mpconfigboard.h" #include "nrf.h" #include "mphalport.h" + +#if NRFX_UART_ENABLED #include "nrfx_uart.h" +#else +#include "nrfx_uarte.h" +#endif #if MICROPY_PY_MACHINE_UART @@ -56,6 +61,40 @@ typedef struct _machine_hard_uart_buf_t { volatile ringbuf_t rx_ringbuf; } machine_hard_uart_buf_t; +#if NRFX_UARTE_ENABLED + +#define nrfx_uart_t nrfx_uarte_t +#define nrfx_uart_config_t nrfx_uarte_config_t + +#define nrfx_uart_rx nrfx_uarte_rx +#define nrfx_uart_tx nrfx_uarte_tx +#define nrfx_uart_tx_in_progress nrfx_uarte_tx_in_progress +#define nrfx_uart_init nrfx_uarte_init +#define nrfx_uart_event_t nrfx_uarte_event_t +#define NRFX_UART_INSTANCE NRFX_UARTE_INSTANCE + +#define NRF_UART_HWFC_ENABLED NRF_UARTE_HWFC_ENABLED +#define NRF_UART_HWFC_DISABLED NRF_UARTE_HWFC_DISABLED +#define NRF_UART_PARITY_EXCLUDED NRF_UARTE_PARITY_EXCLUDED +#define NRFX_UART_EVT_RX_DONE NRFX_UARTE_EVT_RX_DONE + +#define NRF_UART_BAUDRATE_1200 NRF_UARTE_BAUDRATE_1200 +#define NRF_UART_BAUDRATE_2400 NRF_UARTE_BAUDRATE_2400 +#define NRF_UART_BAUDRATE_4800 NRF_UARTE_BAUDRATE_4800 +#define NRF_UART_BAUDRATE_9600 NRF_UARTE_BAUDRATE_9600 +#define NRF_UART_BAUDRATE_14400 NRF_UARTE_BAUDRATE_14400 +#define NRF_UART_BAUDRATE_19200 NRF_UARTE_BAUDRATE_19200 +#define NRF_UART_BAUDRATE_28800 NRF_UARTE_BAUDRATE_28800 +#define NRF_UART_BAUDRATE_38400 NRF_UARTE_BAUDRATE_38400 +#define NRF_UART_BAUDRATE_57600 NRF_UARTE_BAUDRATE_57600 +#define NRF_UART_BAUDRATE_76800 NRF_UARTE_BAUDRATE_76800 +#define NRF_UART_BAUDRATE_115200 NRF_UARTE_BAUDRATE_115200 +#define NRF_UART_BAUDRATE_230400 NRF_UARTE_BAUDRATE_230400 +#define NRF_UART_BAUDRATE_250000 NRF_UARTE_BAUDRATE_250000 +#define NRF_UART_BAUDRATE_1000000 NRF_UARTE_BAUDRATE_1000000 + +#endif + typedef struct _machine_hard_uart_obj_t { mp_obj_base_t base; const nrfx_uart_t * p_uart; // Driver instance @@ -210,7 +249,10 @@ STATIC mp_obj_t machine_hard_uart_make_new(const mp_obj_type_t *type, size_t n_a // Enable event callback and start asynchronous receive nrfx_uart_init(self->p_uart, &config, uart_event_handler); nrfx_uart_rx(self->p_uart, &self->buf->rx_buf[0], 1); + +#if NRFX_UART_ENABLED nrfx_uart_rx_enable(self->p_uart); +#endif return MP_OBJ_FROM_PTR(self); } From cf383412efab088ab448ec22c838d483f4d082de Mon Sep 17 00:00:00 2001 From: Glenn Ruben Bakke Date: Wed, 3 Apr 2019 23:51:38 +0200 Subject: [PATCH 0782/1788] nrf/flash: Update flash driver to use nrfx_nvmc driver. The the nrfx driver is aware of chip specific registers, while the raw HAL abstraction is not. This driver enables use of NVMC in non-secure domain for nrf9160. --- ports/nrf/Makefile | 5 +---- ports/nrf/drivers/flash.h | 8 ++++---- ports/nrf/nrfx_config.h | 2 ++ 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index c02109a156..1b70851eb8 100644 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -181,10 +181,7 @@ SRC_NRFX += $(addprefix lib/nrfx/drivers/src/,\ nrfx_timer.c \ nrfx_pwm.c \ nrfx_gpiote.c \ - ) - -SRC_NRFX_HAL += $(addprefix lib/nrfx/hal/,\ - nrf_nvmc.c \ + nrfx_nvmc.c \ ) SRC_C += \ diff --git a/ports/nrf/drivers/flash.h b/ports/nrf/drivers/flash.h index 7e6fff37a9..3dd5d06dd4 100644 --- a/ports/nrf/drivers/flash.h +++ b/ports/nrf/drivers/flash.h @@ -27,7 +27,7 @@ #ifndef __MICROPY_INCLUDED_LIB_FLASH_H__ #define __MICROPY_INCLUDED_LIB_FLASH_H__ -#include "nrf_nvmc.h" +#include "nrfx_nvmc.h" #if defined(NRF51) #define FLASH_PAGESIZE (1024) @@ -55,9 +55,9 @@ void flash_operation_finished(flash_state_t result); #else -#define flash_page_erase nrf_nvmc_page_erase -#define flash_write_byte nrf_nvmc_write_byte -#define flash_write_bytes nrf_nvmc_write_bytes +#define flash_page_erase nrfx_nvmc_page_erase +#define flash_write_byte nrfx_nvmc_byte_write +#define flash_write_bytes nrfx_nvmc_bytes_write #endif diff --git a/ports/nrf/nrfx_config.h b/ports/nrf/nrfx_config.h index d8a7d521da..99085a2fe8 100644 --- a/ports/nrf/nrfx_config.h +++ b/ports/nrf/nrfx_config.h @@ -103,6 +103,8 @@ #define NRFX_PWM2_ENABLED 1 #define NRFX_PWM3_ENABLED (NRF52840) +#define NRFX_NVMC_ENABLED 1 + // Peripheral Resource Sharing #if defined(NRF51) || defined(NRF52832) #define NRFX_PRS_BOX_0_ENABLED (NRFX_TWI_ENABLED && NRFX_TWI0_ENABLED && NRFX_SPI_ENABLED && NRFX_SPI0_ENABLED) From 226399bcef8abf2f831cdb139c9bd0d416850ab5 Mon Sep 17 00:00:00 2001 From: roland van straten Date: Fri, 27 Sep 2019 09:55:58 +0200 Subject: [PATCH 0783/1788] nrf/led: Expose public API for LED manipulation. Aligned implementation with the STM32 port. Added empty functions to be used when no LED is available. --- ports/nrf/modules/board/led.c | 29 +++++++++++++++++++---------- ports/nrf/modules/board/led.h | 2 ++ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/ports/nrf/modules/board/led.c b/ports/nrf/modules/board/led.c index 5d7b54ecba..a7efafa366 100644 --- a/ports/nrf/modules/board/led.c +++ b/ports/nrf/modules/board/led.c @@ -65,8 +65,8 @@ static const board_led_obj_t board_led_obj[] = { #if MICROPY_HW_LED_TRICOLOR {{&board_led_type}, BOARD_LED_RED, MICROPY_HW_LED_RED, 0, MICROPY_HW_LED_PULLUP}, - {{&board_led_type}, BOARD_LED_GREEN, MICROPY_HW_LED_GREEN,0, MICROPY_HW_LED_PULLUP}, - {{&board_led_type}, BOARD_LED_BLUE, MICROPY_HW_LED_BLUE,0, MICROPY_HW_LED_PULLUP}, + {{&board_led_type}, BOARD_LED_GREEN, MICROPY_HW_LED_GREEN, 0, MICROPY_HW_LED_PULLUP}, + {{&board_led_type}, BOARD_LED_BLUE, MICROPY_HW_LED_BLUE, 0, MICROPY_HW_LED_PULLUP}, #endif #if (MICROPY_HW_LED_COUNT >= 1) {{&board_led_type}, BOARD_LED1, MICROPY_HW_LED1, 0, @@ -115,17 +115,17 @@ void led_init(void) { } } -void led_state(board_led_obj_t * led_obj, int state) { +void led_state(board_led_t led, int state) { if (state == 1) { - led_on(led_obj); + led_on((board_led_obj_t*)&board_led_obj[led-1]); } else { - led_off(led_obj); + led_off((board_led_obj_t*)&board_led_obj[led-1]); } } -void led_toggle(board_led_obj_t * led_obj) { - nrf_gpio_pin_toggle(led_obj->hw_pin); +void led_toggle(board_led_t led) { + nrf_gpio_pin_toggle(board_led_obj[led-1].hw_pin); } @@ -162,7 +162,7 @@ STATIC mp_obj_t led_obj_make_new(const mp_obj_type_t *type, size_t n_args, size_ /// Turn the LED on. mp_obj_t led_obj_on(mp_obj_t self_in) { board_led_obj_t *self = self_in; - led_state(self, 1); + led_state(self->led_id, 1); return mp_const_none; } @@ -170,7 +170,7 @@ mp_obj_t led_obj_on(mp_obj_t self_in) { /// Turn the LED off. mp_obj_t led_obj_off(mp_obj_t self_in) { board_led_obj_t *self = self_in; - led_state(self, 0); + led_state(self->led_id, 0); return mp_const_none; } @@ -178,7 +178,7 @@ mp_obj_t led_obj_off(mp_obj_t self_in) { /// Toggle the LED between on and off. mp_obj_t led_obj_toggle(mp_obj_t self_in) { board_led_obj_t *self = self_in; - led_toggle(self); + led_toggle(self->led_id); return mp_const_none; } @@ -202,4 +202,13 @@ const mp_obj_type_t board_led_type = { .locals_dict = (mp_obj_dict_t*)&led_locals_dict, }; +#else +// For boards with no LEDs, we leave an empty function here so that we don't +// have to put conditionals everywhere. +void led_init(void) { +} +void led_state(board_led_t led, int state) { +} +void led_toggle(board_led_t led) { +} #endif // MICROPY_HW_HAS_LED diff --git a/ports/nrf/modules/board/led.h b/ports/nrf/modules/board/led.h index 537b9ac546..187752189f 100644 --- a/ports/nrf/modules/board/led.h +++ b/ports/nrf/modules/board/led.h @@ -51,6 +51,8 @@ typedef enum { } board_led_t; void led_init(void); +void led_state(board_led_t, int); +void led_toggle(board_led_t); extern const mp_obj_type_t board_led_type; From a069340c1ee14fe5e956e38aa4482f526145d7d3 Mon Sep 17 00:00:00 2001 From: roland van straten Date: Fri, 27 Sep 2019 09:58:21 +0200 Subject: [PATCH 0784/1788] nrf/main: Update the way the LED is used on startup. In case of LED1 being present, do a short blink during startup instead of turning it on and leave it on. --- ports/nrf/main.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ports/nrf/main.c b/ports/nrf/main.c index 38d41bd8c5..e82cfcf58d 100644 --- a/ports/nrf/main.c +++ b/ports/nrf/main.c @@ -95,7 +95,13 @@ extern uint32_t _heap_end; int main(int argc, char **argv) { + soft_reset: + + led_init(); + + led_state(1, 1); // MICROPY_HW_LED_1 aka MICROPY_HW_LED_RED + mp_stack_set_top(&_ram_end); // Stack limit should be less than real stack size, so we have a chance @@ -192,14 +198,6 @@ pin_init0(); } #endif -#if (MICROPY_HW_HAS_LED) - led_init(); - - do_str("import board\r\n" \ - "board.LED(1).on()", - MP_PARSE_FILE_INPUT); -#endif - // Main script is finished, so now go into REPL mode. // The REPL mode can change, or it can request a soft reset. int ret_code = 0; @@ -225,6 +223,8 @@ pin_init0(); pwm_start(); #endif +led_state(1, 0); + #if MICROPY_VFS || MICROPY_MBFS // run boot.py and main.py if they exist. pyexec_file_if_exists("boot.py"); From 266146ad643b408a307676e320ffb22e0fe1e0ad Mon Sep 17 00:00:00 2001 From: hahmadi Date: Sat, 21 Sep 2019 13:30:19 -0400 Subject: [PATCH 0785/1788] stm32/system_stm32: Support selection of HSE and LSI on L4 MCUs. This commit adds the option to use HSE or MSI system clock, and LSE or LSI RTC clock, on L4 MCUs. Note that prior to this commit the default clocks on an L4 part were MSI and LSE. The defaults are now MSI and LSI. In mpconfigboard.h select the clock source via: #define MICROPY_HW_RTC_USE_LSE (0) or (1) #define MICROPY_HW_CLK_USE_HSE (0) or (1) and the PLLSAI1 N,P,Q,R settings: #define MICROPY_HW_CLK_PLLSAIN (12) #define MICROPY_HW_CLK_PLLSAIP (RCC_PLLP_DIV7) #define MICROPY_HW_CLK_PLLSAIQ (RCC_PLLQ_DIV2) #define MICROPY_HW_CLK_PLLSAIR (RCC_PLLR_DIV2) --- ports/stm32/system_stm32.c | 45 +++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/ports/stm32/system_stm32.c b/ports/stm32/system_stm32.c index 0792d124d6..46dd58ba2f 100644 --- a/ports/stm32/system_stm32.c +++ b/ports/stm32/system_stm32.c @@ -213,12 +213,31 @@ void SystemClock_Config(void) #endif RCC_OscInitStruct.PLL.PLLSource = MICROPY_HW_RCC_PLL_SRC; #elif defined(STM32L4) + + #if MICROPY_HW_CLK_USE_HSE + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; + RCC_OscInitStruct.HSEState = RCC_HSE_ON; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; + RCC_OscInitStruct.PLL.PLLM = MICROPY_HW_CLK_PLLM; + RCC_OscInitStruct.PLL.PLLN = MICROPY_HW_CLK_PLLN; + RCC_OscInitStruct.PLL.PLLP = MICROPY_HW_CLK_PLLP; + RCC_OscInitStruct.PLL.PLLQ = MICROPY_HW_CLK_PLLQ; + RCC_OscInitStruct.PLL.PLLR = MICROPY_HW_CLK_PLLR; + RCC_OscInitStruct.MSIState = RCC_MSI_OFF; + #else 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; RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI; + #endif + + #if MICROPY_HW_RTC_USE_LSE + RCC_OscInitStruct.LSEState = RCC_LSE_ON; + #else + RCC_OscInitStruct.LSEState = RCC_LSE_OFF; + #endif + #endif RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 @@ -362,20 +381,36 @@ void SystemClock_Config(void) |RCC_PERIPHCLK_USB |RCC_PERIPHCLK_ADC |RCC_PERIPHCLK_RNG |RCC_PERIPHCLK_RTC; PeriphClkInitStruct.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1; - /* PLLSAI is used to clock USB, ADC, I2C1 and RNG. The frequency is - 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; PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_PLLSAI1; - PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE; PeriphClkInitStruct.RngClockSelection = RCC_RNGCLKSOURCE_PLLSAI1; + + #if MICROPY_HW_RTC_USE_LSE + PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE; + #else + PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSI; + #endif + + #if MICROPY_HW_CLK_USE_HSE + PeriphClkInitStruct.PLLSAI1.PLLSAI1Source = RCC_PLLSOURCE_HSE; + PeriphClkInitStruct.PLLSAI1.PLLSAI1M = 1; //MICROPY_HW_CLK_PLLSAIM; + PeriphClkInitStruct.PLLSAI1.PLLSAI1N = MICROPY_HW_CLK_PLLSAIN; + PeriphClkInitStruct.PLLSAI1.PLLSAI1P = MICROPY_HW_CLK_PLLSAIP; + PeriphClkInitStruct.PLLSAI1.PLLSAI1Q = MICROPY_HW_CLK_PLLSAIQ; + PeriphClkInitStruct.PLLSAI1.PLLSAI1R = MICROPY_HW_CLK_PLLSAIR; + #else + /* PLLSAI is used to clock USB, ADC, I2C1 and RNG. The frequency is + MSI(4MHz)/PLLM(1)*PLLSAI1N(24)/PLLSAIQ(2) = 48MHz. See the STM32CubeMx + application or the reference manual. */ PeriphClkInitStruct.PLLSAI1.PLLSAI1Source = RCC_PLLSOURCE_MSI; PeriphClkInitStruct.PLLSAI1.PLLSAI1M = 1; PeriphClkInitStruct.PLLSAI1.PLLSAI1N = 24; PeriphClkInitStruct.PLLSAI1.PLLSAI1P = RCC_PLLP_DIV7; PeriphClkInitStruct.PLLSAI1.PLLSAI1Q = RCC_PLLQ_DIV2; PeriphClkInitStruct.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV2; + #endif PeriphClkInitStruct.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_SAI1CLK |RCC_PLLSAI1_48M2CLK |RCC_PLLSAI1_ADC1CLK; From 26e90a051415629796efbec59f1d653b46e43aea Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 4 Oct 2019 16:03:37 +1000 Subject: [PATCH 0786/1788] stm32/boards: Enable MICROPY_HW_RTC_USE_LSE on L4 boards. The previous commit changed the default configuration on L4 MCUs to use LSI, so configure these boards to use LSE again. --- ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.h | 4 +++- ports/stm32/boards/LIMIFROG/mpconfigboard.h | 4 +++- ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h | 3 +++ ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h | 3 +++ ports/stm32/boards/STM32L496GDISC/mpconfigboard.h | 4 +++- 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.h b/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.h index 3ab3d5fa17..a88bcf6756 100644 --- a/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.h +++ b/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.h @@ -12,9 +12,11 @@ #define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV7) #define MICROPY_HW_CLK_PLLR (RCC_PLLR_DIV2) #define MICROPY_HW_CLK_PLLQ (RCC_PLLQ_DIV4) - #define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_4 +// The board has an external 32kHz crystal +#define MICROPY_HW_RTC_USE_LSE (1) + // USART1 config connected to ST-Link #define MICROPY_HW_UART1_TX (pin_B6) #define MICROPY_HW_UART1_RX (pin_B7) diff --git a/ports/stm32/boards/LIMIFROG/mpconfigboard.h b/ports/stm32/boards/LIMIFROG/mpconfigboard.h index d27c2e66ef..4b750c17ff 100644 --- a/ports/stm32/boards/LIMIFROG/mpconfigboard.h +++ b/ports/stm32/boards/LIMIFROG/mpconfigboard.h @@ -16,9 +16,11 @@ void LIMIFROG_board_early_init(void); #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 +// The board has an external 32kHz crystal +#define MICROPY_HW_RTC_USE_LSE (1) + // USART config #define MICROPY_HW_UART3_TX (pin_C10) #define MICROPY_HW_UART3_RX (pin_C11) diff --git a/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h b/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h index 60e053f44f..e7202efe02 100644 --- a/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h @@ -25,6 +25,9 @@ #define MICROPY_HW_CLK_PLLP (7) #define MICROPY_HW_CLK_PLLQ (2) +// 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) diff --git a/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h index 05298253ae..00b033006b 100644 --- a/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h @@ -15,6 +15,9 @@ #define MICROPY_HW_CLK_PLLQ (RCC_PLLQ_DIV2) #define MICROPY_HW_CLK_PLLR (RCC_PLLR_DIV2) +// The board has an external 32kHz crystal +#define MICROPY_HW_RTC_USE_LSE (1) + // UART config #define MICROPY_HW_UART2_TX (pin_A2) #define MICROPY_HW_UART2_RX (pin_A3) diff --git a/ports/stm32/boards/STM32L496GDISC/mpconfigboard.h b/ports/stm32/boards/STM32L496GDISC/mpconfigboard.h index 6a17d74d3a..5d9fa25bc3 100644 --- a/ports/stm32/boards/STM32L496GDISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32L496GDISC/mpconfigboard.h @@ -14,9 +14,11 @@ #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 +// The board has an external 32kHz crystal +#define MICROPY_HW_RTC_USE_LSE (1) + // USART config #define MICROPY_HW_UART2_TX (pin_A2) #define MICROPY_HW_UART2_RX (pin_D6) From 25a9bccdee2fe830046c1c1a0220ca7706597202 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Fri, 20 Sep 2019 09:16:34 +0200 Subject: [PATCH 0787/1788] py/compile: Disallow 'import *' outside module level. This check follows CPython's behaviour, because 'import *' always populates the globals with the imported names, not locals. Since it's safe to do this (doesn't lead to a crash or undefined behaviour) the check is only enabled for MICROPY_CPYTHON_COMPAT. Fixes issue #5121. --- py/compile.c | 7 +++++++ tests/cmdline/cmd_showbc.py | 5 ++++- tests/cmdline/cmd_showbc.py.exp | 12 ++++++------ tests/import/import_star_error.py | 13 +++++++++++++ 4 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 tests/import/import_star_error.py diff --git a/py/compile.c b/py/compile.c index 90d1bfd138..62b0f3938d 100644 --- a/py/compile.c +++ b/py/compile.c @@ -1196,6 +1196,13 @@ STATIC void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) { } while (0); if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_STAR)) { + #if MICROPY_CPYTHON_COMPAT + if (comp->scope_cur->kind != SCOPE_MODULE) { + compile_syntax_error(comp, (mp_parse_node_t)pns, "import * not at module level"); + return; + } + #endif + EMIT_ARG(load_const_small_int, import_level); // build the "fromlist" tuple diff --git a/tests/cmdline/cmd_showbc.py b/tests/cmdline/cmd_showbc.py index 916228356f..f30b39ee10 100644 --- a/tests/cmdline/cmd_showbc.py +++ b/tests/cmdline/cmd_showbc.py @@ -115,7 +115,7 @@ def f(): # import import a from a import b - from a import * + #from sys import * # tested at module scope # raise raise @@ -154,3 +154,6 @@ del Class # load super method def f(self): super().f() + +# import * (needs to be in module scope) +from sys import * diff --git a/tests/cmdline/cmd_showbc.py.exp b/tests/cmdline/cmd_showbc.py.exp index b0a9016c51..4d90ae22ca 100644 --- a/tests/cmdline/cmd_showbc.py.exp +++ b/tests/cmdline/cmd_showbc.py.exp @@ -7,7 +7,7 @@ arg names: (N_EXC_STACK 0) bc=0 line=1 ######## - bc=\\d\+ line=155 + bc=\\d\+ line=159 00 MAKE_FUNCTION \.\+ \\d\+ STORE_NAME f \\d\+ MAKE_FUNCTION \.\+ @@ -27,6 +27,11 @@ arg names: \\d\+ DELETE_NAME Class \\d\+ MAKE_FUNCTION \.\+ \\d\+ STORE_NAME f +\\d\+ LOAD_CONST_SMALL_INT 0 +\\d\+ LOAD_CONST_STRING '*' +\\d\+ BUILD_TUPLE 1 +\\d\+ IMPORT_NAME 'sys' +\\d\+ IMPORT_STAR \\d\+ LOAD_CONST_NONE \\d\+ RETURN_VALUE File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ bytes) @@ -300,11 +305,6 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): \\d\+ IMPORT_FROM 'b' \\d\+ STORE_DEREF 14 \\d\+ POP_TOP -\\d\+ LOAD_CONST_SMALL_INT 0 -\\d\+ LOAD_CONST_STRING '*' -\\d\+ BUILD_TUPLE 1 -\\d\+ IMPORT_NAME 'a' -\\d\+ IMPORT_STAR \\d\+ RAISE_LAST \\d\+ LOAD_CONST_SMALL_INT 1 \\d\+ RAISE_OBJ diff --git a/tests/import/import_star_error.py b/tests/import/import_star_error.py new file mode 100644 index 0000000000..17e237b8c1 --- /dev/null +++ b/tests/import/import_star_error.py @@ -0,0 +1,13 @@ +# test errors with import * + +# 'import *' is not allowed in function scope +try: + exec('def foo(): from x import *') +except SyntaxError as er: + print('function', 'SyntaxError') + +# 'import *' is not allowed in class scope +try: + exec('class C: from x import *') +except SyntaxError as er: + print('class', 'SyntaxError') From 4ddd46e6cfd1f10efbd6fbbbc0fed520a1058045 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Thu, 26 Sep 2019 20:25:39 +1000 Subject: [PATCH 0788/1788] docs/develop/qstr.rst: Add documentation for string interning. --- docs/develop/index.rst | 1 + docs/develop/qstr.rst | 112 +++++++++++++++++++++++++++++++++++++++++ py/mkrules.mk | 1 + py/py.mk | 1 + 4 files changed, 115 insertions(+) create mode 100644 docs/develop/qstr.rst diff --git a/docs/develop/index.rst b/docs/develop/index.rst index 64dbc46613..fff3e43d74 100644 --- a/docs/develop/index.rst +++ b/docs/develop/index.rst @@ -10,3 +10,4 @@ See the `getting started guide :maxdepth: 1 cmodules.rst + qstr.rst diff --git a/docs/develop/qstr.rst b/docs/develop/qstr.rst new file mode 100644 index 0000000000..1b3b9f903b --- /dev/null +++ b/docs/develop/qstr.rst @@ -0,0 +1,112 @@ +MicroPython string interning +============================ + +MicroPython uses `string interning`_ to save both RAM and ROM. This avoids +having to store duplicate copies of the same string. Primarily, this applies to +identifiers in your code, as something like a function or variable name is very +likely to appear in multiple places in the code. In MicroPython an interned +string is called a QSTR (uniQue STRing). + +A QSTR value (with type ``qstr``) is a index into a linked list of QSTR pools. +QSTRs store their length and a hash of their contents for fast comparison during +the de-duplication process. All bytecode operations that work with strings use +a QSTR argument. + +Compile-time QSTR generation +---------------------------- + +In the MicroPython C code, any strings that should be interned in the final +firmware are written as ``MP_QSTR_Foo``. At compile time this will evaluate to +a ``qstr`` value that points to the index of ``"Foo"`` in the QSTR pool. + +A multi-step process in the ``Makefile`` makes this work. In summary this +process has three parts: + +1. Find all ``MP_QSTR_Foo`` tokens in the code. + +2. Generate a static QSTR pool containing all the string data (including lengths + and hashes). + +3. Replace all ``MP_QSTR_Foo`` (via the preprocessor) with their corresponding + index. + +``MP_QSTR_Foo`` tokens are searched for in two sources: + +1. All files referenced in ``$(SRC_QSTR)``. This is all C code (i.e. ``py``, + ``extmod``, ``ports/stm32``) but not including third-party code such as + ``lib``. + +2. Additional ``$(QSTR_GLOBAL_DEPENDENCIES)`` (which includes ``mpconfig*.h``). + +*Note:* ``frozen_mpy.c`` (generated by mpy-tool.py) has its own QSTR generation +and pool. + +Some additional strings that can't be expressed using the ``MP_QSTR_Foo`` syntax +(e.g. they contain non-alphanumeric characters) are explicitly provided in +``qstrdefs.h`` and ``qstrdefsport.h`` via the ``$(QSTR_DEFS)`` variable. + +Processing happens in the following stages: + +1. ``qstr.i.last`` is the concatenation of putting every single input file + through the C pre-processor. This means that any conditionally disabled code + will be removed, and macros expanded. This means we don't add strings to the + pool that won't be used in the final firmware. Because at this stage (thanks + to the ``NO_QSTR`` macro added by ``QSTR_GEN_EXTRA_CFLAGS``) there is no + definition for ``MP_QSTR_Foo`` it passes through this stage unaffected. This + file also includes comments from the preprocessor that include line number + information. Note that this step only uses files that have changed, which + means that ``qstr.i.last`` will only contain data from files that have + changed since the last compile. +2. ``qstr.split`` is an empty file created after running ``makeqstrdefs.py split`` + on qstr.i.last. It's just used as a dependency to indicate that the step ran. + This script outputs one file per input C file, ``genhdr/qstr/...file.c.qstr``, + which contains only the matched QSTRs. Each QSTR is printed as ``Q(Foo)``. + This step is necessary to combine the existing files with the new data + generated from the incremental update in ``qstr.i.last``. + +3. ``qstrdefs.collected.h`` is the output of concatenating ``genhdr/qstr/*`` + using ``makeqstrdefs.py cat``. This is now the full set of ``MP_QSTR_Foo``'s + found in the code, now formatted as ``Q(Foo)``, one-per-line, with duplicates. + This file is only updated if the set of qstrs has changed. A hash of the QSTR + data is written to another file (``qstrdefs.collected.h.hash``) which allows + it to track changes across builds. + +4. ``qstrdefs.preprocessed.h`` adds in the QSTRs from qstrdefs*. It + concatenates ``qstrdefs.collected.h`` with ``qstrdefs*.h``, then it transforms + each line from ``Q(Foo)`` to ``"Q(Foo)"`` so they pass through the preprocessor + unchanged. Then the preprocessor is used to deal with any conditional + compilation in ``qstrdefs*.h``. Then the transformation is undone back to + ``Q(Foo)``, and saved as ``qstrdefs.preprocessed.h``. + +5. ``qstrdefs.generated.h`` is the output of ``makeqstrdata.py``. For each + ``Q(Foo)`` in qstrdefs.preprocessed.h (plus some extra hard-coded ones), it outputs + ``QDEF(MP_QSTR_Foo, (const byte*)"hash" "Foo")``. + +Then in the main compile, two things happen with ``qstrdefs.generated.h``: + +1. In qstr.h, each QDEF becomes an entry in an enum, which makes ``MP_QSTR_Foo`` + available to code and equal to the index of that string in the QSTR table. + +2. In qstr.c, the actual QSTR data table is generated as elements of the + ``mp_qstr_const_pool->qstrs``. + +.. _`string interning`: https://en.wikipedia.org/wiki/String_interning + +Run-time QSTR generation +------------------------ + +Additional QSTR pools can be created at runtime so that strings can be added to +them. For example, the code:: + + foo[x] = 3 + +Will need to create a QSTR for the value of ``x`` so it can be used by the +"load attr" bytecode. + +Also, when compiling Python code, identifiers and literals need to have QSTRs +created. Note: only literals shorter than 10 characters become QSTRs. This is +because a regular string on the heap always takes up a minimum of 16 bytes (one +GC block), whereas QSTRs allow them to be packed more efficiently into the pool. + +QSTR pools (and the underlying "chunks" that store the string data) are allocated +on-demand on the heap with a minimum size. diff --git a/py/mkrules.mk b/py/mkrules.mk index b74dd45495..f9d77c3177 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -70,6 +70,7 @@ $(OBJ): | $(HEADER_BUILD)/qstrdefs.generated.h $(HEADER_BUILD)/mpversion.h # - 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] +# See more information about this process in docs/develop/qstr.rst. $(HEADER_BUILD)/qstr.i.last: $(SRC_QSTR) $(QSTR_GLOBAL_DEPENDENCIES) | $(QSTR_GLOBAL_REQUIREMENTS) $(ECHO) "GEN $@" $(Q)$(CPP) $(QSTR_GEN_EXTRA_CFLAGS) $(CFLAGS) $(if $(filter $?,$(QSTR_GLOBAL_DEPENDENCIES)),$^,$(if $?,$?,$^)) >$(HEADER_BUILD)/qstr.i.last diff --git a/py/py.mk b/py/py.mk index ba3a8639bf..d97852dd43 100644 --- a/py/py.mk +++ b/py/py.mk @@ -231,6 +231,7 @@ MPCONFIGPORT_MK = $(wildcard mpconfigport.mk) # created before we run the script to generate the .h # Note: we need to protect the qstr names from the preprocessor, so we wrap # the lines in "" and then unwrap after the preprocessor is finished. +# See more information about this process in docs/develop/qstr.rst. $(HEADER_BUILD)/qstrdefs.generated.h: $(PY_QSTR_DEFS) $(QSTR_DEFS) $(QSTR_DEFS_COLLECTED) $(PY_SRC)/makeqstrdata.py mpconfigport.h $(MPCONFIGPORT_MK) $(PY_SRC)/mpconfig.h | $(HEADER_BUILD) $(ECHO) "GEN $@" $(Q)$(CAT) $(PY_QSTR_DEFS) $(QSTR_DEFS) $(QSTR_DEFS_COLLECTED) | $(SED) 's/^Q(.*)/"&"/' | $(CPP) $(CFLAGS) - | $(SED) 's/^\"\(Q(.*)\)\"/\1/' > $(HEADER_BUILD)/qstrdefs.preprocessed.h From a09fd0475840ae6a24995ab7ab7955c88289817a Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Thu, 26 Sep 2019 20:41:41 +1000 Subject: [PATCH 0789/1788] py/makeqstrdefs.py: Remove unused blacklist. As of 7d58a197cffa7c0dd3686402d2e381812bb8ddeb, `NULL` should no longer be here because it's allowed (MP_QSTRnull took its place). This entry was preventing the use of MP_QSTR_NULL to mean "NULL" (although this is not currently used). A blacklist should not be needed because it should be possible to intern all strings. Fixes issue #5140. --- py/makeqstrdefs.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/py/makeqstrdefs.py b/py/makeqstrdefs.py index 457bdeef65..209e7a132d 100644 --- a/py/makeqstrdefs.py +++ b/py/makeqstrdefs.py @@ -12,10 +12,6 @@ import sys import io import os -# Blacklist of qstrings that are specially handled in further -# processing and should be ignored -QSTRING_BLACK_LIST = set(['NULL', 'number_of']) - def write_out(fname, output): if output: @@ -46,8 +42,7 @@ def process_file(f): continue for match in re_qstr.findall(line): name = match.replace('MP_QSTR_', '') - if name not in QSTRING_BLACK_LIST: - output.append('Q(' + name + ')') + output.append('Q(' + name + ')') write_out(last_fname, output) return "" From 0096041c9912d34a6227f647c264325b178c0384 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Fri, 27 Sep 2019 14:27:51 +1000 Subject: [PATCH 0790/1788] stm32/{adc,machine_adc}: Change ADC clock and sampling time for F0 MCUs. STM32F0 has PCLK=48MHz and maximum ADC clock is 14MHz so use PCLK/4=12MHz to stay within spec of the ADC peripheral. In pyb.ADC set common sampling time to approx 4uS for internal and external sources. In machine.ADC reduce sample time to approx 1uS for external source, leave internal at maximum sampling time. --- ports/stm32/adc.c | 14 ++++++++------ ports/stm32/machine_adc.c | 4 ++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index a4eaefd758..11b15cd09a 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -241,7 +241,13 @@ STATIC void adcx_init_periph(ADC_HandleTypeDef *adch, uint32_t resolution) { adch->Init.EOCSelection = ADC_EOC_SINGLE_CONV; adch->Init.ExternalTrigConv = ADC_SOFTWARE_START; adch->Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; - #if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) + #if defined(STM32F0) + adch->Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; // 12MHz + adch->Init.ScanConvMode = DISABLE; + adch->Init.DataAlign = ADC_DATAALIGN_RIGHT; + adch->Init.DMAContinuousRequests = DISABLE; + adch->Init.SamplingTimeCommon = ADC_SAMPLETIME_55CYCLES_5; // ~4uS + #elif defined(STM32F4) || defined(STM32F7) adch->Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; adch->Init.ScanConvMode = DISABLE; adch->Init.DataAlign = ADC_DATAALIGN_RIGHT; @@ -266,10 +272,6 @@ STATIC void adcx_init_periph(ADC_HandleTypeDef *adch, uint32_t resolution) { #error Unsupported processor #endif - #if defined(STM32F0) - adch->Init.SamplingTimeCommon = ADC_SAMPLETIME_71CYCLES_5; - #endif - HAL_ADC_Init(adch); #if defined(STM32H7) @@ -309,7 +311,7 @@ STATIC void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel) sConfig.Channel = channel; sConfig.Rank = 1; #if defined(STM32F0) - sConfig.SamplingTime = ADC_SAMPLETIME_71CYCLES_5; + sConfig.SamplingTime = ADC_SAMPLETIME_55CYCLES_5; #elif defined(STM32F4) || defined(STM32F7) sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES; #elif defined(STM32H7) diff --git a/ports/stm32/machine_adc.c b/ports/stm32/machine_adc.c index 3aacae77ba..22e60f043e 100644 --- a/ports/stm32/machine_adc.c +++ b/ports/stm32/machine_adc.c @@ -49,7 +49,7 @@ #endif #if defined(STM32F0) -#define ADC_SAMPLETIME_DEFAULT ADC_SAMPLETIME_71CYCLES_5 +#define ADC_SAMPLETIME_DEFAULT ADC_SAMPLETIME_13CYCLES_5 #define ADC_SAMPLETIME_DEFAULT_INT ADC_SAMPLETIME_239CYCLES_5 #elif defined(STM32F4) || defined(STM32F7) #define ADC_SAMPLETIME_DEFAULT ADC_SAMPLETIME_15CYCLES @@ -126,7 +126,7 @@ STATIC void adc_config(ADC_TypeDef *adc, uint32_t bits) { // Configure clock mode #if defined(STM32F0) - adc->CFGR2 = 1 << ADC_CFGR2_CKMODE_Pos; // PCLK/2 (synchronous clock mode) + adc->CFGR2 = 2 << ADC_CFGR2_CKMODE_Pos; // PCLK/4 (synchronous clock mode) #elif defined(STM32F4) || defined(STM32F7) || defined(STM32L4) ADCx_COMMON->CCR = 0; // ADCPR=PCLK/2 #elif defined(STM32H7) From 82c494a97e874912e7eb23d2f03f39212e343fb3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 28 Sep 2019 00:07:21 +1000 Subject: [PATCH 0791/1788] py/vm: Fix handling of unwind jump out of active finally. Prior to this commit, when unwinding through an active finally the stack was not being correctly popped/folded, which resulting in the VM crashing for complicated unwinding of nested finallys. This should be fixed with this commit, and more tests for return/break/ continue within a finally have been added to exercise this. --- py/vm.c | 104 ++++++++++++++--------- tests/basics/try_finally_break2.py | 19 +++++ tests/basics/try_finally_continue.py | 17 ++++ tests/basics/try_finally_continue.py.exp | 9 ++ tests/basics/try_finally_return5.py | 17 ++++ 5 files changed, 127 insertions(+), 39 deletions(-) create mode 100644 tests/basics/try_finally_break2.py create mode 100644 tests/basics/try_finally_continue.py create mode 100644 tests/basics/try_finally_continue.py.exp create mode 100644 tests/basics/try_finally_return5.py diff --git a/py/vm.c b/py/vm.c index 7487ff61b4..6e5015fc43 100644 --- a/py/vm.c +++ b/py/vm.c @@ -109,6 +109,21 @@ exc_sp--; /* pop back to previous exception handler */ \ CLEAR_SYS_EXC_INFO() /* just clear sys.exc_info(), not compliant, but it shouldn't be used in 1st place */ +#define CANCEL_ACTIVE_FINALLY(sp) do { \ + if (mp_obj_is_small_int(sp[-1])) { \ + /* Stack: (..., prev_dest_ip, prev_cause, dest_ip) */ \ + /* Cancel the unwind through the previous finally, replace with current one */ \ + sp[-2] = sp[0]; \ + sp -= 2; \ + } else { \ + assert(sp[-1] == mp_const_none || mp_obj_is_exception_instance(sp[-1])); \ + /* Stack: (..., None/exception, dest_ip) */ \ + /* Silence the finally's exception value (may be None or an exception) */ \ + sp[-1] = sp[0]; \ + --sp; \ + } \ +} while (0) + #if MICROPY_PY_SYS_SETTRACE #define FRAME_SETUP() do { \ @@ -698,21 +713,28 @@ unwind_jump:; while ((unum & 0x7f) > 0) { unum -= 1; assert(exc_sp >= exc_stack); - if (MP_TAGPTR_TAG1(exc_sp->val_sp) && exc_sp->handler > ip) { - // Getting here the stack looks like: - // (..., X, dest_ip) - // where X is pointed to by exc_sp->val_sp and in the case - // 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 the stack so it can return back to us when it is - // done (when WITH_CLEANUP or END_FINALLY reached). - // 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 + + if (MP_TAGPTR_TAG1(exc_sp->val_sp)) { + if (exc_sp->handler > ip) { + // Found a finally handler that isn't active; run it. + // Getting here the stack looks like: + // (..., X, dest_ip) + // where X is pointed to by exc_sp->val_sp and in the case + // of a "with" block contains the context manager info. + assert(&sp[-1] == MP_TAGPTR_PTR(exc_sp->val_sp)); + // We're going to run "finally" code as a coroutine + // (not calling it recursively). Set up a sentinel + // on the stack so it can return back to us when it is + // done (when WITH_CLEANUP or END_FINALLY reached). + // 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; + goto dispatch_loop; + } else { + // Found a finally handler that is already active; cancel it. + CANCEL_ACTIVE_FINALLY(sp); + } } POP_EXC_BLOCK(); } @@ -740,9 +762,9 @@ unwind_jump:; // if TOS is None, just pops it and continues // if TOS is an integer, finishes coroutine and returns control to caller // if TOS is an exception, reraises the exception + assert(exc_sp >= exc_stack); + POP_EXC_BLOCK(); if (TOP() == mp_const_none) { - assert(exc_sp >= exc_stack); - POP_EXC_BLOCK(); sp--; } else if (mp_obj_is_small_int(TOP())) { // We finished "finally" coroutine and now dispatch back @@ -1113,28 +1135,32 @@ unwind_jump:; unwind_return: // Search for and execute finally handlers that aren't already active while (exc_sp >= exc_stack) { - if (MP_TAGPTR_TAG1(exc_sp->val_sp) && exc_sp->handler > ip) { - // Found a finally handler that isn't active. - // Getting here the stack looks like: - // (..., X, [iter0, iter1, ...,] ret_val) - // where X is pointed to by exc_sp->val_sp and in the case - // of a "with" block contains the context manager info. - // There may be 0 or more for-iterators between X and the - // return value, and these must be removed before control can - // pass to the finally code. We simply copy the ret_value down - // over these iterators, if they exist. If they don't then the - // following is a null operation. - mp_obj_t *finally_sp = MP_TAGPTR_PTR(exc_sp->val_sp); - finally_sp[1] = sp[0]; - sp = &finally_sp[1]; - // 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 - // done (when WITH_CLEANUP or END_FINALLY reached). - PUSH(MP_OBJ_NEW_SMALL_INT(-1)); - ip = exc_sp->handler; - POP_EXC_BLOCK(); - goto dispatch_loop; + if (MP_TAGPTR_TAG1(exc_sp->val_sp)) { + if (exc_sp->handler > ip) { + // Found a finally handler that isn't active; run it. + // Getting here the stack looks like: + // (..., X, [iter0, iter1, ...,] ret_val) + // where X is pointed to by exc_sp->val_sp and in the case + // of a "with" block contains the context manager info. + // There may be 0 or more for-iterators between X and the + // return value, and these must be removed before control can + // pass to the finally code. We simply copy the ret_value down + // over these iterators, if they exist. If they don't then the + // following is a null operation. + mp_obj_t *finally_sp = MP_TAGPTR_PTR(exc_sp->val_sp); + finally_sp[1] = sp[0]; + sp = &finally_sp[1]; + // 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 + // done (when WITH_CLEANUP or END_FINALLY reached). + PUSH(MP_OBJ_NEW_SMALL_INT(-1)); + ip = exc_sp->handler; + goto dispatch_loop; + } else { + // Found a finally handler that is already active; cancel it. + CANCEL_ACTIVE_FINALLY(sp); + } } POP_EXC_BLOCK(); } diff --git a/tests/basics/try_finally_break2.py b/tests/basics/try_finally_break2.py new file mode 100644 index 0000000000..086e92e902 --- /dev/null +++ b/tests/basics/try_finally_break2.py @@ -0,0 +1,19 @@ +def foo(x): + for i in range(x): + for j in range(x): + try: + print(x, i, j, 1) + finally: + try: + try: + print(x, i, j, 2) + finally: + try: + 1 / 0 + finally: + print(x, i, j, 3) + break + finally: + print(x, i, j, 4) + break +print(foo(4)) diff --git a/tests/basics/try_finally_continue.py b/tests/basics/try_finally_continue.py new file mode 100644 index 0000000000..50040e5de0 --- /dev/null +++ b/tests/basics/try_finally_continue.py @@ -0,0 +1,17 @@ +def foo(x): + for i in range(x): + try: + pass + finally: + try: + try: + print(x, i) + finally: + try: + 1 / 0 + finally: + return 42 + finally: + print('continue') + continue +print(foo(4)) diff --git a/tests/basics/try_finally_continue.py.exp b/tests/basics/try_finally_continue.py.exp new file mode 100644 index 0000000000..2901997b1a --- /dev/null +++ b/tests/basics/try_finally_continue.py.exp @@ -0,0 +1,9 @@ +4 0 +continue +4 1 +continue +4 2 +continue +4 3 +continue +None diff --git a/tests/basics/try_finally_return5.py b/tests/basics/try_finally_return5.py new file mode 100644 index 0000000000..aa2327e655 --- /dev/null +++ b/tests/basics/try_finally_return5.py @@ -0,0 +1,17 @@ +def foo(x): + for i in range(x): + try: + pass + finally: + try: + try: + print(x, i) + finally: + try: + 1 / 0 + finally: + return 42 + finally: + print('return') + return 43 +print(foo(4)) From 809d89c794ceb44760ab997ff9a496488b4a2c0c Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 30 Sep 2019 16:06:20 +1000 Subject: [PATCH 0792/1788] py/runtime: Fix PEP479 behaviour throwing StopIteration into yield from. Commit 3f6ffe059f64b3ebc44dc0bbc63452cb8850702b implemented PEP479 but did not catch the case fixed in this commit. Found by coverage analysis, that the VM had uncovered code. --- py/runtime.c | 7 ++++++- py/vm.c | 11 ++--------- tests/basics/generator_pep479.py | 11 +++++++++++ tests/basics/generator_pep479.py.exp | 2 ++ 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/py/runtime.c b/py/runtime.c index 2657e7cc25..6b7a9ce3c6 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -1319,7 +1319,12 @@ 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 = mp_make_raise_obj(throw_value); + if (mp_obj_exception_match(throw_value, MP_OBJ_FROM_PTR(&mp_type_StopIteration))) { + // PEP479: if StopIteration is raised inside a generator it is replaced with RuntimeError + *ret_val = mp_obj_new_exception_msg(&mp_type_RuntimeError, "generator raised StopIteration"); + } else { + *ret_val = mp_make_raise_obj(throw_value); + } return MP_VM_RETURN_EXCEPTION; } } diff --git a/py/vm.c b/py/vm.c index 6e5015fc43..7c702f3863 100644 --- a/py/vm.c +++ b/py/vm.c @@ -1266,17 +1266,10 @@ yield: DISPATCH(); } else { assert(ret_kind == MP_VM_RETURN_EXCEPTION); + assert(!EXC_MATCH(ret_value, MP_OBJ_FROM_PTR(&mp_type_StopIteration))); // Pop exhausted gen sp--; - if (EXC_MATCH(ret_value, MP_OBJ_FROM_PTR(&mp_type_StopIteration))) { - PUSH(mp_obj_exception_get_value(ret_value)); - // If we injected GeneratorExit downstream, then even - // if it was swallowed, we re-raise GeneratorExit - GENERATOR_EXIT_IF_NEEDED(t_exc); - DISPATCH(); - } else { - RAISE(ret_value); - } + RAISE(ret_value); } } diff --git a/tests/basics/generator_pep479.py b/tests/basics/generator_pep479.py index e422c349e7..5385312170 100644 --- a/tests/basics/generator_pep479.py +++ b/tests/basics/generator_pep479.py @@ -27,3 +27,14 @@ try: g.throw(StopIteration) except RuntimeError: print('RuntimeError') + +# throwing a StopIteration through yield from, will be converted to a RuntimeError +def gen(): + yield from range(2) + print('should not get here') +g = gen() +print(next(g)) +try: + g.throw(StopIteration) +except RuntimeError: + print('RuntimeError') diff --git a/tests/basics/generator_pep479.py.exp b/tests/basics/generator_pep479.py.exp index c64fe49561..6101339462 100644 --- a/tests/basics/generator_pep479.py.exp +++ b/tests/basics/generator_pep479.py.exp @@ -3,3 +3,5 @@ RuntimeError StopIteration 1 RuntimeError +0 +RuntimeError From 27fe84e661d664c5c145b4b3a8d544dad7de0acb Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 4 Oct 2019 22:58:43 +1000 Subject: [PATCH 0793/1788] tests/basics: Add test for throw into yield-from with normal return. This test was found by missing coverage of a branch in py/nativeglue.c. --- tests/basics/gen_yield_from_throw.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/basics/gen_yield_from_throw.py b/tests/basics/gen_yield_from_throw.py index 804c53dda0..1f76e13f3c 100644 --- a/tests/basics/gen_yield_from_throw.py +++ b/tests/basics/gen_yield_from_throw.py @@ -34,3 +34,17 @@ try: print(next(g)) except TypeError: print("got TypeError from downstream!") + +# thrown value is caught and then generator returns normally +def gen(): + try: + yield 123 + except ValueError: + print('ValueError') + # return normally after catching thrown exception +def gen2(): + yield from gen() + yield 789 +g = gen2() +print(next(g)) +print(g.throw(ValueError)) From 4107597b845c04b7184215b3202d596998141cb9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 10 Sep 2019 13:35:19 +1000 Subject: [PATCH 0794/1788] py/emitnative: Add support for archs with windowed registers. Such that args/return regs for the parent are different to args/return regs for child calls. For an architecture to use this feature it should define the REG_PARENT_xxx macros before including py/emitnative.c. --- py/emitnative.c | 67 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 22 deletions(-) diff --git a/py/emitnative.c b/py/emitnative.c index 2c976606c7..30f66f6334 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -94,6 +94,15 @@ #define OFFSETOF_OBJ_FUN_BC_GLOBALS (offsetof(mp_obj_fun_bc_t, globals) / sizeof(uintptr_t)) #define OFFSETOF_OBJ_FUN_BC_CONST_TABLE (offsetof(mp_obj_fun_bc_t, const_table) / sizeof(uintptr_t)) +// If not already defined, set parent args to same as child call registers +#ifndef REG_PARENT_RET +#define REG_PARENT_RET REG_RET +#define REG_PARENT_ARG_1 REG_ARG_1 +#define REG_PARENT_ARG_2 REG_ARG_2 +#define REG_PARENT_ARG_3 REG_ARG_3 +#define REG_PARENT_ARG_4 REG_ARG_4 +#endif + // Word index of nlr_buf_t.ret_val #define NLR_BUF_IDX_RET_VAL (1) @@ -413,16 +422,16 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop ASM_ENTRY(emit->as, emit->stack_start + emit->n_state - num_locals_in_regs); #if N_X86 - asm_x86_mov_arg_to_r32(emit->as, 0, REG_ARG_1); + asm_x86_mov_arg_to_r32(emit->as, 0, REG_PARENT_ARG_1); #endif // Load REG_FUN_TABLE with a pointer to mp_fun_table, found in the const_table - ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_ARG_1, OFFSETOF_OBJ_FUN_BC_CONST_TABLE); + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_PARENT_ARG_1, OFFSETOF_OBJ_FUN_BC_CONST_TABLE); ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_LOCAL_3, 0); // Store function object (passed as first arg) to stack if needed if (NEED_FUN_OBJ(emit)) { - ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_FUN_OBJ(emit), REG_ARG_1); + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_FUN_OBJ(emit), REG_PARENT_ARG_1); } // Put n_args in REG_ARG_1, n_kw in REG_ARG_2, args array in REG_LOCAL_3 @@ -431,9 +440,9 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop asm_x86_mov_arg_to_r32(emit->as, 2, REG_ARG_2); asm_x86_mov_arg_to_r32(emit->as, 3, REG_LOCAL_3); #else - ASM_MOV_REG_REG(emit->as, REG_ARG_1, REG_ARG_2); - ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_ARG_3); - ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_ARG_4); + ASM_MOV_REG_REG(emit->as, REG_ARG_1, REG_PARENT_ARG_2); + ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_PARENT_ARG_3); + ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_PARENT_ARG_4); #endif // Check number of args matches this function, and call mp_arg_check_num_sig if not @@ -482,14 +491,14 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop #if N_X86 asm_x86_mov_arg_to_r32(emit->as, 0, REG_GENERATOR_STATE); #else - ASM_MOV_REG_REG(emit->as, REG_GENERATOR_STATE, REG_ARG_1); + ASM_MOV_REG_REG(emit->as, REG_GENERATOR_STATE, REG_PARENT_ARG_1); #endif // Put throw value into LOCAL_IDX_EXC_VAL slot, for yield/yield-from #if N_X86 - asm_x86_mov_arg_to_r32(emit->as, 1, REG_ARG_2); + asm_x86_mov_arg_to_r32(emit->as, 1, REG_PARENT_ARG_2); #endif - ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_ARG_2); + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_PARENT_ARG_2); // Load REG_FUN_TABLE with a pointer to mp_fun_table, found in the const_table ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_GENERATOR_STATE, LOCAL_IDX_FUN_OBJ(emit)); @@ -505,22 +514,22 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop // Prepare incoming arguments for call to mp_setup_code_state #if N_X86 - asm_x86_mov_arg_to_r32(emit->as, 0, REG_ARG_1); - asm_x86_mov_arg_to_r32(emit->as, 1, REG_ARG_2); - asm_x86_mov_arg_to_r32(emit->as, 2, REG_ARG_3); - asm_x86_mov_arg_to_r32(emit->as, 3, REG_ARG_4); + asm_x86_mov_arg_to_r32(emit->as, 0, REG_PARENT_ARG_1); + asm_x86_mov_arg_to_r32(emit->as, 1, REG_PARENT_ARG_2); + asm_x86_mov_arg_to_r32(emit->as, 2, REG_PARENT_ARG_3); + asm_x86_mov_arg_to_r32(emit->as, 3, REG_PARENT_ARG_4); #endif // Load REG_FUN_TABLE with a pointer to mp_fun_table, found in the const_table - ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_ARG_1, OFFSETOF_OBJ_FUN_BC_CONST_TABLE); + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_PARENT_ARG_1, OFFSETOF_OBJ_FUN_BC_CONST_TABLE); ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_LOCAL_3, emit->scope->num_pos_args + emit->scope->num_kwonly_args); // Set code_state.fun_bc - ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_FUN_OBJ(emit), REG_ARG_1); + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_FUN_OBJ(emit), REG_PARENT_ARG_1); // Set code_state.ip (offset from start of this function to prelude info) // TODO this encoding may change size in the final pass, need to make it fixed - emit_native_mov_state_imm_via(emit, emit->code_state_start + OFFSETOF_CODE_STATE_IP, emit->prelude_offset, REG_ARG_1); + emit_native_mov_state_imm_via(emit, emit->code_state_start + OFFSETOF_CODE_STATE_IP, emit->prelude_offset, REG_PARENT_ARG_1); // Set code_state.n_state (only works on little endian targets due to n_state being uint16_t) emit_native_mov_state_imm_via(emit, emit->code_state_start + offsetof(mp_code_state_t, n_state) / sizeof(uintptr_t), emit->n_state, REG_ARG_1); @@ -528,6 +537,17 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop // Put address of code_state into first arg ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, emit->code_state_start); + // Copy next 3 args if needed + #if REG_ARG_2 != REG_PARENT_ARG_2 + ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_PARENT_ARG_2); + #endif + #if REG_ARG_3 != REG_PARENT_ARG_3 + ASM_MOV_REG_REG(emit->as, REG_ARG_3, REG_PARENT_ARG_3); + #endif + #if REG_ARG_4 != REG_PARENT_ARG_4 + ASM_MOV_REG_REG(emit->as, REG_ARG_4, REG_PARENT_ARG_4); + #endif + // Call mp_setup_code_state to prepare code_state structure #if N_THUMB asm_thumb_bl_ind(emit->as, MP_F_SETUP_CODE_STATE, ASM_THUMB_REG_R4); @@ -1174,7 +1194,7 @@ STATIC void emit_native_global_exc_entry(emit_t *emit) { ASM_STORE_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_GENERATOR_STATE, OFFSETOF_CODE_STATE_STATE); // Load return kind - ASM_MOV_REG_IMM(emit->as, REG_RET, MP_VM_RETURN_EXCEPTION); + ASM_MOV_REG_IMM(emit->as, REG_PARENT_RET, MP_VM_RETURN_EXCEPTION); ASM_EXIT(emit->as); } else { @@ -1229,7 +1249,7 @@ STATIC void emit_native_global_exc_exit(emit_t *emit) { } // Load return value - ASM_MOV_REG_LOCAL(emit->as, REG_RET, LOCAL_IDX_RET_VAL(emit)); + ASM_MOV_REG_LOCAL(emit->as, REG_PARENT_RET, LOCAL_IDX_RET_VAL(emit)); } ASM_EXIT(emit->as); @@ -2617,13 +2637,13 @@ STATIC void emit_native_return_value(emit_t *emit) { if (peek_vtype(emit, 0) == VTYPE_PTR_NONE) { emit_pre_pop_discard(emit); if (return_vtype == VTYPE_PYOBJ) { - emit_native_mov_reg_const(emit, REG_RET, MP_F_CONST_NONE_OBJ); + emit_native_mov_reg_const(emit, REG_PARENT_RET, MP_F_CONST_NONE_OBJ); } else { ASM_MOV_REG_IMM(emit->as, REG_ARG_1, 0); } } else { vtype_kind_t vtype; - emit_pre_pop_reg(emit, &vtype, return_vtype == VTYPE_PYOBJ ? REG_RET : REG_ARG_1); + emit_pre_pop_reg(emit, &vtype, return_vtype == VTYPE_PYOBJ ? REG_PARENT_RET : REG_ARG_1); if (vtype != return_vtype) { EMIT_NATIVE_VIPER_TYPE_ERROR(emit, "return expected '%q' but got '%q'", @@ -2632,15 +2652,18 @@ STATIC void emit_native_return_value(emit_t *emit) { } if (return_vtype != VTYPE_PYOBJ) { emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, return_vtype, REG_ARG_2); + #if REG_RET != REG_PARENT_ARG_RET + ASM_MOV_REG_REG(emit->as, REG_PARENT_RET, REG_RET); + #endif } } else { vtype_kind_t vtype; - emit_pre_pop_reg(emit, &vtype, REG_RET); + emit_pre_pop_reg(emit, &vtype, REG_PARENT_RET); assert(vtype == VTYPE_PYOBJ); } if (NEED_GLOBAL_EXC_HANDLER(emit)) { // Save return value for the global exception handler to use - ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_RET_VAL(emit), REG_RET); + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_RET_VAL(emit), REG_PARENT_RET); } emit_native_unwind_jump(emit, emit->exit_label, emit->exc_stack_size); emit->last_emit_was_return_value = true; From 3504edc8048f8ab038ace50b0bbdf65b30619cc5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 10 Sep 2019 13:44:22 +1000 Subject: [PATCH 0795/1788] py/emitnative: Add support for using setjmp with native emitter. To enable this feature the N_NLR_SETJMP macro should be set to 1 before including py/emitnative.c. --- py/emitnative.c | 14 ++++++++++++++ py/nativeglue.c | 9 +++++++++ py/runtime0.h | 1 + 3 files changed, 24 insertions(+) diff --git a/py/emitnative.c b/py/emitnative.c index 30f66f6334..22bfa2c78f 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -1154,6 +1154,10 @@ STATIC void emit_native_global_exc_entry(emit_t *emit) { // Wrap everything in an nlr context ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, 0); emit_call(emit, MP_F_NLR_PUSH); + #if N_NLR_SETJMP + ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, 2); + emit_call(emit, MP_F_SETJMP); + #endif ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, start_label, true); } else { // Clear the unwind state @@ -1168,6 +1172,10 @@ STATIC void emit_native_global_exc_entry(emit_t *emit) { ASM_MOV_REG_LOCAL(emit->as, REG_LOCAL_2, LOCAL_IDX_EXC_HANDLER_UNWIND(emit)); ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, 0); emit_call(emit, MP_F_NLR_PUSH); + #if N_NLR_SETJMP + ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, 2); + emit_call(emit, MP_F_SETJMP); + #endif ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_UNWIND(emit), REG_LOCAL_2); ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, global_except_label, true); @@ -1178,6 +1186,12 @@ STATIC void emit_native_global_exc_entry(emit_t *emit) { // Global exception handler: check for valid exception handler emit_native_label_assign(emit, global_except_label); + #if N_NLR_SETJMP + // Reload REG_FUN_TABLE, since it may be clobbered by longjmp + emit_native_mov_reg_state(emit, REG_LOCAL_1, LOCAL_IDX_FUN_OBJ(emit)); + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_1, REG_LOCAL_1, offsetof(mp_obj_fun_bc_t, const_table) / sizeof(uintptr_t)); + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_LOCAL_1, emit->scope->num_pos_args + emit->scope->num_kwonly_args); + #endif ASM_MOV_REG_LOCAL(emit->as, REG_LOCAL_1, LOCAL_IDX_EXC_HANDLER_PC(emit)); ASM_JUMP_IF_REG_NONZERO(emit->as, REG_LOCAL_1, nlr_label, false); } diff --git a/py/nativeglue.c b/py/nativeglue.c index 62b76eb6b1..4405b2d116 100644 --- a/py/nativeglue.c +++ b/py/nativeglue.c @@ -244,7 +244,11 @@ const void *const mp_fun_table[MP_F_NUMBER_OF] = { mp_call_method_n_kw_var, mp_native_getiter, mp_native_iternext, + #if MICROPY_NLR_SETJMP + nlr_push_tail, + #else nlr_push, + #endif nlr_pop, mp_native_raise, mp_import_name, @@ -262,6 +266,11 @@ const void *const mp_fun_table[MP_F_NUMBER_OF] = { mp_small_int_floor_divide, mp_small_int_modulo, mp_native_yield_from, + #if MICROPY_NLR_SETJMP + setjmp, + #else + NULL, + #endif }; #endif // MICROPY_EMIT_NATIVE diff --git a/py/runtime0.h b/py/runtime0.h index 1df6d0d583..797ae00e60 100644 --- a/py/runtime0.h +++ b/py/runtime0.h @@ -201,6 +201,7 @@ typedef enum { MP_F_SMALL_INT_FLOOR_DIVIDE, MP_F_SMALL_INT_MODULO, MP_F_NATIVE_YIELD_FROM, + MP_F_SETJMP, MP_F_NUMBER_OF, } mp_fun_kind_t; From 306ec5369a1b82c2c9389cea1dfcb5bf1861c71a Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 10 Sep 2019 13:47:24 +1000 Subject: [PATCH 0796/1788] py/emitnative: Add support for archs that cannot read executable data. In which case place the native function prelude in a bytes object, linked from the const_table of that function. An architecture should define N_PRELUDE_AS_BYTES_OBJ to 1 before including py/emitnative.c to emit correct machine code, then enable MICROPY_EMIT_NATIVE_PRELUDE_AS_BYTES_OBJ so the runtime can correctly handle the prelude being in a bytes object. --- py/emitnative.c | 30 ++++++++++++++++++++++++++++++ py/objgenerator.c | 6 ++++++ 2 files changed, 36 insertions(+) diff --git a/py/emitnative.c b/py/emitnative.c index 22bfa2c78f..f3bc8a5c48 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -48,6 +48,7 @@ #include "py/emit.h" #include "py/bc.h" +#include "py/objstr.h" #if MICROPY_DEBUG_VERBOSE // print debugging info #define DEBUG_PRINT (1) @@ -92,6 +93,7 @@ #define OFFSETOF_CODE_STATE_IP (offsetof(mp_code_state_t, ip) / sizeof(uintptr_t)) #define OFFSETOF_CODE_STATE_SP (offsetof(mp_code_state_t, sp) / sizeof(uintptr_t)) #define OFFSETOF_OBJ_FUN_BC_GLOBALS (offsetof(mp_obj_fun_bc_t, globals) / sizeof(uintptr_t)) +#define OFFSETOF_OBJ_FUN_BC_BYTECODE (offsetof(mp_obj_fun_bc_t, bytecode) / sizeof(uintptr_t)) #define OFFSETOF_OBJ_FUN_BC_CONST_TABLE (offsetof(mp_obj_fun_bc_t, const_table) / sizeof(uintptr_t)) // If not already defined, set parent args to same as child call registers @@ -333,7 +335,11 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop emit->pass = pass; emit->do_viper_types = scope->emit_options == MP_EMIT_OPT_VIPER; emit->stack_size = 0; + #if N_PRELUDE_AS_BYTES_OBJ + emit->const_table_cur_obj = emit->do_viper_types ? 0 : 1; // reserve first obj for prelude bytes obj + #else emit->const_table_cur_obj = 0; + #endif emit->const_table_cur_raw_code = 0; #if MICROPY_PERSISTENT_CODE_SAVE emit->qstr_link_cur = 0; @@ -483,7 +489,12 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) { emit->code_state_start = 0; emit->stack_start = SIZEOF_CODE_STATE; + #if N_PRELUDE_AS_BYTES_OBJ + // Load index of prelude bytes object in const_table + mp_asm_base_data(&emit->as->base, ASM_WORD_SIZE, (uintptr_t)(emit->scope->num_pos_args + emit->scope->num_kwonly_args + 1)); + #else mp_asm_base_data(&emit->as->base, ASM_WORD_SIZE, (uintptr_t)emit->prelude_offset); + #endif mp_asm_base_data(&emit->as->base, ASM_WORD_SIZE, (uintptr_t)emit->start_offset); ASM_ENTRY(emit->as, SIZEOF_NLR_BUF); @@ -528,8 +539,17 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_FUN_OBJ(emit), REG_PARENT_ARG_1); // Set code_state.ip (offset from start of this function to prelude info) + #if N_PRELUDE_AS_BYTES_OBJ + // Prelude is a bytes object in const_table; store ip = prelude->data - fun_bc->bytecode + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_LOCAL_3, emit->scope->num_pos_args + emit->scope->num_kwonly_args + 1); + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_LOCAL_3, offsetof(mp_obj_str_t, data) / sizeof(uintptr_t)); + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_PARENT_ARG_1, REG_PARENT_ARG_1, OFFSETOF_OBJ_FUN_BC_BYTECODE); + ASM_SUB_REG_REG(emit->as, REG_LOCAL_3, REG_PARENT_ARG_1); + emit_native_mov_state_reg(emit, emit->code_state_start + OFFSETOF_CODE_STATE_IP, REG_LOCAL_3); + #else // TODO this encoding may change size in the final pass, need to make it fixed emit_native_mov_state_imm_via(emit, emit->code_state_start + OFFSETOF_CODE_STATE_IP, emit->prelude_offset, REG_PARENT_ARG_1); + #endif // Set code_state.n_state (only works on little endian targets due to n_state being uint16_t) emit_native_mov_state_imm_via(emit, emit->code_state_start + offsetof(mp_code_state_t, n_state) / sizeof(uintptr_t), emit->n_state, REG_ARG_1); @@ -634,6 +654,16 @@ STATIC void emit_native_end_pass(emit_t *emit) { } } emit->n_cell = mp_asm_base_get_code_pos(&emit->as->base) - cell_start; + + #if N_PRELUDE_AS_BYTES_OBJ + // Prelude bytes object is after qstr arg names and mp_fun_table + size_t table_off = emit->scope->num_pos_args + emit->scope->num_kwonly_args + 1; + if (emit->pass == MP_PASS_EMIT) { + void *buf = emit->as->base.code_base + emit->prelude_offset; + size_t n = emit->as->base.code_offset - emit->prelude_offset; + emit->const_table[table_off] = (uintptr_t)mp_obj_new_bytes(buf, n); + } + #endif } ASM_END_PASS(emit->as); diff --git a/py/objgenerator.c b/py/objgenerator.c index 359dade888..2cfdb12f63 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -30,6 +30,7 @@ #include "py/runtime.h" #include "py/bc.h" +#include "py/objstr.h" #include "py/objgenerator.h" #include "py/objfun.h" #include "py/stackctrl.h" @@ -88,6 +89,11 @@ STATIC mp_obj_t native_gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_k // Determine start of prelude, and extract n_state from it uintptr_t prelude_offset = ((uintptr_t*)self_fun->bytecode)[0]; + #if MICROPY_EMIT_NATIVE_PRELUDE_AS_BYTES_OBJ + // Prelude is in bytes object in const_table, at index prelude_offset + mp_obj_str_t *prelude_bytes = MP_OBJ_TO_PTR(self_fun->const_table[prelude_offset]); + prelude_offset = (const byte*)prelude_bytes->data - self_fun->bytecode; + #endif const uint8_t *ip = self_fun->bytecode + prelude_offset; size_t n_state, n_exc_stack_unused, scope_flags, n_pos_args, n_kwonly_args, n_def_args; MP_BC_PRELUDE_SIG_DECODE_INTO(ip, n_state, n_exc_stack_unused, scope_flags, n_pos_args, n_kwonly_args, n_def_args); From f7ddc9416622493e6602dabf573b33b249756f8b Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 10 Sep 2019 13:46:13 +1000 Subject: [PATCH 0797/1788] py/asmxtensa: Add support for Xtensa with windowed registers. Window-specific asm emit functions are added, along with a new macro option GENERIC_ASM_API_WIN. --- py/asmxtensa.c | 38 +++++++++++++++++++----- py/asmxtensa.h | 80 ++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 105 insertions(+), 13 deletions(-) diff --git a/py/asmxtensa.c b/py/asmxtensa.c index a269e5e7fc..22ea2300a2 100644 --- a/py/asmxtensa.c +++ b/py/asmxtensa.c @@ -37,7 +37,6 @@ #define WORD_SIZE (4) #define SIGNED_FIT8(x) ((((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80)) #define SIGNED_FIT12(x) ((((x) & 0xfffff800) == 0) || (((x) & 0xfffff800) == 0xfffff800)) -#define NUM_REGS_SAVED (5) void asm_xtensa_end_pass(asm_xtensa_t *as) { as->num_const = as->cur_const; @@ -69,7 +68,7 @@ void asm_xtensa_entry(asm_xtensa_t *as, int num_locals) { as->const_table = (uint32_t*)mp_asm_base_get_cur_to_write_bytes(&as->base, as->num_const * 4); // adjust the stack-pointer to store a0, a12, a13, a14, a15 and locals, 16-byte aligned - as->stack_adjust = (((NUM_REGS_SAVED + num_locals) * WORD_SIZE) + 15) & ~15; + as->stack_adjust = (((ASM_XTENSA_NUM_REGS_SAVED + num_locals) * WORD_SIZE) + 15) & ~15; if (SIGNED_FIT8(-as->stack_adjust)) { asm_xtensa_op_addi(as, ASM_XTENSA_REG_A1, ASM_XTENSA_REG_A1, -as->stack_adjust); } else { @@ -79,14 +78,14 @@ void asm_xtensa_entry(asm_xtensa_t *as, int num_locals) { // save return value (a0) and callee-save registers (a12, a13, a14, a15) asm_xtensa_op_s32i_n(as, ASM_XTENSA_REG_A0, ASM_XTENSA_REG_A1, 0); - for (int i = 1; i < NUM_REGS_SAVED; ++i) { + for (int i = 1; i < ASM_XTENSA_NUM_REGS_SAVED; ++i) { asm_xtensa_op_s32i_n(as, ASM_XTENSA_REG_A11 + i, ASM_XTENSA_REG_A1, i); } } void asm_xtensa_exit(asm_xtensa_t *as) { // restore registers - for (int i = NUM_REGS_SAVED - 1; i >= 1; --i) { + for (int i = ASM_XTENSA_NUM_REGS_SAVED - 1; i >= 1; --i) { asm_xtensa_op_l32i_n(as, ASM_XTENSA_REG_A11 + i, ASM_XTENSA_REG_A1, i); } asm_xtensa_op_l32i_n(as, ASM_XTENSA_REG_A0, ASM_XTENSA_REG_A1, 0); @@ -102,6 +101,22 @@ void asm_xtensa_exit(asm_xtensa_t *as) { asm_xtensa_op_ret_n(as); } +void asm_xtensa_entry_win(asm_xtensa_t *as, int num_locals) { + // jump over the constants + asm_xtensa_op_j(as, as->num_const * WORD_SIZE + 4 - 4); + mp_asm_base_get_cur_to_write_bytes(&as->base, 1); // padding/alignment byte + as->const_table = (uint32_t*)mp_asm_base_get_cur_to_write_bytes(&as->base, as->num_const * 4); + + as->stack_adjust = 32 + ((((ASM_XTENSA_NUM_REGS_SAVED_WIN + num_locals) * WORD_SIZE) + 15) & ~15); + asm_xtensa_op_entry(as, ASM_XTENSA_REG_A1, as->stack_adjust); + asm_xtensa_op_s32i_n(as, ASM_XTENSA_REG_A0, ASM_XTENSA_REG_A1, 0); +} + +void asm_xtensa_exit_win(asm_xtensa_t *as) { + asm_xtensa_op_l32i_n(as, ASM_XTENSA_REG_A0, ASM_XTENSA_REG_A1, 0); + asm_xtensa_op_retw_n(as); +} + STATIC uint32_t get_label_dest(asm_xtensa_t *as, uint label) { assert(label < as->base.max_num_labels); return as->base.label_offsets[label]; @@ -178,15 +193,15 @@ void asm_xtensa_mov_reg_i32_optimised(asm_xtensa_t *as, uint reg_dest, uint32_t } void asm_xtensa_mov_local_reg(asm_xtensa_t *as, int local_num, uint reg_src) { - asm_xtensa_op_s32i(as, reg_src, ASM_XTENSA_REG_A1, NUM_REGS_SAVED + local_num); + asm_xtensa_op_s32i(as, reg_src, ASM_XTENSA_REG_A1, local_num); } void asm_xtensa_mov_reg_local(asm_xtensa_t *as, uint reg_dest, int local_num) { - asm_xtensa_op_l32i(as, reg_dest, ASM_XTENSA_REG_A1, NUM_REGS_SAVED + local_num); + asm_xtensa_op_l32i(as, reg_dest, ASM_XTENSA_REG_A1, local_num); } void asm_xtensa_mov_reg_local_addr(asm_xtensa_t *as, uint reg_dest, int local_num) { - uint off = (NUM_REGS_SAVED + local_num) * WORD_SIZE; + uint off = local_num * WORD_SIZE; if (SIGNED_FIT8(off)) { asm_xtensa_op_addi(as, reg_dest, ASM_XTENSA_REG_A1, off); } else { @@ -226,4 +241,13 @@ void asm_xtensa_call_ind(asm_xtensa_t *as, uint idx) { asm_xtensa_op_callx0(as, ASM_XTENSA_REG_A0); } +void asm_xtensa_call_ind_win(asm_xtensa_t *as, uint idx) { + if (idx < 16) { + asm_xtensa_op_l32i_n(as, ASM_XTENSA_REG_A8, ASM_XTENSA_REG_FUN_TABLE_WIN, idx); + } else { + asm_xtensa_op_l32i(as, ASM_XTENSA_REG_A8, ASM_XTENSA_REG_FUN_TABLE_WIN, idx); + } + asm_xtensa_op_callx8(as, ASM_XTENSA_REG_A8); +} + #endif // MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA diff --git a/py/asmxtensa.h b/py/asmxtensa.h index d95af14a5d..5eb40daf78 100644 --- a/py/asmxtensa.h +++ b/py/asmxtensa.h @@ -37,6 +37,16 @@ // callee save: a1, a12, a13, a14, a15 // caller save: a3 +// With windowed registers, size 8: +// - a0: return PC +// - a1: stack pointer, full descending, aligned to 16 bytes +// - a2-a7: incoming args, and essentially callee save +// - a2: return value +// - a8-a15: caller save temporaries +// - a10-a15: input args to called function +// - a10: return value of called function +// note: a0-a7 are saved automatically via window shift of called function + #define ASM_XTENSA_REG_A0 (0) #define ASM_XTENSA_REG_A1 (1) #define ASM_XTENSA_REG_A2 (2) @@ -96,6 +106,10 @@ #define ASM_XTENSA_ENCODE_RI7(op0, s, imm7) \ ((((imm7) & 0xf) << 12) | ((s) << 8) | ((imm7) & 0x70) | (op0)) +// Number of registers saved on the stack upon entry to function +#define ASM_XTENSA_NUM_REGS_SAVED (5) +#define ASM_XTENSA_NUM_REGS_SAVED_WIN (1) + typedef struct _asm_xtensa_t { mp_asm_base_t base; uint32_t cur_const; @@ -109,11 +123,18 @@ void asm_xtensa_end_pass(asm_xtensa_t *as); void asm_xtensa_entry(asm_xtensa_t *as, int num_locals); void asm_xtensa_exit(asm_xtensa_t *as); +void asm_xtensa_entry_win(asm_xtensa_t *as, int num_locals); +void asm_xtensa_exit_win(asm_xtensa_t *as); + void asm_xtensa_op16(asm_xtensa_t *as, uint16_t op); void asm_xtensa_op24(asm_xtensa_t *as, uint32_t op); // raw instructions +static inline void asm_xtensa_op_entry(asm_xtensa_t *as, uint reg_src, int32_t num_bytes) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_BRI12(6, reg_src, 0, 3, (num_bytes / 8) & 0xfff)); +} + static inline void asm_xtensa_op_add_n(asm_xtensa_t *as, uint reg_dest, uint reg_src_a, uint reg_src_b) { asm_xtensa_op16(as, ASM_XTENSA_ENCODE_RRRN(10, reg_dest, reg_src_a, reg_src_b)); } @@ -142,6 +163,10 @@ static inline void asm_xtensa_op_callx0(asm_xtensa_t *as, uint reg) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_CALLX(0, 0, 0, 0, reg, 3, 0)); } +static inline void asm_xtensa_op_callx8(asm_xtensa_t *as, uint reg) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_CALLX(0, 0, 0, 0, reg, 3, 2)); +} + static inline void asm_xtensa_op_j(asm_xtensa_t *as, int32_t rel18) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_CALL(6, 0, rel18 & 0x3ffff)); } @@ -194,6 +219,10 @@ static inline void asm_xtensa_op_ret_n(asm_xtensa_t *as) { asm_xtensa_op16(as, ASM_XTENSA_ENCODE_RRRN(13, 15, 0, 0)); } +static inline void asm_xtensa_op_retw_n(asm_xtensa_t *as) { + asm_xtensa_op16(as, ASM_XTENSA_ENCODE_RRRN(13, 15, 0, 1)); +} + static inline void asm_xtensa_op_s8i(asm_xtensa_t *as, uint reg_src, uint reg_base, uint byte_offset) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 4, reg_base, reg_src, byte_offset & 0xff)); } @@ -246,9 +275,11 @@ void asm_xtensa_mov_reg_local(asm_xtensa_t *as, uint reg_dest, int local_num); void asm_xtensa_mov_reg_local_addr(asm_xtensa_t *as, uint reg_dest, int local_num); void asm_xtensa_mov_reg_pcrel(asm_xtensa_t *as, uint reg_dest, uint label); void asm_xtensa_call_ind(asm_xtensa_t *as, uint idx); +void asm_xtensa_call_ind_win(asm_xtensa_t *as, uint idx); // Holds a pointer to mp_fun_table #define ASM_XTENSA_REG_FUN_TABLE ASM_XTENSA_REG_A15 +#define ASM_XTENSA_REG_FUN_TABLE_WIN ASM_XTENSA_REG_A7 #if GENERIC_ASM_API @@ -257,6 +288,9 @@ void asm_xtensa_call_ind(asm_xtensa_t *as, uint idx); #define ASM_WORD_SIZE (4) +#if !GENERIC_ASM_API_WIN +// Configuration for non-windowed calls + #define REG_RET ASM_XTENSA_REG_A2 #define REG_ARG_1 ASM_XTENSA_REG_A2 #define REG_ARG_2 ASM_XTENSA_REG_A3 @@ -273,12 +307,47 @@ void asm_xtensa_call_ind(asm_xtensa_t *as, uint idx); #define REG_LOCAL_3 ASM_XTENSA_REG_A14 #define REG_LOCAL_NUM (3) +#define ASM_NUM_REGS_SAVED ASM_XTENSA_NUM_REGS_SAVED #define REG_FUN_TABLE ASM_XTENSA_REG_FUN_TABLE +#define ASM_ENTRY(as, nlocal) asm_xtensa_entry((as), (nlocal)) +#define ASM_EXIT(as) asm_xtensa_exit((as)) +#define ASM_CALL_IND(as, idx) asm_xtensa_call_ind((as), (idx)) + +#else +// Configuration for windowed calls with window size 8 + +#define REG_PARENT_RET ASM_XTENSA_REG_A2 +#define REG_PARENT_ARG_1 ASM_XTENSA_REG_A2 +#define REG_PARENT_ARG_2 ASM_XTENSA_REG_A3 +#define REG_PARENT_ARG_3 ASM_XTENSA_REG_A4 +#define REG_PARENT_ARG_4 ASM_XTENSA_REG_A5 +#define REG_RET ASM_XTENSA_REG_A10 +#define REG_ARG_1 ASM_XTENSA_REG_A10 +#define REG_ARG_2 ASM_XTENSA_REG_A11 +#define REG_ARG_3 ASM_XTENSA_REG_A12 +#define REG_ARG_4 ASM_XTENSA_REG_A13 + +#define REG_TEMP0 ASM_XTENSA_REG_A10 +#define REG_TEMP1 ASM_XTENSA_REG_A11 +#define REG_TEMP2 ASM_XTENSA_REG_A12 + +#define REG_LOCAL_1 ASM_XTENSA_REG_A4 +#define REG_LOCAL_2 ASM_XTENSA_REG_A5 +#define REG_LOCAL_3 ASM_XTENSA_REG_A6 +#define REG_LOCAL_NUM (3) + +#define ASM_NUM_REGS_SAVED ASM_XTENSA_NUM_REGS_SAVED_WIN +#define REG_FUN_TABLE ASM_XTENSA_REG_FUN_TABLE_WIN + +#define ASM_ENTRY(as, nlocal) asm_xtensa_entry_win((as), (nlocal)) +#define ASM_EXIT(as) asm_xtensa_exit_win((as)) +#define ASM_CALL_IND(as, idx) asm_xtensa_call_ind_win((as), (idx)) + +#endif + #define ASM_T asm_xtensa_t #define ASM_END_PASS asm_xtensa_end_pass -#define ASM_ENTRY asm_xtensa_entry -#define ASM_EXIT asm_xtensa_exit #define ASM_JUMP asm_xtensa_j_label #define ASM_JUMP_IF_REG_ZERO(as, reg, label, bool_test) \ @@ -288,15 +357,14 @@ void asm_xtensa_call_ind(asm_xtensa_t *as, uint idx); #define ASM_JUMP_IF_REG_EQ(as, reg1, reg2, label) \ asm_xtensa_bcc_reg_reg_label(as, ASM_XTENSA_CC_EQ, reg1, reg2, label) #define ASM_JUMP_REG(as, reg) asm_xtensa_op_jx((as), (reg)) -#define ASM_CALL_IND(as, idx) asm_xtensa_call_ind((as), (idx)) -#define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_xtensa_mov_local_reg((as), (local_num), (reg_src)) +#define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_xtensa_mov_local_reg((as), ASM_NUM_REGS_SAVED + (local_num), (reg_src)) #define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_xtensa_mov_reg_i32_optimised((as), (reg_dest), (imm)) #define ASM_MOV_REG_IMM_FIX_U16(as, reg_dest, imm) asm_xtensa_mov_reg_i32((as), (reg_dest), (imm)) #define ASM_MOV_REG_IMM_FIX_WORD(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_LOCAL(as, reg_dest, local_num) asm_xtensa_mov_reg_local((as), (reg_dest), ASM_NUM_REGS_SAVED + (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_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_xtensa_mov_reg_local_addr((as), (reg_dest), (local_num)) +#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_xtensa_mov_reg_local_addr((as), (reg_dest), ASM_NUM_REGS_SAVED + (local_num)) #define ASM_MOV_REG_PCREL(as, reg_dest, label) asm_xtensa_mov_reg_pcrel((as), (reg_dest), (label)) #define ASM_LSL_REG_REG(as, reg_dest, reg_shift) \ From 9adedce42e308692ea22a1e8e1154c51c1e8173d Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 13 Sep 2019 13:15:12 +1000 Subject: [PATCH 0798/1788] py: Add new Xtensa-Windowed arch for native emitter. Enabled via the configuration MICROPY_EMIT_XTENSAWIN. --- py/asmxtensa.c | 4 ++-- py/compile.c | 4 ++++ py/emit.h | 3 +++ py/emitnative.c | 4 ++-- py/emitnxtensawin.c | 23 +++++++++++++++++++++++ py/mpconfig.h | 10 +++++++++- py/nlr.h | 1 + py/persistentcode.c | 4 +++- py/persistentcode.h | 1 + py/py.mk | 1 + tools/mpy-tool.py | 1 + 11 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 py/emitnxtensawin.c diff --git a/py/asmxtensa.c b/py/asmxtensa.c index 22ea2300a2..32e5e958a5 100644 --- a/py/asmxtensa.c +++ b/py/asmxtensa.c @@ -30,7 +30,7 @@ #include "py/mpconfig.h" // wrapper around everything in this file -#if MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA +#if MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA || MICROPY_EMIT_XTENSAWIN #include "py/asmxtensa.h" @@ -250,4 +250,4 @@ void asm_xtensa_call_ind_win(asm_xtensa_t *as, uint idx) { asm_xtensa_op_callx8(as, ASM_XTENSA_REG_A8); } -#endif // MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA +#endif // MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA || MICROPY_EMIT_XTENSAWIN diff --git a/py/compile.c b/py/compile.c index 62b0f3938d..2c818a9340 100644 --- a/py/compile.c +++ b/py/compile.c @@ -95,6 +95,7 @@ STATIC const emit_method_table_t *emit_native_table[] = { &emit_native_thumb_method_table, &emit_native_thumb_method_table, &emit_native_xtensa_method_table, + &emit_native_xtensawin_method_table, }; #elif MICROPY_EMIT_NATIVE @@ -109,6 +110,8 @@ STATIC const emit_method_table_t *emit_native_table[] = { #define NATIVE_EMITTER(f) emit_native_arm_##f #elif MICROPY_EMIT_XTENSA #define NATIVE_EMITTER(f) emit_native_xtensa_##f +#elif MICROPY_EMIT_XTENSAWIN +#define NATIVE_EMITTER(f) emit_native_xtensawin_##f #else #error "unknown native emitter" #endif @@ -131,6 +134,7 @@ STATIC const emit_inline_asm_method_table_t *emit_asm_table[] = { &emit_inline_thumb_method_table, &emit_inline_thumb_method_table, &emit_inline_xtensa_method_table, + NULL, }; #elif MICROPY_EMIT_INLINE_ASM diff --git a/py/emit.h b/py/emit.h index b3b6d755bf..26d027a7ab 100644 --- a/py/emit.h +++ b/py/emit.h @@ -174,6 +174,7 @@ extern const emit_method_table_t emit_native_x86_method_table; extern const emit_method_table_t emit_native_thumb_method_table; extern const emit_method_table_t emit_native_arm_method_table; extern const emit_method_table_t emit_native_xtensa_method_table; +extern const emit_method_table_t emit_native_xtensawin_method_table; extern const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_load_id_ops; extern const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_store_id_ops; @@ -185,6 +186,7 @@ emit_t *emit_native_x86_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t ma emit_t *emit_native_thumb_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels); emit_t *emit_native_arm_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels); emit_t *emit_native_xtensa_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels); +emit_t *emit_native_xtensawin_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels); void emit_bc_set_max_num_labels(emit_t* emit, mp_uint_t max_num_labels); @@ -194,6 +196,7 @@ void emit_native_x86_free(emit_t *emit); void emit_native_thumb_free(emit_t *emit); void emit_native_arm_free(emit_t *emit); void emit_native_xtensa_free(emit_t *emit); +void emit_native_xtensawin_free(emit_t *emit); void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope); void mp_emit_bc_end_pass(emit_t *emit); diff --git a/py/emitnative.c b/py/emitnative.c index f3bc8a5c48..e038b87785 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -58,7 +58,7 @@ #endif // wrapper around everything in this file -#if N_X64 || N_X86 || N_THUMB || N_ARM || N_XTENSA +#if N_X64 || N_X86 || N_THUMB || N_ARM || N_XTENSA || N_XTENSAWIN // C stack layout for native functions: // 0: nlr_buf_t [optional] @@ -2404,7 +2404,7 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) { ASM_ARM_CC_NE, }; asm_arm_setcc_reg(emit->as, REG_RET, ccs[op - MP_BINARY_OP_LESS]); - #elif N_XTENSA + #elif N_XTENSA || N_XTENSAWIN static uint8_t ccs[6] = { ASM_XTENSA_CC_LT, 0x80 | ASM_XTENSA_CC_LT, // for GT we'll swap args diff --git a/py/emitnxtensawin.c b/py/emitnxtensawin.c new file mode 100644 index 0000000000..38d5db13ea --- /dev/null +++ b/py/emitnxtensawin.c @@ -0,0 +1,23 @@ +// Xtensa-Windowed specific stuff + +#include "py/mpconfig.h" + +#if MICROPY_EMIT_XTENSAWIN + +// this is defined so that the assembler exports generic assembler API macros +#define GENERIC_ASM_API (1) +#define GENERIC_ASM_API_WIN (1) +#include "py/asmxtensa.h" + +// Word indices of REG_LOCAL_x in nlr_buf_t +#define NLR_BUF_IDX_LOCAL_1 (2 + 4) // a4 +#define NLR_BUF_IDX_LOCAL_2 (2 + 5) // a5 +#define NLR_BUF_IDX_LOCAL_3 (2 + 6) // a6 + +#define N_NLR_SETJMP (1) +#define N_PRELUDE_AS_BYTES_OBJ (1) +#define N_XTENSAWIN (1) +#define EXPORT_FUN(name) emit_native_xtensawin_##name +#include "py/emitnative.c" + +#endif diff --git a/py/mpconfig.h b/py/mpconfig.h index 64dadde92d..4172b5fcfe 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -323,8 +323,16 @@ #define MICROPY_EMIT_INLINE_XTENSA (0) #endif +// Whether to emit Xtensa-Windowed native code +#ifndef MICROPY_EMIT_XTENSAWIN +#define MICROPY_EMIT_XTENSAWIN (0) +#endif + // Convenience definition for whether any native emitter is enabled -#define MICROPY_EMIT_NATIVE (MICROPY_EMIT_X64 || MICROPY_EMIT_X86 || MICROPY_EMIT_THUMB || MICROPY_EMIT_ARM || MICROPY_EMIT_XTENSA) +#define MICROPY_EMIT_NATIVE (MICROPY_EMIT_X64 || MICROPY_EMIT_X86 || MICROPY_EMIT_THUMB || MICROPY_EMIT_ARM || MICROPY_EMIT_XTENSA || MICROPY_EMIT_XTENSAWIN) + +// Select prelude-as-bytes-object for certain emitters +#define MICROPY_EMIT_NATIVE_PRELUDE_AS_BYTES_OBJ (MICROPY_EMIT_XTENSAWIN) // Convenience definition for whether any inline assembler emitter is enabled #define MICROPY_EMIT_INLINE_ASM (MICROPY_EMIT_INLINE_THUMB || MICROPY_EMIT_INLINE_XTENSA) diff --git a/py/nlr.h b/py/nlr.h index 3e4b31d92b..f2453bc460 100644 --- a/py/nlr.h +++ b/py/nlr.h @@ -40,6 +40,7 @@ #define MICROPY_NLR_NUM_REGS_ARM_THUMB (10) #define MICROPY_NLR_NUM_REGS_ARM_THUMB_FP (10 + 6) #define MICROPY_NLR_NUM_REGS_XTENSA (10) +#define MICROPY_NLR_NUM_REGS_XTENSAWIN (17) // If MICROPY_NLR_SETJMP is not enabled then auto-detect the machine arch #if !MICROPY_NLR_SETJMP diff --git a/py/persistentcode.c b/py/persistentcode.c index 2109d93798..6a8a866ac5 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -71,6 +71,8 @@ #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV6) #elif MICROPY_EMIT_XTENSA #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_XTENSA) +#elif MICROPY_EMIT_XTENSAWIN +#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_XTENSAWIN) #else #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_NONE) #endif @@ -196,7 +198,7 @@ STATIC void arch_link_qstr(uint8_t *pc, bool is_obj, qstr qst) { if (is_obj) { val = (mp_uint_t)MP_OBJ_NEW_QSTR(qst); } - #if MICROPY_EMIT_X86 || MICROPY_EMIT_X64 || MICROPY_EMIT_ARM || MICROPY_EMIT_XTENSA + #if MICROPY_EMIT_X86 || MICROPY_EMIT_X64 || MICROPY_EMIT_ARM || MICROPY_EMIT_XTENSA || MICROPY_EMIT_XTENSAWIN pc[0] = val & 0xff; pc[1] = (val >> 8) & 0xff; pc[2] = (val >> 16) & 0xff; diff --git a/py/persistentcode.h b/py/persistentcode.h index 67c5f3463d..aba44ea2db 100644 --- a/py/persistentcode.h +++ b/py/persistentcode.h @@ -44,6 +44,7 @@ enum { MP_NATIVE_ARCH_ARMV7EMSP, MP_NATIVE_ARCH_ARMV7EMDP, MP_NATIVE_ARCH_XTENSA, + MP_NATIVE_ARCH_XTENSAWIN, }; mp_raw_code_t *mp_raw_code_load(mp_reader_t *reader); diff --git a/py/py.mk b/py/py.mk index d97852dd43..5669e33fcc 100644 --- a/py/py.mk +++ b/py/py.mk @@ -76,6 +76,7 @@ PY_CORE_O_BASENAME = $(addprefix py/,\ asmxtensa.o \ emitnxtensa.o \ emitinlinextensa.o \ + emitnxtensawin.o \ formatfloat.o \ parsenumbase.o \ parsenum.o \ diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index 8c0f5db18a..ab783f4184 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -102,6 +102,7 @@ MP_NATIVE_ARCH_ARMV7EM = 6 MP_NATIVE_ARCH_ARMV7EMSP = 7 MP_NATIVE_ARCH_ARMV7EMDP = 8 MP_NATIVE_ARCH_XTENSA = 9 +MP_NATIVE_ARCH_XTENSAWIN = 10 MP_BC_MASK_EXTRA_BYTE = 0x9e From 917f027c0b4bbb8170fdf529b4d4c1b2e1e5a931 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 10 Sep 2019 13:47:44 +1000 Subject: [PATCH 0799/1788] esp32: Enable native emitter. --- ports/esp32/main.c | 10 ++++++++++ ports/esp32/mpconfigport.h | 3 +++ 2 files changed, 13 insertions(+) diff --git a/ports/esp32/main.c b/ports/esp32/main.c index 7106e0bf5e..b0d1b15370 100644 --- a/ports/esp32/main.c +++ b/ports/esp32/main.c @@ -172,3 +172,13 @@ void nlr_jump_fail(void *val) { void mbedtls_debug_set_threshold(int threshold) { (void)threshold; } + +void *esp_native_code_commit(void *buf, size_t len) { + len = (len + 3) & ~3; + uint32_t *p = heap_caps_malloc(len, MALLOC_CAP_EXEC); + if (p == NULL) { + m_malloc_fail(len); + } + memcpy(p, buf, len); + return p; +} diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 1c0d8700fa..63657741ce 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -20,6 +20,9 @@ // emitters #define MICROPY_PERSISTENT_CODE_LOAD (1) +#define MICROPY_EMIT_XTENSAWIN (1) +void *esp_native_code_commit(void*, size_t); +#define MP_PLAT_COMMIT_EXEC(buf, len) esp_native_code_commit(buf, len) // compiler configuration #define MICROPY_COMP_MODULE_CONST (1) From 1d21b4e7d17fe22dc046a1bfd3251d25c013bd05 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 13 Sep 2019 13:16:00 +1000 Subject: [PATCH 0800/1788] mpy-cross: Enable Xtensa-Windowed native emitter. Selectable via the command line: -march=xtensawin. --- mpy-cross/main.c | 5 ++++- mpy-cross/mpconfigport.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/mpy-cross/main.c b/mpy-cross/main.c index be43598c5f..4a4fccb3b7 100644 --- a/mpy-cross/main.c +++ b/mpy-cross/main.c @@ -109,7 +109,7 @@ STATIC int usage(char **argv) { "-msmall-int-bits=number : set the maximum bits used to encode a small-int\n" "-mno-unicode : don't support unicode in compiled strings\n" "-mcache-lookup-bc : cache map lookups in the bytecode\n" -"-march= : set architecture for native emitter; x86, x64, armv6, armv7m, xtensa\n" +"-march= : set architecture for native emitter; x86, x64, armv6, armv7m, xtensa, xtensawin\n" "\n" "Implementation specific options:\n", argv[0] ); @@ -288,6 +288,9 @@ MP_NOINLINE int main_(int argc, char **argv) { } else if (strcmp(arch, "xtensa") == 0) { mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_XTENSA; mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_XTENSA; + } else if (strcmp(arch, "xtensawin") == 0) { + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_XTENSAWIN; + mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_XTENSAWIN; } else { return usage(argv); } diff --git a/mpy-cross/mpconfigport.h b/mpy-cross/mpconfigport.h index 3145269280..533f58aabe 100644 --- a/mpy-cross/mpconfigport.h +++ b/mpy-cross/mpconfigport.h @@ -39,6 +39,7 @@ #define MICROPY_EMIT_ARM (1) #define MICROPY_EMIT_XTENSA (1) #define MICROPY_EMIT_INLINE_XTENSA (1) +#define MICROPY_EMIT_XTENSAWIN (1) #define MICROPY_DYNAMIC_COMPILER (1) #define MICROPY_COMP_CONST_FOLDING (1) From deef6f3718bb3166eadb78f2fe32d139e4a7803e Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 1 Oct 2019 12:51:57 +1000 Subject: [PATCH 0801/1788] travis: Build unix nanbox with PYTHON=python2. To test build support with Python 2.7. --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index a72f3bc1a3..617cc2035e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -94,16 +94,16 @@ jobs: - make ${MAKEOPTS} -C ports/unix test - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython ./run-perfbench.py 1000 1000) - # unix nanbox + # unix nanbox (and using Python 2 to check it can run the build scripts) - stage: test env: NAME="unix nanbox port build and tests" install: - sudo apt-get install gcc-multilib libffi-dev:i386 script: - git submodule update --init lib/axtls lib/berkeley-db-1.xx lib/libffi - - make ${MAKEOPTS} -C mpy-cross - - make ${MAKEOPTS} -C ports/unix deplibs - - make ${MAKEOPTS} -C ports/unix nanbox + - make ${MAKEOPTS} -C mpy-cross PYTHON=python2 + - make ${MAKEOPTS} -C ports/unix PYTHON=python2 deplibs + - make ${MAKEOPTS} -C ports/unix PYTHON=python2 nanbox - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_nanbox ./run-tests) # unix stackless From a0ce01f62e4e5f8103ab3e607f90fe931e866892 Mon Sep 17 00:00:00 2001 From: Martin Fischer Date: Thu, 3 Oct 2019 22:30:20 +0200 Subject: [PATCH 0802/1788] stm32/usbdev: Fix compile error if MICROPY_HW_USB_CDC_NUM is set to 2. Fixes regression introduced by 6705767da1f7dba7a04e1d16c380a650f1f1074f --- ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c | 1 - 1 file changed, 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 0b94076543..5e24730a0f 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -556,7 +556,6 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode n += make_hid_desc_ep(d + n, hid_info, HID_IFACE_NUM_WITH_CDC2_MSC, HID_IN_EP_WITH_CDC2_MSC, HID_OUT_EP_WITH_CDC2_MSC); usbd->cdc[0]->iface_num = CDC_IFACE_NUM_WITH_MSC; usbd->cdc[1]->iface_num = CDC2_IFACE_NUM_WITH_MSC; - usbd->cdc[2]->iface_num = CDC3_IFACE_NUM_WITH_MSC; usbd->hid->in_ep = HID_IN_EP_WITH_CDC2_MSC; usbd->hid->out_ep = HID_OUT_EP_WITH_CDC2_MSC; usbd->hid->iface_num = HID_IFACE_NUM_WITH_CDC2_MSC; From 4a6974bea598a9b76c4a49afcc0d6f82760a7006 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 5 Oct 2019 23:51:33 +1000 Subject: [PATCH 0803/1788] stm32/boards/PYBD_SF2: Put nimble library in external QSPI XIP flash. The BLE stack is not performance critical, so put it in external memory-mapped flash to save internal flash for other things (like frozen bytecode). --- ports/stm32/boards/PYBD_SF2/f722_qspi.ld | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/stm32/boards/PYBD_SF2/f722_qspi.ld b/ports/stm32/boards/PYBD_SF2/f722_qspi.ld index 554d34b492..b55bfe95fb 100644 --- a/ports/stm32/boards/PYBD_SF2/f722_qspi.ld +++ b/ports/stm32/boards/PYBD_SF2/f722_qspi.ld @@ -49,6 +49,7 @@ SECTIONS { . = ALIGN(4); *lib/mbedtls/*(.text* .rodata*) + *lib/mynewt-nimble/*(.text* .rodata*) . = ALIGN(512); *(.big_const*) . = ALIGN(4); From 902bb4ceae6ca3a8379df35f12ccffc0b492d950 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 1 Oct 2019 23:46:53 +1000 Subject: [PATCH 0804/1788] stm32: Extract port-specific Nimble implementation. On other ports (e.g. ESP32) they provide a complete Nimble implementation (i.e. we don't need to use the code in extmod/nimble). This change extracts out the bits that we don't need to use in other ports: - malloc/free/realloc for Nimble memory. - pendsv poll handler - depowering the cywbt Also cleans up the root pointer management. --- extmod/modbluetooth_nimble.c | 214 +++++++++------------------------- extmod/modbluetooth_nimble.h | 54 +++++++++ extmod/nimble/nimble/npl_os.c | 80 +++++++++++++ ports/stm32/Makefile | 1 + ports/stm32/mpconfigport.h | 3 +- ports/stm32/nimble.c | 82 +++++++++++++ 6 files changed, 274 insertions(+), 160 deletions(-) create mode 100644 extmod/modbluetooth_nimble.h create mode 100644 ports/stm32/nimble.c diff --git a/extmod/modbluetooth_nimble.c b/extmod/modbluetooth_nimble.c index 959360cee7..1e7211bfe8 100644 --- a/extmod/modbluetooth_nimble.c +++ b/extmod/modbluetooth_nimble.c @@ -28,25 +28,22 @@ #include "py/runtime.h" #include "py/mperrno.h" #include "py/mphal.h" -#include "systick.h" -#include "pendsv.h" #if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE -#ifndef MICROPY_PY_BLUETOOTH_DEFAULT_NAME -#define MICROPY_PY_BLUETOOTH_DEFAULT_NAME "PYBD" -#endif - -#include "extmod/modbluetooth.h" +#include "modbluetooth_nimble.h" +#include "modbluetooth.h" #include "host/ble_hs.h" #include "host/util/util.h" #include "nimble/ble.h" #include "nimble/nimble_port.h" #include "services/gap/ble_svc_gap.h" -#include "transport/uart/ble_hci_uart.h" -#define DEBUG_MALLOC_printf(...) //printf(__VA_ARGS__) +#ifndef MICROPY_PY_BLUETOOTH_DEFAULT_NAME +#define MICROPY_PY_BLUETOOTH_DEFAULT_NAME "PYBD" +#endif + #define DEBUG_EVENT_printf(...) //printf(__VA_ARGS__) STATIC int8_t ble_hs_err_to_errno_table[] = { @@ -90,82 +87,6 @@ STATIC int ble_hs_err_to_errno(int err) { } } -// Maintain a linked list of heap memory that we've passed to Nimble, -// discoverable via the bluetooth_nimble_memory root pointer. - -// MP_STATE_PORT(bluetooth_nimble_memory) is a pointer to [next, prev, data...]. - -// TODO: This is duplicated from mbedtls. Perhaps make this a generic feature? -void *m_malloc_bluetooth(size_t size) { - void **ptr = m_malloc0(size + 2 * sizeof(uintptr_t)); - if (MP_STATE_PORT(bluetooth_nimble_memory) != NULL) { - MP_STATE_PORT(bluetooth_nimble_memory)[0] = ptr; - } - ptr[0] = NULL; - ptr[1] = MP_STATE_PORT(bluetooth_nimble_memory); - MP_STATE_PORT(bluetooth_nimble_memory) = ptr; - return &ptr[2]; -} - -#define m_new_bluetooth(type, num) ((type*)m_malloc_bluetooth(sizeof(type) * (num))) - -void m_free_bluetooth(void *ptr_in) { - void **ptr = &((void**)ptr_in)[-2]; - if (ptr[1] != NULL) { - ((void**)ptr[1])[0] = ptr[0]; - } - if (ptr[0] != NULL) { - ((void**)ptr[0])[1] = ptr[1]; - } else { - MP_STATE_PORT(bluetooth_nimble_memory) = ptr[1]; - } - m_free(ptr); -} - -// Check if a nimble ptr is tracked. -// If it isn't, that means that it's from a previous soft-reset cycle. -STATIC bool is_valid_nimble_malloc(void *ptr) { - DEBUG_MALLOC_printf("NIMBLE is_valid_nimble_malloc(%p)\n", ptr); - void** search = MP_STATE_PORT(bluetooth_nimble_memory); - while (search) { - if (&search[2] == ptr) { - return true; - } - - search = (void**)search[1]; - } - return false; -} - -void *nimble_malloc(size_t size) { - DEBUG_MALLOC_printf("NIMBLE malloc(%u)\n", (uint)size); - void* ptr = m_malloc_bluetooth(size); - DEBUG_MALLOC_printf(" --> %p\n", ptr); - return ptr; -} - -// Only free if it's still a valid pointer. -void nimble_free(void *ptr) { - DEBUG_MALLOC_printf("NIMBLE free(%p)\n", ptr); - if (ptr && is_valid_nimble_malloc(ptr)) { - m_free_bluetooth(ptr); - } -} - -// Only realloc if it's still a valid pointer. Otherwise just malloc. -void *nimble_realloc(void *ptr, size_t size) { - // This is only used by ble_gatts.c to grow the queue of pending services to be registered. - DEBUG_MALLOC_printf("NIMBLE realloc(%p, %u)\n", ptr, (uint)size); - void *ptr2 = nimble_malloc(size); - if (ptr && is_valid_nimble_malloc(ptr)) { - // If it's a realloc and we still have the old data, then copy it. - // This will happen as we add services. - memcpy(ptr2, ptr, size); - m_free_bluetooth(ptr); - } - return ptr2; -} - STATIC ble_uuid_t* create_nimble_uuid(const mp_obj_bluetooth_uuid_t *uuid) { if (uuid->type == MP_BLUETOOTH_UUID_TYPE_16) { ble_uuid16_t *result = m_new(ble_uuid16_t, 1); @@ -227,50 +148,13 @@ STATIC ble_addr_t create_nimble_addr(uint8_t addr_type, const uint8_t *addr) { #endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE -STATIC mp_map_t *gatts_db = MP_OBJ_NULL; - typedef struct { uint8_t *data; size_t data_alloc; size_t data_len; } gatts_db_entry_t; -/******************************************************************************/ -// RUN LOOP - -enum { - BLE_STATE_OFF, - BLE_STATE_STARTING, - BLE_STATE_ACTIVE, -}; - -static volatile int ble_state = BLE_STATE_OFF; - -extern void nimble_uart_process(void); -extern void os_eventq_run_all(void); -extern void os_callout_process(void); - -// Hook for pendsv poller to run this periodically every 128ms -#define NIMBLE_TICK(tick) (((tick) & ~(SYSTICK_DISPATCH_NUM_SLOTS - 1) & 0x7f) == 0) - -void nimble_poll(void) { - if (ble_state == BLE_STATE_OFF) { - return; - } - - nimble_uart_process(); - os_callout_process(); - os_eventq_run_all(); -} - -void mod_bluetooth_nimble_poll_wrapper(uint32_t ticks_ms) { - if (NIMBLE_TICK(ticks_ms)) { - pendsv_schedule_dispatch(PENDSV_DISPATCH_NIMBLE, nimble_poll); - } -} - -/******************************************************************************/ -// BINDINGS +volatile int mp_bluetooth_nimble_ble_state = MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF; STATIC void reset_cb(int reason) { (void)reason; @@ -308,11 +192,11 @@ STATIC void sync_cb(void) { ble_svc_gap_device_name_set(MICROPY_PY_BLUETOOTH_DEFAULT_NAME); - ble_state = BLE_STATE_ACTIVE; + mp_bluetooth_nimble_ble_state = MP_BLUETOOTH_NIMBLE_BLE_STATE_ACTIVE; } STATIC void create_gatts_db_entry(uint16_t handle) { - mp_map_elem_t *elem = mp_map_lookup(gatts_db, MP_OBJ_NEW_SMALL_INT(handle), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); + mp_map_elem_t *elem = mp_map_lookup(MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db, MP_OBJ_NEW_SMALL_INT(handle), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); gatts_db_entry_t *entry = m_new(gatts_db_entry_t, 1); entry->data = m_new(uint8_t, MP_BLUETOOTH_MAX_ATTR_SIZE); entry->data_alloc = MP_BLUETOOTH_MAX_ATTR_SIZE; @@ -390,27 +274,27 @@ int mp_bluetooth_init(void) { // Clean up if necessary. mp_bluetooth_deinit(); - MP_STATE_PORT(bluetooth_nimble_memory) = NULL; - ble_hs_cfg.reset_cb = reset_cb; ble_hs_cfg.sync_cb = sync_cb; ble_hs_cfg.gatts_register_cb = gatts_register_cb; ble_hs_cfg.store_status_cb = ble_store_util_status_rr; - gatts_db = m_new_bluetooth(mp_map_t, 1); + MP_STATE_PORT(bluetooth_nimble_root_pointers) = m_new0(mp_bluetooth_nimble_root_pointers_t, 1); + MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db = m_new(mp_map_t, 1); - ble_hci_uart_init(); + mp_bluetooth_nimble_ble_state = MP_BLUETOOTH_NIMBLE_BLE_STATE_STARTING; + + mp_bluetooth_nimble_port_preinit(); nimble_port_init(); + mp_bluetooth_nimble_port_postinit(); // By default, just register the default gap service. ble_svc_gap_init(); - ble_state = BLE_STATE_STARTING; - - ble_hs_start(); + mp_bluetooth_nimble_port_start(); // Wait for sync callback - while (ble_state != BLE_STATE_ACTIVE) { + while (mp_bluetooth_nimble_ble_state != MP_BLUETOOTH_NIMBLE_BLE_STATE_ACTIVE) { MICROPY_EVENT_POLL_HOOK } @@ -419,13 +303,13 @@ int mp_bluetooth_init(void) { // Called when the host stop procedure has completed. STATIC void ble_hs_shutdown_stop_cb(int status, void *arg) { - ble_state = BLE_STATE_OFF; + mp_bluetooth_nimble_ble_state = MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF; } STATIC struct ble_hs_stop_listener ble_hs_shutdown_stop_listener; void mp_bluetooth_deinit(void) { - if (ble_state == BLE_STATE_OFF) { + if (mp_bluetooth_nimble_ble_state == MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF) { return; } @@ -434,25 +318,27 @@ void mp_bluetooth_deinit(void) { mp_bluetooth_gap_scan_stop(); #endif - ble_hs_stop(&ble_hs_shutdown_stop_listener, ble_hs_shutdown_stop_cb, - NULL); + ble_hs_stop(&ble_hs_shutdown_stop_listener, ble_hs_shutdown_stop_cb, NULL); - while (ble_state != BLE_STATE_OFF) { + while (mp_bluetooth_nimble_ble_state != MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF) { MICROPY_EVENT_POLL_HOOK } - // TODO: This should be a port-specific hook. - #ifdef pyb_pin_BT_REG_ON - mp_hal_pin_low(pyb_pin_BT_REG_ON); - #endif + mp_bluetooth_nimble_port_deinit(); + + MP_STATE_PORT(bluetooth_nimble_root_pointers) = NULL; } bool mp_bluetooth_is_enabled(void) { - return ble_state == BLE_STATE_ACTIVE; + return mp_bluetooth_nimble_ble_state == MP_BLUETOOTH_NIMBLE_BLE_STATE_ACTIVE; } void mp_bluetooth_get_device_addr(uint8_t *addr) { + #if MICROPY_PY_BLUETOOTH_RANDOM_ADDR + ble_hs_id_copy_addr(BLE_ADDR_RANDOM, addr, NULL); + #else mp_hal_get_mac(MP_HAL_MAC_BDADDR, addr); + #endif } int mp_bluetooth_gap_advertise_start(bool connectable, uint16_t interval_ms, const uint8_t *adv_data, size_t adv_data_len, const uint8_t *sr_data, size_t sr_data_len) { @@ -528,7 +414,7 @@ static int characteristic_access_cb(uint16_t conn_handle, uint16_t value_handle, } #endif - elem = mp_map_lookup(gatts_db, MP_OBJ_NEW_SMALL_INT(value_handle), MP_MAP_LOOKUP); + elem = mp_map_lookup(MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db, MP_OBJ_NEW_SMALL_INT(value_handle), MP_MAP_LOOKUP); if (!elem) { return BLE_ATT_ERR_ATTR_NOT_FOUND; } @@ -539,7 +425,7 @@ static int characteristic_access_cb(uint16_t conn_handle, uint16_t value_handle, return 0; case BLE_GATT_ACCESS_OP_WRITE_CHR: case BLE_GATT_ACCESS_OP_WRITE_DSC: - elem = mp_map_lookup(gatts_db, MP_OBJ_NEW_SMALL_INT(value_handle), MP_MAP_LOOKUP); + elem = mp_map_lookup(MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db, MP_OBJ_NEW_SMALL_INT(value_handle), MP_MAP_LOOKUP); if (!elem) { return BLE_ATT_ERR_ATTR_NOT_FOUND; } @@ -561,11 +447,13 @@ int mp_bluetooth_gatts_register_service_begin(bool reset) { } // Reset the gatt characteristic value db. - mp_map_init(gatts_db, 0); + mp_map_init(MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db, 0); // By default, just register the default gap service. ble_svc_gap_init(); + MP_STATE_PORT(bluetooth_nimble_root_pointers)->n_services = 0; + return 0; } @@ -575,16 +463,22 @@ int mp_bluetooth_gatts_register_service_end() { return ble_hs_err_to_errno(ret); } + for (int i = 0; i < MP_STATE_PORT(bluetooth_nimble_root_pointers)->n_services; ++i) { + MP_STATE_PORT(bluetooth_nimble_root_pointers)->services[i] = NULL; + } + MP_STATE_PORT(bluetooth_nimble_root_pointers)->n_services = 0; + return 0; } int mp_bluetooth_gatts_register_service(mp_obj_bluetooth_uuid_t *service_uuid, mp_obj_bluetooth_uuid_t **characteristic_uuids, uint8_t *characteristic_flags, mp_obj_bluetooth_uuid_t **descriptor_uuids, uint8_t *descriptor_flags, uint8_t *num_descriptors, uint16_t *handles, size_t num_characteristics) { - // TODO: These allocs need to last until mp_bluetooth_gatts_register_service_end. - // Using m_new_bluetooth means they get leaked, but m_new would mean that they wouldn't be findable by GC. + if (MP_STATE_PORT(bluetooth_nimble_root_pointers)->n_services == MP_BLUETOOTH_NIMBLE_MAX_SERVICES) { + return MP_E2BIG; + } size_t handle_index = 0; size_t descriptor_index = 0; - struct ble_gatt_chr_def *characteristics = m_new_bluetooth(struct ble_gatt_chr_def, num_characteristics + 1); + struct ble_gatt_chr_def *characteristics = m_new(struct ble_gatt_chr_def, num_characteristics + 1); for (size_t i = 0; i < num_characteristics; ++i) { characteristics[i].uuid = create_nimble_uuid(characteristic_uuids[i]); characteristics[i].access_cb = characteristic_access_cb; @@ -597,7 +491,7 @@ int mp_bluetooth_gatts_register_service(mp_obj_bluetooth_uuid_t *service_uuid, m if (num_descriptors[i] == 0) { characteristics[i].descriptors = NULL; } else { - struct ble_gatt_dsc_def *descriptors = m_new_bluetooth(struct ble_gatt_dsc_def, num_descriptors[i] + 1); + struct ble_gatt_dsc_def *descriptors = m_new(struct ble_gatt_dsc_def, num_descriptors[i] + 1); for (size_t j = 0; j < num_descriptors[i]; ++j) { descriptors[j].uuid = create_nimble_uuid(descriptor_uuids[descriptor_index]); @@ -616,13 +510,15 @@ int mp_bluetooth_gatts_register_service(mp_obj_bluetooth_uuid_t *service_uuid, m } characteristics[num_characteristics].uuid = NULL; // no more characteristics - struct ble_gatt_svc_def *service = m_new_bluetooth(struct ble_gatt_svc_def, 2); + struct ble_gatt_svc_def *service = m_new(struct ble_gatt_svc_def, 2); service[0].type = BLE_GATT_SVC_TYPE_PRIMARY; service[0].uuid = create_nimble_uuid(service_uuid); service[0].includes = NULL; service[0].characteristics = characteristics; service[1].type = 0; // no more services + MP_STATE_PORT(bluetooth_nimble_root_pointers)->services[MP_STATE_PORT(bluetooth_nimble_root_pointers)->n_services++] = service; + // Note: advertising must be stopped for gatts registration to work int ret = ble_gatts_count_cfg(service); @@ -643,7 +539,7 @@ int mp_bluetooth_gap_disconnect(uint16_t conn_handle) { } int mp_bluetooth_gatts_read(uint16_t value_handle, uint8_t **value, size_t *value_len) { - mp_map_elem_t *elem = mp_map_lookup(gatts_db, MP_OBJ_NEW_SMALL_INT(value_handle), MP_MAP_LOOKUP); + mp_map_elem_t *elem = mp_map_lookup(MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db, MP_OBJ_NEW_SMALL_INT(value_handle), MP_MAP_LOOKUP); if (!elem) { return MP_EINVAL; } @@ -654,7 +550,7 @@ int mp_bluetooth_gatts_read(uint16_t value_handle, uint8_t **value, size_t *valu } int mp_bluetooth_gatts_write(uint16_t value_handle, const uint8_t *value, size_t value_len) { - mp_map_elem_t *elem = mp_map_lookup(gatts_db, MP_OBJ_NEW_SMALL_INT(value_handle), MP_MAP_LOOKUP); + mp_map_elem_t *elem = mp_map_lookup(MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db, MP_OBJ_NEW_SMALL_INT(value_handle), MP_MAP_LOOKUP); if (!elem) { return MP_EINVAL; } @@ -693,7 +589,7 @@ int mp_bluetooth_gatts_indicate(uint16_t conn_handle, uint16_t value_handle) { #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE STATIC int gap_scan_cb(struct ble_gap_event *event, void *arg) { - DEBUG_EVENT_printf("gap_scan_cb: event=%d\n", event->type); + DEBUG_EVENT_printf("gap_scan_cb: event=%d type=%d\n", event->type, event->disc ? event->disc.event_type : -1); if (event->type == BLE_GAP_EVENT_DISC_COMPLETE) { mp_bluetooth_gap_on_scan_complete(); @@ -704,9 +600,6 @@ STATIC int gap_scan_cb(struct ble_gap_event *event, void *arg) { return 0; } - DEBUG_EVENT_printf(" --> type %d\n", event->disc.event_type); - - if (event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_ADV_IND || event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_NONCONN_IND) { bool connectable = event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_ADV_IND; uint8_t addr[6]; @@ -821,8 +714,7 @@ int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, } STATIC int peripheral_discover_service_cb(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *service, void *arg) { - DEBUG_EVENT_printf("peripheral_discover_service_cb: conn_handle=%d status=%d start_handle=%d\n", conn_handle, error->status, service->start_handle); - // TODO: Find out what error->status == 14 means (probably "end of services"). + DEBUG_EVENT_printf("peripheral_discover_service_cb: conn_handle=%d status=%d start_handle=%d\n", conn_handle, error->status, service ? service->start_handle : -1); if (error->status == 0) { mp_obj_bluetooth_uuid_t service_uuid = create_mp_uuid(&service->uuid); mp_bluetooth_gattc_on_primary_service_result(conn_handle, service->start_handle, service->end_handle, &service_uuid); @@ -836,6 +728,7 @@ int mp_bluetooth_gattc_discover_primary_services(uint16_t conn_handle) { } STATIC int ble_gatt_characteristic_cb(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_chr *characteristic, void *arg) { + DEBUG_EVENT_printf("ble_gatt_characteristic_cb: conn_handle=%d status=%d def_handle=%d val_handle=%d\n", conn_handle, error->status, characteristic ? characteristic->def_handle : -1, characteristic ? characteristic->val_handle : -1); if (error->status == 0) { mp_obj_bluetooth_uuid_t characteristic_uuid = create_mp_uuid(&characteristic->uuid); mp_bluetooth_gattc_on_characteristic_result(conn_handle, characteristic->def_handle, characteristic->val_handle, characteristic->properties, &characteristic_uuid); @@ -849,6 +742,7 @@ int mp_bluetooth_gattc_discover_characteristics(uint16_t conn_handle, uint16_t s } STATIC int ble_gatt_descriptor_cb(uint16_t conn_handle, const struct ble_gatt_error *error, uint16_t characteristic_val_handle, const struct ble_gatt_dsc *descriptor, void *arg) { + DEBUG_EVENT_printf("ble_gatt_descriptor_cb: conn_handle=%d status=%d chr_handle=%d dsc_handle=%d\n", conn_handle, error->status, characteristic_val_handle, descriptor ? descriptor->handle : -1); if (error->status == 0) { mp_obj_bluetooth_uuid_t descriptor_uuid = create_mp_uuid(&descriptor->uuid); mp_bluetooth_gattc_on_descriptor_result(conn_handle, descriptor->handle, &descriptor_uuid); @@ -862,6 +756,7 @@ int mp_bluetooth_gattc_discover_descriptors(uint16_t conn_handle, uint16_t start } STATIC int ble_gatt_attr_read_cb(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) { + DEBUG_EVENT_printf("ble_gatt_attr_read_cb: conn_handle=%d status=%d handle=%d\n", conn_handle, error->status, attr ? attr->handle : -1); // TODO: Maybe send NULL if error->status non-zero. if (error->status == 0) { uint8_t buf[MP_BLUETOOTH_MAX_ATTR_SIZE]; @@ -879,6 +774,7 @@ int mp_bluetooth_gattc_read(uint16_t conn_handle, uint16_t value_handle) { } STATIC int ble_gatt_attr_write_cb(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) { + DEBUG_EVENT_printf("ble_gatt_attr_write_cb: conn_handle=%d status=%d handle=%d\n", conn_handle, error->status, attr ? attr->handle : -1); mp_bluetooth_gattc_on_write_status(conn_handle, attr->handle, error->status); return 0; } diff --git a/extmod/modbluetooth_nimble.h b/extmod/modbluetooth_nimble.h new file mode 100644 index 0000000000..e2474a6ee5 --- /dev/null +++ b/extmod/modbluetooth_nimble.h @@ -0,0 +1,54 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Jim Mussared + * + * 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_MODBLUETOOTH_NIMBLE_H +#define MICROPY_INCLUDED_EXTMOD_MODBLUETOOTH_NIMBLE_H + +#define MP_BLUETOOTH_NIMBLE_MAX_SERVICES (8) + +typedef struct _mp_bluetooth_nimble_root_pointers_t { + // Characteristic (and descriptor) value storage. + mp_map_t *gatts_db; + + // Pending service definitions. + size_t n_services; + struct ble_gatt_svc_def *services[MP_BLUETOOTH_NIMBLE_MAX_SERVICES]; +} mp_bluetooth_nimble_root_pointers_t; + +enum { + MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF, + MP_BLUETOOTH_NIMBLE_BLE_STATE_STARTING, + MP_BLUETOOTH_NIMBLE_BLE_STATE_ACTIVE, +}; + +extern volatile int mp_bluetooth_nimble_ble_state; + +void mp_bluetooth_nimble_port_preinit(void); +void mp_bluetooth_nimble_port_postinit(void); +void mp_bluetooth_nimble_port_deinit(void); +void mp_bluetooth_nimble_port_start(void); + +#endif // MICROPY_INCLUDED_EXTMOD_MODBLUETOOTH_NIMBLE_H diff --git a/extmod/nimble/nimble/npl_os.c b/extmod/nimble/nimble/npl_os.c index 0f852c8780..4875d2d1ad 100644 --- a/extmod/nimble/nimble/npl_os.c +++ b/extmod/nimble/nimble/npl_os.c @@ -26,9 +26,12 @@ #include #include "py/mphal.h" +#include "py/runtime.h" +#include "nimble/ble.h" #include "nimble/nimble_npl.h" #define DEBUG_OS_printf(...) //printf(__VA_ARGS__) +#define DEBUG_MALLOC_printf(...) //printf(__VA_ARGS__) #define DEBUG_EVENT_printf(...) //printf(__VA_ARGS__) #define DEBUG_MUTEX_printf(...) //printf(__VA_ARGS__) #define DEBUG_SEM_printf(...) //printf(__VA_ARGS__) @@ -46,6 +49,83 @@ void *ble_npl_get_current_task_id(void) { return NULL; } +/******************************************************************************/ +// malloc + +// Maintain a linked list of heap memory that we've passed to Nimble, +// discoverable via the bluetooth_nimble_memory root pointer. + +// MP_STATE_PORT(bluetooth_nimble_memory) is a pointer to [next, prev, data...]. + +// TODO: This is duplicated from mbedtls. Perhaps make this a generic feature? +void *m_malloc_bluetooth(size_t size) { + void **ptr = m_malloc0(size + 2 * sizeof(uintptr_t)); + if (MP_STATE_PORT(bluetooth_nimble_memory) != NULL) { + MP_STATE_PORT(bluetooth_nimble_memory)[0] = ptr; + } + ptr[0] = NULL; + ptr[1] = MP_STATE_PORT(bluetooth_nimble_memory); + MP_STATE_PORT(bluetooth_nimble_memory) = ptr; + return &ptr[2]; +} + +void m_free_bluetooth(void *ptr_in) { + void **ptr = &((void**)ptr_in)[-2]; + if (ptr[1] != NULL) { + ((void**)ptr[1])[0] = ptr[0]; + } + if (ptr[0] != NULL) { + ((void**)ptr[0])[1] = ptr[1]; + } else { + MP_STATE_PORT(bluetooth_nimble_memory) = ptr[1]; + } + m_free(ptr); +} + +// Check if a nimble ptr is tracked. +// If it isn't, that means that it's from a previous soft-reset cycle. +STATIC bool is_valid_nimble_malloc(void *ptr) { + DEBUG_MALLOC_printf("NIMBLE is_valid_nimble_malloc(%p)\n", ptr); + void** search = MP_STATE_PORT(bluetooth_nimble_memory); + while (search) { + if (&search[2] == ptr) { + return true; + } + + search = (void**)search[1]; + } + return false; +} + +void *nimble_malloc(size_t size) { + DEBUG_MALLOC_printf("NIMBLE malloc(%u)\n", (uint)size); + void* ptr = m_malloc_bluetooth(size); + DEBUG_MALLOC_printf(" --> %p\n", ptr); + return ptr; +} + +// Only free if it's still a valid pointer. +void nimble_free(void *ptr) { + DEBUG_MALLOC_printf("NIMBLE free(%p)\n", ptr); + if (ptr && is_valid_nimble_malloc(ptr)) { + m_free_bluetooth(ptr); + } +} + +// Only realloc if it's still a valid pointer. Otherwise just malloc. +void *nimble_realloc(void *ptr, size_t size) { + // This is only used by ble_gatts.c to grow the queue of pending services to be registered. + DEBUG_MALLOC_printf("NIMBLE realloc(%p, %u)\n", ptr, (uint)size); + void *ptr2 = nimble_malloc(size); + if (ptr && is_valid_nimble_malloc(ptr)) { + // If it's a realloc and we still have the old data, then copy it. + // This will happen as we add services. + memcpy(ptr2, ptr, size); + m_free_bluetooth(ptr); + } + return ptr2; +} + /******************************************************************************/ // EVENTQ diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 40db2f7560..1a4e3c6902 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -436,6 +436,7 @@ endif ifeq ($(MICROPY_BLUETOOTH_NIMBLE),1) include $(TOP)/extmod/nimble/nimble.mk +SRC_C += nimble.c SRC_C += nimble_hci_uart.c EXTMOD_SRC_C += extmod/modbluetooth_nimble.c ifeq ($(MICROPY_PY_NETWORK_CYW43),1) diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 54e1c503c4..5806755116 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -298,7 +298,8 @@ extern const struct _mp_obj_module_t mp_module_onewire; #endif #if MICROPY_BLUETOOTH_NIMBLE -#define MICROPY_PORT_ROOT_POINTER_BLUETOOTH_NIMBLE void **bluetooth_nimble_memory; +struct _mp_bluetooth_nimble_root_pointers_t; +#define MICROPY_PORT_ROOT_POINTER_BLUETOOTH_NIMBLE void **bluetooth_nimble_memory; struct _mp_bluetooth_nimble_root_pointers_t *bluetooth_nimble_root_pointers; #else #define MICROPY_PORT_ROOT_POINTER_BLUETOOTH_NIMBLE #endif diff --git a/ports/stm32/nimble.c b/ports/stm32/nimble.c new file mode 100644 index 0000000000..b8fdc8f886 --- /dev/null +++ b/ports/stm32/nimble.c @@ -0,0 +1,82 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Jim Mussared + * + * 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 "py/mphal.h" + +#if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE + +#include "systick.h" +#include "pendsv.h" + +#include "transport/uart/ble_hci_uart.h" +#include "host/ble_hs.h" + +#include "extmod/modbluetooth_nimble.h" + +extern void nimble_uart_process(void); +extern void os_eventq_run_all(void); +extern void os_callout_process(void); + +// Hook for pendsv poller to run this periodically every 128ms +#define NIMBLE_TICK(tick) (((tick) & ~(SYSTICK_DISPATCH_NUM_SLOTS - 1) & 0x7f) == 0) + +void nimble_poll(void) { + if (mp_bluetooth_nimble_ble_state == MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF) { + return; + } + + nimble_uart_process(); + os_callout_process(); + os_eventq_run_all(); +} + +void mod_bluetooth_nimble_poll_wrapper(uint32_t ticks_ms) { + if (NIMBLE_TICK(ticks_ms)) { + pendsv_schedule_dispatch(PENDSV_DISPATCH_NIMBLE, nimble_poll); + } +} + +void mp_bluetooth_nimble_port_preinit(void) { + MP_STATE_PORT(bluetooth_nimble_memory) = NULL; + ble_hci_uart_init(); +} + +void mp_bluetooth_nimble_port_postinit(void) { +} + +void mp_bluetooth_nimble_port_deinit(void) { + #ifdef pyb_pin_BT_REG_ON + mp_hal_pin_low(pyb_pin_BT_REG_ON); + #endif +} + +void mp_bluetooth_nimble_port_start(void) { + ble_hs_start(); +} + +#endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE From 6a9bd1c1aba9f80844c0af96a73319797c6e81b8 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 1 Oct 2019 23:47:37 +1000 Subject: [PATCH 0805/1788] esp32: Implement BLE using Nimble from IDF 4.x. --- ports/esp32/Makefile | 65 ++++++++++++++++++++++++++++++++ ports/esp32/boards/sdkconfig.ble | 6 +++ ports/esp32/mpconfigport.h | 18 +++++++++ ports/esp32/nimble.c | 57 ++++++++++++++++++++++++++++ 4 files changed, 146 insertions(+) create mode 100644 ports/esp32/boards/sdkconfig.ble create mode 100644 ports/esp32/nimble.c diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 919a047eb6..f059536af9 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -174,6 +174,29 @@ INC_ESPCOMP += -I$(ESPCOMP)/spi_flash/private_include INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/include/esp_supplicant INC_ESPCOMP += -I$(ESPCOMP)/xtensa/include INC_ESPCOMP += -I$(ESPCOMP)/xtensa/esp32/include +ifeq ($(CONFIG_BT_NIMBLE_ENABLED),y) +INC_ESPCOMP += -I$(ESPCOMP)/bt/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/common/osi/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/common/btc/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/common/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/porting/nimble/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/port/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/ans/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/bas/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/gap/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/gatt/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/ias/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/lls/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/tps/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/util/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/store/ram/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/store/config/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/porting/npl/freertos/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/ext/tinycrypt/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/esp-hci/include +endif else INC_ESPCOMP += -I$(ESPCOMP)/ethernet/include INC_ESPCOMP += -I$(ESPCOMP)/expat/expat/expat/lib @@ -185,6 +208,17 @@ INC_ESPCOMP += -I$(ESPCOMP)/nghttp/port/include INC_ESPCOMP += -I$(ESPCOMP)/nghttp/nghttp2/lib/includes endif +ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) +ifeq ($(MICROPY_PY_BLUETOOTH),1) +CFLAGS_MOD += -DMICROPY_PY_BLUETOOTH=1 +CFLAGS_MOD += -DMICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE=1 + +ifeq ($(MICROPY_BLUETOOTH_NIMBLE),1) +CFLAGS_MOD += -DMICROPY_BLUETOOTH_NIMBLE=1 +endif +endif +endif + # these flags are common to C and C++ compilation CFLAGS_COMMON = -Os -ffunction-sections -fdata-sections -fstrict-volatile-bitfields \ -mlongcalls -nostdlib \ @@ -270,6 +304,7 @@ SRC_C = \ modnetwork.c \ network_lan.c \ network_ppp.c \ + nimble.c \ modsocket.c \ modesp.c \ esp32_partition.c \ @@ -286,6 +321,7 @@ SRC_C = \ EXTMOD_SRC_C = $(addprefix extmod/,\ modonewire.c \ + modbluetooth_nimble.c \ ) LIB_SRC_C = $(addprefix lib/,\ @@ -461,6 +497,31 @@ ESPIDF_ESP_EVENT_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/esp_event/*.c)) ESPIDF_ESP_WIFI_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/esp_wifi/src/*.c)) +ifeq ($(CONFIG_BT_NIMBLE_ENABLED),y) +ESPIDF_BT_NIMBLE_O = $(patsubst %.c,%.o,\ + $(wildcard $(ESPCOMP)/bt/controller/*.c) \ + $(wildcard $(ESPCOMP)/bt/common/btc/core/*.c) \ + $(wildcard $(ESPCOMP)/bt/common/osi/*.c) \ + $(wildcard $(ESPCOMP)/bt/host/nimble/esp-hci/src/*.c) \ + $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/ext/tinycrypt/src/*.c) \ + $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/ans/src/*.c) \ + $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/bas/src/*.c) \ + $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/gap/src/*.c) \ + $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/gatt/src/*.c) \ + $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/ias/src/*.c) \ + $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/lls/src/*.c) \ + $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/tps/src/*.c) \ + $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/nimble/host/src/*.c) \ + $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/nimble/host/store/config/src/ble_store_config.c) \ + $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/nimble/host/store/config/src/ble_store_nvs.c) \ + $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/nimble/host/store/ram/src/*.c) \ + $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/nimble/host/util/src/*.c) \ + $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/nimble/src/*.c) \ + $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/porting/nimble/src/*.c) \ + $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/porting/npl/freertos/src/*.c) \ + ) +endif + $(BUILD)/$(ESPCOMP)/esp_eth/src/esp_eth_mac_dm9051.o: CFLAGS += -fno-strict-aliasing ESPIDF_ESP_ETH_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/esp_eth/src/*.c)) @@ -521,6 +582,9 @@ ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) $(eval $(call gen_espidf_lib_rule,esp_common,$(ESPIDF_ESP_COMMON_O))) $(eval $(call gen_espidf_lib_rule,esp_event,$(ESPIDF_ESP_EVENT_O))) $(eval $(call gen_espidf_lib_rule,esp_wifi,$(ESPIDF_ESP_WIFI_O))) +ifeq ($(CONFIG_BT_NIMBLE_ENABLED),y) +$(eval $(call gen_espidf_lib_rule,bt_nimble,$(ESPIDF_BT_NIMBLE_O))) +endif $(eval $(call gen_espidf_lib_rule,esp_eth,$(ESPIDF_ESP_ETH_O))) $(eval $(call gen_espidf_lib_rule,xtensa,$(ESPIDF_XTENSA_O))) else @@ -636,6 +700,7 @@ APP_LD_ARGS += -L$(dir $(LIBSTDCXX_FILE_NAME)) -lstdc++ APP_LD_ARGS += $(LIBC_LIBM) ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) APP_LD_ARGS += -L$(ESPCOMP)/xtensa/esp32 -lhal +APP_LD_ARGS += -L$(ESPCOMP)/bt/controller/lib -lbtdm_app APP_LD_ARGS += -L$(ESPCOMP)/esp_wifi/lib_esp32 -lcore -lmesh -lnet80211 -lphy -lrtc -lpp -lsmartconfig -lcoexist else APP_LD_ARGS += $(ESPCOMP)/esp32/libhal.a diff --git a/ports/esp32/boards/sdkconfig.ble b/ports/esp32/boards/sdkconfig.ble new file mode 100644 index 0000000000..db9cc11752 --- /dev/null +++ b/ports/esp32/boards/sdkconfig.ble @@ -0,0 +1,6 @@ +# Note this requires building with IDF 4.x +CONFIG_BT_ENABLED=y +CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y +CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY= +CONFIG_BTDM_CTRL_MODE_BTDM= +CONFIG_BT_NIMBLE_ENABLED=y diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 63657741ce..5c9d602abc 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -162,6 +162,8 @@ void *esp_native_code_commit(void*, size_t); #define MICROPY_PY_WEBREPL (1) #define MICROPY_PY_FRAMEBUF (1) #define MICROPY_PY_USOCKET_EVENTS (MICROPY_PY_WEBREPL) +#define MICROPY_PY_BLUETOOTH_RANDOM_ADDR (1) +#define MICROPY_PY_BLUETOOTH_DEFAULT_NAME ("ESP32") // fatfs configuration #define MICROPY_FATFS_ENABLE_LFN (1) @@ -189,8 +191,15 @@ 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_bluetooth; extern const struct _mp_obj_module_t mp_module_onewire; +#if MICROPY_PY_BLUETOOTH +#define BLUETOOTH_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_bluetooth), MP_ROM_PTR(&mp_module_bluetooth) }, +#else +#define BLUETOOTH_BUILTIN_MODULE +#endif + #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 }, \ @@ -199,6 +208,7 @@ extern const struct _mp_obj_module_t mp_module_onewire; { 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 }, \ + BLUETOOTH_BUILTIN_MODULE \ { 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 }, \ @@ -224,10 +234,18 @@ extern const struct _mp_obj_module_t mp_module_onewire; struct _machine_timer_obj_t; +#if MICROPY_BLUETOOTH_NIMBLE +struct mp_bluetooth_nimble_root_pointers_t; +#define MICROPY_PORT_ROOT_POINTER_BLUETOOTH_NIMBLE struct _mp_bluetooth_nimble_root_pointers_t *bluetooth_nimble_root_pointers; +#else +#define MICROPY_PORT_ROOT_POINTER_BLUETOOTH_NIMBLE +#endif + #define MICROPY_PORT_ROOT_POINTERS \ const char *readline_hist[8]; \ mp_obj_t machine_pin_irq_handler[40]; \ struct _machine_timer_obj_t *machine_timer_obj_head; \ + MICROPY_PORT_ROOT_POINTER_BLUETOOTH_NIMBLE // type definitions for the specific machine diff --git a/ports/esp32/nimble.c b/ports/esp32/nimble.c new file mode 100644 index 0000000000..3747ae0f33 --- /dev/null +++ b/ports/esp32/nimble.c @@ -0,0 +1,57 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Jim Mussared + * + * 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 "py/mphal.h" + +#if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE + +#include "esp_nimble_hci.h" +#include "nimble/nimble_port.h" +#include "nimble/nimble_port_freertos.h" + +STATIC void ble_host_task(void *param) { + nimble_port_run(); //This function will return only when nimble_port_stop() is executed. + nimble_port_freertos_deinit(); +} + +void mp_bluetooth_nimble_port_preinit(void) { + esp_nimble_hci_and_controller_init(); +} + +void mp_bluetooth_nimble_port_postinit(void) { + nimble_port_freertos_init(ble_host_task); +} + +void mp_bluetooth_nimble_port_deinit(void) { + nimble_port_stop(); +} + +void mp_bluetooth_nimble_port_start(void) { +} + +#endif From cd8bbf4cfca57f330f256134301e42f137f91eee Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 1 Oct 2019 23:47:55 +1000 Subject: [PATCH 0806/1788] esp32/boards: Enable BLE by default when building with IDF 4.x. --- ports/esp32/Makefile | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index f059536af9..5d63a2586c 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -110,6 +110,16 @@ $(info Add the xtensa toolchain to your PATH. See README.md) $(error C compiler missing) endif +# Support BLE by default when building with IDF 4.x. +# Can be explicitly disabled on the command line or board config. +ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) +MICROPY_PY_BLUETOOTH ?= 1 +ifeq ($(MICROPY_PY_BLUETOOTH),1) +SDKCONFIG += boards/sdkconfig.ble +MICROPY_BLUETOOTH_NIMBLE = 1 +endif +endif + # include sdkconfig to get needed configuration values include $(SDKCONFIG) From fa23033fc4b1b06e92ae5d0f6783257a6774318c Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 8 Oct 2019 14:27:44 +1100 Subject: [PATCH 0807/1788] travis: Add BLE submodules to ESP32 IDF4 build. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 617cc2035e..7633b1a94c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -160,7 +160,7 @@ jobs: - make ${MAKEOPTS} -C ports/esp32 clean # IDF v4 build - git -C esp-idf checkout $(grep "ESPIDF_SUPHASH_V4 :=" ports/esp32/Makefile | cut -d " " -f 3) - - git -C esp-idf submodule update --init components/esp_wifi/lib_esp32 components/esptool_py/esptool components/lwip/lwip components/mbedtls/mbedtls + - git -C esp-idf submodule update --init components/bt/controller/lib components/bt/host/nimble/nimble components/esp_wifi/lib_esp32 components/esptool_py/esptool components/lwip/lwip components/mbedtls/mbedtls - make ${MAKEOPTS} -C ports/esp32 # esp8266 port From 04fe62d06f0e0e56e7dc40bdf9883c7a2f2eac6a Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Thu, 27 Jun 2019 11:00:04 +1000 Subject: [PATCH 0808/1788] stm32/mboot: Add option to automatically reset when USB is disconnected. Enable in board config with: #define MBOOT_USB_RESET_ON_DISCONNECT (1) --- ports/stm32/mboot/main.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ports/stm32/mboot/main.c b/ports/stm32/mboot/main.c index a0f1f1eace..015800ce43 100644 --- a/ports/stm32/mboot/main.c +++ b/ports/stm32/mboot/main.c @@ -1526,6 +1526,9 @@ enter_bootloader: uint32_t ss = systick_ms; int ss2 = -1; #endif + #if MBOOT_USB_RESET_ON_DISCONNECT + bool has_connected = false; + #endif for (;;) { #if USE_USB_POLLING #if MBOOT_USB_AUTODETECT_PORT || MICROPY_HW_USB_MAIN_DEV == USB_PHY_FS_ID @@ -1559,6 +1562,15 @@ enter_bootloader: led_state(LED0, 0); mp_hal_delay_ms(950); #endif + + #if MBOOT_USB_RESET_ON_DISCONNECT + if (pyb_usbdd.hUSBDDevice.dev_state == USBD_STATE_CONFIGURED) { + has_connected = true; + } + if (has_connected && pyb_usbdd.hUSBDDevice.dev_state == USBD_STATE_SUSPENDED) { + do_reset(); + } + #endif } } From 2863dcdf4f9f1fc421c7b745195259fbf46250a2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 8 Oct 2019 16:38:04 +1100 Subject: [PATCH 0809/1788] nrf: Add support to activate MICROPY_PY_SYS_STDFILES. Fixes issue #5162. --- ports/nrf/Makefile | 3 ++- ports/nrf/mphalport.c | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index 1b70851eb8..aa6c189aaa 100644 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -156,6 +156,7 @@ SRC_LIB += $(addprefix lib/,\ libc/string0.c \ mp-readline/readline.c \ utils/pyexec.c \ + utils/sys_stdio_mphal.c \ utils/interrupt_char.c \ timeutils/timeutils.c \ ) @@ -342,7 +343,7 @@ $(BUILD)/$(OUTPUT_FILENAME).elf: $(OBJ) $(Q)$(SIZE) $@ # List of sources for qstr extraction -SRC_QSTR += $(SRC_C) $(DRIVERS_SRC_C) $(SRC_BOARD_MODULES) +SRC_QSTR += $(SRC_C) $(SRC_LIB) $(DRIVERS_SRC_C) $(SRC_BOARD_MODULES) # Append any auto-generated sources that are needed by sources listed in # SRC_QSTR diff --git a/ports/nrf/mphalport.c b/ports/nrf/mphalport.c index a050df1470..bf89697083 100644 --- a/ports/nrf/mphalport.c +++ b/ports/nrf/mphalport.c @@ -30,6 +30,7 @@ #include "py/mphal.h" #include "py/mperrno.h" #include "py/runtime.h" +#include "py/stream.h" #include "uart.h" #include "nrfx_errors.h" #include "nrfx_config.h" @@ -53,6 +54,15 @@ void mp_hal_set_interrupt_char(int c) { #endif #if !MICROPY_PY_BLE_NUS +uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) { + uintptr_t ret = 0; + if ((poll_flags & MP_STREAM_POLL_RD) && MP_STATE_PORT(board_stdio_uart) != NULL + && uart_rx_any(MP_STATE_PORT(board_stdio_uart))) { + ret |= MP_STREAM_POLL_RD; + } + return ret; +} + int mp_hal_stdin_rx_chr(void) { for (;;) { if (MP_STATE_PORT(board_stdio_uart) != NULL && uart_rx_any(MP_STATE_PORT(board_stdio_uart))) { From 53a9b45da1f7f625e273125c259bad7793f17e47 Mon Sep 17 00:00:00 2001 From: Mike Causer Date: Wed, 18 Sep 2019 15:08:06 +1000 Subject: [PATCH 0810/1788] esp8266: Add per-board configs, following other ports. The specific board can be selected with the BOARD makefile variable. This defaults (if not specified) to BOARD=GENERIC, which is the original default firmware build. For the 512k target use BOARD=GENERIC_512K. --- ports/esp8266/Makefile | 34 ++++++++++----- ports/esp8266/README.md | 31 +++++++------ ports/esp8266/boards/GENERIC/mpconfigboard.h | 21 +++++++++ .../boards/GENERIC_512K/mpconfigboard.h | 4 ++ .../boards/GENERIC_512K/mpconfigboard.mk | 3 ++ .../esp8266/{ => boards}/eagle.rom.addr.v6.ld | 0 ports/esp8266/{ => boards}/esp8266.ld | 2 +- ports/esp8266/{ => boards}/esp8266_512k.ld | 2 +- ports/esp8266/{ => boards}/esp8266_common.ld | 6 +-- ports/esp8266/{ => boards}/esp8266_ota.ld | 2 +- ports/esp8266/mpconfigport.h | 25 +++-------- ports/esp8266/mpconfigport_512k.h | 43 ------------------- 12 files changed, 83 insertions(+), 90 deletions(-) create mode 100644 ports/esp8266/boards/GENERIC/mpconfigboard.h create mode 100644 ports/esp8266/boards/GENERIC_512K/mpconfigboard.h create mode 100644 ports/esp8266/boards/GENERIC_512K/mpconfigboard.mk rename ports/esp8266/{ => boards}/eagle.rom.addr.v6.ld (100%) rename ports/esp8266/{ => boards}/esp8266.ld (89%) rename ports/esp8266/{ => boards}/esp8266_512k.ld (89%) rename ports/esp8266/{ => boards}/esp8266_common.ld (98%) rename ports/esp8266/{ => boards}/esp8266_ota.ld (92%) delete mode 100644 ports/esp8266/mpconfigport_512k.h diff --git a/ports/esp8266/Makefile b/ports/esp8266/Makefile index 2162c72f07..8cac07afcc 100644 --- a/ports/esp8266/Makefile +++ b/ports/esp8266/Makefile @@ -1,13 +1,29 @@ +# Select the board to build for: if not given on the command line, +# then default to GENERIC. +BOARD ?= GENERIC + +# If the build directory is not given, make it reflect the board name. +BUILD ?= build-$(BOARD) + +BOARD_DIR ?= boards/$(BOARD) +ifeq ($(wildcard $(BOARD_DIR)/.),) +$(error Invalid BOARD specified: $(BOARD_DIR)) +endif + include ../../py/mkenv.mk +# Optional +-include $(BOARD_DIR)/mpconfigboard.mk + # qstr definitions (must come before including py.mk) QSTR_DEFS = qstrdefsport.h #$(BUILD)/pins_qstr.h +QSTR_GLOBAL_DEPENDENCIES = $(BOARD_DIR)/mpconfigboard.h MICROPY_PY_USSL = 1 MICROPY_SSL_AXTLS = 1 AXTLS_DEFS_EXTRA = -Dabort=abort_ -DRT_MAX_PLAIN_LENGTH=1024 -DRT_EXTRA=4096 -MICROPY_FATFS = 1 -MICROPY_PY_BTREE = 1 +MICROPY_FATFS ?= 1 +MICROPY_PY_BTREE ?= 1 BTREE_DEFS_EXTRA = -DDEFPSIZE=1024 -DMINCACHE=3 FROZEN_DIR ?= scripts @@ -40,10 +56,10 @@ CFLAGS_XTENSA = -fsingle-precision-constant -Wdouble-promotion \ -DLWIP_OPEN_SRC CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 -nostdlib -DUART_OS=$(UART_OS) \ - $(CFLAGS_XTENSA) $(CFLAGS_MOD) $(COPT) $(CFLAGS_EXTRA) + $(CFLAGS_XTENSA) $(CFLAGS_MOD) $(COPT) $(CFLAGS_EXTRA) -I$(BOARD_DIR) -LDSCRIPT = esp8266.ld -LDFLAGS = -nostdlib -T $(LDSCRIPT) -Map=$(@:.elf=.map) --cref +LD_FILES ?= boards/esp8266.ld +LDFLAGS = -nostdlib -T $(LD_FILES) -Map=$(@:.elf=.map) --cref LIBS = -L$(ESP_SDK)/lib -lmain -ljson -llwip_open -lpp -lnet80211 -lwpa -lphy -lnet80211 $(LDFLAGS_MOD) LIBGCC_FILE_NAME = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) @@ -92,6 +108,7 @@ SRC_C = \ fatfs_port.c \ posix_helpers.c \ hspi.c \ + $(wildcard $(BOARD_DIR)/*.c) \ $(SRC_MOD) EXTMOD_SRC_C = $(addprefix extmod/,\ @@ -192,15 +209,12 @@ $(BUILD)/firmware.elf: $(OBJ) $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS) $(Q)$(SIZE) $@ -512k: - $(MAKE) LDSCRIPT=esp8266_512k.ld CFLAGS_EXTRA='-DMP_CONFIGFILE=""' MICROPY_FATFS=0 MICROPY_PY_BTREE=0 - ota: rm -f $(BUILD)/firmware.elf $(BUILD)/firmware.elf*.bin - $(MAKE) LDSCRIPT=esp8266_ota.ld FWBIN=$(BUILD)/firmware-ota.bin + $(MAKE) LD_FILES=boards/esp8266_ota.ld FWBIN=$(BUILD)/firmware-ota.bin include $(TOP)/py/mkrules.mk clean-modules: git clean -f -d modules - rm -f build/frozen*.c + rm -f $(BUILD)/frozen*.c diff --git a/ports/esp8266/README.md b/ports/esp8266/README.md index 402798928c..9541dfd22b 100644 --- a/ports/esp8266/README.md +++ b/ports/esp8266/README.md @@ -52,12 +52,11 @@ Then, to build MicroPython for the ESP8266, just run: $ cd ports/esp8266 $ make ``` -This will produce binary images in the `build/` subdirectory. If you install -MicroPython to your module for the first time, or after installing any other -firmware, you should erase flash completely: - -``` -esptool.py --port /dev/ttyXXX erase_flash +This will produce binary images in the `build-GENERIC/` subdirectory. If you +install MicroPython to your module for the first time, or after installing any +other firmware, you should erase flash completely: +```bash +$ esptool.py --port /dev/ttyXXX erase_flash ``` Erase flash also as a troubleshooting measure, if a module doesn't behave as @@ -76,17 +75,25 @@ that flash size is in megabits): $ make PORT=/dev/ttyUSB0 FLASH_MODE=qio FLASH_SIZE=32m deploy ``` -The image produced is `build/firmware-combined.bin`, to be flashed at 0x00000. +The image produced is `build-GENERIC/firmware-combined.bin`, to be flashed at 0x00000. + +The default board definition is the directory `boards/GENERIC`. +For a custom configuration you can define your own board in the directory `boards/`. + +The `BOARD` variable can be set on the make command line, for example: +```bash +$ make BOARD=GENERIC_512K +``` __512KB FlashROM version__ The normal build described above requires modules with at least 1MB of FlashROM onboard. There's a special configuration for 512KB modules, which can be -built with `make 512k`. This configuration is highly limited, lacks filesystem -support, WebREPL, and has many other features disabled. It's mostly suitable -for advanced users who are interested to fine-tune options to achieve a required -setup. If you are an end user, please consider using a module with at least 1MB -of FlashROM. +built with `make BOARD=GENERIC_512K`. This configuration is highly limited, lacks +filesystem support, WebREPL, and has many other features disabled. It's mostly +suitable for advanced users who are interested to fine-tune options to achieve a +required setup. If you are an end user, please consider using a module with at +least 1MB of FlashROM. First start ----------- diff --git a/ports/esp8266/boards/GENERIC/mpconfigboard.h b/ports/esp8266/boards/GENERIC/mpconfigboard.h new file mode 100644 index 0000000000..a7cacb815e --- /dev/null +++ b/ports/esp8266/boards/GENERIC/mpconfigboard.h @@ -0,0 +1,21 @@ +#define MICROPY_HW_BOARD_NAME "ESP module" +#define MICROPY_HW_MCU_NAME "ESP8266" + +#define MICROPY_PERSISTENT_CODE_LOAD (1) +#define MICROPY_EMIT_XTENSA (1) +#define MICROPY_EMIT_INLINE_XTENSA (1) + +#define MICROPY_DEBUG_PRINTERS (1) +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL) + +#define MICROPY_READER_VFS (MICROPY_VFS) +#define MICROPY_VFS (1) +#define MICROPY_VFS_FAT (1) + +#define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) +#define MICROPY_PY_ALL_SPECIAL_METHODS (1) +#define MICROPY_PY_IO_FILEIO (1) +#define MICROPY_PY_SYS_STDIO_BUFFER (1) +#define MICROPY_PY_URE_SUB (1) +#define MICROPY_PY_UCRYPTOLIB (1) +#define MICROPY_PY_FRAMEBUF (1) diff --git a/ports/esp8266/boards/GENERIC_512K/mpconfigboard.h b/ports/esp8266/boards/GENERIC_512K/mpconfigboard.h new file mode 100644 index 0000000000..0693232aa1 --- /dev/null +++ b/ports/esp8266/boards/GENERIC_512K/mpconfigboard.h @@ -0,0 +1,4 @@ +#define MICROPY_HW_BOARD_NAME "ESP module (512K)" +#define MICROPY_HW_MCU_NAME "ESP8266" + +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) diff --git a/ports/esp8266/boards/GENERIC_512K/mpconfigboard.mk b/ports/esp8266/boards/GENERIC_512K/mpconfigboard.mk new file mode 100644 index 0000000000..90f3c1773d --- /dev/null +++ b/ports/esp8266/boards/GENERIC_512K/mpconfigboard.mk @@ -0,0 +1,3 @@ +MICROPY_FATFS = 0 +MICROPY_PY_BTREE = 0 +LD_FILES = boards/esp8266_512k.ld diff --git a/ports/esp8266/eagle.rom.addr.v6.ld b/ports/esp8266/boards/eagle.rom.addr.v6.ld similarity index 100% rename from ports/esp8266/eagle.rom.addr.v6.ld rename to ports/esp8266/boards/eagle.rom.addr.v6.ld diff --git a/ports/esp8266/esp8266.ld b/ports/esp8266/boards/esp8266.ld similarity index 89% rename from ports/esp8266/esp8266.ld rename to ports/esp8266/boards/esp8266.ld index deeb82b456..745edaadbb 100644 --- a/ports/esp8266/esp8266.ld +++ b/ports/esp8266/boards/esp8266.ld @@ -9,4 +9,4 @@ MEMORY } /* define common sections and symbols */ -INCLUDE esp8266_common.ld +INCLUDE boards/esp8266_common.ld diff --git a/ports/esp8266/esp8266_512k.ld b/ports/esp8266/boards/esp8266_512k.ld similarity index 89% rename from ports/esp8266/esp8266_512k.ld rename to ports/esp8266/boards/esp8266_512k.ld index 0ae663db11..8690447813 100644 --- a/ports/esp8266/esp8266_512k.ld +++ b/ports/esp8266/boards/esp8266_512k.ld @@ -9,4 +9,4 @@ MEMORY } /* define common sections and symbols */ -INCLUDE esp8266_common.ld +INCLUDE boards/esp8266_common.ld diff --git a/ports/esp8266/esp8266_common.ld b/ports/esp8266/boards/esp8266_common.ld similarity index 98% rename from ports/esp8266/esp8266_common.ld rename to ports/esp8266/boards/esp8266_common.ld index bbbb1325e1..ce67e48048 100644 --- a/ports/esp8266/esp8266_common.ld +++ b/ports/esp8266/boards/esp8266_common.ld @@ -142,7 +142,7 @@ SECTIONS *lib/utils/interrupt_char.o*(.literal.mp_hal_set_interrupt_char, .text.mp_hal_set_interrupt_char) *drivers/bus/*.o(.literal* .text*) - build/main.o(.literal* .text*) + build-*/main.o(.literal* .text*) *fatfs_port.o(.literal* .text*) *gccollect.o(.literal* .text*) *gchelper.o(.literal* .text*) @@ -179,7 +179,7 @@ SECTIONS */frozen.o(.rodata.mp_frozen_content) /* frozen modules */ /* for -mforce-l32 */ - build/*.o(.rodata*) + build-*/*.o(.rodata*) _irom0_text_end = ABSOLUTE(.); } >irom0_0_seg :irom0_0_phdr @@ -313,4 +313,4 @@ SECTIONS } /* get ROM code address */ -INCLUDE "eagle.rom.addr.v6.ld" +INCLUDE "boards/eagle.rom.addr.v6.ld" diff --git a/ports/esp8266/esp8266_ota.ld b/ports/esp8266/boards/esp8266_ota.ld similarity index 92% rename from ports/esp8266/esp8266_ota.ld rename to ports/esp8266/boards/esp8266_ota.ld index 604480a0a9..7fdf6abef0 100644 --- a/ports/esp8266/esp8266_ota.ld +++ b/ports/esp8266/boards/esp8266_ota.ld @@ -10,4 +10,4 @@ MEMORY } /* define common sections and symbols */ -INCLUDE esp8266_common.ld +INCLUDE boards/esp8266_common.ld diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h index 5a1ca098d8..fa809d91a6 100644 --- a/ports/esp8266/mpconfigport.h +++ b/ports/esp8266/mpconfigport.h @@ -1,6 +1,10 @@ -#include +// Options to control how MicroPython is built for this port, +// overriding defaults in py/mpconfig.h. -// options to control how MicroPython is built +// Board-specific definitions +#include "mpconfigboard.h" + +#include #define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_C) #define MICROPY_GC_STACK_ENTRY_TYPE uint16_t @@ -10,13 +14,8 @@ #define MICROPY_ALLOC_PARSE_RULE_INC (8) #define MICROPY_ALLOC_PARSE_RESULT_INC (8) #define MICROPY_ALLOC_PARSE_CHUNK_INIT (64) -#define MICROPY_PERSISTENT_CODE_LOAD (1) -#define MICROPY_EMIT_XTENSA (1) -#define MICROPY_EMIT_INLINE_XTENSA (1) #define MICROPY_MEM_STATS (0) #define MICROPY_DEBUG_PRINTER (&mp_debug_print) -#define MICROPY_DEBUG_PRINTERS (1) -#define MICROPY_READER_VFS (MICROPY_VFS) #define MICROPY_ENABLE_GC (1) #define MICROPY_ENABLE_FINALISER (1) #define MICROPY_STACK_CHECK (1) @@ -32,7 +31,6 @@ #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) #define MICROPY_PY_BUILTINS_BYTEARRAY (1) @@ -40,7 +38,6 @@ #define MICROPY_PY_BUILTINS_FROZENSET (1) #define MICROPY_PY_BUILTINS_SET (1) #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) @@ -58,25 +55,21 @@ #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) #define MICROPY_PY_SYS_MAXSIZE (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_UBINASCII (1) #define MICROPY_PY_UCTYPES (1) #define MICROPY_PY_UHASHLIB (1) #define MICROPY_PY_UHASHLIB_SHA1 (MICROPY_PY_USSL && MICROPY_SSL_AXTLS) -#define MICROPY_PY_UCRYPTOLIB (1) #define MICROPY_PY_UHEAPQ (1) #define MICROPY_PY_UTIMEQ (1) #define MICROPY_PY_UJSON (1) #define MICROPY_PY_URANDOM (1) #define MICROPY_PY_URE (1) -#define MICROPY_PY_URE_SUB (1) #define MICROPY_PY_USELECT (1) #define MICROPY_PY_UTIME_MP_HAL (1) #define MICROPY_PY_UZLIB (1) @@ -92,13 +85,11 @@ #define MICROPY_PY_WEBREPL (1) #define MICROPY_PY_WEBREPL_DELAY (20) #define MICROPY_PY_WEBREPL_STATIC_FILEBUF (1) -#define MICROPY_PY_FRAMEBUF (1) #define MICROPY_PY_MICROPYTHON_MEM_INFO (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) -#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL) #define MICROPY_WARNINGS (1) #define MICROPY_PY_STR_BYTES_CMP_WARN (1) #define MICROPY_STREAMS_NON_BLOCK (1) @@ -108,12 +99,10 @@ #define MICROPY_MODULE_FROZEN_LEXER mp_lexer_new_from_str32 #define MICROPY_QSTR_EXTRA_POOL mp_qstr_frozen_const_pool -#define MICROPY_VFS (1) #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 MICROPY_VFS_FAT (1) #define MICROPY_ESP8266_APA102 (1) #define MICROPY_ESP8266_NEOPIXEL (1) @@ -211,8 +200,6 @@ extern const struct _mp_obj_module_t mp_module_onewire; // board specifics #define MICROPY_MPHALPORT_H "esp_mphal.h" -#define MICROPY_HW_BOARD_NAME "ESP module" -#define MICROPY_HW_MCU_NAME "ESP8266" #define MICROPY_PY_SYS_PLATFORM "esp8266" #define MP_FASTCODE(n) __attribute__((section(".iram0.text." #n))) n diff --git a/ports/esp8266/mpconfigport_512k.h b/ports/esp8266/mpconfigport_512k.h deleted file mode 100644 index df670d4c96..0000000000 --- a/ports/esp8266/mpconfigport_512k.h +++ /dev/null @@ -1,43 +0,0 @@ -#include - -#undef MICROPY_EMIT_XTENSA -#define MICROPY_EMIT_XTENSA (0) -#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) - -#undef MICROPY_VFS -#define MICROPY_VFS (0) -#undef MICROPY_VFS_FAT -#define MICROPY_VFS_FAT (0) - -#undef MICROPY_PERSISTENT_CODE_LOAD -#define MICROPY_PERSISTENT_CODE_LOAD (0) - -#undef MICROPY_PY_IO_FILEIO -#define MICROPY_PY_IO_FILEIO (0) - -#undef MICROPY_PY_SYS_STDIO_BUFFER -#define MICROPY_PY_SYS_STDIO_BUFFER (0) -#undef MICROPY_PY_BUILTINS_SLICE_ATTRS -#define MICROPY_PY_BUILTINS_SLICE_ATTRS (0) -#undef MICROPY_PY_ALL_SPECIAL_METHODS -#define MICROPY_PY_ALL_SPECIAL_METHODS (0) - -#undef MICROPY_PY_FRAMEBUF -#define MICROPY_PY_FRAMEBUF (0) - -#undef MICROPY_PY_URE_SUB -#define MICROPY_PY_URE_SUB (0) - -#undef MICROPY_PY_UCRYPTOLIB -#define MICROPY_PY_UCRYPTOLIB (0) - -#undef mp_import_stat -#undef mp_builtin_open -#undef mp_builtin_open_obj From 3117fde407064cd6e51c4f4bdd35ac9ca3cca20f Mon Sep 17 00:00:00 2001 From: Mike Causer Date: Mon, 30 Sep 2019 17:26:41 +1000 Subject: [PATCH 0811/1788] travis: Add esp8266 GENERIC_512K build to CI. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 7633b1a94c..cc015bda39 100644 --- a/.travis.yml +++ b/.travis.yml @@ -174,6 +174,7 @@ jobs: - git submodule update --init lib/axtls lib/berkeley-db-1.xx - make ${MAKEOPTS} -C mpy-cross - make ${MAKEOPTS} -C ports/esp8266 + - make ${MAKEOPTS} -C ports/esp8266 BOARD=GENERIC_512K # nrf port - stage: test From 305f537bf940fbbe3474cd1e0938586426d25b48 Mon Sep 17 00:00:00 2001 From: Andrey Belykh Date: Fri, 4 Oct 2019 23:27:14 -0400 Subject: [PATCH 0812/1788] stm32/sdcard: Support boards with no SD card detect pin. If MICROPY_HW_SDCARD_DETECT_PIN is not defined then the SD card will always be detected as present. --- ports/stm32/sdcard.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ports/stm32/sdcard.c b/ports/stm32/sdcard.c index f54d67ea49..44b1c807d8 100644 --- a/ports/stm32/sdcard.c +++ b/ports/stm32/sdcard.c @@ -175,7 +175,9 @@ void sdcard_init(void) { // configure the SD card detect pin // we do this here so we can detect if the SD card is inserted before powering it on + #if defined(MICROPY_HW_SDCARD_DETECT_PIN) mp_hal_pin_config(MICROPY_HW_SDCARD_DETECT_PIN, MP_HAL_PIN_MODE_INPUT, MICROPY_HW_SDCARD_DETECT_PULL, 0); + #endif } STATIC void sdmmc_msp_init(void) { @@ -231,7 +233,11 @@ bool sdcard_is_present(void) { return false; } #endif + #if defined(MICROPY_HW_SDCARD_DETECT_PIN) return HAL_GPIO_ReadPin(MICROPY_HW_SDCARD_DETECT_PIN->gpio, MICROPY_HW_SDCARD_DETECT_PIN->pin_mask) == MICROPY_HW_SDCARD_DETECT_PRESENT; + #else + return true; + #endif } #if MICROPY_HW_ENABLE_SDCARD From 580a2656d10cc7c1fc93e094d7eb71f04d99c329 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Wed, 9 Oct 2019 22:59:35 +1100 Subject: [PATCH 0813/1788] stm32: Use hardware double sqrt on F7/H7 MCUs. Identical to cd527bb324ade952d11a134859d38bf5272c165e but for doubles. This gives a -2.754% improvement on bm_float.py, and -35% improvement on calling sqrt in a loop. --- lib/libm_dbl/thumb_vfp_sqrt.c | 10 ++++++++++ ports/stm32/Makefile | 6 +++++- 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 lib/libm_dbl/thumb_vfp_sqrt.c diff --git a/lib/libm_dbl/thumb_vfp_sqrt.c b/lib/libm_dbl/thumb_vfp_sqrt.c new file mode 100644 index 0000000000..dd37a07b05 --- /dev/null +++ b/lib/libm_dbl/thumb_vfp_sqrt.c @@ -0,0 +1,10 @@ +// an implementation of sqrt for Thumb using hardware double-precision VFP instructions + +double sqrt(double x) { + double ret; + asm volatile ( + "vsqrt.f64 %P0, %P1\n" + : "=w" (ret) + : "w" (x)); + return ret; +} diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 1a4e3c6902..28b90199ae 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -173,12 +173,16 @@ SRC_LIBM = $(addprefix lib/libm_dbl/,\ scalbn.c \ sin.c \ sinh.c \ - sqrt.c \ tan.c \ tanh.c \ tgamma.c \ trunc.c \ ) +ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f7 h7)) +SRC_LIBM += lib/libm_dbl/thumb_vfp_sqrt.c +else +SRC_LIBM += lib/libm_dbl/sqrt.c +endif else SRC_LIBM = $(addprefix lib/libm/,\ math.c \ From 79ab82ea77b0a924e96c2f6333e00c97706971ab Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 10 Oct 2019 18:05:56 +1100 Subject: [PATCH 0814/1788] esp8266/modules/ntptime.py: Always close socket, and set day-of-week. Fixes issue #5189. --- ports/esp8266/modules/ntptime.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/ports/esp8266/modules/ntptime.py b/ports/esp8266/modules/ntptime.py index 85c754af6c..1a1da65357 100644 --- a/ports/esp8266/modules/ntptime.py +++ b/ports/esp8266/modules/ntptime.py @@ -17,10 +17,12 @@ def time(): NTP_QUERY[0] = 0x1b addr = socket.getaddrinfo(host, 123)[0][-1] s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - s.settimeout(1) - res = s.sendto(NTP_QUERY, addr) - msg = s.recv(48) - s.close() + try: + s.settimeout(1) + res = s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() val = struct.unpack("!I", msg[40:44])[0] return val - NTP_DELTA @@ -31,5 +33,4 @@ def settime(): import machine import utime tm = utime.localtime(t) - tm = tm[0:3] + (0,) + tm[3:6] + (0,) - machine.RTC().datetime(tm) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) From 1571120dc2c32d1eff451d6d52fde38dbec1d114 Mon Sep 17 00:00:00 2001 From: Glenn Ruben Bakke Date: Wed, 9 Oct 2019 19:34:16 +0200 Subject: [PATCH 0815/1788] nrf/device: Correct SPIM3 IRQ handler entry for nrf52840. --- ports/nrf/device/startup_nrf52840.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ports/nrf/device/startup_nrf52840.c b/ports/nrf/device/startup_nrf52840.c index 0935d7d1d0..288b13820f 100644 --- a/ports/nrf/device/startup_nrf52840.c +++ b/ports/nrf/device/startup_nrf52840.c @@ -176,7 +176,9 @@ const func __Vectors[] __attribute__ ((section(".isr_vector"),used)) = { UARTE1_IRQHandler, QSPI_IRQHandler, CRYPTOCELL_IRQHandler, - SPIM3_IRQHandler, + 0, 0, PWM3_IRQHandler, + 0, + SPIM3_IRQHandler, }; From 60b0b69f202f552c89c7ccc74a8304549f85c4fa Mon Sep 17 00:00:00 2001 From: Glenn Ruben Bakke Date: Wed, 9 Oct 2019 20:01:51 +0200 Subject: [PATCH 0816/1788] nrf: Add tinyusb support for nrf52840. Add nrf-port finyusb driver files. USB CDC can be activated by board configuration files using the MICROPY_HW_USB_CDC. Updating BLE driver, Makefile, nrfx-glue and main.c to plug in the tinyusb stack. --- ports/nrf/Makefile | 31 ++++ ports/nrf/drivers/bluetooth/ble_drv.c | 8 + ports/nrf/drivers/usb/tusb_config.h | 44 +++++ ports/nrf/drivers/usb/usb_cdc.c | 226 ++++++++++++++++++++++++ ports/nrf/drivers/usb/usb_cdc.h | 40 +++++ ports/nrf/drivers/usb/usb_descriptors.c | 114 ++++++++++++ ports/nrf/main.c | 11 +- ports/nrf/mphalport.c | 2 + ports/nrf/nrfx_config.h | 8 + ports/nrf/nrfx_glue.h | 2 + 10 files changed, 485 insertions(+), 1 deletion(-) create mode 100644 ports/nrf/drivers/usb/tusb_config.h create mode 100644 ports/nrf/drivers/usb/usb_cdc.c create mode 100644 ports/nrf/drivers/usb/usb_cdc.h create mode 100644 ports/nrf/drivers/usb/usb_descriptors.c diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index aa6c189aaa..46dd8c8d71 100644 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -66,6 +66,7 @@ INC += -I../../lib/nrfx/drivers INC += -I../../lib/nrfx/drivers/include INC += -I../../lib/nrfx/mdk INC += -I../../lib/nrfx/hal +INC += -I../../lib/nrfx/drivers/src/ MCU_VARIANT_UPPER = $(shell echo $(MCU_VARIANT) | tr '[:lower:]' '[:upper:]') MCU_SUB_VARIANT_UPPER = $(shell echo $(MCU_SUB_VARIANT) | tr '[:lower:]' '[:upper:]') @@ -183,6 +184,8 @@ SRC_NRFX += $(addprefix lib/nrfx/drivers/src/,\ nrfx_pwm.c \ nrfx_gpiote.c \ nrfx_nvmc.c \ + nrfx_power.c \ + nrfx_clock.c \ ) SRC_C += \ @@ -198,6 +201,34 @@ SRC_C += \ drivers/bluetooth/ble_drv.c \ drivers/bluetooth/ble_uart.c \ +ifeq ($(MCU_SUB_VARIANT), nrf52840) + +INC += -I./drivers/usb +INC += -I../../lib/tinyusb/src + + +# If SoftDevice is selected. +ifneq ($(SD), ) +# For external tinyusb drivers to enable SoftDevice mode. +CFLAGS += -DSOFTDEVICE_PRESENT +endif + +SRC_C += $(addprefix drivers/usb/,\ + usb_cdc.c \ + usb_descriptors.c \ + ) + +SRC_C += $(addprefix lib/tinyusb/src/,\ + common/tusb_fifo.c \ + device/usbd.c \ + device/usbd_control.c \ + class/cdc/cdc_device.c \ + tusb.c \ + portable/nordic/nrf5x/dcd_nrf5x.c \ + portable/nordic/nrf5x/hal_nrf5x.c \ + ) +endif + DRIVERS_SRC_C += $(addprefix modules/,\ machine/modmachine.c \ machine/uart.c \ diff --git a/ports/nrf/drivers/bluetooth/ble_drv.c b/ports/nrf/drivers/bluetooth/ble_drv.c index e01d118487..4401369f8b 100644 --- a/ports/nrf/drivers/bluetooth/ble_drv.c +++ b/ports/nrf/drivers/bluetooth/ble_drv.c @@ -40,6 +40,10 @@ #include "mphalport.h" +#if MICROPY_HW_USB_CDC +#include "usb_cdc.h" +#endif + #define BLE_DRIVER_VERBOSE 0 #if BLE_DRIVER_VERBOSE @@ -952,6 +956,10 @@ static void sd_evt_handler(uint32_t evt_id) { // unhandled event! break; } +#if MICROPY_HW_USB_CDC + // Farward SOC events to USB CDC driver. + usb_cdc_sd_event_handler(evt_id); +#endif } static void ble_evt_handler(ble_evt_t * p_ble_evt) { diff --git a/ports/nrf/drivers/usb/tusb_config.h b/ports/nrf/drivers/usb/tusb_config.h new file mode 100644 index 0000000000..619578ad6e --- /dev/null +++ b/ports/nrf/drivers/usb/tusb_config.h @@ -0,0 +1,44 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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_NRF_TUSB_CONFIG_H +#define MICROPY_INCLUDED_NRF_TUSB_CONFIG_H + +// Common configuration + +#define CFG_TUSB_MCU OPT_MCU_NRF5X +#define CFG_TUSB_RHPORT0_MODE OPT_MODE_DEVICE + +#define CFG_TUSB_MEM_SECTION +#define CFG_TUSB_MEM_ALIGN TU_ATTR_ALIGNED(4) + +// Device configuration + +#define CFG_TUD_ENDOINT0_SIZE (64) +#define CFG_TUD_CDC (1) +#define CFG_TUD_CDC_RX_BUFSIZE (64) +#define CFG_TUD_CDC_TX_BUFSIZE (64) + +#endif // MICROPY_INCLUDED_NRF_TUSB_CONFIG_H diff --git a/ports/nrf/drivers/usb/usb_cdc.c b/ports/nrf/drivers/usb/usb_cdc.c new file mode 100644 index 0000000000..c90bced6bb --- /dev/null +++ b/ports/nrf/drivers/usb/usb_cdc.c @@ -0,0 +1,226 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * Copyright (c) 2019 Glenn Ruben Bakke + * + * 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. + * + * This file is part of the TinyUSB stack. + */ + +#include "py/mphal.h" + +#if MICROPY_HW_USB_CDC + +#include "tusb.h" +#include "nrfx.h" +#include "nrfx_power.h" +#include "nrfx_uart.h" +#include "py/ringbuf.h" + +#ifdef BLUETOOTH_SD +#include "nrf_sdm.h" +#include "nrf_soc.h" +#include "ble_drv.h" +#endif + +extern void tusb_hal_nrf_power_event(uint32_t event); + +static void cdc_task(void); + +static uint8_t rx_ringbuf_array[1024]; +static uint8_t tx_ringbuf_array[1024]; +static volatile ringbuf_t rx_ringbuf; +static volatile ringbuf_t tx_ringbuf; + +static void board_init(void) { + // Config clock source. +#ifndef BLUETOOTH_SD + NRF_CLOCK->LFCLKSRC = (uint32_t)((CLOCK_LFCLKSRC_SRC_Xtal << CLOCK_LFCLKSRC_SRC_Pos) & CLOCK_LFCLKSRC_SRC_Msk); + NRF_CLOCK->TASKS_LFCLKSTART = 1UL; +#endif + + // Priorities 0, 1, 4 (nRF52) are reserved for SoftDevice + // 2 is highest for application + NRFX_IRQ_PRIORITY_SET(USBD_IRQn, 2); + + // USB power may already be ready at this time -> no event generated + // We need to invoke the handler based on the status initially + uint32_t usb_reg; + +#ifdef BLUETOOTH_SD + uint8_t sd_en = false; + sd_softdevice_is_enabled(&sd_en); + + if (sd_en) { + sd_power_usbdetected_enable(true); + sd_power_usbpwrrdy_enable(true); + sd_power_usbremoved_enable(true); + + sd_power_usbregstatus_get(&usb_reg); + } else +#endif + { + // Power module init + const nrfx_power_config_t pwr_cfg = { 0 }; + nrfx_power_init(&pwr_cfg); + + // Register tusb function as USB power handler + const nrfx_power_usbevt_config_t config = { .handler = (nrfx_power_usb_event_handler_t) tusb_hal_nrf_power_event }; + nrfx_power_usbevt_init(&config); + + nrfx_power_usbevt_enable(); + + usb_reg = NRF_POWER->USBREGSTATUS; + } + + if (usb_reg & POWER_USBREGSTATUS_VBUSDETECT_Msk) { + tusb_hal_nrf_power_event(NRFX_POWER_USB_EVT_DETECTED); + } + +#ifndef BLUETOOTH_SD + if (usb_reg & POWER_USBREGSTATUS_OUTPUTRDY_Msk) { + tusb_hal_nrf_power_event(NRFX_POWER_USB_EVT_READY); + } +#endif +} + +static bool cdc_rx_any(void) { + return rx_ringbuf.iput != rx_ringbuf.iget; +} + +static int cdc_rx_char(void) { + return ringbuf_get((ringbuf_t*)&rx_ringbuf); +} + +static bool cdc_tx_any(void) { + return tx_ringbuf.iput != tx_ringbuf.iget; +} + +static int cdc_tx_char(void) { + return ringbuf_get((ringbuf_t*)&tx_ringbuf); +} + +static void cdc_task(void) +{ + if ( tud_cdc_connected() ) { + // connected and there are data available + while (tud_cdc_available()) { + int c; + uint32_t count = tud_cdc_read(&c, 1); + (void)count; + ringbuf_put((ringbuf_t*)&rx_ringbuf, c); + } + + int chars = 0; + while (cdc_tx_any()) { + if (chars < 64) { + tud_cdc_write_char(cdc_tx_char()); + chars++; + } else { + chars = 0; + tud_cdc_write_flush(); + } + } + + tud_cdc_write_flush(); + } +} + +static void usb_cdc_loop(void) { + tud_task(); + cdc_task(); +} + +int usb_cdc_init(void) +{ + static bool initialized = false; + if (!initialized) { + +#if BLUETOOTH_SD + // Initialize the clock and BLE stack. + ble_drv_stack_enable(); +#endif + + board_init(); + initialized = true; + } + + rx_ringbuf.buf = rx_ringbuf_array; + rx_ringbuf.size = sizeof(rx_ringbuf_array); + rx_ringbuf.iget = 0; + rx_ringbuf.iput = 0; + + tx_ringbuf.buf = tx_ringbuf_array; + tx_ringbuf.size = sizeof(tx_ringbuf_array); + tx_ringbuf.iget = 0; + tx_ringbuf.iput = 0; + + tusb_init(); + + return 0; +} + +#ifdef BLUETOOTH_SD +// process SOC event from SD +void usb_cdc_sd_event_handler(uint32_t soc_evt) { + /*------------- usb power event handler -------------*/ + int32_t usbevt = (soc_evt == NRF_EVT_POWER_USB_DETECTED ) ? NRFX_POWER_USB_EVT_DETECTED: + (soc_evt == NRF_EVT_POWER_USB_POWER_READY) ? NRFX_POWER_USB_EVT_READY : + (soc_evt == NRF_EVT_POWER_USB_REMOVED ) ? NRFX_POWER_USB_EVT_REMOVED : -1; + + if (usbevt >= 0) { + tusb_hal_nrf_power_event(usbevt); + } +} +#endif + +int mp_hal_stdin_rx_chr(void) { + for (;;) { + usb_cdc_loop(); + if (cdc_rx_any()) { + return cdc_rx_char(); + } + } + + return 0; +} + +void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { + + for (const char *top = str + len; str < top; str++) { + ringbuf_put((ringbuf_t*)&tx_ringbuf, *str); + usb_cdc_loop(); + } +} + +void mp_hal_stdout_tx_strn_cooked(const char *str, mp_uint_t len) { + + for (const char *top = str + len; str < top; str++) { + if (*str == '\n') { + ringbuf_put((ringbuf_t*)&tx_ringbuf, '\r'); + usb_cdc_loop(); + } + ringbuf_put((ringbuf_t*)&tx_ringbuf, *str); + usb_cdc_loop(); + } +} + +#endif // MICROPY_HW_USB_CDC diff --git a/ports/nrf/drivers/usb/usb_cdc.h b/ports/nrf/drivers/usb/usb_cdc.h new file mode 100644 index 0000000000..7cd94f85ba --- /dev/null +++ b/ports/nrf/drivers/usb/usb_cdc.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Glenn Ruben Bakke + * + * 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 NRF_DRIVERS_USB_CDC_H__ +#define NRF_DRIVERS_USB_CDC_H__ + +#include "tusb.h" + +void usb_cdc_init(void); + +void usb_cdc_loop(void); +int usb_cdc_read_char(void); +void usb_cdc_write_char(char c); + +void usb_cdc_sd_event_handler(uint32_t soc_evt); + +#endif // NRF_DRIVERS_USB_CDC_H__ diff --git a/ports/nrf/drivers/usb/usb_descriptors.c b/ports/nrf/drivers/usb/usb_descriptors.c new file mode 100644 index 0000000000..a061302d6b --- /dev/null +++ b/ports/nrf/drivers/usb/usb_descriptors.c @@ -0,0 +1,114 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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 "tusb.h" + +#define USBD_VID (0xf055) +#define USBD_PID (0x9802) + +#define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN) +#define USBD_MAX_POWER_MA (250) + +#define USBD_ITF_CDC (0) // needs 2 interfaces +#define USBD_ITF_MAX (2) + +#define USBD_CDC_EP_CMD (0x81) +#define USBD_CDC_EP_OUT (0x02) +#define USBD_CDC_EP_IN (0x82) +#define USBD_CDC_CMD_MAX_SIZE (8) + +#define USBD_STR_0 (0x00) +#define USBD_STR_MANUF (0x01) +#define USBD_STR_PRODUCT (0x02) +#define USBD_STR_SERIAL (0x03) +#define USBD_STR_CDC (0x04) + +// Note: descriptors returned from callbacks must exist long enough for transfer to complete + +static const tusb_desc_device_t usbd_desc_device = { + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, + .bMaxPacketSize0 = CFG_TUD_ENDOINT0_SIZE, + .idVendor = USBD_VID, + .idProduct = USBD_PID, + .bcdDevice = 0x0100, + .iManufacturer = USBD_STR_MANUF, + .iProduct = USBD_STR_PRODUCT, + .iSerialNumber = USBD_STR_SERIAL, + .bNumConfigurations = 1, +}; + +static const uint8_t usbd_desc_cfg[USBD_DESC_LEN] = { + TUD_CONFIG_DESCRIPTOR(USBD_ITF_MAX, USBD_STR_0, USBD_DESC_LEN, + TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, USBD_MAX_POWER_MA), + + TUD_CDC_DESCRIPTOR(USBD_ITF_CDC, USBD_STR_CDC, USBD_CDC_EP_CMD, + USBD_CDC_CMD_MAX_SIZE, USBD_CDC_EP_OUT, USBD_CDC_EP_IN, CFG_TUD_CDC_RX_BUFSIZE), +}; + +static const char *const usbd_desc_str[] = { + [USBD_STR_MANUF] = "MicroPython", + [USBD_STR_PRODUCT] = "Board in FS mode", + [USBD_STR_SERIAL] = "000000000000", // TODO + [USBD_STR_CDC] = "Board CDC", +}; + +const uint8_t *tud_descriptor_device_cb(void) { + return (const uint8_t*)&usbd_desc_device; +} + +const uint8_t *tud_descriptor_configuration_cb(uint8_t index) { + (void)index; + return usbd_desc_cfg; +} + +const uint16_t *tud_descriptor_string_cb(uint8_t index) { + #define DESC_STR_MAX (20) + static uint16_t desc_str[DESC_STR_MAX]; + + uint8_t len; + if (index == 0) { + desc_str[1] = 0x0409; // supported language is English + len = 1; + } else { + if (index >= sizeof(usbd_desc_str) / sizeof(usbd_desc_str[0])) { + return NULL; + } + const char* str = usbd_desc_str[index]; + for (len = 0; len < DESC_STR_MAX - 1 && str[len]; ++len) { + desc_str[1 + len] = str[len]; + } + } + + // first byte is len, second byte is string type + desc_str[0] = TUD_DESC_STR_HEADER(len); + + return desc_str; +} diff --git a/ports/nrf/main.c b/ports/nrf/main.c index e82cfcf58d..ce8512aee3 100644 --- a/ports/nrf/main.c +++ b/ports/nrf/main.c @@ -70,6 +70,10 @@ #include "softpwm.h" #endif +#if MICROPY_HW_USB_CDC +#include "usb_cdc.h" +#endif + void do_str(const char *src, mp_parse_input_kind_t input_kind) { mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); if (lex == NULL) { @@ -121,6 +125,7 @@ soft_reset: readline_init0(); + #if MICROPY_PY_MACHINE_HW_SPI spi_init0(); #endif @@ -149,7 +154,7 @@ soft_reset: uart_init0(); #endif -#if (MICROPY_PY_BLE_NUS == 0) +#if (MICROPY_PY_BLE_NUS == 0) && (MICROPY_HW_USB_CDC == 0) { mp_obj_t args[2] = { MP_OBJ_NEW_SMALL_INT(0), @@ -231,6 +236,10 @@ led_state(1, 0); pyexec_file_if_exists("main.py"); #endif +#if MICROPY_HW_USB_CDC + usb_cdc_init(); +#endif + for (;;) { if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { if (pyexec_raw_repl() != 0) { diff --git a/ports/nrf/mphalport.c b/ports/nrf/mphalport.c index bf89697083..b915c23e47 100644 --- a/ports/nrf/mphalport.c +++ b/ports/nrf/mphalport.c @@ -62,7 +62,9 @@ uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) { } return ret; } +#endif +#if !MICROPY_PY_BLE_NUS && !MICROPY_HW_USB_CDC int mp_hal_stdin_rx_chr(void) { for (;;) { if (MP_STATE_PORT(board_stdio_uart) != NULL && uart_rx_any(MP_STATE_PORT(board_stdio_uart))) { diff --git a/ports/nrf/nrfx_config.h b/ports/nrf/nrfx_config.h index 99085a2fe8..505ecf57bd 100644 --- a/ports/nrf/nrfx_config.h +++ b/ports/nrf/nrfx_config.h @@ -47,6 +47,14 @@ #define GPIO_COUNT 2 #endif +#if defined(NRF52840) +// for tinyusb +//#define NRFX_IRQ_IS_ENABLED 1 +#define NRFX_POWER_ENABLED 1 +#define NRFX_POWER_CONFIG_IRQ_PRIORITY 2 +#define NRFX_SYSTICK_ENABLED 1 +#endif + #define NRFX_GPIOTE_ENABLED 1 #define NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS 1 #if NRF51 diff --git a/ports/nrf/nrfx_glue.h b/ports/nrf/nrfx_glue.h index 316e02df1d..ffd2cff736 100644 --- a/ports/nrf/nrfx_glue.h +++ b/ports/nrf/nrfx_glue.h @@ -138,4 +138,6 @@ #endif // !BLUETOOTH_SD +#define NRFX_IRQ_IS_ENABLED(irq_number) (0 != (NVIC->ISER[irq_number / 32] & (1UL << (irq_number % 32)))) + #endif // NRFX_GLUE_H From 01a3110e363bbde22b3f26191ac2cececf1afdbc Mon Sep 17 00:00:00 2001 From: Glenn Ruben Bakke Date: Wed, 9 Oct 2019 20:25:12 +0200 Subject: [PATCH 0817/1788] nrf/boards: Add support for pca10059. Add support for pca10059 with REPL over tinyusb USB CDC. The board also includes a board specific module that will recover UICR->REGOUT0 in case this has been erased. This initial support does not preserve any existing bootloader on the pca10090 in case this was present, and expects to use all available flash on the device. --- ports/nrf/README.md | 2 + .../boards/pca10059/modules/boardmodules.h | 34 +++++++++ .../boards/pca10059/modules/boardmodules.mk | 11 +++ .../pca10059/modules/recover_uicr_regout0.c | 61 ++++++++++++++++ ports/nrf/boards/pca10059/mpconfigboard.h | 73 +++++++++++++++++++ ports/nrf/boards/pca10059/mpconfigboard.mk | 7 ++ ports/nrf/boards/pca10059/pins.csv | 31 ++++++++ 7 files changed, 219 insertions(+) create mode 100644 ports/nrf/boards/pca10059/modules/boardmodules.h create mode 100644 ports/nrf/boards/pca10059/modules/boardmodules.mk create mode 100644 ports/nrf/boards/pca10059/modules/recover_uicr_regout0.c create mode 100644 ports/nrf/boards/pca10059/mpconfigboard.h create mode 100644 ports/nrf/boards/pca10059/mpconfigboard.mk create mode 100644 ports/nrf/boards/pca10059/pins.csv diff --git a/ports/nrf/README.md b/ports/nrf/README.md index 49642f00e9..834e2ea291 100644 --- a/ports/nrf/README.md +++ b/ports/nrf/README.md @@ -39,6 +39,7 @@ This is a port of MicroPython to the Nordic Semiconductor nRF series of chips. * [uBlox EVK-NINA-B1](https://www.u-blox.com/en/product/evk-nina-b1) * nRF52840 * [PCA10056](http://www.nordicsemi.com/eng/Products/nRF52840-Preview-DK) + * [PCA10059](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-Dongle) * [Particle Xenon](https://docs.particle.io/xenon/) ## Compile and Flash @@ -129,6 +130,7 @@ idk_blyst_nano | s132 | Peripheral and Central | [IDAP] blueio_tag_evim | s132 | Peripheral and Central | [IDAP](#idap-midap-link-targets) evk_nina_b1 | s132 | Peripheral and Central | [Segger](#segger-targets) pca10056 | s140 | Peripheral and Central | [Segger](#segger-targets) +pca10059 | s140 | Peripheral and Central | Manual, SWDIO and SWCLK solder points on the sides. particle_xenon | s140 | Peripheral and Central | [Black Magic Probe](#black-magic-probe-targets) ## IDAP-M/IDAP-Link Targets diff --git a/ports/nrf/boards/pca10059/modules/boardmodules.h b/ports/nrf/boards/pca10059/modules/boardmodules.h new file mode 100644 index 0000000000..1d70ec9161 --- /dev/null +++ b/ports/nrf/boards/pca10059/modules/boardmodules.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Glenn Ruben Bakke + * + * 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_NRF_BOARD_PCA10059_BOARD_MODULES_H +#define MICROPY_INCLUDED_NRF_BOARD_PCA10059_BOARD_MODULES_H + +#define BOARD_MODULES + +void board_modules_init0(void); + +#endif // MICROPY_INCLUDED_NRF_BOARD_PCA10059_BOARD_MODULES_H diff --git a/ports/nrf/boards/pca10059/modules/boardmodules.mk b/ports/nrf/boards/pca10059/modules/boardmodules.mk new file mode 100644 index 0000000000..413790fbea --- /dev/null +++ b/ports/nrf/boards/pca10059/modules/boardmodules.mk @@ -0,0 +1,11 @@ +BOARD_PCA10059_DIR = boards/pca10059/modules + +INC += -I./$(BOARD_PCA10059_DIR) +CFLAGS += -DBOARD_SPECIFIC_MODULES + +SRC_BOARD_MODULES = $(addprefix $(BOARD_PCA10059_DIR)/,\ + recover_uicr_regout0.c \ + ) + +OBJ += $(addprefix $(BUILD)/, $(SRC_BOARD_MODULES:.c=.o)) + diff --git a/ports/nrf/boards/pca10059/modules/recover_uicr_regout0.c b/ports/nrf/boards/pca10059/modules/recover_uicr_regout0.c new file mode 100644 index 0000000000..8ae5e218aa --- /dev/null +++ b/ports/nrf/boards/pca10059/modules/recover_uicr_regout0.c @@ -0,0 +1,61 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Glenn Ruben Bakke + * + * 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 "nrf.h" +#include "nrf52840_bitfields.h" + +bool uicr_REGOUT0_erased() { + if (NRF_UICR->REGOUT0 == 0xFFFFFFFFUL) { + return true; + } + return false; +} + +void board_modules_init0(void) +{ + if (uicr_REGOUT0_erased()) { + + // Wait for pending NVMC operations to finish. + while (NRF_NVMC->READY != NVMC_READY_READY_Ready); + + // Enable write mode in NVMC. + NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen; + while (NRF_NVMC->READY != NVMC_READY_READY_Ready); + + // Write 3v3 value to UICR->REGOUT0. + NRF_UICR->REGOUT0 = (UICR_REGOUT0_VOUT_3V3 & UICR_REGOUT0_VOUT_Msk) << UICR_REGOUT0_VOUT_Pos; + while (NRF_NVMC->READY != NVMC_READY_READY_Ready); + + // Enable read mode in NVMC. + NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren; + while (NRF_NVMC->READY != NVMC_READY_READY_Ready); + + // Reset to apply the update. + NVIC_SystemReset(); + } +} diff --git a/ports/nrf/boards/pca10059/mpconfigboard.h b/ports/nrf/boards/pca10059/mpconfigboard.h new file mode 100644 index 0000000000..08fda1bb29 --- /dev/null +++ b/ports/nrf/boards/pca10059/mpconfigboard.h @@ -0,0 +1,73 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Glenn Ruben Bakke + * + * 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. + */ + +#define MICROPY_HW_BOARD_NAME "PCA10059" +#define MICROPY_HW_MCU_NAME "NRF52840" +#define MICROPY_PY_SYS_PLATFORM "nrf52840-Dongle" + +#define MICROPY_PY_MACHINE_UART (1) +#define MICROPY_PY_MACHINE_HW_PWM (1) +#define MICROPY_PY_MACHINE_HW_SPI (1) +#define MICROPY_PY_MACHINE_TIMER (1) +#define MICROPY_PY_MACHINE_RTCOUNTER (1) +#define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_ADC (1) +#define MICROPY_PY_MACHINE_TEMP (1) +#define MICROPY_PY_RANDOM_HW_RNG (1) + +#define MICROPY_HW_USB_CDC (1) + +#define MICROPY_HW_HAS_LED (1) +#define MICROPY_HW_LED_COUNT (4) +#define MICROPY_HW_LED_PULLUP (1) + +#define MICROPY_HW_LED1 (6) // LED1 GREEN +#define MICROPY_HW_LED2 (8) // LED2 RED (RGB) +#define MICROPY_HW_LED3 (41) // LED2 GREEN (RGB) +#define MICROPY_HW_LED4 (12) // LED2 BLUE (RGB) + +// UART config +#define MICROPY_HW_UART1_RX (13) +#define MICROPY_HW_UART1_TX (15) +#define MICROPY_HW_UART1_CTS (17) +#define MICROPY_HW_UART1_RTS (20) +#define MICROPY_HW_UART1_HWFC (1) + +// SPI0 config +#define MICROPY_HW_SPI0_NAME "SPI0" + +#define MICROPY_HW_SPI0_SCK (22) +#define MICROPY_HW_SPI0_MOSI (32) +#define MICROPY_HW_SPI0_MISO (24) + +#define MICROPY_HW_PWM0_NAME "PWM0" +#define MICROPY_HW_PWM1_NAME "PWM1" +#define MICROPY_HW_PWM2_NAME "PWM2" +#if 0 +#define MICROPY_HW_PWM3_NAME "PWM3" +#endif + +#define HELP_TEXT_BOARD_LED "1,2,3,4" diff --git a/ports/nrf/boards/pca10059/mpconfigboard.mk b/ports/nrf/boards/pca10059/mpconfigboard.mk new file mode 100644 index 0000000000..ca555d3932 --- /dev/null +++ b/ports/nrf/boards/pca10059/mpconfigboard.mk @@ -0,0 +1,7 @@ +MCU_SERIES = m4 +MCU_VARIANT = nrf52 +MCU_SUB_VARIANT = nrf52840 +SOFTDEV_VERSION = 6.1.1 +LD_FILES += boards/nrf52840_1M_256k.ld + +NRF_DEFINES += -DNRF52840_XXAA diff --git a/ports/nrf/boards/pca10059/pins.csv b/ports/nrf/boards/pca10059/pins.csv new file mode 100644 index 0000000000..9d142b9f12 --- /dev/null +++ b/ports/nrf/boards/pca10059/pins.csv @@ -0,0 +1,31 @@ +P2,P2,ADC0_IN0 +P4,P4,ADC0_IN2 +LED1_GREEN,P6 +LED2_RED,P8 +P9,P9 +P10,P10 +P11,P11 +LED2_BLUE,P12 +UART1_RX,P13 +P14,P14 +UART1_TX,P15 +P16,P16 +UART1_CTS,P17 +SWITCH2_NRESET,P18 +UART1_RTS,P20 +SPI0_SCK,P22,P22 +SPI0_MISO,P24 +P26,P26 +P29,P29,ADC0_IN5 +P31,P31,ADC0_IN7 +SPI0_MOSI,P32 +P33,P33 +P34,P34 +P36,P36 +SWITCH1,P38,P38 +P39,P39 +LED2_GREEN,P41 +P42,P42 +P43,P43 +P45,P45 +P47,P47 From 82fe6b0526ad8c10e923174a45063f93f312d681 Mon Sep 17 00:00:00 2001 From: Glenn Ruben Bakke Date: Thu, 26 Sep 2019 22:25:16 +0200 Subject: [PATCH 0818/1788] nrf: Add nrf9160 base support. This patch add basic building blocks for nrf9P60. It also includes a secure bootloader which forwards all possible peripherals that are user selectable to become non-secure. After configuring Flash, RAM and peripherals the secure bootloader will jump to the non-secure domain where MicroPython is placed. The minimum size of a secure boot has to be a flash block of 32Kb, hence why the linker scripts are offsetting the main application this much. The RAM offset is set to 128K, to allow for later integration of Nordic Semiconductor's BSD socket library which reserves the range 0x20010000 - 0x2001FFFF. --- ports/nrf/Makefile | 61 +++- ports/nrf/boards/nrf9160_1M_256k.ld | 13 + ports/nrf/boards/nrf9160_1M_256k_secure.ld | 6 + ports/nrf/boards/nrf91_prefix.c | 29 ++ ports/nrf/device/startup_nrf9160.c | 270 ++++++++++++++++++ ports/nrf/drivers/flash.h | 4 + ports/nrf/drivers/secureboot/secureboot.mk | 55 ++++ .../nrf/drivers/secureboot/secureboot_main.c | 194 +++++++++++++ ports/nrf/main.c | 3 +- ports/nrf/modules/machine/modmachine.c | 2 + ports/nrf/mphalport.c | 3 +- ports/nrf/nrf91_af.csv | 32 +++ ports/nrf/nrfx_config.h | 109 ++++++- ports/nrf/pin_defs_nrf5.h | 5 + 14 files changed, 771 insertions(+), 15 deletions(-) create mode 100644 ports/nrf/boards/nrf9160_1M_256k.ld create mode 100644 ports/nrf/boards/nrf9160_1M_256k_secure.ld create mode 100644 ports/nrf/boards/nrf91_prefix.c create mode 100644 ports/nrf/device/startup_nrf9160.c create mode 100644 ports/nrf/drivers/secureboot/secureboot.mk create mode 100644 ports/nrf/drivers/secureboot/secureboot_main.c create mode 100644 ports/nrf/nrf91_af.csv diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index 46dd8c8d71..a8bd95cc6d 100644 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -82,6 +82,9 @@ else ifeq ($(MCU_SUB_VARIANT),nrf52832) else ifeq ($(MCU_SUB_VARIANT),nrf52840) SYSTEM_C_SRC += $(addprefix lib/nrfx/mdk/, system_nrf52840.c) # Do not pass MCU_VARIANT_UPPER flag, as NRF52 defines NRF52832 only. +else ifeq ($(MCU_SUB_VARIANT),nrf9160) + SYSTEM_C_SRC += $(addprefix lib/nrfx/mdk/, system_nrf9160.c) + NRF_DEFINES += -D$(MCU_VARIANT_UPPER) endif NRF_DEFINES += -D$(MCU_SUB_VARIANT_UPPER) @@ -89,6 +92,8 @@ NRF_DEFINES += -DCONFIG_GPIO_AS_PINRESET CFLAGS_CORTEX_M = -mthumb -mabi=aapcs -fsingle-precision-constant -Wdouble-promotion +CFLAGS_MCU_m33 = $(CFLAGS_CORTEX_M) -mcpu=cortex-m33 -march=armv8-m.main+dsp -mcmse -mfpu=fpv5-sp-d16 -mfloat-abi=hard + CFLAGS_MCU_m4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard CFLAGS_MCU_m0 = $(CFLAGS_CORTEX_M) -fshort-enums -mtune=cortex-m0 -mcpu=cortex-m0 -mfloat-abi=soft -fno-builtin @@ -125,10 +130,6 @@ endif LIBS = \ ifeq ($(MCU_VARIANT), nrf52) -LIBGCC_FILE_NAME = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) - -LIBS += -L $(dir $(LIBGCC_FILE_NAME)) -lgcc - SRC_LIB += $(addprefix lib/,\ libm/math.c \ @@ -153,6 +154,38 @@ SRC_LIB += $(addprefix lib/,\ endif +ifeq ($(MCU_VARIANT), nrf91) + +SRC_LIB += $(addprefix lib/,\ + libm/math.c \ + libm/fmodf.c \ + libm/nearbyintf.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 \ + ) + +SRC_NRFX += $(addprefix lib/nrfx/drivers/src/,\ + nrfx_uarte.c \ + nrfx_twim.c \ + ) + +include drivers/secureboot/secureboot.mk + +endif + SRC_LIB += $(addprefix lib/,\ libc/string0.c \ mp-readline/readline.c \ @@ -271,13 +304,16 @@ FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py') FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) endif +LIBGCC_FILE_NAME = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) +LIBS += -L $(dir $(LIBGCC_FILE_NAME)) -lgcc + OBJ += $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) -OBJ += $(addprefix $(BUILD)/, $(SRC_LIB:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_NRFX:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_NRFX_HAL:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SYSTEM_C_SRC:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_LIB:.c=.o)) OBJ += $(BUILD)/pins_gen.o $(BUILD)/$(FATFS_DIR)/ff.o: COPT += -Os @@ -285,7 +321,11 @@ $(filter $(PY_BUILD)/../extmod/vfs_fat_%.o, $(PY_O)): COPT += -Os .PHONY: all flash deploy sd binary hex +ifeq ($(MCU_VARIANT), nrf91) +all: binary hex secureboot +else all: binary hex +endif OUTPUT_FILENAME = firmware @@ -305,10 +345,21 @@ FLASHER ?= ifeq ($(FLASHER),) +ifeq ($(MCU_VARIANT), nrf91) + +deploy: $(BUILD)/$(OUTPUT_FILENAME).hex $(BUILD)/secureboot.hex + nrfjprog --program $(BUILD)/secureboot.hex --sectorerase -f $(MCU_VARIANT) + nrfjprog --program $(BUILD)/$(OUTPUT_FILENAME).hex --sectorerase -f $(MCU_VARIANT) + nrfjprog --reset -f $(MCU_VARIANT) + +else + deploy: $(BUILD)/$(OUTPUT_FILENAME).hex nrfjprog --program $< --sectorerase -f $(MCU_VARIANT) nrfjprog --reset -f $(MCU_VARIANT) +endif + sd: $(BUILD)/$(OUTPUT_FILENAME).hex nrfjprog --eraseall -f $(MCU_VARIANT) nrfjprog --program $(SOFTDEV_HEX) -f $(MCU_VARIANT) diff --git a/ports/nrf/boards/nrf9160_1M_256k.ld b/ports/nrf/boards/nrf9160_1M_256k.ld new file mode 100644 index 0000000000..6347095a89 --- /dev/null +++ b/ports/nrf/boards/nrf9160_1M_256k.ld @@ -0,0 +1,13 @@ +/* + GNU linker script for NRF9160 NS +*/ + +_flash_size = 1M; +_ram_size = 256K; +_sd_size = 0x00008000; +_sd_ram = 0x00020000; +_fs_size = 80K; + +/* produce a link error if there is not this amount of RAM for these sections */ +_stack_size = 32K; +_minimum_heap_size = 64K; diff --git a/ports/nrf/boards/nrf9160_1M_256k_secure.ld b/ports/nrf/boards/nrf9160_1M_256k_secure.ld new file mode 100644 index 0000000000..79db18ab22 --- /dev/null +++ b/ports/nrf/boards/nrf9160_1M_256k_secure.ld @@ -0,0 +1,6 @@ +/* Specify the memory areas */ +MEMORY +{ + FLASH_TEXT (rx) : ORIGIN = 0x00000000, LENGTH = 32K + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K +} diff --git a/ports/nrf/boards/nrf91_prefix.c b/ports/nrf/boards/nrf91_prefix.c new file mode 100644 index 0000000000..d8bb0fc70b --- /dev/null +++ b/ports/nrf/boards/nrf91_prefix.c @@ -0,0 +1,29 @@ +// nrf91_prefix.c becomes the initial portion of the generated pins file. + +#include + +#include "py/obj.h" +#include "py/mphal.h" +#include "pin.h" + +#define AF(af_idx, af_fn, af_unit, af_type, af_ptr) \ +{ \ + { &pin_af_type }, \ + .name = MP_QSTR_AF ## af_idx ## _ ## af_fn ## af_unit, \ + .idx = (af_idx), \ + .fn = AF_FN_ ## af_fn, \ + .unit = (af_unit), \ + .type = AF_PIN_TYPE_ ## af_fn ## _ ## af_type, \ + .af_fn = (af_ptr) \ +} + +#define PIN(p_pin, p_af, p_adc_num, p_adc_channel) \ +{ \ + { &pin_type }, \ + .name = MP_QSTR_P ## p_pin, \ + .pin = (p_pin), \ + .num_af = (sizeof(p_af) / sizeof(pin_af_obj_t)), \ + .af = p_af, \ + .adc_num = p_adc_num, \ + .adc_channel = p_adc_channel, \ +} diff --git a/ports/nrf/device/startup_nrf9160.c b/ports/nrf/device/startup_nrf9160.c new file mode 100644 index 0000000000..5a32ddff32 --- /dev/null +++ b/ports/nrf/device/startup_nrf9160.c @@ -0,0 +1,270 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Glenn Ruben Bakke + * + * 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 + +extern uint32_t _estack; +extern uint32_t _sidata; +extern uint32_t _sdata; +extern uint32_t _edata; +extern uint32_t _sbss; +extern uint32_t _ebss; + +typedef void (*func)(void); + +extern void _start(void) __attribute__((noreturn)); +extern void SystemInit(void); + +void Default_Handler(void) { while (1); } + +void Reserved_Handler1(void) { while (1); } +void Reserved_Handler2(void) { while (1); } +void Reserved_Handler3(void) { while (1); } +void Reserved_Handler4(void) { while (1); } +void Reserved_Handler5(void) { while (1); } +void Reserved_Handler6(void) { while (1); } +void Reserved_Handler7(void) { while (1); } +void Reserved_Handler8(void) { while (1); } +void Reserved_Handler9(void) { while (1); } +void Reserved_Handler10(void) { while (1); } +void Reserved_Handler11(void) { while (1); } +void Reserved_Handler12(void) { while (1); } +void Reserved_Handler13(void) { while (1); } +void Reserved_Handler14(void) { while (1); } +void Reserved_Handler15(void) { while (1); } +void Reserved_Handler16(void) { while (1); } +void Reserved_Handler17(void) { while (1); } +void Reserved_Handler18(void) { while (1); } +void Reserved_Handler19(void) { while (1); } +void Reserved_Handler20(void) { while (1); } +void Reserved_Handler21(void) { while (1); } +void Reserved_Handler22(void) { while (1); } +void Reserved_Handler23(void) { while (1); } +void Reserved_Handler24(void) { while (1); } +void Reserved_Handler25(void) { while (1); } +void Reserved_Handler26(void) { while (1); } +void Reserved_Handler27(void) { while (1); } +void Reserved_Handler28(void) { while (1); } +void Reserved_Handler29(void) { while (1); } +void Reserved_Handler30(void) { while (1); } +void Reserved_Handler31(void) { while (1); } +void Reserved_Handler32(void) { while (1); } +void Reserved_Handler33(void) { while (1); } +void Reserved_Handler34(void) { while (1); } +void Reserved_Handler35(void) { while (1); } +void Reserved_Handler36(void) { while (1); } +void Reserved_Handler37(void) { while (1); } +void Reserved_Handler38(void) { while (1); } + +void Default_NMI_Handler (void) { while (1); } +void Default_HardFault_Handler (void) { while (1); } +void Default_MemoryManagement_Handler (void) { while (1); } +void Default_BusFault_Handler (void) { while (1); } +void Default_UsageFault_Handler (void) { while (1); } +void Default_SecureFault_Handler (void) { while (1); } +void Default_SVC_Handler (void) { while (1); } +void Default_DebugMon_Handler (void) { while (1); } +void Default_PendSV_Handler (void) { while (1); } +void Default_SysTick_Handler (void) { while (1); } + +void Default_SPU_IRQHandler (void) { while (1); } +void Default_CLOCK_POWER_IRQHandler (void) { while (1); } +void Default_UARTE0_SPIM0_SPIS0_TWIM0_TWIS0_IRQHandler (void) { while (1); } +void Default_UARTE1_SPIM1_SPIS1_TWIM1_TWIS1_IRQHandler (void) { while (1); } +void Default_UARTE2_SPIM2_SPIS2_TWIM2_TWIS2_IRQHandler (void) { while (1); } +void Default_UARTE3_SPIM3_SPIS3_TWIM3_TWIS3_IRQHandler (void) { while (1); } +void Default_GPIOTE0_IRQHandler (void) { while (1); } +void Default_SAADC_IRQHandler (void) { while (1); } +void Default_TIMER0_IRQHandler (void) { while (1); } +void Default_TIMER1_IRQHandler (void) { while (1); } +void Default_TIMER2_IRQHandler (void) { while (1); } +void Default_RTC0_IRQHandler (void) { while (1); } +void Default_RTC1_IRQHandler (void) { while (1); } +void Default_WDT_IRQHandler (void) { while (1); } +void Default_EGU0_IRQHandler (void) { while (1); } +void Default_EGU1_IRQHandler (void) { while (1); } +void Default_EGU2_IRQHandler (void) { while (1); } +void Default_EGU3_IRQHandler (void) { while (1); } +void Default_EGU4_IRQHandler (void) { while (1); } +void Default_EGU5_IRQHandler (void) { while (1); } +void Default_PWM0_IRQHandler (void) { while (1); } +void Default_PWM1_IRQHandler (void) { while (1); } +void Default_PWM2_IRQHandler (void) { while (1); } +void Default_PWM3_IRQHandler (void) { while (1); } +void Default_PDM_IRQHandler (void) { while (1); } +void Default_I2S_IRQHandler (void) { while (1); } +void Default_IPC_IRQHandler (void) { while (1); } +void Default_FPU_IRQHandler (void) { while (1); } +void Default_GPIOTE1_IRQHandler (void) { while (1); } +void Default_KMU_IRQHandler (void) { while (1); } +void Default_CRYPTOCELL_IRQHandler (void) { while (1); } + +void Reset_Handler(void) { + uint32_t * p_src = &_sidata; + uint32_t * p_dest = &_sdata; + + while (p_dest < &_edata) { + *p_dest++ = *p_src++; + } + + uint32_t * p_bss = &_sbss; + uint32_t * p_bss_end = &_ebss; + while (p_bss < p_bss_end) { + *p_bss++ = 0ul; + } + + SystemInit(); + _start(); +} + +void NMI_Handler (void) __attribute__ ((weak, alias("Default_Handler"))); +void HardFault_Handler (void) __attribute__ ((weak, alias("Default_HardFault_Handler"))); +void MemoryManagement_Handler (void) __attribute__ ((weak, alias("Default_MemoryManagement_Handler"))); +void BusFault_Handler (void) __attribute__ ((weak, alias("Default_BusFault_Handler"))); +void UsageFault_Handler (void) __attribute__ ((weak, alias("Default_UsageFault_Handler"))); +void SecureFault_Handler (void) __attribute__ ((weak, alias("Default_SecureFault_Handler"))); +void SVC_Handler (void) __attribute__ ((weak, alias("Default_SVC_Handler"))); +void DebugMon_Handler (void) __attribute__ ((weak, alias("Default_DebugMon_Handler"))); +void PendSV_Handler (void) __attribute__ ((weak, alias("Default_PendSV_Handler"))); +void SysTick_Handler (void) __attribute__ ((weak, alias("Default_SysTick_Handler"))); + +void SPU_IRQHandler (void) __attribute__ ((weak, alias("Default_SPU_IRQHandler"))); +void CLOCK_POWER_IRQHandler (void) __attribute__ ((weak, alias("Default_CLOCK_POWER_IRQHandler"))); +void UARTE0_SPIM0_SPIS0_TWIM0_TWIS0_IRQHandler (void) __attribute__ ((weak, alias("Default_UARTE0_SPIM0_SPIS0_TWIM0_TWIS0_IRQHandler"))); +void UARTE1_SPIM1_SPIS1_TWIM1_TWIS1_IRQHandler (void) __attribute__ ((weak, alias("Default_UARTE1_SPIM1_SPIS1_TWIM1_TWIS1_IRQHandler"))); +void UARTE2_SPIM2_SPIS2_TWIM2_TWIS2_IRQHandler (void) __attribute__ ((weak, alias("Default_UARTE2_SPIM2_SPIS2_TWIM2_TWIS2_IRQHandler"))); +void UARTE3_SPIM3_SPIS3_TWIM3_TWIS3_IRQHandler (void) __attribute__ ((weak, alias("Default_UARTE3_SPIM3_SPIS3_TWIM3_TWIS3_IRQHandler"))); +void GPIOTE0_IRQHandler (void) __attribute__ ((weak, alias("Default_GPIOTE0_IRQHandler"))); +void SAADC_IRQHandler (void) __attribute__ ((weak, alias("Default_SAADC_IRQHandler"))); +void TIMER0_IRQHandler (void) __attribute__ ((weak, alias("Default_TIMER0_IRQHandler"))); +void TIMER1_IRQHandler (void) __attribute__ ((weak, alias("Default_TIMER1_IRQHandler"))); +void TIMER2_IRQHandler (void) __attribute__ ((weak, alias("Default_TIMER2_IRQHandler"))); +void RTC0_IRQHandler (void) __attribute__ ((weak, alias("Default_RTC0_IRQHandler"))); +void RTC1_IRQHandler (void) __attribute__ ((weak, alias("Default_RTC1_IRQHandler"))); +void WDT_IRQHandler (void) __attribute__ ((weak, alias("Default_WDT_IRQHandler"))); +void EGU0_IRQHandler (void) __attribute__ ((weak, alias("Default_EGU0_IRQHandler"))); +void EGU1_IRQHandler (void) __attribute__ ((weak, alias("Default_EGU1_IRQHandler"))); +void EGU2_IRQHandler (void) __attribute__ ((weak, alias("Default_EGU2_IRQHandler"))); +void EGU3_IRQHandler (void) __attribute__ ((weak, alias("Default_EGU3_IRQHandler"))); +void EGU4_IRQHandler (void) __attribute__ ((weak, alias("Default_EGU4_IRQHandler"))); +void EGU5_IRQHandler (void) __attribute__ ((weak, alias("Default_EGU5_IRQHandler"))); +void PWM0_IRQHandler (void) __attribute__ ((weak, alias("Default_PWM0_IRQHandler"))); +void PWM1_IRQHandler (void) __attribute__ ((weak, alias("Default_PWM1_IRQHandler"))); +void PWM2_IRQHandler (void) __attribute__ ((weak, alias("Default_PWM2_IRQHandler"))); +void PWM3_IRQHandler (void) __attribute__ ((weak, alias("Default_PWM3_IRQHandler"))); +void PDM_IRQHandler (void) __attribute__ ((weak, alias("Default_PDM_IRQHandler"))); +void I2S_IRQHandler (void) __attribute__ ((weak, alias("Default_I2S_IRQHandler"))); +void IPC_IRQHandler (void) __attribute__ ((weak, alias("Default_IPC_IRQHandler"))); +void FPU_IRQHandler (void) __attribute__ ((weak, alias("Default_FPU_IRQHandler"))); +void GPIOTE1_IRQHandler (void) __attribute__ ((weak, alias("Default_GPIOTE1_IRQHandler"))); +void KMU_IRQHandler (void) __attribute__ ((weak, alias("Default_KMU_IRQHandler"))); +void CRYPTOCELL_IRQHandler (void) __attribute__ ((weak, alias("Default_CRYPTOCELL_IRQHandler"))); + +const func __Vectors[] __attribute__ ((section(".isr_vector"),used)) = { + (func)&_estack, + Reset_Handler, + NMI_Handler, + HardFault_Handler, + MemoryManagement_Handler, + BusFault_Handler, + UsageFault_Handler, + SecureFault_Handler, + Reserved_Handler1, + Reserved_Handler2, + Reserved_Handler3, + SVC_Handler, + DebugMon_Handler, + Reserved_Handler4, + PendSV_Handler, + SysTick_Handler, + + /* External Interrupts */ + Reserved_Handler5, + Reserved_Handler6, + Reserved_Handler7, + SPU_IRQHandler, + Reserved_Handler8, + CLOCK_POWER_IRQHandler, + Reserved_Handler9, + Reserved_Handler10, + UARTE0_SPIM0_SPIS0_TWIM0_TWIS0_IRQHandler, + UARTE1_SPIM1_SPIS1_TWIM1_TWIS1_IRQHandler, + UARTE2_SPIM2_SPIS2_TWIM2_TWIS2_IRQHandler, + UARTE3_SPIM3_SPIS3_TWIM3_TWIS3_IRQHandler, + Reserved_Handler11, + GPIOTE0_IRQHandler, + SAADC_IRQHandler, + TIMER0_IRQHandler, + TIMER1_IRQHandler, + TIMER2_IRQHandler, + Reserved_Handler12, + Reserved_Handler13, + RTC0_IRQHandler, + RTC1_IRQHandler, + Reserved_Handler14, + Reserved_Handler15, + WDT_IRQHandler, + Reserved_Handler16, + Reserved_Handler17, + EGU0_IRQHandler, + EGU1_IRQHandler, + EGU2_IRQHandler, + EGU3_IRQHandler, + EGU4_IRQHandler, + EGU5_IRQHandler, + PWM0_IRQHandler, + PWM1_IRQHandler, + PWM2_IRQHandler, + PWM3_IRQHandler, + Reserved_Handler18, + PDM_IRQHandler, + Reserved_Handler19, + I2S_IRQHandler, + Reserved_Handler20, + IPC_IRQHandler, + Reserved_Handler21, + FPU_IRQHandler, + Reserved_Handler22, + Reserved_Handler23, + Reserved_Handler24, + Reserved_Handler25, + GPIOTE1_IRQHandler, + Reserved_Handler26, + Reserved_Handler27, + Reserved_Handler28, + Reserved_Handler29, + Reserved_Handler30, + Reserved_Handler31, + Reserved_Handler32, + KMU_IRQHandler, + Reserved_Handler33, + Reserved_Handler34, + Reserved_Handler35, + Reserved_Handler36, + Reserved_Handler37, + Reserved_Handler38, + CRYPTOCELL_IRQHandler, +}; diff --git a/ports/nrf/drivers/flash.h b/ports/nrf/drivers/flash.h index 3dd5d06dd4..ed53afd81b 100644 --- a/ports/nrf/drivers/flash.h +++ b/ports/nrf/drivers/flash.h @@ -34,6 +34,10 @@ #elif defined(NRF52_SERIES) #define FLASH_PAGESIZE (4096) + +#elif defined(NRF91_SERIES) +#define FLASH_PAGESIZE (4096) + #else #error Unknown chip #endif diff --git a/ports/nrf/drivers/secureboot/secureboot.mk b/ports/nrf/drivers/secureboot/secureboot.mk new file mode 100644 index 0000000000..89833cb6de --- /dev/null +++ b/ports/nrf/drivers/secureboot/secureboot.mk @@ -0,0 +1,55 @@ +DRIVERS_SECUREBOOT_DIR = drivers/secureboot + +SRC_SECUREBOOT += $(addprefix $(DRIVERS_SECUREBOOT_DIR)/,\ + secureboot_main.c \ + ) + +SRC_SECUREBOOT += $(addprefix device/,\ + startup_nrf9160.c \ + ) + +SRC_SECUREBOOT += $(addprefix $(TOP)/lib/nrfx/mdk/,\ + system_nrf9160.c \ + ) + +.PHONY: secureboot clean + +INC_SECUREBOOT += -I./../../lib/nrfx/mdk +INC_SECUREBOOT += -I./../../lib/cmsis/inc + +MCU_SERIES = m33 + +CFLAGS_CORTEX_M = -mthumb -mabi=aapcs -fsingle-precision-constant -Wdouble-promotion + +CFLAGS_MCU_m33 = $(CFLAGS_CORTEX_M) -mcpu=cortex-m33 -march=armv8-m.main+dsp -mcmse -mfpu=fpv5-sp-d16 -mfloat-abi=hard + + +CFLAGS_SECUREBOOT += -DNRF9160_XXAA +CFLAGS_SECUREBOOT += $(CFLAGS_MCU_$(MCU_SERIES)) +CFLAGS_SECUREBOOT += -Wall -Werror -g -ansi -std=c11 -nostdlib $(COPT) +CFLAGS_SECUREBOOT += -fno-strict-aliasing + +LD_FILES_SECUREBOOT += nrf9160_1M_256k_secure.ld common.ld + +LDFLAGS_SECUREBOOT = $(CFLAGS_SECUREBOOT) +LDFLAGS_SECUREBOOT += -Xlinker -Map=$(@:.elf=.map) +LDFLAGS_SECUREBOOT += -mthumb -mabi=aapcs $(addprefix -T,$(LD_FILES_SECUREBOOT)) -L ./boards + +CC = arm-none-eabi-gcc +SIZE = arm-none-eabi-size +OBJCOPY = arm-none-eabi-objcopy + +LIBGCC_FILE_NAME = $(shell $(CC) $(CFLAGS_SECUREBOOT) -print-libgcc-file-name) +LIBC_FILE_NAME = $(shell $(CC) $(CFLAGS_SECUREBOOT) -print-file-name=libc.a) +LIBS_SECUREBOOT += -L $(dir $(LIBGCC_FILE_NAME)) -lgcc +LIBS_SECUREBOOT += -L $(dir $(LIBC_FILE_NAME)) -lc + +$(BUILD)/secureboot.elf: + $(Q)$(CC) $(LDFLAGS_SECUREBOOT) $(SRC_SECUREBOOT) $(INC_SECUREBOOT) -O3 -o $@ $(LIBS_SECUREBOOT) + $(SIZE) $@ + +$(BUILD)/secureboot.hex: $(BUILD)/secureboot.elf + $(OBJCOPY) -O ihex $< $@ + +secureboot: $(BUILD)/secureboot.hex + @echo "Secure boot" diff --git a/ports/nrf/drivers/secureboot/secureboot_main.c b/ports/nrf/drivers/secureboot/secureboot_main.c new file mode 100644 index 0000000000..748e080a24 --- /dev/null +++ b/ports/nrf/drivers/secureboot/secureboot_main.c @@ -0,0 +1,194 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Glenn Ruben Bakke + * + * 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 + +// Secure flash 32K. +#define SECURE_32K_FLASH_PAGE_START (0) +#define SECURE_32K_FLASH_PAGE_END (0) + +// Non-secure flash 992K. +#define NONSECURE_32K_FLASH_PAGE_START (1) +#define NONSECURE_32K_FLASH_PAGE_END (31) + +// Secure RAM 64K. +#define SECURE_8K_RAM_BLOCK_START (0) +#define SECURE_8K_RAM_BLOCK_END (7) + +// Non-secure RAM 128K + 64K BSD lib. +#define NONSECURE_8K_RAM_BLOCK_START (8) +#define NONSECURE_8K_RAM_BLOCK_END (31) + +#define PERIPHERAL_ID_GET(base_addr) (((uint32_t)(base_addr) >> 12) & 0xFF) + +#if !defined(__ARM_FEATURE_CMSE) + #pragma warning "CMSE not enabled" +#endif + +static void configure_flash(void) { + for (uint8_t i = SECURE_32K_FLASH_PAGE_START; i <= SECURE_32K_FLASH_PAGE_END; i++) { + uint32_t perm = 0; + perm |= (SPU_FLASHREGION_PERM_EXECUTE_Enable << SPU_FLASHREGION_PERM_EXECUTE_Pos); + perm |= (SPU_FLASHREGION_PERM_WRITE_Enable << SPU_FLASHREGION_PERM_WRITE_Pos); + perm |= (SPU_FLASHREGION_PERM_READ_Enable << SPU_FLASHREGION_PERM_READ_Pos); + perm |= (SPU_FLASHREGION_PERM_LOCK_Locked << SPU_FLASHREGION_PERM_LOCK_Pos); + perm |= (SPU_FLASHREGION_PERM_SECATTR_Secure << SPU_FLASHREGION_PERM_SECATTR_Pos); + NRF_SPU_S->FLASHREGION[i].PERM = perm; + } + + for (uint8_t i = NONSECURE_32K_FLASH_PAGE_START; i <= NONSECURE_32K_FLASH_PAGE_END; i++) { + uint32_t perm = 0; + perm |= (SPU_FLASHREGION_PERM_EXECUTE_Enable << SPU_FLASHREGION_PERM_EXECUTE_Pos); + perm |= (SPU_FLASHREGION_PERM_WRITE_Enable << SPU_FLASHREGION_PERM_WRITE_Pos); + perm |= (SPU_FLASHREGION_PERM_READ_Enable << SPU_FLASHREGION_PERM_READ_Pos); + perm |= (SPU_FLASHREGION_PERM_LOCK_Locked << SPU_FLASHREGION_PERM_LOCK_Pos); + perm |= (SPU_FLASHREGION_PERM_SECATTR_Non_Secure << SPU_FLASHREGION_PERM_SECATTR_Pos); + NRF_SPU_S->FLASHREGION[i].PERM = perm; + } +} + +static void configure_ram(void) { + for (uint8_t i = SECURE_8K_RAM_BLOCK_START; i <= SECURE_8K_RAM_BLOCK_END; i++) { + uint32_t perm = 0; + perm |= (SPU_RAMREGION_PERM_EXECUTE_Enable << SPU_RAMREGION_PERM_EXECUTE_Pos); + perm |= (SPU_RAMREGION_PERM_WRITE_Enable << SPU_RAMREGION_PERM_WRITE_Pos); + perm |= (SPU_RAMREGION_PERM_READ_Enable << SPU_RAMREGION_PERM_READ_Pos); + perm |= (SPU_RAMREGION_PERM_LOCK_Locked << SPU_RAMREGION_PERM_LOCK_Pos); + perm |= (SPU_RAMREGION_PERM_SECATTR_Secure << SPU_RAMREGION_PERM_SECATTR_Pos); + NRF_SPU_S->RAMREGION[i].PERM = perm; + } + + for (uint8_t i = NONSECURE_8K_RAM_BLOCK_START; i <= NONSECURE_8K_RAM_BLOCK_END; i++) { + uint32_t perm = 0; + perm |= (SPU_RAMREGION_PERM_EXECUTE_Enable << SPU_RAMREGION_PERM_EXECUTE_Pos); + perm |= (SPU_RAMREGION_PERM_WRITE_Enable << SPU_RAMREGION_PERM_WRITE_Pos); + perm |= (SPU_RAMREGION_PERM_READ_Enable << SPU_RAMREGION_PERM_READ_Pos); + perm |= (SPU_RAMREGION_PERM_LOCK_Locked << SPU_RAMREGION_PERM_LOCK_Pos); + perm |= (SPU_RAMREGION_PERM_SECATTR_Non_Secure << SPU_RAMREGION_PERM_SECATTR_Pos); + NRF_SPU_S->RAMREGION[i].PERM = perm; + } +} + +static void peripheral_setup(uint8_t peripheral_id) +{ + NVIC_DisableIRQ(peripheral_id); + uint32_t perm = 0; + perm |= (SPU_PERIPHID_PERM_PRESENT_IsPresent << SPU_PERIPHID_PERM_PRESENT_Pos); + perm |= (SPU_PERIPHID_PERM_SECATTR_NonSecure << SPU_PERIPHID_PERM_SECATTR_Pos); + perm |= (SPU_PERIPHID_PERM_LOCK_Locked << SPU_PERIPHID_PERM_LOCK_Pos); + NRF_SPU_S->PERIPHID[peripheral_id].PERM = perm; + + NVIC_SetTargetState(peripheral_id); +} + +static void configure_peripherals(void) +{ + NRF_SPU_S->GPIOPORT[0].PERM = 0; + peripheral_setup(PERIPHERAL_ID_GET(NRF_REGULATORS_S)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_CLOCK_S)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_UARTE0_S)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_UARTE1_S)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_UARTE2_S)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_UARTE3_S)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_SAADC_S)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_TIMER0_S)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_TIMER1_S)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_TIMER2_S)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_RTC0_S)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_RTC1_S)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_DPPIC_S)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_WDT_S)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_EGU1_S)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_EGU2_S)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_EGU3_S)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_EGU4_S)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_EGU5_S)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_PWM0_S)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_PWM1_S)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_PWM2_S)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_PWM3_S)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_PDM_S)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_I2S_S)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_IPC_S)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_FPU_S)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_GPIOTE1_NS)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_NVMC_S)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_VMC_S)); + peripheral_setup(PERIPHERAL_ID_GET(NRF_P0_NS)); +} + +typedef void __attribute__((cmse_nonsecure_call)) nsfunc(void); + +static void jump_to_non_secure(void) +{ + TZ_SAU_Disable(); + SAU->CTRL |= SAU_CTRL_ALLNS_Msk; + + // Set NS vector table. + uint32_t * vtor_ns = (uint32_t *)0x8000; + SCB_NS->VTOR = (uint32_t)vtor_ns; + + // Allow for FPU to be used by NS. + SCB->NSACR |= (1UL << SCB_NSACR_CP10_Pos) | (1UL << SCB_NSACR_CP11_Pos); + + // Set stack pointers. + __TZ_set_MSP_NS(vtor_ns[0]); + __TZ_set_PSP_NS(0); + + uint32_t control_ns = __TZ_get_CONTROL_NS(); + control_ns &= ~(CONTROL_SPSEL_Msk | CONTROL_nPRIV_Msk); + __TZ_set_CONTROL_NS(control_ns); + + // Cast NS Reset_Handler to a non-secure function. + nsfunc *fp = (nsfunc *)vtor_ns[1]; + fp = (nsfunc *)((intptr_t)(fp) & ~1); + + if (cmse_is_nsfptr(fp)) { + __DSB(); + __ISB(); + + // Jump to Non-Secure function. + fp(); + } +} + +int main(void) { + configure_flash(); + configure_ram(); + configure_peripherals(); + + jump_to_non_secure(); + + while (1) { + ; + } + + return 0; +} + +void _start(void) {main();} + diff --git a/ports/nrf/main.c b/ports/nrf/main.c index ce8512aee3..26ac0ad6c9 100644 --- a/ports/nrf/main.c +++ b/ports/nrf/main.c @@ -299,9 +299,10 @@ MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open); #endif #endif + void HardFault_Handler(void) { -#if defined(NRF52_SERIES) +#if defined(NRF52_SERIES) || defined(NRF91_SERIES) static volatile uint32_t reg; static volatile uint32_t reg2; static volatile uint32_t bfar; diff --git a/ports/nrf/modules/machine/modmachine.c b/ports/nrf/modules/machine/modmachine.c index 841e136d0d..1436495fcb 100644 --- a/ports/nrf/modules/machine/modmachine.c +++ b/ports/nrf/modules/machine/modmachine.c @@ -78,8 +78,10 @@ void machine_init(void) { reset_cause = PYB_RESET_LOCKUP; } else if (state & POWER_RESETREAS_OFF_Msk) { reset_cause = PYB_RESET_POWER_ON; +#if !defined(NRF9160_XXAA) } else if (state & POWER_RESETREAS_LPCOMP_Msk) { reset_cause = PYB_RESET_LPCOMP; +#endif } else if (state & POWER_RESETREAS_DIF_Msk) { reset_cause = PYB_RESET_DIF; #if defined(NRF52_SERIES) diff --git a/ports/nrf/mphalport.c b/ports/nrf/mphalport.c index b915c23e47..57d61b041d 100644 --- a/ports/nrf/mphalport.c +++ b/ports/nrf/mphalport.c @@ -98,7 +98,6 @@ void mp_hal_delay_us(mp_uint_t us) if (us == 0) { return; } - register uint32_t delay __ASM ("r0") = us; __ASM volatile ( #ifdef NRF51 @@ -118,7 +117,7 @@ void mp_hal_delay_us(mp_uint_t us) " NOP\n" " NOP\n" " NOP\n" -#ifdef NRF52 +#if defined(NRF52) || defined(NRF9160_XXAA) " NOP\n" " NOP\n" " NOP\n" diff --git a/ports/nrf/nrf91_af.csv b/ports/nrf/nrf91_af.csv new file mode 100644 index 0000000000..7d060f68ff --- /dev/null +++ b/ports/nrf/nrf91_af.csv @@ -0,0 +1,32 @@ +P0,P0 +P1,P1 +P2,P2 +P3,P3 +P4,P4 +P5,P5 +P6,P6 +P7,P7 +P8,P8 +P9,P9 +P10,P10 +P11,P11 +P12,P12 +P13,P13 +P14,P14 +P15,P15 +P16,P16 +P17,P17 +P18,P18 +P19,P19 +P20,P20 +P21,P21 +P22,P22 +P23,P23 +P24,P24 +P25,P25 +P26,P26 +P27,P27 +P28,P28 +P29,P29 +P30,P30 +P31,P31 diff --git a/ports/nrf/nrfx_config.h b/ports/nrf/nrfx_config.h index 505ecf57bd..65b37e6ace 100644 --- a/ports/nrf/nrfx_config.h +++ b/ports/nrf/nrfx_config.h @@ -45,6 +45,8 @@ #define GPIO_COUNT 1 #elif NRF52840 || NRF52840_XXAA #define GPIO_COUNT 2 +#elif NRF9160_XXAA + #define GPIO_COUNT 1 #endif #if defined(NRF52840) @@ -63,12 +65,27 @@ #define NRFX_GPIOTE_CONFIG_IRQ_PRIORITY 6 #endif -#define NRFX_UART_ENABLED 1 -#define NRFX_UART0_ENABLED 1 +#if defined(NRF51) || defined(NRF52_SERIES) + #define NRFX_UART_ENABLED 1 + #define NRFX_UART0_ENABLED 1 + #define NRFX_UART1_ENABLED 1 +#else + #define NRFX_UARTE_ENABLED 1 + #define NRFX_UARTE0_ENABLED 1 + #define NRFX_UARTE1_ENABLED 1 + #define NRFX_UARTE2_ENABLED 1 + #define NRFX_UARTE3_ENABLED 1 +#endif -#define NRFX_TWI_ENABLED (MICROPY_PY_MACHINE_I2C) -#define NRFX_TWI0_ENABLED 1 -#define NRFX_TWI1_ENABLED 1 +#if defined(NRF51) || defined(NRF52_SERIES) + #define NRFX_TWI_ENABLED (MICROPY_PY_MACHINE_I2C) + #define NRFX_TWI0_ENABLED 1 + #define NRFX_TWI1_ENABLED 1 +#elif defined(NRF9160_XXAA) + #define NRFX_TWIM_ENABLED (MICROPY_PY_MACHINE_I2C) + #define NRFX_TWIM0_ENABLED 1 + #define NRFX_TWIM1_ENABLED 1 +#endif #if defined(NRF51) || defined(NRF52832) #define NRFX_SPI_ENABLED (MICROPY_PY_MACHINE_HW_SPI) @@ -84,6 +101,15 @@ #define NRFX_SPIM1_ENABLED 1 #define NRFX_SPIM2_ENABLED 1 #define NRFX_SPIM3_ENABLED (NRF52840) +#elif defined(NRF9160_XXAA) + #define NRFX_SPIM_ENABLED (MICROPY_PY_MACHINE_HW_SPI) + #define NRFX_SPIM0_ENABLED 1 + #define NRFX_SPIM1_ENABLED 1 + + // 0 NRF_GPIO_PIN_NOPULL + // 1 NRF_GPIO_PIN_PULLDOWN + // 3 NRF_GPIO_PIN_PULLUP + #define NRFX_SPIM_MISO_PULL_CFG 1 #endif // NRF51 // 0 NRF_GPIO_PIN_NOPULL @@ -101,8 +127,8 @@ #define NRFX_TIMER0_ENABLED 1 #define NRFX_TIMER1_ENABLED (!MICROPY_PY_MACHINE_SOFT_PWM) #define NRFX_TIMER2_ENABLED 1 -#define NRFX_TIMER3_ENABLED (!NRF51) -#define NRFX_TIMER4_ENABLED (!NRF51) +#define NRFX_TIMER3_ENABLED (!NRF51) && (!NRF9160_XXAA) +#define NRFX_TIMER4_ENABLED (!NRF51) && (!NRF9160_XXAA) #define NRFX_PWM_ENABLED (!NRF51) && MICROPY_PY_MACHINE_HW_PWM @@ -125,6 +151,10 @@ #define NRFX_PRS_BOX_0_ENABLED (NRFX_TWI_ENABLED && NRFX_TWI0_ENABLED && NRFX_SPIM_ENABLED && NRFX_SPIM0_ENABLED) #define NRFX_PRS_BOX_1_ENABLED (NRFX_TWI_ENABLED && NRFX_TWI1_ENABLED && NRFX_SPIM_ENABLED && NRFX_SPIM1_ENABLED) #define NRFX_PRS_BOX_2_ENABLED (NRFX_TWI_ENABLED && NRFX_TWI2_ENABLED && NRFX_SPIM_ENABLED && NRFX_SPIM2_ENABLED) +#elif defined(NRF9160_XXAA) + #define NRFX_PRS_BOX_0_ENABLED (NRFX_TWIM_ENABLED && NRFX_TWIM0_ENABLED && NRFX_SPIM_ENABLED && NRFX_SPIM0_ENABLED) + #define NRFX_PRS_BOX_1_ENABLED (NRFX_TWIM_ENABLED && NRFX_TWIM1_ENABLED && NRFX_SPIM_ENABLED && NRFX_SPIM1_ENABLED) + #define NRFX_PRS_BOX_2_ENABLED (NRFX_TWIM_ENABLED && NRFX_TWIM2_ENABLED && NRFX_SPIM_ENABLED && NRFX_SPIM2_ENABLED) #endif #define NRFX_PRS_ENABLED (NRFX_PRS_BOX_0_ENABLED || NRFX_PRS_BOX_1_ENABLED || NRFX_PRS_BOX_2_ENABLED) @@ -132,4 +162,69 @@ #define NRFX_SAADC_ENABLED !(NRF51) && (MICROPY_PY_MACHINE_ADC) #define NRFX_ADC_ENABLED (NRF51) && (MICROPY_PY_MACHINE_ADC) +#if defined(NRF9160_XXAA) + +#define NRF_CLOCK NRF_CLOCK_NS +#define NRF_DPPIC NRF_DPPIC_NS +#define NRF_EGU0 NRF_EGU0_NS +#define NRF_EGU1 NRF_EGU1_NS +#define NRF_EGU2 NRF_EGU2_NS +#define NRF_EGU3 NRF_EGU3_NS +#define NRF_EGU4 NRF_EGU4_NS +#define NRF_EGU5 NRF_EGU5_NS +#define NRF_FPU NRF_FPU_NS +#define NRF_P0 NRF_P0_NS +#define NRF_I2S NRF_I2S_NS +#define NRF_KMU NRF_KMU_NS +#define NRF_NVMC NRF_NVMC_NS +#define NRF_PDM NRF_PDM_NS +#define NRF_POWER NRF_POWER_NS +#define NRF_PWM0 NRF_PWM0_NS +#define NRF_PWM1 NRF_PWM1_NS +#define NRF_PWM2 NRF_PWM2_NS +#define NRF_PWM3 NRF_PWM3_NS +#define NRF_REGULATORS NRF_REGULATORS_NS +#define NRF_RTC0 NRF_RTC0_NS +#define NRF_RTC1 NRF_RTC1_NS +#define NRF_SAADC NRF_SAADC_NS +#define NRF_SPIM0 NRF_SPIM0_NS +#define NRF_SPIM1 NRF_SPIM1_NS +#define NRF_SPIM2 NRF_SPIM2_NS +#define NRF_SPIM3 NRF_SPIM3_NS +#define NRF_SPIS0 NRF_SPIS0_NS +#define NRF_SPIS1 NRF_SPIS1_NS +#define NRF_SPIS2 NRF_SPIS2_NS +#define NRF_SPIS3 NRF_SPIS3_NS +#define NRF_TIMER0 NRF_TIMER0_NS +#define NRF_TIMER1 NRF_TIMER1_NS +#define NRF_TIMER2 NRF_TIMER2_NS +#define NRF_TWIM0 NRF_TWIM0_NS +#define NRF_TWIM1 NRF_TWIM1_NS +#define NRF_TWIM2 NRF_TWIM2_NS +#define NRF_TWIM3 NRF_TWIM3_NS +#define NRF_TWIS0 NRF_TWIS0_NS +#define NRF_TWIS1 NRF_TWIS1_NS +#define NRF_TWIS2 NRF_TWIS2_NS +#define NRF_TWIS3 NRF_TWIS3_NS +#define NRF_UARTE0 NRF_UARTE0_NS +#define NRF_UARTE1 NRF_UARTE1_NS +#define NRF_UARTE2 NRF_UARTE2_NS +#define NRF_UARTE3 NRF_UARTE3_NS +#define NRF_VMC NRF_VMC_NS +#define NRF_WDT NRF_WDT_NS +#define NRF_IPC NRF_IPC_NS + +#define NRF_CRYPTOCELL NRF_CRYPTOCELL_S +#define NRF_FICR NRF_FICR_S +#define NRF_GPIOTE0 NRF_GPIOTE0_S +#define NRF_GPIOTE1 NRF_GPIOTE1_NS +#define NRF_SPU NRF_SPU_S +#define NRF_UICR NRF_UICR_S + +#define NRF_GPIOTE NRF_GPIOTE1_NS +#define GPIOTE_IRQn GPIOTE1_IRQn +#define GPIOTE_IRQHandler GPIOTE1_IRQHandler + +#endif + #endif // NRFX_CONFIG_H diff --git a/ports/nrf/pin_defs_nrf5.h b/ports/nrf/pin_defs_nrf5.h index db05aef995..fb2930d1d1 100644 --- a/ports/nrf/pin_defs_nrf5.h +++ b/ports/nrf/pin_defs_nrf5.h @@ -52,10 +52,15 @@ enum { AF_PIN_TYPE_SPI_NSS, }; +#if defined(NRF51) || defined(NRF52_SERIES) #define PIN_DEFS_PORT_AF_UNION \ NRF_UART_Type *UART; // NRF_SPI_Type *SPIM; // NRF_SPIS_Type *SPIS; +#elif defined(NRF91_SERIES) +#define PIN_DEFS_PORT_AF_UNION \ + NRF_UARTE_Type *UART; +#endif enum { PIN_ADC1 = (1 << 0), From 98c2eabaff6c049810d7cbf8aafb536080ae5b60 Mon Sep 17 00:00:00 2001 From: Glenn Ruben Bakke Date: Thu, 26 Sep 2019 23:59:47 +0200 Subject: [PATCH 0819/1788] nrf/boards: Add nrf9160 pca10090 board. --- ports/nrf/README.md | 3 + ports/nrf/boards/pca10090/mpconfigboard.h | 91 ++++++++++++++++++++++ ports/nrf/boards/pca10090/mpconfigboard.mk | 6 ++ ports/nrf/boards/pca10090/pins.csv | 32 ++++++++ 4 files changed, 132 insertions(+) create mode 100644 ports/nrf/boards/pca10090/mpconfigboard.h create mode 100644 ports/nrf/boards/pca10090/mpconfigboard.mk create mode 100644 ports/nrf/boards/pca10090/pins.csv diff --git a/ports/nrf/README.md b/ports/nrf/README.md index 834e2ea291..1b9c2ec7f0 100644 --- a/ports/nrf/README.md +++ b/ports/nrf/README.md @@ -41,6 +41,8 @@ This is a port of MicroPython to the Nordic Semiconductor nRF series of chips. * [PCA10056](http://www.nordicsemi.com/eng/Products/nRF52840-Preview-DK) * [PCA10059](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-Dongle) * [Particle Xenon](https://docs.particle.io/xenon/) +* nRF9160 + * [PCA10090](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF9160-DK) ## Compile and Flash @@ -132,6 +134,7 @@ evk_nina_b1 | s132 | Peripheral and Central | [Segge pca10056 | s140 | Peripheral and Central | [Segger](#segger-targets) pca10059 | s140 | Peripheral and Central | Manual, SWDIO and SWCLK solder points on the sides. particle_xenon | s140 | Peripheral and Central | [Black Magic Probe](#black-magic-probe-targets) +pca10090 | None (bsdlib.a) | None (LTE/GNSS) | [Segger](#segger-targets) ## IDAP-M/IDAP-Link Targets diff --git a/ports/nrf/boards/pca10090/mpconfigboard.h b/ports/nrf/boards/pca10090/mpconfigboard.h new file mode 100644 index 0000000000..92bb61d695 --- /dev/null +++ b/ports/nrf/boards/pca10090/mpconfigboard.h @@ -0,0 +1,91 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Glenn Ruben Bakke + * + * 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. + */ + +#define PCA10090 + +#define MICROPY_HW_BOARD_NAME "PCA10090" +#define MICROPY_HW_MCU_NAME "NRF9160" +#define MICROPY_PY_SYS_PLATFORM "nrf9160-DK" + +#define MICROPY_PY_MACHINE_UART (1) +#define MICROPY_PY_MACHINE_HW_PWM (0) +#define MICROPY_PY_MACHINE_HW_SPI (1) +#define MICROPY_PY_MACHINE_TIMER (0) +#define MICROPY_PY_MACHINE_RTCOUNTER (0) +#define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_ADC (0) +#define MICROPY_PY_MACHINE_TEMP (0) +#define MICROPY_PY_RANDOM_HW_RNG (0) + +#define MICROPY_MBFS (0) + +#define MICROPY_HW_HAS_LED (1) +#define MICROPY_HW_HAS_SWITCH (0) +#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 (0) +#define MICROPY_HW_ENABLE_RTC (0) +#define MICROPY_HW_ENABLE_TIMER (0) +#define MICROPY_HW_ENABLE_SERVO (0) +#define MICROPY_HW_ENABLE_DAC (0) +#define MICROPY_HW_ENABLE_CAN (0) + +#define MICROPY_HW_LED_COUNT (4) +#define MICROPY_HW_LED_PULLUP (0) + +#define MICROPY_HW_LED1 (2) // LED1 +#define MICROPY_HW_LED2 (3) // LED2 +#define MICROPY_HW_LED3 (4) // LED3 +#define MICROPY_HW_LED4 (5) // LED4 + +// UART config +// VCOM0 +#define MICROPY_HW_UART1_RX (28) +#define MICROPY_HW_UART1_TX (29) +#define MICROPY_HW_UART1_CTS (26) +#define MICROPY_HW_UART1_RTS (27) +#define MICROPY_HW_UART1_HWFC (1) + +/* +// VCOM2 +#define MICROPY_HW_UART1_RX (0) +#define MICROPY_HW_UART1_TX (1) +#define MICROPY_HW_UART1_CTS (15) +#define MICROPY_HW_UART1_RTS (14) +#define MICROPY_HW_UART1_HWFC (1) +*/ + +// SPI0 config +#define MICROPY_HW_SPI0_NAME "SPI0" + +#define MICROPY_HW_SPI0_SCK (13) +#define MICROPY_HW_SPI0_MOSI (11) +#define MICROPY_HW_SPI0_MISO (12) + +#define HELP_TEXT_BOARD_LED "1,2,3,4" diff --git a/ports/nrf/boards/pca10090/mpconfigboard.mk b/ports/nrf/boards/pca10090/mpconfigboard.mk new file mode 100644 index 0000000000..9363900e2b --- /dev/null +++ b/ports/nrf/boards/pca10090/mpconfigboard.mk @@ -0,0 +1,6 @@ +MCU_SERIES = m33 +MCU_VARIANT = nrf91 +MCU_SUB_VARIANT = nrf9160 +LD_FILES += boards/nrf9160_1M_256k.ld + +NRF_DEFINES += -DNRF9160_XXAA -DNRF_TRUSTZONE_NONSECURE diff --git a/ports/nrf/boards/pca10090/pins.csv b/ports/nrf/boards/pca10090/pins.csv new file mode 100644 index 0000000000..7d060f68ff --- /dev/null +++ b/ports/nrf/boards/pca10090/pins.csv @@ -0,0 +1,32 @@ +P0,P0 +P1,P1 +P2,P2 +P3,P3 +P4,P4 +P5,P5 +P6,P6 +P7,P7 +P8,P8 +P9,P9 +P10,P10 +P11,P11 +P12,P12 +P13,P13 +P14,P14 +P15,P15 +P16,P16 +P17,P17 +P18,P18 +P19,P19 +P20,P20 +P21,P21 +P22,P22 +P23,P23 +P24,P24 +P25,P25 +P26,P26 +P27,P27 +P28,P28 +P29,P29 +P30,P30 +P31,P31 From 06ae818f9360e83284c64614144f1ad00998a739 Mon Sep 17 00:00:00 2001 From: ladyada Date: Thu, 3 Oct 2019 02:54:47 -0400 Subject: [PATCH 0820/1788] stm32/boards: Add new board ADAFRUIT_F405_EXPRESS. --- .../ADAFRUIT_F405_EXPRESS/mpconfigboard.h | 86 +++++++++++++++++++ .../ADAFRUIT_F405_EXPRESS/mpconfigboard.mk | 13 +++ .../boards/ADAFRUIT_F405_EXPRESS/pins.csv | 48 +++++++++++ .../stm32f4xx_hal_conf.h | 19 ++++ 4 files changed, 166 insertions(+) create mode 100644 ports/stm32/boards/ADAFRUIT_F405_EXPRESS/mpconfigboard.h create mode 100644 ports/stm32/boards/ADAFRUIT_F405_EXPRESS/mpconfigboard.mk create mode 100644 ports/stm32/boards/ADAFRUIT_F405_EXPRESS/pins.csv create mode 100644 ports/stm32/boards/ADAFRUIT_F405_EXPRESS/stm32f4xx_hal_conf.h diff --git a/ports/stm32/boards/ADAFRUIT_F405_EXPRESS/mpconfigboard.h b/ports/stm32/boards/ADAFRUIT_F405_EXPRESS/mpconfigboard.h new file mode 100644 index 0000000000..36d1d31315 --- /dev/null +++ b/ports/stm32/boards/ADAFRUIT_F405_EXPRESS/mpconfigboard.h @@ -0,0 +1,86 @@ +#define MICROPY_HW_BOARD_NAME "Adafruit Feather STM32F405" +#define MICROPY_HW_MCU_NAME "STM32F405RG" + +#define MICROPY_HW_HAS_SWITCH (0) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_HAS_MMA7660 (0) +#define MICROPY_HW_HAS_LCD (0) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_SERVO (1) +#define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_ENABLE_SDCARD (1) + +// HSE is 12MHz +#define MICROPY_HW_CLK_PLLM (12) +#define MICROPY_HW_CLK_PLLN (336) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (7) +#define MICROPY_HW_CLK_LAST_FREQ (1) + +// The Feather has a 32kHz crystal for the RTC +#define MICROPY_HW_RTC_USE_LSE (1) +#define MICROPY_HW_RTC_USE_US (0) +#define MICROPY_HW_RTC_USE_CALOUT (1) + +// UART config +#define MICROPY_HW_UART3_NAME "UART3" // on RX / TX +#define MICROPY_HW_UART3_TX (pin_B10) // TX +#define MICROPY_HW_UART3_RX (pin_B11) // RX +#define MICROPY_HW_UART3_RTS (pin_B14) // MISO +#define MICROPY_HW_UART3_CTS (pin_B13) // SCK + +#define MICROPY_HW_UART2_NAME "UART2" // on SDA/SCL +#define MICROPY_HW_UART2_TX (pin_B6) // SCL +#define MICROPY_HW_UART2_RX (pin_B7) // SDA + +#define MICROPY_HW_UART6_NAME "UART6" // on D5/D6 +#define MICROPY_HW_UART6_TX (pin_C6) // D6 +#define MICROPY_HW_UART6_RX (pin_C7) // D5 + +// I2C busses +#define MICROPY_HW_I2C1_NAME "I2C1" +#define MICROPY_HW_I2C1_SCL (pin_B6) // SCL +#define MICROPY_HW_I2C1_SDA (pin_B7) // SDA +#define MICROPY_HW_I2C2_NAME "I2C2" +#define MICROPY_HW_I2C2_SCL (pin_B10) // TX +#define MICROPY_HW_I2C2_SDA (pin_B11) // RX + +// SPI busses +#define MICROPY_HW_SPI1_NAME "SPIFLASH" +#define MICROPY_HW_SPI1_NSS (pin_A15) // FLASH CS +#define MICROPY_HW_SPI1_SCK (pin_B3) // FLASH CLK +#define MICROPY_HW_SPI1_MISO (pin_B4) // FLASH MISO +#define MICROPY_HW_SPI1_MOSI (pin_B5) // FLASH MOSI +#define MICROPY_HW_SPI2_NAME "SPI1" +#define MICROPY_HW_SPI2_NSS (pin_B12) // SD DETECT +#define MICROPY_HW_SPI2_SCK (pin_B13) // SCK +#define MICROPY_HW_SPI2_MISO (pin_B14) // MISO +#define MICROPY_HW_SPI2_MOSI (pin_B15) // MOSI + +// CAN busses +#define MICROPY_HW_CAN1_NAME "CAN1" +#define MICROPY_HW_CAN1_TX (pin_B9) // D10 +#define MICROPY_HW_CAN1_RX (pin_B8) // D9 + +// The Feather has 1 LED +#define MICROPY_HW_LED1 (pin_C1) // red +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// SD card detect switch +#define MICROPY_HW_SDCARD_DETECT_PIN (pin_B12) +#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP) +#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) + +// Bootloader configuration (only needed if Mboot is used) +#define MBOOT_I2C_PERIPH_ID 1 +#define MBOOT_I2C_SCL (pin_B8) +#define MBOOT_I2C_SDA (pin_B9) +#define MBOOT_I2C_ALTFUNC (4) diff --git a/ports/stm32/boards/ADAFRUIT_F405_EXPRESS/mpconfigboard.mk b/ports/stm32/boards/ADAFRUIT_F405_EXPRESS/mpconfigboard.mk new file mode 100644 index 0000000000..a4430cc1df --- /dev/null +++ b/ports/stm32/boards/ADAFRUIT_F405_EXPRESS/mpconfigboard.mk @@ -0,0 +1,13 @@ +MCU_SERIES = f4 +CMSIS_MCU = STM32F405xx +AF_FILE = boards/stm32f405_af.csv +ifeq ($(USE_MBOOT),1) +# When using Mboot all the text goes together after the filesystem +LD_FILES = boards/stm32f405.ld boards/common_blifs.ld +TEXT0_ADDR = 0x08020000 +else +# When not using Mboot the ISR text goes first, then the rest after the filesystem +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 +endif diff --git a/ports/stm32/boards/ADAFRUIT_F405_EXPRESS/pins.csv b/ports/stm32/boards/ADAFRUIT_F405_EXPRESS/pins.csv new file mode 100644 index 0000000000..15e810e1ae --- /dev/null +++ b/ports/stm32/boards/ADAFRUIT_F405_EXPRESS/pins.csv @@ -0,0 +1,48 @@ +POWER,3.3V +GND,GND +USB_ID,PA10 +USB_DM,PA11 +USB_DP,PA12 +SWDIO,PA13 +SWCLK,PA14 +FLASH_CS,PA15 +BATTERY_MONITOR,PA3 +A0,PA4 +A1,PA5 +A2,PA6 +A3,PA7 +USB_VBUS,PA9 +TX,PB10 +D1,PB10 +RX,PB11 +D0,PB11 +SD_DETECT,PB12 +SCK,PB13 +MISO,PB14 +MOSI,PB15 +BOOT1,PB2 +FLASH_SCK,PB3 +FLASH_MISO,PB4 +FLASH_MOSI,PB5 +SCL,PB6 +SDA,PB7 +D9,PB8 +D10,PB9 +D8,PC0 +NEOPIXEL,PC0 +D13,PC1 +SD_D2,PC10 +SD_D3,PC11 +SD_CK,PC12 +D12,PC2 +D11,PC3 +A4,PC4 +A5,PC5 +D6,PC6 +D5,PC7 +SD_D0,PC8 +SD_D1,PC9 +SD_CMD,PD2 +NC_A0,PA0 +NC_A1,PA1 +NC_A2,PA2 diff --git a/ports/stm32/boards/ADAFRUIT_F405_EXPRESS/stm32f4xx_hal_conf.h b/ports/stm32/boards/ADAFRUIT_F405_EXPRESS/stm32f4xx_hal_conf.h new file mode 100644 index 0000000000..9719157e55 --- /dev/null +++ b/ports/stm32/boards/ADAFRUIT_F405_EXPRESS/stm32f4xx_hal_conf.h @@ -0,0 +1,19 @@ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H + +#include "boards/stm32f4xx_hal_conf_base.h" + +// Oscillator values in Hz +#define HSE_VALUE (12000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) + +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) + +#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H From b65cc387cd0819ab97a4a8f7ebbc1f6345f65379 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 8 Oct 2019 14:25:32 +1100 Subject: [PATCH 0821/1788] extmod/modbluetooth: Allow config of scan interval/window. This adds two additional optional kwargs to `gap_scan()`: - `interval_us`: How long between scans. - `window_us`: How long to scan for during a scan. The default with NimBLE is a 11.25ms window with a 1.28s interval. Changing these parameters is important for detecting low-frequency advertisements (e.g. beacons). Note: these params are in microseconds, not milliseconds in order to allow the 625us granularity offered by the spec. --- extmod/modbluetooth.c | 31 +++++++++++++++++-------------- extmod/modbluetooth.h | 2 +- extmod/modbluetooth_nimble.c | 10 +++++----- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index f4996f7e88..0cfa3ac0d3 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -501,23 +501,26 @@ STATIC mp_obj_t bluetooth_ble_gap_connect(size_t n_args, const mp_obj_t *args) { STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gap_connect_obj, 3, 4, bluetooth_ble_gap_connect); STATIC mp_obj_t bluetooth_ble_gap_scan(size_t n_args, const mp_obj_t *args) { - if (n_args == 2 && args[1] == mp_const_none) { - int err = mp_bluetooth_gap_scan_stop(); - return bluetooth_handle_errno(err); - } else { - mp_int_t duration_ms = 0; - if (n_args == 2) { - if (!mp_obj_is_int(args[1])) { - mp_raise_ValueError("invalid duration"); - } - duration_ms = mp_obj_get_int(args[1]); + // Default is indefinite scan, with the NimBLE "background scan" interval and window. + mp_int_t duration_ms = 0; + mp_int_t interval_us = 1280000; + mp_int_t window_us = 11250; + if (n_args > 1) { + if (args[1] == mp_const_none) { + // scan(None) --> stop scan. + return bluetooth_handle_errno(mp_bluetooth_gap_scan_stop()); + } + duration_ms = mp_obj_get_int(args[1]); + if (n_args > 2) { + interval_us = mp_obj_get_int(args[2]); + if (n_args > 3) { + window_us = mp_obj_get_int(args[3]); + } } - - int err = mp_bluetooth_gap_scan_start(duration_ms); - return bluetooth_handle_errno(err); } + return bluetooth_handle_errno(mp_bluetooth_gap_scan_start(duration_ms, interval_us, window_us)); } -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gap_scan_obj, 1, 2, bluetooth_ble_gap_scan); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gap_scan_obj, 1, 4, bluetooth_ble_gap_scan); #endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE STATIC mp_obj_t bluetooth_ble_gap_disconnect(mp_obj_t self_in, mp_obj_t conn_handle_in) { diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h index 9db3bed6cd..8f34e3484d 100644 --- a/extmod/modbluetooth.h +++ b/extmod/modbluetooth.h @@ -186,7 +186,7 @@ int mp_bluetooth_gap_disconnect(uint16_t conn_handle); #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE // Start a discovery (scan). Set duration to zero to run continuously. -int mp_bluetooth_gap_scan_start(int32_t duration_ms); +int mp_bluetooth_gap_scan_start(int32_t duration_ms, int32_t interval_us, int32_t window_us); // Stop discovery (if currently active). int mp_bluetooth_gap_scan_stop(void); diff --git a/extmod/modbluetooth_nimble.c b/extmod/modbluetooth_nimble.c index 1e7211bfe8..727894f862 100644 --- a/extmod/modbluetooth_nimble.c +++ b/extmod/modbluetooth_nimble.c @@ -614,16 +614,16 @@ STATIC int gap_scan_cb(struct ble_gap_event *event, void *arg) { return 0; } -int mp_bluetooth_gap_scan_start(int32_t duration_ms) { +int mp_bluetooth_gap_scan_start(int32_t duration_ms, int32_t interval_us, int32_t window_us) { if (duration_ms == 0) { duration_ms = BLE_HS_FOREVER; } - STATIC const struct ble_gap_disc_params discover_params = { - .itvl = BLE_GAP_SCAN_SLOW_INTERVAL1, - .window = BLE_GAP_SCAN_SLOW_WINDOW1, + struct ble_gap_disc_params discover_params = { + .itvl = MAX(BLE_HCI_SCAN_ITVL_MIN, MIN(BLE_HCI_SCAN_ITVL_MAX, interval_us / BLE_HCI_SCAN_ITVL)), + .window = MAX(BLE_HCI_SCAN_WINDOW_MIN, MIN(BLE_HCI_SCAN_WINDOW_MAX, window_us / BLE_HCI_SCAN_ITVL)), .filter_policy = BLE_HCI_CONN_FILT_NO_WL, .limited = 0, - .passive = 0, + .passive = 1, // TODO: Handle BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP in gap_scan_cb above. .filter_duplicates = 0, }; int err = ble_gap_disc(BLE_OWN_ADDR_PUBLIC, duration_ms, &discover_params, gap_scan_cb, NULL); From 76f474129e571f1de7a5e66298866675f9f2c8f1 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Fri, 11 Oct 2019 13:12:59 +1100 Subject: [PATCH 0822/1788] extmod/modbluetooth: Use us instead of ms for advertising interval. This is to more accurately match the BLE spec, where intervals are configured in units of channel hop time (625us). When it was specified in ms, not all "valid" intervals were able to be specified. Now that we're also allowing configuration of scan interval, this commit updates advertising to match. --- extmod/modbluetooth.c | 10 +++++----- extmod/modbluetooth.h | 2 +- extmod/modbluetooth_nimble.c | 14 ++++---------- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index 0cfa3ac0d3..45ca61b6f0 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -301,9 +301,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bluetooth_ble_irq_obj, 1, bluetooth_ble_irq); // ---------------------------------------------------------------------------- STATIC mp_obj_t bluetooth_ble_gap_advertise(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_interval_ms, ARG_adv_data, ARG_resp_data, ARG_connectable }; + enum { ARG_interval_us, ARG_adv_data, ARG_resp_data, ARG_connectable }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_interval_ms, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(100)} }, + { MP_QSTR_interval_us, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(100)} }, { MP_QSTR_adv_data, MP_ARG_OBJ, {.u_obj = mp_const_none } }, { MP_QSTR_resp_data, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none } }, { MP_QSTR_connectable, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_true } }, @@ -311,8 +311,8 @@ STATIC mp_obj_t bluetooth_ble_gap_advertise(size_t n_args, const mp_obj_t *pos_a 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); - mp_int_t interval_ms; - if (args[ARG_interval_ms].u_obj == mp_const_none || (interval_ms = mp_obj_get_int(args[ARG_interval_ms].u_obj)) == 0) { + mp_int_t interval_us; + if (args[ARG_interval_us].u_obj == mp_const_none || (interval_us = mp_obj_get_int(args[ARG_interval_us].u_obj)) == 0) { mp_bluetooth_gap_advertise_stop(); return mp_const_none; } @@ -329,7 +329,7 @@ STATIC mp_obj_t bluetooth_ble_gap_advertise(size_t n_args, const mp_obj_t *pos_a mp_get_buffer_raise(args[ARG_resp_data].u_obj, &resp_bufinfo, MP_BUFFER_READ); } - return bluetooth_handle_errno(mp_bluetooth_gap_advertise_start(connectable, interval_ms, adv_bufinfo.buf, adv_bufinfo.len, resp_bufinfo.buf, resp_bufinfo.len)); + return bluetooth_handle_errno(mp_bluetooth_gap_advertise_start(connectable, interval_us, adv_bufinfo.buf, adv_bufinfo.len, resp_bufinfo.buf, resp_bufinfo.len)); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bluetooth_ble_gap_advertise_obj, 1, bluetooth_ble_gap_advertise); diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h index 8f34e3484d..f7284a43e8 100644 --- a/extmod/modbluetooth.h +++ b/extmod/modbluetooth.h @@ -157,7 +157,7 @@ void mp_bluetooth_get_device_addr(uint8_t *addr); // Start advertisement. Will re-start advertisement when already enabled. // Returns errno on failure. -int mp_bluetooth_gap_advertise_start(bool connectable, uint16_t interval_ms, const uint8_t *adv_data, size_t adv_data_len, const uint8_t *sr_data, size_t sr_data_len); +int mp_bluetooth_gap_advertise_start(bool connectable, int32_t interval_us, const uint8_t *adv_data, size_t adv_data_len, const uint8_t *sr_data, size_t sr_data_len); // Stop advertisement. No-op when already stopped. void mp_bluetooth_gap_advertise_stop(void); diff --git a/extmod/modbluetooth_nimble.c b/extmod/modbluetooth_nimble.c index 727894f862..8805d41007 100644 --- a/extmod/modbluetooth_nimble.c +++ b/extmod/modbluetooth_nimble.c @@ -341,7 +341,7 @@ void mp_bluetooth_get_device_addr(uint8_t *addr) { #endif } -int mp_bluetooth_gap_advertise_start(bool connectable, uint16_t interval_ms, const uint8_t *adv_data, size_t adv_data_len, const uint8_t *sr_data, size_t sr_data_len) { +int mp_bluetooth_gap_advertise_start(bool connectable, int32_t interval_us, const uint8_t *adv_data, size_t adv_data_len, const uint8_t *sr_data, size_t sr_data_len) { int ret; mp_bluetooth_gap_advertise_stop(); @@ -360,18 +360,12 @@ int mp_bluetooth_gap_advertise_start(bool connectable, uint16_t interval_ms, con } } - // Convert from 1ms to 0.625ms units. - interval_ms = interval_ms * 8 / 5; - if (interval_ms < 0x20 || interval_ms > 0x4000) { - return MP_EINVAL; - } - struct ble_gap_adv_params adv_params = { .conn_mode = connectable ? BLE_GAP_CONN_MODE_UND : BLE_GAP_CONN_MODE_NON, .disc_mode = BLE_GAP_DISC_MODE_GEN, - .itvl_min = interval_ms, - .itvl_max = interval_ms, - .channel_map = 7, // all 3 channels + .itvl_min = interval_us / BLE_HCI_ADV_ITVL, // convert to 625us units. + .itvl_max = interval_us / BLE_HCI_ADV_ITVL, + .channel_map = 7, // all 3 channels. }; ret = ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER, &adv_params, gap_event_cb, NULL); From dc82bee298b0a9d4ba1cb85608ba85b3f3e9b77b Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 8 Oct 2019 15:55:11 +1100 Subject: [PATCH 0823/1788] docs/library/bluetooth: Add initial BLE documentation. --- docs/library/bluetooth.rst | 308 +++++++++++++++++++++++++++++++++++++ docs/library/index.rst | 1 + 2 files changed, 309 insertions(+) create mode 100644 docs/library/bluetooth.rst diff --git a/docs/library/bluetooth.rst b/docs/library/bluetooth.rst new file mode 100644 index 0000000000..e9a803cb9b --- /dev/null +++ b/docs/library/bluetooth.rst @@ -0,0 +1,308 @@ +:mod:`bluetooth` --- low-level Bluetooth +======================================== + +.. module:: bluetooth + :synopsis: Low-level Bluetooth radio functionality + +This module provides an interface to a Bluetooth controller on a board. +Currently this supports Bluetooth Low Energy (BLE) in Central, Peripheral, +Broadcaster, and Observer roles. + +This API is intended to match the low-level Bluetooth protocol and provide +building-blocks for higher-level abstractions such as specific device types. + +class BLE +--------- + +Constructor +----------- + +.. class:: BLE() + + Returns the singleton BLE object. + +Configuration +------------- + +.. method:: BLE.active([active]) + + Optionally changes the active state of the BLE radio, and returns the + current state. + + The radio must be made active before using any other methods on this class. + +.. method:: BLE.config(name) + + Queries a configuration value by *name*. Currently supported values are: + + - ``'mac'``: Returns the device MAC address. If a device has a fixed address + (e.g. PYBD) then it will be returned. Otherwise (e.g. ESP32) a random + address will be generated when the BLE interface is made active. + +Event Handling +-------------- + +.. method:: BLE.irq(handler, trigger=0xffff) + + Registers a callback for events from the BLE stack. The *handler* takes two + arguments, ``event`` (which will be one of the codes below) and ``data`` + (which is an event-specific tuple of values). + + The optional *trigger* parameter allows you to set a mask of events that + your program is interested in. The default is all events. + + An event handler showing all possible events:: + + def bt_irq(event, data): + if event == _IRQ_CENTRAL_CONNECT: + # A central has connected to this peripheral. + conn_handle, addr_type, addr = data + elif event == _IRQ_CENTRAL_DISCONNECT: + # A central has disconnected from this peripheral. + conn_handle, addr_type, addr = data + elif event == _IRQ_GATTS_WRITE: + # A central has written to this characteristic or descriptor. + conn_handle, attr_handle = data + elif event == _IRQ_GATTS_READ_REQUEST: + # A central has issued a read. Note: this is a hard IRQ. + # Return None to deny the read. + conn_handle, attr_handle = data + elif event == _IRQ_SCAN_RESULT: + # A single scan result. + addr_type, addr, connectable, rssi, adv_data = data + elif event == _IRQ_SCAN_COMPLETE: + # Scan duration finished or manually stopped. + pass + elif event == _IRQ_PERIPHERAL_CONNECT: + # A successful gap_connect(). + conn_handle, addr_type, addr = data + elif event == _IRQ_PERIPHERAL_DISCONNECT: + # Connected peripheral has disconnected. + conn_handle, addr_type, addr = data + elif event == _IRQ_GATTC_SERVICE_RESULT: + # Called for each service found by gattc_discover_services(). + conn_handle, start_handle, end_handle, uuid = data + elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT: + # Called for each characteristic found by gattc_discover_services(). + conn_handle, def_handle, value_handle, properties, uuid = data + elif event == _IRQ_GATTC_DESCRIPTOR_RESULT: + # Called for each descriptor found by gattc_discover_descriptors(). + conn_handle, dsc_handle, uuid = data + elif event == _IRQ_GATTC_READ_RESULT: + # A gattc_read() has completed. + conn_handle, value_handle, char_data = data + elif event == _IRQ_GATTC_WRITE_STATUS: + # A gattc_write() has completed. + conn_handle, value_handle, status = data + elif event == _IRQ_GATTC_NOTIFY: + # A peripheral has sent a notify request. + conn_handle, value_handle, notify_data = data + elif event == _IRQ_GATTC_INDICATE: + # A peripheral has sent an indicate request. + conn_handle, value_handle, notify_data = data + +The event codes are:: + + from micropython import const + _IRQ_CENTRAL_CONNECT = const(1 << 0) + _IRQ_CENTRAL_DISCONNECT = const(1 << 1) + _IRQ_GATTS_WRITE = const(1 << 2) + _IRQ_GATTS_READ_REQUEST = const(1 << 3) + _IRQ_SCAN_RESULT = const(1 << 4) + _IRQ_SCAN_COMPLETE = const(1 << 5) + _IRQ_PERIPHERAL_CONNECT = const(1 << 6) + _IRQ_PERIPHERAL_DISCONNECT = const(1 << 7) + _IRQ_GATTC_SERVICE_RESULT = const(1 << 8) + _IRQ_GATTC_CHARACTERISTIC_RESULT = const(1 << 9) + _IRQ_GATTC_DESCRIPTOR_RESULT = const(1 << 10) + _IRQ_GATTC_READ_RESULT = const(1 << 11) + _IRQ_GATTC_WRITE_STATUS = const(1 << 12) + _IRQ_GATTC_NOTIFY = const(1 << 13) + _IRQ_GATTC_INDICATE = const(1 << 14) + +In order to save space in the firmware, these constants are not included on the +:mod:`bluetooth` module. Add the ones that you need from the list above to your +program. + + +Broadcaster Role (Advertiser) +----------------------------- + +.. method:: BLE.gap_advertise(interval_us, adv_data=None, resp_data=None, connectable=True) + + Starts advertising at the specified interval (in **micro**\ seconds). This + interval will be rounded down to the nearest 625us. To stop advertising, set + *interval_us* to ``None``. + + *adv_data* and *resp_data* can be any type that implements the buffer + protocol (e.g. ``bytes``, ``bytearray``, ``str``). *adv_data* is included + in all broadcasts, and *resp_data* is send in reply to an active scan. + + +Observer Role (Scanner) +----------------------- + +.. method:: BLE.gap_scan(duration_ms, [interval_us], [window_us]) + + Run a scan operation lasting for the specified duration (in **milli**\ seconds). + + To scan indefinitely, set *duration_ms* to ``0``. + + To stop scanning, set *duration_ms* to ``None``. + + Use *interval_us* and *window_us* to optionally configure the duty cycle. + The scanner will run for *window_us* **micro**\ seconds every *interval_us* + **micro**\ seconds for a total of *duration_ms* **milli**\ seconds. The default + interval and window are 1.28 seconds and 11.25 milliseconds respectively + (background scanning). + + For each scan result, the ``_IRQ_SCAN_RESULT`` event will be raised. + + When scanning is stopped (either due to the duration finishing or when + explicitly stopped), the ``_IRQ_SCAN_COMPLETE`` event will be raised. + + +Peripheral Role (GATT Server) +----------------------------- + +A BLE peripheral has a set of registered services. Each service may contain +characteristics, which each have a value. Characteristics can also contain +descriptors, which themselves have values. + +These values are stored locally and can be read from or written to by a remote +central device. Additionally, a peripheral can "notify" its value to a connected +central via its connection handle. + +.. method:: BLE.gatts_register_services(services_definition) + + Configures the peripheral with the specified services, replacing any + existing services. + + *services_definition* is a list of **services**, where each **service** is a + two-element tuple containing a UUID and a list of **characteristics**. + + Each **characteristic** is a two-or-three-element tuple containing a UUID, a + **flags** value, and optionally a list of *descriptors*. + + Each **descriptor** is a two-element tuple containing a UUID and a **flags** + value. + + The **flags** are a bitwise-OR combination of the + :data:`bluetooth.FLAGS_READ`, :data:`bluetooth.FLAGS_WRITE` and + :data:`bluetooth.FLAGS_NOTIFY` values defined below. + + The return value is a list (one element per service) of tuples (each element + is a value handle). Characteristics and descriptor handles are flattened + into the same tuple, in the order that they are defined. + + The following example registers two services (Heart Rate, and Nordic UART):: + + HR_UUID = bluetooth.UUID(0x180D) + HR_CHAR = (bluetooth.UUID(0x2A37), bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,) + HR_SERVICE = (HR_SERVICE, (HR_CHAR,),) + UART_UUID = bluetooth.UUID('6E400001-B5A3-F393-E0A9-E50E24DCCA9E') + UART_TX = (bluetooth.UUID('6E400003-B5A3-F393-E0A9-E50E24DCCA9E'), bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,) + UART_RX = (bluetooth.UUID('6E400002-B5A3-F393-E0A9-E50E24DCCA9E'), bluetooth.FLAG_WRITE,) + UART_SERVICE = (UART_UUID, (UART_TX, UART_RX,),) + SERVICES = (HR_SERVICE, UART_SERVICE,) + ( (hr,), (tx, rx,), ) = bt.gatts_register_services(SERVICES) + + The three value handles (``hr``, ``tx``, ``rx``) can be used with + :meth:`gatts_read `, :meth:`gatts_write `, + and :meth:`gatts_notify `. + + **Note:** Advertising must be stopped before registering services. + +.. method:: BLE.gatts_read(value_handle) + + Reads the local value for this handle (which has either been written by + :meth:`gatts_write ` or by a remote central). + +.. method:: BLE.gatts_write(value_handle, data) + + Writes the local value for this handle, which can be read by a central. + +.. method:: BLE.gatts_notify(conn_handle, value_handle, [data]) + + Notifies a connected central that this value has changed and that it should + issue a read of the current value from this peripheral. + + If *data* is specified, then the that value is sent to the central as part + of the notification, avoiding the need for a separate read request. Note + that this will not update the local value stored. + + +Central Role (GATT Client) +-------------------------- + +.. method:: BLE.gap_connect(addr_type, addr, scan_duration_ms=2000) + + Connect to a peripheral. + + On success, the ``_IRQ_PERIPHERAL_CONNECT`` event will be raised. + +.. method:: BLE.gap_disconnect(conn_handle) + + Disconnect the specified connection handle. + + On success, the ``_IRQ_PERIPHERAL_DISCONNECT`` event will be raised. + +.. method:: BLE.gattc_discover_services(conn_handle) + + Query a connected peripheral for its services. + + For each service discovered, the ``_IRQ_GATTC_SERVICE_RESULT`` event will be + raised. + +.. method:: BLE.gattc_discover_characteristics(conn_handle, start_handle, end_handle) + + Query a connected peripheral for characteristics in the specified range. + + For each characteristic discovered, the ``_IRQ_GATTC_CHARACTERISTIC_RESULT`` + event will be raised. + +.. method:: BLE.gattc_discover_descriptors(conn_handle, start_handle, end_handle) + + Query a connected peripheral for descriptors in the specified range. + + For each descriptor discovered, the ``_IRQ_GATTC_DESCRIPTOR_RESULT`` event + will be raised. + +.. method:: BLE.gattc_read(conn_handle, value_handle) + + Issue a remote read to a connected peripheral for the specified + characteristic or descriptor handle. + + On success, the ``_IRQ_GATTC_READ_RESULT`` event will be raised. + +.. method:: BLE.gattc_write(conn_handle, value_handle, data) + + Issue a remote write to a connected peripheral for the specified + characteristic or descriptor handle. + + On success, the ``_IRQ_GATTC_WRITE_STATUS`` event will be raised. + + +class UUID +---------- + + +Constructor +----------- + +.. class:: UUID(value) + + Creates a UUID instance with the specified **value**. + + The **value** can be either: + + - A 16-bit integer. e.g. ``0x2908``. + - A 128-bit UUID string. e.g. ``'6E400001-B5A3-F393-E0A9-E50E24DCCA9E'``. + + +Constants +--------- + +.. data:: bluetooth.FLAG_READ + bluetooth.FLAG_WRITE + bluetooth.FLAG_NOTIFY diff --git a/docs/library/index.rst b/docs/library/index.rst index 4e23e6e01d..7d4bb872cf 100644 --- a/docs/library/index.rst +++ b/docs/library/index.rst @@ -75,6 +75,7 @@ it will fallback to loading the built-in ``ujson`` module. builtins.rst array.rst + bluetooth.rst cmath.rst gc.rst math.rst From d5cbee3cfbc5fe41e366a55a96e2006fed819d6c Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Fri, 11 Oct 2019 14:30:47 +1100 Subject: [PATCH 0824/1788] esp32: Add 4.x version of IDLE WDT config. --- ports/esp32/boards/sdkconfig.base | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/ports/esp32/boards/sdkconfig.base b/ports/esp32/boards/sdkconfig.base index d44a97e138..a11c9397f6 100644 --- a/ports/esp32/boards/sdkconfig.base +++ b/ports/esp32/boards/sdkconfig.base @@ -12,8 +12,8 @@ CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y # ESP32-specific CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y -CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=n -CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1=n +CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=n +CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1=n CONFIG_ESP32_XTAL_FREQ_AUTO=y # Power Management @@ -25,11 +25,16 @@ CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP=y # UDP -CONFIG_PPP_SUPPORT=y -CONFIG_PPP_PAP_SUPPORT=y -CONFIG_PPP_CHAP_SUPPORT=y +CONFIG_LWIP_PPP_SUPPORT=y +CONFIG_LWIP_PPP_PAP_SUPPORT=y +CONFIG_LWIP_PPP_CHAP_SUPPORT=y # v3.3-only (renamed in 4.0) CONFIG_LOG_BOOTLOADER_LEVEL_WARN=y +CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=n +CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1=n CONFIG_SUPPORT_STATIC_ALLOCATION=y CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK=y +CONFIG_PPP_SUPPORT=y +CONFIG_PPP_PAP_SUPPORT=y +CONFIG_PPP_CHAP_SUPPORT=y From e0befd9e04bb79d9b74b54bacb89610731609d20 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 26 Sep 2019 23:48:30 +1000 Subject: [PATCH 0825/1788] top: Add CODEOFCONDUCT.md document based on the PSF code of conduct. --- CODEOFCONDUCT.md | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 CODEOFCONDUCT.md diff --git a/CODEOFCONDUCT.md b/CODEOFCONDUCT.md new file mode 100644 index 0000000000..07cf87713b --- /dev/null +++ b/CODEOFCONDUCT.md @@ -0,0 +1,53 @@ +MicroPython Code of Conduct +=========================== + +The MicroPython community is made up of members from around the globe with a +diverse set of skills, personalities, and experiences. It is through these +differences that our community experiences great successes and continued growth. +When you're working with members of the community, this Code of Conduct will +help steer your interactions and keep MicroPython a positive, successful, and +growing community. + +Members of the MicroPython community are open, considerate, and respectful. +Behaviours that reinforce these values contribute to a positive environment, and +include: acknowledging time and effort, being respectful of differing viewpoints +and experiences, gracefully accepting constructive criticism, and using +welcoming and inclusive language. + +Every member of our community has the right to have their identity respected. +The MicroPython community is dedicated to providing a positive experience for +everyone, regardless of age, gender identity and expression, sexual orientation, +disability, physical appearance, body size, ethnicity, nationality, race, or +religion (or lack thereof), education, or socio-economic status. + +Unacceptable behaviour includes: harassment, trolling, deliberate intimidation, +violent threats or language directed against another person; insults, put downs, +or jokes that are based upon stereotypes, that are exclusionary, or that hold +others up for ridicule; unwelcome sexual attention or advances; sustained +disruption of community discussions; publishing others' private information +without explicit permission; and other conduct that is inappropriate for a +professional audience including people of many different backgrounds. + +This code of conduct covers all online and offline presence related to the +MicroPython project, including GitHub and the forum. If a participant engages +in behaviour that violates this code of conduct, the MicroPython team may take +action as they deem appropriate, including warning the offender or expulsion +from the community. Community members asked to stop any inappropriate behaviour +are expected to comply immediately. + +Thank you for helping make this a welcoming, friendly community for everyone. + +If you believe that someone is violating the code of conduct, or have any other +concerns, please contact a member of the MicroPython team by emailing +contact@micropython.org. + +License +------- + +This Code of Conduct is licensed under the Creative Commons +Attribution-ShareAlike 3.0 Unported License. + +Attributions +------------ + +Based on the Python code of conduct found at https://www.python.org/psf/conduct/ From a93495b66d1e1101fffa3c8f2811d8750b5601f9 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Thu, 22 Aug 2019 13:19:40 +1000 Subject: [PATCH 0826/1788] docs/reference/glossary.rst: Add new terms and reduce complexity of old. --- docs/reference/glossary.rst | 275 +++++++++++++++++++++--------------- 1 file changed, 160 insertions(+), 115 deletions(-) diff --git a/docs/reference/glossary.rst b/docs/reference/glossary.rst index a6abc8b9da..d63f372298 100644 --- a/docs/reference/glossary.rst +++ b/docs/reference/glossary.rst @@ -4,152 +4,197 @@ Glossary .. glossary:: baremetal - A system without a (full-fledged) OS, for example an + A system without a (full-fledged) operating system, 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). + MicroPython effectively functions like a small operating system, + running user programs and providing a command interpreter + (:term:`REPL`). + + buffer protocol + Any Python object that can be automatically converted into bytes, such + as ``bytes``, ``bytearray``, ``memoryview`` and ``str`` objects, which + all implement the "buffer protocol". board - A PCB board. Oftentimes, the term is used to denote a particular - model of an :term:`MCU` system. Sometimes, it is used to actually - refer to :term:`MicroPython port` to a particular board (and then - may also refer to "boardless" ports like - :term:`Unix port `). + Typically this refers to a printed circuit board (PCB) containing a + :term:`microcontroller ` and supporting components. + MicroPython firmware is typically provided per-board, as the firmware + contains both MCU-specific functionality but also board-level + functionality such as drivers or pin names. + + bytecode + A compact representation of a Python program that generated by + compiling the Python source code. This is what the VM actually + executes. Bytecode is typically generated automatically at runtime and + is invisible to the user. Note that while :term:`CPython` and + MicroPython both use bytecode, the format is different. You can also + pre-compile source code offline using the :term:`cross-compiler`. 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.) + This is a MicroPython-specific construct where, for efficiency + reasons, some built-in functions or methods may re-use the same + underlying tuple object to return data. This avoids having to allocate + a new tuple for every call, and reduces heap fragmentation. Programs + should not hold references to callee-owned tuples and instead only + extract data from them (or make a copy). + + CircuitPython + A variant of MicroPython developed by `Adafruit Industries + `_. CPython - CPython is the reference implementation of Python programming - language, and the most well-known one, which most of the people - run. It is however one of many implementations (among which - Jython, IronPython, PyPy, and many more, including MicroPython). - As there is no formal specification of the Python language, only - CPython documentation, it is not always easy to draw a line - between Python the language and CPython its particular - implementation. This however leaves more freedom for other - implementations. For example, MicroPython does a lot of things - differently than CPython, while still aspiring to be a Python - language implementation. + CPython is the reference implementation of the Python programming + language, and the most well-known one. It is, however, one of many + implementations (including Jython, IronPython, PyPy, and MicroPython). + While MicroPython's implementation differs substantially from CPython, + it aims to maintain as much compatibility as possible. + + cross-compiler + Also known as ``mpy-cross``. This tool runs on your PC and converts a + :term:`.py file` containing MicroPython code into a :term:`.mpy file` + containing MicroPython bytecode. This means it loads faster (the board + doesn't have to compile the code), and uses less space on flash (the + bytecode is more space efficient). + + driver + A MicroPython library that implements support for a particular + component, such as a sensor or display. + + FFI + Acronym for Foreign Function Interface. A mechanism used by the + :term:`MicroPython Unix port` to access operating system functionality. + This is not available on :term:`baremetal` ports. + + filesystem + Most MicroPython ports and boards provide a filesystem stored in flash + that is available to user code via the standard Python file APIs such + as ``open()``. Some boards also make this internal filesystem + accessible to the host via USB mass-storage. + + frozen module + A Python module that has been cross compiled and bundled into the + firmware image. This reduces RAM requirements as the code is executed + directly from flash. + + Garbage Collector + A background process that runs in Python (and MicroPython) to reclaim + unused memory in the :term:`heap`. GPIO - General-purpose input/output. The simplest means to control - electrical signals. With GPIO, user can configure hardware - signal pin to be either input or output, and set or get - its digital signal value (logical "0" or "1"). MicroPython - abstracts GPIO access using :class:`machine.Pin` and :class:`machine.Signal` + General-purpose input/output. The simplest means to control electrical + signals (commonly referred to as "pins") on a microcontroller. GPIO + typically allows pins to be either input or output, and to set or get + their digital value (logical "0" or "1"). MicroPython abstracts GPIO + access using the :class:`machine.Pin` and :class:`machine.Signal` classes. GPIO port - A group of :term:`GPIO` pins, usually based on hardware - properties of these pins (e.g. controllable by the same - register). + A group of :term:`GPIO` pins, usually based on hardware properties of + these pins (e.g. controllable by the same register). + + heap + A region of RAM where MicroPython stores dynamic data. It is managed + automatically by the :term:`Garbage Collector`. Different MCUs and + boards have vastly different amounts of RAM available for the heap, so + this will affect how complex your program can be. 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. + An optimisation used by MicroPython to improve the efficiency of + working with strings. An interned string is referenced by its (unique) + identity rather than its address and can therefore be quickly compared + just by its identifier. It also means that identical strings can be + de-duplicated in memory. String interning is almost always invisible to + the user. MCU Microcontroller. Microcontrollers usually have much less resources - than a full-fledged computing system, but smaller, cheaper and + than a desktop, laptop, or phone, but are smaller, cheaper and require much less power. MicroPython is designed to be small and optimized enough to run on an average modern microcontroller. micropython-lib MicroPython is (usually) distributed as a single executable/binary file with just few builtin modules. There is no extensive standard - library comparable with :term:`CPython`. Instead, there is a related, but - separate project - `micropython-lib `_ - which provides implementations for many modules from CPython's - standard library. However, large subset of these modules require - 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. + library comparable with :term:`CPython`'s. Instead, there is a related, + but separate project `micropython-lib + `_ which provides + implementations for many modules from CPython's standard library. - Unlike monolithic :term:`CPython` stdlib, micropython-lib modules - are intended to be installed individually - either using manual - copying or using :term:`upip`. + Some of the modules are are implemented in pure Python, and are able to + be used on all ports. However, the majority of these modules use + :term:`FFI` to access operating system functionality, and as such can + only be used on the :term:`MicroPython Unix port` (with limited support + for Windows). + + Unlike the :term:`CPython` stdlib, micropython-lib modules are + intended to be installed individually - either using manual copying or + using :term:`upip`. MicroPython port - MicroPython supports different :term:`boards `, RTOSes, - and OSes, and can be relatively easily adapted to new systems. - MicroPython with support for a particular system is called a - "port" to that system. Different ports may have widely different - functionality. This documentation is intended to be a reference - of the generic APIs available across different ports ("MicroPython - core"). Note that some ports may still omit some APIs described - here (e.g. due to resource constraints). Any such differences, - and port-specific extensions beyond MicroPython core functionality, - would be described in the separate port-specific documentation. + MicroPython supports different :term:`boards `, RTOSes, and + OSes, and can be relatively easily adapted to new systems. MicroPython + with support for a particular system is called a "port" to that + system. Different ports may have widely different functionality. This + documentation is intended to be a reference of the generic APIs + available across different ports ("MicroPython core"). Note that some + ports may still omit some APIs described here (e.g. due to resource + constraints). Any such differences, and port-specific extensions + beyond the MicroPython core functionality, would be described in the + separate port-specific documentation. MicroPython Unix port - Unix port is one of the major :term:`MicroPython ports `. - It is intended to run on POSIX-compatible operating systems, like - Linux, MacOS, FreeBSD, Solaris, etc. It also serves as the basis - of Windows port. The importance of Unix port lies in the fact - that while there are many different :term:`boards `, so - two random users unlikely have the same board, almost all modern - OSes have some level of POSIX compatibility, so Unix port serves - as a kind of "common ground" to which any user can have access. - So, Unix port is used for initial prototyping, different kinds - of testing, development of machine-independent features, etc. - All users of MicroPython, even those which are interested only - in running MicroPython on :term:`MCU` systems, are recommended - to be familiar with Unix (or Windows) port, as it is important - productivity helper and a part of normal MicroPython workflow. + The unix port is one of the major :term:`MicroPython ports + `. It is intended to run on POSIX-compatible + operating systems, like Linux, MacOS, FreeBSD, Solaris, etc. It also + serves as the basis of Windows port. The Unix port is very useful for + quick development and testing of the MicroPython language and + machine-independent features. It can also function in a similar way to + :term:`CPython`'s ``python`` executable. + + .mpy file + The output of the :term:`cross-compiler`. A compiled form of a + :term:`.py file` that contains MicroPython bytecode instead of Python + source code. + + native + Usually refers to "native code", i.e. machine code for the target + microcontroller (such as ARM Thumb, Xtensa, x86/x64). The ``@native`` + decorator can be applied to a MicroPython function to generate native + code instead of bytecode for that function, which will likely be + faster but use more RAM. port - Either :term:`MicroPython port` or :term:`GPIO port`. If not clear - from context, it's recommended to use full specification like one - of the above. + Usually short for :term:`MicroPython port`, but could also refer to + :term:`GPIO port`. + + .py file + A file containing Python source code. + + REPL + An acronym for "Read, Eval, Print, Loop". This is the interactive + Python prompt, useful for debugging or testing short snippets of code. + Most MicroPython boards make a REPL available over a UART, and this is + typically accessible on a host PC via USB. 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. + Also known as a "file-like object". An Python 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 the `uio` module. + + UART + Acronym for "Universal Asynchronous Receiver/Transmitter". This is a + peripheral that sends data over a pair of pins (TX & RX). Many boards + include a way to make at least one of the UARTs available to a host PC + as a serial port over USB. upip - (Literally, "micro pip"). A package manage for MicroPython, inspired - by :term:`CPython`'s pip, but much smaller and with reduced functionality. - upip runs both on :term:`Unix port ` and on - :term:`baremetal` ports (those which offer filesystem and networking - support). + (Literally, "micro pip"). A package manager for MicroPython, inspired + by :term:`CPython`'s pip, but much smaller and with reduced + functionality. + upip runs both on the :term:`Unix port ` and on + :term:`baremetal` ports which offer filesystem and networking support. From cfd17f4ebe0a942f02f5f515dd2da0bffb252f97 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Thu, 10 Oct 2019 00:45:27 +1100 Subject: [PATCH 0827/1788] tests/perf_bench: Add bm_fft test. This is mostly a test of complex number performance. The FFT implementation is from Project Nayuki and is MIT licensed. --- tests/perf_bench/bm_fft.py | 69 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 tests/perf_bench/bm_fft.py diff --git a/tests/perf_bench/bm_fft.py b/tests/perf_bench/bm_fft.py new file mode 100644 index 0000000000..9ea8b08f49 --- /dev/null +++ b/tests/perf_bench/bm_fft.py @@ -0,0 +1,69 @@ +# Copyright (c) 2019 Project Nayuki. (MIT License) +# https://www.nayuki.io/page/free-small-fft-in-multiple-languages + +import math, cmath + +def transform_radix2(vector, inverse): + # Returns the integer whose value is the reverse of the lowest 'bits' bits of the integer 'x'. + def reverse(x, bits): + y = 0 + for i in range(bits): + y = (y << 1) | (x & 1) + x >>= 1 + return y + + # Initialization + n = len(vector) + levels = int(math.log2(n)) + coef = (2 if inverse else -2) * cmath.pi / n + exptable = [cmath.rect(1, i * coef) for i in range(n // 2)] + vector = [vector[reverse(i, levels)] for i in range(n)] # Copy with bit-reversed permutation + + # Radix-2 decimation-in-time FFT + size = 2 + while size <= n: + halfsize = size // 2 + tablestep = n // size + for i in range(0, n, size): + k = 0 + for j in range(i, i + halfsize): + temp = vector[j + halfsize] * exptable[k] + vector[j + halfsize] = vector[j] - temp + vector[j] += temp + k += tablestep + size *= 2 + return vector + +########################################################################### +# Benchmark interface + +bm_params = { + (50, 25): (2, 128), + (100, 100): (3, 256), + (1000, 1000): (20, 512), + (5000, 1000): (100, 512), +} + +def bm_setup(params): + state = None + signal = [math.cos(2 * math.pi * i / params[1]) + 0j for i in range(params[1])] + fft = None + fft_inv = None + + def run(): + nonlocal fft, fft_inv + for _ in range(params[0]): + fft = transform_radix2(signal, False) + fft_inv = transform_radix2(fft, True) + + def result(): + nonlocal fft, fft_inv + fft[1] -= 0.5 * params[1] + fft[-1] -= 0.5 * params[1] + fft_ok = all(abs(f) < 1e-3 for f in fft) + for i in range(len(fft_inv)): + fft_inv[i] -= params[1] * signal[i] + fft_inv_ok = all(abs(f) < 1e-3 for f in fft_inv) + return params[0] * params[1], (fft_ok, fft_inv_ok) + + return run, result From f1882636c0919ef16d0e549ff2dad1e5a2f59f13 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 15 Oct 2019 14:13:21 +1100 Subject: [PATCH 0828/1788] tests/run-perfbench.py: Show error when truth check fails. --- tests/run-perfbench.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/run-perfbench.py b/tests/run-perfbench.py index e52aa0ccbc..75dc0210b0 100755 --- a/tests/run-perfbench.py +++ b/tests/run-perfbench.py @@ -123,7 +123,6 @@ def run_benchmarks(target, param_n, param_m, n_average, test_list): _, _, result_exp = run_benchmark_on_target(PYTHON_TRUTH, test_script) if result_out != result_exp: error = 'FAIL truth' - break if error is not None: print(error) From 858e992d2e25cf50b06abc33978040092e6f1e16 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 15 Oct 2019 16:46:06 +1100 Subject: [PATCH 0829/1788] tests/run-perfbench.py: Skip complex tests if target doesn't enable it. --- tests/run-perfbench.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/run-perfbench.py b/tests/run-perfbench.py index 75dc0210b0..d02021719a 100755 --- a/tests/run-perfbench.py +++ b/tests/run-perfbench.py @@ -77,13 +77,17 @@ def run_benchmark_on_target(target, script): return -1, -1, 'CRASH: %r' % err def run_benchmarks(target, param_n, param_m, n_average, test_list): + skip_complex = run_feature_test(target, 'complex') != 'complex' skip_native = run_feature_test(target, 'native_check') != '' for test_file in sorted(test_list): print(test_file + ': ', end='') # Check if test should be skipped - skip = skip_native and test_file.find('viper_') != -1 + skip = ( + skip_complex and test_file.find('bm_fft') != -1 + or skip_native and test_file.find('viper_') != -1 + ) if skip: print('skip') continue From 23f0691fddfc35acd2f81f54b15ad2ecaa15c6d4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 10 Oct 2019 15:30:16 +1100 Subject: [PATCH 0830/1788] py/persistentcode: Make .mpy more compact with qstr directly in prelude. Instead of encoding 4 zero bytes as placeholders for the simple_name and source_file qstrs, and storing the qstrs after the bytecode, store the qstrs at the location of these 4 bytes. This saves 4 bytes per bytecode function stored in a .mpy file (for example lcd160cr.mpy drops by 232 bytes, 4x 58 functions). And resulting code size is slightly reduced on ports that use this feature. --- py/persistentcode.c | 83 +++++++++++++++++++++----------------- tests/import/mpy_native.py | 4 +- tools/mpy-tool.py | 19 +++++---- 3 files changed, 57 insertions(+), 49 deletions(-) diff --git a/py/persistentcode.c b/py/persistentcode.c index 6a8a866ac5..d55e371592 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -160,8 +160,8 @@ typedef struct _bytecode_prelude_t { } bytecode_prelude_t; // ip will point to start of opcodes -// ip2 will point to simple_name, source_file qstrs -STATIC void extract_prelude(const byte **ip, const byte **ip2, bytecode_prelude_t *prelude) { +// return value will point to simple_name, source_file qstrs +STATIC byte *extract_prelude(const byte **ip, bytecode_prelude_t *prelude) { MP_BC_PRELUDE_SIG_DECODE(*ip); prelude->n_state = n_state; prelude->n_exc_stack = n_exc_stack; @@ -170,9 +170,10 @@ STATIC void extract_prelude(const byte **ip, const byte **ip2, bytecode_prelude_ prelude->n_kwonly_args = n_kwonly_args; prelude->n_def_pos_args = n_def_pos_args; MP_BC_PRELUDE_SIZE_DECODE(*ip); - *ip2 = *ip; + byte *ip_info = (byte*)*ip; *ip += n_info; *ip += n_cell; + return ip_info; } #endif // MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE @@ -282,17 +283,28 @@ STATIC mp_obj_t load_obj(mp_reader_t *reader) { } } -STATIC void load_prelude(mp_reader_t *reader, byte **ip, byte **ip2, bytecode_prelude_t *prelude) { - // Read in the prelude +STATIC void load_prelude_qstrs(mp_reader_t *reader, qstr_window_t *qw, byte *ip) { + qstr simple_name = load_qstr(reader, qw); + ip[0] = simple_name; ip[1] = simple_name >> 8; + qstr source_file = load_qstr(reader, qw); + ip[2] = source_file; ip[3] = source_file >> 8; +} + +STATIC void load_prelude(mp_reader_t *reader, qstr_window_t *qw, byte **ip, bytecode_prelude_t *prelude) { + // Read in the prelude header byte *ip_read = *ip; read_uint(reader, &ip_read); // read in n_state/etc (is effectively a var-uint) - byte *ip_read_save = ip_read; read_uint(reader, &ip_read); // read in n_info/n_cell (is effectively a var-uint) - MP_BC_PRELUDE_SIZE_DECODE(ip_read_save); - read_bytes(reader, ip_read, n_info + n_cell); // read remaining code info - // Entire prelude has been read into *ip, now decode and extract values from it - extract_prelude((const byte**)ip, (const byte**)ip2, prelude); + // Prelude header has been read into *ip, now decode and extract values from it + extract_prelude((const byte**)ip, prelude); + + // Load qstrs in prelude + load_prelude_qstrs(reader, qw, ip_read); + ip_read += 4; + + // Read remaining code info + read_bytes(reader, ip_read, *ip - ip_read); } STATIC void load_bytecode(mp_reader_t *reader, qstr_window_t *qw, byte *ip, byte *ip_top) { @@ -329,7 +341,6 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { #endif uint8_t *fun_data = NULL; - byte *ip2; bytecode_prelude_t prelude = {0}; #if MICROPY_EMIT_MACHINE_CODE size_t prelude_offset = 0; @@ -343,7 +354,7 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { // Load prelude byte *ip = fun_data; - load_prelude(reader, &ip, &ip2, &prelude); + load_prelude(reader, qw, &ip, &prelude); // Load bytecode load_bytecode(reader, qw, ip, fun_data + fun_data_len); @@ -377,7 +388,9 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { // Extract prelude for later use prelude_offset = read_uint(reader, NULL); const byte *ip = fun_data + prelude_offset; - extract_prelude(&ip, (const byte**)&ip2, &prelude); + byte *ip_info = extract_prelude(&ip, &prelude); + // Load qstrs in prelude + load_prelude_qstrs(reader, qw, ip_info); } else { // Load basic scope info for viper and asm prelude.scope_flags = read_uint(reader, NULL); @@ -391,14 +404,6 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { #endif } - if (kind == MP_CODE_BYTECODE || kind == MP_CODE_NATIVE_PY) { - // Load qstrs in prelude - qstr simple_name = load_qstr(reader, qw); - qstr source_file = load_qstr(reader, qw); - ip2[0] = simple_name; ip2[1] = simple_name >> 8; - ip2[2] = source_file; ip2[3] = source_file >> 8; - } - size_t n_obj = 0; size_t n_raw_code = 0; mp_uint_t *const_table = NULL; @@ -591,6 +596,11 @@ STATIC void save_obj(mp_print_t *print, mp_obj_t o) { } } +STATIC void save_prelude_qstrs(mp_print_t *print, qstr_window_t *qw, const byte *ip) { + save_qstr(print, qw, ip[0] | (ip[1] << 8)); // simple_name + save_qstr(print, qw, ip[2] | (ip[3] << 8)); // source_file +} + STATIC void save_bytecode(mp_print_t *print, qstr_window_t *qw, const byte *ip, const byte *ip_top) { while (ip < ip_top) { size_t sz; @@ -611,18 +621,21 @@ STATIC void save_raw_code(mp_print_t *print, mp_raw_code_t *rc, qstr_window_t *q // Save function kind and data length mp_print_uint(print, (rc->fun_data_len << 2) | (rc->kind - MP_CODE_BYTECODE)); - const byte *ip2; bytecode_prelude_t prelude; if (rc->kind == MP_CODE_BYTECODE) { - // Save prelude + // Extract prelude const byte *ip = rc->fun_data; - extract_prelude(&ip, &ip2, &prelude); - size_t prelude_len = ip - (const byte*)rc->fun_data; - const byte *ip_top = (const byte*)rc->fun_data + rc->fun_data_len; - mp_print_bytes(print, rc->fun_data, prelude_len); + const byte *ip_info = extract_prelude(&ip, &prelude); + + // Save prelude + mp_print_bytes(print, rc->fun_data, ip_info - (const byte*)rc->fun_data); + save_prelude_qstrs(print, qstr_window, ip_info); + ip_info += 4; + mp_print_bytes(print, ip_info, ip - ip_info); // Save bytecode + const byte *ip_top = (const byte*)rc->fun_data + rc->fun_data_len; save_bytecode(print, qstr_window, ip, ip_top); #if MICROPY_EMIT_MACHINE_CODE } else { @@ -639,10 +652,13 @@ STATIC void save_raw_code(mp_print_t *print, mp_raw_code_t *rc, qstr_window_t *q } if (rc->kind == MP_CODE_NATIVE_PY) { - // Save prelude size, and extract prelude for later use + // Save prelude size mp_print_uint(print, rc->prelude_offset); + + // Extract prelude and save qstrs in prelude const byte *ip = (const byte*)rc->fun_data + rc->prelude_offset; - extract_prelude(&ip, &ip2, &prelude); + const byte *ip_info = extract_prelude(&ip, &prelude); + save_prelude_qstrs(print, qstr_window, ip_info); } else { // Save basic scope info for viper and asm mp_print_uint(print, rc->scope_flags); @@ -656,12 +672,6 @@ STATIC void save_raw_code(mp_print_t *print, mp_raw_code_t *rc, qstr_window_t *q #endif } - if (rc->kind == MP_CODE_BYTECODE || rc->kind == MP_CODE_NATIVE_PY) { - // Save qstrs in prelude - save_qstr(print, qstr_window, ip2[0] | (ip2[1] << 8)); // simple_name - save_qstr(print, qstr_window, ip2[2] | (ip2[3] << 8)); // source_file - } - if (rc->kind != MP_CODE_NATIVE_ASM) { // Save constant table for bytecode, native and viper @@ -699,9 +709,8 @@ STATIC bool mp_raw_code_has_native(mp_raw_code_t *rc) { } const byte *ip = rc->fun_data; - const byte *ip2; bytecode_prelude_t prelude; - extract_prelude(&ip, &ip2, &prelude); + extract_prelude(&ip, &prelude); const mp_uint_t *const_table = rc->const_table + prelude.n_pos_args + prelude.n_kwonly_args diff --git a/tests/import/mpy_native.py b/tests/import/mpy_native.py index 749320dbbe..c33b3350c3 100644 --- a/tests/import/mpy_native.py +++ b/tests/import/mpy_native.py @@ -57,11 +57,11 @@ user_files = { b'M\x05\x0b\x1f\x20' # header b'\x20' # n bytes, bytecode - b'\x00\x08\x00\x00\x00\x00' # prelude + b'\x00\x08\x02m\x02m' # prelude b'\x51' # LOAD_CONST_NONE b'\x63' # RETURN_VALUE - b'\x02m\x02m\x00\x02' # simple_name, source_file, n_obj, n_raw_code + b'\x00\x02' # n_obj, n_raw_code b'\x22' # n bytes, viper code b'\x00\x00\x00\x00\x00\x00' # dummy machine code diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index ab783f4184..39362bc092 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -583,13 +583,14 @@ def read_obj(f): else: assert 0 -def read_prelude(f, bytecode): +def read_prelude(f, bytecode, qstr_win): n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args = read_prelude_sig(lambda: read_byte(f, bytecode)) n_info, n_cell = read_prelude_size(lambda: read_byte(f, bytecode)) - l2 = bytecode.idx - for _ in range(n_info + n_cell): + read_qstr_and_pack(f, bytecode, qstr_win) # simple_name + read_qstr_and_pack(f, bytecode, qstr_win) # source_file + for _ in range(n_info - 4 + n_cell): read_byte(f, bytecode) - return l2, (n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args) + return n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args def read_qstr_and_pack(f, bytecode, qstr_win): qst = read_qstr(f, qstr_win) @@ -617,7 +618,7 @@ def read_raw_code(f, qstr_win): fun_data = BytecodeBuffer(fun_data_len) if kind == MP_CODE_BYTECODE: - name_idx, prelude = read_prelude(f, fun_data) + prelude = read_prelude(f, fun_data, qstr_win) read_bytecode(f, fun_data, qstr_win) else: fun_data.buf[:] = f.read(fun_data_len) @@ -635,6 +636,9 @@ def read_raw_code(f, qstr_win): if kind == MP_CODE_NATIVE_PY: prelude_offset = read_uint(f) _, name_idx, prelude = extract_prelude(fun_data.buf, prelude_offset) + fun_data.idx = name_idx # rewind to where qstrs are in prelude + read_qstr_and_pack(f, fun_data, qstr_win) # simple_name + read_qstr_and_pack(f, fun_data, qstr_win) # source_file else: prelude_offset = None scope_flags = read_uint(f) @@ -644,11 +648,6 @@ def read_raw_code(f, qstr_win): type_sig = read_uint(f) prelude = (None, None, scope_flags, n_pos_args, 0) - if kind in (MP_CODE_BYTECODE, MP_CODE_NATIVE_PY): - fun_data.idx = name_idx # rewind to where qstrs are in prelude - read_qstr_and_pack(f, fun_data, qstr_win) # simple_name - read_qstr_and_pack(f, fun_data, qstr_win) # source_file - qstrs = [] objs = [] raw_codes = [] From 3ee71ff314c33410964edff6e12ffc638d2df661 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 11 Oct 2019 11:48:01 +1100 Subject: [PATCH 0831/1788] minimal/frozentest.mpy: Recompile now that mpy format changed. --- ports/minimal/frozentest.mpy | Bin 200 -> 196 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/ports/minimal/frozentest.mpy b/ports/minimal/frozentest.mpy index 178b811ba0924a78ea825c22983ebbd9c597c2ff..8a89194a1048700453ca5b682c972e131a878610 100644 GIT binary patch delta 36 rcmX@Xc!W{Xmz7Cgp(#W_jDcM$tth`LHLoPKxJ0j@aw2cQ#N22AwCxKD delta 41 wcmX@Yc!H7Fmz7Cgp(#W_jGZBnaiU~^00X;JT2X#gYF Date: Mon, 14 Oct 2019 12:09:06 +1100 Subject: [PATCH 0832/1788] ports: Add new make target "submodules" which inits required modules. --- README.md | 19 ++++++++++--------- ports/esp32/Makefile | 2 ++ ports/esp32/README.md | 9 +-------- ports/esp8266/Makefile | 2 ++ ports/nrf/Makefile | 2 ++ ports/nrf/README.md | 2 +- ports/samd/Makefile | 2 ++ ports/stm32/Makefile | 2 ++ ports/stm32/README.md | 6 +++++- ports/unix/Makefile | 2 ++ py/mkrules.mk | 7 +++++++ 11 files changed, 36 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index aaf310b662..ed0f20091f 100644 --- a/README.md +++ b/README.md @@ -86,8 +86,8 @@ Alternatively, fallback implementation based on setjmp/longjmp can be used. To build (see section below for required dependencies): - $ git submodule update --init $ cd ports/unix + $ make submodules $ make Then to give it a try: @@ -127,13 +127,14 @@ Debian/Ubuntu/Mint derivative Linux distros, install `build-essential` Other dependencies can be built together with MicroPython. This may be required to enable extra features or capabilities, and in recent versions of MicroPython, these may be enabled by default. To build -these additional dependencies, first fetch git submodules for them: +these additional dependencies, in the port directory you're +interested in (e.g. `ports/unix/`) first execute: - $ git submodule update --init + $ make submodules -Use the same command to get the latest versions of dependencies, as -they are updated from time to time. After that, in the port directory -(e.g. `ports/unix/`), execute: +This will fetch all the relevant git submodules (sub repositories) that +the port needs. Use the same command to get the latest versions of +submodules as they are updated from time to time. After that execute: $ make deplibs @@ -146,8 +147,8 @@ For example, to build SSL module (required for `upip` tool described above, and so enabled by dfeault), `MICROPY_PY_USSL` should be set to 1. For some ports, building required dependences is transparent, and happens -automatically. They still need to be fetched with the git submodule command -above. +automatically. But they still need to be fetched with the `make submodules` +command. The STM32 version ----------------- @@ -159,8 +160,8 @@ https://launchpad.net/gcc-arm-embedded To build: - $ git submodule update --init $ cd ports/stm32 + $ make submodules $ make You then need to get your board into DFU mode. On the pyboard, connect the diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 5d63a2586c..2a752553e8 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -38,6 +38,8 @@ FROZEN_MPY_DIR = modules # include py core make definitions include $(TOP)/py/py.mk +GIT_SUBMODULES = lib/berkeley-db-1.xx + PORT ?= /dev/ttyUSB0 BAUD ?= 460800 FLASH_MODE ?= dio diff --git a/ports/esp32/README.md b/ports/esp32/README.md index 2c7351ee53..518cafb710 100644 --- a/ports/esp32/README.md +++ b/ports/esp32/README.md @@ -122,17 +122,10 @@ this repository): $ 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 submodules $ make ``` This will produce binary firmware images in the `build/` subdirectory diff --git a/ports/esp8266/Makefile b/ports/esp8266/Makefile index 8cac07afcc..030f39fa91 100644 --- a/ports/esp8266/Makefile +++ b/ports/esp8266/Makefile @@ -32,6 +32,8 @@ FROZEN_MPY_DIR ?= modules # include py core make definitions include $(TOP)/py/py.mk +GIT_SUBMODULES = lib/axtls lib/berkeley-db-1.xx + FWBIN = $(BUILD)/firmware-combined.bin PORT ?= /dev/ttyACM0 BAUD ?= 115200 diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index a8bd95cc6d..62208525fe 100644 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -41,6 +41,8 @@ QSTR_DEFS = qstrdefsport.h $(BUILD)/pins_qstr.h # include py core make definitions include ../../py/py.mk +GIT_SUBMODULES = lib/nrfx lib/tinyusb + MICROPY_FATFS ?= 0 FATFS_DIR = lib/oofatfs MPY_CROSS = ../../mpy-cross/mpy-cross diff --git a/ports/nrf/README.md b/ports/nrf/README.md index 1b9c2ec7f0..3c177c705c 100644 --- a/ports/nrf/README.md +++ b/ports/nrf/README.md @@ -50,11 +50,11 @@ Prerequisite steps for building the nrf port: git clone .git micropython cd micropython - git submodule update --init make -C mpy-cross By default, the PCA10040 (nrf52832) is used as compile target. To build and flash issue the following command inside the ports/nrf/ folder: + make submodules make make flash diff --git a/ports/samd/Makefile b/ports/samd/Makefile index 77a53bd486..23646a4842 100644 --- a/ports/samd/Makefile +++ b/ports/samd/Makefile @@ -19,6 +19,8 @@ QSTR_GLOBAL_DEPENDENCIES = $(BOARD_DIR)/mpconfigboard.h # Include py core make definitions include $(TOP)/py/py.mk +GIT_SUBMODULES = lib/asf4 lib/tinyusb + INC += -I. INC += -I$(TOP) INC += -I$(BUILD) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 28b90199ae..112271fe18 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -24,6 +24,8 @@ FROZEN_MPY_DIR ?= modules # include py core make definitions include $(TOP)/py/py.mk +GIT_SUBMODULES = lib/lwip lib/mbedtls lib/mynewt-nimble lib/stm32lib + MCU_SERIES_UPPER = $(shell echo $(MCU_SERIES) | tr '[:lower:]' '[:upper:]') CMSIS_MCU_LOWER = $(shell echo $(CMSIS_MCU) | tr '[:upper:]' '[:lower:]') diff --git a/ports/stm32/README.md b/ports/stm32/README.md index a0c3b7ff39..f5ac362a81 100644 --- a/ports/stm32/README.md +++ b/ports/stm32/README.md @@ -40,7 +40,11 @@ see [here](https://launchpad.net/gcc-arm-embedded) for the main GCC ARM Embedded page. The compiler can be changed using the `CROSS_COMPILE` variable when invoking `make`. -To build for a given board, run: +First the submodules must be obtained using: + + $ make submodules + +Then to build for a given board, run: $ make BOARD=PYBV11 diff --git a/ports/unix/Makefile b/ports/unix/Makefile index 41552bf5c9..134502b4da 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -16,6 +16,8 @@ UNAME_S := $(shell uname -s) # include py core make definitions include $(TOP)/py/py.mk +GIT_SUBMODULES = lib/axtls lib/berkeley-db-1.xx lib/libffi + INC += -I. INC += -I$(TOP) INC += -I$(BUILD) diff --git a/py/mkrules.mk b/py/mkrules.mk index f9d77c3177..a75c64db93 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -143,6 +143,13 @@ clean-prog: .PHONY: clean-prog endif +submodules: + $(ECHO) "Updating submodules: $(GIT_SUBMODULES)" +ifneq ($(GIT_SUBMODULES),) + $(Q)git submodule update --init $(addprefix $(TOP)/,$(GIT_SUBMODULES)) +endif +.PHONY: submodules + LIBMICROPYTHON = libmicropython.a # We can execute extra commands after library creation using From f562f94e1c4ba3dd62a30b778ca6e88474fbc8e8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 14 Oct 2019 12:09:39 +1100 Subject: [PATCH 0833/1788] travis: Use "make submodules" to init required modules for each port. --- .travis.yml | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index cc015bda39..077fca20af 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,8 +32,8 @@ jobs: - sudo apt-get install libnewlib-arm-none-eabi - arm-none-eabi-gcc --version script: - - git submodule update --init lib/lwip lib/mbedtls lib/stm32lib lib/mynewt-nimble - make ${MAKEOPTS} -C mpy-cross + - make ${MAKEOPTS} -C ports/stm32 submodules - make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_F091RC - make ${MAKEOPTS} -C ports/stm32 BOARD=PYBV11 MICROPY_PY_WIZNET5K=5200 MICROPY_PY_CC3K=1 - make ${MAKEOPTS} -C ports/stm32 BOARD=PYBD_SF2 @@ -66,8 +66,8 @@ jobs: - gcc --version - python3 --version script: - - git submodule update --init lib/axtls lib/berkeley-db-1.xx lib/libffi - make ${MAKEOPTS} -C mpy-cross + - make ${MAKEOPTS} -C ports/unix submodules - make ${MAKEOPTS} -C ports/unix deplibs - make ${MAKEOPTS} -C ports/unix coverage # run the main test suite @@ -87,8 +87,8 @@ jobs: - stage: test env: NAME="unix port build and tests" script: - - git submodule update --init lib/axtls lib/berkeley-db-1.xx lib/libffi - make ${MAKEOPTS} -C mpy-cross + - make ${MAKEOPTS} -C ports/unix submodules - make ${MAKEOPTS} -C ports/unix deplibs - make ${MAKEOPTS} -C ports/unix - make ${MAKEOPTS} -C ports/unix test @@ -100,8 +100,8 @@ jobs: install: - sudo apt-get install gcc-multilib libffi-dev:i386 script: - - git submodule update --init lib/axtls lib/berkeley-db-1.xx lib/libffi - make ${MAKEOPTS} -C mpy-cross PYTHON=python2 + - make ${MAKEOPTS} -C ports/unix submodules - make ${MAKEOPTS} -C ports/unix PYTHON=python2 deplibs - make ${MAKEOPTS} -C ports/unix PYTHON=python2 nanbox - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_nanbox ./run-tests) @@ -112,8 +112,8 @@ jobs: install: - sudo apt-get install clang script: - - git submodule update --init lib/axtls lib/berkeley-db-1.xx lib/libffi - make ${MAKEOPTS} -C mpy-cross CC=clang + - make ${MAKEOPTS} -C ports/unix submodules - make ${MAKEOPTS} -C ports/unix CC=clang CFLAGS_EXTRA="-DMICROPY_STACKLESS=1 -DMICROPY_STACKLESS_STRICT=1" - make ${MAKEOPTS} -C ports/unix CC=clang test @@ -149,11 +149,11 @@ jobs: - git clone https://github.com/espressif/esp-idf.git - export IDF_PATH=$(pwd)/esp-idf script: - - git submodule update --init lib/berkeley-db-1.xx - make ${MAKEOPTS} -C mpy-cross # IDF v3 build - git -C esp-idf checkout $(grep "ESPIDF_SUPHASH_V3 :=" ports/esp32/Makefile | cut -d " " -f 3) - git -C esp-idf submodule update --init components/json/cJSON components/esp32/lib components/esptool_py/esptool components/expat/expat components/lwip/lwip components/mbedtls/mbedtls components/micro-ecc/micro-ecc components/nghttp/nghttp2 + - make ${MAKEOPTS} -C ports/esp32 submodules - make ${MAKEOPTS} -C ports/esp32 # clean - git -C esp-idf clean -f -f -d components/json/cJSON components/esp32/lib components/expat/expat components/micro-ecc/micro-ecc components/nghttp/nghttp2 @@ -161,6 +161,7 @@ jobs: # IDF v4 build - git -C esp-idf checkout $(grep "ESPIDF_SUPHASH_V4 :=" ports/esp32/Makefile | cut -d " " -f 3) - git -C esp-idf submodule update --init components/bt/controller/lib components/bt/host/nimble/nimble components/esp_wifi/lib_esp32 components/esptool_py/esptool components/lwip/lwip components/mbedtls/mbedtls + - make ${MAKEOPTS} -C ports/esp32 submodules - make ${MAKEOPTS} -C ports/esp32 # esp8266 port @@ -171,8 +172,8 @@ jobs: - zcat xtensa-lx106-elf-standalone.tar.gz | tar x - export PATH=$(pwd)/xtensa-lx106-elf/bin:$PATH script: - - git submodule update --init lib/axtls lib/berkeley-db-1.xx - make ${MAKEOPTS} -C mpy-cross + - make ${MAKEOPTS} -C ports/esp8266 submodules - make ${MAKEOPTS} -C ports/esp8266 - make ${MAKEOPTS} -C ports/esp8266 BOARD=GENERIC_512K @@ -184,7 +185,7 @@ jobs: - sudo apt-get install libnewlib-arm-none-eabi - arm-none-eabi-gcc --version script: - - git submodule update --init lib/nrfx + - make ${MAKEOPTS} -C ports/nrf submodules - make ${MAKEOPTS} -C ports/nrf # bare-arm and minimal ports @@ -220,7 +221,7 @@ jobs: - sudo apt-get install gcc-arm-none-eabi - sudo apt-get install libnewlib-arm-none-eabi script: - - git submodule update --init lib/asf4 lib/tinyusb + - make ${MAKEOPTS} -C ports/samd submodules - make ${MAKEOPTS} -C ports/samd # teensy port From 418f12c5f50b6642aee0193adaa792c962226683 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 14 Oct 2019 15:39:40 +1100 Subject: [PATCH 0834/1788] extmod/modbluetooth: Increase maximum connections from 1 to 4. This avoids a confusing ENOMEM raised from gap_advertise if there is currently an active connection. This refers to the static connection buffer pre-allocated by Nimble (nothing to do with MicroPython heap memory). --- extmod/nimble/syscfg/syscfg.h | 2 +- ports/esp32/boards/sdkconfig.ble | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/extmod/nimble/syscfg/syscfg.h b/extmod/nimble/syscfg/syscfg.h index 0d3acf9a76..485e5be3cc 100644 --- a/extmod/nimble/syscfg/syscfg.h +++ b/extmod/nimble/syscfg/syscfg.h @@ -40,7 +40,7 @@ int nimble_sprintf(char *str, const char *fmt, ...); /*** nimble */ #define MYNEWT_VAL_BLE_EXT_ADV (0) #define MYNEWT_VAL_BLE_EXT_ADV_MAX_SIZE (31) -#define MYNEWT_VAL_BLE_MAX_CONNECTIONS (1) +#define MYNEWT_VAL_BLE_MAX_CONNECTIONS (4) #define MYNEWT_VAL_BLE_MULTI_ADV_INSTANCES (0) #define MYNEWT_VAL_BLE_ROLE_BROADCASTER (1) #define MYNEWT_VAL_BLE_ROLE_CENTRAL (1) diff --git a/ports/esp32/boards/sdkconfig.ble b/ports/esp32/boards/sdkconfig.ble index db9cc11752..2c7c97b612 100644 --- a/ports/esp32/boards/sdkconfig.ble +++ b/ports/esp32/boards/sdkconfig.ble @@ -4,3 +4,4 @@ CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY= CONFIG_BTDM_CTRL_MODE_BTDM= CONFIG_BT_NIMBLE_ENABLED=y +CONFIG_BT_NIMBLE_MAX_CONNECTIONS=4 From ba16a229914e9c1a4c56ad7da41567ed8fe5b91c Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 14 Oct 2019 15:44:22 +1100 Subject: [PATCH 0835/1788] extmod/modbluetooth: Clear gap_advertise payload when data is empty. Also fix default adv interval to 500ms. --- extmod/modbluetooth.c | 2 +- extmod/modbluetooth_nimble.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index 45ca61b6f0..5e3171e2b5 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -303,7 +303,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bluetooth_ble_irq_obj, 1, bluetooth_ble_irq); STATIC mp_obj_t bluetooth_ble_gap_advertise(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_interval_us, ARG_adv_data, ARG_resp_data, ARG_connectable }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_interval_us, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(100)} }, + { MP_QSTR_interval_us, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(500000)} }, { MP_QSTR_adv_data, MP_ARG_OBJ, {.u_obj = mp_const_none } }, { MP_QSTR_resp_data, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none } }, { MP_QSTR_connectable, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_true } }, diff --git a/extmod/modbluetooth_nimble.c b/extmod/modbluetooth_nimble.c index 8805d41007..131b73574d 100644 --- a/extmod/modbluetooth_nimble.c +++ b/extmod/modbluetooth_nimble.c @@ -346,14 +346,14 @@ int mp_bluetooth_gap_advertise_start(bool connectable, int32_t interval_us, cons mp_bluetooth_gap_advertise_stop(); - if ((adv_data != NULL) && (adv_data_len > 0)) { + if (adv_data) { ret = ble_gap_adv_set_data(adv_data, adv_data_len); if (ret != 0) { return ble_hs_err_to_errno(ret); } } - if ((sr_data != NULL) && (sr_data_len > 0)) { + if (sr_data) { ret = ble_gap_adv_rsp_set_data(sr_data, sr_data_len); if (ret != 0) { return ble_hs_err_to_errno(ret); @@ -384,6 +384,7 @@ int mp_bluetooth_gap_advertise_start(bool connectable, int32_t interval_us, cons if (ret == 0) { return 0; } + DEBUG_EVENT_printf("ble_gap_adv_start: %d\n", ret); return ble_hs_err_to_errno(ret); } @@ -583,7 +584,7 @@ int mp_bluetooth_gatts_indicate(uint16_t conn_handle, uint16_t value_handle) { #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE STATIC int gap_scan_cb(struct ble_gap_event *event, void *arg) { - DEBUG_EVENT_printf("gap_scan_cb: event=%d type=%d\n", event->type, event->disc ? event->disc.event_type : -1); + DEBUG_EVENT_printf("gap_scan_cb: event=%d type=%d\n", event->type, event->type == BLE_GAP_EVENT_DISC ? event->disc.event_type : -1); if (event->type == BLE_GAP_EVENT_DISC_COMPLETE) { mp_bluetooth_gap_on_scan_complete(); From 62e3a966fbb51f66f370523d04677a44680f0760 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 14 Oct 2019 15:45:31 +1100 Subject: [PATCH 0836/1788] docs/library/bluetooth.rst: Clarify gap_advertise adv_data behavior. Make it clear that the previous adv_data will be reused if it's not set. And some minor other improvements. --- docs/library/bluetooth.rst | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/docs/library/bluetooth.rst b/docs/library/bluetooth.rst index e9a803cb9b..3ab6c72b4e 100644 --- a/docs/library/bluetooth.rst +++ b/docs/library/bluetooth.rst @@ -6,7 +6,8 @@ This module provides an interface to a Bluetooth controller on a board. Currently this supports Bluetooth Low Energy (BLE) in Central, Peripheral, -Broadcaster, and Observer roles. +Broadcaster, and Observer roles, and a device may operate in multiple +roles concurrently. This API is intended to match the low-level Bluetooth protocol and provide building-blocks for higher-level abstractions such as specific device types. @@ -66,6 +67,7 @@ Event Handling elif event == _IRQ_GATTS_READ_REQUEST: # A central has issued a read. Note: this is a hard IRQ. # Return None to deny the read. + # Note: This event is not supported on ESP32. conn_handle, attr_handle = data elif event == _IRQ_SCAN_RESULT: # A single scan result. @@ -138,6 +140,11 @@ Broadcaster Role (Advertiser) protocol (e.g. ``bytes``, ``bytearray``, ``str``). *adv_data* is included in all broadcasts, and *resp_data* is send in reply to an active scan. + Note: if *adv_data* (or *resp_data*) is ``None``, then the data passed + to the previous call to ``gap_advertise`` will be re-used. This allows a + broadcaster to resume advertising with just ``gap_advertise(interval_us)``. + To clear the advertising payload pass an empty ``bytes``, i.e. ``b''``. + Observer Role (Scanner) ----------------------- @@ -169,9 +176,10 @@ A BLE peripheral has a set of registered services. Each service may contain characteristics, which each have a value. Characteristics can also contain descriptors, which themselves have values. -These values are stored locally and can be read from or written to by a remote -central device. Additionally, a peripheral can "notify" its value to a connected -central via its connection handle. +These values are stored locally, and are accessed by their "value handle" which +is generated during service registration. They can also be read from or written +to by a remote central device. Additionally, a peripheral can "notify" a +characteristic to a connected central via a connection handle. .. method:: BLE.gatts_register_services(services_definition) From cb73103f57aac8c5d58c4e7d495567b6fe3fa137 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 14 Oct 2019 15:48:00 +1100 Subject: [PATCH 0837/1788] extmod/modbluetooth: Fix order of params to IRQ_GATTS_WRITE event. --- extmod/modbluetooth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index 5e3171e2b5..1f247a20ca 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -829,7 +829,7 @@ void mp_bluetooth_gap_on_connected_disconnected(uint16_t event, uint16_t conn_ha schedule_ringbuf(sched); } -void mp_bluetooth_gatts_on_write(uint16_t value_handle, uint16_t conn_handle) { +void mp_bluetooth_gatts_on_write(uint16_t conn_handle, uint16_t value_handle) { MICROPY_PY_BLUETOOTH_ENTER mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); bool sched; From 423e67d0a000bb2379f0c2f2a93989bfa17157e0 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 14 Oct 2019 23:37:35 +1100 Subject: [PATCH 0838/1788] extmod/modbluetooth: Improve ringbuf handling. No need to share the irq_data buffer with addresses. Split them into two separate buffers and manage their max length independently. --- extmod/modbluetooth.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index 1f247a20ca..cd8a2b0700 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -59,6 +59,7 @@ typedef struct { mp_obj_base_t base; mp_obj_t irq_handler; mp_obj_t irq_data_tuple; + uint8_t irq_addr_bytes[6]; uint8_t irq_data_bytes[MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN]; mp_obj_t irq_data_uuid; uint16_t irq_trigger; @@ -232,7 +233,7 @@ STATIC mp_obj_t bluetooth_ble_make_new(const mp_obj_type_t *type, size_t n_args, mp_obj_bluetooth_ble_t *o = m_new_obj(mp_obj_bluetooth_ble_t); o->base.type = &bluetooth_ble_type; o->irq_handler = mp_const_none; - // Pre-allocated the event data tuple to prevent needing to allocate in the IRQ handler. + // Pre-allocate the event data tuple to prevent needing to allocate in the IRQ handler. o->irq_data_tuple = mp_obj_new_tuple(MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_TUPLE_LEN, NULL); mp_obj_bluetooth_uuid_t *uuid = m_new_obj(mp_obj_bluetooth_uuid_t); uuid->base.type = &bluetooth_uuid_type; @@ -287,9 +288,9 @@ STATIC mp_obj_t bluetooth_ble_irq(size_t n_args, const mp_obj_t *pos_args, mp_ma // Update the callback. MICROPY_PY_BLUETOOTH_ENTER - mp_obj_bluetooth_ble_t* bt = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); - bt->irq_handler = callback; - bt->irq_trigger = args[ARG_trigger].u_int; + mp_obj_bluetooth_ble_t* o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); + o->irq_handler = callback; + o->irq_trigger = args[ARG_trigger].u_int; MICROPY_PY_BLUETOOTH_EXIT return mp_const_none; @@ -693,7 +694,7 @@ STATIC void ringbuf_extract(ringbuf_t* ringbuf, mp_obj_tuple_t *data_tuple, size if (bytes_addr) { bytes_addr->len = 6; for (int i = 0; i < bytes_addr->len; ++i) { - // cast away const, this is actually bt->irq_data_bytes. + // cast away const, this is actually bt->irq_addr_bytes. ((uint8_t*)bytes_addr->data)[i] = ringbuf_get(ringbuf); } data_tuple->items[j++] = MP_OBJ_FROM_PTR(bytes_addr); @@ -715,7 +716,7 @@ STATIC void ringbuf_extract(ringbuf_t* ringbuf, mp_obj_tuple_t *data_tuple, size if (bytes_data) { bytes_data->len = ringbuf_get(ringbuf); for (int i = 0; i < bytes_data->len; ++i) { - // cast away const, this is actually bt->irq_data_bytes + 6. + // cast away const, this is actually bt->irq_data_bytes. ((uint8_t*)bytes_data->data)[i] = ringbuf_get(ringbuf); } data_tuple->items[j++] = MP_OBJ_FROM_PTR(bytes_data); @@ -746,8 +747,8 @@ STATIC mp_obj_t bluetooth_ble_invoke_irq(mp_obj_t none_in) { // Some events need to pass bytes objects to their handler, using the // pre-allocated bytes array. - mp_obj_str_t irq_data_bytes_addr = {{&mp_type_bytes}, 0, 6, o->irq_data_bytes}; - mp_obj_str_t irq_data_bytes_data = {{&mp_type_bytes}, 0, 0, o->irq_data_bytes + 6}; + mp_obj_str_t irq_data_bytes_addr = {{&mp_type_bytes}, 0, 6, o->irq_addr_bytes}; + mp_obj_str_t irq_data_bytes_data = {{&mp_type_bytes}, 0, 0, o->irq_data_bytes}; if (event == MP_BLUETOOTH_IRQ_CENTRAL_CONNECT || event == MP_BLUETOOTH_IRQ_PERIPHERAL_CONNECT || event == MP_BLUETOOTH_IRQ_CENTRAL_DISCONNECT || event == MP_BLUETOOTH_IRQ_PERIPHERAL_DISCONNECT) { // conn_handle, addr_type, addr @@ -799,7 +800,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(bluetooth_ble_invoke_irq_obj, bluetooth_ble_inv STATIC bool enqueue_irq(mp_obj_bluetooth_ble_t *o, size_t len, uint16_t event, bool *sched) { *sched = false; - if (ringbuf_free(&o->ringbuf) >= len + 2 && (o->irq_trigger & event) && o->irq_handler != mp_const_none) { + if (o && ringbuf_free(&o->ringbuf) >= len + 2 && (o->irq_trigger & event) && o->irq_handler != mp_const_none) { *sched = ringbuf_avail(&o->ringbuf) == 0; ringbuf_put16(&o->ringbuf, event); return true; @@ -818,7 +819,7 @@ void mp_bluetooth_gap_on_connected_disconnected(uint16_t event, uint16_t conn_ha MICROPY_PY_BLUETOOTH_ENTER mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); bool sched; - if (enqueue_irq(o, 9, event, &sched)) { + if (enqueue_irq(o, 2 + 1 + 6, event, &sched)) { ringbuf_put16(&o->ringbuf, conn_handle); ringbuf_put(&o->ringbuf, addr_type); for (int i = 0; i < 6; ++i) { @@ -833,7 +834,7 @@ void mp_bluetooth_gatts_on_write(uint16_t conn_handle, uint16_t value_handle) { MICROPY_PY_BLUETOOTH_ENTER mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); bool sched; - if (enqueue_irq(o, 4, MP_BLUETOOTH_IRQ_GATTS_WRITE, &sched)) { + if (enqueue_irq(o, 2 + 2, MP_BLUETOOTH_IRQ_GATTS_WRITE, &sched)) { ringbuf_put16(&o->ringbuf, conn_handle); ringbuf_put16(&o->ringbuf, value_handle); } @@ -856,7 +857,8 @@ void mp_bluetooth_gap_on_scan_result(uint8_t addr_type, const uint8_t *addr, boo MICROPY_PY_BLUETOOTH_ENTER mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); bool sched; - if (enqueue_irq(o, 1 + 6 + 1 + 1 + data_len, MP_BLUETOOTH_IRQ_SCAN_RESULT, &sched)) { + data_len = MIN(MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN, data_len); + if (enqueue_irq(o, 1 + 6 + 1 + 1 + 1 + data_len, MP_BLUETOOTH_IRQ_SCAN_RESULT, &sched)) { ringbuf_put(&o->ringbuf, addr_type); for (int i = 0; i < 6; ++i) { ringbuf_put(&o->ringbuf, addr[i]); @@ -864,7 +866,6 @@ void mp_bluetooth_gap_on_scan_result(uint8_t addr_type, const uint8_t *addr, boo ringbuf_put(&o->ringbuf, connectable ? 1 : 0); // Note conversion of int8_t rssi to uint8_t. Must un-convert on the way out. ringbuf_put(&o->ringbuf, (uint8_t)rssi); - data_len = MIN(MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN, data_len); ringbuf_put(&o->ringbuf, data_len); for (int i = 0; i < data_len; ++i) { ringbuf_put(&o->ringbuf, data[i]); @@ -920,10 +921,10 @@ void mp_bluetooth_gattc_on_data_available(uint16_t event, uint16_t conn_handle, MICROPY_PY_BLUETOOTH_ENTER mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); bool sched; + data_len = MIN(MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN, data_len); if (enqueue_irq(o, 2 + 2 + 1 + data_len, event, &sched)) { ringbuf_put16(&o->ringbuf, conn_handle); ringbuf_put16(&o->ringbuf, value_handle); - data_len = MIN(MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN, data_len); ringbuf_put(&o->ringbuf, data_len); for (int i = 0; i < data_len; ++i) { ringbuf_put(&o->ringbuf, data[i]); @@ -949,6 +950,8 @@ void mp_bluetooth_gattc_on_write_status(uint16_t conn_handle, uint16_t value_han #endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE #if MICROPY_PY_BLUETOOTH_GATTS_ON_READ_CALLBACK +// This can only be enabled when the thread invoking this is a MicroPython thread. +// On ESP32, for example, this is not the case. bool mp_bluetooth_gatts_on_read_request(uint16_t conn_handle, uint16_t value_handle) { mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); if ((o->irq_trigger & MP_BLUETOOTH_IRQ_GATTS_READ_REQUEST) && o->irq_handler != mp_const_none) { From 4b2b05718a5b07a4cdf678fbe1005162b1e043ca Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 14 Oct 2019 23:40:04 +1100 Subject: [PATCH 0839/1788] esp32: Run NimBLE on the app core. This prevents issues with concurrent access to the ringbuf. MICROPY_BEGIN_ATOMIC_SECTION is only atomic to the same core. We could address this with a mutex, but it's also not safe to call mp_sched_schedule across cores. --- ports/esp32/boards/sdkconfig.ble | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ports/esp32/boards/sdkconfig.ble b/ports/esp32/boards/sdkconfig.ble index 2c7c97b612..15422903c1 100644 --- a/ports/esp32/boards/sdkconfig.ble +++ b/ports/esp32/boards/sdkconfig.ble @@ -3,5 +3,12 @@ CONFIG_BT_ENABLED=y CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY= CONFIG_BTDM_CTRL_MODE_BTDM= + CONFIG_BT_NIMBLE_ENABLED=y + CONFIG_BT_NIMBLE_MAX_CONNECTIONS=4 + +# Pin to the same core as MP. +CONFIG_BT_NIMBLE_PINNED_TO_CORE_0=n +CONFIG_BT_NIMBLE_PINNED_TO_CORE_1=y +CONFIG_BT_NIMBLE_PINNED_TO_CORE=1 From ea315d7d58e429d27c4d4fb4b98a432e86fdcae6 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 15 Oct 2019 10:10:41 +1100 Subject: [PATCH 0840/1788] docs/library/bluetooth.rst: Explain how to increase char buffer size. --- docs/library/bluetooth.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/library/bluetooth.rst b/docs/library/bluetooth.rst index 3ab6c72b4e..6ef660416a 100644 --- a/docs/library/bluetooth.rst +++ b/docs/library/bluetooth.rst @@ -181,6 +181,13 @@ is generated during service registration. They can also be read from or written to by a remote central device. Additionally, a peripheral can "notify" a characteristic to a connected central via a connection handle. +Characteristics and descriptors have a default maximum size of 20 bytes. +Anything written to them by a central will be truncated to this length. However, +any local write will increase the maximum size, so if you want to allow larger +writes from a central to a given characteristic, use +:meth:`gatts_write` after registration. e.g. +``gatts_write(char_handle, bytes(100))``. + .. method:: BLE.gatts_register_services(services_definition) Configures the peripheral with the specified services, replacing any From 36502bdfdcd63b2bc87027380dc63098221e8b04 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 15 Oct 2019 12:07:29 +1100 Subject: [PATCH 0841/1788] extmod/modbluetooth: Make gap_disconnect not raise when disconnected. Previously it raised OSError(MP_ENOTCONN) if the conn_handle was already disconnected. Now it returns True/False. --- docs/library/bluetooth.rst | 3 +++ extmod/modbluetooth.c | 9 ++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/library/bluetooth.rst b/docs/library/bluetooth.rst index 6ef660416a..00ced33e5f 100644 --- a/docs/library/bluetooth.rst +++ b/docs/library/bluetooth.rst @@ -262,6 +262,9 @@ Central Role (GATT Client) On success, the ``_IRQ_PERIPHERAL_DISCONNECT`` event will be raised. + Returns ``False`` if the connection handle wasn't connected, and ``True`` + otherwise. + .. method:: BLE.gattc_discover_services(conn_handle) Query a connected peripheral for its services. diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index cd8a2b0700..6404499251 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -27,6 +27,7 @@ #include "py/binary.h" #include "py/misc.h" +#include "py/mperrno.h" #include "py/obj.h" #include "py/objstr.h" #include "py/objarray.h" @@ -527,7 +528,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gap_scan_obj, 1, 4, blu STATIC mp_obj_t bluetooth_ble_gap_disconnect(mp_obj_t self_in, mp_obj_t conn_handle_in) { uint16_t conn_handle = mp_obj_get_int(conn_handle_in); int err = mp_bluetooth_gap_disconnect(conn_handle); - return bluetooth_handle_errno(err); + if (err == 0) { + return mp_const_true; + } else if (err == MP_ENOTCONN) { + return mp_const_false; + } else { + return bluetooth_handle_errno(err); + } } STATIC MP_DEFINE_CONST_FUN_OBJ_2(bluetooth_ble_gap_disconnect_obj, bluetooth_ble_gap_disconnect); From 8f7f67123680947d7f7a38f8a2aff63c0ddd0338 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 15 Oct 2019 17:29:27 +1100 Subject: [PATCH 0842/1788] extmod/modbluetooth: In gap_advertise only accept None to stop adv. To match the docs, and interval=0 may be used in the future to indicate something else. --- extmod/modbluetooth.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index 6404499251..3c00d5c1b5 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -313,12 +313,12 @@ STATIC mp_obj_t bluetooth_ble_gap_advertise(size_t n_args, const mp_obj_t *pos_a 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); - mp_int_t interval_us; - if (args[ARG_interval_us].u_obj == mp_const_none || (interval_us = mp_obj_get_int(args[ARG_interval_us].u_obj)) == 0) { + if (args[ARG_interval_us].u_obj == mp_const_none) { mp_bluetooth_gap_advertise_stop(); return mp_const_none; } + mp_int_t interval_us = mp_obj_get_int(args[ARG_interval_us].u_obj); bool connectable = mp_obj_is_true(args[ARG_connectable].u_obj); mp_buffer_info_t adv_bufinfo = {0}; From 8e8cfa6f53b95fb9a7f7a430fb7bda77be56a6bd Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 10 Oct 2019 23:22:29 +1100 Subject: [PATCH 0843/1788] tools/make-frozen.py: Allow to run with no directory passed in. In which case it will just emit empty frozen C definitions. --- tools/make-frozen.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tools/make-frozen.py b/tools/make-frozen.py index 1051b520e4..8809fd0c8e 100755 --- a/tools/make-frozen.py +++ b/tools/make-frozen.py @@ -27,14 +27,15 @@ def module_name(f): modules = [] -root = sys.argv[1].rstrip("/") -root_len = len(root) +if len(sys.argv) > 1: + root = sys.argv[1].rstrip("/") + root_len = len(root) -for dirpath, dirnames, filenames in os.walk(root): - for f in filenames: - fullpath = dirpath + "/" + f - st = os.stat(fullpath) - modules.append((fullpath[root_len + 1:], st)) + for dirpath, dirnames, filenames in os.walk(root): + for f in filenames: + fullpath = dirpath + "/" + f + st = os.stat(fullpath) + modules.append((fullpath[root_len + 1:], st)) print("#include ") print("const char mp_frozen_str_names[] = {") From e81f538e2509938b25eb48ed2670142eed1f2573 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 10 Sep 2019 00:49:02 +1000 Subject: [PATCH 0844/1788] tools: Add mechanism to provide a manifest of frozen files. This introduces a new build variable FROZEN_MANIFEST which can be set to a manifest listing (written in Python) that describes the set of files to be frozen in to the firmware. --- py/mkenv.mk | 1 + py/mkrules.mk | 6 + py/py.mk | 5 + tools/makemanifest.py | 252 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 264 insertions(+) create mode 100644 tools/makemanifest.py diff --git a/py/mkenv.mk b/py/mkenv.mk index 0a59c2ac74..70d937c450 100644 --- a/py/mkenv.mk +++ b/py/mkenv.mk @@ -61,6 +61,7 @@ CXX += -m32 LD += -m32 endif +MAKE_MANIFEST = $(PYTHON) $(TOP)/tools/makemanifest.py MAKE_FROZEN = $(PYTHON) $(TOP)/tools/make-frozen.py MPY_CROSS = $(TOP)/mpy-cross/mpy-cross MPY_TOOL = $(PYTHON) $(TOP)/tools/mpy-tool.py diff --git a/py/mkrules.mk b/py/mkrules.mk index a75c64db93..2a7e1980c9 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -97,6 +97,12 @@ $(OBJ_DIRS): $(HEADER_BUILD): $(MKDIR) -p $@ +ifneq ($(FROZEN_MANIFEST),) +# to build frozen_content.c from a manifest +$(BUILD)/frozen_content.c: FORCE $(BUILD)/genhdr/qstrdefs.generated.h + $(Q)$(MAKE_MANIFEST) -o $@ $(TOP) $(BUILD) "$(MPY_CROSS_FLAGS)" $(FROZEN_MANIFEST) +endif + ifneq ($(FROZEN_DIR),) $(BUILD)/frozen.c: $(wildcard $(FROZEN_DIR)/*) $(HEADER_BUILD) $(FROZEN_EXTRA_DEPS) $(ECHO) "GEN $@" diff --git a/py/py.mk b/py/py.mk index 5669e33fcc..514a0e405a 100644 --- a/py/py.mk +++ b/py/py.mk @@ -202,6 +202,11 @@ 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) +# object file for frozen code specified via a manifest +ifneq ($(FROZEN_MANIFEST),) +PY_O += $(BUILD)/$(BUILD)/frozen_content.o +endif + # object file for frozen files ifneq ($(FROZEN_DIR),) PY_O += $(BUILD)/$(BUILD)/frozen.o diff --git a/tools/makemanifest.py b/tools/makemanifest.py new file mode 100644 index 0000000000..3017d7a21f --- /dev/null +++ b/tools/makemanifest.py @@ -0,0 +1,252 @@ +#!/usr/bin/env python3 +# +# This file is part of the MicroPython project, http://micropython.org/ +# +# The MIT License (MIT) +# +# Copyright (c) 2019 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. + +from __future__ import print_function +import sys +import os +import subprocess + + +########################################################################### +# Public functions to be used in the manifest + +def include(manifest): + """Include another manifest. + + The manifest argument can be a string (filename) or an iterable of + strings. + """ + + if not isinstance(manifest, str): + for m in manifest: + include(m) + else: + with open(manifest) as f: + exec(f.read()) + +def freeze(path, script=None, opt=0): + """Freeze the input, automatically determining its type. A .py script + will be compiled to a .mpy first then frozen, and a .mpy file will be + frozen directly. + + `path` must be a directory, which is the base directory to search for + files from. When importing the resulting frozen modules, the name of + the module will start after `path`, ie `path` is excluded from the + module name. + + If `script` is None all files in `path` will be frozen. + + If `script` is an iterable then freeze() is called on all items of the + iterable (with the same `path` and `opt` passed through). + + If `script` is a string then it specifies the filename to freeze, and + can include extra directories before the file. The file will be + searched for in `path`. + + `opt` is the optimisation level to pass to mpy-cross when compiling .py + to .mpy. + """ + + freeze_internal(KIND_AUTO, path, script, opt) + +def freeze_as_str(path): + """Freeze the given `path` and all .py scripts within it as a string, + which will be compiled upon import. + """ + + freeze_internal(KIND_AS_STR, path, None, 0) + +def freeze_as_mpy(path, script=None, opt=0): + """Freeze the input (see above) by first compiling the .py scripts to + .mpy files, then freezing the resulting .mpy files. + """ + + freeze_internal(KIND_AS_MPY, path, script, opt) + +def freeze_mpy(path, script=None, opt=0): + """Freeze the input (see above), which must be .mpy files that are + frozen directly. + """ + + freeze_internal(KIND_MPY, path, script, opt) + + +########################################################################### +# Internal implementation + +KIND_AUTO = 0 +KIND_AS_STR = 1 +KIND_AS_MPY = 2 +KIND_MPY = 3 + +manifest_list = [] + +class FreezeError(Exception): + pass + +def system(cmd): + try: + output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) + return 0, output + except subprocess.CalledProcessError as er: + return -1, er.output + +def convert_path(path): + return path.replace('$(MPY)', TOP) + +def get_timestamp(path, default=None): + try: + stat = os.stat(path) + return stat.st_mtime + except OSError: + if default is None: + raise FreezeError('cannot stat {}'.format(path)) + return default + +def get_timestamp_newest(path): + ts_newest = 0 + for dirpath, dirnames, filenames in os.walk(path): + for f in filenames: + ts_newest = max(ts_newest, get_timestamp(os.path.join(dirpath, f))) + return ts_newest + +def mkdir(path): + cur_path = '' + for p in path.split('/')[:-1]: + cur_path += p + '/' + try: + os.mkdir(cur_path) + except OSError as er: + if er.args[0] == 17: # file exists + pass + else: + raise er + +def freeze_internal(kind, path, script, opt): + path = convert_path(path) + if script is None and kind == KIND_AS_STR: + if any(f[0] == KIND_AS_STR for f in manifest_list): + raise FreezeError('can only freeze one str directory') + manifest_list.append((KIND_AS_STR, path, script, opt)) + elif script is None: + for dirpath, dirnames, filenames in os.walk(path): + for f in filenames: + freeze_internal(kind, path, (dirpath + '/' + f)[len(path) + 1:], opt) + elif not isinstance(script, str): + for s in script: + freeze_internal(kind, path, s, opt) + else: + extension_kind = {KIND_AS_MPY: '.py', KIND_MPY: '.mpy'} + if kind == KIND_AUTO: + for k, ext in extension_kind.items(): + if script.endswith(ext): + kind = k + break + else: + raise FreezeError('unsupported file type {}'.format(script)) + wanted_extension = extension_kind[kind] + if not script.endswith(wanted_extension): + raise FreezeError('expecting a {} file, got {}'.format(wanted_extension, script)) + manifest_list.append((kind, path, script, opt)) + +def main(): + global TOP + + # Parse arguments + assert sys.argv[1] == '-o' + output_file = sys.argv[2] + TOP = sys.argv[3] + BUILD = sys.argv[4] + mpy_cross_flags = sys.argv[5] + input_manifest_list = sys.argv[6:] + + # Get paths to tools + MAKE_FROZEN = TOP + '/tools/make-frozen.py' + MPY_CROSS = TOP + '/mpy-cross/mpy-cross' + MPY_TOOL = TOP + '/tools/mpy-tool.py' + + # Include top-level inputs, to generate the manifest + for input_manifest in input_manifest_list: + try: + if input_manifest.endswith('.py'): + include(input_manifest) + else: + exec(input_manifest) + except FreezeError as er: + print('freeze error executing "{}": {}'.format(input_manifest, er.args[0])) + sys.exit(1) + + # Process the manifest + str_paths = [] + mpy_files = [] + ts_newest = 0 + for kind, path, script, opt in manifest_list: + if kind == KIND_AS_STR: + str_paths.append(path) + ts_outfile = get_timestamp_newest(path) + elif kind == KIND_AS_MPY: + infile = '{}/{}'.format(path, script) + outfile = '{}/frozen_mpy/{}.mpy'.format(BUILD, script[:-3]) + ts_infile = get_timestamp(infile) + ts_outfile = get_timestamp(outfile, 0) + if ts_infile >= ts_outfile: + print('MPY', script) + mkdir(outfile) + res, out = system([MPY_CROSS] + mpy_cross_flags.split() + ['-o', outfile, '-s', script, '-O{}'.format(opt), infile]) + if res != 0: + print('error compiling {}: {}'.format(infile, out)) + raise SystemExit(1) + ts_outfile = get_timestamp(outfile) + mpy_files.append(outfile) + else: + assert kind == KIND_MPY + infile = '{}/{}'.format(path, script) + mpy_files.append(infile) + ts_outfile = get_timestamp(infile) + ts_newest = max(ts_newest, ts_outfile) + + # Check if output file needs generating + if ts_newest < get_timestamp(output_file, 0): + # No files are newer than output file so it does not need updating + return + + # Freeze paths as strings + _, output_str = system([MAKE_FROZEN] + str_paths) + + # Freeze .mpy files + _, output_mpy = system([MPY_TOOL, '-f', '-q', BUILD + '/genhdr/qstrdefs.preprocessed.h'] + mpy_files) + + # Generate output + print('GEN', output_file) + mkdir(output_file) + with open(output_file, 'wb') as f: + f.write(b'//\n// Content for MICROPY_MODULE_FROZEN_STR\n//\n') + f.write(output_str) + f.write(b'//\n// Content for MICROPY_MODULE_FROZEN_MPY\n//\n') + f.write(output_mpy) + +if __name__ == '__main__': + main() From b1c0355b9359b0a63e08d9e5f33755f5919a6b8e Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 10 Sep 2019 00:50:04 +1000 Subject: [PATCH 0845/1788] unix: Convert to use FROZEN_MANIFEST to specify frozen code. Removes symlinks in modules directory, all frozen code is now specified by manifest.py. --- ports/unix/Makefile | 16 +++++++++------- ports/unix/manifest.py | 2 ++ ports/unix/manifest_coverage.py | 2 ++ ports/unix/modules/upip.py | 1 - ports/unix/modules/upip_utarfile.py | 1 - 5 files changed, 13 insertions(+), 9 deletions(-) create mode 100644 ports/unix/manifest.py create mode 100644 ports/unix/manifest_coverage.py delete mode 120000 ports/unix/modules/upip.py delete mode 120000 ports/unix/modules/upip_utarfile.py diff --git a/ports/unix/Makefile b/ports/unix/Makefile index 134502b4da..b840856ffa 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -1,8 +1,10 @@ -include mpconfigport.mk include ../../py/mkenv.mk -FROZEN_DIR = scripts -FROZEN_MPY_DIR = modules +# use FROZEN_MANIFEST for new projects, others are legacy +FROZEN_MANIFEST ?= manifest.py +FROZEN_DIR = +FROZEN_MPY_DIR = # define main target PROG = micropython @@ -177,9 +179,9 @@ SRC_QSTR += $(SRC_C) $(LIB_SRC_C) # SRC_QSTR SRC_QSTR_AUTO_DEPS += -ifneq ($(FROZEN_MPY_DIR),) -# To use frozen bytecode, put your .py files in a subdirectory (eg frozen/) and -# then invoke make with FROZEN_MPY_DIR=frozen (be sure to build from scratch). +ifneq ($(FROZEN_MANIFEST)$(FROZEN_MPY_DIR),) +# To use frozen code create a manifest.py file with a description of files to +# freeze, then invoke make with FROZEN_MANIFEST=manifest.py (be sure to build from scratch). CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool CFLAGS += -DMICROPY_MODULE_FROZEN_MPY CFLAGS += -DMPZ_DIG_SIZE=16 # force 16 bits to work on both 32 and 64 bit archs @@ -215,7 +217,7 @@ fast: # build a minimal interpreter minimal: $(MAKE) COPT="-Os -DNDEBUG" CFLAGS_EXTRA='-DMP_CONFIGFILE=""' \ - BUILD=build-minimal PROG=micropython_minimal FROZEN_DIR= FROZEN_MPY_DIR= \ + BUILD=build-minimal PROG=micropython_minimal FROZEN_MANIFEST= \ MICROPY_PY_BTREE=0 MICROPY_PY_FFI=0 MICROPY_PY_SOCKET=0 MICROPY_PY_THREAD=0 \ MICROPY_PY_TERMIOS=0 MICROPY_PY_USSL=0 \ MICROPY_USE_READLINE=0 @@ -252,7 +254,7 @@ coverage: -Wold-style-definition -Wpointer-arith -Wshadow -Wuninitialized -Wunused-parameter \ -DMICROPY_UNIX_COVERAGE' \ LDFLAGS_EXTRA='-fprofile-arcs -ftest-coverage' \ - FROZEN_DIR=coverage-frzstr FROZEN_MPY_DIR=coverage-frzmpy \ + FROZEN_MANIFEST=manifest_coverage.py \ BUILD=build-coverage PROG=micropython_coverage coverage_test: coverage diff --git a/ports/unix/manifest.py b/ports/unix/manifest.py new file mode 100644 index 0000000000..3f332446d1 --- /dev/null +++ b/ports/unix/manifest.py @@ -0,0 +1,2 @@ +freeze_as_mpy('$(MPY)/tools', 'upip.py') +freeze_as_mpy('$(MPY)/tools', 'upip_utarfile.py', opt=3) diff --git a/ports/unix/manifest_coverage.py b/ports/unix/manifest_coverage.py new file mode 100644 index 0000000000..0c32d08578 --- /dev/null +++ b/ports/unix/manifest_coverage.py @@ -0,0 +1,2 @@ +freeze_as_str('coverage-frzstr') +freeze_as_mpy('coverage-frzmpy') diff --git a/ports/unix/modules/upip.py b/ports/unix/modules/upip.py deleted file mode 120000 index 130eb69016..0000000000 --- a/ports/unix/modules/upip.py +++ /dev/null @@ -1 +0,0 @@ -../../../tools/upip.py \ No newline at end of file diff --git a/ports/unix/modules/upip_utarfile.py b/ports/unix/modules/upip_utarfile.py deleted file mode 120000 index d9653d6a60..0000000000 --- a/ports/unix/modules/upip_utarfile.py +++ /dev/null @@ -1 +0,0 @@ -../../../tools/upip_utarfile.py \ No newline at end of file From 2fd3f2520d88a80c12ac6c31f1e2fb1534f1aa42 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 10 Oct 2019 23:01:29 +1100 Subject: [PATCH 0846/1788] esp8266: Convert to use FROZEN_MANIFEST to specify frozen code. Removes symlinks in modules directory, all frozen code is now specified by manifest.py. --- ports/esp8266/Makefile | 11 ++++++----- ports/esp8266/boards/manifest.py | 4 ++++ ports/esp8266/modules/dht.py | 1 - ports/esp8266/modules/ds18x20.py | 1 - ports/esp8266/modules/onewire.py | 1 - ports/esp8266/modules/upip.py | 1 - ports/esp8266/modules/upip_utarfile.py | 1 - 7 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 ports/esp8266/boards/manifest.py delete mode 120000 ports/esp8266/modules/dht.py delete mode 120000 ports/esp8266/modules/ds18x20.py delete mode 120000 ports/esp8266/modules/onewire.py delete mode 120000 ports/esp8266/modules/upip.py delete mode 120000 ports/esp8266/modules/upip_utarfile.py diff --git a/ports/esp8266/Makefile b/ports/esp8266/Makefile index 030f39fa91..c4ffd4f811 100644 --- a/ports/esp8266/Makefile +++ b/ports/esp8266/Makefile @@ -26,8 +26,9 @@ MICROPY_FATFS ?= 1 MICROPY_PY_BTREE ?= 1 BTREE_DEFS_EXTRA = -DDEFPSIZE=1024 -DMINCACHE=3 -FROZEN_DIR ?= scripts -FROZEN_MPY_DIR ?= modules +FROZEN_MANIFEST ?= boards/manifest.py +FROZEN_DIR ?= +FROZEN_MPY_DIR ?= # include py core make definitions include $(TOP)/py/py.mk @@ -179,9 +180,9 @@ CONFVARS_FILE = $(BUILD)/confvars ifeq ($(wildcard $(CONFVARS_FILE)),) $(shell $(MKDIR) -p $(BUILD)) -$(shell echo $(FROZEN_DIR) $(UART_OS) > $(CONFVARS_FILE)) -else ifneq ($(shell cat $(CONFVARS_FILE)), $(FROZEN_DIR) $(UART_OS)) -$(shell echo $(FROZEN_DIR) $(UART_OS) > $(CONFVARS_FILE)) +$(shell echo $(FROZEN_MANIFEST) $(UART_OS) > $(CONFVARS_FILE)) +else ifneq ($(shell cat $(CONFVARS_FILE)), $(FROZEN_MANIFEST) $(UART_OS)) +$(shell echo $(FROZEN_MANIFEST) $(UART_OS) > $(CONFVARS_FILE)) endif $(BUILD)/uart.o: $(CONFVARS_FILE) diff --git a/ports/esp8266/boards/manifest.py b/ports/esp8266/boards/manifest.py new file mode 100644 index 0000000000..1264a22686 --- /dev/null +++ b/ports/esp8266/boards/manifest.py @@ -0,0 +1,4 @@ +freeze('modules') +freeze('$(MPY)/tools', ('upip.py', 'upip_utarfile.py')) +freeze('$(MPY)/drivers/dht', 'dht.py') +freeze('$(MPY)/drivers/onewire') diff --git a/ports/esp8266/modules/dht.py b/ports/esp8266/modules/dht.py deleted file mode 120000 index 2aa2f5cbfe..0000000000 --- a/ports/esp8266/modules/dht.py +++ /dev/null @@ -1 +0,0 @@ -../../../drivers/dht/dht.py \ No newline at end of file diff --git a/ports/esp8266/modules/ds18x20.py b/ports/esp8266/modules/ds18x20.py deleted file mode 120000 index 1ec92d1c99..0000000000 --- a/ports/esp8266/modules/ds18x20.py +++ /dev/null @@ -1 +0,0 @@ -../../../drivers/onewire/ds18x20.py \ No newline at end of file diff --git a/ports/esp8266/modules/onewire.py b/ports/esp8266/modules/onewire.py deleted file mode 120000 index 33f30e84f1..0000000000 --- a/ports/esp8266/modules/onewire.py +++ /dev/null @@ -1 +0,0 @@ -../../../drivers/onewire/onewire.py \ No newline at end of file diff --git a/ports/esp8266/modules/upip.py b/ports/esp8266/modules/upip.py deleted file mode 120000 index 130eb69016..0000000000 --- a/ports/esp8266/modules/upip.py +++ /dev/null @@ -1 +0,0 @@ -../../../tools/upip.py \ No newline at end of file diff --git a/ports/esp8266/modules/upip_utarfile.py b/ports/esp8266/modules/upip_utarfile.py deleted file mode 120000 index d9653d6a60..0000000000 --- a/ports/esp8266/modules/upip_utarfile.py +++ /dev/null @@ -1 +0,0 @@ -../../../tools/upip_utarfile.py \ No newline at end of file From 287800d6e1dd86f8750c432a166f36ee63cb29cc Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 10 Oct 2019 23:42:20 +1100 Subject: [PATCH 0847/1788] stm32: Convert to use FROZEN_MANIFEST to specify frozen code. All symlinks are removed, frozen files are now referenced via boards/manifest.py. --- ports/stm32/Makefile | 8 ++++---- ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.mk | 2 +- ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk | 2 +- ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.mk | 2 +- ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.mk | 2 +- ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.mk | 2 +- ports/stm32/boards/manifest.py | 3 +++ ports/stm32/modules/dht.py | 1 - ports/stm32/modules/lcd160cr.py | 1 - ports/stm32/modules/lcd160cr_test.py | 1 - ports/stm32/modules/onewire.py | 1 - 11 files changed, 12 insertions(+), 13 deletions(-) create mode 100644 ports/stm32/boards/manifest.py delete mode 120000 ports/stm32/modules/dht.py delete mode 120000 ports/stm32/modules/lcd160cr.py delete mode 120000 ports/stm32/modules/lcd160cr_test.py delete mode 120000 ports/stm32/modules/onewire.py diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 112271fe18..30d4d9b48f 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -18,8 +18,8 @@ include $(BOARD_DIR)/mpconfigboard.mk QSTR_DEFS = qstrdefsport.h $(BUILD)/pins_qstr.h $(BUILD)/modstm_qstr.h QSTR_GLOBAL_DEPENDENCIES = mpconfigboard_common.h $(BOARD_DIR)/mpconfigboard.h -# directory containing scripts to be frozen as bytecode -FROZEN_MPY_DIR ?= modules +# File containing description of content to be frozen into firmware. +FROZEN_MANIFEST ?= boards/manifest.py # include py core make definitions include $(TOP)/py/py.mk @@ -485,13 +485,13 @@ $(TOP)/lib/stm32lib/README.md: $(ECHO) "stm32lib submodule not found, fetching it now..." (cd $(TOP) && git submodule update --init lib/stm32lib) -ifneq ($(FROZEN_DIR),) +ifneq ($(FROZEN_MANIFEST)$(FROZEN_DIR),) # To use frozen source modules, put your .py files in a subdirectory (eg scripts/) # and then invoke make with FROZEN_DIR=scripts (be sure to build from scratch). CFLAGS += -DMICROPY_MODULE_FROZEN_STR endif -ifneq ($(FROZEN_MPY_DIR),) +ifneq ($(FROZEN_MANIFEST)$(FROZEN_MPY_DIR),) # To use frozen bytecode, put your .py files in a subdirectory (eg frozen/) and # then invoke make with FROZEN_MPY_DIR=frozen (be sure to build from scratch). CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool diff --git a/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.mk b/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.mk index 084cf4d309..e2ced61183 100644 --- a/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.mk +++ b/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.mk @@ -5,4 +5,4 @@ AF_FILE = boards/stm32l072_af.csv LD_FILES = boards/stm32l072xz.ld boards/common_basic.ld # Don't include default frozen modules because MCU is tight on flash space -FROZEN_MPY_DIR ?= +FROZEN_MANIFEST ?= diff --git a/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk b/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk index 16cacc089e..d40825ec85 100644 --- a/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk +++ b/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk @@ -6,4 +6,4 @@ TEXT0_ADDR = 0x08000000 TEXT1_ADDR = 0x08020000 # Don't include default frozen modules because MCU is tight on flash space -FROZEN_MPY_DIR ?= +FROZEN_MANIFEST ?= diff --git a/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.mk index 1d66f7e6b6..5efa0d4a5d 100644 --- a/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.mk @@ -4,4 +4,4 @@ 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 ?= +FROZEN_MANIFEST ?= diff --git a/ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.mk index 69601f8602..5afe134ba0 100644 --- a/ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.mk @@ -4,4 +4,4 @@ AF_FILE = boards/stm32l072_af.csv LD_FILES = boards/stm32l072xz.ld boards/common_basic.ld # Don't include default frozen modules because MCU is tight on flash space -FROZEN_MPY_DIR ?= +FROZEN_MANIFEST ?= diff --git a/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.mk index 46697348fe..7c7cd34f0e 100644 --- a/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.mk @@ -5,4 +5,4 @@ LD_FILES = boards/stm32l432.ld boards/common_basic.ld OPENOCD_CONFIG = boards/openocd_stm32l4.cfg # Don't include default frozen modules because MCU is tight on flash space -FROZEN_MPY_DIR ?= +FROZEN_MANIFEST ?= diff --git a/ports/stm32/boards/manifest.py b/ports/stm32/boards/manifest.py new file mode 100644 index 0000000000..99b08cca00 --- /dev/null +++ b/ports/stm32/boards/manifest.py @@ -0,0 +1,3 @@ +freeze('$(MPY)/drivers/dht', 'dht.py') +freeze('$(MPY)/drivers/display', ('lcd160cr.py', 'lcd160cr_test.py')) +freeze('$(MPY)/drivers/onewire', 'onewire.py') diff --git a/ports/stm32/modules/dht.py b/ports/stm32/modules/dht.py deleted file mode 120000 index 2aa2f5cbfe..0000000000 --- a/ports/stm32/modules/dht.py +++ /dev/null @@ -1 +0,0 @@ -../../../drivers/dht/dht.py \ No newline at end of file diff --git a/ports/stm32/modules/lcd160cr.py b/ports/stm32/modules/lcd160cr.py deleted file mode 120000 index 9e63f1d23f..0000000000 --- a/ports/stm32/modules/lcd160cr.py +++ /dev/null @@ -1 +0,0 @@ -../../../drivers/display/lcd160cr.py \ No newline at end of file diff --git a/ports/stm32/modules/lcd160cr_test.py b/ports/stm32/modules/lcd160cr_test.py deleted file mode 120000 index 5f5bcc1281..0000000000 --- a/ports/stm32/modules/lcd160cr_test.py +++ /dev/null @@ -1 +0,0 @@ -../../../drivers/display/lcd160cr_test.py \ No newline at end of file diff --git a/ports/stm32/modules/onewire.py b/ports/stm32/modules/onewire.py deleted file mode 120000 index 33f30e84f1..0000000000 --- a/ports/stm32/modules/onewire.py +++ /dev/null @@ -1 +0,0 @@ -../../../drivers/onewire/onewire.py \ No newline at end of file From 2e90ff7fa8f57edeaaa66aba0a6c3286cdb265d6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 10 Oct 2019 23:49:37 +1100 Subject: [PATCH 0848/1788] qemu-arm: Convert to use FROZEN_MANIFEST to specify frozen code. --- ports/qemu-arm/Makefile | 7 +++---- ports/qemu-arm/Makefile.test | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/ports/qemu-arm/Makefile b/ports/qemu-arm/Makefile index c730c82975..92574d0e11 100644 --- a/ports/qemu-arm/Makefile +++ b/ports/qemu-arm/Makefile @@ -114,11 +114,10 @@ OBJ = $(OBJ_COMMON) $(OBJ_RUN) $(OBJ_TEST) # List of sources for qstr extraction SRC_QSTR += $(SRC_COMMON_C) $(SRC_RUN_C) $(LIB_SRC_C) -ifneq ($(FROZEN_MPY_DIR),) -# To use frozen bytecode, put your .py files in a subdirectory (eg frozen/) and -# then invoke make with FROZEN_MPY_DIR=frozen (be sure to build from scratch). -CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool +ifneq ($(FROZEN_MANIFEST),) +CFLAGS += -DMICROPY_MODULE_FROZEN_STR CFLAGS += -DMICROPY_MODULE_FROZEN_MPY +CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool MPY_CROSS_FLAGS += -march=armv7m endif diff --git a/ports/qemu-arm/Makefile.test b/ports/qemu-arm/Makefile.test index 32ec95a4f3..4204a84f0d 100644 --- a/ports/qemu-arm/Makefile.test +++ b/ports/qemu-arm/Makefile.test @@ -1,6 +1,6 @@ LIB_SRC_C = lib/upytesthelper/upytesthelper.c -FROZEN_MPY_DIR ?= test-frzmpy +FROZEN_MANIFEST ?= "freeze('test-frzmpy')" include Makefile From ce1de1faf082abfcc5469ad3d70b88aaa0060ec3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 10 Oct 2019 23:51:35 +1100 Subject: [PATCH 0849/1788] esp32: Convert to use FROZEN_MANIFEST to specify frozen code. All symlinks are removed. boards/manifest.py is used as a default, and can optionally use boards/manifest_release.py for more scripts. --- ports/esp32/Makefile | 3 +-- ports/esp32/boards/manifest.py | 6 ++++++ ports/esp32/boards/manifest_release.py | 8 ++++++++ ports/esp32/modules/dht.py | 1 - ports/esp32/modules/ds18x20.py | 1 - ports/esp32/modules/ntptime.py | 1 - ports/esp32/modules/onewire.py | 1 - ports/esp32/modules/umqtt/robust.py | 1 - ports/esp32/modules/umqtt/simple.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/modules/webrepl.py | 1 - ports/esp32/modules/webrepl_setup.py | 1 - ports/esp32/modules/websocket_helper.py | 1 - 16 files changed, 15 insertions(+), 15 deletions(-) create mode 100644 ports/esp32/boards/manifest.py create mode 100644 ports/esp32/boards/manifest_release.py delete mode 120000 ports/esp32/modules/dht.py delete mode 120000 ports/esp32/modules/ds18x20.py delete mode 120000 ports/esp32/modules/ntptime.py delete mode 120000 ports/esp32/modules/onewire.py delete mode 120000 ports/esp32/modules/umqtt/robust.py delete mode 120000 ports/esp32/modules/umqtt/simple.py delete mode 120000 ports/esp32/modules/upip.py delete mode 120000 ports/esp32/modules/upip_utarfile.py delete mode 120000 ports/esp32/modules/upysh.py delete mode 120000 ports/esp32/modules/urequests.py delete mode 120000 ports/esp32/modules/webrepl.py delete mode 120000 ports/esp32/modules/webrepl_setup.py delete mode 120000 ports/esp32/modules/websocket_helper.py diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 2a752553e8..37261d17bd 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -32,8 +32,7 @@ MICROPY_SSL_AXTLS = 0 MICROPY_FATFS = 1 MICROPY_PY_BTREE = 1 -#FROZEN_DIR = scripts -FROZEN_MPY_DIR = modules +FROZEN_MANIFEST ?= boards/manifest.py # include py core make definitions include $(TOP)/py/py.mk diff --git a/ports/esp32/boards/manifest.py b/ports/esp32/boards/manifest.py new file mode 100644 index 0000000000..3da8af57f8 --- /dev/null +++ b/ports/esp32/boards/manifest.py @@ -0,0 +1,6 @@ +freeze('modules') +freeze('$(MPY)/tools', ('upip.py', 'upip_utarfile.py')) +freeze('$(MPY)/ports/esp8266/modules', 'ntptime.py') +freeze('$(MPY)/ports/esp8266/modules', ('webrepl.py', 'webrepl_setup.py', 'websocket_helper.py',)) +freeze('$(MPY)/drivers/dht', 'dht.py') +freeze('$(MPY)/drivers/onewire') diff --git a/ports/esp32/boards/manifest_release.py b/ports/esp32/boards/manifest_release.py new file mode 100644 index 0000000000..e56704d023 --- /dev/null +++ b/ports/esp32/boards/manifest_release.py @@ -0,0 +1,8 @@ +include('boards/manifest.py') + +LIB = '../../../micropython-lib' + +freeze(LIB + '/upysh', 'upysh.py') +freeze(LIB + '/urequests', 'urequests.py') +freeze(LIB + '/umqtt.simple', 'umqtt/simple.py') +freeze(LIB + '/umqtt.robust', 'umqtt/robust.py') diff --git a/ports/esp32/modules/dht.py b/ports/esp32/modules/dht.py deleted file mode 120000 index 2aa2f5cbfe..0000000000 --- a/ports/esp32/modules/dht.py +++ /dev/null @@ -1 +0,0 @@ -../../../drivers/dht/dht.py \ No newline at end of file diff --git a/ports/esp32/modules/ds18x20.py b/ports/esp32/modules/ds18x20.py deleted file mode 120000 index 9721929a3f..0000000000 --- a/ports/esp32/modules/ds18x20.py +++ /dev/null @@ -1 +0,0 @@ -../../esp8266/modules/ds18x20.py \ No newline at end of file diff --git a/ports/esp32/modules/ntptime.py b/ports/esp32/modules/ntptime.py deleted file mode 120000 index e90900d5a9..0000000000 --- a/ports/esp32/modules/ntptime.py +++ /dev/null @@ -1 +0,0 @@ -../../esp8266/modules/ntptime.py \ No newline at end of file diff --git a/ports/esp32/modules/onewire.py b/ports/esp32/modules/onewire.py deleted file mode 120000 index 091629488e..0000000000 --- a/ports/esp32/modules/onewire.py +++ /dev/null @@ -1 +0,0 @@ -../../esp8266/modules/onewire.py \ No newline at end of file diff --git a/ports/esp32/modules/umqtt/robust.py b/ports/esp32/modules/umqtt/robust.py deleted file mode 120000 index 6bfbbcf552..0000000000 --- a/ports/esp32/modules/umqtt/robust.py +++ /dev/null @@ -1 +0,0 @@ -../../../../../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 deleted file mode 120000 index 6419a46647..0000000000 --- a/ports/esp32/modules/umqtt/simple.py +++ /dev/null @@ -1 +0,0 @@ -../../../../../micropython-lib/umqtt.simple/umqtt/simple.py \ No newline at end of file diff --git a/ports/esp32/modules/upip.py b/ports/esp32/modules/upip.py deleted file mode 120000 index 130eb69016..0000000000 --- a/ports/esp32/modules/upip.py +++ /dev/null @@ -1 +0,0 @@ -../../../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 deleted file mode 120000 index d9653d6a60..0000000000 --- a/ports/esp32/modules/upip_utarfile.py +++ /dev/null @@ -1 +0,0 @@ -../../../tools/upip_utarfile.py \ No newline at end of file diff --git a/ports/esp32/modules/upysh.py b/ports/esp32/modules/upysh.py deleted file mode 120000 index 12d100c29c..0000000000 --- a/ports/esp32/modules/upysh.py +++ /dev/null @@ -1 +0,0 @@ -../../../../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 deleted file mode 120000 index 76661112e1..0000000000 --- a/ports/esp32/modules/urequests.py +++ /dev/null @@ -1 +0,0 @@ -../../../../micropython-lib/urequests/urequests.py \ No newline at end of file diff --git a/ports/esp32/modules/webrepl.py b/ports/esp32/modules/webrepl.py deleted file mode 120000 index 2a3987a729..0000000000 --- a/ports/esp32/modules/webrepl.py +++ /dev/null @@ -1 +0,0 @@ -../../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 deleted file mode 120000 index 999888bf13..0000000000 --- a/ports/esp32/modules/webrepl_setup.py +++ /dev/null @@ -1 +0,0 @@ -../../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 deleted file mode 120000 index 4bcf3bcb6a..0000000000 --- a/ports/esp32/modules/websocket_helper.py +++ /dev/null @@ -1 +0,0 @@ -../../esp8266/modules/websocket_helper.py \ No newline at end of file From cb2b210d45194f2578189ca5b0ec4c8b8fc96810 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Fri, 11 Oct 2019 22:19:33 +0200 Subject: [PATCH 0850/1788] stm32/adc: Update ADC driver to work with the new H7 HAL. Use NB_TO_CHANNEL to map decimal numbers to channel numbers. And use the correct rank to initialize channels (ADC_REGULAR_RANK_1). --- ports/stm32/adc.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index 11b15cd09a..de4b910cb6 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -165,6 +165,13 @@ #define ADC_SCALE (ADC_SCALE_V / ((1 << ADC_CAL_BITS) - 1)) #define VREFIN_CAL ((uint16_t *)ADC_CAL_ADDRESS) +#ifndef __HAL_ADC_IS_CHANNEL_INTERNAL +#define __HAL_ADC_IS_CHANNEL_INTERNAL(channel) \ + (channel == ADC_CHANNEL_VBAT \ + || channel == ADC_CHANNEL_VREFINT \ + || channel == ADC_CHANNEL_TEMPSENSOR) +#endif + typedef struct _pyb_obj_adc_t { mp_obj_base_t base; mp_obj_t pin_name; @@ -188,8 +195,11 @@ 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(STM32F0) || defined(STM32F4) || defined(STM32F7) || defined(STM32H7) +#elif defined(STM32F0) || defined(STM32F4) || defined(STM32F7) return IS_ADC_CHANNEL(channel); +#elif defined(STM32H7) + return __HAL_ADC_IS_CHANNEL_INTERNAL(channel) + || IS_ADC_CHANNEL(__HAL_ADC_DECIMAL_NB_TO_CHANNEL(channel)); #elif defined(STM32L4) ADC_HandleTypeDef handle; handle.Instance = ADCx; @@ -308,8 +318,16 @@ STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) { STATIC void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel) { ADC_ChannelConfTypeDef sConfig; - sConfig.Channel = channel; + #if defined (STM32H7) + sConfig.Rank = ADC_REGULAR_RANK_1; + if (__HAL_ADC_IS_CHANNEL_INTERNAL(channel) == 0) { + channel = __HAL_ADC_DECIMAL_NB_TO_CHANNEL(channel); + } + #else sConfig.Rank = 1; + #endif + sConfig.Channel = channel; + #if defined(STM32F0) sConfig.SamplingTime = ADC_SAMPLETIME_55CYCLES_5; #elif defined(STM32F4) || defined(STM32F7) From d523a377d17e667f760c2c64dc3a41dafe072ebc Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Fri, 11 Oct 2019 22:27:13 +0200 Subject: [PATCH 0851/1788] stm32/adc: Remove unused macro and channel check, and fix spacing. The call to is_adcx_channel is redundant because the channel is already checked just before calling adc_init_single in adc_make_new. --- ports/stm32/adc.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index de4b910cb6..ace6505a3f 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -63,7 +63,6 @@ #endif #define ADCx_CLK_ENABLE __HAL_RCC_ADC1_CLK_ENABLE -#define ADC_NUM_CHANNELS (19) #if defined(STM32F0) @@ -293,9 +292,6 @@ STATIC void adcx_init_periph(ADC_HandleTypeDef *adch, uint32_t resolution) { } STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) { - if (!is_adcx_channel(adc_obj->channel)) { - return; - } 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. @@ -731,7 +727,7 @@ int adc_get_resolution(ADC_HandleTypeDef *adcHandle) { uint32_t res_reg = ADC_GET_RESOLUTION(adcHandle); switch (res_reg) { - #if !defined(STM32H7) + #if !defined(STM32H7) case ADC_RESOLUTION_6B: return 6; #endif case ADC_RESOLUTION_8B: return 8; From 4cee42d864eaabf40de6809ae76fcf20cd550a62 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Fri, 11 Oct 2019 22:36:58 +0200 Subject: [PATCH 0852/1788] stm32/adc: Use IS_CHANNEL_INTERNAL macro to check for internal channels. --- ports/stm32/adc.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index ace6505a3f..50abbebe15 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -329,9 +329,7 @@ STATIC void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel) #elif defined(STM32F4) || defined(STM32F7) sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES; #elif defined(STM32H7) - if (channel == ADC_CHANNEL_VREFINT - || channel == ADC_CHANNEL_TEMPSENSOR - || channel == ADC_CHANNEL_VBAT) { + if (__HAL_ADC_IS_CHANNEL_INTERNAL(channel)) { sConfig.SamplingTime = ADC_SAMPLETIME_387CYCLES_5; } else { sConfig.SamplingTime = ADC_SAMPLETIME_8CYCLES_5; @@ -341,9 +339,7 @@ STATIC void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel) sConfig.OffsetRightShift = DISABLE; sConfig.OffsetSignedSaturation = DISABLE; #elif defined(STM32L4) - if (channel == ADC_CHANNEL_VREFINT - || channel == ADC_CHANNEL_TEMPSENSOR - || channel == ADC_CHANNEL_VBAT) { + if (__HAL_ADC_IS_CHANNEL_INTERNAL(channel)) { sConfig.SamplingTime = ADC_SAMPLETIME_247CYCLES_5; } else { sConfig.SamplingTime = ADC_SAMPLETIME_12CYCLES_5; From 6e4468a2ab3be4a258d8c50929c553550301b1cb Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Fri, 11 Oct 2019 22:38:50 +0200 Subject: [PATCH 0853/1788] stm32/adc: Fix sampling for internal channels on H7 MCUs. Set to 810 cycles following HAL examples. --- ports/stm32/adc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index 50abbebe15..ca8366652a 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -330,7 +330,7 @@ STATIC void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel) sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES; #elif defined(STM32H7) if (__HAL_ADC_IS_CHANNEL_INTERNAL(channel)) { - sConfig.SamplingTime = ADC_SAMPLETIME_387CYCLES_5; + sConfig.SamplingTime = ADC_SAMPLETIME_810CYCLES_5; } else { sConfig.SamplingTime = ADC_SAMPLETIME_8CYCLES_5; } From d1ed73ca8f5034c1128de1fd995ca15eccb05ad9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 16 Oct 2019 11:23:54 +1100 Subject: [PATCH 0854/1788] docs/library/bluetooth.rst: Fix typo in HR/UART services example. --- docs/library/bluetooth.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/library/bluetooth.rst b/docs/library/bluetooth.rst index 00ced33e5f..e672cef927 100644 --- a/docs/library/bluetooth.rst +++ b/docs/library/bluetooth.rst @@ -214,7 +214,7 @@ writes from a central to a given characteristic, use HR_UUID = bluetooth.UUID(0x180D) HR_CHAR = (bluetooth.UUID(0x2A37), bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,) - HR_SERVICE = (HR_SERVICE, (HR_CHAR,),) + HR_SERVICE = (HR_UUID, (HR_CHAR,),) UART_UUID = bluetooth.UUID('6E400001-B5A3-F393-E0A9-E50E24DCCA9E') UART_TX = (bluetooth.UUID('6E400003-B5A3-F393-E0A9-E50E24DCCA9E'), bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,) UART_RX = (bluetooth.UUID('6E400002-B5A3-F393-E0A9-E50E24DCCA9E'), bluetooth.FLAG_WRITE,) From 5463ab6df6243a63a88f686113e408933956b8eb Mon Sep 17 00:00:00 2001 From: Thiago Paes Date: Thu, 1 Nov 2018 21:47:43 -0300 Subject: [PATCH 0855/1788] docs/esp8266/tutorial: Make http_get sample function self contained. --- docs/esp8266/tutorial/network_tcp.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/esp8266/tutorial/network_tcp.rst b/docs/esp8266/tutorial/network_tcp.rst index 26a2f469ce..852fc82f39 100644 --- a/docs/esp8266/tutorial/network_tcp.rst +++ b/docs/esp8266/tutorial/network_tcp.rst @@ -61,6 +61,7 @@ of the request you need to specify the page to retrieve. Let's define a function that can download and print a URL:: def http_get(url): + import socket _, _, host, path = url.split('/', 3) addr = socket.getaddrinfo(host, 80)[0][-1] s = socket.socket() @@ -74,8 +75,7 @@ Let's define a function that can download and print a URL:: break s.close() -Make sure that you import the socket module before running this function. Then -you can try:: +Then you can try:: >>> http_get('http://micropython.org/ks/test.html') From c0b3419261a7fa373d9d6f07d4bef55d019d52b9 Mon Sep 17 00:00:00 2001 From: Peter Hinch Date: Mon, 5 Nov 2018 07:13:12 +0000 Subject: [PATCH 0856/1788] docs/library: Clarify relation between machine and port-specific mods. --- docs/library/index.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/library/index.rst b/docs/library/index.rst index 7d4bb872cf..dc89766e2d 100644 --- a/docs/library/index.rst +++ b/docs/library/index.rst @@ -116,6 +116,19 @@ the following libraries. uctypes.rst +Port-specific libraries +----------------------- + +In some cases the following port/board-specific libraries have functions or +classes similar to those in the :mod:`machine` library. Where this occurs, the +entry in the port specific library exposes hardware functionality unique to +that platform. + +To write portable code use functions and classes from the :mod:`machine` module. +To access platform-specific hardware use the appropriate library, e.g. +:mod:`pyb` in the case of the Pyboard. + + Libraries specific to the pyboard --------------------------------- From 5a8f392f09e3826ff2a1f4330700198e9c0d42cc Mon Sep 17 00:00:00 2001 From: Mike Causer Date: Wed, 13 Feb 2019 03:20:23 +1100 Subject: [PATCH 0857/1788] docs/esp8266: Add ntptime usage to esp8266 quickref. --- docs/esp8266/quickref.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/esp8266/quickref.rst b/docs/esp8266/quickref.rst index 95ae55b570..a50e3dd6b5 100644 --- a/docs/esp8266/quickref.rst +++ b/docs/esp8266/quickref.rst @@ -243,6 +243,12 @@ See :ref:`machine.RTC ` :: rtc.datetime((2017, 8, 23, 1, 12, 48, 0, 0)) # set a specific date and time rtc.datetime() # get date and time + # synchronize with ntp + # need to be connected to wifi + import ntptime + ntptime.settime() # set the rtc datetime from the remote server + rtc.datetime() # get the date and time in UTC + Deep-sleep mode --------------- From a2c4cb484d6018a65dabd921c509fc12b71a088b Mon Sep 17 00:00:00 2001 From: Mike Causer Date: Wed, 13 Feb 2019 12:29:01 +1100 Subject: [PATCH 0858/1788] docs: Fix spelling in various parts of the docs. --- docs/esp32/quickref.rst | 6 +++--- docs/esp8266/general.rst | 2 +- docs/esp8266/quickref.rst | 2 +- docs/library/network.rst | 2 +- docs/library/uhashlib.rst | 4 ++-- docs/library/uos.rst | 4 ++-- docs/pyboard/tutorial/leds.rst | 2 +- docs/reference/packages.rst | 4 ++-- docs/reference/speed_python.rst | 2 +- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst index dd85b102b2..20e728d1c7 100644 --- a/docs/esp32/quickref.rst +++ b/docs/esp32/quickref.rst @@ -77,7 +77,7 @@ The :mod:`network` module:: wlan.scan() # scan for access points wlan.isconnected() # check if the station is connected to an AP wlan.connect('essid', 'password') # connect to an AP - wlan.config('mac') # get the interface's MAC adddress + wlan.config('mac') # get the interface's MAC address wlan.ifconfig() # get the interface's IP/netmask/gw/DNS addresses ap = network.WLAN(network.AP_IF) # create access-point interface @@ -203,7 +203,7 @@ Use the :ref:`machine.ADC ` class:: adc = ADC(Pin(32)) # create ADC object on ADC pin adc.read() # read value, 0-4095 across voltage range 0.0v - 1.0v - adc.atten(ADC.ATTN_11DB) # set 11dB input attentuation (voltage range roughly 0.0v - 3.6v) + adc.atten(ADC.ATTN_11DB) # set 11dB input attenuation (voltage range roughly 0.0v - 3.6v) adc.width(ADC.WIDTH_9BIT) # set 9 bit return values (returned range 0-511) adc.read() # read value using the newly configured attenuation and width @@ -257,7 +257,7 @@ class:: spi.init(baudrate=200000) # set the baudrate spi.read(10) # read 10 bytes on MISO - spi.read(10, 0xff) # read 10 bytes while outputing 0xff on MOSI + spi.read(10, 0xff) # read 10 bytes while outputting 0xff on MOSI buf = bytearray(50) # create a buffer spi.readinto(buf) # read into the given buffer (reads 50 bytes in this case) diff --git a/docs/esp8266/general.rst b/docs/esp8266/general.rst index 020e21df62..fbe8fe1c3c 100644 --- a/docs/esp8266/general.rst +++ b/docs/esp8266/general.rst @@ -140,7 +140,7 @@ The above may also happen after an application terminates and quits to the REPL for any reason including an exception. Subsequent arrival of data provokes the failure with the above error message repeatedly issued. So, sockets should be closed in any case, regardless whether an application terminates successfully -or by an exeption, for example using try/finally:: +or by an exception, for example using try/finally:: sock = socket(...) try: diff --git a/docs/esp8266/quickref.rst b/docs/esp8266/quickref.rst index a50e3dd6b5..a197665043 100644 --- a/docs/esp8266/quickref.rst +++ b/docs/esp8266/quickref.rst @@ -188,7 +188,7 @@ class:: spi.init(baudrate=200000) # set the baudrate spi.read(10) # read 10 bytes on MISO - spi.read(10, 0xff) # read 10 bytes while outputing 0xff on MOSI + spi.read(10, 0xff) # read 10 bytes while outputting 0xff on MOSI buf = bytearray(50) # create a buffer spi.readinto(buf) # read into the given buffer (reads 50 bytes in this case) diff --git a/docs/library/network.rst b/docs/library/network.rst index 0c5659244c..01e6f61369 100644 --- a/docs/library/network.rst +++ b/docs/library/network.rst @@ -68,7 +68,7 @@ parameter should be `id`. (password) required to access said service. There can be further arbitrary keyword-only parameters, depending on the networking medium type and/or particular device. Parameters can be used to: a) - specify alternative service identifer types; b) provide additional + specify alternative service identifier types; b) provide additional connection parameters. For various medium types, there are different sets of predefined/recommended parameters, among them: diff --git a/docs/library/uhashlib.rst b/docs/library/uhashlib.rst index 50ed658cc1..e1eddd2b71 100644 --- a/docs/library/uhashlib.rst +++ b/docs/library/uhashlib.rst @@ -18,10 +18,10 @@ be implemented: * SHA1 - A previous generation algorithm. Not recommended for new usages, but SHA1 is a part of number of Internet standards and existing applications, so boards targeting network connectivity and - interoperatiability will try to provide this. + interoperability will try to provide this. * MD5 - A legacy algorithm, not considered cryptographically secure. Only - selected boards, targeting interoperatibility with legacy applications, + selected boards, targeting interoperability with legacy applications, will offer this. Constructors diff --git a/docs/library/uos.rst b/docs/library/uos.rst index c7460134b1..58ac83b2b1 100644 --- a/docs/library/uos.rst +++ b/docs/library/uos.rst @@ -94,10 +94,10 @@ Filesystem access * ``f_frsize`` -- fragment size * ``f_blocks`` -- size of fs in f_frsize units * ``f_bfree`` -- number of free blocks - * ``f_bavail`` -- number of free blocks for unpriviliged users + * ``f_bavail`` -- number of free blocks for unprivileged users * ``f_files`` -- number of inodes * ``f_ffree`` -- number of free inodes - * ``f_favail`` -- number of free inodes for unpriviliged users + * ``f_favail`` -- number of free inodes for unprivileged users * ``f_flag`` -- mount flags * ``f_namemax`` -- maximum filename length diff --git a/docs/pyboard/tutorial/leds.rst b/docs/pyboard/tutorial/leds.rst index 6b05f5db05..2b76d17cde 100644 --- a/docs/pyboard/tutorial/leds.rst +++ b/docs/pyboard/tutorial/leds.rst @@ -20,7 +20,7 @@ When you save, the red light on the pyboard should turn on for about a second. T So what does this code do? First we need some terminology. Python is an object-oriented language, almost everything in python is a *class* and when you create an instance of a class you get an *object*. Classes have *methods* associated to them. A method (also called a member function) is used to interact with or control the object. -The first line of code creates an LED object which we have then called led. When we create the object, it takes a single parameter which must be between 1 and 4, corresponding to the 4 LEDs on the board. The pyb.LED class has three important member functions that we will use: on(), off() and toggle(). The other function that we use is pyb.delay() this simply waits for a given time in miliseconds. Once we have created the LED object, the statement while True: creates an infinite loop which toggles the led between on and off and waits for 1 second. +The first line of code creates an LED object which we have then called led. When we create the object, it takes a single parameter which must be between 1 and 4, corresponding to the 4 LEDs on the board. The pyb.LED class has three important member functions that we will use: on(), off() and toggle(). The other function that we use is pyb.delay() this simply waits for a given time in milliseconds. Once we have created the LED object, the statement while True: creates an infinite loop which toggles the led between on and off and waits for 1 second. **Exercise: Try changing the time between toggling the led and turning on a different LED.** diff --git a/docs/reference/packages.rst b/docs/reference/packages.rst index 8be2461c2d..43217493e5 100644 --- a/docs/reference/packages.rst +++ b/docs/reference/packages.rst @@ -39,7 +39,7 @@ 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 +contiguous 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 @@ -132,7 +132,7 @@ Installing to a directory image involves using ``-p`` switch to `upip`:: micropython -m upip install -p install_dir micropython-pystone_lowmem -After this command, the package content (and contents of every depenency +After this command, the package content (and contents of every dependency packages) will be available in the ``install_dir/`` subdirectory. You would need to transfer contents of this directory (without the ``install_dir/`` prefix) to the device, at the suitable location, where diff --git a/docs/reference/speed_python.rst b/docs/reference/speed_python.rst index aa0b54cb50..a6951ed334 100644 --- a/docs/reference/speed_python.rst +++ b/docs/reference/speed_python.rst @@ -214,7 +214,7 @@ There are certain limitations in the current implementation of the native code e * Generators are not supported. * If ``raise`` is used an argument must be supplied. -The trade-off for the improved performance (roughly twices as fast as bytecode) is an +The trade-off for the improved performance (roughly twice as fast as bytecode) is an increase in compiled code size. The Viper code emitter From 615d6b3c66da710d2b43de9ad889eae4fd6bd366 Mon Sep 17 00:00:00 2001 From: Volodymyr Shymanskyy Date: Fri, 15 Feb 2019 20:16:41 +0200 Subject: [PATCH 0859/1788] docs/wipy/tutorial: Link Blynk examples to the official library. --- docs/wipy/tutorial/blynk.rst | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/docs/wipy/tutorial/blynk.rst b/docs/wipy/tutorial/blynk.rst index b5a2f24a47..b34ea17ae1 100644 --- a/docs/wipy/tutorial/blynk.rst +++ b/docs/wipy/tutorial/blynk.rst @@ -1,19 +1,17 @@ Getting started with Blynk and the WiPy --------------------------------------- -Blynk is a platform with iOS and Android apps to control -Arduino, Raspberry Pi and the likes over the Internet. -You can easily build graphic interfaces for all your -projects by simply dragging and dropping widgets. +Blynk provides iOS and Android apps to control any hardware over the Internet +or directly using Bluetooth. You can easily build graphic interfaces for all +your projects by simply dragging and dropping widgets, right on your smartphone. -There are several examples available that work out-of-the-box with -the WiPy. Before anything else, make sure that your WiPy is running +Before anything else, make sure that your WiPy is running the latest software, check :ref:`OTA How-To ` for instructions. -1. Get the `Blynk library `_ and put it in ``/flash/lib/`` via FTP. -2. Get the `Blynk examples `_, edit the network settings, and afterwards - upload them to ``/flash/lib/`` via FTP as well. +1. Get the `Blynk library `_ and put it in ``/flash/lib/`` via FTP. +2. Get the `Blynk example for WiPy `_, edit the network settings, and afterwards + upload it to ``/flash/`` via FTP as well. 3. Follow the instructions on each example to setup the Blynk dashboard on your smartphone or tablet. 4. Give it a try, for instance:: - >>> execfile('01_simple.py') + >>> execfile('sync_virtual.py') From 595438785879552912a1a6832a4f2715f4e82272 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 16 Oct 2019 14:27:01 +1100 Subject: [PATCH 0860/1788] drivers/onewire/ds18x20.py: Add support for DS1822 sensor. DS1822P sensors behave just like the DS18B20 except for the following: - it has a different family code: 0x22 - it has only the GND and DQ pins connected, it uses parasitic power from the data line Contributed by @nebelgrau77. --- drivers/onewire/ds18x20.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/onewire/ds18x20.py b/drivers/onewire/ds18x20.py index bf06094835..272642239e 100644 --- a/drivers/onewire/ds18x20.py +++ b/drivers/onewire/ds18x20.py @@ -13,7 +13,7 @@ class DS18X20: self.buf = bytearray(9) def scan(self): - return [rom for rom in self.ow.scan() if rom[0] == 0x10 or rom[0] == 0x28] + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] def convert_temp(self): self.ow.reset(True) From 4f2c737b0c05cd138f15703d492ad64d39c3fcfd Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 16 Oct 2019 23:12:06 +1100 Subject: [PATCH 0861/1788] stm32/mpu: Save and restore the IRQ state when configuring MPU. In case IRQs are already disabled during the MPU configuration. Fixes issue #5152. --- ports/stm32/eth.c | 4 ++-- ports/stm32/mpu.h | 8 ++++---- ports/stm32/qspi.c | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ports/stm32/eth.c b/ports/stm32/eth.c index 9633d32b28..756bb6dd64 100644 --- a/ports/stm32/eth.c +++ b/ports/stm32/eth.c @@ -153,9 +153,9 @@ void eth_set_trace(eth_t *self, uint32_t value) { STATIC int eth_mac_init(eth_t *self) { // Configure MPU - mpu_config_start(); + uint32_t irq_state = mpu_config_start(); mpu_config_region(MPU_REGION_ETH, (uint32_t)ð_dma, MPU_CONFIG_ETH(MPU_REGION_SIZE_16KB)); - mpu_config_end(); + mpu_config_end(irq_state); // Configure GPIO mp_hal_pin_config_alt_static(MICROPY_HW_ETH_MDC, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_MDC); diff --git a/ports/stm32/mpu.h b/ports/stm32/mpu.h index 1efe93a68b..74ba81496f 100644 --- a/ports/stm32/mpu.h +++ b/ports/stm32/mpu.h @@ -78,8 +78,8 @@ static inline void mpu_init(void) { __ISB(); } -static inline void mpu_config_start(void) { - __disable_irq(); +static inline uint32_t mpu_config_start(void) { + return disable_irq(); } static inline void mpu_config_region(uint32_t region, uint32_t base_addr, uint32_t attr_size) { @@ -88,11 +88,11 @@ static inline void mpu_config_region(uint32_t region, uint32_t base_addr, uint32 MPU->RASR = attr_size; } -static inline void mpu_config_end(void) { +static inline void mpu_config_end(uint32_t irq_state) { __ISB(); __DSB(); __DMB(); - __enable_irq(); + enable_irq(irq_state); } #else diff --git a/ports/stm32/qspi.c b/ports/stm32/qspi.c index ec744bfb27..30ee2c9ea7 100644 --- a/ports/stm32/qspi.c +++ b/ports/stm32/qspi.c @@ -55,9 +55,9 @@ static inline void qspi_mpu_disable_all(void) { // Configure MPU to disable access to entire QSPI region, to prevent CPU // speculative execution from accessing this region and modifying QSPI registers. - mpu_config_start(); + uint32_t irq_state = mpu_config_start(); mpu_config_region(MPU_REGION_QSPI1, QSPI_MAP_ADDR, MPU_CONFIG_DISABLE(0x00, MPU_REGION_SIZE_256MB)); - mpu_config_end(); + mpu_config_end(irq_state); } static inline void qspi_mpu_enable_mapped(void) { @@ -67,11 +67,11 @@ static inline void qspi_mpu_enable_mapped(void) { // to everything except the valid address space, using holes in the bottom // of the regions and nesting them. // At the moment this is hard-coded to 2MiB of QSPI address space. - mpu_config_start(); + uint32_t irq_state = mpu_config_start(); mpu_config_region(MPU_REGION_QSPI1, QSPI_MAP_ADDR, MPU_CONFIG_DISABLE(0x01, MPU_REGION_SIZE_256MB)); mpu_config_region(MPU_REGION_QSPI2, QSPI_MAP_ADDR, MPU_CONFIG_DISABLE(0x0f, MPU_REGION_SIZE_32MB)); mpu_config_region(MPU_REGION_QSPI3, QSPI_MAP_ADDR, MPU_CONFIG_DISABLE(0x01, MPU_REGION_SIZE_16MB)); - mpu_config_end(); + mpu_config_end(irq_state); } void qspi_init(void) { From 3105207afff2ec0b22ecbdea756be5bc5006daff Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 15 Oct 2019 22:42:18 +1100 Subject: [PATCH 0862/1788] stm32/accel: Rename MMA I2C macro constants to make it generic. --- ports/stm32/accel.c | 52 ++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/ports/stm32/accel.c b/ports/stm32/accel.c index 73ddcf8cfa..b4916b5059 100644 --- a/ports/stm32/accel.c +++ b/ports/stm32/accel.c @@ -48,13 +48,13 @@ #define I2C_TIMEOUT_MS (50) -#define MMA_ADDR (76) -#define MMA_REG_X (0) -#define MMA_REG_Y (1) -#define MMA_REG_Z (2) -#define MMA_REG_TILT (3) -#define MMA_REG_MODE (7) -#define MMA_AXIS_SIGNED_VALUE(i) (((i) & 0x3f) | ((i) & 0x20 ? (~0x1f) : 0)) +#define ACCEL_ADDR (76) +#define ACCEL_REG_X (0) +#define ACCEL_REG_Y (1) +#define ACCEL_REG_Z (2) +#define ACCEL_REG_TILT (3) +#define ACCEL_REG_MODE (7) +#define ACCEL_AXIS_SIGNED_VALUE(i) (((i) & 0x3f) | ((i) & 0x20 ? (~0x1f) : 0)) void accel_init(void) { // PB5 is connected to AVDD; pull high to enable MMA accel device @@ -74,7 +74,7 @@ STATIC void accel_start(void) { int ret; for (int i = 0; i < 4; i++) { - ret = i2c_writeto(I2C1, MMA_ADDR, NULL, 0, true); + ret = i2c_writeto(I2C1, ACCEL_ADDR, NULL, 0, true); if (ret == 0) { break; } @@ -85,8 +85,8 @@ STATIC void accel_start(void) { } // set MMA to active mode - uint8_t data[2] = {MMA_REG_MODE, 1}; // active mode - i2c_writeto(I2C1, MMA_ADDR, data, 2, true); + uint8_t data[2] = {ACCEL_REG_MODE, 1}; // active mode + i2c_writeto(I2C1, ACCEL_ADDR, data, 2, true); // wait for MMA to become active mp_hal_delay_ms(30); @@ -129,38 +129,38 @@ 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] = { 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])); + i2c_writeto(I2C1, ACCEL_ADDR, data, 1, false); + i2c_readfrom(I2C1, ACCEL_ADDR, data, 1, true); + return mp_obj_new_int(ACCEL_AXIS_SIGNED_VALUE(data[0])); } /// \method x() /// Get the x-axis value. STATIC mp_obj_t pyb_accel_x(mp_obj_t self_in) { - return read_axis(MMA_REG_X); + return read_axis(ACCEL_REG_X); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_x_obj, pyb_accel_x); /// \method y() /// Get the y-axis value. STATIC mp_obj_t pyb_accel_y(mp_obj_t self_in) { - return read_axis(MMA_REG_Y); + return read_axis(ACCEL_REG_Y); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_y_obj, pyb_accel_y); /// \method z() /// Get the z-axis value. STATIC mp_obj_t pyb_accel_z(mp_obj_t self_in) { - return read_axis(MMA_REG_Z); + return read_axis(ACCEL_REG_Z); } 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] = { MMA_REG_TILT }; - i2c_writeto(I2C1, MMA_ADDR, data, 1, false); - i2c_readfrom(I2C1, MMA_ADDR, data, 1, true); + uint8_t data[1] = { ACCEL_REG_TILT }; + i2c_writeto(I2C1, ACCEL_ADDR, data, 1, false); + i2c_readfrom(I2C1, ACCEL_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); @@ -172,13 +172,13 @@ 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] = { MMA_REG_X }; - i2c_writeto(I2C1, MMA_ADDR, data, 1, false); - i2c_readfrom(I2C1, MMA_ADDR, data, 3, true); + uint8_t data[NUM_AXIS] = { ACCEL_REG_X }; + i2c_writeto(I2C1, ACCEL_ADDR, data, 1, false); + i2c_readfrom(I2C1, ACCEL_ADDR, data, 3, true); mp_obj_t tuple[NUM_AXIS]; for (int i = 0; i < NUM_AXIS; i++) { - self->buf[NUM_AXIS * (FILT_DEPTH - 1) + i] = MMA_AXIS_SIGNED_VALUE(data[i]); + self->buf[NUM_AXIS * (FILT_DEPTH - 1) + i] = ACCEL_AXIS_SIGNED_VALUE(data[i]); int32_t val = 0; for (int j = 0; j < FILT_DEPTH; j++) { val += self->buf[i + NUM_AXIS * j]; @@ -192,15 +192,15 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_filtered_xyz_obj, pyb_accel_filtered_ STATIC mp_obj_t pyb_accel_read(mp_obj_t self_in, mp_obj_t reg) { 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); + i2c_writeto(I2C1, ACCEL_ADDR, data, 1, false); + i2c_writeto(I2C1, ACCEL_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[2] = { mp_obj_get_int(reg), mp_obj_get_int(val) }; - i2c_writeto(I2C1, MMA_ADDR, data, 2, true); + i2c_writeto(I2C1, ACCEL_ADDR, data, 2, true); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_3(pyb_accel_write_obj, pyb_accel_write); From 28062b510835655b26fc387db7e9db770621586d Mon Sep 17 00:00:00 2001 From: "Frederic.Pierson" Date: Sat, 12 Oct 2019 12:38:23 +0200 Subject: [PATCH 0863/1788] stm32/accel: Add support for KXTJ3. --- ports/stm32/accel.c | 76 ++++++++++++++++++++++++++++++++++++++++---- ports/stm32/modpyb.c | 2 +- 2 files changed, 70 insertions(+), 8 deletions(-) diff --git a/ports/stm32/accel.c b/ports/stm32/accel.c index b4916b5059..634ed0a752 100644 --- a/ports/stm32/accel.c +++ b/ports/stm32/accel.c @@ -33,21 +33,30 @@ #include "i2c.h" #include "accel.h" -#if MICROPY_HW_HAS_MMA7660 +#if MICROPY_HW_HAS_MMA7660 || MICROPY_HW_HAS_KXTJ3 /// \moduleref pyb /// \class Accel - accelerometer control /// -/// Accel is an object that controls the accelerometer. Example usage: +/// Accel is an object that controls the MMA7660 or the KXTJ3 accelerometer +/// depending on one/two constant in mpconfigboard.h file of board project : +/// #define MICROPY_HW_HAS_MMA7660 (1) +/// #define MICROPY_HW_HAS_KXTJ3 (0) // not mandatory if equal to 0 +/// +/// Example usage: /// /// accel = pyb.Accel() /// for i in range(10): /// print(accel.x(), accel.y(), accel.z()) /// -/// Raw values are between -32 and 31. +/// Raw values are between -32 and 31 for -/+ 1.5G acceleration for MMA7660. +/// Raw values are between -128 and 127 for -/+ 8G acceleration for KXTJ3. + #define I2C_TIMEOUT_MS (50) +#if MICROPY_HW_HAS_MMA7660 + #define ACCEL_ADDR (76) #define ACCEL_REG_X (0) #define ACCEL_REG_Y (1) @@ -56,16 +65,36 @@ #define ACCEL_REG_MODE (7) #define ACCEL_AXIS_SIGNED_VALUE(i) (((i) & 0x3f) | ((i) & 0x20 ? (~0x1f) : 0)) +#elif MICROPY_HW_HAS_KXTJ3 + +#define ACCEL_ADDR (0x0f) +#define ACCEL_REG_DCST_RESP (0x0c) +#define ACCEL_REG_WHO_AM_I (0x0f) +#define ACCEL_REG_X (0x07) // XOUT_H +#define ACCEL_REG_Y (0x09) // YOUT_H +#define ACCEL_REG_Z (0x0B) // ZOUT_H +#define ACCEL_REG_CTRL_REG1 (0x1B) +#define ACCEL_REG_CTRL_REG2 (0x1d) +#define ACCEL_REG_CTRL_REG2 (0x1d) +#define ACCEL_REG_DATA_CTRL_REG (0x21) +#define ACCEL_AXIS_SIGNED_VALUE(i) (((i) & 0x7f) | ((i) & 0x80 ? (~0x7f) : 0)) + +#endif + void accel_init(void) { + #if MICROPY_HW_HAS_MMA7660 // 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); + #endif } STATIC void accel_start(void) { // start the I2C bus in master mode i2c_init(I2C1, MICROPY_HW_I2C1_SCL, MICROPY_HW_I2C1_SDA, 400000, I2C_TIMEOUT_MS); + #if MICROPY_HW_HAS_MMA7660 + // turn off AVDD, wait 30ms, turn on AVDD, wait 30ms again mp_hal_pin_low(MICROPY_HW_MMA_AVDD_PIN); // turn off mp_hal_delay_ms(30); @@ -90,6 +119,27 @@ STATIC void accel_start(void) { // wait for MMA to become active mp_hal_delay_ms(30); + + #elif MICROPY_HW_HAS_KXTJ3 + + // readout WHO_AM_I register to check KXTJ3 device presence + uint8_t data[2] = { ACCEL_REG_WHO_AM_I }; + i2c_writeto(I2C1, ACCEL_ADDR, data, 1, false); + i2c_readfrom(I2C1, ACCEL_ADDR, data, 1, true); + if (data[0] != 0x35) { + mp_raise_msg(&mp_type_OSError, "accelerometer not found"); + } + + // set operating mode (default: 8 bits, range +/-8G) + data[0] = ACCEL_REG_CTRL_REG1; + data[1] = 0x90; + i2c_writeto(I2C1, ACCEL_ADDR, data, 2, true); + // set dat output rates to 200Hz (LPF roll-over 10ms), idd=35uA + data[0] = ACCEL_REG_DATA_CTRL_REG; + data[1] = 0x04; + i2c_writeto(I2C1, ACCEL_ADDR, data, 2, true); + + #endif } /******************************************************************************/ @@ -158,10 +208,15 @@ 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) { + #if MICROPY_HW_HAS_MMA7660 uint8_t data[1] = { ACCEL_REG_TILT }; i2c_writeto(I2C1, ACCEL_ADDR, data, 1, false); i2c_readfrom(I2C1, ACCEL_ADDR, data, 1, true); return mp_obj_new_int(data[0]); + #elif MICROPY_HW_HAS_KXTJ3 + /// No tilt like register with KXTJ3 accelerometer + return 0; + #endif } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_tilt_obj, pyb_accel_tilt); @@ -172,13 +227,20 @@ 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] = { ACCEL_REG_X }; + #if MICROPY_HW_HAS_MMA7660 + const size_t DATA_SIZE = NUM_AXIS; + const size_t DATA_STRIDE = 1; + #elif MICROPY_HW_HAS_KXTJ3 + const size_t DATA_SIZE = 5; + const size_t DATA_STRIDE = 2; + #endif + uint8_t data[DATA_SIZE]; data[0] = ACCEL_REG_X; i2c_writeto(I2C1, ACCEL_ADDR, data, 1, false); - i2c_readfrom(I2C1, ACCEL_ADDR, data, 3, true); + i2c_readfrom(I2C1, ACCEL_ADDR, data, DATA_SIZE, true); mp_obj_t tuple[NUM_AXIS]; for (int i = 0; i < NUM_AXIS; i++) { - self->buf[NUM_AXIS * (FILT_DEPTH - 1) + i] = ACCEL_AXIS_SIGNED_VALUE(data[i]); + self->buf[NUM_AXIS * (FILT_DEPTH - 1) + i] = ACCEL_AXIS_SIGNED_VALUE(data[i * DATA_STRIDE]); int32_t val = 0; for (int j = 0; j < FILT_DEPTH; j++) { val += self->buf[i + NUM_AXIS * j]; @@ -225,4 +287,4 @@ const mp_obj_type_t pyb_accel_type = { .locals_dict = (mp_obj_dict_t*)&pyb_accel_locals_dict, }; -#endif // MICROPY_HW_HAS_MMA7660 +#endif // MICROPY_HW_HAS_MMA7660 || MICROPY_HW_HAS_KXTJ3 diff --git a/ports/stm32/modpyb.c b/ports/stm32/modpyb.c index 1a1f567a5f..71d7849233 100644 --- a/ports/stm32/modpyb.c +++ b/ports/stm32/modpyb.c @@ -248,7 +248,7 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&pyb_dac_type) }, #endif -#if MICROPY_HW_HAS_MMA7660 +#if MICROPY_HW_HAS_MMA7660 || MICROPY_HW_HAS_KXTJ3 { MP_ROM_QSTR(MP_QSTR_Accel), MP_ROM_PTR(&pyb_accel_type) }, #endif From 925f244ab39d52901b402695a9a8b0bfce6415f7 Mon Sep 17 00:00:00 2001 From: "Frederic.Pierson" Date: Thu, 19 Sep 2019 18:14:55 +0200 Subject: [PATCH 0864/1788] stm32/boards: Add NADHAT_PYB405 board. --- .../boards/NADHAT_PYBF405/mpconfigboard.h | 105 ++++++++++++++++++ .../boards/NADHAT_PYBF405/mpconfigboard.mk | 13 +++ ports/stm32/boards/NADHAT_PYBF405/pins.csv | 58 ++++++++++ .../NADHAT_PYBF405/stm32f4xx_hal_conf.h | 19 ++++ 4 files changed, 195 insertions(+) create mode 100644 ports/stm32/boards/NADHAT_PYBF405/mpconfigboard.h create mode 100644 ports/stm32/boards/NADHAT_PYBF405/mpconfigboard.mk create mode 100644 ports/stm32/boards/NADHAT_PYBF405/pins.csv create mode 100644 ports/stm32/boards/NADHAT_PYBF405/stm32f4xx_hal_conf.h diff --git a/ports/stm32/boards/NADHAT_PYBF405/mpconfigboard.h b/ports/stm32/boards/NADHAT_PYBF405/mpconfigboard.h new file mode 100644 index 0000000000..c6f1a7bc6e --- /dev/null +++ b/ports/stm32/boards/NADHAT_PYBF405/mpconfigboard.h @@ -0,0 +1,105 @@ +#define MICROPY_HW_BOARD_NAME "NADHAT_PYBF405" +#define MICROPY_HW_MCU_NAME "STM32F405RG" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_HAS_KXTJ3 (1) +#define MICROPY_HW_HAS_LCD (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_SERVO (1) +#define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_ENABLE_SDCARD (1) + +// HSE is 16MHz +#define MICROPY_HW_CLK_PLLM (16) +#define MICROPY_HW_CLK_PLLN (336) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (7) +#define MICROPY_HW_CLK_LAST_FREQ (1) + +// The board has a 32kHz crystal for the RTC +#define MICROPY_HW_RTC_USE_LSE (1) +#define MICROPY_HW_RTC_USE_US (0) +#define MICROPY_HW_RTC_USE_CALOUT (1) + +// UART config +#define MICROPY_HW_UART1_NAME "XB" +#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) +#define MICROPY_HW_UART2_RTS (pin_A1) +#define MICROPY_HW_UART2_CTS (pin_A0) +#define MICROPY_HW_UART3_NAME "YB" +#define MICROPY_HW_UART3_TX (pin_B10) +#define MICROPY_HW_UART3_RX (pin_B11) +#define MICROPY_HW_UART3_RTS (pin_B14) +#define MICROPY_HW_UART3_CTS (pin_B13) +#define MICROPY_HW_UART4_NAME "XA" +#define MICROPY_HW_UART4_TX (pin_A0) +#define MICROPY_HW_UART4_RX (pin_A1) +#define MICROPY_HW_UART6_NAME "YA" +#define MICROPY_HW_UART6_TX (pin_C6) +#define MICROPY_HW_UART6_RX (pin_C7) + +// I2C buses +#define MICROPY_HW_I2C1_NAME "X" +#define MICROPY_HW_I2C1_SCL (pin_B6) +#define MICROPY_HW_I2C1_SDA (pin_B7) +#define MICROPY_HW_I2C2_NAME "Y" +#define MICROPY_HW_I2C2_SCL (pin_B10) +#define MICROPY_HW_I2C2_SDA (pin_B11) + +// SPI buses +#define MICROPY_HW_SPI1_NAME "X" +#define MICROPY_HW_SPI1_NSS (pin_A4) // X5 +#define MICROPY_HW_SPI1_SCK (pin_A5) // X6 +#define MICROPY_HW_SPI1_MISO (pin_A6) // X7 +#define MICROPY_HW_SPI1_MOSI (pin_A7) // X8 +#define MICROPY_HW_SPI2_NAME "Y" +#define MICROPY_HW_SPI2_NSS (pin_B12) // Y5 +#define MICROPY_HW_SPI2_SCK (pin_B13) // Y6 +#define MICROPY_HW_SPI2_MISO (pin_B14) // Y7 +#define MICROPY_HW_SPI2_MOSI (pin_B15) // Y8 + +// CAN buses +#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) +#define MICROPY_HW_USRSW_PULL (GPIO_PULLUP) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_FALLING) +#define MICROPY_HW_USRSW_PRESSED (0) + +// The board has 4 LEDs +#define MICROPY_HW_LED1 (pin_A13) // red +#define MICROPY_HW_LED2 (pin_A14) // green +#define MICROPY_HW_LED3 (pin_A15) // yellow +#define MICROPY_HW_LED4 (pin_B4) // blue +#define MICROPY_HW_LED3_PWM { TIM2, 2, TIM_CHANNEL_1, GPIO_AF1_TIM2 } +#define MICROPY_HW_LED4_PWM { TIM3, 3, TIM_CHANNEL_1, GPIO_AF2_TIM3 } +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// SD card detect switch +#define MICROPY_HW_SDCARD_DETECT_PIN (pin_A8) +#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP) +#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) + +// Bootloader configuration (only needed if Mboot is used) +#define MBOOT_I2C_PERIPH_ID 1 +#define MBOOT_I2C_SCL (pin_B8) +#define MBOOT_I2C_SDA (pin_B9) +#define MBOOT_I2C_ALTFUNC (4) diff --git a/ports/stm32/boards/NADHAT_PYBF405/mpconfigboard.mk b/ports/stm32/boards/NADHAT_PYBF405/mpconfigboard.mk new file mode 100644 index 0000000000..a4430cc1df --- /dev/null +++ b/ports/stm32/boards/NADHAT_PYBF405/mpconfigboard.mk @@ -0,0 +1,13 @@ +MCU_SERIES = f4 +CMSIS_MCU = STM32F405xx +AF_FILE = boards/stm32f405_af.csv +ifeq ($(USE_MBOOT),1) +# When using Mboot all the text goes together after the filesystem +LD_FILES = boards/stm32f405.ld boards/common_blifs.ld +TEXT0_ADDR = 0x08020000 +else +# When not using Mboot the ISR text goes first, then the rest after the filesystem +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 +endif diff --git a/ports/stm32/boards/NADHAT_PYBF405/pins.csv b/ports/stm32/boards/NADHAT_PYBF405/pins.csv new file mode 100644 index 0000000000..0a030e985c --- /dev/null +++ b/ports/stm32/boards/NADHAT_PYBF405/pins.csv @@ -0,0 +1,58 @@ +X1,PA0 +X2,PA1 +X3,PA2 +X4,PA3 +X5,PA4 +X6,PA5 +X7,PA6 +X8,PA7 +X9,PB6 +X10,PB7 +X11,PC4 +X12,PC5 +X13,Reset +X14,GND +X15,3.3V +X16,VIN +X17,PB3 +X18,PC13 +X19,PC0 +X20,PC1 +X21,PC2 +X22,PC3 +X23,A3.3V +X24,AGND +Y1,PC6 +Y2,PC7 +Y3,PB8 +Y4,PB9 +Y5,PB12 +Y6,PB13 +Y7,PB14 +Y8,PB15 +Y9,PB10 +Y10,PB11 +Y11,PB0 +Y12,PB1 +Y13,PB2 +Y14,GND +Y15,3.3V +Y16,VIN +SW,PB3 +LED_RED,PA13 +LED_GREEN,PA14 +LED_YELLOW,PA15 +LED_BLUE,PB4 +NC,PB5 +SD_D0,PC8 +SD_D1,PC9 +SD_D2,PC10 +SD_D3,PC11 +SD_CMD,PD2 +SD_CK,PC12 +SD,PA8 +SD_SW,PA8 +USB_VBUS,PA9 +USB_ID,PA10 +USB_DM,PA11 +USB_DP,PA12 diff --git a/ports/stm32/boards/NADHAT_PYBF405/stm32f4xx_hal_conf.h b/ports/stm32/boards/NADHAT_PYBF405/stm32f4xx_hal_conf.h new file mode 100644 index 0000000000..7d6344f0a2 --- /dev/null +++ b/ports/stm32/boards/NADHAT_PYBF405/stm32f4xx_hal_conf.h @@ -0,0 +1,19 @@ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H + +#include "boards/stm32f4xx_hal_conf_base.h" + +// Oscillator values in Hz +#define HSE_VALUE (16000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) + +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) + +#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H From 69b238ec63b808429b1495516a62fd56a9faf764 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 18 Oct 2019 11:53:34 +1100 Subject: [PATCH 0865/1788] stm32/accel: Fix Accel.read() method so it does read a byte. This bug was introduced in a0f7b4c678829bf252df58f0153351a44bd95059 --- ports/stm32/accel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/accel.c b/ports/stm32/accel.c index 634ed0a752..eb55b5d012 100644 --- a/ports/stm32/accel.c +++ b/ports/stm32/accel.c @@ -255,7 +255,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_filtered_xyz_obj, pyb_accel_filtered_ STATIC mp_obj_t pyb_accel_read(mp_obj_t self_in, mp_obj_t reg) { uint8_t data[1] = { mp_obj_get_int(reg) }; i2c_writeto(I2C1, ACCEL_ADDR, data, 1, false); - i2c_writeto(I2C1, ACCEL_ADDR, data, 1, true); + i2c_readfrom(I2C1, ACCEL_ADDR, data, 1, true); return mp_obj_new_int(data[0]); } MP_DEFINE_CONST_FUN_OBJ_2(pyb_accel_read_obj, pyb_accel_read); From 7a7ee16ccf51d4218c17628e745228316f0151f0 Mon Sep 17 00:00:00 2001 From: Jeremy Herbert Date: Thu, 10 Oct 2019 05:11:01 -0700 Subject: [PATCH 0866/1788] esp32/machine_uart: Add ability to invert UART pins. --- ports/esp32/machine_uart.c | 47 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/ports/esp32/machine_uart.c b/ports/esp32/machine_uart.c index 38cc1a8a9a..352ef32a78 100644 --- a/ports/esp32/machine_uart.c +++ b/ports/esp32/machine_uart.c @@ -50,6 +50,7 @@ typedef struct _machine_uart_obj_t { uint16_t rxbuf; uint16_t timeout; // timeout waiting for first char (in ms) uint16_t timeout_char; // timeout waiting between chars (in ms) + uint32_t invert; // lines to invert } machine_uart_obj_t; STATIC const char *_parity_name[] = {"None", "1", "0"}; @@ -61,13 +62,42 @@ STATIC void machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_pri 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, txbuf=%u, rxbuf=%u, timeout=%u, timeout_char=%u)", + mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, tx=%d, rx=%d, rts=%d, cts=%d, txbuf=%u, rxbuf=%u, 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->txbuf, self->rxbuf, self->timeout, self->timeout_char); + if (self->invert) { + mp_printf(print, ", invert="); + uint32_t invert_mask = self->invert; + if (invert_mask & UART_INVERSE_TXD) { + mp_printf(print, "INV_TX"); + invert_mask &= ~UART_INVERSE_TXD; + if (invert_mask) { + mp_printf(print, "|"); + } + } + if (invert_mask & UART_INVERSE_RXD) { + mp_printf(print, "INV_RX"); + invert_mask &= ~UART_INVERSE_RXD; + if (invert_mask) { + mp_printf(print, "|"); + } + } + if (invert_mask & UART_INVERSE_RTS) { + mp_printf(print, "INV_RTS"); + invert_mask &= ~UART_INVERSE_RTS; + if (invert_mask) { + mp_printf(print, "|"); + } + } + if (invert_mask & UART_INVERSE_CTS) { + mp_printf(print, "INV_CTS"); + } + } + mp_printf(print, ")"); } 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_txbuf, ARG_rxbuf, ARG_timeout, ARG_timeout_char }; + enum { ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_tx, ARG_rx, ARG_rts, ARG_cts, ARG_txbuf, ARG_rxbuf, ARG_timeout, ARG_timeout_char, ARG_invert }; 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} }, @@ -81,6 +111,7 @@ STATIC void machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, co { MP_QSTR_rxbuf, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, { 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_QSTR_invert, 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); @@ -205,6 +236,13 @@ STATIC void machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, co if (self->timeout_char < min_timeout_char) { self->timeout_char = min_timeout_char; } + + // set line inversion + if (args[ARG_invert].u_int & ~UART_LINE_INV_MASK) { + mp_raise_ValueError("invalid inversion mask"); + } + self->invert = args[ARG_invert].u_int; + uart_set_line_inverse(self->uart_num, self->invert); } STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { @@ -341,6 +379,11 @@ STATIC const mp_rom_map_elem_t machine_uart_locals_dict_table[] = { { 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_sendbreak), MP_ROM_PTR(&machine_uart_sendbreak_obj) }, + + { MP_ROM_QSTR(MP_QSTR_INV_TX), MP_ROM_INT(UART_INVERSE_TXD) }, + { MP_ROM_QSTR(MP_QSTR_INV_RX), MP_ROM_INT(UART_INVERSE_RXD) }, + { MP_ROM_QSTR(MP_QSTR_INV_RTS), MP_ROM_INT(UART_INVERSE_RTS) }, + { MP_ROM_QSTR(MP_QSTR_INV_CTS), MP_ROM_INT(UART_INVERSE_CTS) }, }; STATIC MP_DEFINE_CONST_DICT(machine_uart_locals_dict, machine_uart_locals_dict_table); From ebf8332104c1c6fbd01b521a713e49d040c62920 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Wed, 16 Oct 2019 16:56:29 +1100 Subject: [PATCH 0867/1788] extmod/re1.5: Support escaping within RE classes. Fixes issues #3178 and #5220. Tests are added, including all the cases mentioned in both bugs. --- extmod/re1.5/compilecode.c | 3 +++ tests/extmod/ure1.py | 20 ++++++++++++++++++++ tests/extmod/ure_error.py | 1 + 3 files changed, 24 insertions(+) diff --git a/extmod/re1.5/compilecode.c b/extmod/re1.5/compilecode.c index a685a508a0..3f54b3993f 100644 --- a/extmod/re1.5/compilecode.c +++ b/extmod/re1.5/compilecode.c @@ -53,6 +53,9 @@ static const char *_compilecode(const char *re, ByteProg *prog, int sizecode) PC++; // Skip # of pair byte prog->len++; for (cnt = 0; *re != ']'; re++, cnt++) { + if (*re == '\\') { + ++re; + } if (!*re) return NULL; EMIT(PC++, *re); if (re[1] == '-' && re[2] != ']') { diff --git a/tests/extmod/ure1.py b/tests/extmod/ure1.py index 54471ed4f9..ae9ff34703 100644 --- a/tests/extmod/ure1.py +++ b/tests/extmod/ure1.py @@ -88,3 +88,23 @@ except: # bytes objects m = re.match(rb'a+?', b'ab'); print(m.group(0)) +print("===") + +# escaping +m = re.match(r'a\.c', 'a.c'); print(m.group(0) if m else '') +m = re.match(r'a\.b', 'abc'); print(m is None) +m = re.match(r'a\.b', 'a\\bc'); print(m is None) +m = re.match(r'[a\-z]', 'abc'); print(m.group(0)) +m = re.match(r'[.\]]*', '.].]a'); print(m.group(0)) +m = re.match(r'[.\]+]*', '.]+.]a'); print(m.group(0)) +m = re.match(r'[a-f0-9x\-yz]*', 'abxcd1-23'); print(m.group(0)) +m = re.match(r'[a\\b]*', 'a\\aa\\bb\\bbab'); print(m.group(0)) +m = re.search(r'[a\-z]', '-'); print(m.group(0)) +m = re.search(r'[a\-z]', 'f'); print(m is None) +m = re.search(r'[a\]z]', 'a'); print(m.group(0)) +print(re.compile(r'[-a]').split('foo-bar')) +print(re.compile(r'[a-]').split('foo-bar')) +print(re.compile(r'[ax\-]').split('foo-bar')) +print(re.compile(r'[a\-x]').split('foo-bar')) +print(re.compile(r'[\-ax]').split('foo-bar')) +print("===") diff --git a/tests/extmod/ure_error.py b/tests/extmod/ure_error.py index f52f735c7f..02d48d2a83 100644 --- a/tests/extmod/ure_error.py +++ b/tests/extmod/ure_error.py @@ -23,3 +23,4 @@ test_re(r')') test_re(r'[') test_re(r'([') test_re(r'([)') +test_re(r'[a\]') From 25a228af7e5809fe3a582f665c13a2d38eb5ed40 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 15 Oct 2019 17:45:21 +1100 Subject: [PATCH 0868/1788] examples/bluetooth: Add basic BLE peripheral examples. Consisting of: - ble_advertising.py -- helper to generate advertising payload. - ble_temperature.py -- simple temperature device. - ble_uart_periperhal.py -- BLE UART wrapper. - ble_uart_repl.py -- dupterm-compatible uart. --- examples/bluetooth/ble_advertising.py | 37 +++++++++++ examples/bluetooth/ble_temperature.py | 76 +++++++++++++++++++++ examples/bluetooth/ble_uart_peripheral.py | 78 ++++++++++++++++++++++ examples/bluetooth/ble_uart_repl.py | 80 +++++++++++++++++++++++ 4 files changed, 271 insertions(+) create mode 100644 examples/bluetooth/ble_advertising.py create mode 100644 examples/bluetooth/ble_temperature.py create mode 100644 examples/bluetooth/ble_uart_peripheral.py create mode 100644 examples/bluetooth/ble_uart_repl.py diff --git a/examples/bluetooth/ble_advertising.py b/examples/bluetooth/ble_advertising.py new file mode 100644 index 0000000000..f52598a62a --- /dev/null +++ b/examples/bluetooth/ble_advertising.py @@ -0,0 +1,37 @@ +# Helpers for generating BLE advertising payloads. + +from micropython import const +import struct + +# Advertising payloads are repeated packets of the following form: +# 1 byte data length (N + 1) +# 1 byte type (see constants below) +# N bytes type-specific data + +_ADV_TYPE_FLAGS = const(0x01) +_ADV_TYPE_NAME = const(0x09) +_ADV_TYPE_UUID16_COMPLETE = const(0x3) +_ADV_TYPE_APPEARANCE = const(0x19) + +# Generate a payload to be passed to gap_advertise(adv_data=...). +def advertising_payload(limited_disc=False, br_edr=False, name=None, services=None, appearance=0): + payload = bytearray() + + def _append(adv_type, value): + nonlocal payload + payload += struct.pack('BB', len(value) + 1, adv_type) + value + + _append(_ADV_TYPE_FLAGS, struct.pack('B', (0x01 if limited_disc else 0x02) + (0x00 if br_edr else 0x04))) + + if name: + _append(_ADV_TYPE_NAME, name) + + if services: + for uuid in services: + # TODO: Support bluetooth.UUID class. + _append(_ADV_TYPE_UUID16_COMPLETE, struct.pack(' Date: Fri, 11 Oct 2019 10:52:07 +1300 Subject: [PATCH 0869/1788] esp32/boards: Split out CPU frequency config, make 160MHz the default. Remove the 240MHz CPU config option from sdkconfig.base and create a new sdkconfig.240mhz file for those boards that want to use 240MHz on boot. The default CPU frequency is now 160MHz (was 240MHz), to align with the ESP IDF and support more boards (eg those with D2WD chips). Fixes issue #5169. --- ports/esp32/boards/TINYPICO/mpconfigboard.mk | 1 + ports/esp32/boards/sdkconfig.240mhz | 5 +++++ ports/esp32/boards/sdkconfig.base | 1 - 3 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 ports/esp32/boards/sdkconfig.240mhz diff --git a/ports/esp32/boards/TINYPICO/mpconfigboard.mk b/ports/esp32/boards/TINYPICO/mpconfigboard.mk index 2efdba0f39..485b3f1656 100644 --- a/ports/esp32/boards/TINYPICO/mpconfigboard.mk +++ b/ports/esp32/boards/TINYPICO/mpconfigboard.mk @@ -1,5 +1,6 @@ FLASH_FREQ = 80m SDKCONFIG += boards/sdkconfig.base +SDKCONFIG += boards/sdkconfig.240mhz SDKCONFIG += boards/sdkconfig.spiram SDKCONFIG += boards/TINYPICO/sdkconfig.board diff --git a/ports/esp32/boards/sdkconfig.240mhz b/ports/esp32/boards/sdkconfig.240mhz new file mode 100644 index 0000000000..a0cb113a48 --- /dev/null +++ b/ports/esp32/boards/sdkconfig.240mhz @@ -0,0 +1,5 @@ +# MicroPython on ESP32, ESP IDF configuration with 240MHz CPU +CONFIG_ESP32_DEFAULT_CPU_FREQ_80= +CONFIG_ESP32_DEFAULT_CPU_FREQ_160= +CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y +CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240 \ No newline at end of file diff --git a/ports/esp32/boards/sdkconfig.base b/ports/esp32/boards/sdkconfig.base index a11c9397f6..9348f40632 100644 --- a/ports/esp32/boards/sdkconfig.base +++ b/ports/esp32/boards/sdkconfig.base @@ -11,7 +11,6 @@ CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR=y CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y # ESP32-specific -CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=n CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1=n CONFIG_ESP32_XTAL_FREQ_AUTO=y From 8f9e2e325ab0d0dfa9457779010a4cb2cfe60fef Mon Sep 17 00:00:00 2001 From: Josh Lloyd Date: Tue, 24 Sep 2019 17:01:54 +1200 Subject: [PATCH 0870/1788] py/objtype: Add type.__bases__ attribute. Enabled as part of MICROPY_CPYTHON_COMPAT. --- py/objtype.c | 15 +++++++++++++ tests/basics/class_bases.py | 45 +++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 tests/basics/class_bases.py diff --git a/py/objtype.c b/py/objtype.c index 236c79e6ad..bf089dc490 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -1014,6 +1014,21 @@ STATIC void type_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { dest[0] = MP_OBJ_NEW_QSTR(self->name); return; } + if (attr == MP_QSTR___bases__) { + if (self == &mp_type_object) { + dest[0] = mp_const_empty_tuple; + return; + } + mp_obj_t parent_obj = self->parent ? MP_OBJ_FROM_PTR(self->parent) : MP_OBJ_FROM_PTR(&mp_type_object); + #if MICROPY_MULTIPLE_INHERITANCE + if (mp_obj_is_type(parent_obj, &mp_type_tuple)) { + dest[0] = parent_obj; + return; + } + #endif + dest[0] = mp_obj_new_tuple(1, &parent_obj); + return; + } #endif struct class_lookup_data lookup = { .obj = (mp_obj_instance_t*)self, diff --git a/tests/basics/class_bases.py b/tests/basics/class_bases.py new file mode 100644 index 0000000000..d3cf4f598a --- /dev/null +++ b/tests/basics/class_bases.py @@ -0,0 +1,45 @@ +# test for type.__bases__ implementation + +if not hasattr(object, '__bases__'): + print("SKIP") + raise SystemExit + +class A: + pass + +class B(object): + pass + +class C(B): + pass + +class D(C, A): + pass + +# Check the attribute exists +print(hasattr(A, '__bases__')) +print(hasattr(B, '__bases__')) +print(hasattr(C, '__bases__')) +print(hasattr(D, '__bases__')) + +# Check it is always a tuple +print(type(A.__bases__) == tuple) +print(type(B.__bases__) == tuple) +print(type(C.__bases__) == tuple) +print(type(D.__bases__) == tuple) + +# Check size +print(len(A.__bases__) == 1) +print(len(B.__bases__) == 1) +print(len(C.__bases__) == 1) +print(len(D.__bases__) == 2) + +# Check values +print(A.__bases__[0] == object) +print(B.__bases__[0] == object) +print(C.__bases__[0] == B) +print(D.__bases__[0] == C) +print(D.__bases__[1] == A) + +# Object has an empty tuple +print(object.__bases__ == tuple()) From 12413e92a3f938bdfe844bd65bf189ee1431e1d0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 21 Oct 2019 12:23:41 +1100 Subject: [PATCH 0871/1788] stm32/powerctrlboot: Fix config of systick IRQ priority on F0/L0/WB MCU. Prior to this commit the systick IRQ priority was set at lowest priority on F0/L0/WB MCUs, because it was left at the default and never configured. This commit ensures the priority is configured and sets it to the highest priority. --- ports/stm32/irq.h | 4 ++-- ports/stm32/powerctrlboot.c | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/ports/stm32/irq.h b/ports/stm32/irq.h index 78ba46ced4..4b1251666c 100644 --- a/ports/stm32/irq.h +++ b/ports/stm32/irq.h @@ -120,7 +120,7 @@ MP_DECLARE_CONST_FUN_OBJ_0(pyb_irq_stats_obj); #if __CORTEX_M == 0 -//#def IRQ_PRI_SYSTICK 0 +#define IRQ_PRI_SYSTICK 0 #define IRQ_PRI_UART 1 #define IRQ_PRI_SDIO 1 #define IRQ_PRI_DMA 1 @@ -136,7 +136,7 @@ MP_DECLARE_CONST_FUN_OBJ_0(pyb_irq_stats_obj); #else -//#def IRQ_PRI_SYSTICK NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 0, 0) +#define 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 diff --git a/ports/stm32/powerctrlboot.c b/ports/stm32/powerctrlboot.c index 766c52dfb1..acc33f1259 100644 --- a/ports/stm32/powerctrlboot.c +++ b/ports/stm32/powerctrlboot.c @@ -27,6 +27,13 @@ #include "py/mphal.h" #include "powerctrl.h" +static inline void powerctrl_config_systick(void) { + // Configure SYSTICK to run at 1kHz (1ms interval) + SysTick->CTRL |= SYSTICK_CLKSOURCE_HCLK; + SysTick_Config(HAL_RCC_GetHCLKFreq() / 1000); + NVIC_SetPriority(SysTick_IRQn, IRQ_PRI_SYSTICK); +} + #if defined(STM32F0) void SystemClock_Config(void) { @@ -88,9 +95,7 @@ void SystemClock_Config(void) { } SystemCoreClockUpdate(); - - HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000); - HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); + powerctrl_config_systick(); } #elif defined(STM32L0) @@ -122,9 +127,7 @@ void SystemClock_Config(void) { } SystemCoreClockUpdate(); - - HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000); - HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); + powerctrl_config_systick(); #if MICROPY_HW_ENABLE_RNG || MICROPY_HW_ENABLE_USB // Enable the 48MHz internal oscillator @@ -189,9 +192,7 @@ void SystemClock_Config(void) { RCC->CCIPR = 2 << RCC_CCIPR_CLK48SEL_Pos; SystemCoreClockUpdate(); - - HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000); - HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); + powerctrl_config_systick(); } #endif From 8ba963cfa3da8e712e94c2429cfd6f064b1b4c69 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Wed, 16 Oct 2019 15:12:39 +1100 Subject: [PATCH 0872/1788] tools/makemanifest.py: Eval relative paths w.r.t. current manifest file. When loading a manifest file, e.g. by include(), it will chdir first to the directory of that manifest. This means that all file operations within a manifest are relative to that manifest's location. As a consequence of this, additional environment variables are needed to find absolute paths, so the following are added: $(MPY_LIB_DIR), $(PORT_DIR), $(BOARD_DIR). And rename $(MPY) to $(MPY_DIR) to be consistent. Existing manifests are updated to match. --- ports/esp32/boards/manifest.py | 12 ++-- ports/esp32/boards/manifest_release.py | 12 ++-- ports/esp8266/boards/manifest.py | 8 +-- ports/stm32/boards/manifest.py | 6 +- ports/unix/manifest.py | 4 +- py/mkenv.mk | 2 + py/mkrules.mk | 2 +- tools/makemanifest.py | 83 +++++++++++++++++++------- 8 files changed, 85 insertions(+), 44 deletions(-) diff --git a/ports/esp32/boards/manifest.py b/ports/esp32/boards/manifest.py index 3da8af57f8..2b07639ee9 100644 --- a/ports/esp32/boards/manifest.py +++ b/ports/esp32/boards/manifest.py @@ -1,6 +1,6 @@ -freeze('modules') -freeze('$(MPY)/tools', ('upip.py', 'upip_utarfile.py')) -freeze('$(MPY)/ports/esp8266/modules', 'ntptime.py') -freeze('$(MPY)/ports/esp8266/modules', ('webrepl.py', 'webrepl_setup.py', 'websocket_helper.py',)) -freeze('$(MPY)/drivers/dht', 'dht.py') -freeze('$(MPY)/drivers/onewire') +freeze('$(PORT_DIR)/modules') +freeze('$(MPY_DIR)/tools', ('upip.py', 'upip_utarfile.py')) +freeze('$(MPY_DIR)/ports/esp8266/modules', 'ntptime.py') +freeze('$(MPY_DIR)/ports/esp8266/modules', ('webrepl.py', 'webrepl_setup.py', 'websocket_helper.py',)) +freeze('$(MPY_DIR)/drivers/dht', 'dht.py') +freeze('$(MPY_DIR)/drivers/onewire') diff --git a/ports/esp32/boards/manifest_release.py b/ports/esp32/boards/manifest_release.py index e56704d023..9c898af26d 100644 --- a/ports/esp32/boards/manifest_release.py +++ b/ports/esp32/boards/manifest_release.py @@ -1,8 +1,6 @@ -include('boards/manifest.py') +include('manifest.py') -LIB = '../../../micropython-lib' - -freeze(LIB + '/upysh', 'upysh.py') -freeze(LIB + '/urequests', 'urequests.py') -freeze(LIB + '/umqtt.simple', 'umqtt/simple.py') -freeze(LIB + '/umqtt.robust', 'umqtt/robust.py') +freeze('$(MPY_LIB_DIR)/upysh', 'upysh.py') +freeze('$(MPY_LIB_DIR)/urequests', 'urequests.py') +freeze('$(MPY_LIB_DIR)/umqtt.simple', 'umqtt/simple.py') +freeze('$(MPY_LIB_DIR)/umqtt.robust', 'umqtt/robust.py') diff --git a/ports/esp8266/boards/manifest.py b/ports/esp8266/boards/manifest.py index 1264a22686..779e840880 100644 --- a/ports/esp8266/boards/manifest.py +++ b/ports/esp8266/boards/manifest.py @@ -1,4 +1,4 @@ -freeze('modules') -freeze('$(MPY)/tools', ('upip.py', 'upip_utarfile.py')) -freeze('$(MPY)/drivers/dht', 'dht.py') -freeze('$(MPY)/drivers/onewire') +freeze('$(PORT_DIR)/modules') +freeze('$(MPY_DIR)/tools', ('upip.py', 'upip_utarfile.py')) +freeze('$(MPY_DIR)/drivers/dht', 'dht.py') +freeze('$(MPY_DIR)/drivers/onewire') diff --git a/ports/stm32/boards/manifest.py b/ports/stm32/boards/manifest.py index 99b08cca00..41b728fa28 100644 --- a/ports/stm32/boards/manifest.py +++ b/ports/stm32/boards/manifest.py @@ -1,3 +1,3 @@ -freeze('$(MPY)/drivers/dht', 'dht.py') -freeze('$(MPY)/drivers/display', ('lcd160cr.py', 'lcd160cr_test.py')) -freeze('$(MPY)/drivers/onewire', 'onewire.py') +freeze('$(MPY_DIR)/drivers/dht', 'dht.py') +freeze('$(MPY_DIR)/drivers/display', ('lcd160cr.py', 'lcd160cr_test.py')) +freeze('$(MPY_DIR)/drivers/onewire', 'onewire.py') diff --git a/ports/unix/manifest.py b/ports/unix/manifest.py index 3f332446d1..666b4c0ab3 100644 --- a/ports/unix/manifest.py +++ b/ports/unix/manifest.py @@ -1,2 +1,2 @@ -freeze_as_mpy('$(MPY)/tools', 'upip.py') -freeze_as_mpy('$(MPY)/tools', 'upip_utarfile.py', opt=3) +freeze_as_mpy('$(MPY_DIR)/tools', 'upip.py') +freeze_as_mpy('$(MPY_DIR)/tools', 'upip_utarfile.py', opt=3) diff --git a/py/mkenv.mk b/py/mkenv.mk index 70d937c450..3efeb18164 100644 --- a/py/mkenv.mk +++ b/py/mkenv.mk @@ -66,6 +66,8 @@ MAKE_FROZEN = $(PYTHON) $(TOP)/tools/make-frozen.py MPY_CROSS = $(TOP)/mpy-cross/mpy-cross MPY_TOOL = $(PYTHON) $(TOP)/tools/mpy-tool.py +MPY_LIB_DIR = $(TOP)/../micropython-lib + all: .PHONY: all diff --git a/py/mkrules.mk b/py/mkrules.mk index 2a7e1980c9..b43c6b8e37 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -100,7 +100,7 @@ $(HEADER_BUILD): ifneq ($(FROZEN_MANIFEST),) # to build frozen_content.c from a manifest $(BUILD)/frozen_content.c: FORCE $(BUILD)/genhdr/qstrdefs.generated.h - $(Q)$(MAKE_MANIFEST) -o $@ $(TOP) $(BUILD) "$(MPY_CROSS_FLAGS)" $(FROZEN_MANIFEST) + $(Q)$(MAKE_MANIFEST) -o $@ -v "MPY_DIR=$(TOP)" -v "MPY_LIB_DIR=$(MPY_LIB_DIR)" -v "PORT_DIR=$(shell pwd)" -v "BOARD_DIR=$(BOARD_DIR)" -b "$(BUILD)" $(if $(MPY_CROSS_FLAGS),-f"$(MPY_CROSS_FLAGS)",) $(FROZEN_MANIFEST) endif ifneq ($(FROZEN_DIR),) diff --git a/tools/makemanifest.py b/tools/makemanifest.py index 3017d7a21f..9889d50750 100644 --- a/tools/makemanifest.py +++ b/tools/makemanifest.py @@ -38,14 +38,22 @@ def include(manifest): The manifest argument can be a string (filename) or an iterable of strings. + + Relative paths are resolved with respect to the current manifest file. """ if not isinstance(manifest, str): for m in manifest: include(m) else: + manifest = convert_path(manifest) with open(manifest) as f: + # Make paths relative to this manifest file while processing it. + # Applies to includes and input files. + prev_cwd = os.getcwd() + os.chdir(os.path.dirname(manifest)) exec(f.read()) + os.chdir(prev_cwd) def freeze(path, script=None, opt=0): """Freeze the input, automatically determining its type. A .py script @@ -57,6 +65,10 @@ def freeze(path, script=None, opt=0): the module will start after `path`, ie `path` is excluded from the module name. + If `path` is relative, it is resolved to the current manifest.py. + Use $(MPY_DIR), $(MPY_LIB_DIR), $(PORT_DIR), $(BOARD_DIR) if you need + to access specific paths. + If `script` is None all files in `path` will be frozen. If `script` is an iterable then freeze() is called on all items of the @@ -102,6 +114,8 @@ KIND_AS_STR = 1 KIND_AS_MPY = 2 KIND_MPY = 3 +VARS = {} + manifest_list = [] class FreezeError(Exception): @@ -115,7 +129,12 @@ def system(cmd): return -1, er.output def convert_path(path): - return path.replace('$(MPY)', TOP) + # Perform variable substituion. + for name, value in VARS.items(): + path = path.replace('$({})'.format(name), value) + # Convert to absolute path (so that future operations don't rely on + # still being chdir'ed). + return os.path.abspath(path) def get_timestamp(path, default=None): try: @@ -173,23 +192,39 @@ def freeze_internal(kind, path, script, opt): manifest_list.append((kind, path, script, opt)) def main(): - global TOP - # Parse arguments - assert sys.argv[1] == '-o' - output_file = sys.argv[2] - TOP = sys.argv[3] - BUILD = sys.argv[4] - mpy_cross_flags = sys.argv[5] - input_manifest_list = sys.argv[6:] + import argparse + cmd_parser = argparse.ArgumentParser(description='A tool to generate frozen content in MicroPython firmware images.') + cmd_parser.add_argument('-o', '--output', help='output path') + cmd_parser.add_argument('-b', '--build-dir', help='output path') + cmd_parser.add_argument('-f', '--mpy-cross-flags', default='', help='flags to pass to mpy-cross') + cmd_parser.add_argument('-v', '--var', action='append', help='variables to substitute') + cmd_parser.add_argument('files', nargs='+', help='input manifest list') + args = cmd_parser.parse_args() + + # Extract variables for substitution. + for var in args.var: + name, value = var.split('=', 1) + if os.path.exists(value): + value = os.path.abspath(value) + VARS[name] = value + + if 'MPY_DIR' not in VARS or 'PORT_DIR' not in VARS: + print('MPY_DIR and PORT_DIR variables must be specified') + sys.exit(1) # Get paths to tools - MAKE_FROZEN = TOP + '/tools/make-frozen.py' - MPY_CROSS = TOP + '/mpy-cross/mpy-cross' - MPY_TOOL = TOP + '/tools/mpy-tool.py' + MAKE_FROZEN = VARS['MPY_DIR'] + '/tools/make-frozen.py' + MPY_CROSS = VARS['MPY_DIR'] + '/mpy-cross/mpy-cross' + MPY_TOOL = VARS['MPY_DIR'] + '/tools/mpy-tool.py' + + # Ensure mpy-cross is built + if not os.path.exists(MPY_CROSS): + print('mpy-cross not found at {}, please build it first'.format(MPY_CROSS)) + sys.exit(1) # Include top-level inputs, to generate the manifest - for input_manifest in input_manifest_list: + for input_manifest in args.files: try: if input_manifest.endswith('.py'): include(input_manifest) @@ -209,13 +244,13 @@ def main(): ts_outfile = get_timestamp_newest(path) elif kind == KIND_AS_MPY: infile = '{}/{}'.format(path, script) - outfile = '{}/frozen_mpy/{}.mpy'.format(BUILD, script[:-3]) + outfile = '{}/frozen_mpy/{}.mpy'.format(args.build_dir, script[:-3]) ts_infile = get_timestamp(infile) ts_outfile = get_timestamp(outfile, 0) if ts_infile >= ts_outfile: print('MPY', script) mkdir(outfile) - res, out = system([MPY_CROSS] + mpy_cross_flags.split() + ['-o', outfile, '-s', script, '-O{}'.format(opt), infile]) + res, out = system([MPY_CROSS] + args.mpy_cross_flags.split() + ['-o', outfile, '-s', script, '-O{}'.format(opt), infile]) if res != 0: print('error compiling {}: {}'.format(infile, out)) raise SystemExit(1) @@ -229,20 +264,26 @@ def main(): ts_newest = max(ts_newest, ts_outfile) # Check if output file needs generating - if ts_newest < get_timestamp(output_file, 0): + if ts_newest < get_timestamp(args.output, 0): # No files are newer than output file so it does not need updating return # Freeze paths as strings - _, output_str = system([MAKE_FROZEN] + str_paths) + res, output_str = system([MAKE_FROZEN] + str_paths) + if res != 0: + print('error freezing strings {}: {}'.format(str_paths, output_str)) + sys.exit(1) # Freeze .mpy files - _, output_mpy = system([MPY_TOOL, '-f', '-q', BUILD + '/genhdr/qstrdefs.preprocessed.h'] + mpy_files) + res, output_mpy = system([MPY_TOOL, '-f', '-q', args.build_dir + '/genhdr/qstrdefs.preprocessed.h'] + mpy_files) + if res != 0: + print('error freezing mpy {}: {}'.format(mpy_files, output_mpy)) + sys.exit(1) # Generate output - print('GEN', output_file) - mkdir(output_file) - with open(output_file, 'wb') as f: + print('GEN', args.output) + mkdir(args.output) + with open(args.output, 'wb') as f: f.write(b'//\n// Content for MICROPY_MODULE_FROZEN_STR\n//\n') f.write(output_str) f.write(b'//\n// Content for MICROPY_MODULE_FROZEN_MPY\n//\n') From 7662501d5b7c93fad6466b972d9912ee4fcc7660 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Sat, 19 Oct 2019 00:38:35 +1100 Subject: [PATCH 0873/1788] py/mkrules.mk: Add warning/error for invalid frozen config. --- py/mkrules.mk | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/py/mkrules.mk b/py/mkrules.mk index b43c6b8e37..68da3e793c 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -101,15 +101,25 @@ ifneq ($(FROZEN_MANIFEST),) # to build frozen_content.c from a manifest $(BUILD)/frozen_content.c: FORCE $(BUILD)/genhdr/qstrdefs.generated.h $(Q)$(MAKE_MANIFEST) -o $@ -v "MPY_DIR=$(TOP)" -v "MPY_LIB_DIR=$(MPY_LIB_DIR)" -v "PORT_DIR=$(shell pwd)" -v "BOARD_DIR=$(BOARD_DIR)" -b "$(BUILD)" $(if $(MPY_CROSS_FLAGS),-f"$(MPY_CROSS_FLAGS)",) $(FROZEN_MANIFEST) + +ifneq ($(FROZEN_DIR),) +$(error FROZEN_DIR cannot be used in conjunction with FROZEN_MANIFEST) +endif + +ifneq ($(FROZEN_MPY_DIR),) +$(error FROZEN_MPY_DIR cannot be used in conjunction with FROZEN_MANIFEST) +endif endif ifneq ($(FROZEN_DIR),) +$(info Warning: FROZEN_DIR is deprecated in favour of FROZEN_MANIFEST) $(BUILD)/frozen.c: $(wildcard $(FROZEN_DIR)/*) $(HEADER_BUILD) $(FROZEN_EXTRA_DEPS) $(ECHO) "GEN $@" $(Q)$(MAKE_FROZEN) $(FROZEN_DIR) > $@ endif ifneq ($(FROZEN_MPY_DIR),) +$(info Warning: FROZEN_MPY_DIR is deprecated in favour of FROZEN_MANIFEST) # make a list of all the .py files that need compiling and freezing FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py' | $(SED) -e 's=^$(FROZEN_MPY_DIR)/==') FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/frozen_mpy/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) From df7f632fd7003824500ec6c05f4395f667667d54 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Sat, 19 Oct 2019 00:39:04 +1100 Subject: [PATCH 0874/1788] esp8266: Allow building without a manifest. --- ports/esp8266/Makefile | 9 +++++++++ ports/esp8266/mpconfigport.h | 3 --- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/ports/esp8266/Makefile b/ports/esp8266/Makefile index c4ffd4f811..f1b718c781 100644 --- a/ports/esp8266/Makefile +++ b/ports/esp8266/Makefile @@ -189,6 +189,15 @@ $(BUILD)/uart.o: $(CONFVARS_FILE) FROZEN_EXTRA_DEPS = $(CONFVARS_FILE) +ifneq ($(FROZEN_MANIFEST)$(FROZEN_MPY_DIR),) +CFLAGS += -DMICROPY_MODULE_FROZEN_MPY +CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool +endif + +ifneq ($(FROZEN_MANIFEST)$(FROZEN_DIR),) +CFLAGS += -DMICROPY_MODULE_FROZEN_STR +endif + .PHONY: deploy deploy: $(BUILD)/firmware-combined.bin diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h index fa809d91a6..e77f88c83c 100644 --- a/ports/esp8266/mpconfigport.h +++ b/ports/esp8266/mpconfigport.h @@ -94,10 +94,7 @@ #define MICROPY_PY_STR_BYTES_CMP_WARN (1) #define MICROPY_STREAMS_NON_BLOCK (1) #define MICROPY_STREAMS_POSIX_API (1) -#define MICROPY_MODULE_FROZEN_STR (1) -#define MICROPY_MODULE_FROZEN_MPY (1) #define MICROPY_MODULE_FROZEN_LEXER mp_lexer_new_from_str32 -#define MICROPY_QSTR_EXTRA_POOL mp_qstr_frozen_const_pool #define MICROPY_FATFS_ENABLE_LFN (1) #define MICROPY_FATFS_RPATH (2) From 93bd61ca91a3efcec9bc090fae193287bfa120e0 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Sat, 19 Oct 2019 00:39:11 +1100 Subject: [PATCH 0875/1788] unix: Allow building without a manifest. --- ports/unix/Makefile | 5 ++++- ports/unix/mpconfigport.h | 1 - ports/unix/mpconfigport_fast.h | 5 ----- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/ports/unix/Makefile b/ports/unix/Makefile index b840856ffa..bcc76ce160 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -188,6 +188,9 @@ CFLAGS += -DMPZ_DIG_SIZE=16 # force 16 bits to work on both 32 and 64 bit archs MPY_CROSS_FLAGS += -mcache-lookup-bc endif +ifneq ($(FROZEN_MANIFEST)$(FROZEN_DIR),) +CFLAGS += -DMICROPY_MODULE_FROZEN_STR +endif include $(TOP)/py/mkrules.mk @@ -212,7 +215,7 @@ uninstall: # build synthetically fast interpreter for benchmarking fast: - $(MAKE) COPT="-O2 -DNDEBUG -fno-crossjumping" CFLAGS_EXTRA='-DMP_CONFIGFILE=""' BUILD=build-fast PROG=micropython_fast + $(MAKE) COPT="-O2 -DNDEBUG -fno-crossjumping" CFLAGS_EXTRA='-DMP_CONFIGFILE=""' BUILD=build-fast PROG=micropython_fast FROZEN_MANIFEST= # build a minimal interpreter minimal: diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h index 0ff6b2b06d..1bb80f9704 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -113,7 +113,6 @@ #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) #ifndef MICROPY_STACKLESS #define MICROPY_STACKLESS (0) diff --git a/ports/unix/mpconfigport_fast.h b/ports/unix/mpconfigport_fast.h index 442159eb4f..193567a294 100644 --- a/ports/unix/mpconfigport_fast.h +++ b/ports/unix/mpconfigport_fast.h @@ -33,8 +33,3 @@ // 91 is a magic number proposed by @dpgeorge, which make pystone run ~ at tie // with CPython 3.4. #define MICROPY_MODULE_DICT_SIZE (91) - -// Don't include builtin upip, as this build is again intended just for -// synthetic benchmarking -#undef MICROPY_MODULE_FROZEN_STR -#define MICROPY_MODULE_FROZEN_STR (0) From ffd11486d426fa3b45946da72d274cd88be942d1 Mon Sep 17 00:00:00 2001 From: clach04 Date: Sun, 20 Oct 2019 18:22:20 -0700 Subject: [PATCH 0876/1788] tests/cpydiff: Fix typo in types_bytes_keywords.py doc comments. --- tests/cpydiff/types_bytes_keywords.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cpydiff/types_bytes_keywords.py b/tests/cpydiff/types_bytes_keywords.py index 4dc383f262..bdba966f7f 100644 --- a/tests/cpydiff/types_bytes_keywords.py +++ b/tests/cpydiff/types_bytes_keywords.py @@ -2,6 +2,6 @@ categories: Types,bytes description: bytes() with keywords not implemented cause: Unknown -workaround: Pass the encoding as a positional paramter, e.g. ``print(bytes('abc', 'utf-8'))`` +workaround: Pass the encoding as a positional parameter, e.g. ``print(bytes('abc', 'utf-8'))`` """ print(bytes('abc', encoding='utf8')) From 912892b2093f45a77986399f5e4600fe23b3efcf Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 21 Oct 2019 17:42:14 +1100 Subject: [PATCH 0877/1788] esp32: Add missing and necessary newline at EOF for sdkconfig.240mhz. When these files get concatenated the newline-at-EOF is necessary so that the start of the next file doesn't join with the end of the previous. --- ports/esp32/boards/sdkconfig.240mhz | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/esp32/boards/sdkconfig.240mhz b/ports/esp32/boards/sdkconfig.240mhz index a0cb113a48..e36884009d 100644 --- a/ports/esp32/boards/sdkconfig.240mhz +++ b/ports/esp32/boards/sdkconfig.240mhz @@ -2,4 +2,4 @@ CONFIG_ESP32_DEFAULT_CPU_FREQ_80= CONFIG_ESP32_DEFAULT_CPU_FREQ_160= CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y -CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240 \ No newline at end of file +CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240 From f1d91908fa427cb419d6fcd5f64f6c581a0cdd0f Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 22 Oct 2019 00:23:22 +1100 Subject: [PATCH 0878/1788] esp8266/boards: Add manifest_release.py with files for a release. A release also sets: UART_OS = -1 --- ports/esp8266/boards/manifest_release.py | 27 ++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 ports/esp8266/boards/manifest_release.py diff --git a/ports/esp8266/boards/manifest_release.py b/ports/esp8266/boards/manifest_release.py new file mode 100644 index 0000000000..f2788c8157 --- /dev/null +++ b/ports/esp8266/boards/manifest_release.py @@ -0,0 +1,27 @@ +include('manifest.py') + +# drivers +freeze('$(MPY_DIR)/drivers/display', 'ssd1306.py') + +# file utilities +freeze('$(MPY_LIB_DIR)/upysh', 'upysh.py') + +# uasyncio +freeze('$(MPY_LIB_DIR)/uasyncio', 'uasyncio/__init__.py') +freeze('$(MPY_LIB_DIR)/uasyncio.core', 'uasyncio/core.py') + +# requests +freeze('$(MPY_LIB_DIR)/urequests', 'urequests.py') +freeze('$(MPY_LIB_DIR)/urllib.urequest', 'urllib/urequest.py') + +# umqtt with examples +freeze('$(MPY_LIB_DIR)/umqtt.simple', 'umqtt/simple.py') +freeze('$(MPY_LIB_DIR)/umqtt.robust', 'umqtt/robust.py') +freeze('$(MPY_LIB_DIR)/umqtt.simple', 'example_pub_button.py') +freeze('$(MPY_LIB_DIR)/umqtt.simple', 'example_sub_led.py') + +# HTTP examples +freeze('$(MPY_DIR)/examples/network', 'http_client.py') +freeze('$(MPY_DIR)/examples/network', 'http_client_ssl.py') +freeze('$(MPY_DIR)/examples/network', 'http_server.py') +freeze('$(MPY_DIR)/examples/network', 'http_server_ssl.py') From 56fc3edf989e1216b1a00d8ab75ebefff33a67e8 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Wed, 16 Oct 2019 20:45:44 +1100 Subject: [PATCH 0879/1788] extmod/modbluetooth: Make UUID support the buffer protocol. Internally change the representation of UUIDs to LE uint8* to simplify this. This allows UUIDs to be easily used in BLE payloads (such as advertising). Ref: #5186 --- extmod/modbluetooth.c | 88 +++++++++++++----------------------- extmod/modbluetooth.h | 16 ++++--- extmod/modbluetooth_nimble.c | 19 +++++--- 3 files changed, 53 insertions(+), 70 deletions(-) diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index 3c00d5c1b5..1b98888448 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -122,10 +122,11 @@ STATIC mp_obj_t bluetooth_uuid_make_new(const mp_obj_type_t *type, size_t n_args if (value > 65535) { mp_raise_ValueError("invalid UUID"); } - self->uuid._16 = value; + self->data[0] = value & 0xff; + self->data[1] = (value >> 8) & 0xff; } else { self->type = MP_BLUETOOTH_UUID_TYPE_128; - mp_bluetooth_parse_uuid_128bit_str(all_args[0], self->uuid._128); + mp_bluetooth_parse_uuid_128bit_str(all_args[0], self->data); } return self; @@ -135,41 +136,39 @@ STATIC mp_obj_t bluetooth_uuid_unary_op(mp_unary_op_t op, mp_obj_t self_in) { mp_obj_bluetooth_uuid_t *self = MP_OBJ_TO_PTR(self_in); switch (op) { case MP_UNARY_OP_HASH: { - if (self->type == MP_BLUETOOTH_UUID_TYPE_16) { - return mp_unary_op(MP_UNARY_OP_HASH, MP_OBJ_NEW_SMALL_INT(self->uuid._16)); - - } else if (self->type == MP_BLUETOOTH_UUID_TYPE_32) { - return mp_unary_op(MP_UNARY_OP_HASH, MP_OBJ_NEW_SMALL_INT(self->uuid._32)); - - } else if (self->type == MP_BLUETOOTH_UUID_TYPE_128) { - return MP_OBJ_NEW_SMALL_INT(qstr_compute_hash(self->uuid._128, sizeof(self->uuid._128))); - } - return MP_OBJ_NULL; + // Use the QSTR hash function. + return MP_OBJ_NEW_SMALL_INT(qstr_compute_hash(self->data, self->type)); } default: return MP_OBJ_NULL; // op not supported } } - STATIC void bluetooth_uuid_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { mp_obj_bluetooth_uuid_t *self = MP_OBJ_TO_PTR(self_in); - - if (self->type == MP_BLUETOOTH_UUID_TYPE_16) { - mp_printf(print, "UUID16(0x%04x)", self->uuid._16); - } else if (self->type == MP_BLUETOOTH_UUID_TYPE_32) { - mp_printf(print, "UUID32(0x%08x)", self->uuid._32); - } else if (self->type == MP_BLUETOOTH_UUID_TYPE_128) { - mp_printf(print, "UUID128('"); - for (int i = 0; i < 16; ++i) { - mp_printf(print, "%02x", self->uuid._128[15-i]); - if (i == 3 || i == 5 || i == 7 || i == 9) { - mp_printf(print, "-"); - } + mp_printf(print, "UUID%u(%s", self->type * 8, self->type <= 4 ? "0x" : "'"); + for (int i = 0; i < self->type; ++i) { + if (i == 4 || i == 6 || i == 8 || i == 10) { + mp_printf(print, "-"); } - mp_printf(print, "')"); - } else { - mp_printf(print, "UUID?(%d)", self->type); + mp_printf(print, "%02x", self->data[self->type - 1 - i]); } + if (self->type == MP_BLUETOOTH_UUID_TYPE_128) { + mp_printf(print, "'"); + } + mp_printf(print, ")"); +} + +mp_int_t bluetooth_uuid_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) { + mp_obj_bluetooth_uuid_t *self = MP_OBJ_TO_PTR(self_in); + + if (flags != MP_BUFFER_READ) { + return 1; + } + + bufinfo->buf = self->data; + bufinfo->len = self->type; + bufinfo->typecode = 'B'; + return 0; } #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE @@ -177,19 +176,8 @@ STATIC void bluetooth_uuid_print(const mp_print_t *print, mp_obj_t self_in, mp_p STATIC void ringbuf_put_uuid(ringbuf_t *ringbuf, mp_obj_bluetooth_uuid_t *uuid) { assert(ringbuf_free(ringbuf) >= uuid->type + 1); ringbuf_put(ringbuf, uuid->type); - switch (uuid->type) { - case MP_BLUETOOTH_UUID_TYPE_16: - ringbuf_put16(ringbuf, uuid->uuid._16); - break; - case MP_BLUETOOTH_UUID_TYPE_32: - ringbuf_put16(ringbuf, uuid->uuid._32 >> 16); - ringbuf_put16(ringbuf, uuid->uuid._32 & 0xffff); - break; - case MP_BLUETOOTH_UUID_TYPE_128: - for (int i = 0; i < 16; ++i) { - ringbuf_put(ringbuf, uuid->uuid._128[i]); - } - break; + for (int i = 0; i < uuid->type; ++i) { + ringbuf_put(ringbuf, uuid->data[i]); } } @@ -197,21 +185,8 @@ STATIC void ringbuf_get_uuid(ringbuf_t *ringbuf, mp_obj_bluetooth_uuid_t *uuid) assert(ringbuf_avail(ringbuf) >= 1); uuid->type = ringbuf_get(ringbuf); assert(ringbuf_avail(ringbuf) >= uuid->type); - uint16_t h, l; - switch (uuid->type) { - case MP_BLUETOOTH_UUID_TYPE_16: - uuid->uuid._16 = ringbuf_get16(ringbuf); - break; - case MP_BLUETOOTH_UUID_TYPE_32: - h = ringbuf_get16(ringbuf); - l = ringbuf_get16(ringbuf); - uuid->uuid._32 = (h << 16) | l; - break; - case MP_BLUETOOTH_UUID_TYPE_128: - for (int i = 0; i < 16; ++i) { - uuid->uuid._128[i] = ringbuf_get(ringbuf); - } - break; + for (int i = 0; i < uuid->type; ++i) { + uuid->data[i] = ringbuf_get(ringbuf); } } #endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE @@ -223,6 +198,7 @@ STATIC const mp_obj_type_t bluetooth_uuid_type = { .unary_op = bluetooth_uuid_unary_op, .locals_dict = NULL, .print = bluetooth_uuid_print, + .buffer_p = { .get_buffer = bluetooth_uuid_get_buffer }, }; // ---------------------------------------------------------------------------- diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h index f7284a43e8..e99641e8f7 100644 --- a/extmod/modbluetooth.h +++ b/extmod/modbluetooth.h @@ -120,14 +120,14 @@ _IRQ_ALL = const(0xffff) // Common UUID type. // Ports are expected to map this to their own internal UUID types. +// Internally the UUID data is little-endian, but the user should only +// ever see this if they use the buffer protocol, e.g. in order to +// construct an advertising payload (which needs to be in LE). +// Both the constructor and the print function work in BE. typedef struct { mp_obj_base_t base; uint8_t type; - union { - uint16_t _16; - uint32_t _32; - uint8_t _128[16]; - } uuid; + uint8_t data[16]; } mp_obj_bluetooth_uuid_t; ////////////////////////////////////////////////////////////// @@ -140,8 +140,10 @@ typedef struct { // Any method returning an int returns errno on failure, otherwise zero. // Note: All methods dealing with addresses (as 6-byte uint8 pointers) are in big-endian format. -// (i.e. the same way they would be printed on a device sticker or in a UI). -// This means that the lower level implementation might need to reorder them (e.g. Nimble works in little-endian) +// (i.e. the same way they would be printed on a device sticker or in a UI), so the user sees +// addresses in a way that looks like what they'd expect. +// This means that the lower level implementation will likely need to reorder them (e.g. Nimble +// works in little-endian, as does BLE itself). // Enables the Bluetooth stack. int mp_bluetooth_init(void); diff --git a/extmod/modbluetooth_nimble.c b/extmod/modbluetooth_nimble.c index 131b73574d..c09f1cd2de 100644 --- a/extmod/modbluetooth_nimble.c +++ b/extmod/modbluetooth_nimble.c @@ -87,21 +87,22 @@ STATIC int ble_hs_err_to_errno(int err) { } } +// Note: modbluetooth UUIDs store their data in LE. STATIC ble_uuid_t* create_nimble_uuid(const mp_obj_bluetooth_uuid_t *uuid) { if (uuid->type == MP_BLUETOOTH_UUID_TYPE_16) { ble_uuid16_t *result = m_new(ble_uuid16_t, 1); result->u.type = BLE_UUID_TYPE_16; - result->value = uuid->uuid._16; + result->value = (uuid->data[1] << 8) | uuid->data[0]; return (ble_uuid_t*)result; } else if (uuid->type == MP_BLUETOOTH_UUID_TYPE_32) { ble_uuid32_t *result = m_new(ble_uuid32_t, 1); result->u.type = BLE_UUID_TYPE_32; - result->value = uuid->uuid._32; + result->value = (uuid->data[1] << 24) | (uuid->data[1] << 16) | (uuid->data[1] << 8) | uuid->data[0]; return (ble_uuid_t*)result; } else if (uuid->type == MP_BLUETOOTH_UUID_TYPE_128) { ble_uuid128_t *result = m_new(ble_uuid128_t, 1); result->u.type = BLE_UUID_TYPE_128; - memcpy(result->value, uuid->uuid._128, 16); + memcpy(result->value, uuid->data, 16); return (ble_uuid_t*)result; } else { return NULL; @@ -115,15 +116,19 @@ STATIC mp_obj_bluetooth_uuid_t create_mp_uuid(const ble_uuid_any_t *uuid) { switch (uuid->u.type) { case BLE_UUID_TYPE_16: result.type = MP_BLUETOOTH_UUID_TYPE_16; - result.uuid._16 = uuid->u16.value; + result.data[0] = uuid->u16.value & 0xff; + result.data[1] = (uuid->u16.value << 8) & 0xff; break; case BLE_UUID_TYPE_32: result.type = MP_BLUETOOTH_UUID_TYPE_32; - result.uuid._32 = uuid->u32.value; + result.data[0] = uuid->u32.value & 0xff; + result.data[1] = (uuid->u32.value << 8) & 0xff; + result.data[2] = (uuid->u32.value << 16) & 0xff; + result.data[3] = (uuid->u32.value << 24) & 0xff; break; case BLE_UUID_TYPE_128: result.type = MP_BLUETOOTH_UUID_TYPE_128; - memcpy(result.uuid._128, uuid->u128.value, 16); + memcpy(result.data, uuid->u128.value, 16); break; default: assert(false); @@ -131,7 +136,7 @@ STATIC mp_obj_bluetooth_uuid_t create_mp_uuid(const ble_uuid_any_t *uuid) { return result; } -// modbluetooth (and the layers above it) work in BE addresses, Nimble works in LE. +// modbluetooth (and the layers above it) work in BE for addresses, Nimble works in LE. STATIC void reverse_addr_byte_order(uint8_t *addr_out, const uint8_t *addr_in) { for (int i = 0; i < 6; ++i) { addr_out[i] = addr_in[5-i]; From 3e1af5b36fc181231b6c7b7603b21490fb9b22e6 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 22 Oct 2019 12:31:40 +1100 Subject: [PATCH 0880/1788] examples/bluetooth: Use UUIDs directly to add services to adv payload. --- examples/bluetooth/ble_advertising.py | 15 +++++++++++++-- examples/bluetooth/ble_temperature.py | 2 +- examples/bluetooth/ble_uart_peripheral.py | 1 + 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/examples/bluetooth/ble_advertising.py b/examples/bluetooth/ble_advertising.py index f52598a62a..b57d5e031c 100644 --- a/examples/bluetooth/ble_advertising.py +++ b/examples/bluetooth/ble_advertising.py @@ -11,8 +11,14 @@ import struct _ADV_TYPE_FLAGS = const(0x01) _ADV_TYPE_NAME = const(0x09) _ADV_TYPE_UUID16_COMPLETE = const(0x3) +_ADV_TYPE_UUID32_COMPLETE = const(0x5) +_ADV_TYPE_UUID128_COMPLETE = const(0x7) +_ADV_TYPE_UUID16_MORE = const(0x2) +_ADV_TYPE_UUID32_MORE = const(0x4) +_ADV_TYPE_UUID128_MORE = const(0x6) _ADV_TYPE_APPEARANCE = const(0x19) + # Generate a payload to be passed to gap_advertise(adv_data=...). def advertising_payload(limited_disc=False, br_edr=False, name=None, services=None, appearance=0): payload = bytearray() @@ -28,8 +34,13 @@ def advertising_payload(limited_disc=False, br_edr=False, name=None, services=No if services: for uuid in services: - # TODO: Support bluetooth.UUID class. - _append(_ADV_TYPE_UUID16_COMPLETE, struct.pack(' Date: Tue, 22 Oct 2019 12:36:02 +1100 Subject: [PATCH 0881/1788] py/objstr: Size-optimise failure path for mp_obj_str_get_buffer. These fields are never looked at if the function returns non-zero. --- py/objstr.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/py/objstr.c b/py/objstr.c index 8824363637..e221982c57 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -1913,9 +1913,6 @@ mp_int_t mp_obj_str_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_u return 0; } else { // can't write to a string - bufinfo->buf = NULL; - bufinfo->len = 0; - bufinfo->typecode = -1; return 1; } } From f34e16dbc6648a46590501bbc5e4b146bd032eef Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 21 Oct 2019 22:35:58 +1100 Subject: [PATCH 0882/1788] extmod/modbluetooth: Persist reference to NimBLE service instances. NimBLE doesn't actually copy this data, it requires it to stay live. Only dereference when we register a new set of services. Fixes #5226 This will allow incrementally adding services in the future, so rename `reset` to `append` to make it clearer. --- extmod/modbluetooth.c | 6 +++--- extmod/modbluetooth.h | 2 +- extmod/modbluetooth_nimble.c | 15 ++++++++------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index 1b98888448..2a3e87bc24 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -421,9 +421,9 @@ STATIC mp_obj_t bluetooth_ble_gatts_register_services(mp_obj_t self_in, mp_obj_t uint16_t **handles = m_new0(uint16_t*, len); size_t *num_handles = m_new0(size_t, len); - // We always reset the service list, as Nimble has no other option. - // TODO: Add a `reset` or `clear` kwarg (defaulting to True) to make this behavior optional. - int err = mp_bluetooth_gatts_register_service_begin(true); + // TODO: Add a `append` kwarg (defaulting to False) to make this behavior optional. + bool append = false; + int err = mp_bluetooth_gatts_register_service_begin(append); if (err != 0) { return bluetooth_handle_errno(err); } diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h index e99641e8f7..20476b183c 100644 --- a/extmod/modbluetooth.h +++ b/extmod/modbluetooth.h @@ -165,7 +165,7 @@ int mp_bluetooth_gap_advertise_start(bool connectable, int32_t interval_us, cons void mp_bluetooth_gap_advertise_stop(void); // Start adding services. Must be called before mp_bluetooth_register_service. -int mp_bluetooth_gatts_register_service_begin(bool reset); +int mp_bluetooth_gatts_register_service_begin(bool append); // // Add a service with the given list of characteristics to the queue to be registered. // The value_handles won't be valid until after mp_bluetooth_register_service_end is called. int mp_bluetooth_gatts_register_service(mp_obj_bluetooth_uuid_t *service_uuid, mp_obj_bluetooth_uuid_t **characteristic_uuids, uint8_t *characteristic_flags, mp_obj_bluetooth_uuid_t **descriptor_uuids, uint8_t *descriptor_flags, uint8_t *num_descriptors, uint16_t *handles, size_t num_characteristics); diff --git a/extmod/modbluetooth_nimble.c b/extmod/modbluetooth_nimble.c index c09f1cd2de..d873368581 100644 --- a/extmod/modbluetooth_nimble.c +++ b/extmod/modbluetooth_nimble.c @@ -440,7 +440,7 @@ static int characteristic_access_cb(uint16_t conn_handle, uint16_t value_handle, return BLE_ATT_ERR_UNLIKELY; } -int mp_bluetooth_gatts_register_service_begin(bool reset) { +int mp_bluetooth_gatts_register_service_begin(bool append) { int ret = ble_gatts_reset(); if (ret != 0) { return ble_hs_err_to_errno(ret); @@ -452,7 +452,13 @@ int mp_bluetooth_gatts_register_service_begin(bool reset) { // By default, just register the default gap service. ble_svc_gap_init(); - MP_STATE_PORT(bluetooth_nimble_root_pointers)->n_services = 0; + if (!append) { + // Unref any previous service definitions. + for (int i = 0; i < MP_STATE_PORT(bluetooth_nimble_root_pointers)->n_services; ++i) { + MP_STATE_PORT(bluetooth_nimble_root_pointers)->services[i] = NULL; + } + MP_STATE_PORT(bluetooth_nimble_root_pointers)->n_services = 0; + } return 0; } @@ -463,11 +469,6 @@ int mp_bluetooth_gatts_register_service_end() { return ble_hs_err_to_errno(ret); } - for (int i = 0; i < MP_STATE_PORT(bluetooth_nimble_root_pointers)->n_services; ++i) { - MP_STATE_PORT(bluetooth_nimble_root_pointers)->services[i] = NULL; - } - MP_STATE_PORT(bluetooth_nimble_root_pointers)->n_services = 0; - return 0; } From 2c1f269918331a50678119410219e965fcdb822e Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 22 Oct 2019 01:03:17 +1100 Subject: [PATCH 0883/1788] extmod/modbluetooth_nimble: Use `data_alloc` length to truncate writes. This allows the maximum size of a characteristic/descriptor to be increased by locally writing to it first. --- extmod/modbluetooth_nimble.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extmod/modbluetooth_nimble.c b/extmod/modbluetooth_nimble.c index d873368581..6287ca89ee 100644 --- a/extmod/modbluetooth_nimble.c +++ b/extmod/modbluetooth_nimble.c @@ -430,7 +430,7 @@ static int characteristic_access_cb(uint16_t conn_handle, uint16_t value_handle, return BLE_ATT_ERR_ATTR_NOT_FOUND; } entry = MP_OBJ_TO_PTR(elem->value); - entry->data_len = MIN(MP_BLUETOOTH_MAX_ATTR_SIZE, OS_MBUF_PKTLEN(ctxt->om)); + entry->data_len = MIN(entry->data_alloc, OS_MBUF_PKTLEN(ctxt->om)); os_mbuf_copydata(ctxt->om, 0, entry->data_len, entry->data); mp_bluetooth_gatts_on_write(conn_handle, value_handle); From 9c5262f25ef29950da241380c76e035b3a8cec38 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 22 Oct 2019 01:04:48 +1100 Subject: [PATCH 0884/1788] examples/bluetooth/ble_uart_peripheral.py: Add usage demo. --- examples/bluetooth/ble_uart_peripheral.py | 28 +++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/examples/bluetooth/ble_uart_peripheral.py b/examples/bluetooth/ble_uart_peripheral.py index 3508a15e7b..90cdbcaf52 100644 --- a/examples/bluetooth/ble_uart_peripheral.py +++ b/examples/bluetooth/ble_uart_peripheral.py @@ -75,5 +75,29 @@ class BLEUART: self._ble.gap_advertise(interval_us, adv_data=self._payload) -# ble = bluetooth.BLE() -# uart = BLEUART(ble) +def demo(): + import time + + ble = bluetooth.BLE() + uart = BLEUART(ble) + + def on_rx(): + print('rx: ', uart.read().decode().strip()) + + uart.irq(handler=on_rx) + nums = [4, 8, 15, 16, 23, 42] + i = 0 + + try: + while True: + uart.write(str(nums[i]) + '\n') + i = (i + 1) % len(nums) + time.sleep_ms(1000) + except KeyboardInterrupt: + pass + + uart.close() + + +if __name__ == '__main__': + demo() From d2384efa809953152c57cbda4c339dfbaa64cf29 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 22 Oct 2019 01:06:34 +1100 Subject: [PATCH 0885/1788] py: Automatically provide weak links from "foo" to "ufoo" module name. This commit implements automatic module weak links for all built-in modules, by searching for "ufoo" in the built-in module list if "foo" cannot be found. This means that all modules named "ufoo" are always available as "foo". Also, a port can no longer add any other weak links, which makes strict the definition of a weak link. It saves some code size (about 100-200 bytes) on ports that previously had lots of weak links. Some changes from the previous behaviour: - It doesn't intern the non-u module names (eg "foo" is not interned), which saves code size, but will mean that "import foo" creates a new qstr (namely "foo") in RAM (unless the importing module is frozen). - help('modules') no longer lists non-u module names, only the u-variants; this reduces duplication in the help listing. Weak links are effectively the same as having a set of symbolic links on the filesystem that is searched last. So an "import foo" will search built-in modules first, then all paths in sys.path, then weak links last, importing "ufoo" if it exists. Thus a file called "foo.py" somewhere in sys.path will still have precedence over the weak link of "foo" to "ufoo". See issues: #1740, #4449, #5229, #5241. --- ports/cc3200/mpconfigport.h | 13 ------------- ports/esp32/mpconfigport.h | 18 ------------------ ports/esp8266/mpconfigport.h | 17 ----------------- ports/javascript/mpconfigport.h | 15 --------------- ports/nrf/mpconfigport.h | 4 ---- ports/stm32/mpconfigport.h | 28 ---------------------------- ports/zephyr/mpconfigport.h | 6 ------ py/builtinhelp.c | 4 ---- py/builtinimport.c | 27 ++++++++++++--------------- py/mpconfig.h | 5 ----- py/objmodule.c | 26 +++++++++++++++++--------- py/objmodule.h | 4 +++- 12 files changed, 32 insertions(+), 135 deletions(-) diff --git a/ports/cc3200/mpconfigport.h b/ports/cc3200/mpconfigport.h index e7894dd023..d5c3c07e43 100644 --- a/ports/cc3200/mpconfigport.h +++ b/ports/cc3200/mpconfigport.h @@ -169,19 +169,6 @@ extern const struct _mp_obj_module_t mp_module_ussl; { MP_ROM_QSTR(MP_QSTR_ubinascii), MP_ROM_PTR(&mp_module_ubinascii) }, \ { MP_ROM_QSTR(MP_QSTR_ussl), MP_ROM_PTR(&mp_module_ussl) }, \ -#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \ - { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mp_module_uerrno) }, \ - { MP_ROM_QSTR(MP_QSTR_struct), MP_ROM_PTR(&mp_module_ustruct) }, \ - { MP_ROM_QSTR(MP_QSTR_re), MP_ROM_PTR(&mp_module_ure) }, \ - { MP_ROM_QSTR(MP_QSTR_json), MP_ROM_PTR(&mp_module_ujson) }, \ - { MP_ROM_QSTR(MP_QSTR_os), MP_ROM_PTR(&mp_module_uos) }, \ - { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mp_module_utime) }, \ - { MP_ROM_QSTR(MP_QSTR_select), MP_ROM_PTR(&mp_module_uselect) }, \ - { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&mp_module_usocket) }, \ - { MP_ROM_QSTR(MP_QSTR_binascii), MP_ROM_PTR(&mp_module_ubinascii) }, \ - { MP_ROM_QSTR(MP_QSTR_ssl), MP_ROM_PTR(&mp_module_ussl) }, \ - { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&machine_module) }, \ - // extra constants #define MICROPY_PORT_CONSTANTS \ { MP_ROM_QSTR(MP_QSTR_umachine), MP_ROM_PTR(&machine_module) }, \ diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 5c9d602abc..89e5373472 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -212,24 +212,6 @@ extern const struct _mp_obj_module_t mp_module_onewire; { 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 }, \ - { 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 struct _machine_timer_obj_t; diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h index e77f88c83c..7263193928 100644 --- a/ports/esp8266/mpconfigport.h +++ b/ports/esp8266/mpconfigport.h @@ -167,23 +167,6 @@ extern const struct _mp_obj_module_t mp_module_onewire; { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&mp_module_machine) }, \ { MP_ROM_QSTR(MP_QSTR__onewire), MP_ROM_PTR(&mp_module_onewire) }, \ -#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \ - { 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 #define MICROPY_PORT_ROOT_POINTERS \ diff --git a/ports/javascript/mpconfigport.h b/ports/javascript/mpconfigport.h index 02d83f402d..8ea43d84ce 100644 --- a/ports/javascript/mpconfigport.h +++ b/ports/javascript/mpconfigport.h @@ -131,21 +131,6 @@ extern const struct _mp_obj_module_t mp_module_utime; #define MICROPY_PORT_BUILTIN_MODULES \ { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_utime) }, \ -#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \ - { 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_re), MP_ROM_PTR(&mp_module_ure) }, \ - { MP_ROM_QSTR(MP_QSTR_zlib), MP_ROM_PTR(&mp_module_uzlib) }, \ - { MP_ROM_QSTR(MP_QSTR_json), MP_ROM_PTR(&mp_module_ujson) }, \ - { MP_ROM_QSTR(MP_QSTR_heapq), MP_ROM_PTR(&mp_module_uheapq) }, \ - { 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_random), MP_ROM_PTR(&mp_module_urandom) }, \ - { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mp_module_utime) }, \ - { MP_ROM_QSTR(MP_QSTR_select), MP_ROM_PTR(&mp_module_uselect) }, \ - { MP_ROM_QSTR(MP_QSTR_struct), MP_ROM_PTR(&mp_module_ustruct) }, \ - { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mp_module_uerrno) }, \ - //#define MICROPY_EVENT_POLL_HOOK {ets_event_poll();} #if MICROPY_PY_THREAD #define MICROPY_EVENT_POLL_HOOK \ diff --git a/ports/nrf/mpconfigport.h b/ports/nrf/mpconfigport.h index da9a03e1d0..71f9f6804d 100644 --- a/ports/nrf/mpconfigport.h +++ b/ports/nrf/mpconfigport.h @@ -281,10 +281,6 @@ extern const struct _mp_obj_module_t ble_module; #endif // BLUETOOTH_SD -#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \ - { MP_ROM_QSTR(MP_QSTR_os), MP_ROM_PTR(&mp_module_uos) }, \ - { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mp_module_utime) }, \ - // extra built in names to add to the global namespace #define MICROPY_PORT_BUILTINS \ { MP_ROM_QSTR(MP_QSTR_help), MP_ROM_PTR(&mp_builtin_help_obj) }, \ diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 5806755116..2cc37e3bf2 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -223,21 +223,12 @@ extern const struct _mp_obj_module_t mp_module_onewire; #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) }, #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) }, #else // no usocket module #define SOCKET_BUILTIN_MODULE -#define SOCKET_BUILTIN_MODULE_WEAK_LINKS -#endif - -#if MICROPY_PY_USSL -#define SSL_BUILTIN_MODULE_WEAK_LINKS { MP_ROM_QSTR(MP_QSTR_ssl), MP_ROM_PTR(&mp_module_ussl) }, -#else -#define SSL_BUILTIN_MODULE_WEAK_LINKS #endif #if MICROPY_PY_NETWORK @@ -263,25 +254,6 @@ extern const struct _mp_obj_module_t mp_module_onewire; BLUETOOTH_BUILTIN_MODULE \ { MP_ROM_QSTR(MP_QSTR__onewire), MP_ROM_PTR(&mp_module_onewire) }, \ -#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \ - { 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_re), MP_ROM_PTR(&mp_module_ure) }, \ - { MP_ROM_QSTR(MP_QSTR_zlib), MP_ROM_PTR(&mp_module_uzlib) }, \ - { MP_ROM_QSTR(MP_QSTR_json), MP_ROM_PTR(&mp_module_ujson) }, \ - { MP_ROM_QSTR(MP_QSTR_heapq), MP_ROM_PTR(&mp_module_uheapq) }, \ - { 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_os), MP_ROM_PTR(&mp_module_uos) }, \ - { MP_ROM_QSTR(MP_QSTR_random), MP_ROM_PTR(&mp_module_urandom) }, \ - { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mp_module_utime) }, \ - { MP_ROM_QSTR(MP_QSTR_select), MP_ROM_PTR(&mp_module_uselect) }, \ - SOCKET_BUILTIN_MODULE_WEAK_LINKS \ - SSL_BUILTIN_MODULE_WEAK_LINKS \ - { MP_ROM_QSTR(MP_QSTR_struct), MP_ROM_PTR(&mp_module_ustruct) }, \ - { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&machine_module) }, \ - { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mp_module_uerrno) }, \ - // extra constants #define MICROPY_PORT_CONSTANTS \ { MP_ROM_QSTR(MP_QSTR_umachine), MP_ROM_PTR(&machine_module) }, \ diff --git a/ports/zephyr/mpconfigport.h b/ports/zephyr/mpconfigport.h index 0b35de35b7..1ca357756c 100644 --- a/ports/zephyr/mpconfigport.h +++ b/ports/zephyr/mpconfigport.h @@ -119,10 +119,8 @@ 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) }, -#define MICROPY_PY_USOCKET_WEAK_DEF { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&mp_module_usocket) }, #else #define MICROPY_PY_USOCKET_DEF -#define MICROPY_PY_USOCKET_WEAK_DEF #endif #if MICROPY_PY_UTIME @@ -150,10 +148,6 @@ extern const struct _mp_obj_module_t mp_module_zsensor; 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) }, \ - MICROPY_PY_USOCKET_WEAK_DEF \ - // extra built in names to add to the global namespace #define MICROPY_PORT_BUILTINS \ diff --git a/py/builtinhelp.c b/py/builtinhelp.c index a7fede00ac..8f162d8858 100644 --- a/py/builtinhelp.c +++ b/py/builtinhelp.c @@ -80,10 +80,6 @@ STATIC void mp_help_print_modules(void) { mp_help_add_from_map(list, &mp_builtin_module_map); - #if MICROPY_MODULE_WEAK_LINKS - mp_help_add_from_map(list, &mp_builtin_module_weak_links_map); - #endif - #if MICROPY_MODULE_FROZEN_STR extern const char mp_frozen_str_names[]; mp_help_add_from_names(list, mp_frozen_str_names); diff --git a/py/builtinimport.c b/py/builtinimport.c index 008a21dcff..b9f6c2ab2d 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2013-2019 Damien P. George * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -381,21 +381,18 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { DEBUG_printf("Current path: %.*s\n", vstr_len(&path), vstr_str(&path)); if (stat == MP_IMPORT_STAT_NO_EXIST) { + module_obj = MP_OBJ_NULL; #if MICROPY_MODULE_WEAK_LINKS // check if there is a weak link to this module if (i == mod_len) { - mp_map_elem_t *el = mp_map_lookup((mp_map_t*)&mp_builtin_module_weak_links_map, MP_OBJ_NEW_QSTR(mod_name), MP_MAP_LOOKUP); - if (el == NULL) { - goto no_exist; + module_obj = mp_module_search_umodule(mod_str); + if (module_obj != MP_OBJ_NULL) { + // found weak linked module + mp_module_call_init(mod_name, module_obj); } - // found weak linked module - module_obj = el->value; - mp_module_call_init(mod_name, module_obj); - } else { - no_exist: - #else - { + } #endif + if (module_obj == MP_OBJ_NULL) { // couldn't find the file, so fail if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_msg(&mp_type_ImportError, "module not found"); @@ -492,11 +489,11 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { #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) { + module_obj = mp_module_search_umodule(qstr_str(module_name_qstr)); + if (module_obj != MP_OBJ_NULL) { // Found weak-linked module - mp_module_call_init(module_name_qstr, el->value); - return el->value; + mp_module_call_init(module_name_qstr, module_obj); + return module_obj; } #endif diff --git a/py/mpconfig.h b/py/mpconfig.h index 4172b5fcfe..e46da3e83c 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -1392,11 +1392,6 @@ typedef double mp_float_t; #define MICROPY_PORT_BUILTIN_MODULES #endif -// Any module weak links - see objmodule.c:mp_builtin_module_weak_links_table. -#ifndef MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS -#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS -#endif - // Additional constant definitions for the compiler - see compile.c:mp_constants_table. #ifndef MICROPY_PORT_CONSTANTS #define MICROPY_PORT_CONSTANTS diff --git a/py/objmodule.c b/py/objmodule.c index 4a07913c5e..d725bb6a14 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2013-2019 Damien P. George * Copyright (c) 2014-2015 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -26,6 +26,7 @@ */ #include +#include #include #include "py/objmodule.h" @@ -235,14 +236,6 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = { MP_DEFINE_CONST_MAP(mp_builtin_module_map, mp_builtin_module_table); -#if MICROPY_MODULE_WEAK_LINKS -STATIC const mp_rom_map_elem_t mp_builtin_module_weak_links_table[] = { - MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS -}; - -MP_DEFINE_CONST_MAP(mp_builtin_module_weak_links_map, mp_builtin_module_weak_links_table); -#endif - // returns MP_OBJ_NULL if not found mp_obj_t mp_module_get(qstr module_name) { mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map; @@ -267,6 +260,21 @@ void mp_module_register(qstr qst, mp_obj_t module) { mp_map_lookup(mp_loaded_modules_map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = module; } +#if MICROPY_MODULE_WEAK_LINKS +// Search for u"foo" in built-in modules, return MP_OBJ_NULL if not found +mp_obj_t mp_module_search_umodule(const char *module_str) { + for (size_t i = 0; i < MP_ARRAY_SIZE(mp_builtin_module_table); ++i) { + const mp_map_elem_t *entry = (const mp_map_elem_t*)&mp_builtin_module_table[i]; + const char *key = qstr_str(MP_OBJ_QSTR_VALUE(entry->key)); + if (key[0] == 'u' && strcmp(&key[1], module_str) == 0) { + return (mp_obj_t)entry->value; + } + + } + return MP_OBJ_NULL; +} +#endif + #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 diff --git a/py/objmodule.h b/py/objmodule.h index b7702ec50b..33a0ff07e1 100644 --- a/py/objmodule.h +++ b/py/objmodule.h @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2013-2019 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 @@ -34,6 +34,8 @@ 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); +mp_obj_t mp_module_search_umodule(const char *module_str); + #if MICROPY_MODULE_BUILTIN_INIT void mp_module_call_init(qstr module_name, mp_obj_t module_obj); #else From 1582c7eeb0707acc5d645c0a5a9e59d14ff7c8be Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 22 Oct 2019 01:08:27 +1100 Subject: [PATCH 0886/1788] unix,windows: Enable module weak links. --- ports/unix/mpconfigport.h | 1 + ports/windows/mpconfigport.h | 1 + 2 files changed, 2 insertions(+) diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h index 1bb80f9704..e42ad5e49c 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -70,6 +70,7 @@ #ifndef MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE #define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (1) #endif +#define MICROPY_MODULE_WEAK_LINKS (1) #define MICROPY_CAN_OVERRIDE_BUILTINS (1) #define MICROPY_PY_FUNCTION_ATTRS (1) #define MICROPY_PY_DESCRIPTORS (1) diff --git a/ports/windows/mpconfigport.h b/ports/windows/mpconfigport.h index 1a9842609a..fae01d74ee 100644 --- a/ports/windows/mpconfigport.h +++ b/ports/windows/mpconfigport.h @@ -60,6 +60,7 @@ #define MICROPY_STREAMS_POSIX_API (1) #define MICROPY_OPT_COMPUTED_GOTO (0) #define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (1) +#define MICROPY_MODULE_WEAK_LINKS (1) #define MICROPY_CAN_OVERRIDE_BUILTINS (1) #define MICROPY_PY_FUNCTION_ATTRS (1) #define MICROPY_PY_DESCRIPTORS (1) From 21a60935a5d5885817881b4f690fdfd3ef009100 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 22 Oct 2019 16:35:46 +1100 Subject: [PATCH 0887/1788] py/modarray: Rename "array" module to "uarray". Following the other modules like ustruct, ucollections. See issues #4370 and #4449. --- py/builtin.h | 2 +- py/modarray.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/py/builtin.h b/py/builtin.h index a5e0f5f2d0..1928577be8 100644 --- a/py/builtin.h +++ b/py/builtin.h @@ -89,7 +89,7 @@ MP_DECLARE_CONST_FUN_OBJ_2(mp_op_delitem_obj); extern const mp_obj_module_t mp_module___main__; extern const mp_obj_module_t mp_module_builtins; -extern const mp_obj_module_t mp_module_array; +extern const mp_obj_module_t mp_module_uarray; extern const mp_obj_module_t mp_module_collections; extern const mp_obj_module_t mp_module_io; extern const mp_obj_module_t mp_module_math; diff --git a/py/modarray.c b/py/modarray.c index de84fc8587..b459a83756 100644 --- a/py/modarray.c +++ b/py/modarray.c @@ -29,17 +29,17 @@ #if MICROPY_PY_ARRAY STATIC const mp_rom_map_elem_t mp_module_array_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_array) }, + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uarray) }, { MP_ROM_QSTR(MP_QSTR_array), MP_ROM_PTR(&mp_type_array) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_array_globals, mp_module_array_globals_table); -const mp_obj_module_t mp_module_array = { +const mp_obj_module_t mp_module_uarray = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_array_globals, }; -MP_REGISTER_MODULE(MP_QSTR_array, mp_module_array, MICROPY_PY_ARRAY); +MP_REGISTER_MODULE(MP_QSTR_uarray, mp_module_uarray, MICROPY_PY_ARRAY); #endif From a2eea57b1d5456696598703aa4ffdbc7e9fb52ea Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 22 Oct 2019 16:40:58 +1100 Subject: [PATCH 0888/1788] docs/library: Rename "array" module to "uarray". --- docs/library/index.rst | 2 +- docs/library/{array.rst => uarray.rst} | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) rename docs/library/{array.rst => uarray.rst} (82%) diff --git a/docs/library/index.rst b/docs/library/index.rst index dc89766e2d..223304881a 100644 --- a/docs/library/index.rst +++ b/docs/library/index.rst @@ -74,12 +74,12 @@ it will fallback to loading the built-in ``ujson`` module. :maxdepth: 1 builtins.rst - array.rst bluetooth.rst cmath.rst gc.rst math.rst sys.rst + uarray.rst ubinascii.rst ucollections.rst uerrno.rst diff --git a/docs/library/array.rst b/docs/library/uarray.rst similarity index 82% rename from docs/library/array.rst rename to docs/library/uarray.rst index f837b03436..9fa82ff31b 100644 --- a/docs/library/array.rst +++ b/docs/library/uarray.rst @@ -1,7 +1,7 @@ -:mod:`array` -- arrays of numeric data -====================================== +:mod:`uarray` -- arrays of numeric data +======================================= -.. module:: array +.. module:: uarray :synopsis: efficient arrays of numeric data |see_cpython_module| :mod:`python:array`. @@ -13,7 +13,7 @@ floating-point support). Classes ------- -.. class:: array.array(typecode, [iterable]) +.. class:: array(typecode, [iterable]) Create array with elements of given type. Initial contents of the array are given by *iterable*. If it is not provided, an empty From 30e25174bbf077e8a3cbe2a3a6a97795f8d67dc2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 22 Oct 2019 17:33:23 +1100 Subject: [PATCH 0889/1788] tests: Rename "array" module to "uarray". --- tests/basics/array1.py | 9 ++++++--- tests/basics/array_add.py | 9 ++++++--- tests/basics/array_construct.py | 9 ++++++--- tests/basics/array_construct2.py | 9 ++++++--- tests/basics/array_construct_endian.py | 9 ++++++--- tests/basics/array_intbig.py | 9 ++++++--- tests/basics/array_micropython.py | 9 ++++++--- tests/basics/bytearray_construct_array.py | 9 ++++++--- tests/basics/bytearray_construct_endian.py | 9 ++++++--- tests/basics/bytes_add_array.py | 9 ++++++--- tests/basics/bytes_add_endian.py | 9 ++++++--- tests/basics/bytes_compare_array.py | 9 ++++++--- tests/basics/bytes_construct_array.py | 9 ++++++--- tests/basics/bytes_construct_endian.py | 9 ++++++--- tests/basics/memoryview1.py | 9 ++++++++- tests/basics/memoryview2.py | 9 ++++++++- tests/basics/memoryview_intbig.py | 9 ++++++++- tests/basics/memoryview_itemsize.py | 9 ++++++++- tests/float/array_construct.py | 9 ++++++--- tests/float/bytearray_construct.py | 9 ++++++--- tests/float/bytes_construct.py | 9 ++++++--- tests/float/float_array.py | 9 ++++++--- tests/inlineasm/asmfpldrstr.py | 2 +- tests/inlineasm/asmsum.py | 2 +- tests/micropython/heapalloc_iter.py | 11 +++++++++-- tests/misc/non_compliant.py | 2 +- 26 files changed, 152 insertions(+), 63 deletions(-) diff --git a/tests/basics/array1.py b/tests/basics/array1.py index bad879035c..3370c240d3 100644 --- a/tests/basics/array1.py +++ b/tests/basics/array1.py @@ -1,8 +1,11 @@ try: - import array + import uarray as array except ImportError: - print("SKIP") - raise SystemExit + try: + import array + except ImportError: + print("SKIP") + raise SystemExit a = array.array('B', [1, 2, 3]) print(a, len(a)) diff --git a/tests/basics/array_add.py b/tests/basics/array_add.py index 76ce59f761..8335eb6b82 100644 --- a/tests/basics/array_add.py +++ b/tests/basics/array_add.py @@ -1,9 +1,12 @@ # test array + array try: - import array + import uarray as array except ImportError: - print("SKIP") - raise SystemExit + try: + import array + except ImportError: + print("SKIP") + raise SystemExit a1 = array.array('I', [1]) a2 = array.array('I', [2]) diff --git a/tests/basics/array_construct.py b/tests/basics/array_construct.py index 2221de9906..4985244d13 100644 --- a/tests/basics/array_construct.py +++ b/tests/basics/array_construct.py @@ -1,10 +1,13 @@ # test construction of array.array from different objects try: - from array import array + from uarray import array except ImportError: - print("SKIP") - raise SystemExit + try: + from array import array + except ImportError: + print("SKIP") + raise SystemExit # tuple, list print(array('b', (1, 2))) diff --git a/tests/basics/array_construct2.py b/tests/basics/array_construct2.py index c305b7f011..d1b1e9d158 100644 --- a/tests/basics/array_construct2.py +++ b/tests/basics/array_construct2.py @@ -1,8 +1,11 @@ try: - from array import array + from uarray import array except ImportError: - print("SKIP") - raise SystemExit + try: + from array import array + except ImportError: + print("SKIP") + raise SystemExit # construct from something with unknown length (requires generators) print(array('i', (i for i in range(10)))) diff --git a/tests/basics/array_construct_endian.py b/tests/basics/array_construct_endian.py index 990d7b1ea0..82a962fbe0 100644 --- a/tests/basics/array_construct_endian.py +++ b/tests/basics/array_construct_endian.py @@ -1,10 +1,13 @@ # test construction of array.array from different objects try: - from array import array + from uarray import array except ImportError: - print("SKIP") - raise SystemExit + try: + from array import array + except ImportError: + print("SKIP") + raise SystemExit # raw copy from bytes, bytearray print(array('h', b'12')) diff --git a/tests/basics/array_intbig.py b/tests/basics/array_intbig.py index 5702a8ae63..ba7f9ef985 100644 --- a/tests/basics/array_intbig.py +++ b/tests/basics/array_intbig.py @@ -1,10 +1,13 @@ # test array types QqLl that require big-ints try: - from array import array + from uarray import array except ImportError: - print("SKIP") - raise SystemExit + try: + from array import array + except ImportError: + print("SKIP") + raise SystemExit print(array('L', [0, 2**32-1])) print(array('l', [-2**31, 0, 2**31-1])) diff --git a/tests/basics/array_micropython.py b/tests/basics/array_micropython.py index e26ad7ae96..6b3dc7a93b 100644 --- a/tests/basics/array_micropython.py +++ b/tests/basics/array_micropython.py @@ -1,9 +1,12 @@ # test MicroPython-specific features of array.array try: - import array + import uarray as array except ImportError: - print("SKIP") - raise SystemExit + try: + import array + except ImportError: + print("SKIP") + raise SystemExit # arrays of objects a = array.array('O') diff --git a/tests/basics/bytearray_construct_array.py b/tests/basics/bytearray_construct_array.py index bde5fa08bd..52eaa7c6ef 100644 --- a/tests/basics/bytearray_construct_array.py +++ b/tests/basics/bytearray_construct_array.py @@ -1,9 +1,12 @@ # test construction of bytearray from different objects try: - from array import array + from uarray import array except ImportError: - print("SKIP") - raise SystemExit + try: + from array import array + except ImportError: + print("SKIP") + raise SystemExit # arrays print(bytearray(array('b', [1, 2]))) diff --git a/tests/basics/bytearray_construct_endian.py b/tests/basics/bytearray_construct_endian.py index 0002f19c5f..332b43e686 100644 --- a/tests/basics/bytearray_construct_endian.py +++ b/tests/basics/bytearray_construct_endian.py @@ -1,9 +1,12 @@ # test construction of bytearray from different objects try: - from array import array + from uarray import array except ImportError: - print("SKIP") - raise SystemExit + try: + from array import array + except ImportError: + print("SKIP") + raise SystemExit # arrays print(bytearray(array('h', [1, 2]))) diff --git a/tests/basics/bytes_add_array.py b/tests/basics/bytes_add_array.py index b17556d83c..c6382bed74 100644 --- a/tests/basics/bytes_add_array.py +++ b/tests/basics/bytes_add_array.py @@ -1,9 +1,12 @@ # test bytes + other try: - import array + import uarray as array except ImportError: - print("SKIP") - raise SystemExit + try: + import array + except ImportError: + print("SKIP") + raise SystemExit # should be byteorder-neutral print(b"123" + array.array('h', [0x1515])) diff --git a/tests/basics/bytes_add_endian.py b/tests/basics/bytes_add_endian.py index 8cfffa7b6a..40b3de7d61 100644 --- a/tests/basics/bytes_add_endian.py +++ b/tests/basics/bytes_add_endian.py @@ -1,8 +1,11 @@ # test bytes + other try: - import array + import uarray as array except ImportError: - print("SKIP") - raise SystemExit + try: + import array + except ImportError: + print("SKIP") + raise SystemExit print(b"123" + array.array('i', [1])) diff --git a/tests/basics/bytes_compare_array.py b/tests/basics/bytes_compare_array.py index ad378de70c..6bad50b55a 100644 --- a/tests/basics/bytes_compare_array.py +++ b/tests/basics/bytes_compare_array.py @@ -1,8 +1,11 @@ try: - import array + import uarray as array except ImportError: - print("SKIP") - raise SystemExit + try: + import array + except ImportError: + print("SKIP") + raise SystemExit print(array.array('b', [1, 2]) in b'\x01\x02\x03') # CPython gives False here diff --git a/tests/basics/bytes_construct_array.py b/tests/basics/bytes_construct_array.py index 453eb59010..7bdd8f10df 100644 --- a/tests/basics/bytes_construct_array.py +++ b/tests/basics/bytes_construct_array.py @@ -1,9 +1,12 @@ # test construction of bytes from different objects try: - from array import array + from uarray import array except ImportError: - print("SKIP") - raise SystemExit + try: + from array import array + except ImportError: + print("SKIP") + raise SystemExit # arrays print(bytes(array('b', [1, 2]))) diff --git a/tests/basics/bytes_construct_endian.py b/tests/basics/bytes_construct_endian.py index cf1a9f408f..294c5f23f5 100644 --- a/tests/basics/bytes_construct_endian.py +++ b/tests/basics/bytes_construct_endian.py @@ -1,10 +1,13 @@ # test construction of bytes from different objects try: - from array import array + from uarray import array except ImportError: - print("SKIP") - raise SystemExit + try: + from array import array + except ImportError: + print("SKIP") + raise SystemExit # arrays print(bytes(array('h', [1, 2]))) diff --git a/tests/basics/memoryview1.py b/tests/basics/memoryview1.py index a0ac9e3449..b5314f3e99 100644 --- a/tests/basics/memoryview1.py +++ b/tests/basics/memoryview1.py @@ -4,6 +4,14 @@ try: except: print("SKIP") raise SystemExit +try: + import uarray as array +except ImportError: + try: + import array + except ImportError: + print("SKIP") + raise SystemExit # test reading from bytes b = b'1234' @@ -39,7 +47,6 @@ m = memoryview(bytearray(2)) print(bytearray(m)) print(list(memoryview(memoryview(b'1234')))) # read-only memoryview -import array a = array.array('i', [1, 2, 3, 4]) m = memoryview(a) print(list(m)) diff --git a/tests/basics/memoryview2.py b/tests/basics/memoryview2.py index 06a7be59fd..eacc227c28 100644 --- a/tests/basics/memoryview2.py +++ b/tests/basics/memoryview2.py @@ -1,10 +1,17 @@ # test memoryview accessing maximum values for signed/unsigned elements try: - from array import array memoryview except: print("SKIP") raise SystemExit +try: + from uarray import array +except ImportError: + try: + from array import array + except ImportError: + print("SKIP") + raise SystemExit print(list(memoryview(b'\x7f\x80\x81\xff'))) print(list(memoryview(array('b', [0x7f, -0x80])))) diff --git a/tests/basics/memoryview_intbig.py b/tests/basics/memoryview_intbig.py index a76d9cbec7..4800a70cc2 100644 --- a/tests/basics/memoryview_intbig.py +++ b/tests/basics/memoryview_intbig.py @@ -1,10 +1,17 @@ # test memoryview accessing maximum values for signed/unsigned elements try: - from array import array memoryview except: print("SKIP") raise SystemExit +try: + from uarray import array +except ImportError: + try: + from array import array + except ImportError: + print("SKIP") + raise SystemExit print(list(memoryview(array('i', [0x7f000000, -0x80000000])))) print(list(memoryview(array('I', [0x7f000000, 0x80000000, 0x81000000, 0xffffffff])))) diff --git a/tests/basics/memoryview_itemsize.py b/tests/basics/memoryview_itemsize.py index 60cb823087..cd7a87c23d 100644 --- a/tests/basics/memoryview_itemsize.py +++ b/tests/basics/memoryview_itemsize.py @@ -1,9 +1,16 @@ try: memoryview(b'a').itemsize - from array import array except: print("SKIP") raise SystemExit +try: + from uarray import array +except ImportError: + try: + from array import array + except ImportError: + print("SKIP") + raise SystemExit for code in ['b', 'h', 'i', 'l', 'q', 'f', 'd']: print(memoryview(array(code)).itemsize) diff --git a/tests/float/array_construct.py b/tests/float/array_construct.py index 938675835b..eb735c67c3 100644 --- a/tests/float/array_construct.py +++ b/tests/float/array_construct.py @@ -1,10 +1,13 @@ # test construction of array from array with float type try: - from array import array + from uarray import array except ImportError: - print("SKIP") - raise SystemExit + try: + from array import array + except ImportError: + print("SKIP") + raise SystemExit print(array('f', array('h', [1, 2]))) print(array('d', array('f', [1, 2]))) diff --git a/tests/float/bytearray_construct.py b/tests/float/bytearray_construct.py index e960d624ec..4e7631b2b9 100644 --- a/tests/float/bytearray_construct.py +++ b/tests/float/bytearray_construct.py @@ -1,9 +1,12 @@ # test construction of bytearray from array with float type try: - from array import array + from uarray import array except ImportError: - print("SKIP") - raise SystemExit + try: + from array import array + except ImportError: + print("SKIP") + raise SystemExit print(bytearray(array('f', [1, 2.3]))) diff --git a/tests/float/bytes_construct.py b/tests/float/bytes_construct.py index 0e4482e436..96294659bf 100644 --- a/tests/float/bytes_construct.py +++ b/tests/float/bytes_construct.py @@ -1,9 +1,12 @@ # test construction of bytearray from array with float type try: - from array import array + from uarray import array except ImportError: - print("SKIP") - raise SystemExit + try: + from array import array + except ImportError: + print("SKIP") + raise SystemExit print(bytes(array('f', [1, 2.3]))) diff --git a/tests/float/float_array.py b/tests/float/float_array.py index 8c8edcff7c..0c7f1b3ade 100644 --- a/tests/float/float_array.py +++ b/tests/float/float_array.py @@ -1,8 +1,11 @@ try: - from array import array + from uarray import array except ImportError: - print("SKIP") - raise SystemExit + try: + from array import array + except ImportError: + print("SKIP") + raise SystemExit def test(a): print(a) diff --git a/tests/inlineasm/asmfpldrstr.py b/tests/inlineasm/asmfpldrstr.py index 8fa9af6369..0efb50bb0e 100644 --- a/tests/inlineasm/asmfpldrstr.py +++ b/tests/inlineasm/asmfpldrstr.py @@ -1,4 +1,4 @@ -import array +import uarray as array @micropython.asm_thumb # test vldr, vstr def arrayadd(r0): vldr(s0, [r0, 0]) diff --git a/tests/inlineasm/asmsum.py b/tests/inlineasm/asmsum.py index 9cbd8418ea..93d8eec8dc 100644 --- a/tests/inlineasm/asmsum.py +++ b/tests/inlineasm/asmsum.py @@ -46,7 +46,7 @@ def asm_sum_bytes(r0, r1): mov(r0, r2) -import array +import uarray as array b = array.array('l', (100, 200, 300, 400)) n = asm_sum_words(len(b), b) diff --git a/tests/micropython/heapalloc_iter.py b/tests/micropython/heapalloc_iter.py index 163e172111..5a44a558bb 100644 --- a/tests/micropython/heapalloc_iter.py +++ b/tests/micropython/heapalloc_iter.py @@ -1,10 +1,17 @@ # test that iterating doesn't use the heap try: frozenset - import array -except (NameError, ImportError): +except NameError: print("SKIP") raise SystemExit +try: + import uarray as array +except ImportError: + try: + import array + except ImportError: + print("SKIP") + raise SystemExit try: from micropython import heap_lock, heap_unlock diff --git a/tests/misc/non_compliant.py b/tests/misc/non_compliant.py index 580583bf39..ea67382227 100644 --- a/tests/misc/non_compliant.py +++ b/tests/misc/non_compliant.py @@ -1,7 +1,7 @@ # tests for things that are not implemented, or have non-compliant behaviour try: - import array + import uarray as array import ustruct except ImportError: print("SKIP") From b02d7e612d12b507a3a91a95eb30187b24ce21a7 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 22 Oct 2019 17:03:59 +1100 Subject: [PATCH 0890/1788] extmod/modbluetooth: Rename module to "ubluetooth". For consistency with "umachine". Now that weak links are enabled by default for built-in modules, this should be a no-op, but allows extension of the bluetooth module by user code. Also move registration of ubluetooth to objmodule rather than port-specific. --- extmod/modbluetooth.c | 4 ++-- ports/esp32/mpconfigport.h | 8 -------- ports/stm32/mpconfigport.h | 8 -------- py/builtin.h | 1 + py/objmodule.c | 3 +++ 5 files changed, 6 insertions(+), 18 deletions(-) diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index 2a3e87bc24..d1a7d576e1 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -645,7 +645,7 @@ STATIC const mp_obj_type_t bluetooth_ble_type = { }; STATIC const mp_rom_map_elem_t mp_module_bluetooth_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bluetooth) }, + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ubluetooth) }, { MP_ROM_QSTR(MP_QSTR_BLE), MP_ROM_PTR(&bluetooth_ble_type) }, { MP_ROM_QSTR(MP_QSTR_UUID), MP_ROM_PTR(&bluetooth_uuid_type) }, { MP_ROM_QSTR(MP_QSTR_FLAG_READ), MP_ROM_INT(MP_BLUETOOTH_CHARACTERISTIC_FLAG_READ) }, @@ -655,7 +655,7 @@ STATIC const mp_rom_map_elem_t mp_module_bluetooth_globals_table[] = { STATIC MP_DEFINE_CONST_DICT(mp_module_bluetooth_globals, mp_module_bluetooth_globals_table); -const mp_obj_module_t mp_module_bluetooth = { +const mp_obj_module_t mp_module_ubluetooth = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_bluetooth_globals, }; diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 89e5373472..6cf86446b2 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -191,15 +191,8 @@ 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_bluetooth; extern const struct _mp_obj_module_t mp_module_onewire; -#if MICROPY_PY_BLUETOOTH -#define BLUETOOTH_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_bluetooth), MP_ROM_PTR(&mp_module_bluetooth) }, -#else -#define BLUETOOTH_BUILTIN_MODULE -#endif - #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 }, \ @@ -208,7 +201,6 @@ extern const struct _mp_obj_module_t mp_module_onewire; { 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 }, \ - BLUETOOTH_BUILTIN_MODULE \ { 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 }, \ diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 2cc37e3bf2..b31eed2932 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -211,7 +211,6 @@ extern const struct _mp_obj_module_t mp_module_uos; extern const struct _mp_obj_module_t mp_module_utime; 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_bluetooth; extern const struct _mp_obj_module_t mp_module_onewire; #if MICROPY_PY_STM @@ -237,12 +236,6 @@ extern const struct _mp_obj_module_t mp_module_onewire; #define NETWORK_BUILTIN_MODULE #endif -#if MICROPY_PY_BLUETOOTH -#define BLUETOOTH_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_bluetooth), MP_ROM_PTR(&mp_module_bluetooth) }, -#else -#define BLUETOOTH_BUILTIN_MODULE -#endif - #define MICROPY_PORT_BUILTIN_MODULES \ { MP_ROM_QSTR(MP_QSTR_umachine), MP_ROM_PTR(&machine_module) }, \ { MP_ROM_QSTR(MP_QSTR_pyb), MP_ROM_PTR(&pyb_module) }, \ @@ -251,7 +244,6 @@ extern const struct _mp_obj_module_t mp_module_onewire; { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_utime) }, \ SOCKET_BUILTIN_MODULE \ NETWORK_BUILTIN_MODULE \ - BLUETOOTH_BUILTIN_MODULE \ { MP_ROM_QSTR(MP_QSTR__onewire), MP_ROM_PTR(&mp_module_onewire) }, \ // extra constants diff --git a/py/builtin.h b/py/builtin.h index 1928577be8..2dbe8a7820 100644 --- a/py/builtin.h +++ b/py/builtin.h @@ -122,6 +122,7 @@ extern const mp_obj_module_t mp_module_uwebsocket; extern const mp_obj_module_t mp_module_webrepl; extern const mp_obj_module_t mp_module_framebuf; extern const mp_obj_module_t mp_module_btree; +extern const mp_obj_module_t mp_module_ubluetooth; extern const char MICROPY_PY_BUILTINS_HELP_TEXT[]; diff --git a/py/objmodule.c b/py/objmodule.c index d725bb6a14..81558a02ef 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -224,6 +224,9 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = { #if MICROPY_PY_BTREE { MP_ROM_QSTR(MP_QSTR_btree), MP_ROM_PTR(&mp_module_btree) }, #endif +#if MICROPY_PY_BLUETOOTH + { MP_ROM_QSTR(MP_QSTR_ubluetooth), MP_ROM_PTR(&mp_module_ubluetooth) }, +#endif // extra builtin modules as defined by a port MICROPY_PORT_BUILTIN_MODULES From 19e87742c41e7732258ea06406039be7a734e890 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 22 Oct 2019 17:05:36 +1100 Subject: [PATCH 0891/1788] docs/library/bluetooth: Rename to "ubluetooth". --- docs/library/index.rst | 2 +- docs/library/{bluetooth.rst => ubluetooth.rst} | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) rename docs/library/{bluetooth.rst => ubluetooth.rst} (96%) diff --git a/docs/library/index.rst b/docs/library/index.rst index 223304881a..a2d11dee7f 100644 --- a/docs/library/index.rst +++ b/docs/library/index.rst @@ -74,13 +74,13 @@ it will fallback to loading the built-in ``ujson`` module. :maxdepth: 1 builtins.rst - bluetooth.rst cmath.rst gc.rst math.rst sys.rst uarray.rst ubinascii.rst + ubluetooth.rst ucollections.rst uerrno.rst uhashlib.rst diff --git a/docs/library/bluetooth.rst b/docs/library/ubluetooth.rst similarity index 96% rename from docs/library/bluetooth.rst rename to docs/library/ubluetooth.rst index e672cef927..831c64a95f 100644 --- a/docs/library/bluetooth.rst +++ b/docs/library/ubluetooth.rst @@ -1,7 +1,7 @@ -:mod:`bluetooth` --- low-level Bluetooth -======================================== +:mod:`ubluetooth` --- low-level Bluetooth +========================================= -.. module:: bluetooth +.. module:: ubluetooth :synopsis: Low-level Bluetooth radio functionality This module provides an interface to a Bluetooth controller on a board. @@ -123,7 +123,7 @@ The event codes are:: _IRQ_GATTC_INDICATE = const(1 << 14) In order to save space in the firmware, these constants are not included on the -:mod:`bluetooth` module. Add the ones that you need from the list above to your +:mod:`ubluetooth` module. Add the ones that you need from the list above to your program. @@ -203,8 +203,8 @@ writes from a central to a given characteristic, use value. The **flags** are a bitwise-OR combination of the - :data:`bluetooth.FLAGS_READ`, :data:`bluetooth.FLAGS_WRITE` and - :data:`bluetooth.FLAGS_NOTIFY` values defined below. + :data:`ubluetooth.FLAGS_READ`, :data:`bluetooth.FLAGS_WRITE` and + :data:`ubluetooth.FLAGS_NOTIFY` values defined below. The return value is a list (one element per service) of tuples (each element is a value handle). Characteristics and descriptor handles are flattened @@ -321,6 +321,6 @@ Constructor Constants --------- -.. data:: bluetooth.FLAG_READ - bluetooth.FLAG_WRITE - bluetooth.FLAG_NOTIFY +.. data:: ubluetooth.FLAG_READ + ubluetooth.FLAG_WRITE + ubluetooth.FLAG_NOTIFY From 19ca025b45b3160a2ad5a20014cdd7bf0053ff9d Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Mon, 21 Oct 2019 11:43:22 +1100 Subject: [PATCH 0892/1788] stm32/sdram: Fix to use new mpu_config_start/mpu_config_end signature. --- ports/stm32/sdram.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/stm32/sdram.c b/ports/stm32/sdram.c index 5d54dc2cb3..7e7e1d7641 100644 --- a/ports/stm32/sdram.c +++ b/ports/stm32/sdram.c @@ -248,10 +248,10 @@ static void sdram_init_seq(SDRAM_HandleTypeDef Initially disable all access for the entire SDRAM memory space, then enable access/caching for the size used */ - mpu_config_start(); + uint32_t irq_state = mpu_config_start(); mpu_config_region(MPU_REGION_SDRAM1, SDRAM_START_ADDRESS, MPU_CONFIG_DISABLE(0x00, MPU_REGION_SIZE_512MB)); mpu_config_region(MPU_REGION_SDRAM2, SDRAM_START_ADDRESS, MPU_CONFIG_SDRAM(SDRAM_MPU_REGION_SIZE)); - mpu_config_end(); + mpu_config_end(irq_state); #endif } From 079cc940a68b3b3b9d47d4402267393a528a0477 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Thu, 22 Aug 2019 10:21:48 +1000 Subject: [PATCH 0893/1788] powerpc: Add initial port to bare metal PowerPC arch. Runs in microwatt (GHDL and FPGA) and qemu. Port done initially by Michael Neuling, with help from Anton Blanchard and Jordan Niethe. --- .travis.yml | 9 +++ ports/powerpc/Makefile | 64 +++++++++++++++ ports/powerpc/README.md | 40 +++++++++ ports/powerpc/frozentest.mpy | Bin 0 -> 196 bytes ports/powerpc/frozentest.py | 7 ++ ports/powerpc/head.S | 121 +++++++++++++++++++++++++++ ports/powerpc/main.c | 139 ++++++++++++++++++++++++++++++++ ports/powerpc/mpconfigport.h | 123 ++++++++++++++++++++++++++++ ports/powerpc/mphalport.h | 45 +++++++++++ ports/powerpc/powerpc.lds | 13 +++ ports/powerpc/qstrdefsport.h | 1 + ports/powerpc/uart_core.c | 73 +++++++++++++++++ ports/powerpc/uart_lpc_serial.c | 111 +++++++++++++++++++++++++ ports/powerpc/uart_lpc_serial.h | 29 +++++++ ports/powerpc/uart_potato.c | 121 +++++++++++++++++++++++++++ ports/powerpc/uart_potato.h | 29 +++++++ ports/powerpc/unistd.h | 36 +++++++++ py/nlr.h | 4 + py/nlrpowerpc.c | 121 +++++++++++++++++++++++++++ py/py.mk | 1 + 20 files changed, 1087 insertions(+) create mode 100644 ports/powerpc/Makefile create mode 100644 ports/powerpc/README.md create mode 100644 ports/powerpc/frozentest.mpy create mode 100644 ports/powerpc/frozentest.py create mode 100644 ports/powerpc/head.S create mode 100644 ports/powerpc/main.c create mode 100644 ports/powerpc/mpconfigport.h create mode 100644 ports/powerpc/mphalport.h create mode 100644 ports/powerpc/powerpc.lds create mode 100644 ports/powerpc/qstrdefsport.h create mode 100644 ports/powerpc/uart_core.c create mode 100644 ports/powerpc/uart_lpc_serial.c create mode 100644 ports/powerpc/uart_lpc_serial.h create mode 100644 ports/powerpc/uart_potato.c create mode 100644 ports/powerpc/uart_potato.h create mode 100644 ports/powerpc/unistd.h create mode 100644 py/nlrpowerpc.c diff --git a/.travis.yml b/.travis.yml index 077fca20af..5923cb2b96 100644 --- a/.travis.yml +++ b/.travis.yml @@ -232,3 +232,12 @@ jobs: - sudo apt-get install libnewlib-arm-none-eabi script: - make ${MAKEOPTS} -C ports/teensy + + # powerpc port + - stage: test + env: NAME="powerpc port build" + install: + - sudo apt-get install gcc-powerpc64le-linux-gnu + - sudo apt-get install libc6-dev-ppc64el-cross + script: + - make ${MAKEOPTS} -C ports/powerpc CROSS_COMPILE=powerpc64le-linux-gnu- diff --git a/ports/powerpc/Makefile b/ports/powerpc/Makefile new file mode 100644 index 0000000000..30474df1d1 --- /dev/null +++ b/ports/powerpc/Makefile @@ -0,0 +1,64 @@ +include ../../py/mkenv.mk + +# qstr definitions (must come before including py.mk) +QSTR_DEFS = qstrdefsport.h + +# include py core make definitions +include $(TOP)/py/py.mk + +ARCH = $(shell uname -m) +ifneq ("$(ARCH)", "ppc64") +ifneq ("$(ARCH)", "ppc64le") + CROSS_COMPILE = powerpc64le-linux- +endif +endif + +INC += -I. +INC += -I$(TOP) +INC += -I$(BUILD) + +CFLAGS = $(INC) -g -Wall -std=c99 $(COPT) +CFLAGS += -mno-string -mno-multiple -mno-vsx -mno-altivec -nostdlib +CFLAGS += -mlittle-endian -mstrict-align -msoft-float +CFLAGS += -Os +CFLAGS += -fdata-sections -ffunction-sections -fno-stack-protector -ffreestanding +CFLAGS += -U_FORTIFY_SOURCE + +LDFLAGS = -N -T powerpc.lds -nostdlib + +LIBS = + +SRC_C = \ + main.c \ + uart_core.c \ + uart_potato.c \ + uart_lpc_serial.c \ + lib/utils/printf.c \ + lib/utils/stdout_helpers.c \ + lib/utils/pyexec.c \ + lib/libc/string0.c \ + lib/mp-readline/readline.c \ + $(BUILD)/_frozen_mpy.c \ + +OBJ = $(PY_CORE_O) +OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) +OBJ += $(BUILD)/head.o + +all: $(BUILD)/firmware.elf $(BUILD)/firmware.map $(BUILD)/firmware.bin + +$(BUILD)/_frozen_mpy.c: frozentest.mpy $(BUILD)/genhdr/qstrdefs.generated.h + $(ECHO) "MISC freezing bytecode" + $(Q)$(MPY_TOOL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h -mlongint-impl=mpz $< > $@ + +$(BUILD)/firmware.elf: $(OBJ) powerpc.lds + $(ECHO) "LINK $@" + $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS) + $(Q)$(SIZE) $@ + +$(BUILD)/firmware.bin: $(BUILD)/firmware.elf + $(Q)$(OBJCOPY) -O binary $^ $(BUILD)/firmware.bin + +$(BUILD)/firmware.map: $(BUILD)/firmware.elf + $(Q)nm $^ | sort > $(BUILD)/firmware.map + +include $(TOP)/py/mkrules.mk diff --git a/ports/powerpc/README.md b/ports/powerpc/README.md new file mode 100644 index 0000000000..862bfcd3c5 --- /dev/null +++ b/ports/powerpc/README.md @@ -0,0 +1,40 @@ +# The PowerPC port that runs on microwatt and qemu + +This port is intended to be a minimal MicroPython port that runs in +QEMU, microwatt simulator with ghdl or microwatt on Xilinx FPGA with +potato UART. + +## Building + +By default the port will be built for the host machine: + + $ make + +## Cross compilation for POWERPC + +If you need to cross compilers you'll want to grab a powerpc64le +compiler (not powerpc or powerpc64). + +On Ubuntu (18.04) you'll want: + + $ apt install gcc-powerpc64le-linux-gnu + +*(Use CROSS_COMPILE=powerpc64le-linux-gnu-)* + +If your distro doesn't have cross compilers, you can get cross compilers here: +- https://toolchains.bootlin.com/ +*(use CROSS_COMPILE=powerpc64le-buildroot-linux-gnu-)* + +(Avoid musl libc as it defines __assert_fail() differently to glibc +which breaks the micropython powerpc code) + +Then do: + + $ make CROSS_COMPILE= + +Building will produce the build/firmware.bin file which can be used +QEMU or [microwatt](https://github.com/antonblanchard/microwatt). + +To run in QEMU use: + + $ ./qemu-system-ppc64 -M powernv -cpu POWER9 -nographic -bios build/firmware.bin diff --git a/ports/powerpc/frozentest.mpy b/ports/powerpc/frozentest.mpy new file mode 100644 index 0000000000000000000000000000000000000000..8a89194a1048700453ca5b682c972e131a878610 GIT binary patch literal 196 zcmeZeWs+BD3K0-vV3$fO%CAbzD@iRb(JQFb)X>n-)?g51s1{%=4X89>j07^38K5*H zlxBj^O1s|A5(P3FocJ5U#h5aIN(Dhm8lQ%@Tz7t59~qd;%uuY9sF0JNm#$D;Qj`g# zN-`2l6f%ny^74Tc(AuKB)RbbiL=@?a#A1cgyv*eMlvIUt8_#Vzw^<=MBeAGBi94wh M=uibiBV!Xr0D7G~UjP6A literal 0 HcmV?d00001 diff --git a/ports/powerpc/frozentest.py b/ports/powerpc/frozentest.py new file mode 100644 index 0000000000..0f99b74297 --- /dev/null +++ b/ports/powerpc/frozentest.py @@ -0,0 +1,7 @@ +print('uPy') +print('a long string that is not interned') +print('a string that has unicode αβγ chars') +print(b'bytes 1234\x01') +print(123456789) +for i in range(4): + print(i) diff --git a/ports/powerpc/head.S b/ports/powerpc/head.S new file mode 100644 index 0000000000..09aa62e59c --- /dev/null +++ b/ports/powerpc/head.S @@ -0,0 +1,121 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019, Michael Neuling, IBM Corporation. + * + * 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. + */ + +#define STACK_TOP 0x60000 + +#define FIXUP_ENDIAN \ + tdi 0,0,0x48; /* Reverse endian of b . + 8 */ \ + b 191f; /* Skip trampoline if endian is good */ \ + .long 0xa600607d; /* mfmsr r11 */ \ + .long 0x01006b69; /* xori r11,r11,1 */ \ + .long 0x05009f42; /* bcl 20,31,$+4 */ \ + .long 0xa602487d; /* mflr r10 */ \ + .long 0x14004a39; /* addi r10,r10,20 */ \ + .long 0xa64b5a7d; /* mthsrr0 r10 */ \ + .long 0xa64b7b7d; /* mthsrr1 r11 */ \ + .long 0x2402004c; /* hrfid */ \ + 191: + +/* Load an immediate 64-bit value into a register */ +#define LOAD_IMM64(r, e) \ + lis r,(e)@highest; \ + ori r,r,(e)@higher; \ + rldicr r,r, 32, 31; \ + oris r,r, (e)@h; \ + ori r,r, (e)@l; + +.section ".head","ax" + +/* + * Microwatt comes in at 0 as little endian so we do not need to worry up + * FIXUP_ENDIAN. + */ + . = 0 + .global _start +_start: + b boot_entry + +/* QEMU comes in at 0x10. Put a value in argc/r3 to distingush from + * microwatt. */ + . = 0x10 + FIXUP_ENDIAN + LOAD_IMM64(%r3, 1) + b boot_entry + + .global boot_entry + boot_entry: + /* Save R3 to non-volatile register */ + mr %r14, %r3 + restart: + /* + * setup stack with a safety gap, since we might write to the + * previous frame. + */ + LOAD_IMM64(%r1, STACK_TOP - 0x100) + LOAD_IMM64(%r12, main) + mtctr %r12 + bctrl + + /* On exit, restart */ + mr %r3, %r14 + b restart + +#define EXCEPTION(nr) \ + .= nr; \ +b . + + /* More exception stubs */ + EXCEPTION(0x300) + EXCEPTION(0x380) + EXCEPTION(0x400) + EXCEPTION(0x480) + EXCEPTION(0x500) + EXCEPTION(0x600) + EXCEPTION(0x700) + EXCEPTION(0x800) + EXCEPTION(0x900) + EXCEPTION(0x980) + EXCEPTION(0xa00) + EXCEPTION(0xb00) + EXCEPTION(0xc00) + EXCEPTION(0xd00) + EXCEPTION(0xe00) + EXCEPTION(0xe20) + EXCEPTION(0xe40) + EXCEPTION(0xe60) + EXCEPTION(0xe80) + EXCEPTION(0xf00) + EXCEPTION(0xf20) + EXCEPTION(0xf40) + EXCEPTION(0xf60) + EXCEPTION(0xf80) + EXCEPTION(0x1000) + EXCEPTION(0x1100) + EXCEPTION(0x1200) + EXCEPTION(0x1300) + EXCEPTION(0x1400) + EXCEPTION(0x1500) + EXCEPTION(0x1600) diff --git a/ports/powerpc/main.c b/ports/powerpc/main.c new file mode 100644 index 0000000000..9b164ac18c --- /dev/null +++ b/ports/powerpc/main.c @@ -0,0 +1,139 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019, Michael Neuling, IBM Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/compile.h" +#include "py/runtime.h" +#include "py/repl.h" +#include "py/gc.h" +#include "py/mperrno.h" +#include "py/stackctrl.h" +#include "lib/utils/pyexec.h" + +void __stack_chk_fail(void); +void __stack_chk_fail(void) { + static bool failed_once; + + if (failed_once) { + return; + } + failed_once = true; + printf("Stack corruption detected !\n"); + assert(0); +} + +/* fill in __assert_fail for libc */ +void __assert_fail(const char *__assertion, const char *__file, + unsigned int __line, const char *__function) { + printf("Assert at %s:%d:%s() \"%s\" failed\n", __file, __line, __function, __assertion); + for (;;) ; +} + +static char *stack_top; +#if MICROPY_ENABLE_GC +static char heap[32 * 1024]; +#endif + +extern void uart_init_ppc(int qemu); + +int main(int argc, char **argv) { + int stack_dummy; + stack_top = (char*)&stack_dummy; + + // microwatt has argc/r3 = 0 whereas QEMU has r3 set in head.S + uart_init_ppc(argc); + + #if MICROPY_ENABLE_PYSTACK + static mp_obj_t pystack[1024]; + mp_pystack_init(pystack, &pystack[1024]); + #endif + + #if MICROPY_STACK_CHECK + mp_stack_ctrl_init(); + mp_stack_set_limit(48 * 1024); + #endif + + #if MICROPY_ENABLE_GC + gc_init(heap, heap + sizeof(heap)); + #endif + mp_init(); + #if MICROPY_ENABLE_COMPILER + #if MICROPY_REPL_EVENT_DRIVEN + pyexec_event_repl_init(); + for (;;) { + int c = mp_hal_stdin_rx_chr(); + if (pyexec_event_repl_process_char(c)) { + break; + } + } + #else + pyexec_friendly_repl(); + #endif + #else + pyexec_frozen_module("frozentest.py"); + #endif + mp_deinit(); + return 0; +} + +void gc_collect(void) { + // WARNING: This gc_collect implementation doesn't try to get root + // pointers from CPU registers, and thus may function incorrectly. + void *dummy; + gc_collect_start(); + gc_collect_root(&dummy, ((mp_uint_t)stack_top - (mp_uint_t)&dummy) / sizeof(mp_uint_t)); + gc_collect_end(); + gc_dump_info(); +} + +mp_lexer_t *mp_lexer_new_from_file(const char *filename) { + mp_raise_OSError(MP_ENOENT); +} + +mp_import_stat_t mp_import_stat(const char *path) { + return MP_IMPORT_STAT_NO_EXIST; +} + +mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open); + +void nlr_jump_fail(void *val) { + while (1); +} + +void NORETURN __fatal_error(const char *msg) { + while (1); +} + +#ifndef NDEBUG +void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) { + printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line); + __fatal_error("Assertion failed"); +} +#endif diff --git a/ports/powerpc/mpconfigport.h b/ports/powerpc/mpconfigport.h new file mode 100644 index 0000000000..93ef699ad9 --- /dev/null +++ b/ports/powerpc/mpconfigport.h @@ -0,0 +1,123 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019, Michael Neuling, IBM Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +// options to control how MicroPython is built + +// You can disable the built-in MicroPython compiler by setting the following +// config option to 0. If you do this then you won't get a REPL prompt, but you +// will still be able to execute pre-compiled scripts, compiled with mpy-cross. +#define MICROPY_ENABLE_COMPILER (1) + +//#define MICROPY_DEBUG_VERBOSE (1) + +#define MICROPY_QSTR_BYTES_IN_HASH (1) +#define MICROPY_QSTR_EXTRA_POOL mp_qstr_frozen_const_pool +#define MICROPY_ALLOC_PATH_MAX (256) +#define MICROPY_ALLOC_PARSE_CHUNK_INIT (16) +#define MICROPY_EMIT_X64 (0) +#define MICROPY_EMIT_THUMB (0) +#define MICROPY_EMIT_INLINE_THUMB (0) +#define MICROPY_COMP_MODULE_CONST (0) +#define MICROPY_COMP_CONST (0) +#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0) +#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0) +#define MICROPY_MEM_STATS (0) +#define MICROPY_DEBUG_PRINTERS (1) +#define MICROPY_ENABLE_GC (1) +#define MICROPY_STACK_CHECK (1) +#define MICROPY_GC_ALLOC_THRESHOLD (0) +#define MICROPY_REPL_EVENT_DRIVEN (0) +#define MICROPY_HELPER_REPL (1) +#define MICROPY_HELPER_LEXER_UNIX (0) +#define MICROPY_ENABLE_SOURCE_LINE (1) +#define MICROPY_ENABLE_DOC_STRING (0) +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) +#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0) +#define MICROPY_PY_ASYNC_AWAIT (0) +#define MICROPY_MODULE_BUILTIN_INIT (1) +#define MICROPY_PY_BUILTINS_BYTEARRAY (1) +#define MICROPY_PY_BUILTINS_DICT_FROMKEYS (1) +#define MICROPY_PY_BUILTINS_MEMORYVIEW (1) +#define MICROPY_PY_BUILTINS_ENUMERATE (1) +#define MICROPY_PY_BUILTINS_FILTER (1) +#define MICROPY_PY_BUILTINS_FROZENSET (1) +#define MICROPY_PY_BUILTINS_REVERSED (1) +#define MICROPY_PY_BUILTINS_SET (1) +#define MICROPY_PY_BUILTINS_SLICE (1) +#define MICROPY_PY_BUILTINS_PROPERTY (1) +#define MICROPY_PY_BUILTINS_MIN_MAX (1) +#define MICROPY_PY_BUILTINS_STR_COUNT (1) +#define MICROPY_PY_BUILTINS_STR_OP_MODULO (1) +#define MICROPY_PY_BUILTINS_HELP (1) +#define MICROPY_PY_BUILTINS_HELP_MODULES (1) +#define MICROPY_PY___FILE__ (0) +#define MICROPY_PY_GC (1) +#define MICROPY_PY_ARRAY (1) +#define MICROPY_PY_COLLECTIONS (1) +#define MICROPY_PY_MATH (0) +#define MICROPY_PY_CMATH (0) +#define MICROPY_PY_IO (0) +#define MICROPY_PY_STRUCT (1) +#define MICROPY_PY_SYS (1) +#define MICROPY_MODULE_FROZEN_MPY (1) +#define MICROPY_CPYTHON_COMPAT (0) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE) +#define MICROPY_ENABLE_PYSTACK (1) +#define MICROPY_USE_INTERNAL_PRINTF (1) + +// type definitions for the specific machine + +#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1)) + +// This port is 64-bit +#define UINT_FMT "%lu" +#define INT_FMT "%ld" +typedef signed long mp_int_t; // must be pointer size +typedef unsigned long mp_uint_t; // must be pointer size + +typedef long mp_off_t; + +#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) + +// extra built in names to add to the global namespace +#define MICROPY_PORT_BUILTINS \ + { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) }, + +#define MICROPY_HW_BOARD_NAME "bare-metal" +#define MICROPY_HW_MCU_NAME "POWERPC" + +#define MP_STATE_PORT MP_STATE_VM + +#define MICROPY_PORT_ROOT_POINTERS \ + const char *readline_hist[8]; + +// powerpc64 gcc doesn't seem to define these +// These are pointers, so make them 64 bit types +typedef long intptr_t; +typedef unsigned long uintptr_t; diff --git a/ports/powerpc/mphalport.h b/ports/powerpc/mphalport.h new file mode 100644 index 0000000000..c6bf940072 --- /dev/null +++ b/ports/powerpc/mphalport.h @@ -0,0 +1,45 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019, Michael Neuling, IBM Corporation. + * + * 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. + */ + +#define mftb() ({unsigned long rval; \ + __asm__ volatile("mftb %0" : "=r" (rval)); rval;}) + +#define TBFREQ 512000000 + +static inline mp_uint_t mp_hal_ticks_ms(void) { + unsigned long tb = mftb(); + + return tb * 1000 / TBFREQ; +} + +static inline mp_uint_t mp_hal_ticks_us(void) { + unsigned long tb = mftb(); + + return tb * 1000000 / TBFREQ; +} + +static inline void mp_hal_set_interrupt_char(char c) { +} diff --git a/ports/powerpc/powerpc.lds b/ports/powerpc/powerpc.lds new file mode 100644 index 0000000000..93bd8a605c --- /dev/null +++ b/ports/powerpc/powerpc.lds @@ -0,0 +1,13 @@ +SECTIONS +{ + . = 0; + _start = .; + .head : { + KEEP(*(.head)) + } + + /* Put this at 0x1700 which is right after our execption + * vectors in head.S. + */ + . = 0x1700; +} diff --git a/ports/powerpc/qstrdefsport.h b/ports/powerpc/qstrdefsport.h new file mode 100644 index 0000000000..3ba897069b --- /dev/null +++ b/ports/powerpc/qstrdefsport.h @@ -0,0 +1 @@ +// qstrs specific to this port diff --git a/ports/powerpc/uart_core.c b/ports/powerpc/uart_core.c new file mode 100644 index 0000000000..b0dcd031a5 --- /dev/null +++ b/ports/powerpc/uart_core.c @@ -0,0 +1,73 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019, Michael Neuling, IBM Corporation. + * + * 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 "uart_potato.h" +#include "uart_lpc_serial.h" + +static int lpc_console; +static int potato_console; + +void uart_init_ppc(int lpc) { + lpc_console = lpc; + + if (!lpc_console) { + potato_console = 1; + + potato_uart_init(); + } else { + lpc_uart_init(); + } +} + +// Receive single character +int mp_hal_stdin_rx_chr(void) { + unsigned char c = 0; + if (lpc_console) { + c = lpc_uart_read(); + } else if (potato_console) { + c = potato_uart_read(); + } + return c; +} + +// Send string of given length +void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { + if (lpc_console) { + int i; + for (i = 0; i < len; i++) { + lpc_uart_write(str[i]); + } + } else if (potato_console) { + int i; + for (i = 0; i < len; i++) { + potato_uart_write(str[i]); + } + } +} diff --git a/ports/powerpc/uart_lpc_serial.c b/ports/powerpc/uart_lpc_serial.c new file mode 100644 index 0000000000..51a55cb1e6 --- /dev/null +++ b/ports/powerpc/uart_lpc_serial.c @@ -0,0 +1,111 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019, Michael Neuling, IBM Corporation. + * + * 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. + */ + +/* + * This is the LPC serial UART used by POWER9 boxes. This is modelled + * in the qemu POWER9 machine. + */ + +#include +#include +#include "py/mpconfig.h" + +#define PROC_FREQ 50000000 +#define UART_FREQ 115200 +#define UART_BASE 0xc0002000 +#define LPC_UART_BASE 0x60300d00103f8 + +/* Taken from skiboot */ +#define REG_RBR 0 +#define REG_THR 0 +#define REG_DLL 0 +#define REG_IER 1 +#define REG_DLM 1 +#define REG_FCR 2 +#define REG_IIR 2 +#define REG_LCR 3 +#define REG_MCR 4 +#define REG_LSR 5 +#define REG_MSR 6 +#define REG_SCR 7 + +#define LSR_DR 0x01 /* Data ready */ +#define LSR_OE 0x02 /* Overrun */ +#define LSR_PE 0x04 /* Parity error */ +#define LSR_FE 0x08 /* Framing error */ +#define LSR_BI 0x10 /* Break */ +#define LSR_THRE 0x20 /* Xmit holding register empty */ +#define LSR_TEMT 0x40 /* Xmitter empty */ +#define LSR_ERR 0x80 /* Error */ + +#define LCR_DLAB 0x80 /* DLL access */ + +#define IER_RX 0x01 +#define IER_THRE 0x02 +#define IER_ALL 0x0f + +static uint64_t lpc_uart_base; + +static void lpc_uart_reg_write(uint64_t offset, uint8_t val) { + uint64_t addr; + + addr = lpc_uart_base + offset; + + *(volatile uint8_t *)addr = val; +} + +static uint8_t lpc_uart_reg_read(uint64_t offset) { + uint64_t addr; + uint8_t val; + + addr = lpc_uart_base + offset; + + val = *(volatile uint8_t *)addr; + + return val; +} + +static int lpc_uart_tx_full(void) { + return !(lpc_uart_reg_read(REG_LSR) & LSR_THRE); +} + +static int lpc_uart_rx_empty(void) { + return !(lpc_uart_reg_read(REG_LSR) & LSR_DR); +} + +void lpc_uart_init(void) { + lpc_uart_base = LPC_UART_BASE; +} + +char lpc_uart_read(void) { + while (lpc_uart_rx_empty()) ; + return lpc_uart_reg_read(REG_THR); +} + +void lpc_uart_write(char c) { + while (lpc_uart_tx_full()); + lpc_uart_reg_write(REG_RBR, c); +} diff --git a/ports/powerpc/uart_lpc_serial.h b/ports/powerpc/uart_lpc_serial.h new file mode 100644 index 0000000000..d0e35ca32b --- /dev/null +++ b/ports/powerpc/uart_lpc_serial.h @@ -0,0 +1,29 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019, Michael Neuling, IBM Corporation. + * + * 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. + */ + +void lpc_uart_init(void); +char lpc_uart_read(void); +void lpc_uart_write(char c); diff --git a/ports/powerpc/uart_potato.c b/ports/powerpc/uart_potato.c new file mode 100644 index 0000000000..18f89d463a --- /dev/null +++ b/ports/powerpc/uart_potato.c @@ -0,0 +1,121 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019, Michael Neuling, IBM Corporation. + * + * 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. + */ + +/* + * This is a driver for the potato UART used by the microwatt core. + * The original potato UART came from here + * https://github.com/skordal/potato + */ + +#include +#include +#include "py/mpconfig.h" + +#define PROC_FREQ 50000000 +#define UART_FREQ 115200 +#define POTATO_UART_BASE 0xc0002000 +uint64_t potato_uart_base; + +#define POTATO_CONSOLE_TX 0x00 +#define POTATO_CONSOLE_RX 0x08 +#define POTATO_CONSOLE_STATUS 0x10 +#define POTATO_CONSOLE_STATUS_RX_EMPTY 0x01 +#define POTATO_CONSOLE_STATUS_TX_EMPTY 0x02 +#define POTATO_CONSOLE_STATUS_RX_FULL 0x04 +#define POTATO_CONSOLE_STATUS_TX_FULL 0x08 +#define POTATO_CONSOLE_CLOCK_DIV 0x18 +#define POTATO_CONSOLE_IRQ_EN 0x20 + +static uint64_t potato_uart_reg_read(int offset) { + uint64_t addr; + uint64_t val; + + addr = potato_uart_base + offset; + + val = *(volatile uint64_t *)addr; + + return val; +} + +void potato_uart_reg_write(int offset, uint64_t val) { + uint64_t addr; + + addr = potato_uart_base + offset; + + *(volatile uint64_t *)addr = val; +} + +static int potato_uart_rx_empty(void) { + uint64_t val; + + val = potato_uart_reg_read(POTATO_CONSOLE_STATUS); + + if (val & POTATO_CONSOLE_STATUS_RX_EMPTY) { + return 1; + } + + return 0; +} + +static int potato_uart_tx_full(void) { + uint64_t val; + + val = potato_uart_reg_read(POTATO_CONSOLE_STATUS); + + if (val & POTATO_CONSOLE_STATUS_TX_FULL) { + return 1; + } + + return 0; +} + +static unsigned long potato_uart_divisor(unsigned long proc_freq, unsigned long uart_freq) { + return proc_freq / (uart_freq * 16) - 1; +} + +void potato_uart_init(void) { + potato_uart_base = POTATO_UART_BASE; + potato_uart_reg_write(POTATO_CONSOLE_CLOCK_DIV, potato_uart_divisor(PROC_FREQ, UART_FREQ)); + +} + +char potato_uart_read(void) { + uint64_t val; + + while (potato_uart_rx_empty()); + val = potato_uart_reg_read(POTATO_CONSOLE_RX); + + return (char)(val & 0x000000ff); +} + +void potato_uart_write(char c) { + uint64_t val; + + val = c; + + while (potato_uart_tx_full()); + potato_uart_reg_write(POTATO_CONSOLE_TX, val); +} diff --git a/ports/powerpc/uart_potato.h b/ports/powerpc/uart_potato.h new file mode 100644 index 0000000000..d6bd93aa4e --- /dev/null +++ b/ports/powerpc/uart_potato.h @@ -0,0 +1,29 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019, Michael Neuling, IBM Corporation. + * + * 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. + */ + +void potato_uart_init(void); +char potato_uart_read(void); +void potato_uart_write(char c); diff --git a/ports/powerpc/unistd.h b/ports/powerpc/unistd.h new file mode 100644 index 0000000000..88e3b27218 --- /dev/null +++ b/ports/powerpc/unistd.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019, Michael Neuling, IBM Corporation. + * + * 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_POWERPC_UNISTD_H +#define MICROPY_INCLUDED_POWERPC_UNISTD_H + +// powerpc gcc compiler doesn't seem to have unistd.h file + +#define SEEK_SET 0 +#define SEEK_CUR 1 + +typedef int ssize_t; + +#endif // MICROPY_INCLUDED_POWERPC_UNISTD_H diff --git a/py/nlr.h b/py/nlr.h index f2453bc460..3be3eb58cc 100644 --- a/py/nlr.h +++ b/py/nlr.h @@ -73,6 +73,10 @@ #elif defined(__xtensa__) #define MICROPY_NLR_XTENSA (1) #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_XTENSA) +#elif defined(__powerpc__) + #define MICROPY_NLR_POWERPC (1) + // this could be less but using 128 for safety + #define MICROPY_NLR_NUM_REGS (128) #else #define MICROPY_NLR_SETJMP (1) //#warning "No native NLR support for this arch, using setjmp implementation" diff --git a/py/nlrpowerpc.c b/py/nlrpowerpc.c new file mode 100644 index 0000000000..b403823813 --- /dev/null +++ b/py/nlrpowerpc.c @@ -0,0 +1,121 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019, Michael Neuling, IBM Corporation. + * + * 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_POWERPC + +#undef nlr_push + +// Saving all ABI non-vol registers here + +unsigned int nlr_push(nlr_buf_t *nlr) { + + __asm__ volatile( + "li 4, 0x4eed ; " // Store canary + "std 4, 0x00(%0) ;" + "std 0, 0x08(%0) ;" + "std 1, 0x10(%0) ;" + "std 2, 0x18(%0) ;" + "std 14, 0x20(%0) ;" + "std 15, 0x28(%0) ;" + "std 16, 0x30(%0) ;" + "std 17, 0x38(%0) ;" + "std 18, 0x40(%0) ;" + "std 19, 0x48(%0) ;" + "std 20, 0x50(%0) ;" + "std 21, 0x58(%0) ;" + "std 22, 0x60(%0) ;" + "std 23, 0x68(%0) ;" + "std 24, 0x70(%0) ;" + "std 25, 0x78(%0) ;" + "std 26, 0x80(%0) ;" + "std 27, 0x88(%0) ;" + "std 28, 0x90(%0) ;" + "std 29, 0x98(%0) ;" + "std 30, 0xA0(%0) ;" + "std 31, 0xA8(%0) ;" + + "mfcr 4 ; " + "std 4, 0xB0(%0) ;" + "mflr 4 ;" + "std 4, 0xB8(%0) ;" + "li 4, nlr_push_tail@l ;" + "oris 4, 4, nlr_push_tail@h ;" + "mtctr 4 ;" + "mr 3, %1 ; " + "bctr ;" + : + : "r"(&nlr->regs), "r"(nlr) + : + ); + + return 0; +} + +NORETURN void nlr_jump(void *val) { + MP_NLR_JUMP_HEAD(val, top) + + __asm__ volatile( + "ld 3, 0x0(%0) ;" + "cmpdi 3, 0x4eed ; " // Check canary + "bne . ; " + "ld 0, 0x08(%0) ;" + "ld 1, 0x10(%0) ;" + "ld 2, 0x18(%0) ;" + "ld 14, 0x20(%0) ;" + "ld 15, 0x28(%0) ;" + "ld 16, 0x30(%0) ;" + "ld 17, 0x38(%0) ;" + "ld 18, 0x40(%0) ;" + "ld 19, 0x48(%0) ;" + "ld 20, 0x50(%0) ;" + "ld 21, 0x58(%0) ;" + "ld 22, 0x60(%0) ;" + "ld 23, 0x68(%0) ;" + "ld 24, 0x70(%0) ;" + "ld 25, 0x78(%0) ;" + "ld 26, 0x80(%0) ;" + "ld 27, 0x88(%0) ;" + "ld 28, 0x90(%0) ;" + "ld 29, 0x98(%0) ;" + "ld 30, 0xA0(%0) ;" + "ld 31, 0xA8(%0) ;" + "ld 3, 0xB0(%0) ;" + "mtcr 3 ;" + "ld 3, 0xB8(%0) ;" + "mtlr 3 ; " + "li 3, 1;" + "blr ;" + : + : "r"(&top->regs) + : + ); + + MP_UNREACHABLE; +} + +#endif // MICROPY_NLR_POWERPC diff --git a/py/py.mk b/py/py.mk index 514a0e405a..d7021d3268 100644 --- a/py/py.mk +++ b/py/py.mk @@ -46,6 +46,7 @@ PY_CORE_O_BASENAME = $(addprefix py/,\ nlrx86.o \ nlrx64.o \ nlrthumb.o \ + nlrpowerpc.o \ nlrxtensa.o \ nlrsetjmp.o \ malloc.o \ From f301170c7cb50fdb9250a6e4b89682f9c0e543cb Mon Sep 17 00:00:00 2001 From: Mike Teachman Date: Tue, 22 Oct 2019 10:25:37 -0700 Subject: [PATCH 0894/1788] esp32/machine_hw_spi: Fix exception msg when host is already in use. When a SPI bus is initialized with a SPI host that is currently in use the exception msg incorrectly indicates "SPI device already in use". The mention of "device" in the exception msg is confusing because the error is about trying to use a SPI host that is already claimed. A better exception msg is "SPI host already in use". --- ports/esp32/machine_hw_spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/esp32/machine_hw_spi.c b/ports/esp32/machine_hw_spi.c index 2f63a32d4a..af47711aad 100644 --- a/ports/esp32/machine_hw_spi.c +++ b/ports/esp32/machine_hw_spi.c @@ -205,7 +205,7 @@ STATIC void machine_hw_spi_init_internal( return; case ESP_ERR_INVALID_STATE: - mp_raise_msg(&mp_type_OSError, "SPI device already in use"); + mp_raise_msg(&mp_type_OSError, "SPI host already in use"); return; } From f69ef97f241434a1b3b6907336cf88cf4bb52780 Mon Sep 17 00:00:00 2001 From: Mike Wadsten Date: Wed, 23 Oct 2019 11:43:01 -0500 Subject: [PATCH 0895/1788] docs: Move ubluetooth under "MicroPython-specific libraries". CPython does not have a bluetooth module, so it is not appropriate to call ubluetooth a Python standard library or micro-library. --- docs/library/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/library/index.rst b/docs/library/index.rst index a2d11dee7f..34b937d412 100644 --- a/docs/library/index.rst +++ b/docs/library/index.rst @@ -80,7 +80,6 @@ it will fallback to loading the built-in ``ujson`` module. sys.rst uarray.rst ubinascii.rst - ubluetooth.rst ucollections.rst uerrno.rst uhashlib.rst @@ -112,6 +111,7 @@ the following libraries. machine.rst micropython.rst network.rst + ubluetooth.rst ucryptolib.rst uctypes.rst From ece4e21a55609163466d96875c60bb7f1556c468 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 28 Oct 2019 13:48:51 +1100 Subject: [PATCH 0896/1788] stm32/Makefile: Only enable hardware sqrt on parts that support it. Not enough to detect f7/h7, need to use the specific parts. Follow-up to 580a2656d10cc7c1fc93e094d7eb71f04d99c329. --- ports/stm32/Makefile | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 30d4d9b48f..fca92f841e 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -64,13 +64,18 @@ INC += -Ilwip_inc CFLAGS_CORTEX_M = -mthumb # Select hardware floating-point support +SUPPORTS_HARDWARE_FP_SINGLE = 0 +SUPPORTS_HARDWARE_FP_DOUBLE = 0 ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32F765xx STM32F767xx STM32F769xx STM32H743xx)) CFLAGS_CORTEX_M += -mfpu=fpv5-d16 -mfloat-abi=hard +SUPPORTS_HARDWARE_FP_SINGLE = 1 +SUPPORTS_HARDWARE_FP_DOUBLE = 1 else ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f0 l0)) CFLAGS_CORTEX_M += -msoft-float else CFLAGS_CORTEX_M += -mfpu=fpv4-sp-d16 -mfloat-abi=hard +SUPPORTS_HARDWARE_FP_SINGLE = 1 endif endif @@ -180,7 +185,7 @@ SRC_LIBM = $(addprefix lib/libm_dbl/,\ tgamma.c \ trunc.c \ ) -ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f7 h7)) +ifeq ($(SUPPORTS_HARDWARE_FP_DOUBLE),1) SRC_LIBM += lib/libm_dbl/thumb_vfp_sqrt.c else SRC_LIBM += lib/libm_dbl/sqrt.c @@ -213,10 +218,10 @@ SRC_LIBM = $(addprefix lib/libm/,\ wf_lgamma.c \ wf_tgamma.c \ ) -ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f0 l0)) -SRC_LIBM += lib/libm/ef_sqrt.c -else +ifeq ($(SUPPORTS_HARDWARE_FP_SINGLE),1) SRC_LIBM += lib/libm/thumb_vfp_sqrtf.c +else +SRC_LIBM += lib/libm/ef_sqrt.c endif endif From 9aabb6c01ba4166bb389e28b55f21614fca5aa7f Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 7 Sep 2019 14:03:41 +1000 Subject: [PATCH 0897/1788] extmod: Factor out block-device struct to make independent of fatfs. --- extmod/vfs.h | 20 +++++++++++++++++++ extmod/vfs_fat.c | 24 +++++++++++------------ extmod/vfs_fat.h | 19 +----------------- extmod/vfs_fat_diskio.c | 38 ++++++++++++++++++------------------ ports/cc3200/mods/pybflash.c | 18 ++++++++--------- ports/cc3200/mptask.c | 2 +- ports/nrf/main.c | 2 +- ports/stm32/main.c | 4 ++-- ports/stm32/sdcard.c | 18 ++++++++--------- ports/stm32/storage.c | 18 ++++++++--------- 10 files changed, 83 insertions(+), 80 deletions(-) diff --git a/extmod/vfs.h b/extmod/vfs.h index 730dea0431..85b020faa5 100644 --- a/extmod/vfs.h +++ b/extmod/vfs.h @@ -38,6 +38,12 @@ #define MP_S_IFDIR (0x4000) #define MP_S_IFREG (0x8000) +// these are the values for mp_vfs_blockdev_t.flags +#define MP_BLOCKDEV_FLAG_NATIVE (0x0001) // readblocks[2]/writeblocks[2] contain native func +#define MP_BLOCKDEV_FLAG_FREE_OBJ (0x0002) // fs_user_mount_t obj should be freed on umount +#define MP_BLOCKDEV_FLAG_HAVE_IOCTL (0x0004) // new protocol with ioctl +#define MP_BLOCKDEV_FLAG_NO_FILESYSTEM (0x0008) // the block device has no filesystem on it + // constants for block protocol ioctl #define BP_IOCTL_INIT (1) #define BP_IOCTL_DEINIT (2) @@ -50,6 +56,20 @@ 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_blockdev_t { + uint16_t flags; + mp_obj_t readblocks[4]; + mp_obj_t writeblocks[4]; + // new protocol uses just ioctl, old uses sync (optional) and count + union { + mp_obj_t ioctl[4]; + struct { + mp_obj_t sync[2]; + mp_obj_t count[2]; + } old; + } u; +} mp_vfs_blockdev_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 ec7aaed388..dcfb677b1f 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -68,27 +68,27 @@ STATIC mp_obj_t fat_vfs_make_new(const mp_obj_type_t *type, size_t n_args, size_ // create new object fs_user_mount_t *vfs = m_new_obj(fs_user_mount_t); vfs->base.type = type; - vfs->flags = FSUSER_FREE_OBJ; + vfs->blockdev.flags = MP_BLOCKDEV_FLAG_FREE_OBJ; vfs->fatfs.drv = vfs; // load block protocol methods - mp_load_method(args[0], MP_QSTR_readblocks, vfs->readblocks); - mp_load_method_maybe(args[0], MP_QSTR_writeblocks, vfs->writeblocks); - mp_load_method_maybe(args[0], MP_QSTR_ioctl, vfs->u.ioctl); - if (vfs->u.ioctl[0] != MP_OBJ_NULL) { + mp_load_method(args[0], MP_QSTR_readblocks, vfs->blockdev.readblocks); + mp_load_method_maybe(args[0], MP_QSTR_writeblocks, vfs->blockdev.writeblocks); + mp_load_method_maybe(args[0], MP_QSTR_ioctl, vfs->blockdev.u.ioctl); + if (vfs->blockdev.u.ioctl[0] != MP_OBJ_NULL) { // device supports new block protocol, so indicate it - vfs->flags |= FSUSER_HAVE_IOCTL; + vfs->blockdev.flags |= MP_BLOCKDEV_FLAG_HAVE_IOCTL; } else { // no ioctl method, so assume the device uses the old block protocol - mp_load_method_maybe(args[0], MP_QSTR_sync, vfs->u.old.sync); - mp_load_method(args[0], MP_QSTR_count, vfs->u.old.count); + mp_load_method_maybe(args[0], MP_QSTR_sync, vfs->blockdev.u.old.sync); + mp_load_method(args[0], MP_QSTR_count, vfs->blockdev.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; + vfs->blockdev.flags |= MP_BLOCKDEV_FLAG_NO_FILESYSTEM; } else if (res != FR_OK) { mp_raise_OSError(fresult_to_errno_table[res]); } @@ -380,11 +380,11 @@ STATIC mp_obj_t vfs_fat_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs // 1. readonly=True keyword argument // 2. nonexistent writeblocks method (then writeblocks[0] == MP_OBJ_NULL already) if (mp_obj_is_true(readonly)) { - self->writeblocks[0] = MP_OBJ_NULL; + self->blockdev.writeblocks[0] = MP_OBJ_NULL; } // check if we need to make the filesystem - FRESULT res = (self->flags & FSUSER_NO_FILESYSTEM) ? FR_NO_FILESYSTEM : FR_OK; + FRESULT res = (self->blockdev.flags & MP_BLOCKDEV_FLAG_NO_FILESYSTEM) ? FR_NO_FILESYSTEM : FR_OK; if (res == FR_NO_FILESYSTEM && mp_obj_is_true(mkfs)) { uint8_t working_buf[FF_MAX_SS]; res = f_mkfs(&self->fatfs, FM_FAT | FM_SFD, 0, working_buf, sizeof(working_buf)); @@ -392,7 +392,7 @@ 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; + self->blockdev.flags &= ~MP_BLOCKDEV_FLAG_NO_FILESYSTEM; return mp_const_none; } diff --git a/extmod/vfs_fat.h b/extmod/vfs_fat.h index ba2915386f..83685b5027 100644 --- a/extmod/vfs_fat.h +++ b/extmod/vfs_fat.h @@ -26,30 +26,13 @@ #ifndef MICROPY_INCLUDED_EXTMOD_VFS_FAT_H #define MICROPY_INCLUDED_EXTMOD_VFS_FAT_H -#include "py/lexer.h" #include "py/obj.h" #include "lib/oofatfs/ff.h" #include "extmod/vfs.h" -// these are the values for fs_user_mount_t.flags -#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; - uint16_t flags; - mp_obj_t readblocks[4]; - mp_obj_t writeblocks[4]; - // new protocol uses just ioctl, old uses sync (optional) and count - union { - mp_obj_t ioctl[4]; - struct { - mp_obj_t sync[2]; - mp_obj_t count[2]; - } old; - } u; + mp_vfs_blockdev_t blockdev; FATFS fatfs; } fs_user_mount_t; diff --git a/extmod/vfs_fat_diskio.c b/extmod/vfs_fat_diskio.c index e80d612411..25b1310670 100644 --- a/extmod/vfs_fat_diskio.c +++ b/extmod/vfs_fat_diskio.c @@ -69,16 +69,16 @@ DRESULT disk_read ( return RES_PARERR; } - if (vfs->flags & FSUSER_NATIVE) { - mp_uint_t (*f)(uint8_t*, uint32_t, uint32_t) = (void*)(uintptr_t)vfs->readblocks[2]; + if (vfs->blockdev.flags & MP_BLOCKDEV_FLAG_NATIVE) { + mp_uint_t (*f)(uint8_t*, uint32_t, uint32_t) = (void*)(uintptr_t)vfs->blockdev.readblocks[2]; if (f(buff, sector, count) != 0) { 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_FROM_PTR(&ar); - mp_call_method_n_kw(2, 0, vfs->readblocks); + vfs->blockdev.readblocks[2] = MP_OBJ_NEW_SMALL_INT(sector); + vfs->blockdev.readblocks[3] = MP_OBJ_FROM_PTR(&ar); + mp_call_method_n_kw(2, 0, vfs->blockdev.readblocks); // TODO handle error return } @@ -101,21 +101,21 @@ DRESULT disk_write ( return RES_PARERR; } - if (vfs->writeblocks[0] == MP_OBJ_NULL) { + if (vfs->blockdev.writeblocks[0] == MP_OBJ_NULL) { // read-only block device return RES_WRPRT; } - if (vfs->flags & FSUSER_NATIVE) { - mp_uint_t (*f)(const uint8_t*, uint32_t, uint32_t) = (void*)(uintptr_t)vfs->writeblocks[2]; + if (vfs->blockdev.flags & MP_BLOCKDEV_FLAG_NATIVE) { + mp_uint_t (*f)(const uint8_t*, uint32_t, uint32_t) = (void*)(uintptr_t)vfs->blockdev.writeblocks[2]; if (f(buff, sector, count) != 0) { 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_FROM_PTR(&ar); - mp_call_method_n_kw(2, 0, vfs->writeblocks); + vfs->blockdev.writeblocks[2] = MP_OBJ_NEW_SMALL_INT(sector); + vfs->blockdev.writeblocks[3] = MP_OBJ_FROM_PTR(&ar); + mp_call_method_n_kw(2, 0, vfs->blockdev.writeblocks); // TODO handle error return } @@ -140,7 +140,7 @@ DRESULT disk_ioctl ( // First part: call the relevant method of the underlying block device mp_obj_t ret = mp_const_none; - if (vfs->flags & FSUSER_HAVE_IOCTL) { + if (vfs->blockdev.flags & MP_BLOCKDEV_FLAG_HAVE_IOCTL) { // new protocol with ioctl static const uint8_t op_map[8] = { [CTRL_SYNC] = BP_IOCTL_SYNC, @@ -150,21 +150,21 @@ DRESULT disk_ioctl ( }; 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); + vfs->blockdev.u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(bp_op); + vfs->blockdev.u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused + ret = mp_call_method_n_kw(2, 0, vfs->blockdev.u.ioctl); } } else { // old protocol with sync and count switch (cmd) { case CTRL_SYNC: - if (vfs->u.old.sync[0] != MP_OBJ_NULL) { - mp_call_method_n_kw(0, 0, vfs->u.old.sync); + if (vfs->blockdev.u.old.sync[0] != MP_OBJ_NULL) { + mp_call_method_n_kw(0, 0, vfs->blockdev.u.old.sync); } break; case GET_SECTOR_COUNT: - ret = mp_call_method_n_kw(0, 0, vfs->u.old.count); + ret = mp_call_method_n_kw(0, 0, vfs->blockdev.u.old.count); break; case GET_SECTOR_SIZE: @@ -211,7 +211,7 @@ DRESULT disk_ioctl ( 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) { + } else if (vfs->blockdev.writeblocks[0] == MP_OBJ_NULL) { stat = STA_PROTECT; } else { stat = 0; diff --git a/ports/cc3200/mods/pybflash.c b/ports/cc3200/mods/pybflash.c index 51f4cb5172..185913ce31 100644 --- a/ports/cc3200/mods/pybflash.c +++ b/ports/cc3200/mods/pybflash.c @@ -96,14 +96,14 @@ const mp_obj_type_t pyb_flash_type = { void pyb_flash_init_vfs(fs_user_mount_t *vfs) { vfs->base.type = &mp_fat_vfs_type; - vfs->flags |= FSUSER_NATIVE | FSUSER_HAVE_IOCTL; + vfs->blockdev.flags |= MP_BLOCKDEV_FLAG_NATIVE | MP_BLOCKDEV_FLAG_HAVE_IOCTL; vfs->fatfs.drv = vfs; - vfs->readblocks[0] = (mp_obj_t)&pyb_flash_readblocks_obj; - vfs->readblocks[1] = (mp_obj_t)&pyb_flash_obj; - vfs->readblocks[2] = (mp_obj_t)sflash_disk_read; // native version - vfs->writeblocks[0] = (mp_obj_t)&pyb_flash_writeblocks_obj; - vfs->writeblocks[1] = (mp_obj_t)&pyb_flash_obj; - vfs->writeblocks[2] = (mp_obj_t)sflash_disk_write; // native version - vfs->u.ioctl[0] = (mp_obj_t)&pyb_flash_ioctl_obj; - vfs->u.ioctl[1] = (mp_obj_t)&pyb_flash_obj; + vfs->blockdev.readblocks[0] = (mp_obj_t)&pyb_flash_readblocks_obj; + vfs->blockdev.readblocks[1] = (mp_obj_t)&pyb_flash_obj; + vfs->blockdev.readblocks[2] = (mp_obj_t)sflash_disk_read; // native version + vfs->blockdev.writeblocks[0] = (mp_obj_t)&pyb_flash_writeblocks_obj; + vfs->blockdev.writeblocks[1] = (mp_obj_t)&pyb_flash_obj; + vfs->blockdev.writeblocks[2] = (mp_obj_t)sflash_disk_write; // native version + vfs->blockdev.u.ioctl[0] = (mp_obj_t)&pyb_flash_ioctl_obj; + vfs->blockdev.u.ioctl[1] = (mp_obj_t)&pyb_flash_obj; } diff --git a/ports/cc3200/mptask.c b/ports/cc3200/mptask.c index d35338be18..c253804267 100644 --- a/ports/cc3200/mptask.c +++ b/ports/cc3200/mptask.c @@ -300,7 +300,7 @@ STATIC void mptask_init_sflash_filesystem (void) { // Initialise the local flash filesystem. // init the vfs object fs_user_mount_t *vfs_fat = sflash_vfs_fat; - vfs_fat->flags = 0; + vfs_fat->blockdev.flags = 0; pyb_flash_init_vfs(vfs_fat); // Create it if needed, and mount in on /flash. diff --git a/ports/nrf/main.c b/ports/nrf/main.c index 26ac0ad6c9..f7d42060e8 100644 --- a/ports/nrf/main.c +++ b/ports/nrf/main.c @@ -180,7 +180,7 @@ pin_init0(); } vfs->str = "/sd"; vfs->len = 3; - vfs->flags = FSUSER_FREE_OBJ; + vfs->flags = MP_BLOCKDEV_FLAG_FREE_OBJ; sdcard_init_vfs(vfs); // put the sd device in slot 1 (it will be unused at this point) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 2da3626f12..685dbd10c7 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -161,7 +161,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(pyb_main_obj, 1, pyb_main); MP_NOINLINE STATIC bool init_flash_fs(uint reset_mode) { // init the vfs object fs_user_mount_t *vfs_fat = &fs_user_mount_flash; - vfs_fat->flags = 0; + vfs_fat->blockdev.flags = 0; pyb_flash_init_vfs(vfs_fat); // try to mount the flash @@ -230,7 +230,7 @@ STATIC bool init_sdcard_fs(void) { if (vfs == NULL || vfs_fat == NULL) { break; } - vfs_fat->flags = FSUSER_FREE_OBJ; + vfs_fat->blockdev.flags = MP_BLOCKDEV_FLAG_FREE_OBJ; sdcard_init_vfs(vfs_fat, part_num); // try to mount the partition diff --git a/ports/stm32/sdcard.c b/ports/stm32/sdcard.c index 44b1c807d8..da9c1c681a 100644 --- a/ports/stm32/sdcard.c +++ b/ports/stm32/sdcard.c @@ -873,17 +873,17 @@ const mp_obj_type_t pyb_mmcard_type = { void sdcard_init_vfs(fs_user_mount_t *vfs, int part) { pyb_sdmmc_flags = (pyb_sdmmc_flags & PYB_SDMMC_FLAG_ACTIVE) | PYB_SDMMC_FLAG_SD; // force SD mode vfs->base.type = &mp_fat_vfs_type; - vfs->flags |= FSUSER_NATIVE | FSUSER_HAVE_IOCTL; + vfs->blockdev.flags |= MP_BLOCKDEV_FLAG_NATIVE | MP_BLOCKDEV_FLAG_HAVE_IOCTL; vfs->fatfs.drv = vfs; vfs->fatfs.part = part; - vfs->readblocks[0] = MP_OBJ_FROM_PTR(&pyb_sdcard_readblocks_obj); - vfs->readblocks[1] = MP_OBJ_FROM_PTR(&pyb_sdcard_obj); - vfs->readblocks[2] = MP_OBJ_FROM_PTR(sdcard_read_blocks); // native version - vfs->writeblocks[0] = MP_OBJ_FROM_PTR(&pyb_sdcard_writeblocks_obj); - vfs->writeblocks[1] = MP_OBJ_FROM_PTR(&pyb_sdcard_obj); - vfs->writeblocks[2] = MP_OBJ_FROM_PTR(sdcard_write_blocks); // native version - vfs->u.ioctl[0] = MP_OBJ_FROM_PTR(&pyb_sdcard_ioctl_obj); - vfs->u.ioctl[1] = MP_OBJ_FROM_PTR(&pyb_sdcard_obj); + vfs->blockdev.readblocks[0] = MP_OBJ_FROM_PTR(&pyb_sdcard_readblocks_obj); + vfs->blockdev.readblocks[1] = MP_OBJ_FROM_PTR(&pyb_sdcard_obj); + vfs->blockdev.readblocks[2] = MP_OBJ_FROM_PTR(sdcard_read_blocks); // native version + vfs->blockdev.writeblocks[0] = MP_OBJ_FROM_PTR(&pyb_sdcard_writeblocks_obj); + vfs->blockdev.writeblocks[1] = MP_OBJ_FROM_PTR(&pyb_sdcard_obj); + vfs->blockdev.writeblocks[2] = MP_OBJ_FROM_PTR(sdcard_write_blocks); // native version + vfs->blockdev.u.ioctl[0] = MP_OBJ_FROM_PTR(&pyb_sdcard_ioctl_obj); + vfs->blockdev.u.ioctl[1] = MP_OBJ_FROM_PTR(&pyb_sdcard_obj); } #endif // MICROPY_HW_ENABLE_SDCARD || MICROPY_HW_ENABLE_MMCARD diff --git a/ports/stm32/storage.c b/ports/stm32/storage.c index b150d73763..7685f6f175 100644 --- a/ports/stm32/storage.c +++ b/ports/stm32/storage.c @@ -290,17 +290,17 @@ const mp_obj_type_t pyb_flash_type = { void pyb_flash_init_vfs(fs_user_mount_t *vfs) { vfs->base.type = &mp_fat_vfs_type; - vfs->flags |= FSUSER_NATIVE | FSUSER_HAVE_IOCTL; + vfs->blockdev.flags |= MP_BLOCKDEV_FLAG_NATIVE | MP_BLOCKDEV_FLAG_HAVE_IOCTL; vfs->fatfs.drv = vfs; vfs->fatfs.part = 1; // flash filesystem lives on first partition - vfs->readblocks[0] = MP_OBJ_FROM_PTR(&pyb_flash_readblocks_obj); - vfs->readblocks[1] = MP_OBJ_FROM_PTR(&pyb_flash_obj); - vfs->readblocks[2] = MP_OBJ_FROM_PTR(storage_read_blocks); // native version - vfs->writeblocks[0] = MP_OBJ_FROM_PTR(&pyb_flash_writeblocks_obj); - vfs->writeblocks[1] = MP_OBJ_FROM_PTR(&pyb_flash_obj); - vfs->writeblocks[2] = MP_OBJ_FROM_PTR(storage_write_blocks); // native version - vfs->u.ioctl[0] = MP_OBJ_FROM_PTR(&pyb_flash_ioctl_obj); - vfs->u.ioctl[1] = MP_OBJ_FROM_PTR(&pyb_flash_obj); + vfs->blockdev.readblocks[0] = MP_OBJ_FROM_PTR(&pyb_flash_readblocks_obj); + vfs->blockdev.readblocks[1] = MP_OBJ_FROM_PTR(&pyb_flash_obj); + vfs->blockdev.readblocks[2] = MP_OBJ_FROM_PTR(storage_read_blocks); // native version + vfs->blockdev.writeblocks[0] = MP_OBJ_FROM_PTR(&pyb_flash_writeblocks_obj); + vfs->blockdev.writeblocks[1] = MP_OBJ_FROM_PTR(&pyb_flash_obj); + vfs->blockdev.writeblocks[2] = MP_OBJ_FROM_PTR(storage_write_blocks); // native version + vfs->blockdev.u.ioctl[0] = MP_OBJ_FROM_PTR(&pyb_flash_ioctl_obj); + vfs->blockdev.u.ioctl[1] = MP_OBJ_FROM_PTR(&pyb_flash_obj); } #endif From e1c7b1cb431f17bc00a76e7d411f5106b1a967cc Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 8 Sep 2019 22:01:09 +1000 Subject: [PATCH 0898/1788] extmod/vfs_blockdev: Factor out block device interface code. --- extmod/vfs.h | 6 +++ extmod/vfs_blockdev.c | 112 ++++++++++++++++++++++++++++++++++++++++ extmod/vfs_fat.c | 17 ++---- extmod/vfs_fat_diskio.c | 89 ++++++------------------------- py/py.mk | 1 + 5 files changed, 140 insertions(+), 85 deletions(-) create mode 100644 extmod/vfs_blockdev.c diff --git a/extmod/vfs.h b/extmod/vfs.h index 85b020faa5..e626a14df0 100644 --- a/extmod/vfs.h +++ b/extmod/vfs.h @@ -58,6 +58,7 @@ typedef struct _mp_vfs_proto_t { typedef struct _mp_vfs_blockdev_t { uint16_t flags; + size_t block_size; mp_obj_t readblocks[4]; mp_obj_t writeblocks[4]; // new protocol uses just ioctl, old uses sync (optional) and count @@ -77,6 +78,11 @@ typedef struct _mp_vfs_mount_t { struct _mp_vfs_mount_t *next; } mp_vfs_mount_t; +void mp_vfs_blockdev_init(mp_vfs_blockdev_t *self, mp_obj_t bdev); +int mp_vfs_blockdev_read(mp_vfs_blockdev_t *self, size_t block_num, size_t num_blocks, uint8_t *buf); +int mp_vfs_blockdev_write(mp_vfs_blockdev_t *self, size_t block_num, size_t num_blocks, const uint8_t *buf); +mp_obj_t mp_vfs_blockdev_ioctl(mp_vfs_blockdev_t *self, uintptr_t cmd, uintptr_t arg); + mp_vfs_mount_t *mp_vfs_lookup_path(const char *path, const char **path_out); 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); diff --git a/extmod/vfs_blockdev.c b/extmod/vfs_blockdev.c new file mode 100644 index 0000000000..0bc0fdebfa --- /dev/null +++ b/extmod/vfs_blockdev.c @@ -0,0 +1,112 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2019 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/binary.h" +#include "py/objarray.h" +#include "py/mperrno.h" +#include "extmod/vfs.h" + +#if MICROPY_VFS + +void mp_vfs_blockdev_init(mp_vfs_blockdev_t *self, mp_obj_t bdev) { + mp_load_method(bdev, MP_QSTR_readblocks, self->readblocks); + mp_load_method_maybe(bdev, MP_QSTR_writeblocks, self->writeblocks); + mp_load_method_maybe(bdev, MP_QSTR_ioctl, self->u.ioctl); + if (self->u.ioctl[0] != MP_OBJ_NULL) { + // Device supports new block protocol, so indicate it + self->flags |= MP_BLOCKDEV_FLAG_HAVE_IOCTL; + } else { + // No ioctl method, so assume the device uses the old block protocol + mp_load_method_maybe(bdev, MP_QSTR_sync, self->u.old.sync); + mp_load_method(bdev, MP_QSTR_count, self->u.old.count); + } +} + +int mp_vfs_blockdev_read(mp_vfs_blockdev_t *self, size_t block_num, size_t num_blocks, uint8_t *buf) { + if (self->flags & MP_BLOCKDEV_FLAG_NATIVE) { + mp_uint_t (*f)(uint8_t*, uint32_t, uint32_t) = (void*)(uintptr_t)self->readblocks[2]; + return f(buf, block_num, num_blocks); + } else { + mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, num_blocks * self->block_size, buf}; + self->readblocks[2] = MP_OBJ_NEW_SMALL_INT(block_num); + self->readblocks[3] = MP_OBJ_FROM_PTR(&ar); + mp_call_method_n_kw(2, 0, self->readblocks); + // TODO handle error return + return 0; + } +} + +int mp_vfs_blockdev_write(mp_vfs_blockdev_t *self, size_t block_num, size_t num_blocks, const uint8_t *buf) { + if (self->writeblocks[0] == MP_OBJ_NULL) { + // read-only block device + return -MP_EROFS; + } + + if (self->flags & MP_BLOCKDEV_FLAG_NATIVE) { + mp_uint_t (*f)(const uint8_t*, uint32_t, uint32_t) = (void*)(uintptr_t)self->writeblocks[2]; + return f(buf, block_num, num_blocks); + } else { + mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, num_blocks * self->block_size, (void*)buf}; + self->writeblocks[2] = MP_OBJ_NEW_SMALL_INT(block_num); + self->writeblocks[3] = MP_OBJ_FROM_PTR(&ar); + mp_call_method_n_kw(2, 0, self->writeblocks); + // TODO handle error return + return 0; + } +} + +mp_obj_t mp_vfs_blockdev_ioctl(mp_vfs_blockdev_t *self, uintptr_t cmd, uintptr_t arg) { + if (self->flags & MP_BLOCKDEV_FLAG_HAVE_IOCTL) { + // New protocol with ioctl + self->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(cmd); + self->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(arg); + return mp_call_method_n_kw(2, 0, self->u.ioctl); + } else { + // Old protocol with sync and count + switch (cmd) { + case BP_IOCTL_SYNC: + if (self->u.old.sync[0] != MP_OBJ_NULL) { + mp_call_method_n_kw(0, 0, self->u.old.sync); + } + break; + + case BP_IOCTL_SEC_COUNT: + return mp_call_method_n_kw(0, 0, self->u.old.count); + + case BP_IOCTL_SEC_SIZE: + // Old protocol has fixed sector size of 512 bytes + break; + + case BP_IOCTL_INIT: + // Old protocol doesn't have init + break; + } + return mp_const_none; + } +} + +#endif // MICROPY_VFS diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index dcfb677b1f..129b6cc669 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -68,21 +68,12 @@ STATIC mp_obj_t fat_vfs_make_new(const mp_obj_type_t *type, size_t n_args, size_ // create new object fs_user_mount_t *vfs = m_new_obj(fs_user_mount_t); vfs->base.type = type; - vfs->blockdev.flags = MP_BLOCKDEV_FLAG_FREE_OBJ; vfs->fatfs.drv = vfs; - // load block protocol methods - mp_load_method(args[0], MP_QSTR_readblocks, vfs->blockdev.readblocks); - mp_load_method_maybe(args[0], MP_QSTR_writeblocks, vfs->blockdev.writeblocks); - mp_load_method_maybe(args[0], MP_QSTR_ioctl, vfs->blockdev.u.ioctl); - if (vfs->blockdev.u.ioctl[0] != MP_OBJ_NULL) { - // device supports new block protocol, so indicate it - vfs->blockdev.flags |= MP_BLOCKDEV_FLAG_HAVE_IOCTL; - } else { - // no ioctl method, so assume the device uses the old block protocol - mp_load_method_maybe(args[0], MP_QSTR_sync, vfs->blockdev.u.old.sync); - mp_load_method(args[0], MP_QSTR_count, vfs->blockdev.u.old.count); - } + // Initialise underlying block device + vfs->blockdev.flags = MP_BLOCKDEV_FLAG_FREE_OBJ; + vfs->blockdev.block_size = FF_MIN_SS; // default, will be populated by call to BP_IOCTL_SEC_SIZE + mp_vfs_blockdev_init(&vfs->blockdev, args[0]); // mount the block device so the VFS methods can be used FRESULT res = f_mount(&vfs->fatfs); diff --git a/extmod/vfs_fat_diskio.c b/extmod/vfs_fat_diskio.c index 25b1310670..61a4d6da50 100644 --- a/extmod/vfs_fat_diskio.c +++ b/extmod/vfs_fat_diskio.c @@ -38,16 +38,11 @@ #include "py/runtime.h" #include "py/binary.h" #include "py/objarray.h" +#include "py/mperrno.h" #include "lib/oofatfs/ff.h" #include "lib/oofatfs/diskio.h" #include "extmod/vfs_fat.h" -#if FF_MAX_SS == FF_MIN_SS -#define SECSIZE(fs) (FF_MIN_SS) -#else -#define SECSIZE(fs) ((fs)->ssize) -#endif - typedef void *bdev_t; STATIC fs_user_mount_t *disk_get_device(void *bdev) { return (fs_user_mount_t*)bdev; @@ -69,20 +64,9 @@ DRESULT disk_read ( return RES_PARERR; } - if (vfs->blockdev.flags & MP_BLOCKDEV_FLAG_NATIVE) { - mp_uint_t (*f)(uint8_t*, uint32_t, uint32_t) = (void*)(uintptr_t)vfs->blockdev.readblocks[2]; - if (f(buff, sector, count) != 0) { - return RES_ERROR; - } - } else { - mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, count * SECSIZE(&vfs->fatfs), buff}; - vfs->blockdev.readblocks[2] = MP_OBJ_NEW_SMALL_INT(sector); - vfs->blockdev.readblocks[3] = MP_OBJ_FROM_PTR(&ar); - mp_call_method_n_kw(2, 0, vfs->blockdev.readblocks); - // TODO handle error return - } + int ret = mp_vfs_blockdev_read(&vfs->blockdev, sector, count, buff); - return RES_OK; + return ret == 0 ? RES_OK : RES_ERROR; } /*-----------------------------------------------------------------------*/ @@ -101,25 +85,14 @@ DRESULT disk_write ( return RES_PARERR; } - if (vfs->blockdev.writeblocks[0] == MP_OBJ_NULL) { + int ret = mp_vfs_blockdev_write(&vfs->blockdev, sector, count, buff); + + if (ret == -MP_EROFS) { // read-only block device return RES_WRPRT; } - if (vfs->blockdev.flags & MP_BLOCKDEV_FLAG_NATIVE) { - mp_uint_t (*f)(const uint8_t*, uint32_t, uint32_t) = (void*)(uintptr_t)vfs->blockdev.writeblocks[2]; - if (f(buff, sector, count) != 0) { - return RES_ERROR; - } - } else { - mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, count * SECSIZE(&vfs->fatfs), (void*)buff}; - vfs->blockdev.writeblocks[2] = MP_OBJ_NEW_SMALL_INT(sector); - vfs->blockdev.writeblocks[3] = MP_OBJ_FROM_PTR(&ar); - mp_call_method_n_kw(2, 0, vfs->blockdev.writeblocks); - // TODO handle error return - } - - return RES_OK; + return ret == 0 ? RES_OK : RES_ERROR; } @@ -139,42 +112,16 @@ DRESULT disk_ioctl ( } // First part: call the relevant method of the underlying block device + 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]; mp_obj_t ret = mp_const_none; - if (vfs->blockdev.flags & MP_BLOCKDEV_FLAG_HAVE_IOCTL) { - // new protocol with ioctl - 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->blockdev.u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(bp_op); - vfs->blockdev.u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused - ret = mp_call_method_n_kw(2, 0, vfs->blockdev.u.ioctl); - } - } else { - // old protocol with sync and count - switch (cmd) { - case CTRL_SYNC: - if (vfs->blockdev.u.old.sync[0] != MP_OBJ_NULL) { - mp_call_method_n_kw(0, 0, vfs->blockdev.u.old.sync); - } - break; - - case GET_SECTOR_COUNT: - ret = mp_call_method_n_kw(0, 0, vfs->blockdev.u.old.count); - break; - - case GET_SECTOR_SIZE: - // old protocol has fixed sector size of 512 bytes - break; - - case IOCTL_INIT: - // old protocol doesn't have init - break; - } + if (bp_op != 0) { + ret = mp_vfs_blockdev_ioctl(&vfs->blockdev, bp_op, 0); } // Second part: convert the result for return @@ -194,10 +141,8 @@ DRESULT disk_ioctl ( } else { *((WORD*)buff) = mp_obj_get_int(ret); } - #if FF_MAX_SS != FF_MIN_SS // need to store ssize because we use it in disk_read/disk_write - vfs->fatfs.ssize = *((WORD*)buff); - #endif + vfs->blockdev.block_size = *((WORD*)buff); return RES_OK; } diff --git a/py/py.mk b/py/py.mk index d7021d3268..b08b3f80c8 100644 --- a/py/py.mk +++ b/py/py.mk @@ -185,6 +185,7 @@ PY_EXTMOD_O_BASENAME = \ extmod/modwebrepl.o \ extmod/modframebuf.o \ extmod/vfs.o \ + extmod/vfs_blockdev.o \ extmod/vfs_reader.o \ extmod/vfs_posix.o \ extmod/vfs_posix_file.o \ From 669d1d20ab8be16bc847d509a9397c2ad4f912fc Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 18 Oct 2019 17:23:08 +1100 Subject: [PATCH 0899/1788] lib/littlefs: Add littlefs v1.7.2 source. --- lib/littlefs/lfs1.c | 2583 ++++++++++++++++++++++++++++++++++++++ lib/littlefs/lfs1.h | 501 ++++++++ lib/littlefs/lfs1_util.c | 31 + lib/littlefs/lfs1_util.h | 186 +++ 4 files changed, 3301 insertions(+) create mode 100644 lib/littlefs/lfs1.c create mode 100644 lib/littlefs/lfs1.h create mode 100644 lib/littlefs/lfs1_util.c create mode 100644 lib/littlefs/lfs1_util.h diff --git a/lib/littlefs/lfs1.c b/lib/littlefs/lfs1.c new file mode 100644 index 0000000000..6a3fd67001 --- /dev/null +++ b/lib/littlefs/lfs1.c @@ -0,0 +1,2583 @@ +/* + * The little filesystem + * + * Copyright (c) 2017, Arm Limited. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "lfs1.h" +#include "lfs1_util.h" + +#include + + +/// Caching block device operations /// +static int lfs1_cache_read(lfs1_t *lfs1, lfs1_cache_t *rcache, + const lfs1_cache_t *pcache, lfs1_block_t block, + lfs1_off_t off, void *buffer, lfs1_size_t size) { + uint8_t *data = buffer; + LFS1_ASSERT(block < lfs1->cfg->block_count); + + while (size > 0) { + if (pcache && block == pcache->block && off >= pcache->off && + off < pcache->off + lfs1->cfg->prog_size) { + // is already in pcache? + lfs1_size_t diff = lfs1_min(size, + lfs1->cfg->prog_size - (off-pcache->off)); + memcpy(data, &pcache->buffer[off-pcache->off], diff); + + data += diff; + off += diff; + size -= diff; + continue; + } + + if (block == rcache->block && off >= rcache->off && + off < rcache->off + lfs1->cfg->read_size) { + // is already in rcache? + lfs1_size_t diff = lfs1_min(size, + lfs1->cfg->read_size - (off-rcache->off)); + memcpy(data, &rcache->buffer[off-rcache->off], diff); + + data += diff; + off += diff; + size -= diff; + continue; + } + + if (off % lfs1->cfg->read_size == 0 && size >= lfs1->cfg->read_size) { + // bypass cache? + lfs1_size_t diff = size - (size % lfs1->cfg->read_size); + int err = lfs1->cfg->read(lfs1->cfg, block, off, data, diff); + if (err) { + return err; + } + + data += diff; + off += diff; + size -= diff; + continue; + } + + // load to cache, first condition can no longer fail + rcache->block = block; + rcache->off = off - (off % lfs1->cfg->read_size); + int err = lfs1->cfg->read(lfs1->cfg, rcache->block, + rcache->off, rcache->buffer, lfs1->cfg->read_size); + if (err) { + return err; + } + } + + return 0; +} + +static int lfs1_cache_cmp(lfs1_t *lfs1, lfs1_cache_t *rcache, + const lfs1_cache_t *pcache, lfs1_block_t block, + lfs1_off_t off, const void *buffer, lfs1_size_t size) { + const uint8_t *data = buffer; + + for (lfs1_off_t i = 0; i < size; i++) { + uint8_t c; + int err = lfs1_cache_read(lfs1, rcache, pcache, + block, off+i, &c, 1); + if (err) { + return err; + } + + if (c != data[i]) { + return false; + } + } + + return true; +} + +static int lfs1_cache_crc(lfs1_t *lfs1, lfs1_cache_t *rcache, + const lfs1_cache_t *pcache, lfs1_block_t block, + lfs1_off_t off, lfs1_size_t size, uint32_t *crc) { + for (lfs1_off_t i = 0; i < size; i++) { + uint8_t c; + int err = lfs1_cache_read(lfs1, rcache, pcache, + block, off+i, &c, 1); + if (err) { + return err; + } + + lfs1_crc(crc, &c, 1); + } + + return 0; +} + +static inline void lfs1_cache_drop(lfs1_t *lfs1, lfs1_cache_t *rcache) { + // do not zero, cheaper if cache is readonly or only going to be + // written with identical data (during relocates) + (void)lfs1; + rcache->block = 0xffffffff; +} + +static inline void lfs1_cache_zero(lfs1_t *lfs1, lfs1_cache_t *pcache) { + // zero to avoid information leak + memset(pcache->buffer, 0xff, lfs1->cfg->prog_size); + pcache->block = 0xffffffff; +} + +static int lfs1_cache_flush(lfs1_t *lfs1, + lfs1_cache_t *pcache, lfs1_cache_t *rcache) { + if (pcache->block != 0xffffffff) { + int err = lfs1->cfg->prog(lfs1->cfg, pcache->block, + pcache->off, pcache->buffer, lfs1->cfg->prog_size); + if (err) { + return err; + } + + if (rcache) { + int res = lfs1_cache_cmp(lfs1, rcache, NULL, pcache->block, + pcache->off, pcache->buffer, lfs1->cfg->prog_size); + if (res < 0) { + return res; + } + + if (!res) { + return LFS1_ERR_CORRUPT; + } + } + + lfs1_cache_zero(lfs1, pcache); + } + + return 0; +} + +static int lfs1_cache_prog(lfs1_t *lfs1, lfs1_cache_t *pcache, + lfs1_cache_t *rcache, lfs1_block_t block, + lfs1_off_t off, const void *buffer, lfs1_size_t size) { + const uint8_t *data = buffer; + LFS1_ASSERT(block < lfs1->cfg->block_count); + + while (size > 0) { + if (block == pcache->block && off >= pcache->off && + off < pcache->off + lfs1->cfg->prog_size) { + // is already in pcache? + lfs1_size_t diff = lfs1_min(size, + lfs1->cfg->prog_size - (off-pcache->off)); + memcpy(&pcache->buffer[off-pcache->off], data, diff); + + data += diff; + off += diff; + size -= diff; + + if (off % lfs1->cfg->prog_size == 0) { + // eagerly flush out pcache if we fill up + int err = lfs1_cache_flush(lfs1, pcache, rcache); + if (err) { + return err; + } + } + + continue; + } + + // pcache must have been flushed, either by programming and + // entire block or manually flushing the pcache + LFS1_ASSERT(pcache->block == 0xffffffff); + + if (off % lfs1->cfg->prog_size == 0 && + size >= lfs1->cfg->prog_size) { + // bypass pcache? + lfs1_size_t diff = size - (size % lfs1->cfg->prog_size); + int err = lfs1->cfg->prog(lfs1->cfg, block, off, data, diff); + if (err) { + return err; + } + + if (rcache) { + int res = lfs1_cache_cmp(lfs1, rcache, NULL, + block, off, data, diff); + if (res < 0) { + return res; + } + + if (!res) { + return LFS1_ERR_CORRUPT; + } + } + + data += diff; + off += diff; + size -= diff; + continue; + } + + // prepare pcache, first condition can no longer fail + pcache->block = block; + pcache->off = off - (off % lfs1->cfg->prog_size); + } + + return 0; +} + + +/// General lfs1 block device operations /// +static int lfs1_bd_read(lfs1_t *lfs1, lfs1_block_t block, + lfs1_off_t off, void *buffer, lfs1_size_t size) { + // if we ever do more than writes to alternating pairs, + // this may need to consider pcache + return lfs1_cache_read(lfs1, &lfs1->rcache, NULL, + block, off, buffer, size); +} + +static int lfs1_bd_prog(lfs1_t *lfs1, lfs1_block_t block, + lfs1_off_t off, const void *buffer, lfs1_size_t size) { + return lfs1_cache_prog(lfs1, &lfs1->pcache, NULL, + block, off, buffer, size); +} + +static int lfs1_bd_cmp(lfs1_t *lfs1, lfs1_block_t block, + lfs1_off_t off, const void *buffer, lfs1_size_t size) { + return lfs1_cache_cmp(lfs1, &lfs1->rcache, NULL, block, off, buffer, size); +} + +static int lfs1_bd_crc(lfs1_t *lfs1, lfs1_block_t block, + lfs1_off_t off, lfs1_size_t size, uint32_t *crc) { + return lfs1_cache_crc(lfs1, &lfs1->rcache, NULL, block, off, size, crc); +} + +static int lfs1_bd_erase(lfs1_t *lfs1, lfs1_block_t block) { + return lfs1->cfg->erase(lfs1->cfg, block); +} + +static int lfs1_bd_sync(lfs1_t *lfs1) { + lfs1_cache_drop(lfs1, &lfs1->rcache); + + int err = lfs1_cache_flush(lfs1, &lfs1->pcache, NULL); + if (err) { + return err; + } + + return lfs1->cfg->sync(lfs1->cfg); +} + + +/// Internal operations predeclared here /// +int lfs1_traverse(lfs1_t *lfs1, int (*cb)(void*, lfs1_block_t), void *data); +static int lfs1_pred(lfs1_t *lfs1, const lfs1_block_t dir[2], lfs1_dir_t *pdir); +static int lfs1_parent(lfs1_t *lfs1, const lfs1_block_t dir[2], + lfs1_dir_t *parent, lfs1_entry_t *entry); +static int lfs1_moved(lfs1_t *lfs1, const void *e); +static int lfs1_relocate(lfs1_t *lfs1, + const lfs1_block_t oldpair[2], const lfs1_block_t newpair[2]); +int lfs1_deorphan(lfs1_t *lfs1); + + +/// Block allocator /// +static int lfs1_alloc_lookahead(void *p, lfs1_block_t block) { + lfs1_t *lfs1 = p; + + lfs1_block_t off = ((block - lfs1->free.off) + + lfs1->cfg->block_count) % lfs1->cfg->block_count; + + if (off < lfs1->free.size) { + lfs1->free.buffer[off / 32] |= 1U << (off % 32); + } + + return 0; +} + +static int lfs1_alloc(lfs1_t *lfs1, lfs1_block_t *block) { + while (true) { + while (lfs1->free.i != lfs1->free.size) { + lfs1_block_t off = lfs1->free.i; + lfs1->free.i += 1; + lfs1->free.ack -= 1; + + if (!(lfs1->free.buffer[off / 32] & (1U << (off % 32)))) { + // found a free block + *block = (lfs1->free.off + off) % lfs1->cfg->block_count; + + // eagerly find next off so an alloc ack can + // discredit old lookahead blocks + while (lfs1->free.i != lfs1->free.size && + (lfs1->free.buffer[lfs1->free.i / 32] + & (1U << (lfs1->free.i % 32)))) { + lfs1->free.i += 1; + lfs1->free.ack -= 1; + } + + return 0; + } + } + + // check if we have looked at all blocks since last ack + if (lfs1->free.ack == 0) { + LFS1_WARN("No more free space %" PRIu32, + lfs1->free.i + lfs1->free.off); + return LFS1_ERR_NOSPC; + } + + lfs1->free.off = (lfs1->free.off + lfs1->free.size) + % lfs1->cfg->block_count; + lfs1->free.size = lfs1_min(lfs1->cfg->lookahead, lfs1->free.ack); + lfs1->free.i = 0; + + // find mask of free blocks from tree + memset(lfs1->free.buffer, 0, lfs1->cfg->lookahead/8); + int err = lfs1_traverse(lfs1, lfs1_alloc_lookahead, lfs1); + if (err) { + return err; + } + } +} + +static void lfs1_alloc_ack(lfs1_t *lfs1) { + lfs1->free.ack = lfs1->cfg->block_count; +} + + +/// Endian swapping functions /// +static void lfs1_dir_fromle32(struct lfs1_disk_dir *d) { + d->rev = lfs1_fromle32(d->rev); + d->size = lfs1_fromle32(d->size); + d->tail[0] = lfs1_fromle32(d->tail[0]); + d->tail[1] = lfs1_fromle32(d->tail[1]); +} + +static void lfs1_dir_tole32(struct lfs1_disk_dir *d) { + d->rev = lfs1_tole32(d->rev); + d->size = lfs1_tole32(d->size); + d->tail[0] = lfs1_tole32(d->tail[0]); + d->tail[1] = lfs1_tole32(d->tail[1]); +} + +static void lfs1_entry_fromle32(struct lfs1_disk_entry *d) { + d->u.dir[0] = lfs1_fromle32(d->u.dir[0]); + d->u.dir[1] = lfs1_fromle32(d->u.dir[1]); +} + +static void lfs1_entry_tole32(struct lfs1_disk_entry *d) { + d->u.dir[0] = lfs1_tole32(d->u.dir[0]); + d->u.dir[1] = lfs1_tole32(d->u.dir[1]); +} + +static void lfs1_superblock_fromle32(struct lfs1_disk_superblock *d) { + d->root[0] = lfs1_fromle32(d->root[0]); + d->root[1] = lfs1_fromle32(d->root[1]); + d->block_size = lfs1_fromle32(d->block_size); + d->block_count = lfs1_fromle32(d->block_count); + d->version = lfs1_fromle32(d->version); +} + +static void lfs1_superblock_tole32(struct lfs1_disk_superblock *d) { + d->root[0] = lfs1_tole32(d->root[0]); + d->root[1] = lfs1_tole32(d->root[1]); + d->block_size = lfs1_tole32(d->block_size); + d->block_count = lfs1_tole32(d->block_count); + d->version = lfs1_tole32(d->version); +} + + +/// Metadata pair and directory operations /// +static inline void lfs1_pairswap(lfs1_block_t pair[2]) { + lfs1_block_t t = pair[0]; + pair[0] = pair[1]; + pair[1] = t; +} + +static inline bool lfs1_pairisnull(const lfs1_block_t pair[2]) { + return pair[0] == 0xffffffff || pair[1] == 0xffffffff; +} + +static inline int lfs1_paircmp( + const lfs1_block_t paira[2], + const lfs1_block_t pairb[2]) { + return !(paira[0] == pairb[0] || paira[1] == pairb[1] || + paira[0] == pairb[1] || paira[1] == pairb[0]); +} + +static inline bool lfs1_pairsync( + const lfs1_block_t paira[2], + const lfs1_block_t pairb[2]) { + return (paira[0] == pairb[0] && paira[1] == pairb[1]) || + (paira[0] == pairb[1] && paira[1] == pairb[0]); +} + +static inline lfs1_size_t lfs1_entry_size(const lfs1_entry_t *entry) { + return 4 + entry->d.elen + entry->d.alen + entry->d.nlen; +} + +static int lfs1_dir_alloc(lfs1_t *lfs1, lfs1_dir_t *dir) { + // allocate pair of dir blocks + for (int i = 0; i < 2; i++) { + int err = lfs1_alloc(lfs1, &dir->pair[i]); + if (err) { + return err; + } + } + + // rather than clobbering one of the blocks we just pretend + // the revision may be valid + int err = lfs1_bd_read(lfs1, dir->pair[0], 0, &dir->d.rev, 4); + if (err && err != LFS1_ERR_CORRUPT) { + return err; + } + + if (err != LFS1_ERR_CORRUPT) { + dir->d.rev = lfs1_fromle32(dir->d.rev); + } + + // set defaults + dir->d.rev += 1; + dir->d.size = sizeof(dir->d)+4; + dir->d.tail[0] = 0xffffffff; + dir->d.tail[1] = 0xffffffff; + dir->off = sizeof(dir->d); + + // don't write out yet, let caller take care of that + return 0; +} + +static int lfs1_dir_fetch(lfs1_t *lfs1, + lfs1_dir_t *dir, const lfs1_block_t pair[2]) { + // copy out pair, otherwise may be aliasing dir + const lfs1_block_t tpair[2] = {pair[0], pair[1]}; + bool valid = false; + + // check both blocks for the most recent revision + for (int i = 0; i < 2; i++) { + struct lfs1_disk_dir test; + int err = lfs1_bd_read(lfs1, tpair[i], 0, &test, sizeof(test)); + lfs1_dir_fromle32(&test); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + continue; + } + return err; + } + + if (valid && lfs1_scmp(test.rev, dir->d.rev) < 0) { + continue; + } + + if ((0x7fffffff & test.size) < sizeof(test)+4 || + (0x7fffffff & test.size) > lfs1->cfg->block_size) { + continue; + } + + uint32_t crc = 0xffffffff; + lfs1_dir_tole32(&test); + lfs1_crc(&crc, &test, sizeof(test)); + lfs1_dir_fromle32(&test); + err = lfs1_bd_crc(lfs1, tpair[i], sizeof(test), + (0x7fffffff & test.size) - sizeof(test), &crc); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + continue; + } + return err; + } + + if (crc != 0) { + continue; + } + + valid = true; + + // setup dir in case it's valid + dir->pair[0] = tpair[(i+0) % 2]; + dir->pair[1] = tpair[(i+1) % 2]; + dir->off = sizeof(dir->d); + dir->d = test; + } + + if (!valid) { + LFS1_ERROR("Corrupted dir pair at %" PRIu32 " %" PRIu32 , + tpair[0], tpair[1]); + return LFS1_ERR_CORRUPT; + } + + return 0; +} + +struct lfs1_region { + lfs1_off_t oldoff; + lfs1_size_t oldlen; + const void *newdata; + lfs1_size_t newlen; +}; + +static int lfs1_dir_commit(lfs1_t *lfs1, lfs1_dir_t *dir, + const struct lfs1_region *regions, int count) { + // increment revision count + dir->d.rev += 1; + + // keep pairs in order such that pair[0] is most recent + lfs1_pairswap(dir->pair); + for (int i = 0; i < count; i++) { + dir->d.size += regions[i].newlen - regions[i].oldlen; + } + + const lfs1_block_t oldpair[2] = {dir->pair[0], dir->pair[1]}; + bool relocated = false; + + while (true) { + if (true) { + int err = lfs1_bd_erase(lfs1, dir->pair[0]); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + uint32_t crc = 0xffffffff; + lfs1_dir_tole32(&dir->d); + lfs1_crc(&crc, &dir->d, sizeof(dir->d)); + err = lfs1_bd_prog(lfs1, dir->pair[0], 0, &dir->d, sizeof(dir->d)); + lfs1_dir_fromle32(&dir->d); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + int i = 0; + lfs1_off_t oldoff = sizeof(dir->d); + lfs1_off_t newoff = sizeof(dir->d); + while (newoff < (0x7fffffff & dir->d.size)-4) { + if (i < count && regions[i].oldoff == oldoff) { + lfs1_crc(&crc, regions[i].newdata, regions[i].newlen); + err = lfs1_bd_prog(lfs1, dir->pair[0], + newoff, regions[i].newdata, regions[i].newlen); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + oldoff += regions[i].oldlen; + newoff += regions[i].newlen; + i += 1; + } else { + uint8_t data; + err = lfs1_bd_read(lfs1, oldpair[1], oldoff, &data, 1); + if (err) { + return err; + } + + lfs1_crc(&crc, &data, 1); + err = lfs1_bd_prog(lfs1, dir->pair[0], newoff, &data, 1); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + oldoff += 1; + newoff += 1; + } + } + + crc = lfs1_tole32(crc); + err = lfs1_bd_prog(lfs1, dir->pair[0], newoff, &crc, 4); + crc = lfs1_fromle32(crc); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + err = lfs1_bd_sync(lfs1); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + // successful commit, check checksum to make sure + uint32_t ncrc = 0xffffffff; + err = lfs1_bd_crc(lfs1, dir->pair[0], 0, + (0x7fffffff & dir->d.size)-4, &ncrc); + if (err) { + return err; + } + + if (ncrc != crc) { + goto relocate; + } + } + + break; +relocate: + //commit was corrupted + LFS1_DEBUG("Bad block at %" PRIu32, dir->pair[0]); + + // drop caches and prepare to relocate block + relocated = true; + lfs1_cache_drop(lfs1, &lfs1->pcache); + + // can't relocate superblock, filesystem is now frozen + if (lfs1_paircmp(oldpair, (const lfs1_block_t[2]){0, 1}) == 0) { + LFS1_WARN("Superblock %" PRIu32 " has become unwritable", + oldpair[0]); + return LFS1_ERR_CORRUPT; + } + + // relocate half of pair + int err = lfs1_alloc(lfs1, &dir->pair[0]); + if (err) { + return err; + } + } + + if (relocated) { + // update references if we relocated + LFS1_DEBUG("Relocating %" PRIu32 " %" PRIu32 " to %" PRIu32 " %" PRIu32, + oldpair[0], oldpair[1], dir->pair[0], dir->pair[1]); + int err = lfs1_relocate(lfs1, oldpair, dir->pair); + if (err) { + return err; + } + } + + // shift over any directories that are affected + for (lfs1_dir_t *d = lfs1->dirs; d; d = d->next) { + if (lfs1_paircmp(d->pair, dir->pair) == 0) { + d->pair[0] = dir->pair[0]; + d->pair[1] = dir->pair[1]; + } + } + + return 0; +} + +static int lfs1_dir_update(lfs1_t *lfs1, lfs1_dir_t *dir, + lfs1_entry_t *entry, const void *data) { + lfs1_entry_tole32(&entry->d); + int err = lfs1_dir_commit(lfs1, dir, (struct lfs1_region[]){ + {entry->off, sizeof(entry->d), &entry->d, sizeof(entry->d)}, + {entry->off+sizeof(entry->d), entry->d.nlen, data, entry->d.nlen} + }, data ? 2 : 1); + lfs1_entry_fromle32(&entry->d); + return err; +} + +static int lfs1_dir_append(lfs1_t *lfs1, lfs1_dir_t *dir, + lfs1_entry_t *entry, const void *data) { + // check if we fit, if top bit is set we do not and move on + while (true) { + if (dir->d.size + lfs1_entry_size(entry) <= lfs1->cfg->block_size) { + entry->off = dir->d.size - 4; + + lfs1_entry_tole32(&entry->d); + int err = lfs1_dir_commit(lfs1, dir, (struct lfs1_region[]){ + {entry->off, 0, &entry->d, sizeof(entry->d)}, + {entry->off, 0, data, entry->d.nlen} + }, 2); + lfs1_entry_fromle32(&entry->d); + return err; + } + + // we need to allocate a new dir block + if (!(0x80000000 & dir->d.size)) { + lfs1_dir_t olddir = *dir; + int err = lfs1_dir_alloc(lfs1, dir); + if (err) { + return err; + } + + dir->d.tail[0] = olddir.d.tail[0]; + dir->d.tail[1] = olddir.d.tail[1]; + entry->off = dir->d.size - 4; + lfs1_entry_tole32(&entry->d); + err = lfs1_dir_commit(lfs1, dir, (struct lfs1_region[]){ + {entry->off, 0, &entry->d, sizeof(entry->d)}, + {entry->off, 0, data, entry->d.nlen} + }, 2); + lfs1_entry_fromle32(&entry->d); + if (err) { + return err; + } + + olddir.d.size |= 0x80000000; + olddir.d.tail[0] = dir->pair[0]; + olddir.d.tail[1] = dir->pair[1]; + return lfs1_dir_commit(lfs1, &olddir, NULL, 0); + } + + int err = lfs1_dir_fetch(lfs1, dir, dir->d.tail); + if (err) { + return err; + } + } +} + +static int lfs1_dir_remove(lfs1_t *lfs1, lfs1_dir_t *dir, lfs1_entry_t *entry) { + // check if we should just drop the directory block + if ((dir->d.size & 0x7fffffff) == sizeof(dir->d)+4 + + lfs1_entry_size(entry)) { + lfs1_dir_t pdir; + int res = lfs1_pred(lfs1, dir->pair, &pdir); + if (res < 0) { + return res; + } + + if (pdir.d.size & 0x80000000) { + pdir.d.size &= dir->d.size | 0x7fffffff; + pdir.d.tail[0] = dir->d.tail[0]; + pdir.d.tail[1] = dir->d.tail[1]; + return lfs1_dir_commit(lfs1, &pdir, NULL, 0); + } + } + + // shift out the entry + int err = lfs1_dir_commit(lfs1, dir, (struct lfs1_region[]){ + {entry->off, lfs1_entry_size(entry), NULL, 0}, + }, 1); + if (err) { + return err; + } + + // shift over any files/directories that are affected + for (lfs1_file_t *f = lfs1->files; f; f = f->next) { + if (lfs1_paircmp(f->pair, dir->pair) == 0) { + if (f->poff == entry->off) { + f->pair[0] = 0xffffffff; + f->pair[1] = 0xffffffff; + } else if (f->poff > entry->off) { + f->poff -= lfs1_entry_size(entry); + } + } + } + + for (lfs1_dir_t *d = lfs1->dirs; d; d = d->next) { + if (lfs1_paircmp(d->pair, dir->pair) == 0) { + if (d->off > entry->off) { + d->off -= lfs1_entry_size(entry); + d->pos -= lfs1_entry_size(entry); + } + } + } + + return 0; +} + +static int lfs1_dir_next(lfs1_t *lfs1, lfs1_dir_t *dir, lfs1_entry_t *entry) { + while (dir->off + sizeof(entry->d) > (0x7fffffff & dir->d.size)-4) { + if (!(0x80000000 & dir->d.size)) { + entry->off = dir->off; + return LFS1_ERR_NOENT; + } + + int err = lfs1_dir_fetch(lfs1, dir, dir->d.tail); + if (err) { + return err; + } + + dir->off = sizeof(dir->d); + dir->pos += sizeof(dir->d) + 4; + } + + int err = lfs1_bd_read(lfs1, dir->pair[0], dir->off, + &entry->d, sizeof(entry->d)); + lfs1_entry_fromle32(&entry->d); + if (err) { + return err; + } + + entry->off = dir->off; + dir->off += lfs1_entry_size(entry); + dir->pos += lfs1_entry_size(entry); + return 0; +} + +static int lfs1_dir_find(lfs1_t *lfs1, lfs1_dir_t *dir, + lfs1_entry_t *entry, const char **path) { + const char *pathname = *path; + size_t pathlen; + entry->d.type = LFS1_TYPE_DIR; + entry->d.elen = sizeof(entry->d) - 4; + entry->d.alen = 0; + entry->d.nlen = 0; + entry->d.u.dir[0] = lfs1->root[0]; + entry->d.u.dir[1] = lfs1->root[1]; + + while (true) { +nextname: + // skip slashes + pathname += strspn(pathname, "/"); + pathlen = strcspn(pathname, "/"); + + // skip '.' and root '..' + if ((pathlen == 1 && memcmp(pathname, ".", 1) == 0) || + (pathlen == 2 && memcmp(pathname, "..", 2) == 0)) { + pathname += pathlen; + goto nextname; + } + + // skip if matched by '..' in name + const char *suffix = pathname + pathlen; + size_t sufflen; + int depth = 1; + while (true) { + suffix += strspn(suffix, "/"); + sufflen = strcspn(suffix, "/"); + if (sufflen == 0) { + break; + } + + if (sufflen == 2 && memcmp(suffix, "..", 2) == 0) { + depth -= 1; + if (depth == 0) { + pathname = suffix + sufflen; + goto nextname; + } + } else { + depth += 1; + } + + suffix += sufflen; + } + + // found path + if (pathname[0] == '\0') { + return 0; + } + + // update what we've found + *path = pathname; + + // continue on if we hit a directory + if (entry->d.type != LFS1_TYPE_DIR) { + return LFS1_ERR_NOTDIR; + } + + int err = lfs1_dir_fetch(lfs1, dir, entry->d.u.dir); + if (err) { + return err; + } + + // find entry matching name + while (true) { + err = lfs1_dir_next(lfs1, dir, entry); + if (err) { + return err; + } + + if (((0x7f & entry->d.type) != LFS1_TYPE_REG && + (0x7f & entry->d.type) != LFS1_TYPE_DIR) || + entry->d.nlen != pathlen) { + continue; + } + + int res = lfs1_bd_cmp(lfs1, dir->pair[0], + entry->off + 4+entry->d.elen+entry->d.alen, + pathname, pathlen); + if (res < 0) { + return res; + } + + // found match + if (res) { + break; + } + } + + // check that entry has not been moved + if (!lfs1->moving && entry->d.type & 0x80) { + int moved = lfs1_moved(lfs1, &entry->d.u); + if (moved < 0 || moved) { + return (moved < 0) ? moved : LFS1_ERR_NOENT; + } + + entry->d.type &= ~0x80; + } + + // to next name + pathname += pathlen; + } +} + + +/// Top level directory operations /// +int lfs1_mkdir(lfs1_t *lfs1, const char *path) { + // deorphan if we haven't yet, needed at most once after poweron + if (!lfs1->deorphaned) { + int err = lfs1_deorphan(lfs1); + if (err) { + return err; + } + } + + // fetch parent directory + lfs1_dir_t cwd; + lfs1_entry_t entry; + int err = lfs1_dir_find(lfs1, &cwd, &entry, &path); + if (err != LFS1_ERR_NOENT || strchr(path, '/') != NULL) { + return err ? err : LFS1_ERR_EXIST; + } + + // build up new directory + lfs1_alloc_ack(lfs1); + + lfs1_dir_t dir; + err = lfs1_dir_alloc(lfs1, &dir); + if (err) { + return err; + } + dir.d.tail[0] = cwd.d.tail[0]; + dir.d.tail[1] = cwd.d.tail[1]; + + err = lfs1_dir_commit(lfs1, &dir, NULL, 0); + if (err) { + return err; + } + + entry.d.type = LFS1_TYPE_DIR; + entry.d.elen = sizeof(entry.d) - 4; + entry.d.alen = 0; + entry.d.nlen = strlen(path); + entry.d.u.dir[0] = dir.pair[0]; + entry.d.u.dir[1] = dir.pair[1]; + + cwd.d.tail[0] = dir.pair[0]; + cwd.d.tail[1] = dir.pair[1]; + + err = lfs1_dir_append(lfs1, &cwd, &entry, path); + if (err) { + return err; + } + + lfs1_alloc_ack(lfs1); + return 0; +} + +int lfs1_dir_open(lfs1_t *lfs1, lfs1_dir_t *dir, const char *path) { + dir->pair[0] = lfs1->root[0]; + dir->pair[1] = lfs1->root[1]; + + lfs1_entry_t entry; + int err = lfs1_dir_find(lfs1, dir, &entry, &path); + if (err) { + return err; + } else if (entry.d.type != LFS1_TYPE_DIR) { + return LFS1_ERR_NOTDIR; + } + + err = lfs1_dir_fetch(lfs1, dir, entry.d.u.dir); + if (err) { + return err; + } + + // setup head dir + // special offset for '.' and '..' + dir->head[0] = dir->pair[0]; + dir->head[1] = dir->pair[1]; + dir->pos = sizeof(dir->d) - 2; + dir->off = sizeof(dir->d); + + // add to list of directories + dir->next = lfs1->dirs; + lfs1->dirs = dir; + + return 0; +} + +int lfs1_dir_close(lfs1_t *lfs1, lfs1_dir_t *dir) { + // remove from list of directories + for (lfs1_dir_t **p = &lfs1->dirs; *p; p = &(*p)->next) { + if (*p == dir) { + *p = dir->next; + break; + } + } + + return 0; +} + +int lfs1_dir_read(lfs1_t *lfs1, lfs1_dir_t *dir, struct lfs1_info *info) { + memset(info, 0, sizeof(*info)); + + // special offset for '.' and '..' + if (dir->pos == sizeof(dir->d) - 2) { + info->type = LFS1_TYPE_DIR; + strcpy(info->name, "."); + dir->pos += 1; + return 1; + } else if (dir->pos == sizeof(dir->d) - 1) { + info->type = LFS1_TYPE_DIR; + strcpy(info->name, ".."); + dir->pos += 1; + return 1; + } + + lfs1_entry_t entry; + while (true) { + int err = lfs1_dir_next(lfs1, dir, &entry); + if (err) { + return (err == LFS1_ERR_NOENT) ? 0 : err; + } + + if ((0x7f & entry.d.type) != LFS1_TYPE_REG && + (0x7f & entry.d.type) != LFS1_TYPE_DIR) { + continue; + } + + // check that entry has not been moved + if (entry.d.type & 0x80) { + int moved = lfs1_moved(lfs1, &entry.d.u); + if (moved < 0) { + return moved; + } + + if (moved) { + continue; + } + + entry.d.type &= ~0x80; + } + + break; + } + + info->type = entry.d.type; + if (info->type == LFS1_TYPE_REG) { + info->size = entry.d.u.file.size; + } + + int err = lfs1_bd_read(lfs1, dir->pair[0], + entry.off + 4+entry.d.elen+entry.d.alen, + info->name, entry.d.nlen); + if (err) { + return err; + } + + return 1; +} + +int lfs1_dir_seek(lfs1_t *lfs1, lfs1_dir_t *dir, lfs1_off_t off) { + // simply walk from head dir + int err = lfs1_dir_rewind(lfs1, dir); + if (err) { + return err; + } + dir->pos = off; + + while (off > (0x7fffffff & dir->d.size)) { + off -= 0x7fffffff & dir->d.size; + if (!(0x80000000 & dir->d.size)) { + return LFS1_ERR_INVAL; + } + + err = lfs1_dir_fetch(lfs1, dir, dir->d.tail); + if (err) { + return err; + } + } + + dir->off = off; + return 0; +} + +lfs1_soff_t lfs1_dir_tell(lfs1_t *lfs1, lfs1_dir_t *dir) { + (void)lfs1; + return dir->pos; +} + +int lfs1_dir_rewind(lfs1_t *lfs1, lfs1_dir_t *dir) { + // reload the head dir + int err = lfs1_dir_fetch(lfs1, dir, dir->head); + if (err) { + return err; + } + + dir->pair[0] = dir->head[0]; + dir->pair[1] = dir->head[1]; + dir->pos = sizeof(dir->d) - 2; + dir->off = sizeof(dir->d); + return 0; +} + + +/// File index list operations /// +static int lfs1_ctz_index(lfs1_t *lfs1, lfs1_off_t *off) { + lfs1_off_t size = *off; + lfs1_off_t b = lfs1->cfg->block_size - 2*4; + lfs1_off_t i = size / b; + if (i == 0) { + return 0; + } + + i = (size - 4*(lfs1_popc(i-1)+2)) / b; + *off = size - b*i - 4*lfs1_popc(i); + return i; +} + +static int lfs1_ctz_find(lfs1_t *lfs1, + lfs1_cache_t *rcache, const lfs1_cache_t *pcache, + lfs1_block_t head, lfs1_size_t size, + lfs1_size_t pos, lfs1_block_t *block, lfs1_off_t *off) { + if (size == 0) { + *block = 0xffffffff; + *off = 0; + return 0; + } + + lfs1_off_t current = lfs1_ctz_index(lfs1, &(lfs1_off_t){size-1}); + lfs1_off_t target = lfs1_ctz_index(lfs1, &pos); + + while (current > target) { + lfs1_size_t skip = lfs1_min( + lfs1_npw2(current-target+1) - 1, + lfs1_ctz(current)); + + int err = lfs1_cache_read(lfs1, rcache, pcache, head, 4*skip, &head, 4); + head = lfs1_fromle32(head); + if (err) { + return err; + } + + LFS1_ASSERT(head >= 2 && head <= lfs1->cfg->block_count); + current -= 1 << skip; + } + + *block = head; + *off = pos; + return 0; +} + +static int lfs1_ctz_extend(lfs1_t *lfs1, + lfs1_cache_t *rcache, lfs1_cache_t *pcache, + lfs1_block_t head, lfs1_size_t size, + lfs1_block_t *block, lfs1_off_t *off) { + while (true) { + // go ahead and grab a block + lfs1_block_t nblock; + int err = lfs1_alloc(lfs1, &nblock); + if (err) { + return err; + } + LFS1_ASSERT(nblock >= 2 && nblock <= lfs1->cfg->block_count); + + if (true) { + err = lfs1_bd_erase(lfs1, nblock); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + if (size == 0) { + *block = nblock; + *off = 0; + return 0; + } + + size -= 1; + lfs1_off_t index = lfs1_ctz_index(lfs1, &size); + size += 1; + + // just copy out the last block if it is incomplete + if (size != lfs1->cfg->block_size) { + for (lfs1_off_t i = 0; i < size; i++) { + uint8_t data; + err = lfs1_cache_read(lfs1, rcache, NULL, + head, i, &data, 1); + if (err) { + return err; + } + + err = lfs1_cache_prog(lfs1, pcache, rcache, + nblock, i, &data, 1); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + goto relocate; + } + return err; + } + } + + *block = nblock; + *off = size; + return 0; + } + + // append block + index += 1; + lfs1_size_t skips = lfs1_ctz(index) + 1; + + for (lfs1_off_t i = 0; i < skips; i++) { + head = lfs1_tole32(head); + err = lfs1_cache_prog(lfs1, pcache, rcache, + nblock, 4*i, &head, 4); + head = lfs1_fromle32(head); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + if (i != skips-1) { + err = lfs1_cache_read(lfs1, rcache, NULL, + head, 4*i, &head, 4); + head = lfs1_fromle32(head); + if (err) { + return err; + } + } + + LFS1_ASSERT(head >= 2 && head <= lfs1->cfg->block_count); + } + + *block = nblock; + *off = 4*skips; + return 0; + } + +relocate: + LFS1_DEBUG("Bad block at %" PRIu32, nblock); + + // just clear cache and try a new block + lfs1_cache_drop(lfs1, &lfs1->pcache); + } +} + +static int lfs1_ctz_traverse(lfs1_t *lfs1, + lfs1_cache_t *rcache, const lfs1_cache_t *pcache, + lfs1_block_t head, lfs1_size_t size, + int (*cb)(void*, lfs1_block_t), void *data) { + if (size == 0) { + return 0; + } + + lfs1_off_t index = lfs1_ctz_index(lfs1, &(lfs1_off_t){size-1}); + + while (true) { + int err = cb(data, head); + if (err) { + return err; + } + + if (index == 0) { + return 0; + } + + lfs1_block_t heads[2]; + int count = 2 - (index & 1); + err = lfs1_cache_read(lfs1, rcache, pcache, head, 0, &heads, count*4); + heads[0] = lfs1_fromle32(heads[0]); + heads[1] = lfs1_fromle32(heads[1]); + if (err) { + return err; + } + + for (int i = 0; i < count-1; i++) { + err = cb(data, heads[i]); + if (err) { + return err; + } + } + + head = heads[count-1]; + index -= count; + } +} + + +/// Top level file operations /// +int lfs1_file_opencfg(lfs1_t *lfs1, lfs1_file_t *file, + const char *path, int flags, + const struct lfs1_file_config *cfg) { + // deorphan if we haven't yet, needed at most once after poweron + if ((flags & 3) != LFS1_O_RDONLY && !lfs1->deorphaned) { + int err = lfs1_deorphan(lfs1); + if (err) { + return err; + } + } + + // allocate entry for file if it doesn't exist + lfs1_dir_t cwd; + lfs1_entry_t entry; + int err = lfs1_dir_find(lfs1, &cwd, &entry, &path); + if (err && (err != LFS1_ERR_NOENT || strchr(path, '/') != NULL)) { + return err; + } + + if (err == LFS1_ERR_NOENT) { + if (!(flags & LFS1_O_CREAT)) { + return LFS1_ERR_NOENT; + } + + // create entry to remember name + entry.d.type = LFS1_TYPE_REG; + entry.d.elen = sizeof(entry.d) - 4; + entry.d.alen = 0; + entry.d.nlen = strlen(path); + entry.d.u.file.head = 0xffffffff; + entry.d.u.file.size = 0; + err = lfs1_dir_append(lfs1, &cwd, &entry, path); + if (err) { + return err; + } + } else if (entry.d.type == LFS1_TYPE_DIR) { + return LFS1_ERR_ISDIR; + } else if (flags & LFS1_O_EXCL) { + return LFS1_ERR_EXIST; + } + + // setup file struct + file->cfg = cfg; + file->pair[0] = cwd.pair[0]; + file->pair[1] = cwd.pair[1]; + file->poff = entry.off; + file->head = entry.d.u.file.head; + file->size = entry.d.u.file.size; + file->flags = flags; + file->pos = 0; + + if (flags & LFS1_O_TRUNC) { + if (file->size != 0) { + file->flags |= LFS1_F_DIRTY; + } + file->head = 0xffffffff; + file->size = 0; + } + + // allocate buffer if needed + file->cache.block = 0xffffffff; + if (file->cfg && file->cfg->buffer) { + file->cache.buffer = file->cfg->buffer; + } else if (lfs1->cfg->file_buffer) { + if (lfs1->files) { + // already in use + return LFS1_ERR_NOMEM; + } + file->cache.buffer = lfs1->cfg->file_buffer; + } else if ((file->flags & 3) == LFS1_O_RDONLY) { + file->cache.buffer = lfs1_malloc(lfs1->cfg->read_size); + if (!file->cache.buffer) { + return LFS1_ERR_NOMEM; + } + } else { + file->cache.buffer = lfs1_malloc(lfs1->cfg->prog_size); + if (!file->cache.buffer) { + return LFS1_ERR_NOMEM; + } + } + + // zero to avoid information leak + lfs1_cache_drop(lfs1, &file->cache); + if ((file->flags & 3) != LFS1_O_RDONLY) { + lfs1_cache_zero(lfs1, &file->cache); + } + + // add to list of files + file->next = lfs1->files; + lfs1->files = file; + + return 0; +} + +int lfs1_file_open(lfs1_t *lfs1, lfs1_file_t *file, + const char *path, int flags) { + return lfs1_file_opencfg(lfs1, file, path, flags, NULL); +} + +int lfs1_file_close(lfs1_t *lfs1, lfs1_file_t *file) { + int err = lfs1_file_sync(lfs1, file); + + // remove from list of files + for (lfs1_file_t **p = &lfs1->files; *p; p = &(*p)->next) { + if (*p == file) { + *p = file->next; + break; + } + } + + // clean up memory + if (!(file->cfg && file->cfg->buffer) && !lfs1->cfg->file_buffer) { + lfs1_free(file->cache.buffer); + } + + return err; +} + +static int lfs1_file_relocate(lfs1_t *lfs1, lfs1_file_t *file) { +relocate: + LFS1_DEBUG("Bad block at %" PRIu32, file->block); + + // just relocate what exists into new block + lfs1_block_t nblock; + int err = lfs1_alloc(lfs1, &nblock); + if (err) { + return err; + } + + err = lfs1_bd_erase(lfs1, nblock); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + // either read from dirty cache or disk + for (lfs1_off_t i = 0; i < file->off; i++) { + uint8_t data; + err = lfs1_cache_read(lfs1, &lfs1->rcache, &file->cache, + file->block, i, &data, 1); + if (err) { + return err; + } + + err = lfs1_cache_prog(lfs1, &lfs1->pcache, &lfs1->rcache, + nblock, i, &data, 1); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + goto relocate; + } + return err; + } + } + + // copy over new state of file + memcpy(file->cache.buffer, lfs1->pcache.buffer, lfs1->cfg->prog_size); + file->cache.block = lfs1->pcache.block; + file->cache.off = lfs1->pcache.off; + lfs1_cache_zero(lfs1, &lfs1->pcache); + + file->block = nblock; + return 0; +} + +static int lfs1_file_flush(lfs1_t *lfs1, lfs1_file_t *file) { + if (file->flags & LFS1_F_READING) { + // just drop read cache + lfs1_cache_drop(lfs1, &file->cache); + file->flags &= ~LFS1_F_READING; + } + + if (file->flags & LFS1_F_WRITING) { + lfs1_off_t pos = file->pos; + + // copy over anything after current branch + lfs1_file_t orig = { + .head = file->head, + .size = file->size, + .flags = LFS1_O_RDONLY, + .pos = file->pos, + .cache = lfs1->rcache, + }; + lfs1_cache_drop(lfs1, &lfs1->rcache); + + while (file->pos < file->size) { + // copy over a byte at a time, leave it up to caching + // to make this efficient + uint8_t data; + lfs1_ssize_t res = lfs1_file_read(lfs1, &orig, &data, 1); + if (res < 0) { + return res; + } + + res = lfs1_file_write(lfs1, file, &data, 1); + if (res < 0) { + return res; + } + + // keep our reference to the rcache in sync + if (lfs1->rcache.block != 0xffffffff) { + lfs1_cache_drop(lfs1, &orig.cache); + lfs1_cache_drop(lfs1, &lfs1->rcache); + } + } + + // write out what we have + while (true) { + int err = lfs1_cache_flush(lfs1, &file->cache, &lfs1->rcache); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + break; +relocate: + err = lfs1_file_relocate(lfs1, file); + if (err) { + return err; + } + } + + // actual file updates + file->head = file->block; + file->size = file->pos; + file->flags &= ~LFS1_F_WRITING; + file->flags |= LFS1_F_DIRTY; + + file->pos = pos; + } + + return 0; +} + +int lfs1_file_sync(lfs1_t *lfs1, lfs1_file_t *file) { + int err = lfs1_file_flush(lfs1, file); + if (err) { + return err; + } + + if ((file->flags & LFS1_F_DIRTY) && + !(file->flags & LFS1_F_ERRED) && + !lfs1_pairisnull(file->pair)) { + // update dir entry + lfs1_dir_t cwd; + err = lfs1_dir_fetch(lfs1, &cwd, file->pair); + if (err) { + return err; + } + + lfs1_entry_t entry = {.off = file->poff}; + err = lfs1_bd_read(lfs1, cwd.pair[0], entry.off, + &entry.d, sizeof(entry.d)); + lfs1_entry_fromle32(&entry.d); + if (err) { + return err; + } + + LFS1_ASSERT(entry.d.type == LFS1_TYPE_REG); + entry.d.u.file.head = file->head; + entry.d.u.file.size = file->size; + + err = lfs1_dir_update(lfs1, &cwd, &entry, NULL); + if (err) { + return err; + } + + file->flags &= ~LFS1_F_DIRTY; + } + + return 0; +} + +lfs1_ssize_t lfs1_file_read(lfs1_t *lfs1, lfs1_file_t *file, + void *buffer, lfs1_size_t size) { + uint8_t *data = buffer; + lfs1_size_t nsize = size; + + if ((file->flags & 3) == LFS1_O_WRONLY) { + return LFS1_ERR_BADF; + } + + if (file->flags & LFS1_F_WRITING) { + // flush out any writes + int err = lfs1_file_flush(lfs1, file); + if (err) { + return err; + } + } + + if (file->pos >= file->size) { + // eof if past end + return 0; + } + + size = lfs1_min(size, file->size - file->pos); + nsize = size; + + while (nsize > 0) { + // check if we need a new block + if (!(file->flags & LFS1_F_READING) || + file->off == lfs1->cfg->block_size) { + int err = lfs1_ctz_find(lfs1, &file->cache, NULL, + file->head, file->size, + file->pos, &file->block, &file->off); + if (err) { + return err; + } + + file->flags |= LFS1_F_READING; + } + + // read as much as we can in current block + lfs1_size_t diff = lfs1_min(nsize, lfs1->cfg->block_size - file->off); + int err = lfs1_cache_read(lfs1, &file->cache, NULL, + file->block, file->off, data, diff); + if (err) { + return err; + } + + file->pos += diff; + file->off += diff; + data += diff; + nsize -= diff; + } + + return size; +} + +lfs1_ssize_t lfs1_file_write(lfs1_t *lfs1, lfs1_file_t *file, + const void *buffer, lfs1_size_t size) { + const uint8_t *data = buffer; + lfs1_size_t nsize = size; + + if ((file->flags & 3) == LFS1_O_RDONLY) { + return LFS1_ERR_BADF; + } + + if (file->flags & LFS1_F_READING) { + // drop any reads + int err = lfs1_file_flush(lfs1, file); + if (err) { + return err; + } + } + + if ((file->flags & LFS1_O_APPEND) && file->pos < file->size) { + file->pos = file->size; + } + + if (file->pos + size > LFS1_FILE_MAX) { + // larger than file limit? + return LFS1_ERR_FBIG; + } + + if (!(file->flags & LFS1_F_WRITING) && file->pos > file->size) { + // fill with zeros + lfs1_off_t pos = file->pos; + file->pos = file->size; + + while (file->pos < pos) { + lfs1_ssize_t res = lfs1_file_write(lfs1, file, &(uint8_t){0}, 1); + if (res < 0) { + return res; + } + } + } + + while (nsize > 0) { + // check if we need a new block + if (!(file->flags & LFS1_F_WRITING) || + file->off == lfs1->cfg->block_size) { + if (!(file->flags & LFS1_F_WRITING) && file->pos > 0) { + // find out which block we're extending from + int err = lfs1_ctz_find(lfs1, &file->cache, NULL, + file->head, file->size, + file->pos-1, &file->block, &file->off); + if (err) { + file->flags |= LFS1_F_ERRED; + return err; + } + + // mark cache as dirty since we may have read data into it + lfs1_cache_zero(lfs1, &file->cache); + } + + // extend file with new blocks + lfs1_alloc_ack(lfs1); + int err = lfs1_ctz_extend(lfs1, &lfs1->rcache, &file->cache, + file->block, file->pos, + &file->block, &file->off); + if (err) { + file->flags |= LFS1_F_ERRED; + return err; + } + + file->flags |= LFS1_F_WRITING; + } + + // program as much as we can in current block + lfs1_size_t diff = lfs1_min(nsize, lfs1->cfg->block_size - file->off); + while (true) { + int err = lfs1_cache_prog(lfs1, &file->cache, &lfs1->rcache, + file->block, file->off, data, diff); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + goto relocate; + } + file->flags |= LFS1_F_ERRED; + return err; + } + + break; +relocate: + err = lfs1_file_relocate(lfs1, file); + if (err) { + file->flags |= LFS1_F_ERRED; + return err; + } + } + + file->pos += diff; + file->off += diff; + data += diff; + nsize -= diff; + + lfs1_alloc_ack(lfs1); + } + + file->flags &= ~LFS1_F_ERRED; + return size; +} + +lfs1_soff_t lfs1_file_seek(lfs1_t *lfs1, lfs1_file_t *file, + lfs1_soff_t off, int whence) { + // write out everything beforehand, may be noop if rdonly + int err = lfs1_file_flush(lfs1, file); + if (err) { + return err; + } + + // find new pos + lfs1_soff_t npos = file->pos; + if (whence == LFS1_SEEK_SET) { + npos = off; + } else if (whence == LFS1_SEEK_CUR) { + npos = file->pos + off; + } else if (whence == LFS1_SEEK_END) { + npos = file->size + off; + } + + if (npos < 0 || npos > LFS1_FILE_MAX) { + // file position out of range + return LFS1_ERR_INVAL; + } + + // update pos + file->pos = npos; + return npos; +} + +int lfs1_file_truncate(lfs1_t *lfs1, lfs1_file_t *file, lfs1_off_t size) { + if ((file->flags & 3) == LFS1_O_RDONLY) { + return LFS1_ERR_BADF; + } + + lfs1_off_t oldsize = lfs1_file_size(lfs1, file); + if (size < oldsize) { + // need to flush since directly changing metadata + int err = lfs1_file_flush(lfs1, file); + if (err) { + return err; + } + + // lookup new head in ctz skip list + err = lfs1_ctz_find(lfs1, &file->cache, NULL, + file->head, file->size, + size, &file->head, &(lfs1_off_t){0}); + if (err) { + return err; + } + + file->size = size; + file->flags |= LFS1_F_DIRTY; + } else if (size > oldsize) { + lfs1_off_t pos = file->pos; + + // flush+seek if not already at end + if (file->pos != oldsize) { + int err = lfs1_file_seek(lfs1, file, 0, LFS1_SEEK_END); + if (err < 0) { + return err; + } + } + + // fill with zeros + while (file->pos < size) { + lfs1_ssize_t res = lfs1_file_write(lfs1, file, &(uint8_t){0}, 1); + if (res < 0) { + return res; + } + } + + // restore pos + int err = lfs1_file_seek(lfs1, file, pos, LFS1_SEEK_SET); + if (err < 0) { + return err; + } + } + + return 0; +} + +lfs1_soff_t lfs1_file_tell(lfs1_t *lfs1, lfs1_file_t *file) { + (void)lfs1; + return file->pos; +} + +int lfs1_file_rewind(lfs1_t *lfs1, lfs1_file_t *file) { + lfs1_soff_t res = lfs1_file_seek(lfs1, file, 0, LFS1_SEEK_SET); + if (res < 0) { + return res; + } + + return 0; +} + +lfs1_soff_t lfs1_file_size(lfs1_t *lfs1, lfs1_file_t *file) { + (void)lfs1; + if (file->flags & LFS1_F_WRITING) { + return lfs1_max(file->pos, file->size); + } else { + return file->size; + } +} + + +/// General fs operations /// +int lfs1_stat(lfs1_t *lfs1, const char *path, struct lfs1_info *info) { + lfs1_dir_t cwd; + lfs1_entry_t entry; + int err = lfs1_dir_find(lfs1, &cwd, &entry, &path); + if (err) { + return err; + } + + memset(info, 0, sizeof(*info)); + info->type = entry.d.type; + if (info->type == LFS1_TYPE_REG) { + info->size = entry.d.u.file.size; + } + + if (lfs1_paircmp(entry.d.u.dir, lfs1->root) == 0) { + strcpy(info->name, "/"); + } else { + err = lfs1_bd_read(lfs1, cwd.pair[0], + entry.off + 4+entry.d.elen+entry.d.alen, + info->name, entry.d.nlen); + if (err) { + return err; + } + } + + return 0; +} + +int lfs1_remove(lfs1_t *lfs1, const char *path) { + // deorphan if we haven't yet, needed at most once after poweron + if (!lfs1->deorphaned) { + int err = lfs1_deorphan(lfs1); + if (err) { + return err; + } + } + + lfs1_dir_t cwd; + lfs1_entry_t entry; + int err = lfs1_dir_find(lfs1, &cwd, &entry, &path); + if (err) { + return err; + } + + lfs1_dir_t dir; + if (entry.d.type == LFS1_TYPE_DIR) { + // must be empty before removal, checking size + // without masking top bit checks for any case where + // dir is not empty + err = lfs1_dir_fetch(lfs1, &dir, entry.d.u.dir); + if (err) { + return err; + } else if (dir.d.size != sizeof(dir.d)+4) { + return LFS1_ERR_NOTEMPTY; + } + } + + // remove the entry + err = lfs1_dir_remove(lfs1, &cwd, &entry); + if (err) { + return err; + } + + // if we were a directory, find pred, replace tail + if (entry.d.type == LFS1_TYPE_DIR) { + int res = lfs1_pred(lfs1, dir.pair, &cwd); + if (res < 0) { + return res; + } + + LFS1_ASSERT(res); // must have pred + cwd.d.tail[0] = dir.d.tail[0]; + cwd.d.tail[1] = dir.d.tail[1]; + + err = lfs1_dir_commit(lfs1, &cwd, NULL, 0); + if (err) { + return err; + } + } + + return 0; +} + +int lfs1_rename(lfs1_t *lfs1, const char *oldpath, const char *newpath) { + // deorphan if we haven't yet, needed at most once after poweron + if (!lfs1->deorphaned) { + int err = lfs1_deorphan(lfs1); + if (err) { + return err; + } + } + + // find old entry + lfs1_dir_t oldcwd; + lfs1_entry_t oldentry; + int err = lfs1_dir_find(lfs1, &oldcwd, &oldentry, &(const char *){oldpath}); + if (err) { + return err; + } + + // mark as moving + oldentry.d.type |= 0x80; + err = lfs1_dir_update(lfs1, &oldcwd, &oldentry, NULL); + if (err) { + return err; + } + + // allocate new entry + lfs1_dir_t newcwd; + lfs1_entry_t preventry; + err = lfs1_dir_find(lfs1, &newcwd, &preventry, &newpath); + if (err && (err != LFS1_ERR_NOENT || strchr(newpath, '/') != NULL)) { + return err; + } + + // must have same type + bool prevexists = (err != LFS1_ERR_NOENT); + if (prevexists && preventry.d.type != (0x7f & oldentry.d.type)) { + return LFS1_ERR_ISDIR; + } + + lfs1_dir_t dir; + if (prevexists && preventry.d.type == LFS1_TYPE_DIR) { + // must be empty before removal, checking size + // without masking top bit checks for any case where + // dir is not empty + err = lfs1_dir_fetch(lfs1, &dir, preventry.d.u.dir); + if (err) { + return err; + } else if (dir.d.size != sizeof(dir.d)+4) { + return LFS1_ERR_NOTEMPTY; + } + } + + // move to new location + lfs1_entry_t newentry = preventry; + newentry.d = oldentry.d; + newentry.d.type &= ~0x80; + newentry.d.nlen = strlen(newpath); + + if (prevexists) { + err = lfs1_dir_update(lfs1, &newcwd, &newentry, newpath); + if (err) { + return err; + } + } else { + err = lfs1_dir_append(lfs1, &newcwd, &newentry, newpath); + if (err) { + return err; + } + } + + // fetch old pair again in case dir block changed + lfs1->moving = true; + err = lfs1_dir_find(lfs1, &oldcwd, &oldentry, &oldpath); + if (err) { + return err; + } + lfs1->moving = false; + + // remove old entry + err = lfs1_dir_remove(lfs1, &oldcwd, &oldentry); + if (err) { + return err; + } + + // if we were a directory, find pred, replace tail + if (prevexists && preventry.d.type == LFS1_TYPE_DIR) { + int res = lfs1_pred(lfs1, dir.pair, &newcwd); + if (res < 0) { + return res; + } + + LFS1_ASSERT(res); // must have pred + newcwd.d.tail[0] = dir.d.tail[0]; + newcwd.d.tail[1] = dir.d.tail[1]; + + err = lfs1_dir_commit(lfs1, &newcwd, NULL, 0); + if (err) { + return err; + } + } + + return 0; +} + + +/// Filesystem operations /// +static void lfs1_deinit(lfs1_t *lfs1) { + // free allocated memory + if (!lfs1->cfg->read_buffer) { + lfs1_free(lfs1->rcache.buffer); + } + + if (!lfs1->cfg->prog_buffer) { + lfs1_free(lfs1->pcache.buffer); + } + + if (!lfs1->cfg->lookahead_buffer) { + lfs1_free(lfs1->free.buffer); + } +} + +static int lfs1_init(lfs1_t *lfs1, const struct lfs1_config *cfg) { + lfs1->cfg = cfg; + + // setup read cache + if (lfs1->cfg->read_buffer) { + lfs1->rcache.buffer = lfs1->cfg->read_buffer; + } else { + lfs1->rcache.buffer = lfs1_malloc(lfs1->cfg->read_size); + if (!lfs1->rcache.buffer) { + goto cleanup; + } + } + + // setup program cache + if (lfs1->cfg->prog_buffer) { + lfs1->pcache.buffer = lfs1->cfg->prog_buffer; + } else { + lfs1->pcache.buffer = lfs1_malloc(lfs1->cfg->prog_size); + if (!lfs1->pcache.buffer) { + goto cleanup; + } + } + + // zero to avoid information leaks + lfs1_cache_zero(lfs1, &lfs1->pcache); + lfs1_cache_drop(lfs1, &lfs1->rcache); + + // setup lookahead, round down to nearest 32-bits + LFS1_ASSERT(lfs1->cfg->lookahead % 32 == 0); + LFS1_ASSERT(lfs1->cfg->lookahead > 0); + if (lfs1->cfg->lookahead_buffer) { + lfs1->free.buffer = lfs1->cfg->lookahead_buffer; + } else { + lfs1->free.buffer = lfs1_malloc(lfs1->cfg->lookahead/8); + if (!lfs1->free.buffer) { + goto cleanup; + } + } + + // check that program and read sizes are multiples of the block size + LFS1_ASSERT(lfs1->cfg->prog_size % lfs1->cfg->read_size == 0); + LFS1_ASSERT(lfs1->cfg->block_size % lfs1->cfg->prog_size == 0); + + // check that the block size is large enough to fit ctz pointers + LFS1_ASSERT(4*lfs1_npw2(0xffffffff / (lfs1->cfg->block_size-2*4)) + <= lfs1->cfg->block_size); + + // setup default state + lfs1->root[0] = 0xffffffff; + lfs1->root[1] = 0xffffffff; + lfs1->files = NULL; + lfs1->dirs = NULL; + lfs1->deorphaned = false; + lfs1->moving = false; + + return 0; + +cleanup: + lfs1_deinit(lfs1); + return LFS1_ERR_NOMEM; +} + +int lfs1_format(lfs1_t *lfs1, const struct lfs1_config *cfg) { + int err = 0; + if (true) { + err = lfs1_init(lfs1, cfg); + if (err) { + return err; + } + + // create free lookahead + memset(lfs1->free.buffer, 0, lfs1->cfg->lookahead/8); + lfs1->free.off = 0; + lfs1->free.size = lfs1_min(lfs1->cfg->lookahead, lfs1->cfg->block_count); + lfs1->free.i = 0; + lfs1_alloc_ack(lfs1); + + // create superblock dir + lfs1_dir_t superdir; + err = lfs1_dir_alloc(lfs1, &superdir); + if (err) { + goto cleanup; + } + + // write root directory + lfs1_dir_t root; + err = lfs1_dir_alloc(lfs1, &root); + if (err) { + goto cleanup; + } + + err = lfs1_dir_commit(lfs1, &root, NULL, 0); + if (err) { + goto cleanup; + } + + lfs1->root[0] = root.pair[0]; + lfs1->root[1] = root.pair[1]; + + // write superblocks + lfs1_superblock_t superblock = { + .off = sizeof(superdir.d), + .d.type = LFS1_TYPE_SUPERBLOCK, + .d.elen = sizeof(superblock.d) - sizeof(superblock.d.magic) - 4, + .d.nlen = sizeof(superblock.d.magic), + .d.version = LFS1_DISK_VERSION, + .d.magic = {"littlefs"}, + .d.block_size = lfs1->cfg->block_size, + .d.block_count = lfs1->cfg->block_count, + .d.root = {lfs1->root[0], lfs1->root[1]}, + }; + superdir.d.tail[0] = root.pair[0]; + superdir.d.tail[1] = root.pair[1]; + superdir.d.size = sizeof(superdir.d) + sizeof(superblock.d) + 4; + + // write both pairs to be safe + lfs1_superblock_tole32(&superblock.d); + bool valid = false; + for (int i = 0; i < 2; i++) { + err = lfs1_dir_commit(lfs1, &superdir, (struct lfs1_region[]){ + {sizeof(superdir.d), sizeof(superblock.d), + &superblock.d, sizeof(superblock.d)} + }, 1); + if (err && err != LFS1_ERR_CORRUPT) { + goto cleanup; + } + + valid = valid || !err; + } + + if (!valid) { + err = LFS1_ERR_CORRUPT; + goto cleanup; + } + + // sanity check that fetch works + err = lfs1_dir_fetch(lfs1, &superdir, (const lfs1_block_t[2]){0, 1}); + if (err) { + goto cleanup; + } + + lfs1_alloc_ack(lfs1); + } + +cleanup: + lfs1_deinit(lfs1); + return err; +} + +int lfs1_mount(lfs1_t *lfs1, const struct lfs1_config *cfg) { + int err = 0; + if (true) { + err = lfs1_init(lfs1, cfg); + if (err) { + return err; + } + + // setup free lookahead + lfs1->free.off = 0; + lfs1->free.size = 0; + lfs1->free.i = 0; + lfs1_alloc_ack(lfs1); + + // load superblock + lfs1_dir_t dir; + lfs1_superblock_t superblock; + err = lfs1_dir_fetch(lfs1, &dir, (const lfs1_block_t[2]){0, 1}); + if (err && err != LFS1_ERR_CORRUPT) { + goto cleanup; + } + + if (!err) { + err = lfs1_bd_read(lfs1, dir.pair[0], sizeof(dir.d), + &superblock.d, sizeof(superblock.d)); + lfs1_superblock_fromle32(&superblock.d); + if (err) { + goto cleanup; + } + + lfs1->root[0] = superblock.d.root[0]; + lfs1->root[1] = superblock.d.root[1]; + } + + if (err || memcmp(superblock.d.magic, "littlefs", 8) != 0) { + LFS1_ERROR("Invalid superblock at %d %d", 0, 1); + err = LFS1_ERR_CORRUPT; + goto cleanup; + } + + uint16_t major_version = (0xffff & (superblock.d.version >> 16)); + uint16_t minor_version = (0xffff & (superblock.d.version >> 0)); + if ((major_version != LFS1_DISK_VERSION_MAJOR || + minor_version > LFS1_DISK_VERSION_MINOR)) { + LFS1_ERROR("Invalid version %d.%d", major_version, minor_version); + err = LFS1_ERR_INVAL; + goto cleanup; + } + + return 0; + } + +cleanup: + + lfs1_deinit(lfs1); + return err; +} + +int lfs1_unmount(lfs1_t *lfs1) { + lfs1_deinit(lfs1); + return 0; +} + + +/// Littlefs specific operations /// +int lfs1_traverse(lfs1_t *lfs1, int (*cb)(void*, lfs1_block_t), void *data) { + if (lfs1_pairisnull(lfs1->root)) { + return 0; + } + + // iterate over metadata pairs + lfs1_dir_t dir; + lfs1_entry_t entry; + lfs1_block_t cwd[2] = {0, 1}; + + while (true) { + for (int i = 0; i < 2; i++) { + int err = cb(data, cwd[i]); + if (err) { + return err; + } + } + + int err = lfs1_dir_fetch(lfs1, &dir, cwd); + if (err) { + return err; + } + + // iterate over contents + while (dir.off + sizeof(entry.d) <= (0x7fffffff & dir.d.size)-4) { + err = lfs1_bd_read(lfs1, dir.pair[0], dir.off, + &entry.d, sizeof(entry.d)); + lfs1_entry_fromle32(&entry.d); + if (err) { + return err; + } + + dir.off += lfs1_entry_size(&entry); + if ((0x70 & entry.d.type) == (0x70 & LFS1_TYPE_REG)) { + err = lfs1_ctz_traverse(lfs1, &lfs1->rcache, NULL, + entry.d.u.file.head, entry.d.u.file.size, cb, data); + if (err) { + return err; + } + } + } + + cwd[0] = dir.d.tail[0]; + cwd[1] = dir.d.tail[1]; + + if (lfs1_pairisnull(cwd)) { + break; + } + } + + // iterate over any open files + for (lfs1_file_t *f = lfs1->files; f; f = f->next) { + if (f->flags & LFS1_F_DIRTY) { + int err = lfs1_ctz_traverse(lfs1, &lfs1->rcache, &f->cache, + f->head, f->size, cb, data); + if (err) { + return err; + } + } + + if (f->flags & LFS1_F_WRITING) { + int err = lfs1_ctz_traverse(lfs1, &lfs1->rcache, &f->cache, + f->block, f->pos, cb, data); + if (err) { + return err; + } + } + } + + return 0; +} + +static int lfs1_pred(lfs1_t *lfs1, const lfs1_block_t dir[2], lfs1_dir_t *pdir) { + if (lfs1_pairisnull(lfs1->root)) { + return 0; + } + + // iterate over all directory directory entries + int err = lfs1_dir_fetch(lfs1, pdir, (const lfs1_block_t[2]){0, 1}); + if (err) { + return err; + } + + while (!lfs1_pairisnull(pdir->d.tail)) { + if (lfs1_paircmp(pdir->d.tail, dir) == 0) { + return true; + } + + err = lfs1_dir_fetch(lfs1, pdir, pdir->d.tail); + if (err) { + return err; + } + } + + return false; +} + +static int lfs1_parent(lfs1_t *lfs1, const lfs1_block_t dir[2], + lfs1_dir_t *parent, lfs1_entry_t *entry) { + if (lfs1_pairisnull(lfs1->root)) { + return 0; + } + + parent->d.tail[0] = 0; + parent->d.tail[1] = 1; + + // iterate over all directory directory entries + while (!lfs1_pairisnull(parent->d.tail)) { + int err = lfs1_dir_fetch(lfs1, parent, parent->d.tail); + if (err) { + return err; + } + + while (true) { + err = lfs1_dir_next(lfs1, parent, entry); + if (err && err != LFS1_ERR_NOENT) { + return err; + } + + if (err == LFS1_ERR_NOENT) { + break; + } + + if (((0x70 & entry->d.type) == (0x70 & LFS1_TYPE_DIR)) && + lfs1_paircmp(entry->d.u.dir, dir) == 0) { + return true; + } + } + } + + return false; +} + +static int lfs1_moved(lfs1_t *lfs1, const void *e) { + if (lfs1_pairisnull(lfs1->root)) { + return 0; + } + + // skip superblock + lfs1_dir_t cwd; + int err = lfs1_dir_fetch(lfs1, &cwd, (const lfs1_block_t[2]){0, 1}); + if (err) { + return err; + } + + // iterate over all directory directory entries + lfs1_entry_t entry; + while (!lfs1_pairisnull(cwd.d.tail)) { + err = lfs1_dir_fetch(lfs1, &cwd, cwd.d.tail); + if (err) { + return err; + } + + while (true) { + err = lfs1_dir_next(lfs1, &cwd, &entry); + if (err && err != LFS1_ERR_NOENT) { + return err; + } + + if (err == LFS1_ERR_NOENT) { + break; + } + + if (!(0x80 & entry.d.type) && + memcmp(&entry.d.u, e, sizeof(entry.d.u)) == 0) { + return true; + } + } + } + + return false; +} + +static int lfs1_relocate(lfs1_t *lfs1, + const lfs1_block_t oldpair[2], const lfs1_block_t newpair[2]) { + // find parent + lfs1_dir_t parent; + lfs1_entry_t entry; + int res = lfs1_parent(lfs1, oldpair, &parent, &entry); + if (res < 0) { + return res; + } + + if (res) { + // update disk, this creates a desync + entry.d.u.dir[0] = newpair[0]; + entry.d.u.dir[1] = newpair[1]; + + int err = lfs1_dir_update(lfs1, &parent, &entry, NULL); + if (err) { + return err; + } + + // update internal root + if (lfs1_paircmp(oldpair, lfs1->root) == 0) { + LFS1_DEBUG("Relocating root %" PRIu32 " %" PRIu32, + newpair[0], newpair[1]); + lfs1->root[0] = newpair[0]; + lfs1->root[1] = newpair[1]; + } + + // clean up bad block, which should now be a desync + return lfs1_deorphan(lfs1); + } + + // find pred + res = lfs1_pred(lfs1, oldpair, &parent); + if (res < 0) { + return res; + } + + if (res) { + // just replace bad pair, no desync can occur + parent.d.tail[0] = newpair[0]; + parent.d.tail[1] = newpair[1]; + + return lfs1_dir_commit(lfs1, &parent, NULL, 0); + } + + // couldn't find dir, must be new + return 0; +} + +int lfs1_deorphan(lfs1_t *lfs1) { + lfs1->deorphaned = true; + + if (lfs1_pairisnull(lfs1->root)) { + return 0; + } + + lfs1_dir_t pdir = {.d.size = 0x80000000}; + lfs1_dir_t cwd = {.d.tail[0] = 0, .d.tail[1] = 1}; + + // iterate over all directory directory entries + for (lfs1_size_t i = 0; i < lfs1->cfg->block_count; i++) { + if (lfs1_pairisnull(cwd.d.tail)) { + return 0; + } + + int err = lfs1_dir_fetch(lfs1, &cwd, cwd.d.tail); + if (err) { + return err; + } + + // check head blocks for orphans + if (!(0x80000000 & pdir.d.size)) { + // check if we have a parent + lfs1_dir_t parent; + lfs1_entry_t entry; + int res = lfs1_parent(lfs1, pdir.d.tail, &parent, &entry); + if (res < 0) { + return res; + } + + if (!res) { + // we are an orphan + LFS1_DEBUG("Found orphan %" PRIu32 " %" PRIu32, + pdir.d.tail[0], pdir.d.tail[1]); + + pdir.d.tail[0] = cwd.d.tail[0]; + pdir.d.tail[1] = cwd.d.tail[1]; + + err = lfs1_dir_commit(lfs1, &pdir, NULL, 0); + if (err) { + return err; + } + + return 0; + } + + if (!lfs1_pairsync(entry.d.u.dir, pdir.d.tail)) { + // we have desynced + LFS1_DEBUG("Found desync %" PRIu32 " %" PRIu32, + entry.d.u.dir[0], entry.d.u.dir[1]); + + pdir.d.tail[0] = entry.d.u.dir[0]; + pdir.d.tail[1] = entry.d.u.dir[1]; + + err = lfs1_dir_commit(lfs1, &pdir, NULL, 0); + if (err) { + return err; + } + + return 0; + } + } + + // check entries for moves + lfs1_entry_t entry; + while (true) { + err = lfs1_dir_next(lfs1, &cwd, &entry); + if (err && err != LFS1_ERR_NOENT) { + return err; + } + + if (err == LFS1_ERR_NOENT) { + break; + } + + // found moved entry + if (entry.d.type & 0x80) { + int moved = lfs1_moved(lfs1, &entry.d.u); + if (moved < 0) { + return moved; + } + + if (moved) { + LFS1_DEBUG("Found move %" PRIu32 " %" PRIu32, + entry.d.u.dir[0], entry.d.u.dir[1]); + err = lfs1_dir_remove(lfs1, &cwd, &entry); + if (err) { + return err; + } + } else { + LFS1_DEBUG("Found partial move %" PRIu32 " %" PRIu32, + entry.d.u.dir[0], entry.d.u.dir[1]); + entry.d.type &= ~0x80; + err = lfs1_dir_update(lfs1, &cwd, &entry, NULL); + if (err) { + return err; + } + } + } + } + + memcpy(&pdir, &cwd, sizeof(pdir)); + } + + // If we reached here, we have more directory pairs than blocks in the + // filesystem... So something must be horribly wrong + return LFS1_ERR_CORRUPT; +} diff --git a/lib/littlefs/lfs1.h b/lib/littlefs/lfs1.h new file mode 100644 index 0000000000..355c145d08 --- /dev/null +++ b/lib/littlefs/lfs1.h @@ -0,0 +1,501 @@ +/* + * The little filesystem + * + * Copyright (c) 2017, Arm Limited. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef LFS1_H +#define LFS1_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/// Version info /// + +// Software library version +// Major (top-nibble), incremented on backwards incompatible changes +// Minor (bottom-nibble), incremented on feature additions +#define LFS1_VERSION 0x00010007 +#define LFS1_VERSION_MAJOR (0xffff & (LFS1_VERSION >> 16)) +#define LFS1_VERSION_MINOR (0xffff & (LFS1_VERSION >> 0)) + +// Version of On-disk data structures +// Major (top-nibble), incremented on backwards incompatible changes +// Minor (bottom-nibble), incremented on feature additions +#define LFS1_DISK_VERSION 0x00010001 +#define LFS1_DISK_VERSION_MAJOR (0xffff & (LFS1_DISK_VERSION >> 16)) +#define LFS1_DISK_VERSION_MINOR (0xffff & (LFS1_DISK_VERSION >> 0)) + + +/// Definitions /// + +// Type definitions +typedef uint32_t lfs1_size_t; +typedef uint32_t lfs1_off_t; + +typedef int32_t lfs1_ssize_t; +typedef int32_t lfs1_soff_t; + +typedef uint32_t lfs1_block_t; + +// Max name size in bytes +#ifndef LFS1_NAME_MAX +#define LFS1_NAME_MAX 255 +#endif + +// Max file size in bytes +#ifndef LFS1_FILE_MAX +#define LFS1_FILE_MAX 2147483647 +#endif + +// Possible error codes, these are negative to allow +// valid positive return values +enum lfs1_error { + LFS1_ERR_OK = 0, // No error + LFS1_ERR_IO = -5, // Error during device operation + LFS1_ERR_CORRUPT = -52, // Corrupted + LFS1_ERR_NOENT = -2, // No directory entry + LFS1_ERR_EXIST = -17, // Entry already exists + LFS1_ERR_NOTDIR = -20, // Entry is not a dir + LFS1_ERR_ISDIR = -21, // Entry is a dir + LFS1_ERR_NOTEMPTY = -39, // Dir is not empty + LFS1_ERR_BADF = -9, // Bad file number + LFS1_ERR_FBIG = -27, // File too large + LFS1_ERR_INVAL = -22, // Invalid parameter + LFS1_ERR_NOSPC = -28, // No space left on device + LFS1_ERR_NOMEM = -12, // No more memory available +}; + +// File types +enum lfs1_type { + LFS1_TYPE_REG = 0x11, + LFS1_TYPE_DIR = 0x22, + LFS1_TYPE_SUPERBLOCK = 0x2e, +}; + +// File open flags +enum lfs1_open_flags { + // open flags + LFS1_O_RDONLY = 1, // Open a file as read only + LFS1_O_WRONLY = 2, // Open a file as write only + LFS1_O_RDWR = 3, // Open a file as read and write + LFS1_O_CREAT = 0x0100, // Create a file if it does not exist + LFS1_O_EXCL = 0x0200, // Fail if a file already exists + LFS1_O_TRUNC = 0x0400, // Truncate the existing file to zero size + LFS1_O_APPEND = 0x0800, // Move to end of file on every write + + // internally used flags + LFS1_F_DIRTY = 0x10000, // File does not match storage + LFS1_F_WRITING = 0x20000, // File has been written since last flush + LFS1_F_READING = 0x40000, // File has been read since last flush + LFS1_F_ERRED = 0x80000, // An error occured during write +}; + +// File seek flags +enum lfs1_whence_flags { + LFS1_SEEK_SET = 0, // Seek relative to an absolute position + LFS1_SEEK_CUR = 1, // Seek relative to the current file position + LFS1_SEEK_END = 2, // Seek relative to the end of the file +}; + + +// Configuration provided during initialization of the littlefs +struct lfs1_config { + // Opaque user provided context that can be used to pass + // information to the block device operations + void *context; + + // Read a region in a block. Negative error codes are propogated + // to the user. + int (*read)(const struct lfs1_config *c, lfs1_block_t block, + lfs1_off_t off, void *buffer, lfs1_size_t size); + + // Program a region in a block. The block must have previously + // been erased. Negative error codes are propogated to the user. + // May return LFS1_ERR_CORRUPT if the block should be considered bad. + int (*prog)(const struct lfs1_config *c, lfs1_block_t block, + lfs1_off_t off, const void *buffer, lfs1_size_t size); + + // Erase a block. A block must be erased before being programmed. + // The state of an erased block is undefined. Negative error codes + // are propogated to the user. + // May return LFS1_ERR_CORRUPT if the block should be considered bad. + int (*erase)(const struct lfs1_config *c, lfs1_block_t block); + + // Sync the state of the underlying block device. Negative error codes + // are propogated to the user. + int (*sync)(const struct lfs1_config *c); + + // Minimum size of a block read. This determines the size of read buffers. + // This may be larger than the physical read size to improve performance + // by caching more of the block device. + lfs1_size_t read_size; + + // Minimum size of a block program. This determines the size of program + // buffers. This may be larger than the physical program size to improve + // performance by caching more of the block device. + // Must be a multiple of the read size. + lfs1_size_t prog_size; + + // Size of an erasable block. This does not impact ram consumption and + // may be larger than the physical erase size. However, this should be + // kept small as each file currently takes up an entire block. + // Must be a multiple of the program size. + lfs1_size_t block_size; + + // Number of erasable blocks on the device. + lfs1_size_t block_count; + + // Number of blocks to lookahead during block allocation. A larger + // lookahead reduces the number of passes required to allocate a block. + // The lookahead buffer requires only 1 bit per block so it can be quite + // large with little ram impact. Should be a multiple of 32. + lfs1_size_t lookahead; + + // Optional, statically allocated read buffer. Must be read sized. + void *read_buffer; + + // Optional, statically allocated program buffer. Must be program sized. + void *prog_buffer; + + // Optional, statically allocated lookahead buffer. Must be 1 bit per + // lookahead block. + void *lookahead_buffer; + + // Optional, statically allocated buffer for files. Must be program sized. + // If enabled, only one file may be opened at a time. + void *file_buffer; +}; + +// Optional configuration provided during lfs1_file_opencfg +struct lfs1_file_config { + // Optional, statically allocated buffer for files. Must be program sized. + // If NULL, malloc will be used by default. + void *buffer; +}; + +// File info structure +struct lfs1_info { + // Type of the file, either LFS1_TYPE_REG or LFS1_TYPE_DIR + uint8_t type; + + // Size of the file, only valid for REG files + lfs1_size_t size; + + // Name of the file stored as a null-terminated string + char name[LFS1_NAME_MAX+1]; +}; + + +/// littlefs data structures /// +typedef struct lfs1_entry { + lfs1_off_t off; + + struct lfs1_disk_entry { + uint8_t type; + uint8_t elen; + uint8_t alen; + uint8_t nlen; + union { + struct { + lfs1_block_t head; + lfs1_size_t size; + } file; + lfs1_block_t dir[2]; + } u; + } d; +} lfs1_entry_t; + +typedef struct lfs1_cache { + lfs1_block_t block; + lfs1_off_t off; + uint8_t *buffer; +} lfs1_cache_t; + +typedef struct lfs1_file { + struct lfs1_file *next; + lfs1_block_t pair[2]; + lfs1_off_t poff; + + lfs1_block_t head; + lfs1_size_t size; + + const struct lfs1_file_config *cfg; + uint32_t flags; + lfs1_off_t pos; + lfs1_block_t block; + lfs1_off_t off; + lfs1_cache_t cache; +} lfs1_file_t; + +typedef struct lfs1_dir { + struct lfs1_dir *next; + lfs1_block_t pair[2]; + lfs1_off_t off; + + lfs1_block_t head[2]; + lfs1_off_t pos; + + struct lfs1_disk_dir { + uint32_t rev; + lfs1_size_t size; + lfs1_block_t tail[2]; + } d; +} lfs1_dir_t; + +typedef struct lfs1_superblock { + lfs1_off_t off; + + struct lfs1_disk_superblock { + uint8_t type; + uint8_t elen; + uint8_t alen; + uint8_t nlen; + lfs1_block_t root[2]; + uint32_t block_size; + uint32_t block_count; + uint32_t version; + char magic[8]; + } d; +} lfs1_superblock_t; + +typedef struct lfs1_free { + lfs1_block_t off; + lfs1_block_t size; + lfs1_block_t i; + lfs1_block_t ack; + uint32_t *buffer; +} lfs1_free_t; + +// The littlefs type +typedef struct lfs1 { + const struct lfs1_config *cfg; + + lfs1_block_t root[2]; + lfs1_file_t *files; + lfs1_dir_t *dirs; + + lfs1_cache_t rcache; + lfs1_cache_t pcache; + + lfs1_free_t free; + bool deorphaned; + bool moving; +} lfs1_t; + + +/// Filesystem functions /// + +// Format a block device with the littlefs +// +// Requires a littlefs object and config struct. This clobbers the littlefs +// object, and does not leave the filesystem mounted. The config struct must +// be zeroed for defaults and backwards compatibility. +// +// Returns a negative error code on failure. +int lfs1_format(lfs1_t *lfs1, const struct lfs1_config *config); + +// Mounts a littlefs +// +// Requires a littlefs object and config struct. Multiple filesystems +// may be mounted simultaneously with multiple littlefs objects. Both +// lfs1 and config must be allocated while mounted. The config struct must +// be zeroed for defaults and backwards compatibility. +// +// Returns a negative error code on failure. +int lfs1_mount(lfs1_t *lfs1, const struct lfs1_config *config); + +// Unmounts a littlefs +// +// Does nothing besides releasing any allocated resources. +// Returns a negative error code on failure. +int lfs1_unmount(lfs1_t *lfs1); + +/// General operations /// + +// Removes a file or directory +// +// If removing a directory, the directory must be empty. +// Returns a negative error code on failure. +int lfs1_remove(lfs1_t *lfs1, const char *path); + +// Rename or move a file or directory +// +// If the destination exists, it must match the source in type. +// If the destination is a directory, the directory must be empty. +// +// Returns a negative error code on failure. +int lfs1_rename(lfs1_t *lfs1, const char *oldpath, const char *newpath); + +// Find info about a file or directory +// +// Fills out the info structure, based on the specified file or directory. +// Returns a negative error code on failure. +int lfs1_stat(lfs1_t *lfs1, const char *path, struct lfs1_info *info); + + +/// File operations /// + +// Open a file +// +// The mode that the file is opened in is determined by the flags, which +// are values from the enum lfs1_open_flags that are bitwise-ored together. +// +// Returns a negative error code on failure. +int lfs1_file_open(lfs1_t *lfs1, lfs1_file_t *file, + const char *path, int flags); + +// Open a file with extra configuration +// +// The mode that the file is opened in is determined by the flags, which +// are values from the enum lfs1_open_flags that are bitwise-ored together. +// +// The config struct provides additional config options per file as described +// above. The config struct must be allocated while the file is open, and the +// config struct must be zeroed for defaults and backwards compatibility. +// +// Returns a negative error code on failure. +int lfs1_file_opencfg(lfs1_t *lfs1, lfs1_file_t *file, + const char *path, int flags, + const struct lfs1_file_config *config); + +// Close a file +// +// Any pending writes are written out to storage as though +// sync had been called and releases any allocated resources. +// +// Returns a negative error code on failure. +int lfs1_file_close(lfs1_t *lfs1, lfs1_file_t *file); + +// Synchronize a file on storage +// +// Any pending writes are written out to storage. +// Returns a negative error code on failure. +int lfs1_file_sync(lfs1_t *lfs1, lfs1_file_t *file); + +// Read data from file +// +// Takes a buffer and size indicating where to store the read data. +// Returns the number of bytes read, or a negative error code on failure. +lfs1_ssize_t lfs1_file_read(lfs1_t *lfs1, lfs1_file_t *file, + void *buffer, lfs1_size_t size); + +// Write data to file +// +// Takes a buffer and size indicating the data to write. The file will not +// actually be updated on the storage until either sync or close is called. +// +// Returns the number of bytes written, or a negative error code on failure. +lfs1_ssize_t lfs1_file_write(lfs1_t *lfs1, lfs1_file_t *file, + const void *buffer, lfs1_size_t size); + +// Change the position of the file +// +// The change in position is determined by the offset and whence flag. +// Returns the old position of the file, or a negative error code on failure. +lfs1_soff_t lfs1_file_seek(lfs1_t *lfs1, lfs1_file_t *file, + lfs1_soff_t off, int whence); + +// Truncates the size of the file to the specified size +// +// Returns a negative error code on failure. +int lfs1_file_truncate(lfs1_t *lfs1, lfs1_file_t *file, lfs1_off_t size); + +// Return the position of the file +// +// Equivalent to lfs1_file_seek(lfs1, file, 0, LFS1_SEEK_CUR) +// Returns the position of the file, or a negative error code on failure. +lfs1_soff_t lfs1_file_tell(lfs1_t *lfs1, lfs1_file_t *file); + +// Change the position of the file to the beginning of the file +// +// Equivalent to lfs1_file_seek(lfs1, file, 0, LFS1_SEEK_CUR) +// Returns a negative error code on failure. +int lfs1_file_rewind(lfs1_t *lfs1, lfs1_file_t *file); + +// Return the size of the file +// +// Similar to lfs1_file_seek(lfs1, file, 0, LFS1_SEEK_END) +// Returns the size of the file, or a negative error code on failure. +lfs1_soff_t lfs1_file_size(lfs1_t *lfs1, lfs1_file_t *file); + + +/// Directory operations /// + +// Create a directory +// +// Returns a negative error code on failure. +int lfs1_mkdir(lfs1_t *lfs1, const char *path); + +// Open a directory +// +// Once open a directory can be used with read to iterate over files. +// Returns a negative error code on failure. +int lfs1_dir_open(lfs1_t *lfs1, lfs1_dir_t *dir, const char *path); + +// Close a directory +// +// Releases any allocated resources. +// Returns a negative error code on failure. +int lfs1_dir_close(lfs1_t *lfs1, lfs1_dir_t *dir); + +// Read an entry in the directory +// +// Fills out the info structure, based on the specified file or directory. +// Returns a negative error code on failure. +int lfs1_dir_read(lfs1_t *lfs1, lfs1_dir_t *dir, struct lfs1_info *info); + +// Change the position of the directory +// +// The new off must be a value previous returned from tell and specifies +// an absolute offset in the directory seek. +// +// Returns a negative error code on failure. +int lfs1_dir_seek(lfs1_t *lfs1, lfs1_dir_t *dir, lfs1_off_t off); + +// Return the position of the directory +// +// The returned offset is only meant to be consumed by seek and may not make +// sense, but does indicate the current position in the directory iteration. +// +// Returns the position of the directory, or a negative error code on failure. +lfs1_soff_t lfs1_dir_tell(lfs1_t *lfs1, lfs1_dir_t *dir); + +// Change the position of the directory to the beginning of the directory +// +// Returns a negative error code on failure. +int lfs1_dir_rewind(lfs1_t *lfs1, lfs1_dir_t *dir); + + +/// Miscellaneous littlefs specific operations /// + +// Traverse through all blocks in use by the filesystem +// +// The provided callback will be called with each block address that is +// currently in use by the filesystem. This can be used to determine which +// blocks are in use or how much of the storage is available. +// +// Returns a negative error code on failure. +int lfs1_traverse(lfs1_t *lfs1, int (*cb)(void*, lfs1_block_t), void *data); + +// Prunes any recoverable errors that may have occured in the filesystem +// +// Not needed to be called by user unless an operation is interrupted +// but the filesystem is still mounted. This is already called on first +// allocation. +// +// Returns a negative error code on failure. +int lfs1_deorphan(lfs1_t *lfs1); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/lib/littlefs/lfs1_util.c b/lib/littlefs/lfs1_util.c new file mode 100644 index 0000000000..3832a5ddb3 --- /dev/null +++ b/lib/littlefs/lfs1_util.c @@ -0,0 +1,31 @@ +/* + * lfs1 util functions + * + * Copyright (c) 2017, Arm Limited. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "lfs1_util.h" + +// Only compile if user does not provide custom config +#ifndef LFS1_CONFIG + + +// Software CRC implementation with small lookup table +void lfs1_crc(uint32_t *restrict crc, const void *buffer, size_t size) { + static const uint32_t rtable[16] = { + 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, + 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, + 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c, + }; + + const uint8_t *data = buffer; + + for (size_t i = 0; i < size; i++) { + *crc = (*crc >> 4) ^ rtable[(*crc ^ (data[i] >> 0)) & 0xf]; + *crc = (*crc >> 4) ^ rtable[(*crc ^ (data[i] >> 4)) & 0xf]; + } +} + + +#endif diff --git a/lib/littlefs/lfs1_util.h b/lib/littlefs/lfs1_util.h new file mode 100644 index 0000000000..b33b6a7adc --- /dev/null +++ b/lib/littlefs/lfs1_util.h @@ -0,0 +1,186 @@ +/* + * lfs1 utility functions + * + * Copyright (c) 2017, Arm Limited. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef LFS1_UTIL_H +#define LFS1_UTIL_H + +// Users can override lfs1_util.h with their own configuration by defining +// LFS1_CONFIG as a header file to include (-DLFS1_CONFIG=lfs1_config.h). +// +// If LFS1_CONFIG is used, none of the default utils will be emitted and must be +// provided by the config file. To start I would suggest copying lfs1_util.h and +// modifying as needed. +#ifdef LFS1_CONFIG +#define LFS1_STRINGIZE(x) LFS1_STRINGIZE2(x) +#define LFS1_STRINGIZE2(x) #x +#include LFS1_STRINGIZE(LFS1_CONFIG) +#else + +// System includes +#include +#include +#include + +#ifndef LFS1_NO_MALLOC +#include +#endif +#ifndef LFS1_NO_ASSERT +#include +#endif +#if !defined(LFS1_NO_DEBUG) || !defined(LFS1_NO_WARN) || !defined(LFS1_NO_ERROR) +#include +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + + +// Macros, may be replaced by system specific wrappers. Arguments to these +// macros must not have side-effects as the macros can be removed for a smaller +// code footprint + +// Logging functions +#ifndef LFS1_NO_DEBUG +#define LFS1_DEBUG(fmt, ...) \ + printf("lfs1 debug:%d: " fmt "\n", __LINE__, __VA_ARGS__) +#else +#define LFS1_DEBUG(fmt, ...) +#endif + +#ifndef LFS1_NO_WARN +#define LFS1_WARN(fmt, ...) \ + printf("lfs1 warn:%d: " fmt "\n", __LINE__, __VA_ARGS__) +#else +#define LFS1_WARN(fmt, ...) +#endif + +#ifndef LFS1_NO_ERROR +#define LFS1_ERROR(fmt, ...) \ + printf("lfs1 error:%d: " fmt "\n", __LINE__, __VA_ARGS__) +#else +#define LFS1_ERROR(fmt, ...) +#endif + +// Runtime assertions +#ifndef LFS1_NO_ASSERT +#define LFS1_ASSERT(test) assert(test) +#else +#define LFS1_ASSERT(test) +#endif + + +// Builtin functions, these may be replaced by more efficient +// toolchain-specific implementations. LFS1_NO_INTRINSICS falls back to a more +// expensive basic C implementation for debugging purposes + +// Min/max functions for unsigned 32-bit numbers +static inline uint32_t lfs1_max(uint32_t a, uint32_t b) { + return (a > b) ? a : b; +} + +static inline uint32_t lfs1_min(uint32_t a, uint32_t b) { + return (a < b) ? a : b; +} + +// Find the next smallest power of 2 less than or equal to a +static inline uint32_t lfs1_npw2(uint32_t a) { +#if !defined(LFS1_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) + return 32 - __builtin_clz(a-1); +#else + uint32_t r = 0; + uint32_t s; + a -= 1; + s = (a > 0xffff) << 4; a >>= s; r |= s; + s = (a > 0xff ) << 3; a >>= s; r |= s; + s = (a > 0xf ) << 2; a >>= s; r |= s; + s = (a > 0x3 ) << 1; a >>= s; r |= s; + return (r | (a >> 1)) + 1; +#endif +} + +// Count the number of trailing binary zeros in a +// lfs1_ctz(0) may be undefined +static inline uint32_t lfs1_ctz(uint32_t a) { +#if !defined(LFS1_NO_INTRINSICS) && defined(__GNUC__) + return __builtin_ctz(a); +#else + return lfs1_npw2((a & -a) + 1) - 1; +#endif +} + +// Count the number of binary ones in a +static inline uint32_t lfs1_popc(uint32_t a) { +#if !defined(LFS1_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) + return __builtin_popcount(a); +#else + a = a - ((a >> 1) & 0x55555555); + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); + return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24; +#endif +} + +// Find the sequence comparison of a and b, this is the distance +// between a and b ignoring overflow +static inline int lfs1_scmp(uint32_t a, uint32_t b) { + return (int)(unsigned)(a - b); +} + +// Convert from 32-bit little-endian to native order +static inline uint32_t lfs1_fromle32(uint32_t a) { +#if !defined(LFS1_NO_INTRINSICS) && ( \ + (defined( BYTE_ORDER ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ + (defined(__BYTE_ORDER ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ + (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) + return a; +#elif !defined(LFS1_NO_INTRINSICS) && ( \ + (defined( BYTE_ORDER ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ + (defined(__BYTE_ORDER ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ + (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) + return __builtin_bswap32(a); +#else + return (((uint8_t*)&a)[0] << 0) | + (((uint8_t*)&a)[1] << 8) | + (((uint8_t*)&a)[2] << 16) | + (((uint8_t*)&a)[3] << 24); +#endif +} + +// Convert to 32-bit little-endian from native order +static inline uint32_t lfs1_tole32(uint32_t a) { + return lfs1_fromle32(a); +} + +// Calculate CRC-32 with polynomial = 0x04c11db7 +void lfs1_crc(uint32_t *crc, const void *buffer, size_t size); + +// Allocate memory, only used if buffers are not provided to littlefs +static inline void *lfs1_malloc(size_t size) { +#ifndef LFS1_NO_MALLOC + return malloc(size); +#else + (void)size; + return NULL; +#endif +} + +// Deallocate memory, only used if buffers are not provided to littlefs +static inline void lfs1_free(void *p) { +#ifndef LFS1_NO_MALLOC + free(p); +#else + (void)p; +#endif +} + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif +#endif From 2e66d83ca445d5b7216c1e483bd51bc5e6127ddc Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 18 Oct 2019 17:23:23 +1100 Subject: [PATCH 0900/1788] lib/littlefs: Add littlefs v2.1.3 source. --- lib/littlefs/lfs2.c | 4742 ++++++++++++++++++++++++++++++++++++++ lib/littlefs/lfs2.h | 651 ++++++ lib/littlefs/lfs2_util.c | 33 + lib/littlefs/lfs2_util.h | 230 ++ 4 files changed, 5656 insertions(+) create mode 100644 lib/littlefs/lfs2.c create mode 100644 lib/littlefs/lfs2.h create mode 100644 lib/littlefs/lfs2_util.c create mode 100644 lib/littlefs/lfs2_util.h diff --git a/lib/littlefs/lfs2.c b/lib/littlefs/lfs2.c new file mode 100644 index 0000000000..dea01b1c07 --- /dev/null +++ b/lib/littlefs/lfs2.c @@ -0,0 +1,4742 @@ +/* + * The little filesystem + * + * Copyright (c) 2017, Arm Limited. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "lfs2.h" +#include "lfs2_util.h" + +#define LFS2_BLOCK_NULL ((lfs2_block_t)-1) +#define LFS2_BLOCK_INLINE ((lfs2_block_t)-2) + +/// Caching block device operations /// +static inline void lfs2_cache_drop(lfs2_t *lfs2, lfs2_cache_t *rcache) { + // do not zero, cheaper if cache is readonly or only going to be + // written with identical data (during relocates) + (void)lfs2; + rcache->block = LFS2_BLOCK_NULL; +} + +static inline void lfs2_cache_zero(lfs2_t *lfs2, lfs2_cache_t *pcache) { + // zero to avoid information leak + memset(pcache->buffer, 0xff, lfs2->cfg->cache_size); + pcache->block = LFS2_BLOCK_NULL; +} + +static int lfs2_bd_read(lfs2_t *lfs2, + const lfs2_cache_t *pcache, lfs2_cache_t *rcache, lfs2_size_t hint, + lfs2_block_t block, lfs2_off_t off, + void *buffer, lfs2_size_t size) { + uint8_t *data = buffer; + LFS2_ASSERT(block != LFS2_BLOCK_NULL); + if (off+size > lfs2->cfg->block_size) { + return LFS2_ERR_CORRUPT; + } + + while (size > 0) { + lfs2_size_t diff = size; + + if (pcache && block == pcache->block && + off < pcache->off + pcache->size) { + if (off >= pcache->off) { + // is already in pcache? + diff = lfs2_min(diff, pcache->size - (off-pcache->off)); + memcpy(data, &pcache->buffer[off-pcache->off], diff); + + data += diff; + off += diff; + size -= diff; + continue; + } + + // pcache takes priority + diff = lfs2_min(diff, pcache->off-off); + } + + if (block == rcache->block && + off < rcache->off + rcache->size) { + if (off >= rcache->off) { + // is already in rcache? + diff = lfs2_min(diff, rcache->size - (off-rcache->off)); + memcpy(data, &rcache->buffer[off-rcache->off], diff); + + data += diff; + off += diff; + size -= diff; + continue; + } + + // rcache takes priority + diff = lfs2_min(diff, rcache->off-off); + } + + // load to cache, first condition can no longer fail + LFS2_ASSERT(block < lfs2->cfg->block_count); + rcache->block = block; + rcache->off = lfs2_aligndown(off, lfs2->cfg->read_size); + rcache->size = lfs2_min( + lfs2_min( + lfs2_alignup(off+hint, lfs2->cfg->read_size), + lfs2->cfg->block_size) + - rcache->off, + lfs2->cfg->cache_size); + int err = lfs2->cfg->read(lfs2->cfg, rcache->block, + rcache->off, rcache->buffer, rcache->size); + LFS2_ASSERT(err <= 0); + if (err) { + return err; + } + } + + return 0; +} + +enum { + LFS2_CMP_EQ = 0, + LFS2_CMP_LT = 1, + LFS2_CMP_GT = 2, +}; + +static int lfs2_bd_cmp(lfs2_t *lfs2, + const lfs2_cache_t *pcache, lfs2_cache_t *rcache, lfs2_size_t hint, + lfs2_block_t block, lfs2_off_t off, + const void *buffer, lfs2_size_t size) { + const uint8_t *data = buffer; + + for (lfs2_off_t i = 0; i < size; i++) { + uint8_t dat; + int err = lfs2_bd_read(lfs2, + pcache, rcache, hint-i, + block, off+i, &dat, 1); + if (err) { + return err; + } + + if (dat != data[i]) { + return (dat < data[i]) ? LFS2_CMP_LT : LFS2_CMP_GT; + } + } + + return LFS2_CMP_EQ; +} + +static int lfs2_bd_flush(lfs2_t *lfs2, + lfs2_cache_t *pcache, lfs2_cache_t *rcache, bool validate) { + if (pcache->block != LFS2_BLOCK_NULL && pcache->block != LFS2_BLOCK_INLINE) { + LFS2_ASSERT(pcache->block < lfs2->cfg->block_count); + lfs2_size_t diff = lfs2_alignup(pcache->size, lfs2->cfg->prog_size); + int err = lfs2->cfg->prog(lfs2->cfg, pcache->block, + pcache->off, pcache->buffer, diff); + LFS2_ASSERT(err <= 0); + if (err) { + return err; + } + + if (validate) { + // check data on disk + lfs2_cache_drop(lfs2, rcache); + int res = lfs2_bd_cmp(lfs2, + NULL, rcache, diff, + pcache->block, pcache->off, pcache->buffer, diff); + if (res < 0) { + return res; + } + + if (res != LFS2_CMP_EQ) { + return LFS2_ERR_CORRUPT; + } + } + + lfs2_cache_zero(lfs2, pcache); + } + + return 0; +} + +static int lfs2_bd_sync(lfs2_t *lfs2, + lfs2_cache_t *pcache, lfs2_cache_t *rcache, bool validate) { + lfs2_cache_drop(lfs2, rcache); + + int err = lfs2_bd_flush(lfs2, pcache, rcache, validate); + if (err) { + return err; + } + + err = lfs2->cfg->sync(lfs2->cfg); + LFS2_ASSERT(err <= 0); + return err; +} + +static int lfs2_bd_prog(lfs2_t *lfs2, + lfs2_cache_t *pcache, lfs2_cache_t *rcache, bool validate, + lfs2_block_t block, lfs2_off_t off, + const void *buffer, lfs2_size_t size) { + const uint8_t *data = buffer; + LFS2_ASSERT(block != LFS2_BLOCK_NULL); + LFS2_ASSERT(off + size <= lfs2->cfg->block_size); + + while (size > 0) { + if (block == pcache->block && + off >= pcache->off && + off < pcache->off + lfs2->cfg->cache_size) { + // already fits in pcache? + lfs2_size_t diff = lfs2_min(size, + lfs2->cfg->cache_size - (off-pcache->off)); + memcpy(&pcache->buffer[off-pcache->off], data, diff); + + data += diff; + off += diff; + size -= diff; + + pcache->size = lfs2_max(pcache->size, off - pcache->off); + if (pcache->size == lfs2->cfg->cache_size) { + // eagerly flush out pcache if we fill up + int err = lfs2_bd_flush(lfs2, pcache, rcache, validate); + if (err) { + return err; + } + } + + continue; + } + + // pcache must have been flushed, either by programming and + // entire block or manually flushing the pcache + LFS2_ASSERT(pcache->block == LFS2_BLOCK_NULL); + + // prepare pcache, first condition can no longer fail + pcache->block = block; + pcache->off = lfs2_aligndown(off, lfs2->cfg->prog_size); + pcache->size = 0; + } + + return 0; +} + +static int lfs2_bd_erase(lfs2_t *lfs2, lfs2_block_t block) { + LFS2_ASSERT(block < lfs2->cfg->block_count); + int err = lfs2->cfg->erase(lfs2->cfg, block); + LFS2_ASSERT(err <= 0); + return err; +} + + +/// Small type-level utilities /// +// operations on block pairs +static inline void lfs2_pair_swap(lfs2_block_t pair[2]) { + lfs2_block_t t = pair[0]; + pair[0] = pair[1]; + pair[1] = t; +} + +static inline bool lfs2_pair_isnull(const lfs2_block_t pair[2]) { + return pair[0] == LFS2_BLOCK_NULL || pair[1] == LFS2_BLOCK_NULL; +} + +static inline int lfs2_pair_cmp( + const lfs2_block_t paira[2], + const lfs2_block_t pairb[2]) { + return !(paira[0] == pairb[0] || paira[1] == pairb[1] || + paira[0] == pairb[1] || paira[1] == pairb[0]); +} + +static inline bool lfs2_pair_sync( + const lfs2_block_t paira[2], + const lfs2_block_t pairb[2]) { + return (paira[0] == pairb[0] && paira[1] == pairb[1]) || + (paira[0] == pairb[1] && paira[1] == pairb[0]); +} + +static inline void lfs2_pair_fromle32(lfs2_block_t pair[2]) { + pair[0] = lfs2_fromle32(pair[0]); + pair[1] = lfs2_fromle32(pair[1]); +} + +static inline void lfs2_pair_tole32(lfs2_block_t pair[2]) { + pair[0] = lfs2_tole32(pair[0]); + pair[1] = lfs2_tole32(pair[1]); +} + +// operations on 32-bit entry tags +typedef uint32_t lfs2_tag_t; +typedef int32_t lfs2_stag_t; + +#define LFS2_MKTAG(type, id, size) \ + (((lfs2_tag_t)(type) << 20) | ((lfs2_tag_t)(id) << 10) | (lfs2_tag_t)(size)) + +static inline bool lfs2_tag_isvalid(lfs2_tag_t tag) { + return !(tag & 0x80000000); +} + +static inline bool lfs2_tag_isdelete(lfs2_tag_t tag) { + return ((int32_t)(tag << 22) >> 22) == -1; +} + +static inline uint16_t lfs2_tag_type1(lfs2_tag_t tag) { + return (tag & 0x70000000) >> 20; +} + +static inline uint16_t lfs2_tag_type3(lfs2_tag_t tag) { + return (tag & 0x7ff00000) >> 20; +} + +static inline uint8_t lfs2_tag_chunk(lfs2_tag_t tag) { + return (tag & 0x0ff00000) >> 20; +} + +static inline int8_t lfs2_tag_splice(lfs2_tag_t tag) { + return (int8_t)lfs2_tag_chunk(tag); +} + +static inline uint16_t lfs2_tag_id(lfs2_tag_t tag) { + return (tag & 0x000ffc00) >> 10; +} + +static inline lfs2_size_t lfs2_tag_size(lfs2_tag_t tag) { + return tag & 0x000003ff; +} + +static inline lfs2_size_t lfs2_tag_dsize(lfs2_tag_t tag) { + return sizeof(tag) + lfs2_tag_size(tag + lfs2_tag_isdelete(tag)); +} + +// operations on attributes in attribute lists +struct lfs2_mattr { + lfs2_tag_t tag; + const void *buffer; +}; + +struct lfs2_diskoff { + lfs2_block_t block; + lfs2_off_t off; +}; + +#define LFS2_MKATTRS(...) \ + (struct lfs2_mattr[]){__VA_ARGS__}, \ + sizeof((struct lfs2_mattr[]){__VA_ARGS__}) / sizeof(struct lfs2_mattr) + +// operations on global state +static inline void lfs2_gstate_xor(struct lfs2_gstate *a, + const struct lfs2_gstate *b) { + for (int i = 0; i < 3; i++) { + ((uint32_t*)a)[i] ^= ((const uint32_t*)b)[i]; + } +} + +static inline bool lfs2_gstate_iszero(const struct lfs2_gstate *a) { + for (int i = 0; i < 3; i++) { + if (((uint32_t*)a)[i] != 0) { + return false; + } + } + return true; +} + +static inline bool lfs2_gstate_hasorphans(const struct lfs2_gstate *a) { + return lfs2_tag_size(a->tag); +} + +static inline uint8_t lfs2_gstate_getorphans(const struct lfs2_gstate *a) { + return lfs2_tag_size(a->tag); +} + +static inline bool lfs2_gstate_hasmove(const struct lfs2_gstate *a) { + return lfs2_tag_type1(a->tag); +} + +static inline bool lfs2_gstate_hasmovehere(const struct lfs2_gstate *a, + const lfs2_block_t *pair) { + return lfs2_tag_type1(a->tag) && lfs2_pair_cmp(a->pair, pair) == 0; +} + +static inline void lfs2_gstate_xororphans(struct lfs2_gstate *a, + const struct lfs2_gstate *b, bool orphans) { + a->tag ^= LFS2_MKTAG(0x800, 0, 0) & (b->tag ^ ((uint32_t)orphans << 31)); +} + +static inline void lfs2_gstate_xormove(struct lfs2_gstate *a, + const struct lfs2_gstate *b, uint16_t id, const lfs2_block_t pair[2]) { + a->tag ^= LFS2_MKTAG(0x7ff, 0x3ff, 0) & (b->tag ^ ( + (id != 0x3ff) ? LFS2_MKTAG(LFS2_TYPE_DELETE, id, 0) : 0)); + a->pair[0] ^= b->pair[0] ^ ((id != 0x3ff) ? pair[0] : 0); + a->pair[1] ^= b->pair[1] ^ ((id != 0x3ff) ? pair[1] : 0); +} + +static inline void lfs2_gstate_fromle32(struct lfs2_gstate *a) { + a->tag = lfs2_fromle32(a->tag); + a->pair[0] = lfs2_fromle32(a->pair[0]); + a->pair[1] = lfs2_fromle32(a->pair[1]); +} + +static inline void lfs2_gstate_tole32(struct lfs2_gstate *a) { + a->tag = lfs2_tole32(a->tag); + a->pair[0] = lfs2_tole32(a->pair[0]); + a->pair[1] = lfs2_tole32(a->pair[1]); +} + +// other endianness operations +static void lfs2_ctz_fromle32(struct lfs2_ctz *ctz) { + ctz->head = lfs2_fromle32(ctz->head); + ctz->size = lfs2_fromle32(ctz->size); +} + +static void lfs2_ctz_tole32(struct lfs2_ctz *ctz) { + ctz->head = lfs2_tole32(ctz->head); + ctz->size = lfs2_tole32(ctz->size); +} + +static inline void lfs2_superblock_fromle32(lfs2_superblock_t *superblock) { + superblock->version = lfs2_fromle32(superblock->version); + superblock->block_size = lfs2_fromle32(superblock->block_size); + superblock->block_count = lfs2_fromle32(superblock->block_count); + superblock->name_max = lfs2_fromle32(superblock->name_max); + superblock->file_max = lfs2_fromle32(superblock->file_max); + superblock->attr_max = lfs2_fromle32(superblock->attr_max); +} + +static inline void lfs2_superblock_tole32(lfs2_superblock_t *superblock) { + superblock->version = lfs2_tole32(superblock->version); + superblock->block_size = lfs2_tole32(superblock->block_size); + superblock->block_count = lfs2_tole32(superblock->block_count); + superblock->name_max = lfs2_tole32(superblock->name_max); + superblock->file_max = lfs2_tole32(superblock->file_max); + superblock->attr_max = lfs2_tole32(superblock->attr_max); +} + + +/// Internal operations predeclared here /// +static int lfs2_dir_commit(lfs2_t *lfs2, lfs2_mdir_t *dir, + const struct lfs2_mattr *attrs, int attrcount); +static int lfs2_dir_compact(lfs2_t *lfs2, + lfs2_mdir_t *dir, const struct lfs2_mattr *attrs, int attrcount, + lfs2_mdir_t *source, uint16_t begin, uint16_t end); +static int lfs2_file_outline(lfs2_t *lfs2, lfs2_file_t *file); +static int lfs2_file_flush(lfs2_t *lfs2, lfs2_file_t *file); +static void lfs2_fs_preporphans(lfs2_t *lfs2, int8_t orphans); +static void lfs2_fs_prepmove(lfs2_t *lfs2, + uint16_t id, const lfs2_block_t pair[2]); +static int lfs2_fs_pred(lfs2_t *lfs2, const lfs2_block_t dir[2], + lfs2_mdir_t *pdir); +static lfs2_stag_t lfs2_fs_parent(lfs2_t *lfs2, const lfs2_block_t dir[2], + lfs2_mdir_t *parent); +static int lfs2_fs_relocate(lfs2_t *lfs2, + const lfs2_block_t oldpair[2], lfs2_block_t newpair[2]); +static int lfs2_fs_forceconsistency(lfs2_t *lfs2); +static int lfs2_deinit(lfs2_t *lfs2); +#ifdef LFS2_MIGRATE +static int lfs21_traverse(lfs2_t *lfs2, + int (*cb)(void*, lfs2_block_t), void *data); +#endif + +/// Block allocator /// +static int lfs2_alloc_lookahead(void *p, lfs2_block_t block) { + lfs2_t *lfs2 = (lfs2_t*)p; + lfs2_block_t off = ((block - lfs2->free.off) + + lfs2->cfg->block_count) % lfs2->cfg->block_count; + + if (off < lfs2->free.size) { + lfs2->free.buffer[off / 32] |= 1U << (off % 32); + } + + return 0; +} + +static int lfs2_alloc(lfs2_t *lfs2, lfs2_block_t *block) { + while (true) { + while (lfs2->free.i != lfs2->free.size) { + lfs2_block_t off = lfs2->free.i; + lfs2->free.i += 1; + lfs2->free.ack -= 1; + + if (!(lfs2->free.buffer[off / 32] & (1U << (off % 32)))) { + // found a free block + *block = (lfs2->free.off + off) % lfs2->cfg->block_count; + + // eagerly find next off so an alloc ack can + // discredit old lookahead blocks + while (lfs2->free.i != lfs2->free.size && + (lfs2->free.buffer[lfs2->free.i / 32] + & (1U << (lfs2->free.i % 32)))) { + lfs2->free.i += 1; + lfs2->free.ack -= 1; + } + + return 0; + } + } + + // check if we have looked at all blocks since last ack + if (lfs2->free.ack == 0) { + LFS2_ERROR("No more free space %"PRIu32, + lfs2->free.i + lfs2->free.off); + return LFS2_ERR_NOSPC; + } + + lfs2->free.off = (lfs2->free.off + lfs2->free.size) + % lfs2->cfg->block_count; + lfs2->free.size = lfs2_min(8*lfs2->cfg->lookahead_size, lfs2->free.ack); + lfs2->free.i = 0; + + // find mask of free blocks from tree + memset(lfs2->free.buffer, 0, lfs2->cfg->lookahead_size); + int err = lfs2_fs_traverse(lfs2, lfs2_alloc_lookahead, lfs2); + if (err) { + return err; + } + } +} + +static void lfs2_alloc_ack(lfs2_t *lfs2) { + lfs2->free.ack = lfs2->cfg->block_count; +} + + +/// Metadata pair and directory operations /// +static lfs2_stag_t lfs2_dir_getslice(lfs2_t *lfs2, const lfs2_mdir_t *dir, + lfs2_tag_t gmask, lfs2_tag_t gtag, + lfs2_off_t goff, void *gbuffer, lfs2_size_t gsize) { + lfs2_off_t off = dir->off; + lfs2_tag_t ntag = dir->etag; + lfs2_stag_t gdiff = 0; + + if (lfs2_gstate_hasmovehere(&lfs2->gstate, dir->pair) && + lfs2_tag_id(gtag) <= lfs2_tag_id(lfs2->gstate.tag)) { + // synthetic moves + gdiff -= LFS2_MKTAG(0, 1, 0); + } + + // iterate over dir block backwards (for faster lookups) + while (off >= sizeof(lfs2_tag_t) + lfs2_tag_dsize(ntag)) { + off -= lfs2_tag_dsize(ntag); + lfs2_tag_t tag = ntag; + int err = lfs2_bd_read(lfs2, + NULL, &lfs2->rcache, sizeof(ntag), + dir->pair[0], off, &ntag, sizeof(ntag)); + if (err) { + return err; + } + + ntag = (lfs2_frombe32(ntag) ^ tag) & 0x7fffffff; + + if (lfs2_tag_id(gmask) != 0 && + lfs2_tag_type1(tag) == LFS2_TYPE_SPLICE && + lfs2_tag_id(tag) <= lfs2_tag_id(gtag - gdiff)) { + if (tag == (LFS2_MKTAG(LFS2_TYPE_CREATE, 0, 0) | + (LFS2_MKTAG(0, 0x3ff, 0) & (gtag - gdiff)))) { + // found where we were created + return LFS2_ERR_NOENT; + } + + // move around splices + gdiff += LFS2_MKTAG(0, lfs2_tag_splice(tag), 0); + } + + if ((gmask & tag) == (gmask & (gtag - gdiff))) { + if (lfs2_tag_isdelete(tag)) { + return LFS2_ERR_NOENT; + } + + lfs2_size_t diff = lfs2_min(lfs2_tag_size(tag), gsize); + err = lfs2_bd_read(lfs2, + NULL, &lfs2->rcache, diff, + dir->pair[0], off+sizeof(tag)+goff, gbuffer, diff); + if (err) { + return err; + } + + memset((uint8_t*)gbuffer + diff, 0, gsize - diff); + + return tag + gdiff; + } + } + + return LFS2_ERR_NOENT; +} + +static lfs2_stag_t lfs2_dir_get(lfs2_t *lfs2, const lfs2_mdir_t *dir, + lfs2_tag_t gmask, lfs2_tag_t gtag, void *buffer) { + return lfs2_dir_getslice(lfs2, dir, + gmask, gtag, + 0, buffer, lfs2_tag_size(gtag)); +} + +static int lfs2_dir_getread(lfs2_t *lfs2, const lfs2_mdir_t *dir, + const lfs2_cache_t *pcache, lfs2_cache_t *rcache, lfs2_size_t hint, + lfs2_tag_t gmask, lfs2_tag_t gtag, + lfs2_off_t off, void *buffer, lfs2_size_t size) { + uint8_t *data = buffer; + if (off+size > lfs2->cfg->block_size) { + return LFS2_ERR_CORRUPT; + } + + while (size > 0) { + lfs2_size_t diff = size; + + if (pcache && pcache->block == LFS2_BLOCK_INLINE && + off < pcache->off + pcache->size) { + if (off >= pcache->off) { + // is already in pcache? + diff = lfs2_min(diff, pcache->size - (off-pcache->off)); + memcpy(data, &pcache->buffer[off-pcache->off], diff); + + data += diff; + off += diff; + size -= diff; + continue; + } + + // pcache takes priority + diff = lfs2_min(diff, pcache->off-off); + } + + if (rcache->block == LFS2_BLOCK_INLINE && + off < rcache->off + rcache->size) { + if (off >= rcache->off) { + // is already in rcache? + diff = lfs2_min(diff, rcache->size - (off-rcache->off)); + memcpy(data, &rcache->buffer[off-rcache->off], diff); + + data += diff; + off += diff; + size -= diff; + continue; + } + + // rcache takes priority + diff = lfs2_min(diff, rcache->off-off); + } + + // load to cache, first condition can no longer fail + rcache->block = LFS2_BLOCK_INLINE; + rcache->off = lfs2_aligndown(off, lfs2->cfg->read_size); + rcache->size = lfs2_min(lfs2_alignup(off+hint, lfs2->cfg->read_size), + lfs2->cfg->cache_size); + int err = lfs2_dir_getslice(lfs2, dir, gmask, gtag, + rcache->off, rcache->buffer, rcache->size); + if (err < 0) { + return err; + } + } + + return 0; +} + +static int lfs2_dir_traverse_filter(void *p, + lfs2_tag_t tag, const void *buffer) { + lfs2_tag_t *filtertag = p; + (void)buffer; + + // which mask depends on unique bit in tag structure + uint32_t mask = (tag & LFS2_MKTAG(0x100, 0, 0)) + ? LFS2_MKTAG(0x7ff, 0x3ff, 0) + : LFS2_MKTAG(0x700, 0x3ff, 0); + + // check for redundancy + if ((mask & tag) == (mask & *filtertag) || + lfs2_tag_isdelete(*filtertag) || + (LFS2_MKTAG(0x7ff, 0x3ff, 0) & tag) == ( + LFS2_MKTAG(LFS2_TYPE_DELETE, 0, 0) | + (LFS2_MKTAG(0, 0x3ff, 0) & *filtertag))) { + return true; + } + + // check if we need to adjust for created/deleted tags + if (lfs2_tag_type1(tag) == LFS2_TYPE_SPLICE && + lfs2_tag_id(tag) <= lfs2_tag_id(*filtertag)) { + *filtertag += LFS2_MKTAG(0, lfs2_tag_splice(tag), 0); + } + + return false; +} + +static int lfs2_dir_traverse(lfs2_t *lfs2, + const lfs2_mdir_t *dir, lfs2_off_t off, lfs2_tag_t ptag, + const struct lfs2_mattr *attrs, int attrcount, bool hasseenmove, + lfs2_tag_t tmask, lfs2_tag_t ttag, + uint16_t begin, uint16_t end, int16_t diff, + int (*cb)(void *data, lfs2_tag_t tag, const void *buffer), void *data) { + // iterate over directory and attrs + while (true) { + lfs2_tag_t tag; + const void *buffer; + struct lfs2_diskoff disk; + if (off+lfs2_tag_dsize(ptag) < dir->off) { + off += lfs2_tag_dsize(ptag); + int err = lfs2_bd_read(lfs2, + NULL, &lfs2->rcache, sizeof(tag), + dir->pair[0], off, &tag, sizeof(tag)); + if (err) { + return err; + } + + tag = (lfs2_frombe32(tag) ^ ptag) | 0x80000000; + disk.block = dir->pair[0]; + disk.off = off+sizeof(lfs2_tag_t); + buffer = &disk; + ptag = tag; + } else if (attrcount > 0) { + tag = attrs[0].tag; + buffer = attrs[0].buffer; + attrs += 1; + attrcount -= 1; + } else if (!hasseenmove && + lfs2_gstate_hasmovehere(&lfs2->gpending, dir->pair)) { + // Wait, we have pending move? Handle this here (we need to + // or else we risk letting moves fall out of date) + tag = lfs2->gpending.tag & LFS2_MKTAG(0x7ff, 0x3ff, 0); + buffer = NULL; + hasseenmove = true; + } else { + return 0; + } + + lfs2_tag_t mask = LFS2_MKTAG(0x7ff, 0, 0); + if ((mask & tmask & tag) != (mask & tmask & ttag)) { + continue; + } + + // do we need to filter? inlining the filtering logic here allows + // for some minor optimizations + if (lfs2_tag_id(tmask) != 0) { + // scan for duplicates and update tag based on creates/deletes + int filter = lfs2_dir_traverse(lfs2, + dir, off, ptag, attrs, attrcount, hasseenmove, + 0, 0, 0, 0, 0, + lfs2_dir_traverse_filter, &tag); + if (filter < 0) { + return filter; + } + + if (filter) { + continue; + } + + // in filter range? + if (!(lfs2_tag_id(tag) >= begin && lfs2_tag_id(tag) < end)) { + continue; + } + } + + // handle special cases for mcu-side operations + if (lfs2_tag_type3(tag) == LFS2_FROM_NOOP) { + // do nothing + } else if (lfs2_tag_type3(tag) == LFS2_FROM_MOVE) { + uint16_t fromid = lfs2_tag_size(tag); + uint16_t toid = lfs2_tag_id(tag); + int err = lfs2_dir_traverse(lfs2, + buffer, 0, LFS2_BLOCK_NULL, NULL, 0, true, + LFS2_MKTAG(0x600, 0x3ff, 0), + LFS2_MKTAG(LFS2_TYPE_STRUCT, 0, 0), + fromid, fromid+1, toid-fromid+diff, + cb, data); + if (err) { + return err; + } + } else if (lfs2_tag_type3(tag) == LFS2_FROM_USERATTRS) { + for (unsigned i = 0; i < lfs2_tag_size(tag); i++) { + const struct lfs2_attr *a = buffer; + int err = cb(data, LFS2_MKTAG(LFS2_TYPE_USERATTR + a[i].type, + lfs2_tag_id(tag) + diff, a[i].size), a[i].buffer); + if (err) { + return err; + } + } + } else { + int err = cb(data, tag + LFS2_MKTAG(0, diff, 0), buffer); + if (err) { + return err; + } + } + } +} + +static lfs2_stag_t lfs2_dir_fetchmatch(lfs2_t *lfs2, + lfs2_mdir_t *dir, const lfs2_block_t pair[2], + lfs2_tag_t fmask, lfs2_tag_t ftag, uint16_t *id, + int (*cb)(void *data, lfs2_tag_t tag, const void *buffer), void *data) { + // we can find tag very efficiently during a fetch, since we're already + // scanning the entire directory + lfs2_stag_t besttag = -1; + + // find the block with the most recent revision + uint32_t revs[2] = {0, 0}; + int r = 0; + for (int i = 0; i < 2; i++) { + int err = lfs2_bd_read(lfs2, + NULL, &lfs2->rcache, sizeof(revs[i]), + pair[i], 0, &revs[i], sizeof(revs[i])); + revs[i] = lfs2_fromle32(revs[i]); + if (err && err != LFS2_ERR_CORRUPT) { + return err; + } + + if (err != LFS2_ERR_CORRUPT && + lfs2_scmp(revs[i], revs[(i+1)%2]) > 0) { + r = i; + } + } + + dir->pair[0] = pair[(r+0)%2]; + dir->pair[1] = pair[(r+1)%2]; + dir->rev = revs[(r+0)%2]; + dir->off = 0; // nonzero = found some commits + + // now scan tags to fetch the actual dir and find possible match + for (int i = 0; i < 2; i++) { + lfs2_off_t off = 0; + lfs2_tag_t ptag = LFS2_BLOCK_NULL; + + uint16_t tempcount = 0; + lfs2_block_t temptail[2] = {LFS2_BLOCK_NULL, LFS2_BLOCK_NULL}; + bool tempsplit = false; + lfs2_stag_t tempbesttag = besttag; + + dir->rev = lfs2_tole32(dir->rev); + uint32_t crc = lfs2_crc(LFS2_BLOCK_NULL, &dir->rev, sizeof(dir->rev)); + dir->rev = lfs2_fromle32(dir->rev); + + while (true) { + // extract next tag + lfs2_tag_t tag; + off += lfs2_tag_dsize(ptag); + int err = lfs2_bd_read(lfs2, + NULL, &lfs2->rcache, lfs2->cfg->block_size, + dir->pair[0], off, &tag, sizeof(tag)); + if (err) { + if (err == LFS2_ERR_CORRUPT) { + // can't continue? + dir->erased = false; + break; + } + return err; + } + + crc = lfs2_crc(crc, &tag, sizeof(tag)); + tag = lfs2_frombe32(tag) ^ ptag; + + // next commit not yet programmed or we're not in valid range + if (!lfs2_tag_isvalid(tag) || + off + lfs2_tag_dsize(tag) > lfs2->cfg->block_size) { + dir->erased = (lfs2_tag_type1(ptag) == LFS2_TYPE_CRC && + dir->off % lfs2->cfg->prog_size == 0); + break; + } + + ptag = tag; + + if (lfs2_tag_type1(tag) == LFS2_TYPE_CRC) { + // check the crc attr + uint32_t dcrc; + err = lfs2_bd_read(lfs2, + NULL, &lfs2->rcache, lfs2->cfg->block_size, + dir->pair[0], off+sizeof(tag), &dcrc, sizeof(dcrc)); + if (err) { + if (err == LFS2_ERR_CORRUPT) { + dir->erased = false; + break; + } + return err; + } + dcrc = lfs2_fromle32(dcrc); + + if (crc != dcrc) { + dir->erased = false; + break; + } + + // reset the next bit if we need to + ptag ^= (lfs2_tag_t)(lfs2_tag_chunk(tag) & 1U) << 31; + + // toss our crc into the filesystem seed for + // pseudorandom numbers + lfs2->seed ^= crc; + + // update with what's found so far + besttag = tempbesttag; + dir->off = off + lfs2_tag_dsize(tag); + dir->etag = ptag; + dir->count = tempcount; + dir->tail[0] = temptail[0]; + dir->tail[1] = temptail[1]; + dir->split = tempsplit; + + // reset crc + crc = LFS2_BLOCK_NULL; + continue; + } + + // crc the entry first, hopefully leaving it in the cache + for (lfs2_off_t j = sizeof(tag); j < lfs2_tag_dsize(tag); j++) { + uint8_t dat; + err = lfs2_bd_read(lfs2, + NULL, &lfs2->rcache, lfs2->cfg->block_size, + dir->pair[0], off+j, &dat, 1); + if (err) { + if (err == LFS2_ERR_CORRUPT) { + dir->erased = false; + break; + } + return err; + } + + crc = lfs2_crc(crc, &dat, 1); + } + + // directory modification tags? + if (lfs2_tag_type1(tag) == LFS2_TYPE_NAME) { + // increase count of files if necessary + if (lfs2_tag_id(tag) >= tempcount) { + tempcount = lfs2_tag_id(tag) + 1; + } + } else if (lfs2_tag_type1(tag) == LFS2_TYPE_SPLICE) { + tempcount += lfs2_tag_splice(tag); + + if (tag == (LFS2_MKTAG(LFS2_TYPE_DELETE, 0, 0) | + (LFS2_MKTAG(0, 0x3ff, 0) & tempbesttag))) { + tempbesttag |= 0x80000000; + } else if (tempbesttag != -1 && + lfs2_tag_id(tag) <= lfs2_tag_id(tempbesttag)) { + tempbesttag += LFS2_MKTAG(0, lfs2_tag_splice(tag), 0); + } + } else if (lfs2_tag_type1(tag) == LFS2_TYPE_TAIL) { + tempsplit = (lfs2_tag_chunk(tag) & 1); + + err = lfs2_bd_read(lfs2, + NULL, &lfs2->rcache, lfs2->cfg->block_size, + dir->pair[0], off+sizeof(tag), &temptail, 8); + if (err) { + if (err == LFS2_ERR_CORRUPT) { + dir->erased = false; + break; + } + } + lfs2_pair_fromle32(temptail); + } + + // found a match for our fetcher? + if ((fmask & tag) == (fmask & ftag)) { + int res = cb(data, tag, &(struct lfs2_diskoff){ + dir->pair[0], off+sizeof(tag)}); + if (res < 0) { + if (res == LFS2_ERR_CORRUPT) { + dir->erased = false; + break; + } + return res; + } + + if (res == LFS2_CMP_EQ) { + // found a match + tempbesttag = tag; + } else if (res == LFS2_CMP_GT && + lfs2_tag_id(tag) <= lfs2_tag_id(tempbesttag)) { + // found a greater match, keep track to keep things sorted + tempbesttag = tag | 0x80000000; + } + } + } + + // consider what we have good enough + if (dir->off > 0) { + // synthetic move + if (lfs2_gstate_hasmovehere(&lfs2->gstate, dir->pair)) { + if (lfs2_tag_id(lfs2->gstate.tag) == lfs2_tag_id(besttag)) { + besttag |= 0x80000000; + } else if (besttag != -1 && + lfs2_tag_id(lfs2->gstate.tag) < lfs2_tag_id(besttag)) { + besttag -= LFS2_MKTAG(0, 1, 0); + } + } + + // found tag? or found best id? + if (id) { + *id = lfs2_min(lfs2_tag_id(besttag), dir->count); + } + + if (lfs2_tag_isvalid(besttag)) { + return besttag; + } else if (lfs2_tag_id(besttag) < dir->count) { + return LFS2_ERR_NOENT; + } else { + return 0; + } + } + + // failed, try the other block? + lfs2_pair_swap(dir->pair); + dir->rev = revs[(r+1)%2]; + } + + LFS2_ERROR("Corrupted dir pair at %"PRIx32" %"PRIx32, + dir->pair[0], dir->pair[1]); + return LFS2_ERR_CORRUPT; +} + +static int lfs2_dir_fetch(lfs2_t *lfs2, + lfs2_mdir_t *dir, const lfs2_block_t pair[2]) { + // note, mask=-1, tag=0 can never match a tag since this + // pattern has the invalid bit set + return (int)lfs2_dir_fetchmatch(lfs2, dir, pair, -1, 0, NULL, NULL, NULL); +} + +static int lfs2_dir_getgstate(lfs2_t *lfs2, const lfs2_mdir_t *dir, + struct lfs2_gstate *gstate) { + struct lfs2_gstate temp; + lfs2_stag_t res = lfs2_dir_get(lfs2, dir, LFS2_MKTAG(0x7ff, 0, 0), + LFS2_MKTAG(LFS2_TYPE_MOVESTATE, 0, sizeof(temp)), &temp); + if (res < 0 && res != LFS2_ERR_NOENT) { + return res; + } + + if (res != LFS2_ERR_NOENT) { + // xor together to find resulting gstate + lfs2_gstate_fromle32(&temp); + lfs2_gstate_xor(gstate, &temp); + } + + return 0; +} + +static int lfs2_dir_getinfo(lfs2_t *lfs2, lfs2_mdir_t *dir, + uint16_t id, struct lfs2_info *info) { + if (id == 0x3ff) { + // special case for root + strcpy(info->name, "/"); + info->type = LFS2_TYPE_DIR; + return 0; + } + + lfs2_stag_t tag = lfs2_dir_get(lfs2, dir, LFS2_MKTAG(0x780, 0x3ff, 0), + LFS2_MKTAG(LFS2_TYPE_NAME, id, lfs2->name_max+1), info->name); + if (tag < 0) { + return (int)tag; + } + + info->type = lfs2_tag_type3(tag); + + struct lfs2_ctz ctz; + tag = lfs2_dir_get(lfs2, dir, LFS2_MKTAG(0x700, 0x3ff, 0), + LFS2_MKTAG(LFS2_TYPE_STRUCT, id, sizeof(ctz)), &ctz); + if (tag < 0) { + return (int)tag; + } + lfs2_ctz_fromle32(&ctz); + + if (lfs2_tag_type3(tag) == LFS2_TYPE_CTZSTRUCT) { + info->size = ctz.size; + } else if (lfs2_tag_type3(tag) == LFS2_TYPE_INLINESTRUCT) { + info->size = lfs2_tag_size(tag); + } + + return 0; +} + +struct lfs2_dir_find_match { + lfs2_t *lfs2; + const void *name; + lfs2_size_t size; +}; + +static int lfs2_dir_find_match(void *data, + lfs2_tag_t tag, const void *buffer) { + struct lfs2_dir_find_match *name = data; + lfs2_t *lfs2 = name->lfs2; + const struct lfs2_diskoff *disk = buffer; + + // compare with disk + lfs2_size_t diff = lfs2_min(name->size, lfs2_tag_size(tag)); + int res = lfs2_bd_cmp(lfs2, + NULL, &lfs2->rcache, diff, + disk->block, disk->off, name->name, diff); + if (res != LFS2_CMP_EQ) { + return res; + } + + // only equal if our size is still the same + if (name->size != lfs2_tag_size(tag)) { + return (name->size < lfs2_tag_size(tag)) ? LFS2_CMP_LT : LFS2_CMP_GT; + } + + // found a match! + return LFS2_CMP_EQ; +} + +static lfs2_stag_t lfs2_dir_find(lfs2_t *lfs2, lfs2_mdir_t *dir, + const char **path, uint16_t *id) { + // we reduce path to a single name if we can find it + const char *name = *path; + if (id) { + *id = 0x3ff; + } + + // default to root dir + lfs2_stag_t tag = LFS2_MKTAG(LFS2_TYPE_DIR, 0x3ff, 0); + dir->tail[0] = lfs2->root[0]; + dir->tail[1] = lfs2->root[1]; + + while (true) { +nextname: + // skip slashes + name += strspn(name, "/"); + lfs2_size_t namelen = strcspn(name, "/"); + + // skip '.' and root '..' + if ((namelen == 1 && memcmp(name, ".", 1) == 0) || + (namelen == 2 && memcmp(name, "..", 2) == 0)) { + name += namelen; + goto nextname; + } + + // skip if matched by '..' in name + const char *suffix = name + namelen; + lfs2_size_t sufflen; + int depth = 1; + while (true) { + suffix += strspn(suffix, "/"); + sufflen = strcspn(suffix, "/"); + if (sufflen == 0) { + break; + } + + if (sufflen == 2 && memcmp(suffix, "..", 2) == 0) { + depth -= 1; + if (depth == 0) { + name = suffix + sufflen; + goto nextname; + } + } else { + depth += 1; + } + + suffix += sufflen; + } + + // found path + if (name[0] == '\0') { + return tag; + } + + // update what we've found so far + *path = name; + + // only continue if we hit a directory + if (lfs2_tag_type3(tag) != LFS2_TYPE_DIR) { + return LFS2_ERR_NOTDIR; + } + + // grab the entry data + if (lfs2_tag_id(tag) != 0x3ff) { + lfs2_stag_t res = lfs2_dir_get(lfs2, dir, LFS2_MKTAG(0x700, 0x3ff, 0), + LFS2_MKTAG(LFS2_TYPE_STRUCT, lfs2_tag_id(tag), 8), dir->tail); + if (res < 0) { + return res; + } + lfs2_pair_fromle32(dir->tail); + } + + // find entry matching name + while (true) { + tag = lfs2_dir_fetchmatch(lfs2, dir, dir->tail, + LFS2_MKTAG(0x780, 0, 0), + LFS2_MKTAG(LFS2_TYPE_NAME, 0, namelen), + // are we last name? + (strchr(name, '/') == NULL) ? id : NULL, + lfs2_dir_find_match, &(struct lfs2_dir_find_match){ + lfs2, name, namelen}); + if (tag < 0) { + return tag; + } + + if (tag) { + break; + } + + if (!dir->split) { + return LFS2_ERR_NOENT; + } + } + + // to next name + name += namelen; + } +} + +// commit logic +struct lfs2_commit { + lfs2_block_t block; + lfs2_off_t off; + lfs2_tag_t ptag; + uint32_t crc; + + lfs2_off_t begin; + lfs2_off_t end; +}; + +static int lfs2_dir_commitprog(lfs2_t *lfs2, struct lfs2_commit *commit, + const void *buffer, lfs2_size_t size) { + int err = lfs2_bd_prog(lfs2, + &lfs2->pcache, &lfs2->rcache, false, + commit->block, commit->off , + (const uint8_t*)buffer, size); + if (err) { + return err; + } + + commit->crc = lfs2_crc(commit->crc, buffer, size); + commit->off += size; + return 0; +} + +static int lfs2_dir_commitattr(lfs2_t *lfs2, struct lfs2_commit *commit, + lfs2_tag_t tag, const void *buffer) { + // check if we fit + lfs2_size_t dsize = lfs2_tag_dsize(tag); + if (commit->off + dsize > commit->end) { + return LFS2_ERR_NOSPC; + } + + // write out tag + lfs2_tag_t ntag = lfs2_tobe32((tag & 0x7fffffff) ^ commit->ptag); + int err = lfs2_dir_commitprog(lfs2, commit, &ntag, sizeof(ntag)); + if (err) { + return err; + } + + if (!(tag & 0x80000000)) { + // from memory + err = lfs2_dir_commitprog(lfs2, commit, buffer, dsize-sizeof(tag)); + if (err) { + return err; + } + } else { + // from disk + const struct lfs2_diskoff *disk = buffer; + for (lfs2_off_t i = 0; i < dsize-sizeof(tag); i++) { + // rely on caching to make this efficient + uint8_t dat; + err = lfs2_bd_read(lfs2, + NULL, &lfs2->rcache, dsize-sizeof(tag)-i, + disk->block, disk->off+i, &dat, 1); + if (err) { + return err; + } + + err = lfs2_dir_commitprog(lfs2, commit, &dat, 1); + if (err) { + return err; + } + } + } + + commit->ptag = tag & 0x7fffffff; + return 0; +} + +static int lfs2_dir_commitcrc(lfs2_t *lfs2, struct lfs2_commit *commit) { + // align to program units + const lfs2_off_t off1 = commit->off + sizeof(lfs2_tag_t); + const lfs2_off_t end = lfs2_alignup(off1 + sizeof(uint32_t), + lfs2->cfg->prog_size); + + // create crc tags to fill up remainder of commit, note that + // padding is not crcd, which lets fetches skip padding but + // makes committing a bit more complicated + while (commit->off < end) { + lfs2_off_t off = commit->off + sizeof(lfs2_tag_t); + lfs2_off_t noff = lfs2_min(end - off, 0x3fe) + off; + if (noff < end) { + noff = lfs2_min(noff, end - 2*sizeof(uint32_t)); + } + + // read erased state from next program unit + lfs2_tag_t tag = LFS2_BLOCK_NULL; + int err = lfs2_bd_read(lfs2, + NULL, &lfs2->rcache, sizeof(tag), + commit->block, noff, &tag, sizeof(tag)); + if (err && err != LFS2_ERR_CORRUPT) { + return err; + } + + // build crc tag + bool reset = ~lfs2_frombe32(tag) >> 31; + tag = LFS2_MKTAG(LFS2_TYPE_CRC + reset, 0x3ff, noff - off); + + // write out crc + uint32_t footer[2]; + footer[0] = lfs2_tobe32(tag ^ commit->ptag); + commit->crc = lfs2_crc(commit->crc, &footer[0], sizeof(footer[0])); + footer[1] = lfs2_tole32(commit->crc); + err = lfs2_bd_prog(lfs2, + &lfs2->pcache, &lfs2->rcache, false, + commit->block, commit->off, &footer, sizeof(footer)); + if (err) { + return err; + } + + commit->off += sizeof(tag)+lfs2_tag_size(tag); + commit->ptag = tag ^ ((lfs2_tag_t)reset << 31); + commit->crc = LFS2_BLOCK_NULL; // reset crc for next "commit" + } + + // flush buffers + int err = lfs2_bd_sync(lfs2, &lfs2->pcache, &lfs2->rcache, false); + if (err) { + return err; + } + + // successful commit, check checksums to make sure + lfs2_off_t off = commit->begin; + lfs2_off_t noff = off1; + while (off < end) { + uint32_t crc = LFS2_BLOCK_NULL; + for (lfs2_off_t i = off; i < noff+sizeof(uint32_t); i++) { + // leave it up to caching to make this efficient + uint8_t dat; + err = lfs2_bd_read(lfs2, + NULL, &lfs2->rcache, noff+sizeof(uint32_t)-i, + commit->block, i, &dat, 1); + if (err) { + return err; + } + + crc = lfs2_crc(crc, &dat, 1); + } + + // detected write error? + if (crc != 0) { + return LFS2_ERR_CORRUPT; + } + + // skip padding + off = lfs2_min(end - noff, 0x3fe) + noff; + if (off < end) { + off = lfs2_min(off, end - 2*sizeof(uint32_t)); + } + noff = off + sizeof(uint32_t); + } + + return 0; +} + +static int lfs2_dir_alloc(lfs2_t *lfs2, lfs2_mdir_t *dir) { + // allocate pair of dir blocks (backwards, so we write block 1 first) + for (int i = 0; i < 2; i++) { + int err = lfs2_alloc(lfs2, &dir->pair[(i+1)%2]); + if (err) { + return err; + } + } + + // rather than clobbering one of the blocks we just pretend + // the revision may be valid + int err = lfs2_bd_read(lfs2, + NULL, &lfs2->rcache, sizeof(dir->rev), + dir->pair[0], 0, &dir->rev, sizeof(dir->rev)); + dir->rev = lfs2_fromle32(dir->rev); + if (err && err != LFS2_ERR_CORRUPT) { + return err; + } + + // make sure we don't immediately evict + dir->rev += dir->rev & 1; + + // set defaults + dir->off = sizeof(dir->rev); + dir->etag = LFS2_BLOCK_NULL; + dir->count = 0; + dir->tail[0] = LFS2_BLOCK_NULL; + dir->tail[1] = LFS2_BLOCK_NULL; + dir->erased = false; + dir->split = false; + + // don't write out yet, let caller take care of that + return 0; +} + +static int lfs2_dir_drop(lfs2_t *lfs2, lfs2_mdir_t *dir, lfs2_mdir_t *tail) { + // steal state + int err = lfs2_dir_getgstate(lfs2, tail, &lfs2->gdelta); + if (err) { + return err; + } + + // steal tail + lfs2_pair_tole32(tail->tail); + err = lfs2_dir_commit(lfs2, dir, LFS2_MKATTRS( + {LFS2_MKTAG(LFS2_TYPE_TAIL + tail->split, 0x3ff, 8), tail->tail})); + lfs2_pair_fromle32(tail->tail); + if (err) { + return err; + } + + return 0; +} + +static int lfs2_dir_split(lfs2_t *lfs2, + lfs2_mdir_t *dir, const struct lfs2_mattr *attrs, int attrcount, + lfs2_mdir_t *source, uint16_t split, uint16_t end) { + // create tail directory + lfs2_mdir_t tail; + int err = lfs2_dir_alloc(lfs2, &tail); + if (err) { + return err; + } + + tail.split = dir->split; + tail.tail[0] = dir->tail[0]; + tail.tail[1] = dir->tail[1]; + + err = lfs2_dir_compact(lfs2, &tail, attrs, attrcount, source, split, end); + if (err) { + return err; + } + + dir->tail[0] = tail.pair[0]; + dir->tail[1] = tail.pair[1]; + dir->split = true; + + // update root if needed + if (lfs2_pair_cmp(dir->pair, lfs2->root) == 0 && split == 0) { + lfs2->root[0] = tail.pair[0]; + lfs2->root[1] = tail.pair[1]; + } + + return 0; +} + +static int lfs2_dir_commit_size(void *p, lfs2_tag_t tag, const void *buffer) { + lfs2_size_t *size = p; + (void)buffer; + + *size += lfs2_tag_dsize(tag); + return 0; +} + +struct lfs2_dir_commit_commit { + lfs2_t *lfs2; + struct lfs2_commit *commit; +}; + +static int lfs2_dir_commit_commit(void *p, lfs2_tag_t tag, const void *buffer) { + struct lfs2_dir_commit_commit *commit = p; + return lfs2_dir_commitattr(commit->lfs2, commit->commit, tag, buffer); +} + +static int lfs2_dir_compact(lfs2_t *lfs2, + lfs2_mdir_t *dir, const struct lfs2_mattr *attrs, int attrcount, + lfs2_mdir_t *source, uint16_t begin, uint16_t end) { + // save some state in case block is bad + const lfs2_block_t oldpair[2] = {dir->pair[1], dir->pair[0]}; + bool relocated = false; + bool exhausted = false; + + // should we split? + while (end - begin > 1) { + // find size + lfs2_size_t size = 0; + int err = lfs2_dir_traverse(lfs2, + source, 0, LFS2_BLOCK_NULL, attrs, attrcount, false, + LFS2_MKTAG(0x400, 0x3ff, 0), + LFS2_MKTAG(LFS2_TYPE_NAME, 0, 0), + begin, end, -begin, + lfs2_dir_commit_size, &size); + if (err) { + return err; + } + + // space is complicated, we need room for tail, crc, gstate, + // cleanup delete, and we cap at half a block to give room + // for metadata updates. + if (end - begin < 0xff && + size <= lfs2_min(lfs2->cfg->block_size - 36, + lfs2_alignup(lfs2->cfg->block_size/2, + lfs2->cfg->prog_size))) { + break; + } + + // can't fit, need to split, we should really be finding the + // largest size that fits with a small binary search, but right now + // it's not worth the code size + uint16_t split = (end - begin) / 2; + err = lfs2_dir_split(lfs2, dir, attrs, attrcount, + source, begin+split, end); + if (err) { + // if we fail to split, we may be able to overcompact, unless + // we're too big for even the full block, in which case our + // only option is to error + if (err == LFS2_ERR_NOSPC && size <= lfs2->cfg->block_size - 36) { + break; + } + return err; + } + + end = begin + split; + } + + // increment revision count + dir->rev += 1; + if (lfs2->cfg->block_cycles > 0 && + (dir->rev % (lfs2->cfg->block_cycles+1) == 0)) { + if (lfs2_pair_cmp(dir->pair, (const lfs2_block_t[2]){0, 1}) == 0) { + // oh no! we're writing too much to the superblock, + // should we expand? + lfs2_ssize_t res = lfs2_fs_size(lfs2); + if (res < 0) { + return res; + } + + // do we have extra space? littlefs can't reclaim this space + // by itself, so expand cautiously + if ((lfs2_size_t)res < lfs2->cfg->block_count/2) { + LFS2_DEBUG("Expanding superblock at rev %"PRIu32, dir->rev); + int err = lfs2_dir_split(lfs2, dir, attrs, attrcount, + source, begin, end); + if (err && err != LFS2_ERR_NOSPC) { + return err; + } + + // welp, we tried, if we ran out of space there's not much + // we can do, we'll error later if we've become frozen + if (!err) { + end = begin; + } + } +#ifdef LFS2_MIGRATE + } else if (lfs2_pair_cmp(dir->pair, lfs2->root) == 0 && lfs2->lfs21) { + // we can't relocate our root during migrations, as this would + // cause the superblock to get updated, which would clobber v1 +#endif + } else { + // we're writing too much, time to relocate + exhausted = true; + goto relocate; + } + } + + // begin loop to commit compaction to blocks until a compact sticks + while (true) { + { + // There's nothing special about our global delta, so feed it into + // our local global delta + int err = lfs2_dir_getgstate(lfs2, dir, &lfs2->gdelta); + if (err) { + return err; + } + + // setup commit state + struct lfs2_commit commit = { + .block = dir->pair[1], + .off = 0, + .ptag = LFS2_BLOCK_NULL, + .crc = LFS2_BLOCK_NULL, + + .begin = 0, + .end = lfs2->cfg->block_size - 8, + }; + + // erase block to write to + err = lfs2_bd_erase(lfs2, dir->pair[1]); + if (err) { + if (err == LFS2_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + // write out header + dir->rev = lfs2_tole32(dir->rev); + err = lfs2_dir_commitprog(lfs2, &commit, + &dir->rev, sizeof(dir->rev)); + dir->rev = lfs2_fromle32(dir->rev); + if (err) { + if (err == LFS2_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + // traverse the directory, this time writing out all unique tags + err = lfs2_dir_traverse(lfs2, + source, 0, LFS2_BLOCK_NULL, attrs, attrcount, false, + LFS2_MKTAG(0x400, 0x3ff, 0), + LFS2_MKTAG(LFS2_TYPE_NAME, 0, 0), + begin, end, -begin, + lfs2_dir_commit_commit, &(struct lfs2_dir_commit_commit){ + lfs2, &commit}); + if (err) { + if (err == LFS2_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + // commit tail, which may be new after last size check + if (!lfs2_pair_isnull(dir->tail)) { + lfs2_pair_tole32(dir->tail); + err = lfs2_dir_commitattr(lfs2, &commit, + LFS2_MKTAG(LFS2_TYPE_TAIL + dir->split, 0x3ff, 8), + dir->tail); + lfs2_pair_fromle32(dir->tail); + if (err) { + if (err == LFS2_ERR_CORRUPT) { + goto relocate; + } + return err; + } + } + + if (!relocated && !lfs2_gstate_iszero(&lfs2->gdelta)) { + // commit any globals, unless we're relocating, + // in which case our parent will steal our globals + lfs2_gstate_tole32(&lfs2->gdelta); + err = lfs2_dir_commitattr(lfs2, &commit, + LFS2_MKTAG(LFS2_TYPE_MOVESTATE, 0x3ff, + sizeof(lfs2->gdelta)), &lfs2->gdelta); + lfs2_gstate_fromle32(&lfs2->gdelta); + if (err) { + if (err == LFS2_ERR_CORRUPT) { + goto relocate; + } + return err; + } + } + + err = lfs2_dir_commitcrc(lfs2, &commit); + if (err) { + if (err == LFS2_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + // successful compaction, swap dir pair to indicate most recent + LFS2_ASSERT(commit.off % lfs2->cfg->prog_size == 0); + lfs2_pair_swap(dir->pair); + dir->count = end - begin; + dir->off = commit.off; + dir->etag = commit.ptag; + // note we able to have already handled move here + if (lfs2_gstate_hasmovehere(&lfs2->gpending, dir->pair)) { + lfs2_gstate_xormove(&lfs2->gpending, + &lfs2->gpending, 0x3ff, NULL); + } + } + break; + +relocate: + // commit was corrupted, drop caches and prepare to relocate block + relocated = true; + lfs2_cache_drop(lfs2, &lfs2->pcache); + if (!exhausted) { + LFS2_DEBUG("Bad block at %"PRIx32, dir->pair[1]); + } + + // can't relocate superblock, filesystem is now frozen + if (lfs2_pair_cmp(oldpair, (const lfs2_block_t[2]){0, 1}) == 0) { + LFS2_WARN("Superblock %"PRIx32" has become unwritable", oldpair[1]); + return LFS2_ERR_NOSPC; + } + + // relocate half of pair + int err = lfs2_alloc(lfs2, &dir->pair[1]); + if (err && (err != LFS2_ERR_NOSPC && !exhausted)) { + return err; + } + + continue; + } + + if (!relocated) { + lfs2->gstate = lfs2->gpending; + lfs2->gdelta = (struct lfs2_gstate){0}; + } else { + // update references if we relocated + LFS2_DEBUG("Relocating %"PRIx32" %"PRIx32" -> %"PRIx32" %"PRIx32, + oldpair[0], oldpair[1], dir->pair[0], dir->pair[1]); + int err = lfs2_fs_relocate(lfs2, oldpair, dir->pair); + if (err) { + return err; + } + } + + return 0; +} + +static int lfs2_dir_commit(lfs2_t *lfs2, lfs2_mdir_t *dir, + const struct lfs2_mattr *attrs, int attrcount) { + // check for any inline files that aren't RAM backed and + // forcefully evict them, needed for filesystem consistency + for (lfs2_file_t *f = (lfs2_file_t*)lfs2->mlist; f; f = f->next) { + if (dir != &f->m && lfs2_pair_cmp(f->m.pair, dir->pair) == 0 && + f->type == LFS2_TYPE_REG && (f->flags & LFS2_F_INLINE) && + f->ctz.size > lfs2->cfg->cache_size) { + int err = lfs2_file_outline(lfs2, f); + if (err) { + return err; + } + + err = lfs2_file_flush(lfs2, f); + if (err) { + return err; + } + } + } + + // calculate changes to the directory + lfs2_tag_t deletetag = LFS2_BLOCK_NULL; + lfs2_tag_t createtag = LFS2_BLOCK_NULL; + for (int i = 0; i < attrcount; i++) { + if (lfs2_tag_type3(attrs[i].tag) == LFS2_TYPE_CREATE) { + createtag = attrs[i].tag; + dir->count += 1; + } else if (lfs2_tag_type3(attrs[i].tag) == LFS2_TYPE_DELETE) { + deletetag = attrs[i].tag; + LFS2_ASSERT(dir->count > 0); + dir->count -= 1; + } else if (lfs2_tag_type1(attrs[i].tag) == LFS2_TYPE_TAIL) { + dir->tail[0] = ((lfs2_block_t*)attrs[i].buffer)[0]; + dir->tail[1] = ((lfs2_block_t*)attrs[i].buffer)[1]; + dir->split = (lfs2_tag_chunk(attrs[i].tag) & 1); + lfs2_pair_fromle32(dir->tail); + } + } + + // do we have a pending move? + if (lfs2_gstate_hasmovehere(&lfs2->gpending, dir->pair)) { + deletetag = lfs2->gpending.tag & LFS2_MKTAG(0x7ff, 0x3ff, 0); + LFS2_ASSERT(dir->count > 0); + dir->count -= 1; + + // mark gdelta so we reflect the move we will fix + lfs2_gstate_xormove(&lfs2->gdelta, &lfs2->gpending, 0x3ff, NULL); + } + + // should we actually drop the directory block? + if (lfs2_tag_isvalid(deletetag) && dir->count == 0) { + lfs2_mdir_t pdir; + int err = lfs2_fs_pred(lfs2, dir->pair, &pdir); + if (err && err != LFS2_ERR_NOENT) { + return err; + } + + if (err != LFS2_ERR_NOENT && pdir.split) { + return lfs2_dir_drop(lfs2, &pdir, dir); + } + } + + if (dir->erased || dir->count >= 0xff) { + // try to commit + struct lfs2_commit commit = { + .block = dir->pair[0], + .off = dir->off, + .ptag = dir->etag, + .crc = LFS2_BLOCK_NULL, + + .begin = dir->off, + .end = lfs2->cfg->block_size - 8, + }; + + // traverse attrs that need to be written out + lfs2_pair_tole32(dir->tail); + int err = lfs2_dir_traverse(lfs2, + dir, dir->off, dir->etag, attrs, attrcount, false, + 0, 0, 0, 0, 0, + lfs2_dir_commit_commit, &(struct lfs2_dir_commit_commit){ + lfs2, &commit}); + lfs2_pair_fromle32(dir->tail); + if (err) { + if (err == LFS2_ERR_NOSPC || err == LFS2_ERR_CORRUPT) { + goto compact; + } + return err; + } + + // commit any global diffs if we have any + if (!lfs2_gstate_iszero(&lfs2->gdelta)) { + err = lfs2_dir_getgstate(lfs2, dir, &lfs2->gdelta); + if (err) { + return err; + } + + lfs2_gstate_tole32(&lfs2->gdelta); + err = lfs2_dir_commitattr(lfs2, &commit, + LFS2_MKTAG(LFS2_TYPE_MOVESTATE, 0x3ff, + sizeof(lfs2->gdelta)), &lfs2->gdelta); + lfs2_gstate_fromle32(&lfs2->gdelta); + if (err) { + if (err == LFS2_ERR_NOSPC || err == LFS2_ERR_CORRUPT) { + goto compact; + } + return err; + } + } + + // finalize commit with the crc + err = lfs2_dir_commitcrc(lfs2, &commit); + if (err) { + if (err == LFS2_ERR_NOSPC || err == LFS2_ERR_CORRUPT) { + goto compact; + } + return err; + } + + // successful commit, update dir + LFS2_ASSERT(commit.off % lfs2->cfg->prog_size == 0); + dir->off = commit.off; + dir->etag = commit.ptag; + + // note we able to have already handled move here + if (lfs2_gstate_hasmovehere(&lfs2->gpending, dir->pair)) { + lfs2_gstate_xormove(&lfs2->gpending, &lfs2->gpending, 0x3ff, NULL); + } + + // update gstate + lfs2->gstate = lfs2->gpending; + lfs2->gdelta = (struct lfs2_gstate){0}; + } else { +compact: + // fall back to compaction + lfs2_cache_drop(lfs2, &lfs2->pcache); + + int err = lfs2_dir_compact(lfs2, dir, attrs, attrcount, + dir, 0, dir->count); + if (err) { + return err; + } + } + + // update any directories that are affected + lfs2_mdir_t copy = *dir; + + // two passes, once for things that aren't us, and one + // for things that are + for (struct lfs2_mlist *d = lfs2->mlist; d; d = d->next) { + if (lfs2_pair_cmp(d->m.pair, copy.pair) == 0) { + d->m = *dir; + if (d->id == lfs2_tag_id(deletetag)) { + d->m.pair[0] = LFS2_BLOCK_NULL; + d->m.pair[1] = LFS2_BLOCK_NULL; + } else if (d->id > lfs2_tag_id(deletetag)) { + d->id -= 1; + if (d->type == LFS2_TYPE_DIR) { + ((lfs2_dir_t*)d)->pos -= 1; + } + } else if (&d->m != dir && d->id >= lfs2_tag_id(createtag)) { + d->id += 1; + if (d->type == LFS2_TYPE_DIR) { + ((lfs2_dir_t*)d)->pos += 1; + } + } + + while (d->id >= d->m.count && d->m.split) { + // we split and id is on tail now + d->id -= d->m.count; + int err = lfs2_dir_fetch(lfs2, &d->m, d->m.tail); + if (err) { + return err; + } + } + } + } + + return 0; +} + + +/// Top level directory operations /// +int lfs2_mkdir(lfs2_t *lfs2, const char *path) { + LFS2_TRACE("lfs2_mkdir(%p, \"%s\")", (void*)lfs2, path); + // deorphan if we haven't yet, needed at most once after poweron + int err = lfs2_fs_forceconsistency(lfs2); + if (err) { + LFS2_TRACE("lfs2_mkdir -> %d", err); + return err; + } + + lfs2_mdir_t cwd; + uint16_t id; + err = lfs2_dir_find(lfs2, &cwd, &path, &id); + if (!(err == LFS2_ERR_NOENT && id != 0x3ff)) { + LFS2_TRACE("lfs2_mkdir -> %d", (err < 0) ? err : LFS2_ERR_EXIST); + return (err < 0) ? err : LFS2_ERR_EXIST; + } + + // check that name fits + lfs2_size_t nlen = strlen(path); + if (nlen > lfs2->name_max) { + LFS2_TRACE("lfs2_mkdir -> %d", LFS2_ERR_NAMETOOLONG); + return LFS2_ERR_NAMETOOLONG; + } + + // build up new directory + lfs2_alloc_ack(lfs2); + lfs2_mdir_t dir; + err = lfs2_dir_alloc(lfs2, &dir); + if (err) { + LFS2_TRACE("lfs2_mkdir -> %d", err); + return err; + } + + // find end of list + lfs2_mdir_t pred = cwd; + while (pred.split) { + err = lfs2_dir_fetch(lfs2, &pred, pred.tail); + if (err) { + LFS2_TRACE("lfs2_mkdir -> %d", err); + return err; + } + } + + // setup dir + lfs2_pair_tole32(pred.tail); + err = lfs2_dir_commit(lfs2, &dir, LFS2_MKATTRS( + {LFS2_MKTAG(LFS2_TYPE_SOFTTAIL, 0x3ff, 8), pred.tail})); + lfs2_pair_fromle32(pred.tail); + if (err) { + LFS2_TRACE("lfs2_mkdir -> %d", err); + return err; + } + + // current block end of list? + if (cwd.split) { + // update tails, this creates a desync + lfs2_fs_preporphans(lfs2, +1); + lfs2_pair_tole32(dir.pair); + err = lfs2_dir_commit(lfs2, &pred, LFS2_MKATTRS( + {LFS2_MKTAG(LFS2_TYPE_SOFTTAIL, 0x3ff, 8), dir.pair})); + lfs2_pair_fromle32(dir.pair); + if (err) { + LFS2_TRACE("lfs2_mkdir -> %d", err); + return err; + } + lfs2_fs_preporphans(lfs2, -1); + } + + // now insert into our parent block + lfs2_pair_tole32(dir.pair); + err = lfs2_dir_commit(lfs2, &cwd, LFS2_MKATTRS( + {LFS2_MKTAG(LFS2_TYPE_CREATE, id, 0), NULL}, + {LFS2_MKTAG(LFS2_TYPE_DIR, id, nlen), path}, + {LFS2_MKTAG(LFS2_TYPE_DIRSTRUCT, id, 8), dir.pair}, + {!cwd.split + ? LFS2_MKTAG(LFS2_TYPE_SOFTTAIL, 0x3ff, 8) + : LFS2_MKTAG(LFS2_FROM_NOOP, 0, 0), dir.pair})); + lfs2_pair_fromle32(dir.pair); + if (err) { + LFS2_TRACE("lfs2_mkdir -> %d", err); + return err; + } + + LFS2_TRACE("lfs2_mkdir -> %d", 0); + return 0; +} + +int lfs2_dir_open(lfs2_t *lfs2, lfs2_dir_t *dir, const char *path) { + LFS2_TRACE("lfs2_dir_open(%p, %p, \"%s\")", (void*)lfs2, (void*)dir, path); + lfs2_stag_t tag = lfs2_dir_find(lfs2, &dir->m, &path, NULL); + if (tag < 0) { + LFS2_TRACE("lfs2_dir_open -> %d", tag); + return tag; + } + + if (lfs2_tag_type3(tag) != LFS2_TYPE_DIR) { + LFS2_TRACE("lfs2_dir_open -> %d", LFS2_ERR_NOTDIR); + return LFS2_ERR_NOTDIR; + } + + lfs2_block_t pair[2]; + if (lfs2_tag_id(tag) == 0x3ff) { + // handle root dir separately + pair[0] = lfs2->root[0]; + pair[1] = lfs2->root[1]; + } else { + // get dir pair from parent + lfs2_stag_t res = lfs2_dir_get(lfs2, &dir->m, LFS2_MKTAG(0x700, 0x3ff, 0), + LFS2_MKTAG(LFS2_TYPE_STRUCT, lfs2_tag_id(tag), 8), pair); + if (res < 0) { + LFS2_TRACE("lfs2_dir_open -> %d", res); + return res; + } + lfs2_pair_fromle32(pair); + } + + // fetch first pair + int err = lfs2_dir_fetch(lfs2, &dir->m, pair); + if (err) { + LFS2_TRACE("lfs2_dir_open -> %d", err); + return err; + } + + // setup entry + dir->head[0] = dir->m.pair[0]; + dir->head[1] = dir->m.pair[1]; + dir->id = 0; + dir->pos = 0; + + // add to list of mdirs + dir->type = LFS2_TYPE_DIR; + dir->next = (lfs2_dir_t*)lfs2->mlist; + lfs2->mlist = (struct lfs2_mlist*)dir; + + LFS2_TRACE("lfs2_dir_open -> %d", 0); + return 0; +} + +int lfs2_dir_close(lfs2_t *lfs2, lfs2_dir_t *dir) { + LFS2_TRACE("lfs2_dir_close(%p, %p)", (void*)lfs2, (void*)dir); + // remove from list of mdirs + for (struct lfs2_mlist **p = &lfs2->mlist; *p; p = &(*p)->next) { + if (*p == (struct lfs2_mlist*)dir) { + *p = (*p)->next; + break; + } + } + + LFS2_TRACE("lfs2_dir_close -> %d", 0); + return 0; +} + +int lfs2_dir_read(lfs2_t *lfs2, lfs2_dir_t *dir, struct lfs2_info *info) { + LFS2_TRACE("lfs2_dir_read(%p, %p, %p)", + (void*)lfs2, (void*)dir, (void*)info); + memset(info, 0, sizeof(*info)); + + // special offset for '.' and '..' + if (dir->pos == 0) { + info->type = LFS2_TYPE_DIR; + strcpy(info->name, "."); + dir->pos += 1; + LFS2_TRACE("lfs2_dir_read -> %d", true); + return true; + } else if (dir->pos == 1) { + info->type = LFS2_TYPE_DIR; + strcpy(info->name, ".."); + dir->pos += 1; + LFS2_TRACE("lfs2_dir_read -> %d", true); + return true; + } + + while (true) { + if (dir->id == dir->m.count) { + if (!dir->m.split) { + LFS2_TRACE("lfs2_dir_read -> %d", false); + return false; + } + + int err = lfs2_dir_fetch(lfs2, &dir->m, dir->m.tail); + if (err) { + LFS2_TRACE("lfs2_dir_read -> %d", err); + return err; + } + + dir->id = 0; + } + + int err = lfs2_dir_getinfo(lfs2, &dir->m, dir->id, info); + if (err && err != LFS2_ERR_NOENT) { + LFS2_TRACE("lfs2_dir_read -> %d", err); + return err; + } + + dir->id += 1; + if (err != LFS2_ERR_NOENT) { + break; + } + } + + dir->pos += 1; + LFS2_TRACE("lfs2_dir_read -> %d", true); + return true; +} + +int lfs2_dir_seek(lfs2_t *lfs2, lfs2_dir_t *dir, lfs2_off_t off) { + LFS2_TRACE("lfs2_dir_seek(%p, %p, %"PRIu32")", + (void*)lfs2, (void*)dir, off); + // simply walk from head dir + int err = lfs2_dir_rewind(lfs2, dir); + if (err) { + LFS2_TRACE("lfs2_dir_seek -> %d", err); + return err; + } + + // first two for ./.. + dir->pos = lfs2_min(2, off); + off -= dir->pos; + + while (off != 0) { + dir->id = lfs2_min(dir->m.count, off); + dir->pos += dir->id; + off -= dir->id; + + if (dir->id == dir->m.count) { + if (!dir->m.split) { + LFS2_TRACE("lfs2_dir_seek -> %d", LFS2_ERR_INVAL); + return LFS2_ERR_INVAL; + } + + err = lfs2_dir_fetch(lfs2, &dir->m, dir->m.tail); + if (err) { + LFS2_TRACE("lfs2_dir_seek -> %d", err); + return err; + } + } + } + + LFS2_TRACE("lfs2_dir_seek -> %d", 0); + return 0; +} + +lfs2_soff_t lfs2_dir_tell(lfs2_t *lfs2, lfs2_dir_t *dir) { + LFS2_TRACE("lfs2_dir_tell(%p, %p)", (void*)lfs2, (void*)dir); + (void)lfs2; + LFS2_TRACE("lfs2_dir_tell -> %"PRId32, dir->pos); + return dir->pos; +} + +int lfs2_dir_rewind(lfs2_t *lfs2, lfs2_dir_t *dir) { + LFS2_TRACE("lfs2_dir_rewind(%p, %p)", (void*)lfs2, (void*)dir); + // reload the head dir + int err = lfs2_dir_fetch(lfs2, &dir->m, dir->head); + if (err) { + LFS2_TRACE("lfs2_dir_rewind -> %d", err); + return err; + } + + dir->m.pair[0] = dir->head[0]; + dir->m.pair[1] = dir->head[1]; + dir->id = 0; + dir->pos = 0; + LFS2_TRACE("lfs2_dir_rewind -> %d", 0); + return 0; +} + + +/// File index list operations /// +static int lfs2_ctz_index(lfs2_t *lfs2, lfs2_off_t *off) { + lfs2_off_t size = *off; + lfs2_off_t b = lfs2->cfg->block_size - 2*4; + lfs2_off_t i = size / b; + if (i == 0) { + return 0; + } + + i = (size - 4*(lfs2_popc(i-1)+2)) / b; + *off = size - b*i - 4*lfs2_popc(i); + return i; +} + +static int lfs2_ctz_find(lfs2_t *lfs2, + const lfs2_cache_t *pcache, lfs2_cache_t *rcache, + lfs2_block_t head, lfs2_size_t size, + lfs2_size_t pos, lfs2_block_t *block, lfs2_off_t *off) { + if (size == 0) { + *block = LFS2_BLOCK_NULL; + *off = 0; + return 0; + } + + lfs2_off_t current = lfs2_ctz_index(lfs2, &(lfs2_off_t){size-1}); + lfs2_off_t target = lfs2_ctz_index(lfs2, &pos); + + while (current > target) { + lfs2_size_t skip = lfs2_min( + lfs2_npw2(current-target+1) - 1, + lfs2_ctz(current)); + + int err = lfs2_bd_read(lfs2, + pcache, rcache, sizeof(head), + head, 4*skip, &head, sizeof(head)); + head = lfs2_fromle32(head); + if (err) { + return err; + } + + LFS2_ASSERT(head >= 2 && head <= lfs2->cfg->block_count); + current -= 1 << skip; + } + + *block = head; + *off = pos; + return 0; +} + +static int lfs2_ctz_extend(lfs2_t *lfs2, + lfs2_cache_t *pcache, lfs2_cache_t *rcache, + lfs2_block_t head, lfs2_size_t size, + lfs2_block_t *block, lfs2_off_t *off) { + while (true) { + // go ahead and grab a block + lfs2_block_t nblock; + int err = lfs2_alloc(lfs2, &nblock); + if (err) { + return err; + } + LFS2_ASSERT(nblock >= 2 && nblock <= lfs2->cfg->block_count); + + { + err = lfs2_bd_erase(lfs2, nblock); + if (err) { + if (err == LFS2_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + if (size == 0) { + *block = nblock; + *off = 0; + return 0; + } + + size -= 1; + lfs2_off_t index = lfs2_ctz_index(lfs2, &size); + size += 1; + + // just copy out the last block if it is incomplete + if (size != lfs2->cfg->block_size) { + for (lfs2_off_t i = 0; i < size; i++) { + uint8_t data; + err = lfs2_bd_read(lfs2, + NULL, rcache, size-i, + head, i, &data, 1); + if (err) { + return err; + } + + err = lfs2_bd_prog(lfs2, + pcache, rcache, true, + nblock, i, &data, 1); + if (err) { + if (err == LFS2_ERR_CORRUPT) { + goto relocate; + } + return err; + } + } + + *block = nblock; + *off = size; + return 0; + } + + // append block + index += 1; + lfs2_size_t skips = lfs2_ctz(index) + 1; + + for (lfs2_off_t i = 0; i < skips; i++) { + head = lfs2_tole32(head); + err = lfs2_bd_prog(lfs2, pcache, rcache, true, + nblock, 4*i, &head, 4); + head = lfs2_fromle32(head); + if (err) { + if (err == LFS2_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + if (i != skips-1) { + err = lfs2_bd_read(lfs2, + NULL, rcache, sizeof(head), + head, 4*i, &head, sizeof(head)); + head = lfs2_fromle32(head); + if (err) { + return err; + } + } + + LFS2_ASSERT(head >= 2 && head <= lfs2->cfg->block_count); + } + + *block = nblock; + *off = 4*skips; + return 0; + } + +relocate: + LFS2_DEBUG("Bad block at %"PRIx32, nblock); + + // just clear cache and try a new block + lfs2_cache_drop(lfs2, pcache); + } +} + +static int lfs2_ctz_traverse(lfs2_t *lfs2, + const lfs2_cache_t *pcache, lfs2_cache_t *rcache, + lfs2_block_t head, lfs2_size_t size, + int (*cb)(void*, lfs2_block_t), void *data) { + if (size == 0) { + return 0; + } + + lfs2_off_t index = lfs2_ctz_index(lfs2, &(lfs2_off_t){size-1}); + + while (true) { + int err = cb(data, head); + if (err) { + return err; + } + + if (index == 0) { + return 0; + } + + lfs2_block_t heads[2]; + int count = 2 - (index & 1); + err = lfs2_bd_read(lfs2, + pcache, rcache, count*sizeof(head), + head, 0, &heads, count*sizeof(head)); + heads[0] = lfs2_fromle32(heads[0]); + heads[1] = lfs2_fromle32(heads[1]); + if (err) { + return err; + } + + for (int i = 0; i < count-1; i++) { + err = cb(data, heads[i]); + if (err) { + return err; + } + } + + head = heads[count-1]; + index -= count; + } +} + + +/// Top level file operations /// +int lfs2_file_opencfg(lfs2_t *lfs2, lfs2_file_t *file, + const char *path, int flags, + const struct lfs2_file_config *cfg) { + LFS2_TRACE("lfs2_file_opencfg(%p, %p, \"%s\", %x, %p {" + ".buffer=%p, .attrs=%p, .attr_count=%"PRIu32"})", + (void*)lfs2, (void*)file, path, flags, + (void*)cfg, cfg->buffer, (void*)cfg->attrs, cfg->attr_count); + + // deorphan if we haven't yet, needed at most once after poweron + if ((flags & 3) != LFS2_O_RDONLY) { + int err = lfs2_fs_forceconsistency(lfs2); + if (err) { + LFS2_TRACE("lfs2_file_opencfg -> %d", err); + return err; + } + } + + // setup simple file details + int err; + file->cfg = cfg; + file->flags = flags | LFS2_F_OPENED; + file->pos = 0; + file->off = 0; + file->cache.buffer = NULL; + + // allocate entry for file if it doesn't exist + lfs2_stag_t tag = lfs2_dir_find(lfs2, &file->m, &path, &file->id); + if (tag < 0 && !(tag == LFS2_ERR_NOENT && file->id != 0x3ff)) { + err = tag; + goto cleanup; + } + + // get id, add to list of mdirs to catch update changes + file->type = LFS2_TYPE_REG; + file->next = (lfs2_file_t*)lfs2->mlist; + lfs2->mlist = (struct lfs2_mlist*)file; + + if (tag == LFS2_ERR_NOENT) { + if (!(flags & LFS2_O_CREAT)) { + err = LFS2_ERR_NOENT; + goto cleanup; + } + + // check that name fits + lfs2_size_t nlen = strlen(path); + if (nlen > lfs2->name_max) { + err = LFS2_ERR_NAMETOOLONG; + goto cleanup; + } + + // get next slot and create entry to remember name + err = lfs2_dir_commit(lfs2, &file->m, LFS2_MKATTRS( + {LFS2_MKTAG(LFS2_TYPE_CREATE, file->id, 0), NULL}, + {LFS2_MKTAG(LFS2_TYPE_REG, file->id, nlen), path}, + {LFS2_MKTAG(LFS2_TYPE_INLINESTRUCT, file->id, 0), NULL})); + if (err) { + err = LFS2_ERR_NAMETOOLONG; + goto cleanup; + } + + tag = LFS2_MKTAG(LFS2_TYPE_INLINESTRUCT, 0, 0); + } else if (flags & LFS2_O_EXCL) { + err = LFS2_ERR_EXIST; + goto cleanup; + } else if (lfs2_tag_type3(tag) != LFS2_TYPE_REG) { + err = LFS2_ERR_ISDIR; + goto cleanup; + } else if (flags & LFS2_O_TRUNC) { + // truncate if requested + tag = LFS2_MKTAG(LFS2_TYPE_INLINESTRUCT, file->id, 0); + file->flags |= LFS2_F_DIRTY; + } else { + // try to load what's on disk, if it's inlined we'll fix it later + tag = lfs2_dir_get(lfs2, &file->m, LFS2_MKTAG(0x700, 0x3ff, 0), + LFS2_MKTAG(LFS2_TYPE_STRUCT, file->id, 8), &file->ctz); + if (tag < 0) { + err = tag; + goto cleanup; + } + lfs2_ctz_fromle32(&file->ctz); + } + + // fetch attrs + for (unsigned i = 0; i < file->cfg->attr_count; i++) { + if ((file->flags & 3) != LFS2_O_WRONLY) { + lfs2_stag_t res = lfs2_dir_get(lfs2, &file->m, + LFS2_MKTAG(0x7ff, 0x3ff, 0), + LFS2_MKTAG(LFS2_TYPE_USERATTR + file->cfg->attrs[i].type, + file->id, file->cfg->attrs[i].size), + file->cfg->attrs[i].buffer); + if (res < 0 && res != LFS2_ERR_NOENT) { + err = res; + goto cleanup; + } + } + + if ((file->flags & 3) != LFS2_O_RDONLY) { + if (file->cfg->attrs[i].size > lfs2->attr_max) { + err = LFS2_ERR_NOSPC; + goto cleanup; + } + + file->flags |= LFS2_F_DIRTY; + } + } + + // allocate buffer if needed + if (file->cfg->buffer) { + file->cache.buffer = file->cfg->buffer; + } else { + file->cache.buffer = lfs2_malloc(lfs2->cfg->cache_size); + if (!file->cache.buffer) { + err = LFS2_ERR_NOMEM; + goto cleanup; + } + } + + // zero to avoid information leak + lfs2_cache_zero(lfs2, &file->cache); + + if (lfs2_tag_type3(tag) == LFS2_TYPE_INLINESTRUCT) { + // load inline files + file->ctz.head = LFS2_BLOCK_INLINE; + file->ctz.size = lfs2_tag_size(tag); + file->flags |= LFS2_F_INLINE; + file->cache.block = file->ctz.head; + file->cache.off = 0; + file->cache.size = lfs2->cfg->cache_size; + + // don't always read (may be new/trunc file) + if (file->ctz.size > 0) { + lfs2_stag_t res = lfs2_dir_get(lfs2, &file->m, + LFS2_MKTAG(0x700, 0x3ff, 0), + LFS2_MKTAG(LFS2_TYPE_STRUCT, file->id, + lfs2_min(file->cache.size, 0x3fe)), + file->cache.buffer); + if (res < 0) { + err = res; + goto cleanup; + } + } + } + + LFS2_TRACE("lfs2_file_opencfg -> %d", 0); + return 0; + +cleanup: + // clean up lingering resources + file->flags |= LFS2_F_ERRED; + lfs2_file_close(lfs2, file); + LFS2_TRACE("lfs2_file_opencfg -> %d", err); + return err; +} + +int lfs2_file_open(lfs2_t *lfs2, lfs2_file_t *file, + const char *path, int flags) { + LFS2_TRACE("lfs2_file_open(%p, %p, \"%s\", %x)", + (void*)lfs2, (void*)file, path, flags); + static const struct lfs2_file_config defaults = {0}; + int err = lfs2_file_opencfg(lfs2, file, path, flags, &defaults); + LFS2_TRACE("lfs2_file_open -> %d", err); + return err; +} + +int lfs2_file_close(lfs2_t *lfs2, lfs2_file_t *file) { + LFS2_TRACE("lfs2_file_close(%p, %p)", (void*)lfs2, (void*)file); + LFS2_ASSERT(file->flags & LFS2_F_OPENED); + + int err = lfs2_file_sync(lfs2, file); + + // remove from list of mdirs + for (struct lfs2_mlist **p = &lfs2->mlist; *p; p = &(*p)->next) { + if (*p == (struct lfs2_mlist*)file) { + *p = (*p)->next; + break; + } + } + + // clean up memory + if (!file->cfg->buffer) { + lfs2_free(file->cache.buffer); + } + + file->flags &= ~LFS2_F_OPENED; + LFS2_TRACE("lfs2_file_close -> %d", err); + return err; +} + +static int lfs2_file_relocate(lfs2_t *lfs2, lfs2_file_t *file) { + LFS2_ASSERT(file->flags & LFS2_F_OPENED); + + while (true) { + // just relocate what exists into new block + lfs2_block_t nblock; + int err = lfs2_alloc(lfs2, &nblock); + if (err) { + return err; + } + + err = lfs2_bd_erase(lfs2, nblock); + if (err) { + if (err == LFS2_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + // either read from dirty cache or disk + for (lfs2_off_t i = 0; i < file->off; i++) { + uint8_t data; + if (file->flags & LFS2_F_INLINE) { + err = lfs2_dir_getread(lfs2, &file->m, + // note we evict inline files before they can be dirty + NULL, &file->cache, file->off-i, + LFS2_MKTAG(0xfff, 0x1ff, 0), + LFS2_MKTAG(LFS2_TYPE_INLINESTRUCT, file->id, 0), + i, &data, 1); + if (err) { + return err; + } + } else { + err = lfs2_bd_read(lfs2, + &file->cache, &lfs2->rcache, file->off-i, + file->block, i, &data, 1); + if (err) { + return err; + } + } + + err = lfs2_bd_prog(lfs2, + &lfs2->pcache, &lfs2->rcache, true, + nblock, i, &data, 1); + if (err) { + if (err == LFS2_ERR_CORRUPT) { + goto relocate; + } + return err; + } + } + + // copy over new state of file + memcpy(file->cache.buffer, lfs2->pcache.buffer, lfs2->cfg->cache_size); + file->cache.block = lfs2->pcache.block; + file->cache.off = lfs2->pcache.off; + file->cache.size = lfs2->pcache.size; + lfs2_cache_zero(lfs2, &lfs2->pcache); + + file->block = nblock; + file->flags |= LFS2_F_WRITING; + return 0; + +relocate: + LFS2_DEBUG("Bad block at %"PRIx32, nblock); + + // just clear cache and try a new block + lfs2_cache_drop(lfs2, &lfs2->pcache); + } +} + +static int lfs2_file_outline(lfs2_t *lfs2, lfs2_file_t *file) { + file->off = file->pos; + lfs2_alloc_ack(lfs2); + int err = lfs2_file_relocate(lfs2, file); + if (err) { + return err; + } + + file->flags &= ~LFS2_F_INLINE; + return 0; +} + +static int lfs2_file_flush(lfs2_t *lfs2, lfs2_file_t *file) { + LFS2_ASSERT(file->flags & LFS2_F_OPENED); + + if (file->flags & LFS2_F_READING) { + if (!(file->flags & LFS2_F_INLINE)) { + lfs2_cache_drop(lfs2, &file->cache); + } + file->flags &= ~LFS2_F_READING; + } + + if (file->flags & LFS2_F_WRITING) { + lfs2_off_t pos = file->pos; + + if (!(file->flags & LFS2_F_INLINE)) { + // copy over anything after current branch + lfs2_file_t orig = { + .ctz.head = file->ctz.head, + .ctz.size = file->ctz.size, + .flags = LFS2_O_RDONLY | LFS2_F_OPENED, + .pos = file->pos, + .cache = lfs2->rcache, + }; + lfs2_cache_drop(lfs2, &lfs2->rcache); + + while (file->pos < file->ctz.size) { + // copy over a byte at a time, leave it up to caching + // to make this efficient + uint8_t data; + lfs2_ssize_t res = lfs2_file_read(lfs2, &orig, &data, 1); + if (res < 0) { + return res; + } + + res = lfs2_file_write(lfs2, file, &data, 1); + if (res < 0) { + return res; + } + + // keep our reference to the rcache in sync + if (lfs2->rcache.block != LFS2_BLOCK_NULL) { + lfs2_cache_drop(lfs2, &orig.cache); + lfs2_cache_drop(lfs2, &lfs2->rcache); + } + } + + // write out what we have + while (true) { + int err = lfs2_bd_flush(lfs2, &file->cache, &lfs2->rcache, true); + if (err) { + if (err == LFS2_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + break; + +relocate: + LFS2_DEBUG("Bad block at %"PRIx32, file->block); + err = lfs2_file_relocate(lfs2, file); + if (err) { + return err; + } + } + } else { + file->pos = lfs2_max(file->pos, file->ctz.size); + } + + // actual file updates + file->ctz.head = file->block; + file->ctz.size = file->pos; + file->flags &= ~LFS2_F_WRITING; + file->flags |= LFS2_F_DIRTY; + + file->pos = pos; + } + + return 0; +} + +int lfs2_file_sync(lfs2_t *lfs2, lfs2_file_t *file) { + LFS2_TRACE("lfs2_file_sync(%p, %p)", (void*)lfs2, (void*)file); + LFS2_ASSERT(file->flags & LFS2_F_OPENED); + + while (true) { + int err = lfs2_file_flush(lfs2, file); + if (err) { + file->flags |= LFS2_F_ERRED; + LFS2_TRACE("lfs2_file_sync -> %d", err); + return err; + } + + if ((file->flags & LFS2_F_DIRTY) && + !(file->flags & LFS2_F_ERRED) && + !lfs2_pair_isnull(file->m.pair)) { + // update dir entry + uint16_t type; + const void *buffer; + lfs2_size_t size; + struct lfs2_ctz ctz; + if (file->flags & LFS2_F_INLINE) { + // inline the whole file + type = LFS2_TYPE_INLINESTRUCT; + buffer = file->cache.buffer; + size = file->ctz.size; + } else { + // update the ctz reference + type = LFS2_TYPE_CTZSTRUCT; + // copy ctz so alloc will work during a relocate + ctz = file->ctz; + lfs2_ctz_tole32(&ctz); + buffer = &ctz; + size = sizeof(ctz); + } + + // commit file data and attributes + err = lfs2_dir_commit(lfs2, &file->m, LFS2_MKATTRS( + {LFS2_MKTAG(type, file->id, size), buffer}, + {LFS2_MKTAG(LFS2_FROM_USERATTRS, file->id, + file->cfg->attr_count), file->cfg->attrs})); + if (err) { + if (err == LFS2_ERR_NOSPC && (file->flags & LFS2_F_INLINE)) { + goto relocate; + } + file->flags |= LFS2_F_ERRED; + LFS2_TRACE("lfs2_file_sync -> %d", err); + return err; + } + + file->flags &= ~LFS2_F_DIRTY; + } + + LFS2_TRACE("lfs2_file_sync -> %d", 0); + return 0; + +relocate: + // inline file doesn't fit anymore + err = lfs2_file_outline(lfs2, file); + if (err) { + file->flags |= LFS2_F_ERRED; + LFS2_TRACE("lfs2_file_sync -> %d", err); + return err; + } + } +} + +lfs2_ssize_t lfs2_file_read(lfs2_t *lfs2, lfs2_file_t *file, + void *buffer, lfs2_size_t size) { + LFS2_TRACE("lfs2_file_read(%p, %p, %p, %"PRIu32")", + (void*)lfs2, (void*)file, buffer, size); + LFS2_ASSERT(file->flags & LFS2_F_OPENED); + LFS2_ASSERT((file->flags & 3) != LFS2_O_WRONLY); + + uint8_t *data = buffer; + lfs2_size_t nsize = size; + + if (file->flags & LFS2_F_WRITING) { + // flush out any writes + int err = lfs2_file_flush(lfs2, file); + if (err) { + LFS2_TRACE("lfs2_file_read -> %"PRId32, err); + return err; + } + } + + if (file->pos >= file->ctz.size) { + // eof if past end + LFS2_TRACE("lfs2_file_read -> %"PRId32, 0); + return 0; + } + + size = lfs2_min(size, file->ctz.size - file->pos); + nsize = size; + + while (nsize > 0) { + // check if we need a new block + if (!(file->flags & LFS2_F_READING) || + file->off == lfs2->cfg->block_size) { + if (!(file->flags & LFS2_F_INLINE)) { + int err = lfs2_ctz_find(lfs2, NULL, &file->cache, + file->ctz.head, file->ctz.size, + file->pos, &file->block, &file->off); + if (err) { + LFS2_TRACE("lfs2_file_read -> %"PRId32, err); + return err; + } + } else { + file->block = LFS2_BLOCK_INLINE; + file->off = file->pos; + } + + file->flags |= LFS2_F_READING; + } + + // read as much as we can in current block + lfs2_size_t diff = lfs2_min(nsize, lfs2->cfg->block_size - file->off); + if (file->flags & LFS2_F_INLINE) { + int err = lfs2_dir_getread(lfs2, &file->m, + NULL, &file->cache, lfs2->cfg->block_size, + LFS2_MKTAG(0xfff, 0x1ff, 0), + LFS2_MKTAG(LFS2_TYPE_INLINESTRUCT, file->id, 0), + file->off, data, diff); + if (err) { + LFS2_TRACE("lfs2_file_read -> %"PRId32, err); + return err; + } + } else { + int err = lfs2_bd_read(lfs2, + NULL, &file->cache, lfs2->cfg->block_size, + file->block, file->off, data, diff); + if (err) { + LFS2_TRACE("lfs2_file_read -> %"PRId32, err); + return err; + } + } + + file->pos += diff; + file->off += diff; + data += diff; + nsize -= diff; + } + + LFS2_TRACE("lfs2_file_read -> %"PRId32, size); + return size; +} + +lfs2_ssize_t lfs2_file_write(lfs2_t *lfs2, lfs2_file_t *file, + const void *buffer, lfs2_size_t size) { + LFS2_TRACE("lfs2_file_write(%p, %p, %p, %"PRIu32")", + (void*)lfs2, (void*)file, buffer, size); + LFS2_ASSERT(file->flags & LFS2_F_OPENED); + LFS2_ASSERT((file->flags & 3) != LFS2_O_RDONLY); + + const uint8_t *data = buffer; + lfs2_size_t nsize = size; + + if (file->flags & LFS2_F_READING) { + // drop any reads + int err = lfs2_file_flush(lfs2, file); + if (err) { + LFS2_TRACE("lfs2_file_write -> %"PRId32, err); + return err; + } + } + + if ((file->flags & LFS2_O_APPEND) && file->pos < file->ctz.size) { + file->pos = file->ctz.size; + } + + if (file->pos + size > lfs2->file_max) { + // Larger than file limit? + LFS2_TRACE("lfs2_file_write -> %"PRId32, LFS2_ERR_FBIG); + return LFS2_ERR_FBIG; + } + + if (!(file->flags & LFS2_F_WRITING) && file->pos > file->ctz.size) { + // fill with zeros + lfs2_off_t pos = file->pos; + file->pos = file->ctz.size; + + while (file->pos < pos) { + lfs2_ssize_t res = lfs2_file_write(lfs2, file, &(uint8_t){0}, 1); + if (res < 0) { + LFS2_TRACE("lfs2_file_write -> %"PRId32, res); + return res; + } + } + } + + if ((file->flags & LFS2_F_INLINE) && + lfs2_max(file->pos+nsize, file->ctz.size) > + lfs2_min(0x3fe, lfs2_min( + lfs2->cfg->cache_size, lfs2->cfg->block_size/8))) { + // inline file doesn't fit anymore + int err = lfs2_file_outline(lfs2, file); + if (err) { + file->flags |= LFS2_F_ERRED; + LFS2_TRACE("lfs2_file_write -> %"PRId32, err); + return err; + } + } + + while (nsize > 0) { + // check if we need a new block + if (!(file->flags & LFS2_F_WRITING) || + file->off == lfs2->cfg->block_size) { + if (!(file->flags & LFS2_F_INLINE)) { + if (!(file->flags & LFS2_F_WRITING) && file->pos > 0) { + // find out which block we're extending from + int err = lfs2_ctz_find(lfs2, NULL, &file->cache, + file->ctz.head, file->ctz.size, + file->pos-1, &file->block, &file->off); + if (err) { + file->flags |= LFS2_F_ERRED; + LFS2_TRACE("lfs2_file_write -> %"PRId32, err); + return err; + } + + // mark cache as dirty since we may have read data into it + lfs2_cache_zero(lfs2, &file->cache); + } + + // extend file with new blocks + lfs2_alloc_ack(lfs2); + int err = lfs2_ctz_extend(lfs2, &file->cache, &lfs2->rcache, + file->block, file->pos, + &file->block, &file->off); + if (err) { + file->flags |= LFS2_F_ERRED; + LFS2_TRACE("lfs2_file_write -> %"PRId32, err); + return err; + } + } else { + file->block = LFS2_BLOCK_INLINE; + file->off = file->pos; + } + + file->flags |= LFS2_F_WRITING; + } + + // program as much as we can in current block + lfs2_size_t diff = lfs2_min(nsize, lfs2->cfg->block_size - file->off); + while (true) { + int err = lfs2_bd_prog(lfs2, &file->cache, &lfs2->rcache, true, + file->block, file->off, data, diff); + if (err) { + if (err == LFS2_ERR_CORRUPT) { + goto relocate; + } + file->flags |= LFS2_F_ERRED; + LFS2_TRACE("lfs2_file_write -> %"PRId32, err); + return err; + } + + break; +relocate: + err = lfs2_file_relocate(lfs2, file); + if (err) { + file->flags |= LFS2_F_ERRED; + LFS2_TRACE("lfs2_file_write -> %"PRId32, err); + return err; + } + } + + file->pos += diff; + file->off += diff; + data += diff; + nsize -= diff; + + lfs2_alloc_ack(lfs2); + } + + file->flags &= ~LFS2_F_ERRED; + LFS2_TRACE("lfs2_file_write -> %"PRId32, size); + return size; +} + +lfs2_soff_t lfs2_file_seek(lfs2_t *lfs2, lfs2_file_t *file, + lfs2_soff_t off, int whence) { + LFS2_TRACE("lfs2_file_seek(%p, %p, %"PRId32", %d)", + (void*)lfs2, (void*)file, off, whence); + LFS2_ASSERT(file->flags & LFS2_F_OPENED); + + // write out everything beforehand, may be noop if rdonly + int err = lfs2_file_flush(lfs2, file); + if (err) { + LFS2_TRACE("lfs2_file_seek -> %"PRId32, err); + return err; + } + + // find new pos + lfs2_off_t npos = file->pos; + if (whence == LFS2_SEEK_SET) { + npos = off; + } else if (whence == LFS2_SEEK_CUR) { + npos = file->pos + off; + } else if (whence == LFS2_SEEK_END) { + npos = file->ctz.size + off; + } + + if (npos > lfs2->file_max) { + // file position out of range + LFS2_TRACE("lfs2_file_seek -> %"PRId32, LFS2_ERR_INVAL); + return LFS2_ERR_INVAL; + } + + // update pos + file->pos = npos; + LFS2_TRACE("lfs2_file_seek -> %"PRId32, npos); + return npos; +} + +int lfs2_file_truncate(lfs2_t *lfs2, lfs2_file_t *file, lfs2_off_t size) { + LFS2_TRACE("lfs2_file_truncate(%p, %p, %"PRIu32")", + (void*)lfs2, (void*)file, size); + LFS2_ASSERT(file->flags & LFS2_F_OPENED); + LFS2_ASSERT((file->flags & 3) != LFS2_O_RDONLY); + + if (size > LFS2_FILE_MAX) { + LFS2_TRACE("lfs2_file_truncate -> %d", LFS2_ERR_INVAL); + return LFS2_ERR_INVAL; + } + + lfs2_off_t pos = file->pos; + lfs2_off_t oldsize = lfs2_file_size(lfs2, file); + if (size < oldsize) { + // need to flush since directly changing metadata + int err = lfs2_file_flush(lfs2, file); + if (err) { + LFS2_TRACE("lfs2_file_truncate -> %d", err); + return err; + } + + // lookup new head in ctz skip list + err = lfs2_ctz_find(lfs2, NULL, &file->cache, + file->ctz.head, file->ctz.size, + size, &file->block, &file->off); + if (err) { + LFS2_TRACE("lfs2_file_truncate -> %d", err); + return err; + } + + file->ctz.head = file->block; + file->ctz.size = size; + file->flags |= LFS2_F_DIRTY | LFS2_F_READING; + } else if (size > oldsize) { + // flush+seek if not already at end + if (file->pos != oldsize) { + lfs2_soff_t res = lfs2_file_seek(lfs2, file, 0, LFS2_SEEK_END); + if (res < 0) { + LFS2_TRACE("lfs2_file_truncate -> %d", res); + return (int)res; + } + } + + // fill with zeros + while (file->pos < size) { + lfs2_ssize_t res = lfs2_file_write(lfs2, file, &(uint8_t){0}, 1); + if (res < 0) { + LFS2_TRACE("lfs2_file_truncate -> %d", res); + return (int)res; + } + } + } + + // restore pos + lfs2_soff_t res = lfs2_file_seek(lfs2, file, pos, LFS2_SEEK_SET); + if (res < 0) { + LFS2_TRACE("lfs2_file_truncate -> %d", res); + return (int)res; + } + + LFS2_TRACE("lfs2_file_truncate -> %d", 0); + return 0; +} + +lfs2_soff_t lfs2_file_tell(lfs2_t *lfs2, lfs2_file_t *file) { + LFS2_TRACE("lfs2_file_tell(%p, %p)", (void*)lfs2, (void*)file); + LFS2_ASSERT(file->flags & LFS2_F_OPENED); + (void)lfs2; + LFS2_TRACE("lfs2_file_tell -> %"PRId32, file->pos); + return file->pos; +} + +int lfs2_file_rewind(lfs2_t *lfs2, lfs2_file_t *file) { + LFS2_TRACE("lfs2_file_rewind(%p, %p)", (void*)lfs2, (void*)file); + lfs2_soff_t res = lfs2_file_seek(lfs2, file, 0, LFS2_SEEK_SET); + if (res < 0) { + LFS2_TRACE("lfs2_file_rewind -> %d", res); + return (int)res; + } + + LFS2_TRACE("lfs2_file_rewind -> %d", 0); + return 0; +} + +lfs2_soff_t lfs2_file_size(lfs2_t *lfs2, lfs2_file_t *file) { + LFS2_TRACE("lfs2_file_size(%p, %p)", (void*)lfs2, (void*)file); + LFS2_ASSERT(file->flags & LFS2_F_OPENED); + (void)lfs2; + if (file->flags & LFS2_F_WRITING) { + LFS2_TRACE("lfs2_file_size -> %"PRId32, + lfs2_max(file->pos, file->ctz.size)); + return lfs2_max(file->pos, file->ctz.size); + } else { + LFS2_TRACE("lfs2_file_size -> %"PRId32, file->ctz.size); + return file->ctz.size; + } +} + + +/// General fs operations /// +int lfs2_stat(lfs2_t *lfs2, const char *path, struct lfs2_info *info) { + LFS2_TRACE("lfs2_stat(%p, \"%s\", %p)", (void*)lfs2, path, (void*)info); + lfs2_mdir_t cwd; + lfs2_stag_t tag = lfs2_dir_find(lfs2, &cwd, &path, NULL); + if (tag < 0) { + LFS2_TRACE("lfs2_stat -> %d", tag); + return (int)tag; + } + + int err = lfs2_dir_getinfo(lfs2, &cwd, lfs2_tag_id(tag), info); + LFS2_TRACE("lfs2_stat -> %d", err); + return err; +} + +int lfs2_remove(lfs2_t *lfs2, const char *path) { + LFS2_TRACE("lfs2_remove(%p, \"%s\")", (void*)lfs2, path); + // deorphan if we haven't yet, needed at most once after poweron + int err = lfs2_fs_forceconsistency(lfs2); + if (err) { + LFS2_TRACE("lfs2_remove -> %d", err); + return err; + } + + lfs2_mdir_t cwd; + lfs2_stag_t tag = lfs2_dir_find(lfs2, &cwd, &path, NULL); + if (tag < 0 || lfs2_tag_id(tag) == 0x3ff) { + LFS2_TRACE("lfs2_remove -> %d", (tag < 0) ? tag : LFS2_ERR_INVAL); + return (tag < 0) ? (int)tag : LFS2_ERR_INVAL; + } + + lfs2_mdir_t dir; + if (lfs2_tag_type3(tag) == LFS2_TYPE_DIR) { + // must be empty before removal + lfs2_block_t pair[2]; + lfs2_stag_t res = lfs2_dir_get(lfs2, &cwd, LFS2_MKTAG(0x700, 0x3ff, 0), + LFS2_MKTAG(LFS2_TYPE_STRUCT, lfs2_tag_id(tag), 8), pair); + if (res < 0) { + LFS2_TRACE("lfs2_remove -> %d", res); + return (int)res; + } + lfs2_pair_fromle32(pair); + + err = lfs2_dir_fetch(lfs2, &dir, pair); + if (err) { + LFS2_TRACE("lfs2_remove -> %d", err); + return err; + } + + if (dir.count > 0 || dir.split) { + LFS2_TRACE("lfs2_remove -> %d", LFS2_ERR_NOTEMPTY); + return LFS2_ERR_NOTEMPTY; + } + + // mark fs as orphaned + lfs2_fs_preporphans(lfs2, +1); + } + + // delete the entry + err = lfs2_dir_commit(lfs2, &cwd, LFS2_MKATTRS( + {LFS2_MKTAG(LFS2_TYPE_DELETE, lfs2_tag_id(tag), 0), NULL})); + if (err) { + LFS2_TRACE("lfs2_remove -> %d", err); + return err; + } + + if (lfs2_tag_type3(tag) == LFS2_TYPE_DIR) { + // fix orphan + lfs2_fs_preporphans(lfs2, -1); + + err = lfs2_fs_pred(lfs2, dir.pair, &cwd); + if (err) { + LFS2_TRACE("lfs2_remove -> %d", err); + return err; + } + + err = lfs2_dir_drop(lfs2, &cwd, &dir); + if (err) { + LFS2_TRACE("lfs2_remove -> %d", err); + return err; + } + } + + LFS2_TRACE("lfs2_remove -> %d", 0); + return 0; +} + +int lfs2_rename(lfs2_t *lfs2, const char *oldpath, const char *newpath) { + LFS2_TRACE("lfs2_rename(%p, \"%s\", \"%s\")", (void*)lfs2, oldpath, newpath); + + // deorphan if we haven't yet, needed at most once after poweron + int err = lfs2_fs_forceconsistency(lfs2); + if (err) { + LFS2_TRACE("lfs2_rename -> %d", err); + return err; + } + + // find old entry + lfs2_mdir_t oldcwd; + lfs2_stag_t oldtag = lfs2_dir_find(lfs2, &oldcwd, &oldpath, NULL); + if (oldtag < 0 || lfs2_tag_id(oldtag) == 0x3ff) { + LFS2_TRACE("lfs2_rename -> %d", (oldtag < 0) ? oldtag : LFS2_ERR_INVAL); + return (oldtag < 0) ? (int)oldtag : LFS2_ERR_INVAL; + } + + // find new entry + lfs2_mdir_t newcwd; + uint16_t newid; + lfs2_stag_t prevtag = lfs2_dir_find(lfs2, &newcwd, &newpath, &newid); + if ((prevtag < 0 || lfs2_tag_id(prevtag) == 0x3ff) && + !(prevtag == LFS2_ERR_NOENT && newid != 0x3ff)) { + LFS2_TRACE("lfs2_rename -> %d", (prevtag < 0) ? prevtag : LFS2_ERR_INVAL); + return (prevtag < 0) ? (int)prevtag : LFS2_ERR_INVAL; + } + + lfs2_mdir_t prevdir; + if (prevtag == LFS2_ERR_NOENT) { + // check that name fits + lfs2_size_t nlen = strlen(newpath); + if (nlen > lfs2->name_max) { + LFS2_TRACE("lfs2_rename -> %d", LFS2_ERR_NAMETOOLONG); + return LFS2_ERR_NAMETOOLONG; + } + } else if (lfs2_tag_type3(prevtag) != lfs2_tag_type3(oldtag)) { + LFS2_TRACE("lfs2_rename -> %d", LFS2_ERR_ISDIR); + return LFS2_ERR_ISDIR; + } else if (lfs2_tag_type3(prevtag) == LFS2_TYPE_DIR) { + // must be empty before removal + lfs2_block_t prevpair[2]; + lfs2_stag_t res = lfs2_dir_get(lfs2, &newcwd, LFS2_MKTAG(0x700, 0x3ff, 0), + LFS2_MKTAG(LFS2_TYPE_STRUCT, newid, 8), prevpair); + if (res < 0) { + LFS2_TRACE("lfs2_rename -> %d", res); + return (int)res; + } + lfs2_pair_fromle32(prevpair); + + // must be empty before removal + err = lfs2_dir_fetch(lfs2, &prevdir, prevpair); + if (err) { + LFS2_TRACE("lfs2_rename -> %d", err); + return err; + } + + if (prevdir.count > 0 || prevdir.split) { + LFS2_TRACE("lfs2_rename -> %d", LFS2_ERR_NOTEMPTY); + return LFS2_ERR_NOTEMPTY; + } + + // mark fs as orphaned + lfs2_fs_preporphans(lfs2, +1); + } + + // create move to fix later + uint16_t newoldtagid = lfs2_tag_id(oldtag); + if (lfs2_pair_cmp(oldcwd.pair, newcwd.pair) == 0 && + prevtag == LFS2_ERR_NOENT && newid <= newoldtagid) { + // there is a small chance we are being renamed in the same directory + // to an id less than our old id, the global update to handle this + // is a bit messy + newoldtagid += 1; + } + + lfs2_fs_prepmove(lfs2, newoldtagid, oldcwd.pair); + + // move over all attributes + err = lfs2_dir_commit(lfs2, &newcwd, LFS2_MKATTRS( + {prevtag != LFS2_ERR_NOENT + ? LFS2_MKTAG(LFS2_TYPE_DELETE, newid, 0) + : LFS2_MKTAG(LFS2_FROM_NOOP, 0, 0), NULL}, + {LFS2_MKTAG(LFS2_TYPE_CREATE, newid, 0), NULL}, + {LFS2_MKTAG(lfs2_tag_type3(oldtag), newid, strlen(newpath)), + newpath}, + {LFS2_MKTAG(LFS2_FROM_MOVE, newid, lfs2_tag_id(oldtag)), &oldcwd})); + if (err) { + LFS2_TRACE("lfs2_rename -> %d", err); + return err; + } + + // let commit clean up after move (if we're different! otherwise move + // logic already fixed it for us) + if (lfs2_pair_cmp(oldcwd.pair, newcwd.pair) != 0) { + err = lfs2_dir_commit(lfs2, &oldcwd, NULL, 0); + if (err) { + LFS2_TRACE("lfs2_rename -> %d", err); + return err; + } + } + + if (prevtag != LFS2_ERR_NOENT && lfs2_tag_type3(prevtag) == LFS2_TYPE_DIR) { + // fix orphan + lfs2_fs_preporphans(lfs2, -1); + + err = lfs2_fs_pred(lfs2, prevdir.pair, &newcwd); + if (err) { + LFS2_TRACE("lfs2_rename -> %d", err); + return err; + } + + err = lfs2_dir_drop(lfs2, &newcwd, &prevdir); + if (err) { + LFS2_TRACE("lfs2_rename -> %d", err); + return err; + } + } + + LFS2_TRACE("lfs2_rename -> %d", 0); + return 0; +} + +lfs2_ssize_t lfs2_getattr(lfs2_t *lfs2, const char *path, + uint8_t type, void *buffer, lfs2_size_t size) { + LFS2_TRACE("lfs2_getattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")", + (void*)lfs2, path, type, buffer, size); + lfs2_mdir_t cwd; + lfs2_stag_t tag = lfs2_dir_find(lfs2, &cwd, &path, NULL); + if (tag < 0) { + LFS2_TRACE("lfs2_getattr -> %"PRId32, tag); + return tag; + } + + uint16_t id = lfs2_tag_id(tag); + if (id == 0x3ff) { + // special case for root + id = 0; + int err = lfs2_dir_fetch(lfs2, &cwd, lfs2->root); + if (err) { + LFS2_TRACE("lfs2_getattr -> %"PRId32, err); + return err; + } + } + + tag = lfs2_dir_get(lfs2, &cwd, LFS2_MKTAG(0x7ff, 0x3ff, 0), + LFS2_MKTAG(LFS2_TYPE_USERATTR + type, + id, lfs2_min(size, lfs2->attr_max)), + buffer); + if (tag < 0) { + if (tag == LFS2_ERR_NOENT) { + LFS2_TRACE("lfs2_getattr -> %"PRId32, LFS2_ERR_NOATTR); + return LFS2_ERR_NOATTR; + } + + LFS2_TRACE("lfs2_getattr -> %"PRId32, tag); + return tag; + } + + size = lfs2_tag_size(tag); + LFS2_TRACE("lfs2_getattr -> %"PRId32, size); + return size; +} + +static int lfs2_commitattr(lfs2_t *lfs2, const char *path, + uint8_t type, const void *buffer, lfs2_size_t size) { + lfs2_mdir_t cwd; + lfs2_stag_t tag = lfs2_dir_find(lfs2, &cwd, &path, NULL); + if (tag < 0) { + return tag; + } + + uint16_t id = lfs2_tag_id(tag); + if (id == 0x3ff) { + // special case for root + id = 0; + int err = lfs2_dir_fetch(lfs2, &cwd, lfs2->root); + if (err) { + return err; + } + } + + return lfs2_dir_commit(lfs2, &cwd, LFS2_MKATTRS( + {LFS2_MKTAG(LFS2_TYPE_USERATTR + type, id, size), buffer})); +} + +int lfs2_setattr(lfs2_t *lfs2, const char *path, + uint8_t type, const void *buffer, lfs2_size_t size) { + LFS2_TRACE("lfs2_setattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")", + (void*)lfs2, path, type, buffer, size); + if (size > lfs2->attr_max) { + LFS2_TRACE("lfs2_setattr -> %d", LFS2_ERR_NOSPC); + return LFS2_ERR_NOSPC; + } + + int err = lfs2_commitattr(lfs2, path, type, buffer, size); + LFS2_TRACE("lfs2_setattr -> %d", err); + return err; +} + +int lfs2_removeattr(lfs2_t *lfs2, const char *path, uint8_t type) { + LFS2_TRACE("lfs2_removeattr(%p, \"%s\", %"PRIu8")", (void*)lfs2, path, type); + int err = lfs2_commitattr(lfs2, path, type, NULL, 0x3ff); + LFS2_TRACE("lfs2_removeattr -> %d", err); + return err; +} + + +/// Filesystem operations /// +static int lfs2_init(lfs2_t *lfs2, const struct lfs2_config *cfg) { + lfs2->cfg = cfg; + int err = 0; + + // validate that the lfs2-cfg sizes were initiated properly before + // performing any arithmetic logics with them + LFS2_ASSERT(lfs2->cfg->read_size != 0); + LFS2_ASSERT(lfs2->cfg->prog_size != 0); + LFS2_ASSERT(lfs2->cfg->cache_size != 0); + + // check that block size is a multiple of cache size is a multiple + // of prog and read sizes + LFS2_ASSERT(lfs2->cfg->cache_size % lfs2->cfg->read_size == 0); + LFS2_ASSERT(lfs2->cfg->cache_size % lfs2->cfg->prog_size == 0); + LFS2_ASSERT(lfs2->cfg->block_size % lfs2->cfg->cache_size == 0); + + // check that the block size is large enough to fit ctz pointers + LFS2_ASSERT(4*lfs2_npw2(LFS2_BLOCK_NULL / (lfs2->cfg->block_size-2*4)) + <= lfs2->cfg->block_size); + + // block_cycles = 0 is no longer supported. + // + // block_cycles is the number of erase cycles before littlefs evicts + // metadata logs as a part of wear leveling. Suggested values are in the + // range of 100-1000, or set block_cycles to -1 to disable block-level + // wear-leveling. + LFS2_ASSERT(lfs2->cfg->block_cycles != 0); + + + // setup read cache + if (lfs2->cfg->read_buffer) { + lfs2->rcache.buffer = lfs2->cfg->read_buffer; + } else { + lfs2->rcache.buffer = lfs2_malloc(lfs2->cfg->cache_size); + if (!lfs2->rcache.buffer) { + err = LFS2_ERR_NOMEM; + goto cleanup; + } + } + + // setup program cache + if (lfs2->cfg->prog_buffer) { + lfs2->pcache.buffer = lfs2->cfg->prog_buffer; + } else { + lfs2->pcache.buffer = lfs2_malloc(lfs2->cfg->cache_size); + if (!lfs2->pcache.buffer) { + err = LFS2_ERR_NOMEM; + goto cleanup; + } + } + + // zero to avoid information leaks + lfs2_cache_zero(lfs2, &lfs2->rcache); + lfs2_cache_zero(lfs2, &lfs2->pcache); + + // setup lookahead, must be multiple of 64-bits, 32-bit aligned + LFS2_ASSERT(lfs2->cfg->lookahead_size > 0); + LFS2_ASSERT(lfs2->cfg->lookahead_size % 8 == 0 && + (uintptr_t)lfs2->cfg->lookahead_buffer % 4 == 0); + if (lfs2->cfg->lookahead_buffer) { + lfs2->free.buffer = lfs2->cfg->lookahead_buffer; + } else { + lfs2->free.buffer = lfs2_malloc(lfs2->cfg->lookahead_size); + if (!lfs2->free.buffer) { + err = LFS2_ERR_NOMEM; + goto cleanup; + } + } + + // check that the size limits are sane + LFS2_ASSERT(lfs2->cfg->name_max <= LFS2_NAME_MAX); + lfs2->name_max = lfs2->cfg->name_max; + if (!lfs2->name_max) { + lfs2->name_max = LFS2_NAME_MAX; + } + + LFS2_ASSERT(lfs2->cfg->file_max <= LFS2_FILE_MAX); + lfs2->file_max = lfs2->cfg->file_max; + if (!lfs2->file_max) { + lfs2->file_max = LFS2_FILE_MAX; + } + + LFS2_ASSERT(lfs2->cfg->attr_max <= LFS2_ATTR_MAX); + lfs2->attr_max = lfs2->cfg->attr_max; + if (!lfs2->attr_max) { + lfs2->attr_max = LFS2_ATTR_MAX; + } + + // setup default state + lfs2->root[0] = LFS2_BLOCK_NULL; + lfs2->root[1] = LFS2_BLOCK_NULL; + lfs2->mlist = NULL; + lfs2->seed = 0; + lfs2->gstate = (struct lfs2_gstate){0}; + lfs2->gpending = (struct lfs2_gstate){0}; + lfs2->gdelta = (struct lfs2_gstate){0}; +#ifdef LFS2_MIGRATE + lfs2->lfs21 = NULL; +#endif + + return 0; + +cleanup: + lfs2_deinit(lfs2); + return err; +} + +static int lfs2_deinit(lfs2_t *lfs2) { + // free allocated memory + if (!lfs2->cfg->read_buffer) { + lfs2_free(lfs2->rcache.buffer); + } + + if (!lfs2->cfg->prog_buffer) { + lfs2_free(lfs2->pcache.buffer); + } + + if (!lfs2->cfg->lookahead_buffer) { + lfs2_free(lfs2->free.buffer); + } + + return 0; +} + +int lfs2_format(lfs2_t *lfs2, const struct lfs2_config *cfg) { + LFS2_TRACE("lfs2_format(%p, %p {.context=%p, " + ".read=%p, .prog=%p, .erase=%p, .sync=%p, " + ".read_size=%"PRIu32", .prog_size=%"PRIu32", " + ".block_size=%"PRIu32", .block_count=%"PRIu32", " + ".block_cycles=%"PRIu32", .cache_size=%"PRIu32", " + ".lookahead_size=%"PRIu32", .read_buffer=%p, " + ".prog_buffer=%p, .lookahead_buffer=%p, " + ".name_max=%"PRIu32", .file_max=%"PRIu32", " + ".attr_max=%"PRIu32"})", + (void*)lfs2, (void*)cfg, cfg->context, + (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, + (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, + cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, + cfg->block_cycles, cfg->cache_size, cfg->lookahead_size, + cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, + cfg->name_max, cfg->file_max, cfg->attr_max); + int err = 0; + { + err = lfs2_init(lfs2, cfg); + if (err) { + LFS2_TRACE("lfs2_format -> %d", err); + return err; + } + + // create free lookahead + memset(lfs2->free.buffer, 0, lfs2->cfg->lookahead_size); + lfs2->free.off = 0; + lfs2->free.size = lfs2_min(8*lfs2->cfg->lookahead_size, + lfs2->cfg->block_count); + lfs2->free.i = 0; + lfs2_alloc_ack(lfs2); + + // create root dir + lfs2_mdir_t root; + err = lfs2_dir_alloc(lfs2, &root); + if (err) { + goto cleanup; + } + + // write one superblock + lfs2_superblock_t superblock = { + .version = LFS2_DISK_VERSION, + .block_size = lfs2->cfg->block_size, + .block_count = lfs2->cfg->block_count, + .name_max = lfs2->name_max, + .file_max = lfs2->file_max, + .attr_max = lfs2->attr_max, + }; + + lfs2_superblock_tole32(&superblock); + err = lfs2_dir_commit(lfs2, &root, LFS2_MKATTRS( + {LFS2_MKTAG(LFS2_TYPE_CREATE, 0, 0), NULL}, + {LFS2_MKTAG(LFS2_TYPE_SUPERBLOCK, 0, 8), "littlefs"}, + {LFS2_MKTAG(LFS2_TYPE_INLINESTRUCT, 0, sizeof(superblock)), + &superblock})); + if (err) { + goto cleanup; + } + + // sanity check that fetch works + err = lfs2_dir_fetch(lfs2, &root, (const lfs2_block_t[2]){0, 1}); + if (err) { + goto cleanup; + } + + // force compaction to prevent accidentally mounting any + // older version of littlefs that may live on disk + root.erased = false; + err = lfs2_dir_commit(lfs2, &root, NULL, 0); + if (err) { + goto cleanup; + } + } + +cleanup: + lfs2_deinit(lfs2); + LFS2_TRACE("lfs2_format -> %d", err); + return err; +} + +int lfs2_mount(lfs2_t *lfs2, const struct lfs2_config *cfg) { + LFS2_TRACE("lfs2_mount(%p, %p {.context=%p, " + ".read=%p, .prog=%p, .erase=%p, .sync=%p, " + ".read_size=%"PRIu32", .prog_size=%"PRIu32", " + ".block_size=%"PRIu32", .block_count=%"PRIu32", " + ".block_cycles=%"PRIu32", .cache_size=%"PRIu32", " + ".lookahead_size=%"PRIu32", .read_buffer=%p, " + ".prog_buffer=%p, .lookahead_buffer=%p, " + ".name_max=%"PRIu32", .file_max=%"PRIu32", " + ".attr_max=%"PRIu32"})", + (void*)lfs2, (void*)cfg, cfg->context, + (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, + (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, + cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, + cfg->block_cycles, cfg->cache_size, cfg->lookahead_size, + cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, + cfg->name_max, cfg->file_max, cfg->attr_max); + int err = lfs2_init(lfs2, cfg); + if (err) { + LFS2_TRACE("lfs2_mount -> %d", err); + return err; + } + + // scan directory blocks for superblock and any global updates + lfs2_mdir_t dir = {.tail = {0, 1}}; + while (!lfs2_pair_isnull(dir.tail)) { + // fetch next block in tail list + lfs2_stag_t tag = lfs2_dir_fetchmatch(lfs2, &dir, dir.tail, + LFS2_MKTAG(0x7ff, 0x3ff, 0), + LFS2_MKTAG(LFS2_TYPE_SUPERBLOCK, 0, 8), + NULL, + lfs2_dir_find_match, &(struct lfs2_dir_find_match){ + lfs2, "littlefs", 8}); + if (tag < 0) { + err = tag; + goto cleanup; + } + + // has superblock? + if (tag && !lfs2_tag_isdelete(tag)) { + // update root + lfs2->root[0] = dir.pair[0]; + lfs2->root[1] = dir.pair[1]; + + // grab superblock + lfs2_superblock_t superblock; + tag = lfs2_dir_get(lfs2, &dir, LFS2_MKTAG(0x7ff, 0x3ff, 0), + LFS2_MKTAG(LFS2_TYPE_INLINESTRUCT, 0, sizeof(superblock)), + &superblock); + if (tag < 0) { + err = tag; + goto cleanup; + } + lfs2_superblock_fromle32(&superblock); + + // check version + uint16_t major_version = (0xffff & (superblock.version >> 16)); + uint16_t minor_version = (0xffff & (superblock.version >> 0)); + if ((major_version != LFS2_DISK_VERSION_MAJOR || + minor_version > LFS2_DISK_VERSION_MINOR)) { + LFS2_ERROR("Invalid version %"PRIu16".%"PRIu16, + major_version, minor_version); + err = LFS2_ERR_INVAL; + goto cleanup; + } + + // check superblock configuration + if (superblock.name_max) { + if (superblock.name_max > lfs2->name_max) { + LFS2_ERROR("Unsupported name_max (%"PRIu32" > %"PRIu32")", + superblock.name_max, lfs2->name_max); + err = LFS2_ERR_INVAL; + goto cleanup; + } + + lfs2->name_max = superblock.name_max; + } + + if (superblock.file_max) { + if (superblock.file_max > lfs2->file_max) { + LFS2_ERROR("Unsupported file_max (%"PRIu32" > %"PRIu32")", + superblock.file_max, lfs2->file_max); + err = LFS2_ERR_INVAL; + goto cleanup; + } + + lfs2->file_max = superblock.file_max; + } + + if (superblock.attr_max) { + if (superblock.attr_max > lfs2->attr_max) { + LFS2_ERROR("Unsupported attr_max (%"PRIu32" > %"PRIu32")", + superblock.attr_max, lfs2->attr_max); + err = LFS2_ERR_INVAL; + goto cleanup; + } + + lfs2->attr_max = superblock.attr_max; + } + } + + // has gstate? + err = lfs2_dir_getgstate(lfs2, &dir, &lfs2->gpending); + if (err) { + goto cleanup; + } + } + + // found superblock? + if (lfs2_pair_isnull(lfs2->root)) { + err = LFS2_ERR_INVAL; + goto cleanup; + } + + // update littlefs with gstate + lfs2->gpending.tag += !lfs2_tag_isvalid(lfs2->gpending.tag); + lfs2->gstate = lfs2->gpending; + if (lfs2_gstate_hasmove(&lfs2->gstate)) { + LFS2_DEBUG("Found move %"PRIx32" %"PRIx32" %"PRIx16, + lfs2->gstate.pair[0], + lfs2->gstate.pair[1], + lfs2_tag_id(lfs2->gstate.tag)); + } + + // setup free lookahead + lfs2->free.off = lfs2->seed % lfs2->cfg->block_size; + lfs2->free.size = 0; + lfs2->free.i = 0; + lfs2_alloc_ack(lfs2); + + LFS2_TRACE("lfs2_mount -> %d", 0); + return 0; + +cleanup: + lfs2_unmount(lfs2); + LFS2_TRACE("lfs2_mount -> %d", err); + return err; +} + +int lfs2_unmount(lfs2_t *lfs2) { + LFS2_TRACE("lfs2_unmount(%p)", (void*)lfs2); + int err = lfs2_deinit(lfs2); + LFS2_TRACE("lfs2_unmount -> %d", err); + return err; +} + + +/// Filesystem filesystem operations /// +int lfs2_fs_traverse(lfs2_t *lfs2, + int (*cb)(void *data, lfs2_block_t block), void *data) { + LFS2_TRACE("lfs2_fs_traverse(%p, %p, %p)", + (void*)lfs2, (void*)(uintptr_t)cb, data); + // iterate over metadata pairs + lfs2_mdir_t dir = {.tail = {0, 1}}; + +#ifdef LFS2_MIGRATE + // also consider v1 blocks during migration + if (lfs2->lfs21) { + int err = lfs21_traverse(lfs2, cb, data); + if (err) { + LFS2_TRACE("lfs2_fs_traverse -> %d", err); + return err; + } + + dir.tail[0] = lfs2->root[0]; + dir.tail[1] = lfs2->root[1]; + } +#endif + + while (!lfs2_pair_isnull(dir.tail)) { + for (int i = 0; i < 2; i++) { + int err = cb(data, dir.tail[i]); + if (err) { + LFS2_TRACE("lfs2_fs_traverse -> %d", err); + return err; + } + } + + // iterate through ids in directory + int err = lfs2_dir_fetch(lfs2, &dir, dir.tail); + if (err) { + LFS2_TRACE("lfs2_fs_traverse -> %d", err); + return err; + } + + for (uint16_t id = 0; id < dir.count; id++) { + struct lfs2_ctz ctz; + lfs2_stag_t tag = lfs2_dir_get(lfs2, &dir, LFS2_MKTAG(0x700, 0x3ff, 0), + LFS2_MKTAG(LFS2_TYPE_STRUCT, id, sizeof(ctz)), &ctz); + if (tag < 0) { + if (tag == LFS2_ERR_NOENT) { + continue; + } + LFS2_TRACE("lfs2_fs_traverse -> %d", tag); + return tag; + } + lfs2_ctz_fromle32(&ctz); + + if (lfs2_tag_type3(tag) == LFS2_TYPE_CTZSTRUCT) { + err = lfs2_ctz_traverse(lfs2, NULL, &lfs2->rcache, + ctz.head, ctz.size, cb, data); + if (err) { + LFS2_TRACE("lfs2_fs_traverse -> %d", err); + return err; + } + } + } + } + + // iterate over any open files + for (lfs2_file_t *f = (lfs2_file_t*)lfs2->mlist; f; f = f->next) { + if (f->type != LFS2_TYPE_REG) { + continue; + } + + if ((f->flags & LFS2_F_DIRTY) && !(f->flags & LFS2_F_INLINE)) { + int err = lfs2_ctz_traverse(lfs2, &f->cache, &lfs2->rcache, + f->ctz.head, f->ctz.size, cb, data); + if (err) { + LFS2_TRACE("lfs2_fs_traverse -> %d", err); + return err; + } + } + + if ((f->flags & LFS2_F_WRITING) && !(f->flags & LFS2_F_INLINE)) { + int err = lfs2_ctz_traverse(lfs2, &f->cache, &lfs2->rcache, + f->block, f->pos, cb, data); + if (err) { + LFS2_TRACE("lfs2_fs_traverse -> %d", err); + return err; + } + } + } + + LFS2_TRACE("lfs2_fs_traverse -> %d", 0); + return 0; +} + +static int lfs2_fs_pred(lfs2_t *lfs2, + const lfs2_block_t pair[2], lfs2_mdir_t *pdir) { + // iterate over all directory directory entries + pdir->tail[0] = 0; + pdir->tail[1] = 1; + while (!lfs2_pair_isnull(pdir->tail)) { + if (lfs2_pair_cmp(pdir->tail, pair) == 0) { + return 0; + } + + int err = lfs2_dir_fetch(lfs2, pdir, pdir->tail); + if (err) { + return err; + } + } + + return LFS2_ERR_NOENT; +} + +struct lfs2_fs_parent_match { + lfs2_t *lfs2; + const lfs2_block_t pair[2]; +}; + +static int lfs2_fs_parent_match(void *data, + lfs2_tag_t tag, const void *buffer) { + struct lfs2_fs_parent_match *find = data; + lfs2_t *lfs2 = find->lfs2; + const struct lfs2_diskoff *disk = buffer; + (void)tag; + + lfs2_block_t child[2]; + int err = lfs2_bd_read(lfs2, + &lfs2->pcache, &lfs2->rcache, lfs2->cfg->block_size, + disk->block, disk->off, &child, sizeof(child)); + if (err) { + return err; + } + + lfs2_pair_fromle32(child); + return (lfs2_pair_cmp(child, find->pair) == 0) ? LFS2_CMP_EQ : LFS2_CMP_LT; +} + +static lfs2_stag_t lfs2_fs_parent(lfs2_t *lfs2, const lfs2_block_t pair[2], + lfs2_mdir_t *parent) { + // use fetchmatch with callback to find pairs + parent->tail[0] = 0; + parent->tail[1] = 1; + while (!lfs2_pair_isnull(parent->tail)) { + lfs2_stag_t tag = lfs2_dir_fetchmatch(lfs2, parent, parent->tail, + LFS2_MKTAG(0x7ff, 0, 0x3ff), + LFS2_MKTAG(LFS2_TYPE_DIRSTRUCT, 0, 8), + NULL, + lfs2_fs_parent_match, &(struct lfs2_fs_parent_match){ + lfs2, {pair[0], pair[1]}}); + if (tag && tag != LFS2_ERR_NOENT) { + return tag; + } + } + + return LFS2_ERR_NOENT; +} + +static int lfs2_fs_relocate(lfs2_t *lfs2, + const lfs2_block_t oldpair[2], lfs2_block_t newpair[2]) { + // update internal root + if (lfs2_pair_cmp(oldpair, lfs2->root) == 0) { + LFS2_DEBUG("Relocating root %"PRIx32" %"PRIx32, + newpair[0], newpair[1]); + lfs2->root[0] = newpair[0]; + lfs2->root[1] = newpair[1]; + } + + // update internally tracked dirs + for (struct lfs2_mlist *d = lfs2->mlist; d; d = d->next) { + if (lfs2_pair_cmp(oldpair, d->m.pair) == 0) { + d->m.pair[0] = newpair[0]; + d->m.pair[1] = newpair[1]; + } + } + + // find parent + lfs2_mdir_t parent; + lfs2_stag_t tag = lfs2_fs_parent(lfs2, oldpair, &parent); + if (tag < 0 && tag != LFS2_ERR_NOENT) { + return tag; + } + + if (tag != LFS2_ERR_NOENT) { + // update disk, this creates a desync + lfs2_fs_preporphans(lfs2, +1); + + lfs2_pair_tole32(newpair); + int err = lfs2_dir_commit(lfs2, &parent, LFS2_MKATTRS({tag, newpair})); + lfs2_pair_fromle32(newpair); + if (err) { + return err; + } + + // next step, clean up orphans + lfs2_fs_preporphans(lfs2, -1); + } + + // find pred + int err = lfs2_fs_pred(lfs2, oldpair, &parent); + if (err && err != LFS2_ERR_NOENT) { + return err; + } + + // if we can't find dir, it must be new + if (err != LFS2_ERR_NOENT) { + // replace bad pair, either we clean up desync, or no desync occured + lfs2_pair_tole32(newpair); + err = lfs2_dir_commit(lfs2, &parent, LFS2_MKATTRS( + {LFS2_MKTAG(LFS2_TYPE_TAIL + parent.split, 0x3ff, 8), newpair})); + lfs2_pair_fromle32(newpair); + if (err) { + return err; + } + } + + return 0; +} + +static void lfs2_fs_preporphans(lfs2_t *lfs2, int8_t orphans) { + lfs2->gpending.tag += orphans; + lfs2_gstate_xororphans(&lfs2->gdelta, &lfs2->gpending, + lfs2_gstate_hasorphans(&lfs2->gpending)); + lfs2_gstate_xororphans(&lfs2->gpending, &lfs2->gpending, + lfs2_gstate_hasorphans(&lfs2->gpending)); +} + +static void lfs2_fs_prepmove(lfs2_t *lfs2, + uint16_t id, const lfs2_block_t pair[2]) { + lfs2_gstate_xormove(&lfs2->gdelta, &lfs2->gpending, id, pair); + lfs2_gstate_xormove(&lfs2->gpending, &lfs2->gpending, id, pair); +} + + +static int lfs2_fs_demove(lfs2_t *lfs2) { + if (!lfs2_gstate_hasmove(&lfs2->gstate)) { + return 0; + } + + // Fix bad moves + LFS2_DEBUG("Fixing move %"PRIx32" %"PRIx32" %"PRIx16, + lfs2->gstate.pair[0], + lfs2->gstate.pair[1], + lfs2_tag_id(lfs2->gstate.tag)); + + // fetch and delete the moved entry + lfs2_mdir_t movedir; + int err = lfs2_dir_fetch(lfs2, &movedir, lfs2->gstate.pair); + if (err) { + return err; + } + + // rely on cancel logic inside commit + err = lfs2_dir_commit(lfs2, &movedir, NULL, 0); + if (err) { + return err; + } + + return 0; +} + +static int lfs2_fs_deorphan(lfs2_t *lfs2) { + if (!lfs2_gstate_hasorphans(&lfs2->gstate)) { + return 0; + } + + // Fix any orphans + lfs2_mdir_t pdir = {.split = true}; + lfs2_mdir_t dir = {.tail = {0, 1}}; + + // iterate over all directory directory entries + while (!lfs2_pair_isnull(dir.tail)) { + int err = lfs2_dir_fetch(lfs2, &dir, dir.tail); + if (err) { + return err; + } + + // check head blocks for orphans + if (!pdir.split) { + // check if we have a parent + lfs2_mdir_t parent; + lfs2_stag_t tag = lfs2_fs_parent(lfs2, pdir.tail, &parent); + if (tag < 0 && tag != LFS2_ERR_NOENT) { + return tag; + } + + if (tag == LFS2_ERR_NOENT) { + // we are an orphan + LFS2_DEBUG("Fixing orphan %"PRIx32" %"PRIx32, + pdir.tail[0], pdir.tail[1]); + + err = lfs2_dir_drop(lfs2, &pdir, &dir); + if (err) { + return err; + } + + break; + } + + lfs2_block_t pair[2]; + lfs2_stag_t res = lfs2_dir_get(lfs2, &parent, + LFS2_MKTAG(0x7ff, 0x3ff, 0), tag, pair); + if (res < 0) { + return res; + } + lfs2_pair_fromle32(pair); + + if (!lfs2_pair_sync(pair, pdir.tail)) { + // we have desynced + LFS2_DEBUG("Fixing half-orphan %"PRIx32" %"PRIx32, + pair[0], pair[1]); + + lfs2_pair_tole32(pair); + err = lfs2_dir_commit(lfs2, &pdir, LFS2_MKATTRS( + {LFS2_MKTAG(LFS2_TYPE_SOFTTAIL, 0x3ff, 8), pair})); + lfs2_pair_fromle32(pair); + if (err) { + return err; + } + + break; + } + } + + memcpy(&pdir, &dir, sizeof(pdir)); + } + + // mark orphans as fixed + lfs2_fs_preporphans(lfs2, -lfs2_gstate_getorphans(&lfs2->gstate)); + lfs2->gstate = lfs2->gpending; + return 0; +} + +static int lfs2_fs_forceconsistency(lfs2_t *lfs2) { + int err = lfs2_fs_demove(lfs2); + if (err) { + return err; + } + + err = lfs2_fs_deorphan(lfs2); + if (err) { + return err; + } + + return 0; +} + +static int lfs2_fs_size_count(void *p, lfs2_block_t block) { + (void)block; + lfs2_size_t *size = p; + *size += 1; + return 0; +} + +lfs2_ssize_t lfs2_fs_size(lfs2_t *lfs2) { + LFS2_TRACE("lfs2_fs_size(%p)", (void*)lfs2); + lfs2_size_t size = 0; + int err = lfs2_fs_traverse(lfs2, lfs2_fs_size_count, &size); + if (err) { + LFS2_TRACE("lfs2_fs_size -> %"PRId32, err); + return err; + } + + LFS2_TRACE("lfs2_fs_size -> %"PRId32, err); + return size; +} + +#ifdef LFS2_MIGRATE +////// Migration from littelfs v1 below this ////// + +/// Version info /// + +// Software library version +// Major (top-nibble), incremented on backwards incompatible changes +// Minor (bottom-nibble), incremented on feature additions +#define LFS21_VERSION 0x00010007 +#define LFS21_VERSION_MAJOR (0xffff & (LFS21_VERSION >> 16)) +#define LFS21_VERSION_MINOR (0xffff & (LFS21_VERSION >> 0)) + +// Version of On-disk data structures +// Major (top-nibble), incremented on backwards incompatible changes +// Minor (bottom-nibble), incremented on feature additions +#define LFS21_DISK_VERSION 0x00010001 +#define LFS21_DISK_VERSION_MAJOR (0xffff & (LFS21_DISK_VERSION >> 16)) +#define LFS21_DISK_VERSION_MINOR (0xffff & (LFS21_DISK_VERSION >> 0)) + + +/// v1 Definitions /// + +// File types +enum lfs21_type { + LFS21_TYPE_REG = 0x11, + LFS21_TYPE_DIR = 0x22, + LFS21_TYPE_SUPERBLOCK = 0x2e, +}; + +typedef struct lfs21 { + lfs2_block_t root[2]; +} lfs21_t; + +typedef struct lfs21_entry { + lfs2_off_t off; + + struct lfs21_disk_entry { + uint8_t type; + uint8_t elen; + uint8_t alen; + uint8_t nlen; + union { + struct { + lfs2_block_t head; + lfs2_size_t size; + } file; + lfs2_block_t dir[2]; + } u; + } d; +} lfs21_entry_t; + +typedef struct lfs21_dir { + struct lfs21_dir *next; + lfs2_block_t pair[2]; + lfs2_off_t off; + + lfs2_block_t head[2]; + lfs2_off_t pos; + + struct lfs21_disk_dir { + uint32_t rev; + lfs2_size_t size; + lfs2_block_t tail[2]; + } d; +} lfs21_dir_t; + +typedef struct lfs21_superblock { + lfs2_off_t off; + + struct lfs21_disk_superblock { + uint8_t type; + uint8_t elen; + uint8_t alen; + uint8_t nlen; + lfs2_block_t root[2]; + uint32_t block_size; + uint32_t block_count; + uint32_t version; + char magic[8]; + } d; +} lfs21_superblock_t; + + +/// Low-level wrappers v1->v2 /// +static void lfs21_crc(uint32_t *crc, const void *buffer, size_t size) { + *crc = lfs2_crc(*crc, buffer, size); +} + +static int lfs21_bd_read(lfs2_t *lfs2, lfs2_block_t block, + lfs2_off_t off, void *buffer, lfs2_size_t size) { + // if we ever do more than writes to alternating pairs, + // this may need to consider pcache + return lfs2_bd_read(lfs2, &lfs2->pcache, &lfs2->rcache, size, + block, off, buffer, size); +} + +static int lfs21_bd_crc(lfs2_t *lfs2, lfs2_block_t block, + lfs2_off_t off, lfs2_size_t size, uint32_t *crc) { + for (lfs2_off_t i = 0; i < size; i++) { + uint8_t c; + int err = lfs21_bd_read(lfs2, block, off+i, &c, 1); + if (err) { + return err; + } + + lfs21_crc(crc, &c, 1); + } + + return 0; +} + + +/// Endian swapping functions /// +static void lfs21_dir_fromle32(struct lfs21_disk_dir *d) { + d->rev = lfs2_fromle32(d->rev); + d->size = lfs2_fromle32(d->size); + d->tail[0] = lfs2_fromle32(d->tail[0]); + d->tail[1] = lfs2_fromle32(d->tail[1]); +} + +static void lfs21_dir_tole32(struct lfs21_disk_dir *d) { + d->rev = lfs2_tole32(d->rev); + d->size = lfs2_tole32(d->size); + d->tail[0] = lfs2_tole32(d->tail[0]); + d->tail[1] = lfs2_tole32(d->tail[1]); +} + +static void lfs21_entry_fromle32(struct lfs21_disk_entry *d) { + d->u.dir[0] = lfs2_fromle32(d->u.dir[0]); + d->u.dir[1] = lfs2_fromle32(d->u.dir[1]); +} + +static void lfs21_entry_tole32(struct lfs21_disk_entry *d) { + d->u.dir[0] = lfs2_tole32(d->u.dir[0]); + d->u.dir[1] = lfs2_tole32(d->u.dir[1]); +} + +static void lfs21_superblock_fromle32(struct lfs21_disk_superblock *d) { + d->root[0] = lfs2_fromle32(d->root[0]); + d->root[1] = lfs2_fromle32(d->root[1]); + d->block_size = lfs2_fromle32(d->block_size); + d->block_count = lfs2_fromle32(d->block_count); + d->version = lfs2_fromle32(d->version); +} + + +///// Metadata pair and directory operations /// +static inline lfs2_size_t lfs21_entry_size(const lfs21_entry_t *entry) { + return 4 + entry->d.elen + entry->d.alen + entry->d.nlen; +} + +static int lfs21_dir_fetch(lfs2_t *lfs2, + lfs21_dir_t *dir, const lfs2_block_t pair[2]) { + // copy out pair, otherwise may be aliasing dir + const lfs2_block_t tpair[2] = {pair[0], pair[1]}; + bool valid = false; + + // check both blocks for the most recent revision + for (int i = 0; i < 2; i++) { + struct lfs21_disk_dir test; + int err = lfs21_bd_read(lfs2, tpair[i], 0, &test, sizeof(test)); + lfs21_dir_fromle32(&test); + if (err) { + if (err == LFS2_ERR_CORRUPT) { + continue; + } + return err; + } + + if (valid && lfs2_scmp(test.rev, dir->d.rev) < 0) { + continue; + } + + if ((0x7fffffff & test.size) < sizeof(test)+4 || + (0x7fffffff & test.size) > lfs2->cfg->block_size) { + continue; + } + + uint32_t crc = LFS2_BLOCK_NULL; + lfs21_dir_tole32(&test); + lfs21_crc(&crc, &test, sizeof(test)); + lfs21_dir_fromle32(&test); + err = lfs21_bd_crc(lfs2, tpair[i], sizeof(test), + (0x7fffffff & test.size) - sizeof(test), &crc); + if (err) { + if (err == LFS2_ERR_CORRUPT) { + continue; + } + return err; + } + + if (crc != 0) { + continue; + } + + valid = true; + + // setup dir in case it's valid + dir->pair[0] = tpair[(i+0) % 2]; + dir->pair[1] = tpair[(i+1) % 2]; + dir->off = sizeof(dir->d); + dir->d = test; + } + + if (!valid) { + LFS2_ERROR("Corrupted dir pair at %" PRIx32 " %" PRIx32 , + tpair[0], tpair[1]); + return LFS2_ERR_CORRUPT; + } + + return 0; +} + +static int lfs21_dir_next(lfs2_t *lfs2, lfs21_dir_t *dir, lfs21_entry_t *entry) { + while (dir->off + sizeof(entry->d) > (0x7fffffff & dir->d.size)-4) { + if (!(0x80000000 & dir->d.size)) { + entry->off = dir->off; + return LFS2_ERR_NOENT; + } + + int err = lfs21_dir_fetch(lfs2, dir, dir->d.tail); + if (err) { + return err; + } + + dir->off = sizeof(dir->d); + dir->pos += sizeof(dir->d) + 4; + } + + int err = lfs21_bd_read(lfs2, dir->pair[0], dir->off, + &entry->d, sizeof(entry->d)); + lfs21_entry_fromle32(&entry->d); + if (err) { + return err; + } + + entry->off = dir->off; + dir->off += lfs21_entry_size(entry); + dir->pos += lfs21_entry_size(entry); + return 0; +} + +/// littlefs v1 specific operations /// +int lfs21_traverse(lfs2_t *lfs2, int (*cb)(void*, lfs2_block_t), void *data) { + if (lfs2_pair_isnull(lfs2->lfs21->root)) { + return 0; + } + + // iterate over metadata pairs + lfs21_dir_t dir; + lfs21_entry_t entry; + lfs2_block_t cwd[2] = {0, 1}; + + while (true) { + for (int i = 0; i < 2; i++) { + int err = cb(data, cwd[i]); + if (err) { + return err; + } + } + + int err = lfs21_dir_fetch(lfs2, &dir, cwd); + if (err) { + return err; + } + + // iterate over contents + while (dir.off + sizeof(entry.d) <= (0x7fffffff & dir.d.size)-4) { + err = lfs21_bd_read(lfs2, dir.pair[0], dir.off, + &entry.d, sizeof(entry.d)); + lfs21_entry_fromle32(&entry.d); + if (err) { + return err; + } + + dir.off += lfs21_entry_size(&entry); + if ((0x70 & entry.d.type) == (0x70 & LFS21_TYPE_REG)) { + err = lfs2_ctz_traverse(lfs2, NULL, &lfs2->rcache, + entry.d.u.file.head, entry.d.u.file.size, cb, data); + if (err) { + return err; + } + } + } + + // we also need to check if we contain a threaded v2 directory + lfs2_mdir_t dir2 = {.split=true, .tail={cwd[0], cwd[1]}}; + while (dir2.split) { + err = lfs2_dir_fetch(lfs2, &dir2, dir2.tail); + if (err) { + break; + } + + for (int i = 0; i < 2; i++) { + err = cb(data, dir2.pair[i]); + if (err) { + return err; + } + } + } + + cwd[0] = dir.d.tail[0]; + cwd[1] = dir.d.tail[1]; + + if (lfs2_pair_isnull(cwd)) { + break; + } + } + + return 0; +} + +static int lfs21_moved(lfs2_t *lfs2, const void *e) { + if (lfs2_pair_isnull(lfs2->lfs21->root)) { + return 0; + } + + // skip superblock + lfs21_dir_t cwd; + int err = lfs21_dir_fetch(lfs2, &cwd, (const lfs2_block_t[2]){0, 1}); + if (err) { + return err; + } + + // iterate over all directory directory entries + lfs21_entry_t entry; + while (!lfs2_pair_isnull(cwd.d.tail)) { + err = lfs21_dir_fetch(lfs2, &cwd, cwd.d.tail); + if (err) { + return err; + } + + while (true) { + err = lfs21_dir_next(lfs2, &cwd, &entry); + if (err && err != LFS2_ERR_NOENT) { + return err; + } + + if (err == LFS2_ERR_NOENT) { + break; + } + + if (!(0x80 & entry.d.type) && + memcmp(&entry.d.u, e, sizeof(entry.d.u)) == 0) { + return true; + } + } + } + + return false; +} + +/// Filesystem operations /// +static int lfs21_mount(lfs2_t *lfs2, struct lfs21 *lfs21, + const struct lfs2_config *cfg) { + int err = 0; + { + err = lfs2_init(lfs2, cfg); + if (err) { + return err; + } + + lfs2->lfs21 = lfs21; + lfs2->lfs21->root[0] = LFS2_BLOCK_NULL; + lfs2->lfs21->root[1] = LFS2_BLOCK_NULL; + + // setup free lookahead + lfs2->free.off = 0; + lfs2->free.size = 0; + lfs2->free.i = 0; + lfs2_alloc_ack(lfs2); + + // load superblock + lfs21_dir_t dir; + lfs21_superblock_t superblock; + err = lfs21_dir_fetch(lfs2, &dir, (const lfs2_block_t[2]){0, 1}); + if (err && err != LFS2_ERR_CORRUPT) { + goto cleanup; + } + + if (!err) { + err = lfs21_bd_read(lfs2, dir.pair[0], sizeof(dir.d), + &superblock.d, sizeof(superblock.d)); + lfs21_superblock_fromle32(&superblock.d); + if (err) { + goto cleanup; + } + + lfs2->lfs21->root[0] = superblock.d.root[0]; + lfs2->lfs21->root[1] = superblock.d.root[1]; + } + + if (err || memcmp(superblock.d.magic, "littlefs", 8) != 0) { + LFS2_ERROR("Invalid superblock at %d %d", 0, 1); + err = LFS2_ERR_CORRUPT; + goto cleanup; + } + + uint16_t major_version = (0xffff & (superblock.d.version >> 16)); + uint16_t minor_version = (0xffff & (superblock.d.version >> 0)); + if ((major_version != LFS21_DISK_VERSION_MAJOR || + minor_version > LFS21_DISK_VERSION_MINOR)) { + LFS2_ERROR("Invalid version %d.%d", major_version, minor_version); + err = LFS2_ERR_INVAL; + goto cleanup; + } + + return 0; + } + +cleanup: + lfs2_deinit(lfs2); + return err; +} + +static int lfs21_unmount(lfs2_t *lfs2) { + return lfs2_deinit(lfs2); +} + +/// v1 migration /// +int lfs2_migrate(lfs2_t *lfs2, const struct lfs2_config *cfg) { + LFS2_TRACE("lfs2_migrate(%p, %p {.context=%p, " + ".read=%p, .prog=%p, .erase=%p, .sync=%p, " + ".read_size=%"PRIu32", .prog_size=%"PRIu32", " + ".block_size=%"PRIu32", .block_count=%"PRIu32", " + ".block_cycles=%"PRIu32", .cache_size=%"PRIu32", " + ".lookahead_size=%"PRIu32", .read_buffer=%p, " + ".prog_buffer=%p, .lookahead_buffer=%p, " + ".name_max=%"PRIu32", .file_max=%"PRIu32", " + ".attr_max=%"PRIu32"})", + (void*)lfs2, (void*)cfg, cfg->context, + (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, + (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, + cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, + cfg->block_cycles, cfg->cache_size, cfg->lookahead_size, + cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, + cfg->name_max, cfg->file_max, cfg->attr_max); + struct lfs21 lfs21; + int err = lfs21_mount(lfs2, &lfs21, cfg); + if (err) { + LFS2_TRACE("lfs2_migrate -> %d", err); + return err; + } + + { + // iterate through each directory, copying over entries + // into new directory + lfs21_dir_t dir1; + lfs2_mdir_t dir2; + dir1.d.tail[0] = lfs2->lfs21->root[0]; + dir1.d.tail[1] = lfs2->lfs21->root[1]; + while (!lfs2_pair_isnull(dir1.d.tail)) { + // iterate old dir + err = lfs21_dir_fetch(lfs2, &dir1, dir1.d.tail); + if (err) { + goto cleanup; + } + + // create new dir and bind as temporary pretend root + err = lfs2_dir_alloc(lfs2, &dir2); + if (err) { + goto cleanup; + } + + dir2.rev = dir1.d.rev; + dir1.head[0] = dir1.pair[0]; + dir1.head[1] = dir1.pair[1]; + lfs2->root[0] = dir2.pair[0]; + lfs2->root[1] = dir2.pair[1]; + + err = lfs2_dir_commit(lfs2, &dir2, NULL, 0); + if (err) { + goto cleanup; + } + + while (true) { + lfs21_entry_t entry1; + err = lfs21_dir_next(lfs2, &dir1, &entry1); + if (err && err != LFS2_ERR_NOENT) { + goto cleanup; + } + + if (err == LFS2_ERR_NOENT) { + break; + } + + // check that entry has not been moved + if (entry1.d.type & 0x80) { + int moved = lfs21_moved(lfs2, &entry1.d.u); + if (moved < 0) { + err = moved; + goto cleanup; + } + + if (moved) { + continue; + } + + entry1.d.type &= ~0x80; + } + + // also fetch name + char name[LFS2_NAME_MAX+1]; + memset(name, 0, sizeof(name)); + err = lfs21_bd_read(lfs2, dir1.pair[0], + entry1.off + 4+entry1.d.elen+entry1.d.alen, + name, entry1.d.nlen); + if (err) { + goto cleanup; + } + + bool isdir = (entry1.d.type == LFS21_TYPE_DIR); + + // create entry in new dir + err = lfs2_dir_fetch(lfs2, &dir2, lfs2->root); + if (err) { + goto cleanup; + } + + uint16_t id; + err = lfs2_dir_find(lfs2, &dir2, &(const char*){name}, &id); + if (!(err == LFS2_ERR_NOENT && id != 0x3ff)) { + err = (err < 0) ? err : LFS2_ERR_EXIST; + goto cleanup; + } + + lfs21_entry_tole32(&entry1.d); + err = lfs2_dir_commit(lfs2, &dir2, LFS2_MKATTRS( + {LFS2_MKTAG(LFS2_TYPE_CREATE, id, 0), NULL}, + {LFS2_MKTAG( + isdir ? LFS2_TYPE_DIR : LFS2_TYPE_REG, + id, entry1.d.nlen), name}, + {LFS2_MKTAG( + isdir ? LFS2_TYPE_DIRSTRUCT : LFS2_TYPE_CTZSTRUCT, + id, sizeof(&entry1.d.u)), &entry1.d.u})); + lfs21_entry_fromle32(&entry1.d); + if (err) { + goto cleanup; + } + } + + if (!lfs2_pair_isnull(dir1.d.tail)) { + // find last block and update tail to thread into fs + err = lfs2_dir_fetch(lfs2, &dir2, lfs2->root); + if (err) { + goto cleanup; + } + + while (dir2.split) { + err = lfs2_dir_fetch(lfs2, &dir2, dir2.tail); + if (err) { + goto cleanup; + } + } + + lfs2_pair_tole32(dir2.pair); + err = lfs2_dir_commit(lfs2, &dir2, LFS2_MKATTRS( + {LFS2_MKTAG(LFS2_TYPE_SOFTTAIL, 0x3ff, 0), + dir1.d.tail})); + lfs2_pair_fromle32(dir2.pair); + if (err) { + goto cleanup; + } + } + + // Copy over first block to thread into fs. Unfortunately + // if this fails there is not much we can do. + LFS2_DEBUG("Migrating %"PRIx32" %"PRIx32" -> %"PRIx32" %"PRIx32, + lfs2->root[0], lfs2->root[1], dir1.head[0], dir1.head[1]); + + err = lfs2_bd_erase(lfs2, dir1.head[1]); + if (err) { + goto cleanup; + } + + err = lfs2_dir_fetch(lfs2, &dir2, lfs2->root); + if (err) { + goto cleanup; + } + + for (lfs2_off_t i = 0; i < dir2.off; i++) { + uint8_t dat; + err = lfs2_bd_read(lfs2, + NULL, &lfs2->rcache, dir2.off, + dir2.pair[0], i, &dat, 1); + if (err) { + goto cleanup; + } + + err = lfs2_bd_prog(lfs2, + &lfs2->pcache, &lfs2->rcache, true, + dir1.head[1], i, &dat, 1); + if (err) { + goto cleanup; + } + } + + err = lfs2_bd_flush(lfs2, &lfs2->pcache, &lfs2->rcache, true); + if (err) { + goto cleanup; + } + } + + // Create new superblock. This marks a successful migration! + err = lfs21_dir_fetch(lfs2, &dir1, (const lfs2_block_t[2]){0, 1}); + if (err) { + goto cleanup; + } + + dir2.pair[0] = dir1.pair[0]; + dir2.pair[1] = dir1.pair[1]; + dir2.rev = dir1.d.rev; + dir2.off = sizeof(dir2.rev); + dir2.etag = LFS2_BLOCK_NULL; + dir2.count = 0; + dir2.tail[0] = lfs2->lfs21->root[0]; + dir2.tail[1] = lfs2->lfs21->root[1]; + dir2.erased = false; + dir2.split = true; + + lfs2_superblock_t superblock = { + .version = LFS2_DISK_VERSION, + .block_size = lfs2->cfg->block_size, + .block_count = lfs2->cfg->block_count, + .name_max = lfs2->name_max, + .file_max = lfs2->file_max, + .attr_max = lfs2->attr_max, + }; + + lfs2_superblock_tole32(&superblock); + err = lfs2_dir_commit(lfs2, &dir2, LFS2_MKATTRS( + {LFS2_MKTAG(LFS2_TYPE_CREATE, 0, 0), NULL}, + {LFS2_MKTAG(LFS2_TYPE_SUPERBLOCK, 0, 8), "littlefs"}, + {LFS2_MKTAG(LFS2_TYPE_INLINESTRUCT, 0, sizeof(superblock)), + &superblock})); + if (err) { + goto cleanup; + } + + // sanity check that fetch works + err = lfs2_dir_fetch(lfs2, &dir2, (const lfs2_block_t[2]){0, 1}); + if (err) { + goto cleanup; + } + + // force compaction to prevent accidentally mounting v1 + dir2.erased = false; + err = lfs2_dir_commit(lfs2, &dir2, NULL, 0); + if (err) { + goto cleanup; + } + } + +cleanup: + lfs21_unmount(lfs2); + LFS2_TRACE("lfs2_migrate -> %d", err); + return err; +} + +#endif diff --git a/lib/littlefs/lfs2.h b/lib/littlefs/lfs2.h new file mode 100644 index 0000000000..fdbe007cc9 --- /dev/null +++ b/lib/littlefs/lfs2.h @@ -0,0 +1,651 @@ +/* + * The little filesystem + * + * Copyright (c) 2017, Arm Limited. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef LFS2_H +#define LFS2_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/// Version info /// + +// Software library version +// Major (top-nibble), incremented on backwards incompatible changes +// Minor (bottom-nibble), incremented on feature additions +#define LFS2_VERSION 0x00020001 +#define LFS2_VERSION_MAJOR (0xffff & (LFS2_VERSION >> 16)) +#define LFS2_VERSION_MINOR (0xffff & (LFS2_VERSION >> 0)) + +// Version of On-disk data structures +// Major (top-nibble), incremented on backwards incompatible changes +// Minor (bottom-nibble), incremented on feature additions +#define LFS2_DISK_VERSION 0x00020000 +#define LFS2_DISK_VERSION_MAJOR (0xffff & (LFS2_DISK_VERSION >> 16)) +#define LFS2_DISK_VERSION_MINOR (0xffff & (LFS2_DISK_VERSION >> 0)) + + +/// Definitions /// + +// Type definitions +typedef uint32_t lfs2_size_t; +typedef uint32_t lfs2_off_t; + +typedef int32_t lfs2_ssize_t; +typedef int32_t lfs2_soff_t; + +typedef uint32_t lfs2_block_t; + +// Maximum name size in bytes, may be redefined to reduce the size of the +// info struct. Limited to <= 1022. Stored in superblock and must be +// respected by other littlefs drivers. +#ifndef LFS2_NAME_MAX +#define LFS2_NAME_MAX 255 +#endif + +// Maximum size of a file in bytes, may be redefined to limit to support other +// drivers. Limited on disk to <= 4294967296. However, above 2147483647 the +// functions lfs2_file_seek, lfs2_file_size, and lfs2_file_tell will return +// incorrect values due to using signed integers. Stored in superblock and +// must be respected by other littlefs drivers. +#ifndef LFS2_FILE_MAX +#define LFS2_FILE_MAX 2147483647 +#endif + +// Maximum size of custom attributes in bytes, may be redefined, but there is +// no real benefit to using a smaller LFS2_ATTR_MAX. Limited to <= 1022. +#ifndef LFS2_ATTR_MAX +#define LFS2_ATTR_MAX 1022 +#endif + +// Possible error codes, these are negative to allow +// valid positive return values +enum lfs2_error { + LFS2_ERR_OK = 0, // No error + LFS2_ERR_IO = -5, // Error during device operation + LFS2_ERR_CORRUPT = -84, // Corrupted + LFS2_ERR_NOENT = -2, // No directory entry + LFS2_ERR_EXIST = -17, // Entry already exists + LFS2_ERR_NOTDIR = -20, // Entry is not a dir + LFS2_ERR_ISDIR = -21, // Entry is a dir + LFS2_ERR_NOTEMPTY = -39, // Dir is not empty + LFS2_ERR_BADF = -9, // Bad file number + LFS2_ERR_FBIG = -27, // File too large + LFS2_ERR_INVAL = -22, // Invalid parameter + LFS2_ERR_NOSPC = -28, // No space left on device + LFS2_ERR_NOMEM = -12, // No more memory available + LFS2_ERR_NOATTR = -61, // No data/attr available + LFS2_ERR_NAMETOOLONG = -36, // File name too long +}; + +// File types +enum lfs2_type { + // file types + LFS2_TYPE_REG = 0x001, + LFS2_TYPE_DIR = 0x002, + + // internally used types + LFS2_TYPE_SPLICE = 0x400, + LFS2_TYPE_NAME = 0x000, + LFS2_TYPE_STRUCT = 0x200, + LFS2_TYPE_USERATTR = 0x300, + LFS2_TYPE_FROM = 0x100, + LFS2_TYPE_TAIL = 0x600, + LFS2_TYPE_GLOBALS = 0x700, + LFS2_TYPE_CRC = 0x500, + + // internally used type specializations + LFS2_TYPE_CREATE = 0x401, + LFS2_TYPE_DELETE = 0x4ff, + LFS2_TYPE_SUPERBLOCK = 0x0ff, + LFS2_TYPE_DIRSTRUCT = 0x200, + LFS2_TYPE_CTZSTRUCT = 0x202, + LFS2_TYPE_INLINESTRUCT = 0x201, + LFS2_TYPE_SOFTTAIL = 0x600, + LFS2_TYPE_HARDTAIL = 0x601, + LFS2_TYPE_MOVESTATE = 0x7ff, + + // internal chip sources + LFS2_FROM_NOOP = 0x000, + LFS2_FROM_MOVE = 0x101, + LFS2_FROM_USERATTRS = 0x102, +}; + +// File open flags +enum lfs2_open_flags { + // open flags + LFS2_O_RDONLY = 1, // Open a file as read only + LFS2_O_WRONLY = 2, // Open a file as write only + LFS2_O_RDWR = 3, // Open a file as read and write + LFS2_O_CREAT = 0x0100, // Create a file if it does not exist + LFS2_O_EXCL = 0x0200, // Fail if a file already exists + LFS2_O_TRUNC = 0x0400, // Truncate the existing file to zero size + LFS2_O_APPEND = 0x0800, // Move to end of file on every write + + // internally used flags + LFS2_F_DIRTY = 0x010000, // File does not match storage + LFS2_F_WRITING = 0x020000, // File has been written since last flush + LFS2_F_READING = 0x040000, // File has been read since last flush + LFS2_F_ERRED = 0x080000, // An error occured during write + LFS2_F_INLINE = 0x100000, // Currently inlined in directory entry + LFS2_F_OPENED = 0x200000, // File has been opened +}; + +// File seek flags +enum lfs2_whence_flags { + LFS2_SEEK_SET = 0, // Seek relative to an absolute position + LFS2_SEEK_CUR = 1, // Seek relative to the current file position + LFS2_SEEK_END = 2, // Seek relative to the end of the file +}; + + +// Configuration provided during initialization of the littlefs +struct lfs2_config { + // Opaque user provided context that can be used to pass + // information to the block device operations + void *context; + + // Read a region in a block. Negative error codes are propogated + // to the user. + int (*read)(const struct lfs2_config *c, lfs2_block_t block, + lfs2_off_t off, void *buffer, lfs2_size_t size); + + // Program a region in a block. The block must have previously + // been erased. Negative error codes are propogated to the user. + // May return LFS2_ERR_CORRUPT if the block should be considered bad. + int (*prog)(const struct lfs2_config *c, lfs2_block_t block, + lfs2_off_t off, const void *buffer, lfs2_size_t size); + + // Erase a block. A block must be erased before being programmed. + // The state of an erased block is undefined. Negative error codes + // are propogated to the user. + // May return LFS2_ERR_CORRUPT if the block should be considered bad. + int (*erase)(const struct lfs2_config *c, lfs2_block_t block); + + // Sync the state of the underlying block device. Negative error codes + // are propogated to the user. + int (*sync)(const struct lfs2_config *c); + + // Minimum size of a block read. All read operations will be a + // multiple of this value. + lfs2_size_t read_size; + + // Minimum size of a block program. All program operations will be a + // multiple of this value. + lfs2_size_t prog_size; + + // Size of an erasable block. This does not impact ram consumption and + // may be larger than the physical erase size. However, non-inlined files + // take up at minimum one block. Must be a multiple of the read + // and program sizes. + lfs2_size_t block_size; + + // Number of erasable blocks on the device. + lfs2_size_t block_count; + + // Number of erase cycles before littlefs evicts metadata logs and moves + // the metadata to another block. Suggested values are in the + // range 100-1000, with large values having better performance at the cost + // of less consistent wear distribution. + // + // Set to -1 to disable block-level wear-leveling. + int32_t block_cycles; + + // Size of block caches. Each cache buffers a portion of a block in RAM. + // The littlefs needs a read cache, a program cache, and one additional + // cache per file. Larger caches can improve performance by storing more + // data and reducing the number of disk accesses. Must be a multiple of + // the read and program sizes, and a factor of the block size. + lfs2_size_t cache_size; + + // Size of the lookahead buffer in bytes. A larger lookahead buffer + // increases the number of blocks found during an allocation pass. The + // lookahead buffer is stored as a compact bitmap, so each byte of RAM + // can track 8 blocks. Must be a multiple of 8. + lfs2_size_t lookahead_size; + + // Optional statically allocated read buffer. Must be cache_size. + // By default lfs2_malloc is used to allocate this buffer. + void *read_buffer; + + // Optional statically allocated program buffer. Must be cache_size. + // By default lfs2_malloc is used to allocate this buffer. + void *prog_buffer; + + // Optional statically allocated lookahead buffer. Must be lookahead_size + // and aligned to a 32-bit boundary. By default lfs2_malloc is used to + // allocate this buffer. + void *lookahead_buffer; + + // Optional upper limit on length of file names in bytes. No downside for + // larger names except the size of the info struct which is controlled by + // the LFS2_NAME_MAX define. Defaults to LFS2_NAME_MAX when zero. Stored in + // superblock and must be respected by other littlefs drivers. + lfs2_size_t name_max; + + // Optional upper limit on files in bytes. No downside for larger files + // but must be <= LFS2_FILE_MAX. Defaults to LFS2_FILE_MAX when zero. Stored + // in superblock and must be respected by other littlefs drivers. + lfs2_size_t file_max; + + // Optional upper limit on custom attributes in bytes. No downside for + // larger attributes size but must be <= LFS2_ATTR_MAX. Defaults to + // LFS2_ATTR_MAX when zero. + lfs2_size_t attr_max; +}; + +// File info structure +struct lfs2_info { + // Type of the file, either LFS2_TYPE_REG or LFS2_TYPE_DIR + uint8_t type; + + // Size of the file, only valid for REG files. Limited to 32-bits. + lfs2_size_t size; + + // Name of the file stored as a null-terminated string. Limited to + // LFS2_NAME_MAX+1, which can be changed by redefining LFS2_NAME_MAX to + // reduce RAM. LFS2_NAME_MAX is stored in superblock and must be + // respected by other littlefs drivers. + char name[LFS2_NAME_MAX+1]; +}; + +// Custom attribute structure, used to describe custom attributes +// committed atomically during file writes. +struct lfs2_attr { + // 8-bit type of attribute, provided by user and used to + // identify the attribute + uint8_t type; + + // Pointer to buffer containing the attribute + void *buffer; + + // Size of attribute in bytes, limited to LFS2_ATTR_MAX + lfs2_size_t size; +}; + +// Optional configuration provided during lfs2_file_opencfg +struct lfs2_file_config { + // Optional statically allocated file buffer. Must be cache_size. + // By default lfs2_malloc is used to allocate this buffer. + void *buffer; + + // Optional list of custom attributes related to the file. If the file + // is opened with read access, these attributes will be read from disk + // during the open call. If the file is opened with write access, the + // attributes will be written to disk every file sync or close. This + // write occurs atomically with update to the file's contents. + // + // Custom attributes are uniquely identified by an 8-bit type and limited + // to LFS2_ATTR_MAX bytes. When read, if the stored attribute is smaller + // than the buffer, it will be padded with zeros. If the stored attribute + // is larger, then it will be silently truncated. If the attribute is not + // found, it will be created implicitly. + struct lfs2_attr *attrs; + + // Number of custom attributes in the list + lfs2_size_t attr_count; +}; + + +/// internal littlefs data structures /// +typedef struct lfs2_cache { + lfs2_block_t block; + lfs2_off_t off; + lfs2_size_t size; + uint8_t *buffer; +} lfs2_cache_t; + +typedef struct lfs2_mdir { + lfs2_block_t pair[2]; + uint32_t rev; + lfs2_off_t off; + uint32_t etag; + uint16_t count; + bool erased; + bool split; + lfs2_block_t tail[2]; +} lfs2_mdir_t; + +// littlefs directory type +typedef struct lfs2_dir { + struct lfs2_dir *next; + uint16_t id; + uint8_t type; + lfs2_mdir_t m; + + lfs2_off_t pos; + lfs2_block_t head[2]; +} lfs2_dir_t; + +// littlefs file type +typedef struct lfs2_file { + struct lfs2_file *next; + uint16_t id; + uint8_t type; + lfs2_mdir_t m; + + struct lfs2_ctz { + lfs2_block_t head; + lfs2_size_t size; + } ctz; + + uint32_t flags; + lfs2_off_t pos; + lfs2_block_t block; + lfs2_off_t off; + lfs2_cache_t cache; + + const struct lfs2_file_config *cfg; +} lfs2_file_t; + +typedef struct lfs2_superblock { + uint32_t version; + lfs2_size_t block_size; + lfs2_size_t block_count; + lfs2_size_t name_max; + lfs2_size_t file_max; + lfs2_size_t attr_max; +} lfs2_superblock_t; + +// The littlefs filesystem type +typedef struct lfs2 { + lfs2_cache_t rcache; + lfs2_cache_t pcache; + + lfs2_block_t root[2]; + struct lfs2_mlist { + struct lfs2_mlist *next; + uint16_t id; + uint8_t type; + lfs2_mdir_t m; + } *mlist; + uint32_t seed; + + struct lfs2_gstate { + uint32_t tag; + lfs2_block_t pair[2]; + } gstate, gpending, gdelta; + + struct lfs2_free { + lfs2_block_t off; + lfs2_block_t size; + lfs2_block_t i; + lfs2_block_t ack; + uint32_t *buffer; + } free; + + const struct lfs2_config *cfg; + lfs2_size_t name_max; + lfs2_size_t file_max; + lfs2_size_t attr_max; + +#ifdef LFS2_MIGRATE + struct lfs21 *lfs21; +#endif +} lfs2_t; + + +/// Filesystem functions /// + +// Format a block device with the littlefs +// +// Requires a littlefs object and config struct. This clobbers the littlefs +// object, and does not leave the filesystem mounted. The config struct must +// be zeroed for defaults and backwards compatibility. +// +// Returns a negative error code on failure. +int lfs2_format(lfs2_t *lfs2, const struct lfs2_config *config); + +// Mounts a littlefs +// +// Requires a littlefs object and config struct. Multiple filesystems +// may be mounted simultaneously with multiple littlefs objects. Both +// lfs2 and config must be allocated while mounted. The config struct must +// be zeroed for defaults and backwards compatibility. +// +// Returns a negative error code on failure. +int lfs2_mount(lfs2_t *lfs2, const struct lfs2_config *config); + +// Unmounts a littlefs +// +// Does nothing besides releasing any allocated resources. +// Returns a negative error code on failure. +int lfs2_unmount(lfs2_t *lfs2); + +/// General operations /// + +// Removes a file or directory +// +// If removing a directory, the directory must be empty. +// Returns a negative error code on failure. +int lfs2_remove(lfs2_t *lfs2, const char *path); + +// Rename or move a file or directory +// +// If the destination exists, it must match the source in type. +// If the destination is a directory, the directory must be empty. +// +// Returns a negative error code on failure. +int lfs2_rename(lfs2_t *lfs2, const char *oldpath, const char *newpath); + +// Find info about a file or directory +// +// Fills out the info structure, based on the specified file or directory. +// Returns a negative error code on failure. +int lfs2_stat(lfs2_t *lfs2, const char *path, struct lfs2_info *info); + +// Get a custom attribute +// +// Custom attributes are uniquely identified by an 8-bit type and limited +// to LFS2_ATTR_MAX bytes. When read, if the stored attribute is smaller than +// the buffer, it will be padded with zeros. If the stored attribute is larger, +// then it will be silently truncated. If no attribute is found, the error +// LFS2_ERR_NOATTR is returned and the buffer is filled with zeros. +// +// Returns the size of the attribute, or a negative error code on failure. +// Note, the returned size is the size of the attribute on disk, irrespective +// of the size of the buffer. This can be used to dynamically allocate a buffer +// or check for existance. +lfs2_ssize_t lfs2_getattr(lfs2_t *lfs2, const char *path, + uint8_t type, void *buffer, lfs2_size_t size); + +// Set custom attributes +// +// Custom attributes are uniquely identified by an 8-bit type and limited +// to LFS2_ATTR_MAX bytes. If an attribute is not found, it will be +// implicitly created. +// +// Returns a negative error code on failure. +int lfs2_setattr(lfs2_t *lfs2, const char *path, + uint8_t type, const void *buffer, lfs2_size_t size); + +// Removes a custom attribute +// +// If an attribute is not found, nothing happens. +// +// Returns a negative error code on failure. +int lfs2_removeattr(lfs2_t *lfs2, const char *path, uint8_t type); + + +/// File operations /// + +// Open a file +// +// The mode that the file is opened in is determined by the flags, which +// are values from the enum lfs2_open_flags that are bitwise-ored together. +// +// Returns a negative error code on failure. +int lfs2_file_open(lfs2_t *lfs2, lfs2_file_t *file, + const char *path, int flags); + +// Open a file with extra configuration +// +// The mode that the file is opened in is determined by the flags, which +// are values from the enum lfs2_open_flags that are bitwise-ored together. +// +// The config struct provides additional config options per file as described +// above. The config struct must be allocated while the file is open, and the +// config struct must be zeroed for defaults and backwards compatibility. +// +// Returns a negative error code on failure. +int lfs2_file_opencfg(lfs2_t *lfs2, lfs2_file_t *file, + const char *path, int flags, + const struct lfs2_file_config *config); + +// Close a file +// +// Any pending writes are written out to storage as though +// sync had been called and releases any allocated resources. +// +// Returns a negative error code on failure. +int lfs2_file_close(lfs2_t *lfs2, lfs2_file_t *file); + +// Synchronize a file on storage +// +// Any pending writes are written out to storage. +// Returns a negative error code on failure. +int lfs2_file_sync(lfs2_t *lfs2, lfs2_file_t *file); + +// Read data from file +// +// Takes a buffer and size indicating where to store the read data. +// Returns the number of bytes read, or a negative error code on failure. +lfs2_ssize_t lfs2_file_read(lfs2_t *lfs2, lfs2_file_t *file, + void *buffer, lfs2_size_t size); + +// Write data to file +// +// Takes a buffer and size indicating the data to write. The file will not +// actually be updated on the storage until either sync or close is called. +// +// Returns the number of bytes written, or a negative error code on failure. +lfs2_ssize_t lfs2_file_write(lfs2_t *lfs2, lfs2_file_t *file, + const void *buffer, lfs2_size_t size); + +// Change the position of the file +// +// The change in position is determined by the offset and whence flag. +// Returns the new position of the file, or a negative error code on failure. +lfs2_soff_t lfs2_file_seek(lfs2_t *lfs2, lfs2_file_t *file, + lfs2_soff_t off, int whence); + +// Truncates the size of the file to the specified size +// +// Returns a negative error code on failure. +int lfs2_file_truncate(lfs2_t *lfs2, lfs2_file_t *file, lfs2_off_t size); + +// Return the position of the file +// +// Equivalent to lfs2_file_seek(lfs2, file, 0, LFS2_SEEK_CUR) +// Returns the position of the file, or a negative error code on failure. +lfs2_soff_t lfs2_file_tell(lfs2_t *lfs2, lfs2_file_t *file); + +// Change the position of the file to the beginning of the file +// +// Equivalent to lfs2_file_seek(lfs2, file, 0, LFS2_SEEK_SET) +// Returns a negative error code on failure. +int lfs2_file_rewind(lfs2_t *lfs2, lfs2_file_t *file); + +// Return the size of the file +// +// Similar to lfs2_file_seek(lfs2, file, 0, LFS2_SEEK_END) +// Returns the size of the file, or a negative error code on failure. +lfs2_soff_t lfs2_file_size(lfs2_t *lfs2, lfs2_file_t *file); + + +/// Directory operations /// + +// Create a directory +// +// Returns a negative error code on failure. +int lfs2_mkdir(lfs2_t *lfs2, const char *path); + +// Open a directory +// +// Once open a directory can be used with read to iterate over files. +// Returns a negative error code on failure. +int lfs2_dir_open(lfs2_t *lfs2, lfs2_dir_t *dir, const char *path); + +// Close a directory +// +// Releases any allocated resources. +// Returns a negative error code on failure. +int lfs2_dir_close(lfs2_t *lfs2, lfs2_dir_t *dir); + +// Read an entry in the directory +// +// Fills out the info structure, based on the specified file or directory. +// Returns a positive value on success, 0 at the end of directory, +// or a negative error code on failure. +int lfs2_dir_read(lfs2_t *lfs2, lfs2_dir_t *dir, struct lfs2_info *info); + +// Change the position of the directory +// +// The new off must be a value previous returned from tell and specifies +// an absolute offset in the directory seek. +// +// Returns a negative error code on failure. +int lfs2_dir_seek(lfs2_t *lfs2, lfs2_dir_t *dir, lfs2_off_t off); + +// Return the position of the directory +// +// The returned offset is only meant to be consumed by seek and may not make +// sense, but does indicate the current position in the directory iteration. +// +// Returns the position of the directory, or a negative error code on failure. +lfs2_soff_t lfs2_dir_tell(lfs2_t *lfs2, lfs2_dir_t *dir); + +// Change the position of the directory to the beginning of the directory +// +// Returns a negative error code on failure. +int lfs2_dir_rewind(lfs2_t *lfs2, lfs2_dir_t *dir); + + +/// Filesystem-level filesystem operations + +// Finds the current size of the filesystem +// +// Note: Result is best effort. If files share COW structures, the returned +// size may be larger than the filesystem actually is. +// +// Returns the number of allocated blocks, or a negative error code on failure. +lfs2_ssize_t lfs2_fs_size(lfs2_t *lfs2); + +// Traverse through all blocks in use by the filesystem +// +// The provided callback will be called with each block address that is +// currently in use by the filesystem. This can be used to determine which +// blocks are in use or how much of the storage is available. +// +// Returns a negative error code on failure. +int lfs2_fs_traverse(lfs2_t *lfs2, int (*cb)(void*, lfs2_block_t), void *data); + +#ifdef LFS2_MIGRATE +// Attempts to migrate a previous version of littlefs +// +// Behaves similarly to the lfs2_format function. Attempts to mount +// the previous version of littlefs and update the filesystem so it can be +// mounted with the current version of littlefs. +// +// Requires a littlefs object and config struct. This clobbers the littlefs +// object, and does not leave the filesystem mounted. The config struct must +// be zeroed for defaults and backwards compatibility. +// +// Returns a negative error code on failure. +int lfs2_migrate(lfs2_t *lfs2, const struct lfs2_config *cfg); +#endif + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/lib/littlefs/lfs2_util.c b/lib/littlefs/lfs2_util.c new file mode 100644 index 0000000000..083a99c36c --- /dev/null +++ b/lib/littlefs/lfs2_util.c @@ -0,0 +1,33 @@ +/* + * lfs2 util functions + * + * Copyright (c) 2017, Arm Limited. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "lfs2_util.h" + +// Only compile if user does not provide custom config +#ifndef LFS2_CONFIG + + +// Software CRC implementation with small lookup table +uint32_t lfs2_crc(uint32_t crc, const void *buffer, size_t size) { + static const uint32_t rtable[16] = { + 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, + 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, + 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c, + }; + + const uint8_t *data = buffer; + + for (size_t i = 0; i < size; i++) { + crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 0)) & 0xf]; + crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 4)) & 0xf]; + } + + return crc; +} + + +#endif diff --git a/lib/littlefs/lfs2_util.h b/lib/littlefs/lfs2_util.h new file mode 100644 index 0000000000..0f27073693 --- /dev/null +++ b/lib/littlefs/lfs2_util.h @@ -0,0 +1,230 @@ +/* + * lfs2 utility functions + * + * Copyright (c) 2017, Arm Limited. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef LFS2_UTIL_H +#define LFS2_UTIL_H + +// Users can override lfs2_util.h with their own configuration by defining +// LFS2_CONFIG as a header file to include (-DLFS2_CONFIG=lfs2_config.h). +// +// If LFS2_CONFIG is used, none of the default utils will be emitted and must be +// provided by the config file. To start, I would suggest copying lfs2_util.h +// and modifying as needed. +#ifdef LFS2_CONFIG +#define LFS2_STRINGIZE(x) LFS2_STRINGIZE2(x) +#define LFS2_STRINGIZE2(x) #x +#include LFS2_STRINGIZE(LFS2_CONFIG) +#else + +// System includes +#include +#include +#include +#include + +#ifndef LFS2_NO_MALLOC +#include +#endif +#ifndef LFS2_NO_ASSERT +#include +#endif +#if !defined(LFS2_NO_DEBUG) || \ + !defined(LFS2_NO_WARN) || \ + !defined(LFS2_NO_ERROR) || \ + defined(LFS2_YES_TRACE) +#include +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + + +// Macros, may be replaced by system specific wrappers. Arguments to these +// macros must not have side-effects as the macros can be removed for a smaller +// code footprint + +// Logging functions +#ifdef LFS2_YES_TRACE +#define LFS2_TRACE(fmt, ...) \ + printf("lfs2_trace:%d: " fmt "\n", __LINE__, __VA_ARGS__) +#else +#define LFS2_TRACE(fmt, ...) +#endif + +#ifndef LFS2_NO_DEBUG +#define LFS2_DEBUG(fmt, ...) \ + printf("lfs2_debug:%d: " fmt "\n", __LINE__, __VA_ARGS__) +#else +#define LFS2_DEBUG(fmt, ...) +#endif + +#ifndef LFS2_NO_WARN +#define LFS2_WARN(fmt, ...) \ + printf("lfs2_warn:%d: " fmt "\n", __LINE__, __VA_ARGS__) +#else +#define LFS2_WARN(fmt, ...) +#endif + +#ifndef LFS2_NO_ERROR +#define LFS2_ERROR(fmt, ...) \ + printf("lfs2_error:%d: " fmt "\n", __LINE__, __VA_ARGS__) +#else +#define LFS2_ERROR(fmt, ...) +#endif + +// Runtime assertions +#ifndef LFS2_NO_ASSERT +#define LFS2_ASSERT(test) assert(test) +#else +#define LFS2_ASSERT(test) +#endif + + +// Builtin functions, these may be replaced by more efficient +// toolchain-specific implementations. LFS2_NO_INTRINSICS falls back to a more +// expensive basic C implementation for debugging purposes + +// Min/max functions for unsigned 32-bit numbers +static inline uint32_t lfs2_max(uint32_t a, uint32_t b) { + return (a > b) ? a : b; +} + +static inline uint32_t lfs2_min(uint32_t a, uint32_t b) { + return (a < b) ? a : b; +} + +// Align to nearest multiple of a size +static inline uint32_t lfs2_aligndown(uint32_t a, uint32_t alignment) { + return a - (a % alignment); +} + +static inline uint32_t lfs2_alignup(uint32_t a, uint32_t alignment) { + return lfs2_aligndown(a + alignment-1, alignment); +} + +// Find the next smallest power of 2 less than or equal to a +static inline uint32_t lfs2_npw2(uint32_t a) { +#if !defined(LFS2_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) + return 32 - __builtin_clz(a-1); +#else + uint32_t r = 0; + uint32_t s; + a -= 1; + s = (a > 0xffff) << 4; a >>= s; r |= s; + s = (a > 0xff ) << 3; a >>= s; r |= s; + s = (a > 0xf ) << 2; a >>= s; r |= s; + s = (a > 0x3 ) << 1; a >>= s; r |= s; + return (r | (a >> 1)) + 1; +#endif +} + +// Count the number of trailing binary zeros in a +// lfs2_ctz(0) may be undefined +static inline uint32_t lfs2_ctz(uint32_t a) { +#if !defined(LFS2_NO_INTRINSICS) && defined(__GNUC__) + return __builtin_ctz(a); +#else + return lfs2_npw2((a & -a) + 1) - 1; +#endif +} + +// Count the number of binary ones in a +static inline uint32_t lfs2_popc(uint32_t a) { +#if !defined(LFS2_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) + return __builtin_popcount(a); +#else + a = a - ((a >> 1) & 0x55555555); + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); + return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24; +#endif +} + +// Find the sequence comparison of a and b, this is the distance +// between a and b ignoring overflow +static inline int lfs2_scmp(uint32_t a, uint32_t b) { + return (int)(unsigned)(a - b); +} + +// Convert between 32-bit little-endian and native order +static inline uint32_t lfs2_fromle32(uint32_t a) { +#if !defined(LFS2_NO_INTRINSICS) && ( \ + (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ + (defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) + return a; +#elif !defined(LFS2_NO_INTRINSICS) && ( \ + (defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ + (defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) + return __builtin_bswap32(a); +#else + return (((uint8_t*)&a)[0] << 0) | + (((uint8_t*)&a)[1] << 8) | + (((uint8_t*)&a)[2] << 16) | + (((uint8_t*)&a)[3] << 24); +#endif +} + +static inline uint32_t lfs2_tole32(uint32_t a) { + return lfs2_fromle32(a); +} + +// Convert between 32-bit big-endian and native order +static inline uint32_t lfs2_frombe32(uint32_t a) { +#if !defined(LFS2_NO_INTRINSICS) && ( \ + (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ + (defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) + return __builtin_bswap32(a); +#elif !defined(LFS2_NO_INTRINSICS) && ( \ + (defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ + (defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) + return a; +#else + return (((uint8_t*)&a)[0] << 24) | + (((uint8_t*)&a)[1] << 16) | + (((uint8_t*)&a)[2] << 8) | + (((uint8_t*)&a)[3] << 0); +#endif +} + +static inline uint32_t lfs2_tobe32(uint32_t a) { + return lfs2_frombe32(a); +} + +// Calculate CRC-32 with polynomial = 0x04c11db7 +uint32_t lfs2_crc(uint32_t crc, const void *buffer, size_t size); + +// Allocate memory, only used if buffers are not provided to littlefs +// Note, memory must be 64-bit aligned +static inline void *lfs2_malloc(size_t size) { +#ifndef LFS2_NO_MALLOC + return malloc(size); +#else + (void)size; + return NULL; +#endif +} + +// Deallocate memory, only used if buffers are not provided to littlefs +static inline void lfs2_free(void *p) { +#ifndef LFS2_NO_MALLOC + free(p); +#else + (void)p; +#endif +} + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif +#endif From 22bfc47977ac51b092765173de4cd01f731712cf Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 27 Oct 2019 18:37:24 +1100 Subject: [PATCH 0901/1788] lib/littlefs: Add README describing origin and how to gen lfs1/lfs2. --- lib/littlefs/README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 lib/littlefs/README.md diff --git a/lib/littlefs/README.md b/lib/littlefs/README.md new file mode 100644 index 0000000000..1f0aacbf98 --- /dev/null +++ b/lib/littlefs/README.md @@ -0,0 +1,19 @@ +littlefs library +================ + +The upstream source for the files in this directory is +https://github.com/ARMmbed/littlefs + +To generate the separate files with lfs1 and lfs2 prefixes run the following +commands in the top-level directory of the littlefs repository (replace the +version tags with the latest/desired ones, and set `$MPY_DIR`): + + git checkout v1.7.2 + python2 ./scripts/prefix.py lfs1 + cp lfs1*.[ch] $MPY_DIR/lib/littlefs + git reset --hard HEAD + + git checkout v2.1.3 + python2 ./scripts/prefix.py lfs2 + cp lfs2*.[ch] $MPY_DIR/lib/littlefs + git reset --hard HEAD From 98beea9cedca522857d12a741ff8ea90f6b873a3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 21 Oct 2019 19:08:04 +1100 Subject: [PATCH 0902/1788] extmod/vfs_blockdev: Add extended read/write methods. This commit adds helper functions to call readblocks/writeblocks with a fourth argument, the byte offset within a block. Although the mp_vfs_blockdev_t struct has grown here by 2 machine words, in all current uses of this struct within this repository it still fits within the same number of GC blocks. --- extmod/vfs.h | 6 ++++-- extmod/vfs_blockdev.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/extmod/vfs.h b/extmod/vfs.h index e626a14df0..767ba3033a 100644 --- a/extmod/vfs.h +++ b/extmod/vfs.h @@ -59,8 +59,8 @@ typedef struct _mp_vfs_proto_t { typedef struct _mp_vfs_blockdev_t { uint16_t flags; size_t block_size; - mp_obj_t readblocks[4]; - mp_obj_t writeblocks[4]; + mp_obj_t readblocks[5]; + mp_obj_t writeblocks[5]; // new protocol uses just ioctl, old uses sync (optional) and count union { mp_obj_t ioctl[4]; @@ -80,7 +80,9 @@ typedef struct _mp_vfs_mount_t { void mp_vfs_blockdev_init(mp_vfs_blockdev_t *self, mp_obj_t bdev); int mp_vfs_blockdev_read(mp_vfs_blockdev_t *self, size_t block_num, size_t num_blocks, uint8_t *buf); +int mp_vfs_blockdev_read_ext(mp_vfs_blockdev_t *self, size_t block_num, size_t block_off, size_t len, uint8_t *buf); int mp_vfs_blockdev_write(mp_vfs_blockdev_t *self, size_t block_num, size_t num_blocks, const uint8_t *buf); +int mp_vfs_blockdev_write_ext(mp_vfs_blockdev_t *self, size_t block_num, size_t block_off, size_t len, const uint8_t *buf); mp_obj_t mp_vfs_blockdev_ioctl(mp_vfs_blockdev_t *self, uintptr_t cmd, uintptr_t arg); mp_vfs_mount_t *mp_vfs_lookup_path(const char *path, const char **path_out); diff --git a/extmod/vfs_blockdev.c b/extmod/vfs_blockdev.c index 0bc0fdebfa..916d71ca47 100644 --- a/extmod/vfs_blockdev.c +++ b/extmod/vfs_blockdev.c @@ -60,6 +60,19 @@ int mp_vfs_blockdev_read(mp_vfs_blockdev_t *self, size_t block_num, size_t num_b } } +int mp_vfs_blockdev_read_ext(mp_vfs_blockdev_t *self, size_t block_num, size_t block_off, size_t len, uint8_t *buf) { + mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, len, buf}; + self->readblocks[2] = MP_OBJ_NEW_SMALL_INT(block_num); + self->readblocks[3] = MP_OBJ_FROM_PTR(&ar); + self->readblocks[4] = MP_OBJ_NEW_SMALL_INT(block_off); + mp_obj_t ret = mp_call_method_n_kw(3, 0, self->readblocks); + if (ret == mp_const_none) { + return 0; + } else { + return MP_OBJ_SMALL_INT_VALUE(ret); + } +} + int mp_vfs_blockdev_write(mp_vfs_blockdev_t *self, size_t block_num, size_t num_blocks, const uint8_t *buf) { if (self->writeblocks[0] == MP_OBJ_NULL) { // read-only block device @@ -79,6 +92,24 @@ int mp_vfs_blockdev_write(mp_vfs_blockdev_t *self, size_t block_num, size_t num_ } } +int mp_vfs_blockdev_write_ext(mp_vfs_blockdev_t *self, size_t block_num, size_t block_off, size_t len, const uint8_t *buf) { + if (self->writeblocks[0] == MP_OBJ_NULL) { + // read-only block device + return -MP_EROFS; + } + + mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, len, (void*)buf}; + self->writeblocks[2] = MP_OBJ_NEW_SMALL_INT(block_num); + self->writeblocks[3] = MP_OBJ_FROM_PTR(&ar); + self->writeblocks[4] = MP_OBJ_NEW_SMALL_INT(block_off); + mp_obj_t ret = mp_call_method_n_kw(3, 0, self->writeblocks); + if (ret == mp_const_none) { + return 0; + } else { + return MP_OBJ_SMALL_INT_VALUE(ret); + } +} + mp_obj_t mp_vfs_blockdev_ioctl(mp_vfs_blockdev_t *self, uintptr_t cmd, uintptr_t arg) { if (self->flags & MP_BLOCKDEV_FLAG_HAVE_IOCTL) { // New protocol with ioctl From a099505420221790509ab92611db52d0131e401a Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 18 Oct 2019 17:25:08 +1100 Subject: [PATCH 0903/1788] extmod: Add VFS littlefs bindings. Both LFS1 and LFS2 are supported at the same time. --- extmod/extmod.mk | 16 ++ extmod/vfs_lfs.c | 117 +++++++++++ extmod/vfs_lfs.h | 39 ++++ extmod/vfs_lfsx.c | 428 +++++++++++++++++++++++++++++++++++++++++ extmod/vfs_lfsx_file.c | 236 +++++++++++++++++++++++ py/py.mk | 1 + 6 files changed, 837 insertions(+) create mode 100644 extmod/vfs_lfs.c create mode 100644 extmod/vfs_lfs.h create mode 100644 extmod/vfs_lfsx.c create mode 100644 extmod/vfs_lfsx_file.c diff --git a/extmod/extmod.mk b/extmod/extmod.mk index 05d0be3b16..8e63b25f90 100644 --- a/extmod/extmod.mk +++ b/extmod/extmod.mk @@ -3,6 +3,22 @@ # this sets the config file for FatFs CFLAGS_MOD += -DFFCONF_H=\"lib/oofatfs/ffconf.h\" +################################################################################ +# VFS littlefs + +ifeq ($(MICROPY_VFS_LFS),1) +CFLAGS_MOD += -DMICROPY_VFS_LFS=1 +CFLAGS_MOD += -DLFS1_NO_MALLOC -DLFS1_NO_DEBUG -DLFS1_NO_WARN -DLFS1_NO_ERROR -DLFS1_NO_ASSERT +CFLAGS_MOD += -DLFS2_NO_MALLOC -DLFS2_NO_DEBUG -DLFS2_NO_WARN -DLFS2_NO_ERROR -DLFS2_NO_ASSERT +LITTLEFS_DIR = lib/littlefs +SRC_MOD += $(addprefix $(LITTLEFS_DIR)/,\ + lfs1.c \ + lfs1_util.c \ + lfs2.c \ + lfs2_util.c \ + ) +endif + ################################################################################ # ussl diff --git a/extmod/vfs_lfs.c b/extmod/vfs_lfs.c new file mode 100644 index 0000000000..72f501abbf --- /dev/null +++ b/extmod/vfs_lfs.c @@ -0,0 +1,117 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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 "extmod/vfs.h" +#include "extmod/vfs_lfs.h" + +#if MICROPY_VFS && MICROPY_VFS_LFS + +enum { LFS_MAKE_ARG_bdev, LFS_MAKE_ARG_readsize, LFS_MAKE_ARG_progsize, LFS_MAKE_ARG_lookahead }; + +static const mp_arg_t lfs_make_allowed_args[] = { + { MP_QSTR_, MP_ARG_OBJ }, + { MP_QSTR_readsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} }, + { MP_QSTR_progsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} }, + { MP_QSTR_lookahead, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} }, +}; + +#include "lib/littlefs/lfs1.h" + +#define LFS_BUILD_VERSION (1) +#define LFSx_MACRO(s) LFS1 ## s +#define LFSx_API(s) lfs1_ ## s +#define MP_VFS_LFSx(s) mp_vfs_lfs1_ ## s +#define MP_OBJ_VFS_LFSx mp_obj_vfs_lfs1_t +#define MP_OBJ_VFS_LFSx_FILE mp_obj_vfs_lfs1_file_t +#define MP_TYPE_VFS_LFSx mp_type_vfs_lfs1 +#define MP_TYPE_VFS_LFSx_(s) mp_type_vfs_lfs1 ## s + +typedef struct _mp_obj_vfs_lfs1_t { + mp_obj_base_t base; + mp_vfs_blockdev_t blockdev; + vstr_t cur_dir; + struct lfs1_config config; + lfs1_t lfs; +} mp_obj_vfs_lfs1_t; + +typedef struct _mp_obj_vfs_lfs1_file_t { + mp_obj_base_t base; + mp_obj_vfs_lfs1_t *vfs; + lfs1_file_t file; + struct lfs1_file_config cfg; + uint8_t file_buffer[0]; +} mp_obj_vfs_lfs1_file_t; + +const char *mp_vfs_lfs1_make_path(mp_obj_vfs_lfs1_t *self, mp_obj_t path_in); +mp_obj_t mp_vfs_lfs1_file_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode_in); + +#include "extmod/vfs_lfsx.c" +#include "extmod/vfs_lfsx_file.c" + +#undef LFS_BUILD_VERSION +#undef LFSx_MACRO +#undef LFSx_API +#undef MP_VFS_LFSx +#undef MP_OBJ_VFS_LFSx +#undef MP_OBJ_VFS_LFSx_FILE +#undef MP_TYPE_VFS_LFSx +#undef MP_TYPE_VFS_LFSx_ + +#include "lib/littlefs/lfs2.h" + +#define LFS_BUILD_VERSION (2) +#define LFSx_MACRO(s) LFS2 ## s +#define LFSx_API(s) lfs2_ ## s +#define MP_VFS_LFSx(s) mp_vfs_lfs2_ ## s +#define MP_OBJ_VFS_LFSx mp_obj_vfs_lfs2_t +#define MP_OBJ_VFS_LFSx_FILE mp_obj_vfs_lfs2_file_t +#define MP_TYPE_VFS_LFSx mp_type_vfs_lfs2 +#define MP_TYPE_VFS_LFSx_(s) mp_type_vfs_lfs2 ## s + +typedef struct _mp_obj_vfs_lfs2_t { + mp_obj_base_t base; + mp_vfs_blockdev_t blockdev; + vstr_t cur_dir; + struct lfs2_config config; + lfs2_t lfs; +} mp_obj_vfs_lfs2_t; + +typedef struct _mp_obj_vfs_lfs2_file_t { + mp_obj_base_t base; + mp_obj_vfs_lfs2_t *vfs; + lfs2_file_t file; + struct lfs2_file_config cfg; + uint8_t file_buffer[0]; +} mp_obj_vfs_lfs2_file_t; + +const char *mp_vfs_lfs2_make_path(mp_obj_vfs_lfs2_t *self, mp_obj_t path_in); +mp_obj_t mp_vfs_lfs2_file_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode_in); + +#include "extmod/vfs_lfsx.c" +#include "extmod/vfs_lfsx_file.c" + +#endif // MICROPY_VFS && MICROPY_VFS_LFS diff --git a/extmod/vfs_lfs.h b/extmod/vfs_lfs.h new file mode 100644 index 0000000000..1fdf792f1b --- /dev/null +++ b/extmod/vfs_lfs.h @@ -0,0 +1,39 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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_LFS_H +#define MICROPY_INCLUDED_EXTMOD_VFS_LFS_H + +#include "py/obj.h" + +extern const mp_obj_type_t mp_type_vfs_lfs1; +extern const mp_obj_type_t mp_type_vfs_lfs1_fileio; +extern const mp_obj_type_t mp_type_vfs_lfs1_textio; + +extern const mp_obj_type_t mp_type_vfs_lfs2; +extern const mp_obj_type_t mp_type_vfs_lfs2_fileio; +extern const mp_obj_type_t mp_type_vfs_lfs2_textio; + +#endif // MICROPY_INCLUDED_EXTMOD_VFS_LFS_H diff --git a/extmod/vfs_lfsx.c b/extmod/vfs_lfsx.c new file mode 100644 index 0000000000..a042f5ed1e --- /dev/null +++ b/extmod/vfs_lfsx.c @@ -0,0 +1,428 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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/runtime.h" +#include "py/stream.h" +#include "py/binary.h" +#include "py/objarray.h" +#include "py/mperrno.h" +#include "extmod/vfs.h" + +STATIC int MP_VFS_LFSx(dev_ioctl)(const struct LFSx_API(config) *c, int cmd, int arg, bool must_return_int) { + mp_obj_t ret = mp_vfs_blockdev_ioctl(c->context, cmd, arg); + int ret_i = 0; + if (must_return_int || ret != mp_const_none) { + ret_i = mp_obj_get_int(ret); + } + return ret_i; +} + +STATIC int MP_VFS_LFSx(dev_read)(const struct LFSx_API(config) *c, LFSx_API(block_t) block, LFSx_API(off_t) off, void *buffer, LFSx_API(size_t) size) { + return mp_vfs_blockdev_read_ext(c->context, block, off, size, buffer); +} + +STATIC int MP_VFS_LFSx(dev_prog)(const struct LFSx_API(config) *c, LFSx_API(block_t) block, LFSx_API(off_t) off, const void *buffer, LFSx_API(size_t) size) { + return mp_vfs_blockdev_write_ext(c->context, block, off, size, buffer); +} + +STATIC int MP_VFS_LFSx(dev_erase)(const struct LFSx_API(config) *c, LFSx_API(block_t) block) { + return MP_VFS_LFSx(dev_ioctl)(c, 6, block, true); // erase +} + +STATIC int MP_VFS_LFSx(dev_sync)(const struct LFSx_API(config) *c) { + return MP_VFS_LFSx(dev_ioctl)(c, BP_IOCTL_SYNC, 0, false); +} + +STATIC void MP_VFS_LFSx(init_config)(MP_OBJ_VFS_LFSx *self, mp_obj_t bdev, size_t read_size, size_t prog_size, size_t lookahead) { + self->blockdev.flags = MP_BLOCKDEV_FLAG_FREE_OBJ; + mp_vfs_blockdev_init(&self->blockdev, bdev); + + struct LFSx_API(config) *config = &self->config; + memset(config, 0, sizeof(*config)); + + config->context = &self->blockdev; + + config->read = MP_VFS_LFSx(dev_read); + config->prog = MP_VFS_LFSx(dev_prog); + config->erase = MP_VFS_LFSx(dev_erase); + config->sync = MP_VFS_LFSx(dev_sync); + + MP_VFS_LFSx(dev_ioctl)(config, BP_IOCTL_INIT, 0, false); // initialise block device + int bs = MP_VFS_LFSx(dev_ioctl)(config, BP_IOCTL_SEC_SIZE, 0, true); // get block size + int bc = MP_VFS_LFSx(dev_ioctl)(config, BP_IOCTL_SEC_COUNT, 0, true); // get block count + self->blockdev.block_size = bs; + + config->read_size = read_size; + config->prog_size = prog_size; + config->block_size = bs; + config->block_count = bc; + + #if LFS_BUILD_VERSION == 1 + config->lookahead = lookahead; + config->read_buffer = m_new(uint8_t, config->read_size); + config->prog_buffer = m_new(uint8_t, config->prog_size); + config->lookahead_buffer = m_new(uint8_t, config->lookahead / 8); + #else + config->block_cycles = 100; + config->cache_size = 4 * MAX(read_size, prog_size); + config->lookahead_size = lookahead; + config->read_buffer = m_new(uint8_t, config->cache_size); + config->prog_buffer = m_new(uint8_t, config->cache_size); + config->lookahead_buffer = m_new(uint8_t, config->lookahead_size); + #endif +} + +const char *MP_VFS_LFSx(make_path)(MP_OBJ_VFS_LFSx *self, mp_obj_t path_in) { + const char *path = mp_obj_str_get_str(path_in); + if (path[0] != '/') { + size_t l = vstr_len(&self->cur_dir); + if (l > 0) { + vstr_add_str(&self->cur_dir, path); + path = vstr_null_terminated_str(&self->cur_dir); + self->cur_dir.len = l; + } + } + return path; +} + +STATIC mp_obj_t MP_VFS_LFSx(make_new)(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + mp_arg_val_t args[MP_ARRAY_SIZE(lfs_make_allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(lfs_make_allowed_args), lfs_make_allowed_args, args); + + MP_OBJ_VFS_LFSx *self = m_new0(MP_OBJ_VFS_LFSx, 1); + self->base.type = type; + vstr_init(&self->cur_dir, 16); + vstr_add_byte(&self->cur_dir, '/'); + MP_VFS_LFSx(init_config)(self, args[LFS_MAKE_ARG_bdev].u_obj, + args[LFS_MAKE_ARG_readsize].u_int, args[LFS_MAKE_ARG_progsize].u_int, args[LFS_MAKE_ARG_lookahead].u_int); + int ret = LFSx_API(mount)(&self->lfs, &self->config); + if (ret < 0) { + mp_raise_OSError(-ret); + } + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t MP_VFS_LFSx(mkfs)(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + mp_arg_val_t args[MP_ARRAY_SIZE(lfs_make_allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(lfs_make_allowed_args), lfs_make_allowed_args, args); + + MP_OBJ_VFS_LFSx self; + MP_VFS_LFSx(init_config)(&self, args[LFS_MAKE_ARG_bdev].u_obj, + args[LFS_MAKE_ARG_readsize].u_int, args[LFS_MAKE_ARG_progsize].u_int, args[LFS_MAKE_ARG_lookahead].u_int); + int ret = LFSx_API(format)(&self.lfs, &self.config); + if (ret < 0) { + mp_raise_OSError(-ret); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(MP_VFS_LFSx(mkfs_fun_obj), 0, MP_VFS_LFSx(mkfs)); +STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(MP_VFS_LFSx(mkfs_obj), MP_ROM_PTR(&MP_VFS_LFSx(mkfs_fun_obj))); + +// Implementation of mp_vfs_lfs_file_open is provided in vfs_lfsx_file.c +STATIC MP_DEFINE_CONST_FUN_OBJ_3(MP_VFS_LFSx(open_obj), MP_VFS_LFSx(file_open)); + +typedef struct MP_VFS_LFSx(_ilistdir_it_t) { + mp_obj_base_t base; + mp_fun_1_t iternext; + bool is_str; + MP_OBJ_VFS_LFSx *vfs; + LFSx_API(dir_t) dir; +} MP_VFS_LFSx(ilistdir_it_t); + +STATIC mp_obj_t MP_VFS_LFSx(ilistdir_it_iternext)(mp_obj_t self_in) { + MP_VFS_LFSx(ilistdir_it_t) *self = MP_OBJ_TO_PTR(self_in); + + struct LFSx_API(info) info; + for (;;) { + int ret = LFSx_API(dir_read)(&self->vfs->lfs, &self->dir, &info); + if (ret == 0) { + LFSx_API(dir_close)(&self->vfs->lfs, &self->dir); + return MP_OBJ_STOP_ITERATION; + } + if (!(info.name[0] == '.' && (info.name[1] == '\0' + || (info.name[1] == '.' && info.name[2] == '\0')))) { + break; + } + } + + // 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(info.name, strlen(info.name)); + } else { + t->items[0] = mp_obj_new_bytes((const byte*)info.name, strlen(info.name)); + } + t->items[1] = MP_OBJ_NEW_SMALL_INT(info.type == LFSx_MACRO(_TYPE_REG) ? MP_S_IFREG : MP_S_IFDIR); + t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // no inode number + t->items[3] = MP_OBJ_NEW_SMALL_INT(info.size); + + return MP_OBJ_FROM_PTR(t); +} + +STATIC mp_obj_t MP_VFS_LFSx(ilistdir_func)(size_t n_args, const mp_obj_t *args) { + MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(args[0]); + bool is_str_type = true; + const char *path; + if (n_args == 2) { + if (mp_obj_get_type(args[1]) == &mp_type_bytes) { + is_str_type = false; + } + path = MP_VFS_LFSx(make_path)(self, args[1]); + } else { + path = vstr_null_terminated_str(&self->cur_dir); + } + + MP_VFS_LFSx(ilistdir_it_t) *iter = m_new_obj(MP_VFS_LFSx(ilistdir_it_t)); + iter->base.type = &mp_type_polymorph_iter; + iter->iternext = MP_VFS_LFSx(ilistdir_it_iternext); + iter->is_str = is_str_type; + iter->vfs = self; + int ret = LFSx_API(dir_open)(&self->lfs, &iter->dir, path); + if (ret < 0) { + mp_raise_OSError(-ret); + } + return MP_OBJ_FROM_PTR(iter); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(MP_VFS_LFSx(ilistdir_obj), 1, 2, MP_VFS_LFSx(ilistdir_func)); + +STATIC mp_obj_t MP_VFS_LFSx(remove)(mp_obj_t self_in, mp_obj_t path_in) { + MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in); + const char *path = MP_VFS_LFSx(make_path)(self, path_in); + int ret = LFSx_API(remove)(&self->lfs, path); + if (ret < 0) { + mp_raise_OSError(-ret); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(MP_VFS_LFSx(remove_obj), MP_VFS_LFSx(remove)); + +STATIC mp_obj_t MP_VFS_LFSx(rmdir)(mp_obj_t self_in, mp_obj_t path_in) { + MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in); + const char *path = MP_VFS_LFSx(make_path)(self, path_in); + int ret = LFSx_API(remove)(&self->lfs, path); + if (ret < 0) { + mp_raise_OSError(-ret); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(MP_VFS_LFSx(rmdir_obj), MP_VFS_LFSx(rmdir)); + +STATIC mp_obj_t MP_VFS_LFSx(rename)(mp_obj_t self_in, mp_obj_t path_old_in, mp_obj_t path_new_in) { + MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in); + const char *path_old = MP_VFS_LFSx(make_path)(self, path_old_in); + vstr_t path_new; + vstr_init(&path_new, vstr_len(&self->cur_dir)); + vstr_add_strn(&path_new, vstr_str(&self->cur_dir), vstr_len(&self->cur_dir)); + vstr_add_str(&path_new, mp_obj_str_get_str(path_new_in)); + int ret = LFSx_API(rename)(&self->lfs, path_old, vstr_null_terminated_str(&path_new)); + vstr_clear(&path_new); + if (ret < 0) { + mp_raise_OSError(-ret); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(MP_VFS_LFSx(rename_obj), MP_VFS_LFSx(rename)); + +STATIC mp_obj_t MP_VFS_LFSx(mkdir)(mp_obj_t self_in, mp_obj_t path_o) { + MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in); + const char *path = MP_VFS_LFSx(make_path)(self, path_o); + int ret = LFSx_API(mkdir)(&self->lfs, path); + if (ret < 0) { + mp_raise_OSError(-ret); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(MP_VFS_LFSx(mkdir_obj), MP_VFS_LFSx(mkdir)); + +STATIC mp_obj_t MP_VFS_LFSx(chdir)(mp_obj_t self_in, mp_obj_t path_in) { + MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in); + + // Check path exists + const char *path = MP_VFS_LFSx(make_path)(self, path_in); + if (path[1] != '\0') { + // Not at root, check it exists + struct LFSx_API(info) info; + int ret = LFSx_API(stat)(&self->lfs, path, &info); + if (ret < 0 || info.type != LFSx_MACRO(_TYPE_DIR)) { + mp_raise_OSError(-MP_ENOENT); + } + } + + // Update cur_dir with new path + if (path == vstr_str(&self->cur_dir)) { + self->cur_dir.len = strlen(path); + } else { + vstr_reset(&self->cur_dir); + vstr_add_str(&self->cur_dir, path); + } + + // If not at root add trailing / to make it easy to build paths + if (vstr_len(&self->cur_dir) != 1) { + vstr_add_byte(&self->cur_dir, '/'); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(MP_VFS_LFSx(chdir_obj), MP_VFS_LFSx(chdir)); + +STATIC mp_obj_t MP_VFS_LFSx(getcwd)(mp_obj_t self_in) { + MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in); + if (vstr_len(&self->cur_dir) == 1) { + return MP_OBJ_NEW_QSTR(MP_QSTR__slash_); + } else { + // don't include trailing / + return mp_obj_new_str(self->cur_dir.buf, self->cur_dir.len - 1); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(MP_VFS_LFSx(getcwd_obj), MP_VFS_LFSx(getcwd)); + +STATIC mp_obj_t MP_VFS_LFSx(stat)(mp_obj_t self_in, mp_obj_t path_in) { + MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in); + const char *path = mp_obj_str_get_str(path_in); + struct LFSx_API(info) info; + int ret = LFSx_API(stat)(&self->lfs, path, &info); + if (ret < 0) { + mp_raise_OSError(-ret); + } + + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); + t->items[0] = MP_OBJ_NEW_SMALL_INT(info.type == LFSx_MACRO(_TYPE_REG) ? MP_S_IFREG : MP_S_IFDIR); // st_mode + t->items[1] = MP_OBJ_NEW_SMALL_INT(0); // st_ino + t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // st_dev + t->items[3] = MP_OBJ_NEW_SMALL_INT(0); // st_nlink + t->items[4] = MP_OBJ_NEW_SMALL_INT(0); // st_uid + t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // st_gid + t->items[6] = mp_obj_new_int_from_uint(info.size); // st_size + t->items[7] = MP_OBJ_NEW_SMALL_INT(0); // st_atime + t->items[8] = MP_OBJ_NEW_SMALL_INT(0); // st_mtime + t->items[9] = MP_OBJ_NEW_SMALL_INT(0); // st_ctime + + return MP_OBJ_FROM_PTR(t); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(MP_VFS_LFSx(stat_obj), MP_VFS_LFSx(stat)); + +STATIC int LFSx_API(traverse_cb)(void *data, LFSx_API(block_t) bl) { + (void)bl; + uint32_t *n = (uint32_t*)data; + *n += 1; + return LFSx_MACRO(_ERR_OK); +} + +STATIC mp_obj_t MP_VFS_LFSx(statvfs)(mp_obj_t self_in, mp_obj_t path_in) { + (void)path_in; + MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in); + uint32_t n_used_blocks = 0; + #if LFS_BUILD_VERSION == 1 + int ret = LFSx_API(traverse)(&self->lfs, LFSx_API(traverse_cb), &n_used_blocks); + #else + int ret = LFSx_API(fs_traverse)(&self->lfs, LFSx_API(traverse_cb), &n_used_blocks); + #endif + if (ret < 0) { + mp_raise_OSError(-ret); + } + + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); + t->items[0] = MP_OBJ_NEW_SMALL_INT(self->lfs.cfg->block_size); // f_bsize + t->items[1] = t->items[0]; // f_frsize + t->items[2] = MP_OBJ_NEW_SMALL_INT(self->lfs.cfg->block_count); // f_blocks + t->items[3] = MP_OBJ_NEW_SMALL_INT(self->lfs.cfg->block_count - n_used_blocks); // f_bfree + t->items[4] = t->items[3]; // f_bavail + t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // f_files + t->items[6] = MP_OBJ_NEW_SMALL_INT(0); // f_ffree + t->items[7] = MP_OBJ_NEW_SMALL_INT(0); // f_favail + t->items[8] = MP_OBJ_NEW_SMALL_INT(0); // f_flags + t->items[9] = MP_OBJ_NEW_SMALL_INT(LFSx_MACRO(_NAME_MAX)); // f_namemax + + return MP_OBJ_FROM_PTR(t); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(MP_VFS_LFSx(statvfs_obj), MP_VFS_LFSx(statvfs)); + +STATIC mp_obj_t MP_VFS_LFSx(mount)(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs) { + (void)self_in; + (void)readonly; + (void)mkfs; + // already called LFSx_API(mount) in MP_VFS_LFSx(make_new) + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(MP_VFS_LFSx(mount_obj), MP_VFS_LFSx(mount)); + +STATIC mp_obj_t MP_VFS_LFSx(umount)(mp_obj_t self_in) { + MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in); + // LFS unmount never fails + LFSx_API(unmount)(&self->lfs); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(MP_VFS_LFSx(umount_obj), MP_VFS_LFSx(umount)); + +STATIC const mp_rom_map_elem_t MP_VFS_LFSx(locals_dict_table)[] = { + { MP_ROM_QSTR(MP_QSTR_mkfs), MP_ROM_PTR(&MP_VFS_LFSx(mkfs_obj)) }, + { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&MP_VFS_LFSx(open_obj)) }, + { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&MP_VFS_LFSx(ilistdir_obj)) }, + { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&MP_VFS_LFSx(mkdir_obj)) }, + { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&MP_VFS_LFSx(rmdir_obj)) }, + { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&MP_VFS_LFSx(chdir_obj)) }, + { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&MP_VFS_LFSx(getcwd_obj)) }, + { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&MP_VFS_LFSx(remove_obj)) }, + { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&MP_VFS_LFSx(rename_obj)) }, + { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&MP_VFS_LFSx(stat_obj)) }, + { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&MP_VFS_LFSx(statvfs_obj)) }, + { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&MP_VFS_LFSx(mount_obj)) }, + { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&MP_VFS_LFSx(umount_obj)) }, +}; +STATIC MP_DEFINE_CONST_DICT(MP_VFS_LFSx(locals_dict), MP_VFS_LFSx(locals_dict_table)); + +STATIC mp_import_stat_t MP_VFS_LFSx(import_stat)(void *self_in, const char *path) { + MP_OBJ_VFS_LFSx *self = self_in; + struct LFSx_API(info) info; + int ret = LFSx_API(stat)(&self->lfs, path, &info); + if (ret == 0) { + if (info.type == LFSx_MACRO(_TYPE_REG)) { + return MP_IMPORT_STAT_FILE; + } else { + return MP_IMPORT_STAT_DIR; + } + } + return MP_IMPORT_STAT_NO_EXIST; +} + +STATIC const mp_vfs_proto_t MP_VFS_LFSx(proto) = { + .import_stat = MP_VFS_LFSx(import_stat), +}; + +const mp_obj_type_t MP_TYPE_VFS_LFSx = { + { &mp_type_type }, + #if LFS_BUILD_VERSION == 1 + .name = MP_QSTR_VfsLfs1, + #else + .name = MP_QSTR_VfsLfs2, + #endif + .make_new = MP_VFS_LFSx(make_new), + .protocol = &MP_VFS_LFSx(proto), + .locals_dict = (mp_obj_dict_t*)&MP_VFS_LFSx(locals_dict), +}; diff --git a/extmod/vfs_lfsx_file.c b/extmod/vfs_lfsx_file.c new file mode 100644 index 0000000000..113c3ec990 --- /dev/null +++ b/extmod/vfs_lfsx_file.c @@ -0,0 +1,236 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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/runtime.h" +#include "py/stream.h" +#include "py/mperrno.h" +#include "extmod/vfs.h" + +STATIC void MP_VFS_LFSx(check_open)(MP_OBJ_VFS_LFSx_FILE *self) { + if (self->vfs == NULL) { + mp_raise_ValueError(NULL); + } +} + +STATIC void MP_VFS_LFSx(file_print)(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)self_in; + (void)kind; + mp_printf(print, "", mp_obj_get_type_str(self_in)); +} + +mp_obj_t MP_VFS_LFSx(file_open)(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode_in) { + MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in); + + int flags = 0; + const mp_obj_type_t *type = &MP_TYPE_VFS_LFSx_(_textio); + const char *mode_str = mp_obj_str_get_str(mode_in); + for (; *mode_str; ++mode_str) { + int new_flags = 0; + switch (*mode_str) { + case 'r': + new_flags = LFSx_MACRO(_O_RDONLY); + break; + case 'w': + new_flags = LFSx_MACRO(_O_WRONLY) | LFSx_MACRO(_O_CREAT) | LFSx_MACRO(_O_TRUNC); + break; + case 'x': + new_flags = LFSx_MACRO(_O_WRONLY) | LFSx_MACRO(_O_CREAT) | LFSx_MACRO(_O_EXCL); + break; + case 'a': + new_flags = LFSx_MACRO(_O_WRONLY) | LFSx_MACRO(_O_CREAT) | LFSx_MACRO(_O_APPEND); + break; + case '+': + flags |= LFSx_MACRO(_O_RDWR); + break; + #if MICROPY_PY_IO_FILEIO + case 'b': + type = &MP_TYPE_VFS_LFSx_(_fileio); + break; + #endif + case 't': + type = &MP_TYPE_VFS_LFSx_(_textio); + break; + } + if (new_flags) { + if (flags) { + mp_raise_ValueError(NULL); + } + flags = new_flags; + } + } + if (flags == 0) { + flags = LFSx_MACRO(_O_RDONLY); + } + + #if LFS_BUILD_VERSION == 1 + MP_OBJ_VFS_LFSx_FILE *o = m_new_obj_var_with_finaliser(MP_OBJ_VFS_LFSx_FILE, uint8_t, self->lfs.cfg->prog_size); + #else + MP_OBJ_VFS_LFSx_FILE *o = m_new_obj_var_with_finaliser(MP_OBJ_VFS_LFSx_FILE, uint8_t, self->lfs.cfg->cache_size); + #endif + o->base.type = type; + o->vfs = self; + #if !MICROPY_GC_CONSERVATIVE_CLEAR + memset(&o->file, 0, sizeof(o->file)); + memset(&o->cfg, 0, sizeof(o->cfg)); + #endif + o->cfg.buffer = &o->file_buffer[0]; + + const char *path = MP_VFS_LFSx(make_path)(self, path_in); + int ret = LFSx_API(file_opencfg)(&self->lfs, &o->file, path, flags, &o->cfg); + if (ret < 0) { + o->vfs = NULL; + mp_raise_OSError(-ret); + } + + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t MP_VFS_LFSx(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(MP_VFS_LFSx(file___exit___obj), 4, 4, MP_VFS_LFSx(file___exit__)); + +STATIC mp_uint_t MP_VFS_LFSx(file_read)(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) { + MP_OBJ_VFS_LFSx_FILE *self = MP_OBJ_TO_PTR(self_in); + MP_VFS_LFSx(check_open)(self); + LFSx_API(ssize_t) sz = LFSx_API(file_read)(&self->vfs->lfs, &self->file, buf, size); + if (sz < 0) { + *errcode = -sz; + return MP_STREAM_ERROR; + } + return sz; +} + +STATIC mp_uint_t MP_VFS_LFSx(file_write)(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) { + MP_OBJ_VFS_LFSx_FILE *self = MP_OBJ_TO_PTR(self_in); + MP_VFS_LFSx(check_open)(self); + LFSx_API(ssize_t) sz = LFSx_API(file_write)(&self->vfs->lfs, &self->file, buf, size); + if (sz < 0) { + *errcode = -sz; + return MP_STREAM_ERROR; + } + return sz; +} + +STATIC mp_uint_t MP_VFS_LFSx(file_ioctl)(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + MP_OBJ_VFS_LFSx_FILE *self = MP_OBJ_TO_PTR(self_in); + + if (request != MP_STREAM_CLOSE) { + MP_VFS_LFSx(check_open)(self); + } + + if (request == MP_STREAM_SEEK) { + struct mp_stream_seek_t *s = (struct mp_stream_seek_t*)(uintptr_t)arg; + int res = LFSx_API(file_seek)(&self->vfs->lfs, &self->file, s->offset, s->whence); + if (res < 0) { + *errcode = -res; + return MP_STREAM_ERROR; + } + res = LFSx_API(file_tell)(&self->vfs->lfs, &self->file); + if (res < 0) { + *errcode = -res; + return MP_STREAM_ERROR; + } + s->offset = res; + return 0; + } else if (request == MP_STREAM_FLUSH) { + int res = LFSx_API(file_sync)(&self->vfs->lfs, &self->file); + if (res < 0) { + *errcode = -res; + return MP_STREAM_ERROR; + } + return 0; + } else if (request == MP_STREAM_CLOSE) { + if (self->vfs == NULL) { + return 0; + } + int res = LFSx_API(file_close)(&self->vfs->lfs, &self->file); + self->vfs = NULL; // indicate a closed file + if (res < 0) { + *errcode = -res; + return MP_STREAM_ERROR; + } + return 0; + } else { + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } +} + +STATIC const mp_rom_map_elem_t MP_VFS_LFSx(file_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_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(&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(&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(&MP_VFS_LFSx(file___exit___obj)) }, +}; +STATIC MP_DEFINE_CONST_DICT(MP_VFS_LFSx(file_locals_dict), MP_VFS_LFSx(file_locals_dict_table)); + +#if MICROPY_PY_IO_FILEIO +STATIC const mp_stream_p_t MP_VFS_LFSx(fileio_stream_p) = { + .read = MP_VFS_LFSx(file_read), + .write = MP_VFS_LFSx(file_write), + .ioctl = MP_VFS_LFSx(file_ioctl), +}; + +const mp_obj_type_t MP_TYPE_VFS_LFSx_(_fileio) = { + { &mp_type_type }, + .name = MP_QSTR_FileIO, + .print = MP_VFS_LFSx(file_print), + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &MP_VFS_LFSx(fileio_stream_p), + .locals_dict = (mp_obj_dict_t*)&MP_VFS_LFSx(file_locals_dict), +}; +#endif + +STATIC const mp_stream_p_t MP_VFS_LFSx(textio_stream_p) = { + .read = MP_VFS_LFSx(file_read), + .write = MP_VFS_LFSx(file_write), + .ioctl = MP_VFS_LFSx(file_ioctl), + .is_text = true, +}; + +const mp_obj_type_t MP_TYPE_VFS_LFSx_(_textio) = { + { &mp_type_type }, + .name = MP_QSTR_TextIOWrapper, + .print = MP_VFS_LFSx(file_print), + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &MP_VFS_LFSx(textio_stream_p), + .locals_dict = (mp_obj_dict_t*)&MP_VFS_LFSx(file_locals_dict), +}; diff --git a/py/py.mk b/py/py.mk index b08b3f80c8..8c2d3c7b80 100644 --- a/py/py.mk +++ b/py/py.mk @@ -192,6 +192,7 @@ PY_EXTMOD_O_BASENAME = \ extmod/vfs_fat.o \ extmod/vfs_fat_diskio.o \ extmod/vfs_fat_file.o \ + extmod/vfs_lfs.o \ extmod/utime_mphal.o \ extmod/uos_dupterm.o \ lib/embed/abort_.o \ From 62d5659cdd198cf88ed9ac5a2b0aadb03a8098cb Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 18 Oct 2019 17:25:21 +1100 Subject: [PATCH 0904/1788] unix: Enable uos.VfsLfs1, uos.VfsLfs2 on coverage build. --- ports/unix/Makefile | 1 + ports/unix/moduos_vfs.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/ports/unix/Makefile b/ports/unix/Makefile index bcc76ce160..5a21bd6b2a 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -257,6 +257,7 @@ coverage: -Wold-style-definition -Wpointer-arith -Wshadow -Wuninitialized -Wunused-parameter \ -DMICROPY_UNIX_COVERAGE' \ LDFLAGS_EXTRA='-fprofile-arcs -ftest-coverage' \ + MICROPY_VFS_LFS=1 \ FROZEN_MANIFEST=manifest_coverage.py \ BUILD=build-coverage PROG=micropython_coverage diff --git a/ports/unix/moduos_vfs.c b/ports/unix/moduos_vfs.c index e9ac8e1f88..7abd0d150b 100644 --- a/ports/unix/moduos_vfs.c +++ b/ports/unix/moduos_vfs.c @@ -30,6 +30,7 @@ #include "extmod/vfs.h" #include "extmod/vfs_posix.h" #include "extmod/vfs_fat.h" +#include "extmod/vfs_lfs.h" #if MICROPY_VFS @@ -71,6 +72,10 @@ STATIC const mp_rom_map_elem_t uos_vfs_module_globals_table[] = { #if MICROPY_VFS_FAT { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) }, #endif + #if MICROPY_VFS_LFS + { MP_ROM_QSTR(MP_QSTR_VfsLfs1), MP_ROM_PTR(&mp_type_vfs_lfs1) }, + { MP_ROM_QSTR(MP_QSTR_VfsLfs2), MP_ROM_PTR(&mp_type_vfs_lfs2) }, + #endif }; STATIC MP_DEFINE_CONST_DICT(uos_vfs_module_globals, uos_vfs_module_globals_table); From 73fddb84e5b2a313170e1286013b99f23430dbed Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 18 Oct 2019 17:25:48 +1100 Subject: [PATCH 0905/1788] tests/extmod: Add littlefs tests. --- tests/extmod/vfs_lfs.py | 107 +++++++++++++++++++++++++ tests/extmod/vfs_lfs.py.exp | 46 +++++++++++ tests/extmod/vfs_lfs_corrupt.py | 106 +++++++++++++++++++++++++ tests/extmod/vfs_lfs_corrupt.py.exp | 12 +++ tests/extmod/vfs_lfs_error.py | 116 +++++++++++++++++++++++++++ tests/extmod/vfs_lfs_error.py.exp | 28 +++++++ tests/extmod/vfs_lfs_file.py | 117 ++++++++++++++++++++++++++++ tests/extmod/vfs_lfs_file.py.exp | 28 +++++++ tests/extmod/vfs_lfs_mount.py | 73 +++++++++++++++++ tests/extmod/vfs_lfs_mount.py.exp | 6 ++ 10 files changed, 639 insertions(+) create mode 100644 tests/extmod/vfs_lfs.py create mode 100644 tests/extmod/vfs_lfs.py.exp create mode 100644 tests/extmod/vfs_lfs_corrupt.py create mode 100644 tests/extmod/vfs_lfs_corrupt.py.exp create mode 100644 tests/extmod/vfs_lfs_error.py create mode 100644 tests/extmod/vfs_lfs_error.py.exp create mode 100644 tests/extmod/vfs_lfs_file.py create mode 100644 tests/extmod/vfs_lfs_file.py.exp create mode 100644 tests/extmod/vfs_lfs_mount.py create mode 100644 tests/extmod/vfs_lfs_mount.py.exp diff --git a/tests/extmod/vfs_lfs.py b/tests/extmod/vfs_lfs.py new file mode 100644 index 0000000000..46c770b437 --- /dev/null +++ b/tests/extmod/vfs_lfs.py @@ -0,0 +1,107 @@ +# Test for VfsLittle using a RAM device + +try: + import uos + uos.VfsLfs1 + uos.VfsLfs2 +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + +class RAMBlockDevice: + ERASE_BLOCK_SIZE = 1024 + + def __init__(self, blocks): + self.data = bytearray(blocks * self.ERASE_BLOCK_SIZE) + + def readblocks(self, block, buf, off): + addr = block * self.ERASE_BLOCK_SIZE + off + for i in range(len(buf)): + buf[i] = self.data[addr + i] + + def writeblocks(self, block, buf, off): + addr = block * self.ERASE_BLOCK_SIZE + off + for i in range(len(buf)): + self.data[addr + i] = buf[i] + + def ioctl(self, op, arg): + if op == 4: # block count + return len(self.data) // self.ERASE_BLOCK_SIZE + if op == 5: # block size + return self.ERASE_BLOCK_SIZE + if op == 6: # erase block + return 0 + +def test(bdev, vfs_class): + print('test', vfs_class) + + # mkfs + vfs_class.mkfs(bdev) + + # construction + vfs = vfs_class(bdev) + + # statvfs + print(vfs.statvfs('/')) + + # open, write close + f = vfs.open('test', 'w') + f.write('littlefs') + f.close() + + # statvfs after creating a file + print(vfs.statvfs('/')) + + # ilistdir + print(list(vfs.ilistdir())) + print(list(vfs.ilistdir('/'))) + print(list(vfs.ilistdir(b'/'))) + + # mkdir, rmdir + vfs.mkdir('testdir') + print(list(vfs.ilistdir())) + print(list(vfs.ilistdir('testdir'))) + vfs.rmdir('testdir') + print(list(vfs.ilistdir())) + vfs.mkdir('testdir') + + # stat a file + print(vfs.stat('test')) + + # stat a dir (size seems to vary on LFS2 so don't print that) + print(vfs.stat('testdir')[:6]) + + # read + with vfs.open('test', 'r') as f: + print(f.read()) + + # create large file + with vfs.open('testbig', 'w') as f: + data = 'large012' * 32 * 16 + print('data length:', len(data)) + for i in range(4): + print('write', i) + f.write(data) + + # stat after creating large file + print(vfs.statvfs('/')) + + # rename + vfs.rename('testbig', 'testbig2') + print(list(vfs.ilistdir())) + + # remove + vfs.remove('testbig2') + print(list(vfs.ilistdir())) + + # getcwd, chdir + print(vfs.getcwd()) + vfs.chdir('/testdir') + print(vfs.getcwd()) + vfs.chdir('/') + print(vfs.getcwd()) + vfs.rmdir('testdir') + +bdev = RAMBlockDevice(30) +test(bdev, uos.VfsLfs1) +test(bdev, uos.VfsLfs2) diff --git a/tests/extmod/vfs_lfs.py.exp b/tests/extmod/vfs_lfs.py.exp new file mode 100644 index 0000000000..c16e727b81 --- /dev/null +++ b/tests/extmod/vfs_lfs.py.exp @@ -0,0 +1,46 @@ +test +(1024, 1024, 30, 26, 26, 0, 0, 0, 0, 255) +(1024, 1024, 30, 25, 25, 0, 0, 0, 0, 255) +[('test', 32768, 0, 8)] +[('test', 32768, 0, 8)] +[(b'test', 32768, 0, 8)] +[('test', 32768, 0, 8), ('testdir', 16384, 0, 0)] +[] +[('test', 32768, 0, 8)] +(32768, 0, 0, 0, 0, 0, 8, 0, 0, 0) +(16384, 0, 0, 0, 0, 0) +littlefs +data length: 4096 +write 0 +write 1 +write 2 +write 3 +(1024, 1024, 30, 6, 6, 0, 0, 0, 0, 255) +[('test', 32768, 0, 8), ('testdir', 16384, 0, 0), ('testbig2', 32768, 0, 16384)] +[('test', 32768, 0, 8), ('testdir', 16384, 0, 0)] +/ +/testdir +/ +test +(1024, 1024, 30, 28, 28, 0, 0, 0, 0, 255) +(1024, 1024, 30, 28, 28, 0, 0, 0, 0, 255) +[('test', 32768, 0, 8)] +[('test', 32768, 0, 8)] +[(b'test', 32768, 0, 8)] +[('testdir', 16384, 0, 0), ('test', 32768, 0, 8)] +[] +[('test', 32768, 0, 8)] +(32768, 0, 0, 0, 0, 0, 8, 0, 0, 0) +(16384, 0, 0, 0, 0, 0) +littlefs +data length: 4096 +write 0 +write 1 +write 2 +write 3 +(1024, 1024, 30, 9, 9, 0, 0, 0, 0, 255) +[('testbig2', 32768, 0, 16384), ('testdir', 16384, 0, 0), ('test', 32768, 0, 8)] +[('testdir', 16384, 0, 0), ('test', 32768, 0, 8)] +/ +/testdir +/ diff --git a/tests/extmod/vfs_lfs_corrupt.py b/tests/extmod/vfs_lfs_corrupt.py new file mode 100644 index 0000000000..90c3e82163 --- /dev/null +++ b/tests/extmod/vfs_lfs_corrupt.py @@ -0,0 +1,106 @@ +# Test for VfsLittle using a RAM device, testing error handling from corrupt block device + +try: + import uos + uos.VfsLfs1 + uos.VfsLfs2 +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + +class RAMBlockDevice: + ERASE_BLOCK_SIZE = 1024 + + def __init__(self, blocks): + self.data = bytearray(blocks * self.ERASE_BLOCK_SIZE) + self.ret = 0 + + def readblocks(self, block, buf, off): + addr = block * self.ERASE_BLOCK_SIZE + off + for i in range(len(buf)): + buf[i] = self.data[addr + i] + return self.ret + + def writeblocks(self, block, buf, off): + addr = block * self.ERASE_BLOCK_SIZE + off + for i in range(len(buf)): + self.data[addr + i] = buf[i] + return self.ret + + def ioctl(self, op, arg): + if op == 4: # block count + return len(self.data) // self.ERASE_BLOCK_SIZE + if op == 5: # block size + return self.ERASE_BLOCK_SIZE + if op == 6: # erase block + return 0 + +def corrupt(bdev, block): + addr = block * bdev.ERASE_BLOCK_SIZE + for i in range(bdev.ERASE_BLOCK_SIZE): + bdev.data[addr + i] = i & 0xff + +def create_vfs(bdev, vfs_class): + bdev.ret = 0 + vfs_class.mkfs(bdev) + vfs = vfs_class(bdev) + with vfs.open('f', 'w') as f: + for i in range(100): + f.write('test') + return vfs + +def test(bdev, vfs_class): + print('test', vfs_class) + + # statvfs + vfs = create_vfs(bdev, vfs_class) + corrupt(bdev, 0) + corrupt(bdev, 1) + try: + print(vfs.statvfs('')) + except OSError: + print('statvfs OSError') + + # error during read + vfs = create_vfs(bdev, vfs_class) + f = vfs.open('f', 'r') + bdev.ret = -5 # EIO + try: + f.read(10) + except OSError: + print('read OSError') + + # error during write + vfs = create_vfs(bdev, vfs_class) + f = vfs.open('f', 'a') + bdev.ret = -5 # EIO + try: + f.write('test') + except OSError: + print('write OSError') + + # error during close + vfs = create_vfs(bdev, vfs_class) + f = vfs.open('f', 'w') + f.write('test') + bdev.ret = -5 # EIO + try: + f.close() + except OSError: + print('close OSError') + + # error during flush + vfs = create_vfs(bdev, vfs_class) + f = vfs.open('f', 'w') + f.write('test') + bdev.ret = -5 # EIO + try: + f.flush() + except OSError: + print('flush OSError') + bdev.ret = 0 + f.close() + +bdev = RAMBlockDevice(30) +test(bdev, uos.VfsLfs1) +test(bdev, uos.VfsLfs2) diff --git a/tests/extmod/vfs_lfs_corrupt.py.exp b/tests/extmod/vfs_lfs_corrupt.py.exp new file mode 100644 index 0000000000..d6f5f54252 --- /dev/null +++ b/tests/extmod/vfs_lfs_corrupt.py.exp @@ -0,0 +1,12 @@ +test +statvfs OSError +read OSError +write OSError +close OSError +flush OSError +test +statvfs OSError +read OSError +write OSError +close OSError +flush OSError diff --git a/tests/extmod/vfs_lfs_error.py b/tests/extmod/vfs_lfs_error.py new file mode 100644 index 0000000000..b97fe6ec15 --- /dev/null +++ b/tests/extmod/vfs_lfs_error.py @@ -0,0 +1,116 @@ +# Test for VfsLittle using a RAM device, testing error handling + +try: + import uos + uos.VfsLfs1 + uos.VfsLfs2 +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + +class RAMBlockDevice: + ERASE_BLOCK_SIZE = 1024 + + def __init__(self, blocks): + self.data = bytearray(blocks * self.ERASE_BLOCK_SIZE) + + def readblocks(self, block, buf, off): + addr = block * self.ERASE_BLOCK_SIZE + off + for i in range(len(buf)): + buf[i] = self.data[addr + i] + + def writeblocks(self, block, buf, off): + addr = block * self.ERASE_BLOCK_SIZE + off + for i in range(len(buf)): + self.data[addr + i] = buf[i] + + def ioctl(self, op, arg): + if op == 4: # block count + return len(self.data) // self.ERASE_BLOCK_SIZE + if op == 5: # block size + return self.ERASE_BLOCK_SIZE + if op == 6: # erase block + return 0 + +def test(bdev, vfs_class): + print('test', vfs_class) + + # mkfs with too-small block device + try: + vfs_class.mkfs(RAMBlockDevice(1)) + except OSError: + print('mkfs OSError') + + # mount with invalid filesystem + try: + vfs_class(bdev) + except OSError: + print('mount OSError') + + # set up for following tests + vfs_class.mkfs(bdev) + vfs = vfs_class(bdev) + with vfs.open('testfile', 'w') as f: + f.write('test') + vfs.mkdir('testdir') + + # ilistdir + try: + vfs.ilistdir('noexist') + except OSError: + print('ilistdir OSError') + + # remove + try: + vfs.remove('noexist') + except OSError: + print('remove OSError') + + # rmdir + try: + vfs.rmdir('noexist') + except OSError: + print('rmdir OSError') + + # rename + try: + vfs.rename('noexist', 'somethingelse') + except OSError: + print('rename OSError') + + # mkdir + try: + vfs.mkdir('testdir') + except OSError: + print('mkdir OSError') + + # chdir to nonexistent + try: + vfs.chdir('noexist') + except OSError: + print('chdir OSError') + print(vfs.getcwd()) # check still at root + + # chdir to file + try: + vfs.chdir('testfile') + except OSError: + print('chdir OSError') + print(vfs.getcwd()) # check still at root + + # stat + try: + vfs.stat('noexist') + except OSError: + print('stat OSError') + + # error during seek + with vfs.open('testfile', 'r') as f: + try: + f.seek(1 << 31) + except OSError: + print('seek OSError') + +bdev = RAMBlockDevice(30) +test(bdev, uos.VfsLfs1) +test(bdev, uos.VfsLfs2) diff --git a/tests/extmod/vfs_lfs_error.py.exp b/tests/extmod/vfs_lfs_error.py.exp new file mode 100644 index 0000000000..f4327f6962 --- /dev/null +++ b/tests/extmod/vfs_lfs_error.py.exp @@ -0,0 +1,28 @@ +test +mkfs OSError +mount OSError +ilistdir OSError +remove OSError +rmdir OSError +rename OSError +mkdir OSError +chdir OSError +/ +chdir OSError +/ +stat OSError +seek OSError +test +mkfs OSError +mount OSError +ilistdir OSError +remove OSError +rmdir OSError +rename OSError +mkdir OSError +chdir OSError +/ +chdir OSError +/ +stat OSError +seek OSError diff --git a/tests/extmod/vfs_lfs_file.py b/tests/extmod/vfs_lfs_file.py new file mode 100644 index 0000000000..477a62e2ff --- /dev/null +++ b/tests/extmod/vfs_lfs_file.py @@ -0,0 +1,117 @@ +# Test for VfsLittle using a RAM device, file IO + +try: + import uos + uos.VfsLfs1 + uos.VfsLfs2 +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + +class RAMBlockDevice: + ERASE_BLOCK_SIZE = 1024 + + def __init__(self, blocks): + self.data = bytearray(blocks * self.ERASE_BLOCK_SIZE) + + def readblocks(self, block, buf, off): + addr = block * self.ERASE_BLOCK_SIZE + off + for i in range(len(buf)): + buf[i] = self.data[addr + i] + + def writeblocks(self, block, buf, off): + addr = block * self.ERASE_BLOCK_SIZE + off + for i in range(len(buf)): + self.data[addr + i] = buf[i] + + def ioctl(self, op, arg): + if op == 4: # block count + return len(self.data) // self.ERASE_BLOCK_SIZE + if op == 5: # block size + return self.ERASE_BLOCK_SIZE + if op == 6: # erase block + return 0 + +def test(bdev, vfs_class): + print('test', vfs_class) + + # mkfs + vfs_class.mkfs(bdev) + + # construction + vfs = vfs_class(bdev) + + # create text, print, write, close + f = vfs.open('test.txt', 'wt') + print(f) + f.write('littlefs') + f.close() + + # close already-closed file + f.close() + + # create binary, print, write, flush, close + f = vfs.open('test.bin', 'wb') + print(f) + f.write('littlefs') + f.flush() + f.close() + + # create for append + f = vfs.open('test.bin', 'ab') + f.write('more') + f.close() + + # create exclusive + f = vfs.open('test2.bin', 'xb') + f.close() + + # create exclusive with error + try: + vfs.open('test2.bin', 'x') + except OSError: + print('open OSError') + + # read default + with vfs.open('test.txt', '') as f: + print(f.read()) + + # read text + with vfs.open('test.txt', 'rt') as f: + print(f.read()) + + # read binary + with vfs.open('test.bin', 'rb') as f: + print(f.read()) + + # create read and write + with vfs.open('test.bin', 'r+b') as f: + print(f.read(8)) + f.write('MORE') + with vfs.open('test.bin', 'rb') as f: + print(f.read()) + + # seek and tell + f = vfs.open('test.txt', 'r') + print(f.tell()) + f.seek(3, 0) + print(f.tell()) + f.close() + + # open nonexistent + try: + vfs.open('noexist', 'r') + except OSError: + print('open OSError') + + # open multiple files at the same time + f1 = vfs.open('test.txt', '') + f2 = vfs.open('test.bin', 'b') + print(f1.read()) + print(f2.read()) + f1.close() + f2.close() + +bdev = RAMBlockDevice(30) +test(bdev, uos.VfsLfs1) +test(bdev, uos.VfsLfs2) diff --git a/tests/extmod/vfs_lfs_file.py.exp b/tests/extmod/vfs_lfs_file.py.exp new file mode 100644 index 0000000000..55531539ec --- /dev/null +++ b/tests/extmod/vfs_lfs_file.py.exp @@ -0,0 +1,28 @@ +test + + +open OSError +littlefs +littlefs +b'littlefsmore' +b'littlefs' +b'littlefsMORE' +0 +3 +open OSError +littlefs +b'littlefsMORE' +test + + +open OSError +littlefs +littlefs +b'littlefsmore' +b'littlefs' +b'littlefsMORE' +0 +3 +open OSError +littlefs +b'littlefsMORE' diff --git a/tests/extmod/vfs_lfs_mount.py b/tests/extmod/vfs_lfs_mount.py new file mode 100644 index 0000000000..76263f4978 --- /dev/null +++ b/tests/extmod/vfs_lfs_mount.py @@ -0,0 +1,73 @@ +# Test for VfsLittle using a RAM device, with mount/umount + +try: + import uos + uos.VfsLfs1 + uos.VfsLfs2 +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + +class RAMBlockDevice: + ERASE_BLOCK_SIZE = 1024 + + def __init__(self, blocks): + self.data = bytearray(blocks * self.ERASE_BLOCK_SIZE) + + def readblocks(self, block, buf, off): + addr = block * self.ERASE_BLOCK_SIZE + off + for i in range(len(buf)): + buf[i] = self.data[addr + i] + + def writeblocks(self, block, buf, off): + addr = block * self.ERASE_BLOCK_SIZE + off + for i in range(len(buf)): + self.data[addr + i] = buf[i] + + def ioctl(self, op, arg): + if op == 4: # block count + return len(self.data) // self.ERASE_BLOCK_SIZE + if op == 5: # block size + return self.ERASE_BLOCK_SIZE + if op == 6: # erase block + return 0 + +def test(bdev, vfs_class): + print('test', vfs_class) + + # mkfs + vfs_class.mkfs(bdev) + + # construction + vfs = vfs_class(bdev) + + # mount + uos.mount(vfs, '/lfs') + + # import + with open('/lfs/lfsmod.py', 'w') as f: + f.write('print("hello from lfs")\n') + import lfsmod + + # import package + uos.mkdir('/lfs/lfspkg') + with open('/lfs/lfspkg/__init__.py', 'w') as f: + f.write('print("package")\n') + import lfspkg + + # umount + uos.umount('/lfs') + + # clear imported modules + sys.modules.clear() + +bdev = RAMBlockDevice(30) + +# initialise path +import sys +sys.path.clear() +sys.path.append('/lfs') + +# run tests +test(bdev, uos.VfsLfs1) +test(bdev, uos.VfsLfs2) diff --git a/tests/extmod/vfs_lfs_mount.py.exp b/tests/extmod/vfs_lfs_mount.py.exp new file mode 100644 index 0000000000..90aff35016 --- /dev/null +++ b/tests/extmod/vfs_lfs_mount.py.exp @@ -0,0 +1,6 @@ +test +hello from lfs +package +test +hello from lfs +package From 7c8fb27f38b06b5067d913e9d57f87005445601b Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 27 Oct 2019 20:15:29 +1100 Subject: [PATCH 0906/1788] tests/extmod: Add test for blockdev with standard and extended protocol. --- tests/extmod/vfs_blockdev.py | 70 ++++++++++++++++++++++++++++++++ tests/extmod/vfs_blockdev.py.exp | 8 ++++ 2 files changed, 78 insertions(+) create mode 100644 tests/extmod/vfs_blockdev.py create mode 100644 tests/extmod/vfs_blockdev.py.exp diff --git a/tests/extmod/vfs_blockdev.py b/tests/extmod/vfs_blockdev.py new file mode 100644 index 0000000000..d82b10610f --- /dev/null +++ b/tests/extmod/vfs_blockdev.py @@ -0,0 +1,70 @@ +# Test for behaviour of combined standard and extended block device + +try: + import uos + uos.VfsFat + uos.VfsLfs2 +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + +class RAMBlockDevice: + ERASE_BLOCK_SIZE = 512 + + def __init__(self, blocks): + self.data = bytearray(blocks * self.ERASE_BLOCK_SIZE) + + def readblocks(self, block, buf, off=0): + addr = block * self.ERASE_BLOCK_SIZE + off + for i in range(len(buf)): + buf[i] = self.data[addr + i] + + def writeblocks(self, block, buf, off=None): + if off is None: + # erase, then write + off = 0 + addr = block * self.ERASE_BLOCK_SIZE + off + for i in range(len(buf)): + self.data[addr + i] = buf[i] + + def ioctl(self, op, arg): + if op == 4: # block count + return len(self.data) // self.ERASE_BLOCK_SIZE + if op == 5: # block size + return self.ERASE_BLOCK_SIZE + if op == 6: # erase block + return 0 + +def test(bdev, vfs_class): + print('test', vfs_class) + + # mkfs + vfs_class.mkfs(bdev) + + # construction + vfs = vfs_class(bdev) + + # statvfs + print(vfs.statvfs('/')) + + # open, write close + f = vfs.open('test', 'w') + for i in range(10): + f.write('some data') + f.close() + + # ilistdir + print(list(vfs.ilistdir())) + + # read + with vfs.open('test', 'r') as f: + print(f.read()) + +try: + bdev = RAMBlockDevice(50) +except MemoryError: + print("SKIP") + raise SystemExit + +test(bdev, uos.VfsFat) +test(bdev, uos.VfsLfs2) diff --git a/tests/extmod/vfs_blockdev.py.exp b/tests/extmod/vfs_blockdev.py.exp new file mode 100644 index 0000000000..a254133131 --- /dev/null +++ b/tests/extmod/vfs_blockdev.py.exp @@ -0,0 +1,8 @@ +test +(512, 512, 16, 16, 16, 0, 0, 0, 0, 255) +[('test', 32768, 0, 90)] +some datasome datasome datasome datasome datasome datasome datasome datasome datasome data +test +(512, 512, 50, 48, 48, 0, 0, 0, 0, 255) +[('test', 32768, 0, 90)] +some datasome datasome datasome datasome datasome datasome datasome datasome datasome data From cfe1c5abf884027eb0a5792d5a980fee8757051a Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 29 Oct 2019 12:25:30 +1100 Subject: [PATCH 0907/1788] extmod/vfs: Rename BP_IOCTL_xxx constants to MP_BLOCKDEV_IOCTL_xxx. Also rename SEC_COUNT to BLOCK_COUNT and SEC_SIZE to BLOCK_SIZE. --- extmod/vfs.h | 10 +++++----- extmod/vfs_blockdev.c | 8 ++++---- extmod/vfs_fat.c | 2 +- extmod/vfs_fat_diskio.c | 8 ++++---- extmod/vfs_lfsx.c | 8 ++++---- ports/cc3200/mods/pybflash.c | 10 +++++----- ports/cc3200/mods/pybsd.c | 10 +++++----- ports/esp32/esp32_partition.c | 10 +++++----- ports/esp32/machine_sdcard.c | 10 +++++----- ports/esp8266/modules/flashbdev.py | 4 ++-- ports/stm32/sdcard.c | 10 +++++----- ports/stm32/storage.c | 10 +++++----- ports/stm32/usbd_msc_interface.c | 24 ++++++++++++------------ tests/extmod/vfs_fat_fileio1.py | 4 ++-- tests/extmod/vfs_fat_fileio2.py | 4 ++-- tests/extmod/vfs_fat_more.py | 4 ++-- tests/extmod/vfs_fat_ramdisk.py | 4 ++-- tests/extmod/vfs_fat_ramdisklarge.py | 4 ++-- 18 files changed, 72 insertions(+), 72 deletions(-) diff --git a/extmod/vfs.h b/extmod/vfs.h index 767ba3033a..15bd2a5f51 100644 --- a/extmod/vfs.h +++ b/extmod/vfs.h @@ -45,11 +45,11 @@ #define MP_BLOCKDEV_FLAG_NO_FILESYSTEM (0x0008) // the block device has no filesystem on it // constants for block protocol ioctl -#define BP_IOCTL_INIT (1) -#define BP_IOCTL_DEINIT (2) -#define BP_IOCTL_SYNC (3) -#define BP_IOCTL_SEC_COUNT (4) -#define BP_IOCTL_SEC_SIZE (5) +#define MP_BLOCKDEV_IOCTL_INIT (1) +#define MP_BLOCKDEV_IOCTL_DEINIT (2) +#define MP_BLOCKDEV_IOCTL_SYNC (3) +#define MP_BLOCKDEV_IOCTL_BLOCK_COUNT (4) +#define MP_BLOCKDEV_IOCTL_BLOCK_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 { diff --git a/extmod/vfs_blockdev.c b/extmod/vfs_blockdev.c index 916d71ca47..90675aa34f 100644 --- a/extmod/vfs_blockdev.c +++ b/extmod/vfs_blockdev.c @@ -119,20 +119,20 @@ mp_obj_t mp_vfs_blockdev_ioctl(mp_vfs_blockdev_t *self, uintptr_t cmd, uintptr_t } else { // Old protocol with sync and count switch (cmd) { - case BP_IOCTL_SYNC: + case MP_BLOCKDEV_IOCTL_SYNC: if (self->u.old.sync[0] != MP_OBJ_NULL) { mp_call_method_n_kw(0, 0, self->u.old.sync); } break; - case BP_IOCTL_SEC_COUNT: + case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: return mp_call_method_n_kw(0, 0, self->u.old.count); - case BP_IOCTL_SEC_SIZE: + case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: // Old protocol has fixed sector size of 512 bytes break; - case BP_IOCTL_INIT: + case MP_BLOCKDEV_IOCTL_INIT: // Old protocol doesn't have init break; } diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index 129b6cc669..f8cb1f5a52 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -72,7 +72,7 @@ STATIC mp_obj_t fat_vfs_make_new(const mp_obj_type_t *type, size_t n_args, size_ // Initialise underlying block device vfs->blockdev.flags = MP_BLOCKDEV_FLAG_FREE_OBJ; - vfs->blockdev.block_size = FF_MIN_SS; // default, will be populated by call to BP_IOCTL_SEC_SIZE + vfs->blockdev.block_size = FF_MIN_SS; // default, will be populated by call to MP_BLOCKDEV_IOCTL_BLOCK_SIZE mp_vfs_blockdev_init(&vfs->blockdev, args[0]); // mount the block device so the VFS methods can be used diff --git a/extmod/vfs_fat_diskio.c b/extmod/vfs_fat_diskio.c index 61a4d6da50..76a918fa38 100644 --- a/extmod/vfs_fat_diskio.c +++ b/extmod/vfs_fat_diskio.c @@ -113,10 +113,10 @@ DRESULT disk_ioctl ( // First part: call the relevant method of the underlying block device 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, + [CTRL_SYNC] = MP_BLOCKDEV_IOCTL_SYNC, + [GET_SECTOR_COUNT] = MP_BLOCKDEV_IOCTL_BLOCK_COUNT, + [GET_SECTOR_SIZE] = MP_BLOCKDEV_IOCTL_BLOCK_SIZE, + [IOCTL_INIT] = MP_BLOCKDEV_IOCTL_INIT, }; uint8_t bp_op = op_map[cmd & 7]; mp_obj_t ret = mp_const_none; diff --git a/extmod/vfs_lfsx.c b/extmod/vfs_lfsx.c index a042f5ed1e..6aa82b1ef9 100644 --- a/extmod/vfs_lfsx.c +++ b/extmod/vfs_lfsx.c @@ -56,7 +56,7 @@ STATIC int MP_VFS_LFSx(dev_erase)(const struct LFSx_API(config) *c, LFSx_API(blo } STATIC int MP_VFS_LFSx(dev_sync)(const struct LFSx_API(config) *c) { - return MP_VFS_LFSx(dev_ioctl)(c, BP_IOCTL_SYNC, 0, false); + return MP_VFS_LFSx(dev_ioctl)(c, MP_BLOCKDEV_IOCTL_SYNC, 0, false); } STATIC void MP_VFS_LFSx(init_config)(MP_OBJ_VFS_LFSx *self, mp_obj_t bdev, size_t read_size, size_t prog_size, size_t lookahead) { @@ -73,9 +73,9 @@ STATIC void MP_VFS_LFSx(init_config)(MP_OBJ_VFS_LFSx *self, mp_obj_t bdev, size_ config->erase = MP_VFS_LFSx(dev_erase); config->sync = MP_VFS_LFSx(dev_sync); - MP_VFS_LFSx(dev_ioctl)(config, BP_IOCTL_INIT, 0, false); // initialise block device - int bs = MP_VFS_LFSx(dev_ioctl)(config, BP_IOCTL_SEC_SIZE, 0, true); // get block size - int bc = MP_VFS_LFSx(dev_ioctl)(config, BP_IOCTL_SEC_COUNT, 0, true); // get block count + MP_VFS_LFSx(dev_ioctl)(config, MP_BLOCKDEV_IOCTL_INIT, 0, false); // initialise block device + int bs = MP_VFS_LFSx(dev_ioctl)(config, MP_BLOCKDEV_IOCTL_BLOCK_SIZE, 0, true); // get block size + int bc = MP_VFS_LFSx(dev_ioctl)(config, MP_BLOCKDEV_IOCTL_BLOCK_COUNT, 0, true); // get block count self->blockdev.block_size = bs; config->read_size = read_size; diff --git a/ports/cc3200/mods/pybflash.c b/ports/cc3200/mods/pybflash.c index 185913ce31..b586195213 100644 --- a/ports/cc3200/mods/pybflash.c +++ b/ports/cc3200/mods/pybflash.c @@ -69,11 +69,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_flash_writeblocks_obj, pyb_flash_writeblock STATIC mp_obj_t pyb_flash_ioctl(mp_obj_t self, mp_obj_t cmd_in, mp_obj_t arg_in) { mp_int_t cmd = mp_obj_get_int(cmd_in); switch (cmd) { - case BP_IOCTL_INIT: return MP_OBJ_NEW_SMALL_INT(sflash_disk_init() != RES_OK); - case BP_IOCTL_DEINIT: sflash_disk_flush(); return MP_OBJ_NEW_SMALL_INT(0); - case BP_IOCTL_SYNC: sflash_disk_flush(); return MP_OBJ_NEW_SMALL_INT(0); - case BP_IOCTL_SEC_COUNT: return MP_OBJ_NEW_SMALL_INT(SFLASH_SECTOR_COUNT); - case BP_IOCTL_SEC_SIZE: return MP_OBJ_NEW_SMALL_INT(SFLASH_SECTOR_SIZE); + case MP_BLOCKDEV_IOCTL_INIT: return MP_OBJ_NEW_SMALL_INT(sflash_disk_init() != RES_OK); + case MP_BLOCKDEV_IOCTL_DEINIT: sflash_disk_flush(); return MP_OBJ_NEW_SMALL_INT(0); + case MP_BLOCKDEV_IOCTL_SYNC: sflash_disk_flush(); return MP_OBJ_NEW_SMALL_INT(0); + case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: return MP_OBJ_NEW_SMALL_INT(SFLASH_SECTOR_COUNT); + case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: return MP_OBJ_NEW_SMALL_INT(SFLASH_SECTOR_SIZE); default: return mp_const_none; } } diff --git a/ports/cc3200/mods/pybsd.c b/ports/cc3200/mods/pybsd.c index c47d4e9451..e5a6e2624d 100644 --- a/ports/cc3200/mods/pybsd.c +++ b/ports/cc3200/mods/pybsd.c @@ -184,16 +184,16 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_sd_writeblocks_obj, pyb_sd_writeblocks); STATIC mp_obj_t pyb_sd_ioctl(mp_obj_t self, mp_obj_t cmd_in, mp_obj_t arg_in) { mp_int_t cmd = mp_obj_get_int(cmd_in); switch (cmd) { - case BP_IOCTL_INIT: - case BP_IOCTL_DEINIT: - case BP_IOCTL_SYNC: + case MP_BLOCKDEV_IOCTL_INIT: + case MP_BLOCKDEV_IOCTL_DEINIT: + case MP_BLOCKDEV_IOCTL_SYNC: // nothing to do return MP_OBJ_NEW_SMALL_INT(0); // success - case BP_IOCTL_SEC_COUNT: + case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: return MP_OBJ_NEW_SMALL_INT(sd_disk_info.ulNofBlock * (sd_disk_info.ulBlockSize / 512)); - case BP_IOCTL_SEC_SIZE: + case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: return MP_OBJ_NEW_SMALL_INT(SD_SECTOR_SIZE); default: // unknown command diff --git a/ports/esp32/esp32_partition.c b/ports/esp32/esp32_partition.c index 49bb0632e3..52b3859ff0 100644 --- a/ports/esp32/esp32_partition.c +++ b/ports/esp32/esp32_partition.c @@ -173,11 +173,11 @@ STATIC mp_obj_t esp32_partition_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_ esp32_partition_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_int_t cmd = mp_obj_get_int(cmd_in); switch (cmd) { - case BP_IOCTL_INIT: return MP_OBJ_NEW_SMALL_INT(0); - case BP_IOCTL_DEINIT: return MP_OBJ_NEW_SMALL_INT(0); - case BP_IOCTL_SYNC: return MP_OBJ_NEW_SMALL_INT(0); - case BP_IOCTL_SEC_COUNT: return MP_OBJ_NEW_SMALL_INT(self->part->size / BLOCK_SIZE_BYTES); - case BP_IOCTL_SEC_SIZE: return MP_OBJ_NEW_SMALL_INT(BLOCK_SIZE_BYTES); + case MP_BLOCKDEV_IOCTL_INIT: return MP_OBJ_NEW_SMALL_INT(0); + case MP_BLOCKDEV_IOCTL_DEINIT: return MP_OBJ_NEW_SMALL_INT(0); + case MP_BLOCKDEV_IOCTL_SYNC: return MP_OBJ_NEW_SMALL_INT(0); + case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: return MP_OBJ_NEW_SMALL_INT(self->part->size / BLOCK_SIZE_BYTES); + case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: return MP_OBJ_NEW_SMALL_INT(BLOCK_SIZE_BYTES); default: return mp_const_none; } } diff --git a/ports/esp32/machine_sdcard.c b/ports/esp32/machine_sdcard.c index 1400c56f35..8639e4104c 100644 --- a/ports/esp32/machine_sdcard.c +++ b/ports/esp32/machine_sdcard.c @@ -337,26 +337,26 @@ STATIC mp_obj_t machine_sdcard_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t mp_int_t cmd = mp_obj_get_int(cmd_in); switch (cmd) { - case BP_IOCTL_INIT: + case MP_BLOCKDEV_IOCTL_INIT: err = sdcard_ensure_card_init(self, false); return MP_OBJ_NEW_SMALL_INT((err == ESP_OK) ? 0 : -1); - case BP_IOCTL_DEINIT: + case MP_BLOCKDEV_IOCTL_DEINIT: // Ensure that future attempts to look at info re-read the card self->flags &= ~SDCARD_CARD_FLAGS_CARD_INIT_DONE; return MP_OBJ_NEW_SMALL_INT(0); // success - case BP_IOCTL_SYNC: + case MP_BLOCKDEV_IOCTL_SYNC: // nothing to do return MP_OBJ_NEW_SMALL_INT(0); // success - case BP_IOCTL_SEC_COUNT: + case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: err = sdcard_ensure_card_init(self, false); if (err != ESP_OK) return MP_OBJ_NEW_SMALL_INT(-1); return MP_OBJ_NEW_SMALL_INT(self->card.csd.capacity); - case BP_IOCTL_SEC_SIZE: + case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: err = sdcard_ensure_card_init(self, false); if (err != ESP_OK) return MP_OBJ_NEW_SMALL_INT(-1); diff --git a/ports/esp8266/modules/flashbdev.py b/ports/esp8266/modules/flashbdev.py index 40ba655c64..80ddcfbf91 100644 --- a/ports/esp8266/modules/flashbdev.py +++ b/ports/esp8266/modules/flashbdev.py @@ -22,9 +22,9 @@ class FlashBdev: def ioctl(self, op, arg): #print("ioctl(%d, %r)" % (op, arg)) - if op == 4: # BP_IOCTL_SEC_COUNT + if op == 4: # MP_BLOCKDEV_IOCTL_BLOCK_COUNT return self.blocks - if op == 5: # BP_IOCTL_SEC_SIZE + if op == 5: # MP_BLOCKDEV_IOCTL_BLOCK_SIZE return self.SEC_SIZE size = esp.flash_size() diff --git a/ports/stm32/sdcard.c b/ports/stm32/sdcard.c index da9c1c681a..c6832ceb80 100644 --- a/ports/stm32/sdcard.c +++ b/ports/stm32/sdcard.c @@ -812,24 +812,24 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_sdcard_writeblocks_obj, pyb_sdcard_writeblo STATIC mp_obj_t pyb_sdcard_ioctl(mp_obj_t self, mp_obj_t cmd_in, mp_obj_t arg_in) { mp_int_t cmd = mp_obj_get_int(cmd_in); switch (cmd) { - case BP_IOCTL_INIT: + case MP_BLOCKDEV_IOCTL_INIT: if (!sdcard_power_on()) { return MP_OBJ_NEW_SMALL_INT(-1); // error } return MP_OBJ_NEW_SMALL_INT(0); // success - case BP_IOCTL_DEINIT: + case MP_BLOCKDEV_IOCTL_DEINIT: sdcard_power_off(); return MP_OBJ_NEW_SMALL_INT(0); // success - case BP_IOCTL_SYNC: + case MP_BLOCKDEV_IOCTL_SYNC: // nothing to do return MP_OBJ_NEW_SMALL_INT(0); // success - case BP_IOCTL_SEC_COUNT: + case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: return MP_OBJ_NEW_SMALL_INT(sdcard_get_capacity_in_bytes() / SDCARD_BLOCK_SIZE); - case BP_IOCTL_SEC_SIZE: + case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: return MP_OBJ_NEW_SMALL_INT(SDCARD_BLOCK_SIZE); default: // unknown command diff --git a/ports/stm32/storage.c b/ports/stm32/storage.c index 7685f6f175..d9d5464855 100644 --- a/ports/stm32/storage.c +++ b/ports/stm32/storage.c @@ -263,11 +263,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_flash_writeblocks_obj, pyb_flash_writeblock STATIC mp_obj_t pyb_flash_ioctl(mp_obj_t self, mp_obj_t cmd_in, mp_obj_t arg_in) { mp_int_t cmd = mp_obj_get_int(cmd_in); switch (cmd) { - case BP_IOCTL_INIT: storage_init(); return MP_OBJ_NEW_SMALL_INT(0); - case BP_IOCTL_DEINIT: storage_flush(); return MP_OBJ_NEW_SMALL_INT(0); // TODO properly - case BP_IOCTL_SYNC: storage_flush(); return MP_OBJ_NEW_SMALL_INT(0); - case BP_IOCTL_SEC_COUNT: return MP_OBJ_NEW_SMALL_INT(storage_get_block_count()); - case BP_IOCTL_SEC_SIZE: return MP_OBJ_NEW_SMALL_INT(storage_get_block_size()); + case MP_BLOCKDEV_IOCTL_INIT: storage_init(); return MP_OBJ_NEW_SMALL_INT(0); + case MP_BLOCKDEV_IOCTL_DEINIT: storage_flush(); return MP_OBJ_NEW_SMALL_INT(0); // TODO properly + case MP_BLOCKDEV_IOCTL_SYNC: storage_flush(); return MP_OBJ_NEW_SMALL_INT(0); + case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: return MP_OBJ_NEW_SMALL_INT(storage_get_block_count()); + case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: return MP_OBJ_NEW_SMALL_INT(storage_get_block_size()); default: return mp_const_none; } } diff --git a/ports/stm32/usbd_msc_interface.c b/ports/stm32/usbd_msc_interface.c index 7f563004b8..2f5e7aa7d3 100644 --- a/ports/stm32/usbd_msc_interface.c +++ b/ports/stm32/usbd_msc_interface.c @@ -121,17 +121,17 @@ STATIC int lu_ioctl(uint8_t lun, int op, uint32_t *data) { if (lu == &pyb_flash_type) { switch (op) { - case BP_IOCTL_INIT: + case MP_BLOCKDEV_IOCTL_INIT: storage_init(); *data = 0; return 0; - case BP_IOCTL_SYNC: + case MP_BLOCKDEV_IOCTL_SYNC: storage_flush(); return 0; - case BP_IOCTL_SEC_SIZE: + case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: *data = storage_get_block_size(); return 0; - case BP_IOCTL_SEC_COUNT: + case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: *data = storage_get_block_count(); return 0; default: @@ -144,18 +144,18 @@ STATIC int lu_ioctl(uint8_t lun, int op, uint32_t *data) { #endif ) { switch (op) { - case BP_IOCTL_INIT: + case MP_BLOCKDEV_IOCTL_INIT: if (!sdcard_power_on()) { return -1; } *data = 0; return 0; - case BP_IOCTL_SYNC: + case MP_BLOCKDEV_IOCTL_SYNC: return 0; - case BP_IOCTL_SEC_SIZE: + case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: *data = SDCARD_BLOCK_SIZE; return 0; - case BP_IOCTL_SEC_COUNT: + case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: *data = sdcard_get_capacity_in_bytes() / (uint64_t)SDCARD_BLOCK_SIZE; return 0; default: @@ -174,7 +174,7 @@ STATIC int8_t usbd_msc_Init(uint8_t lun_in) { } for (int lun = 0; lun < usbd_msc_lu_num; ++lun) { uint32_t data = 0; - int res = lu_ioctl(lun, BP_IOCTL_INIT, &data); + int res = lu_ioctl(lun, MP_BLOCKDEV_IOCTL_INIT, &data); if (res != 0) { lu_flag_clr(lun, FLAGS_STARTED); } else { @@ -234,12 +234,12 @@ STATIC int usbd_msc_Inquiry(uint8_t lun, const uint8_t *params, uint8_t *data_ou // Get storage capacity of a logical unit STATIC int8_t usbd_msc_GetCapacity(uint8_t lun, uint32_t *block_num, uint16_t *block_size) { uint32_t block_size_u32 = 0; - int res = lu_ioctl(lun, BP_IOCTL_SEC_SIZE, &block_size_u32); + int res = lu_ioctl(lun, MP_BLOCKDEV_IOCTL_BLOCK_SIZE, &block_size_u32); if (res != 0) { return -1; } *block_size = block_size_u32; - return lu_ioctl(lun, BP_IOCTL_SEC_COUNT, block_num); + return lu_ioctl(lun, MP_BLOCKDEV_IOCTL_BLOCK_COUNT, block_num); } // Check if a logical unit is ready @@ -275,7 +275,7 @@ STATIC int8_t usbd_msc_StartStopUnit(uint8_t lun, uint8_t started) { STATIC int8_t usbd_msc_PreventAllowMediumRemoval(uint8_t lun, uint8_t param) { uint32_t dummy; // Sync the logical unit so the device can be unplugged/turned off - return lu_ioctl(lun, BP_IOCTL_SYNC, &dummy); + return lu_ioctl(lun, MP_BLOCKDEV_IOCTL_SYNC, &dummy); } // Read data from a logical unit diff --git a/tests/extmod/vfs_fat_fileio1.py b/tests/extmod/vfs_fat_fileio1.py index 51cd765222..d0a5e4b73c 100644 --- a/tests/extmod/vfs_fat_fileio1.py +++ b/tests/extmod/vfs_fat_fileio1.py @@ -31,9 +31,9 @@ class RAMFS: def ioctl(self, op, arg): #print("ioctl(%d, %r)" % (op, arg)) - if op == 4: # BP_IOCTL_SEC_COUNT + if op == 4: # MP_BLOCKDEV_IOCTL_BLOCK_COUNT return len(self.data) // self.SEC_SIZE - if op == 5: # BP_IOCTL_SEC_SIZE + if op == 5: # MP_BLOCKDEV_IOCTL_BLOCK_SIZE return self.SEC_SIZE diff --git a/tests/extmod/vfs_fat_fileio2.py b/tests/extmod/vfs_fat_fileio2.py index 9b9a11e435..6721f9b934 100644 --- a/tests/extmod/vfs_fat_fileio2.py +++ b/tests/extmod/vfs_fat_fileio2.py @@ -31,9 +31,9 @@ class RAMFS: def ioctl(self, op, arg): #print("ioctl(%d, %r)" % (op, arg)) - if op == 4: # BP_IOCTL_SEC_COUNT + if op == 4: # MP_BLOCKDEV_IOCTL_BLOCK_COUNT return len(self.data) // self.SEC_SIZE - if op == 5: # BP_IOCTL_SEC_SIZE + if op == 5: # MP_BLOCKDEV_IOCTL_BLOCK_SIZE return self.SEC_SIZE diff --git a/tests/extmod/vfs_fat_more.py b/tests/extmod/vfs_fat_more.py index 488697fa85..9505fd3282 100644 --- a/tests/extmod/vfs_fat_more.py +++ b/tests/extmod/vfs_fat_more.py @@ -30,9 +30,9 @@ class RAMFS: def ioctl(self, op, arg): #print("ioctl(%d, %r)" % (op, arg)) - if op == 4: # BP_IOCTL_SEC_COUNT + if op == 4: # MP_BLOCKDEV_IOCTL_BLOCK_COUNT return len(self.data) // self.SEC_SIZE - if op == 5: # BP_IOCTL_SEC_SIZE + if op == 5: # MP_BLOCKDEV_IOCTL_BLOCK_SIZE return self.SEC_SIZE diff --git a/tests/extmod/vfs_fat_ramdisk.py b/tests/extmod/vfs_fat_ramdisk.py index f6e5c64df0..11b2df7f42 100644 --- a/tests/extmod/vfs_fat_ramdisk.py +++ b/tests/extmod/vfs_fat_ramdisk.py @@ -31,9 +31,9 @@ class RAMFS: def ioctl(self, op, arg): #print("ioctl(%d, %r)" % (op, arg)) - if op == 4: # BP_IOCTL_SEC_COUNT + if op == 4: # MP_BLOCKDEV_IOCTL_BLOCK_COUNT return len(self.data) // self.SEC_SIZE - if op == 5: # BP_IOCTL_SEC_SIZE + if op == 5: # MP_BLOCKDEV_IOCTL_BLOCK_SIZE return self.SEC_SIZE diff --git a/tests/extmod/vfs_fat_ramdisklarge.py b/tests/extmod/vfs_fat_ramdisklarge.py index 6f95910315..4ac52b257f 100644 --- a/tests/extmod/vfs_fat_ramdisklarge.py +++ b/tests/extmod/vfs_fat_ramdisklarge.py @@ -39,9 +39,9 @@ class RAMBDevSparse: def ioctl(self, op, arg): #print("ioctl(%d, %r)" % (op, arg)) - if op == 4: # BP_IOCTL_SEC_COUNT + if op == 4: # MP_BLOCKDEV_IOCTL_BLOCK_COUNT return self.blocks - if op == 5: # BP_IOCTL_SEC_SIZE + if op == 5: # MP_BLOCKDEV_IOCTL_BLOCK_SIZE return self.SEC_SIZE From 4cf054a130e90bec19399ef2b8181d434dd22d8e Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 29 Oct 2019 12:29:56 +1100 Subject: [PATCH 0908/1788] extmod/vfs: Add MP_BLOCKDEV_IOCTL_BLOCK_ERASE constant. --- extmod/vfs.h | 1 + extmod/vfs_lfsx.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/extmod/vfs.h b/extmod/vfs.h index 15bd2a5f51..004b002f55 100644 --- a/extmod/vfs.h +++ b/extmod/vfs.h @@ -50,6 +50,7 @@ #define MP_BLOCKDEV_IOCTL_SYNC (3) #define MP_BLOCKDEV_IOCTL_BLOCK_COUNT (4) #define MP_BLOCKDEV_IOCTL_BLOCK_SIZE (5) +#define MP_BLOCKDEV_IOCTL_BLOCK_ERASE (6) // At the moment the VFS protocol just has import_stat, but could be extended to other methods typedef struct _mp_vfs_proto_t { diff --git a/extmod/vfs_lfsx.c b/extmod/vfs_lfsx.c index 6aa82b1ef9..e5826803b2 100644 --- a/extmod/vfs_lfsx.c +++ b/extmod/vfs_lfsx.c @@ -52,7 +52,7 @@ STATIC int MP_VFS_LFSx(dev_prog)(const struct LFSx_API(config) *c, LFSx_API(bloc } STATIC int MP_VFS_LFSx(dev_erase)(const struct LFSx_API(config) *c, LFSx_API(block_t) block) { - return MP_VFS_LFSx(dev_ioctl)(c, 6, block, true); // erase + return MP_VFS_LFSx(dev_ioctl)(c, MP_BLOCKDEV_IOCTL_BLOCK_ERASE, block, true); } STATIC int MP_VFS_LFSx(dev_sync)(const struct LFSx_API(config) *c) { From 7a24b7f0911c8632651616601f02e746eea1c73c Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 29 Oct 2019 12:32:56 +1100 Subject: [PATCH 0909/1788] docs/library: Add documentation for extended block device protocol. --- docs/library/uos.rst | 60 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/docs/library/uos.rst b/docs/library/uos.rst index 58ac83b2b1..d8d8b7a972 100644 --- a/docs/library/uos.rst +++ b/docs/library/uos.rst @@ -187,25 +187,51 @@ 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. +There are two compatible signatures for the ``readblocks`` and ``writeblocks`` +methods (see below), in order to support a variety of use cases. A given block +device may implement one form or the other, or both at the same time. + .. class:: AbstractBlockDev(...) Construct a block device object. The parameters to the constructor are dependent on the specific block device. .. method:: readblocks(block_num, buf) + .. method:: readblocks(block_num, buf, offset) + The first form reads aligned, multiples of blocks. Starting at the block given by the index *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) + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + .. method:: writeblocks(block_num, buf) + .. method:: writeblocks(block_num, buf, offset) + + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. Starting at the block given by the index *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. + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + .. method:: ioctl(op, arg) Control the block device and query its parameters. The operation to @@ -219,6 +245,7 @@ used by a particular filesystem driver to store the data for its filesystem. - 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) + - 6 -- erase a block, *arg* is the block number to erase By way of example, the following class will implement a block device that stores its data in RAM using a ``bytearray``:: @@ -250,3 +277,34 @@ It can be used as follows:: uos.VfsFat.mkfs(bdev) vfs = uos.VfsFat(bdev) uos.mount(vfs, '/ramdisk') + +An example of a block device that supports both signatures and behaviours of +the :meth:`readblocks` and :meth:`writeblocks` methods is:: + + 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, buf, offset=0): + addr = block_num * self.block_size + offset + for i in range(len(buf)): + buf[i] = self.data[addr + i] + + def writeblocks(self, block_num, buf, offset=None): + if offset is None: + # do erase, then write + for i in range(len(buf) // self.block_size): + self.ioctl(6, block_num + i) + offset = 0 + addr = block_num * self.block_size + offset + for i in range(len(buf)): + self.data[addr + i] = buf[i] + + def ioctl(self, op, arg): + if op == 4: # block count + return len(self.data) // self.block_size + if op == 5: # block size + return self.block_size + if op == 6: # block erase + return 0 From 4847460232764a116b731da077074818e316fb55 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 18 Oct 2019 15:41:36 +1100 Subject: [PATCH 0910/1788] unix/mphalport.h: Define mp_hal_stdio_poll to dummy because it's unused. And requires uintptr_t to declare the default version in py/mphal.h. --- ports/unix/mphalport.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/unix/mphalport.h b/ports/unix/mphalport.h index ff7a51567c..e3e045aed1 100644 --- a/ports/unix/mphalport.h +++ b/ports/unix/mphalport.h @@ -31,6 +31,7 @@ void mp_hal_set_interrupt_char(char c); +#define mp_hal_stdio_poll unused // this is not implemented, nor needed void mp_hal_stdio_mode_raw(void); void mp_hal_stdio_mode_orig(void); From 709136e844f93eb7b9ea8c14e9daa5da8e8293d3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 18 Oct 2019 19:18:06 +1100 Subject: [PATCH 0911/1788] tests/basics: Use str.format instead of % for formatting messages. Only use % formatting when testing % itself, because only str.format is guaranteed to be available on any port. --- tests/basics/async_await2.py | 2 +- tests/basics/class_inplace_op.py | 4 ++-- tests/basics/class_notimpl.py | 2 +- tests/basics/class_reverse_op.py | 2 +- tests/basics/string_repr.py | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/basics/async_await2.py b/tests/basics/async_await2.py index 129d3751a5..1e3164df93 100644 --- a/tests/basics/async_await2.py +++ b/tests/basics/async_await2.py @@ -11,7 +11,7 @@ else: @coroutine def wait(value): print('wait value:', value) - msg = yield 'message from wait(%u)' % value + msg = yield 'message from wait({})'.format(value) print('wait got back:', msg) return 10 diff --git a/tests/basics/class_inplace_op.py b/tests/basics/class_inplace_op.py index 62aad8c7cf..8885bdaa85 100644 --- a/tests/basics/class_inplace_op.py +++ b/tests/basics/class_inplace_op.py @@ -10,7 +10,7 @@ class A: return A(self.v + o.v) def __repr__(self): - return "A(%s)" % self.v + return "A({})".format(self.v) a = A(5) b = a @@ -37,7 +37,7 @@ class L: return self def __repr__(self): - return "L(%s)" % self.v + return "L({})".format(self.v) c = L([1, 2]) d = c diff --git a/tests/basics/class_notimpl.py b/tests/basics/class_notimpl.py index 7fd8166f90..308075f92f 100644 --- a/tests/basics/class_notimpl.py +++ b/tests/basics/class_notimpl.py @@ -11,7 +11,7 @@ class C: self.value = value def __str__(self): - return "C(%s)" % self.value + return "C({})".format(self.value) def __add__(self, rhs): print(self, '+', rhs) diff --git a/tests/basics/class_reverse_op.py b/tests/basics/class_reverse_op.py index d41c55c9d7..b0dae5f8a3 100644 --- a/tests/basics/class_reverse_op.py +++ b/tests/basics/class_reverse_op.py @@ -12,7 +12,7 @@ class A: return A(self.v + o) def __repr__(self): - return "A(%s)" % self.v + return "A({})".format(self.v) print(A(3) + 1) print(2 + A(5)) diff --git a/tests/basics/string_repr.py b/tests/basics/string_repr.py index 2a3ef2527c..b4842e1475 100644 --- a/tests/basics/string_repr.py +++ b/tests/basics/string_repr.py @@ -1,4 +1,4 @@ # anything above 0xa0 is printed as Unicode by CPython # the abobe is CPython implementation detail, stick to ASCII for c in range(0x80): - print("0x%02x: %s" % (c, repr(chr(c)))) + print("0x{:02x}: {}".format(c, repr(chr(c)))) From 7a49fc387c2ecbc374967f1ebc221770c2ca4b7a Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 18 Oct 2019 19:26:30 +1100 Subject: [PATCH 0912/1788] tests/basics/builtin_dir.py: Look for "version" in dir(sys). Because "version" will always be there, but "exit" may not. --- tests/basics/builtin_dir.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/basics/builtin_dir.py b/tests/basics/builtin_dir.py index c15a76f4c6..1eecbd044b 100644 --- a/tests/basics/builtin_dir.py +++ b/tests/basics/builtin_dir.py @@ -5,7 +5,7 @@ print('__name__' in dir()) # dir of module import sys -print('exit' in dir(sys)) +print('version' in dir(sys)) # dir of type print('append' in dir(list)) From 6e9ba1cf4b0cd8e2986e9abe9a8a66c43a43c63a Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 18 Oct 2019 19:48:15 +1100 Subject: [PATCH 0913/1788] tests: Add feature check for bytearray and skip corresponding tests. --- tests/feature_check/bytearray.py | 5 +++++ tests/feature_check/bytearray.py.exp | 0 tests/run-tests | 8 ++++++++ 3 files changed, 13 insertions(+) create mode 100644 tests/feature_check/bytearray.py create mode 100644 tests/feature_check/bytearray.py.exp diff --git a/tests/feature_check/bytearray.py b/tests/feature_check/bytearray.py new file mode 100644 index 0000000000..601ef4597c --- /dev/null +++ b/tests/feature_check/bytearray.py @@ -0,0 +1,5 @@ +try: + bytearray + print("bytearray") +except NameError: + print("no") diff --git a/tests/feature_check/bytearray.py.exp b/tests/feature_check/bytearray.py.exp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/run-tests b/tests/run-tests index b22d067192..9e98125797 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -221,6 +221,7 @@ def run_tests(pyb, tests, args, base_path="."): skip_tests = set() skip_native = False skip_int_big = False + skip_bytearray = False skip_set_type = False skip_async = False skip_const = False @@ -244,6 +245,11 @@ def run_tests(pyb, tests, args, base_path="."): if output != b'1000000000000000000000000000000000000000000000\n': skip_int_big = True + # Check if bytearray is supported, and skip such tests if it's not + output = run_feature_check(pyb, args, base_path, 'bytearray.py') + if output != b'bytearray\n': + skip_bytearray = True + # Check if set type (and set literals) is supported, and skip such tests if it's not output = run_feature_check(pyb, args, base_path, 'set_check.py') if output == b'CRASH': @@ -397,6 +403,7 @@ def run_tests(pyb, tests, args, base_path="."): is_native = test_name.startswith("native_") or test_name.startswith("viper_") is_endian = test_name.endswith("_endian") is_int_big = test_name.startswith("int_big") or test_name.endswith("_intbig") + is_bytearray = test_name.startswith("bytearray") or test_name.endswith("_bytearray") is_set_type = test_name.startswith("set_") or test_name.startswith("frozenset") is_async = test_name.startswith("async_") is_const = test_name.startswith("const") @@ -405,6 +412,7 @@ def run_tests(pyb, tests, args, base_path="."): skip_it |= skip_native and is_native skip_it |= skip_endian and is_endian skip_it |= skip_int_big and is_int_big + skip_it |= skip_bytearray and is_bytearray skip_it |= skip_set_type and is_set_type skip_it |= skip_async and is_async skip_it |= skip_const and is_const From aeea204e9802d6a175d94bdb03de428b5f1c74d1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 29 Oct 2019 21:24:51 +1100 Subject: [PATCH 0914/1788] tests/basics: Split out specific bytearray tests to separate files. So they can be automatically skipped if bytearray is not enabled. --- tests/basics/bytes_add.py | 2 -- tests/basics/bytes_add_bytearray.py | 5 +++++ tests/basics/bytes_compare2.py | 4 ---- tests/basics/bytes_compare_bytearray.py | 4 ++++ tests/basics/bytes_construct.py | 3 +-- tests/basics/bytes_construct_bytearray.py | 3 +++ tests/basics/op_error.py | 14 -------------- tests/basics/op_error_bytearray.py | 19 +++++++++++++++++++ 8 files changed, 32 insertions(+), 22 deletions(-) create mode 100644 tests/basics/bytes_add_bytearray.py create mode 100644 tests/basics/bytes_compare_bytearray.py create mode 100644 tests/basics/bytes_construct_bytearray.py create mode 100644 tests/basics/op_error_bytearray.py diff --git a/tests/basics/bytes_add.py b/tests/basics/bytes_add.py index ebccf0662d..ab027a26df 100644 --- a/tests/basics/bytes_add.py +++ b/tests/basics/bytes_add.py @@ -1,8 +1,6 @@ # test bytes + other print(b"123" + b"456") -print(b"123" + bytearray(2)) print(b"123" + b"") # RHS is empty, can be optimised print(b"" + b"123") # LHS is empty, can be optimised -print(b"" + bytearray(1)) # LHS is empty but can't be optimised diff --git a/tests/basics/bytes_add_bytearray.py b/tests/basics/bytes_add_bytearray.py new file mode 100644 index 0000000000..4998800b51 --- /dev/null +++ b/tests/basics/bytes_add_bytearray.py @@ -0,0 +1,5 @@ +# test bytes + bytearray + +print(b"123" + bytearray(2)) + +print(b"" + bytearray(1)) # LHS is empty but can't be optimised diff --git a/tests/basics/bytes_compare2.py b/tests/basics/bytes_compare2.py index 4d5de21d21..8559685378 100644 --- a/tests/basics/bytes_compare2.py +++ b/tests/basics/bytes_compare2.py @@ -1,5 +1 @@ print(b"1" == 1) -print(b"123" == bytearray(b"123")) -print(b'123' < bytearray(b"124")) -print(b'123' > bytearray(b"122")) -print(bytearray(b"23") in b"1234") diff --git a/tests/basics/bytes_compare_bytearray.py b/tests/basics/bytes_compare_bytearray.py new file mode 100644 index 0000000000..6a8d8b8a51 --- /dev/null +++ b/tests/basics/bytes_compare_bytearray.py @@ -0,0 +1,4 @@ +print(b"123" == bytearray(b"123")) +print(b'123' < bytearray(b"124")) +print(b'123' > bytearray(b"122")) +print(bytearray(b"23") in b"1234") diff --git a/tests/basics/bytes_construct.py b/tests/basics/bytes_construct.py index 0d638c08f2..6f83f1cb20 100644 --- a/tests/basics/bytes_construct.py +++ b/tests/basics/bytes_construct.py @@ -1,9 +1,8 @@ # test construction of bytes from different objects -# tuple, list, bytearray +# tuple, list print(bytes((1, 2))) print(bytes([1, 2])) -print(bytes(bytearray(4))) # constructor value out of range try: diff --git a/tests/basics/bytes_construct_bytearray.py b/tests/basics/bytes_construct_bytearray.py new file mode 100644 index 0000000000..75f08acd3b --- /dev/null +++ b/tests/basics/bytes_construct_bytearray.py @@ -0,0 +1,3 @@ +# test construction of bytes from bytearray + +print(bytes(bytearray(4))) diff --git a/tests/basics/op_error.py b/tests/basics/op_error.py index 7b4f896e14..63c35db3f5 100644 --- a/tests/basics/op_error.py +++ b/tests/basics/op_error.py @@ -13,10 +13,6 @@ try: ~[] except TypeError: print('TypeError') -try: - ~bytearray() -except TypeError: - print('TypeError') # unsupported binary operators try: @@ -31,16 +27,6 @@ try: 1 in 1 except TypeError: print('TypeError') -try: - bytearray() // 2 -except TypeError: - print('TypeError') - -# object with buffer protocol needed on rhs -try: - bytearray(1) + 1 -except TypeError: - print('TypeError') # unsupported subscription try: diff --git a/tests/basics/op_error_bytearray.py b/tests/basics/op_error_bytearray.py new file mode 100644 index 0000000000..9ab69371d2 --- /dev/null +++ b/tests/basics/op_error_bytearray.py @@ -0,0 +1,19 @@ +# test errors from bad operations (unary, binary, etc) + +# unsupported unary operators +try: + ~bytearray() +except TypeError: + print('TypeError') + +# unsupported binary operators +try: + bytearray() // 2 +except TypeError: + print('TypeError') + +# object with buffer protocol needed on rhs +try: + bytearray(1) + 1 +except TypeError: + print('TypeError') From 9162a87d4d21ce7f682e5d4ae7703fa1b13f45e9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 29 Oct 2019 21:25:38 +1100 Subject: [PATCH 0915/1788] tests/basics: Use bytes not bytearray when checking user buffer proto. Using bytes will test the same path for the buffer protocol in py/objtype.c. --- tests/basics/class_misc.py | 2 +- tests/basics/subclass_native_buffer.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/basics/class_misc.py b/tests/basics/class_misc.py index 82b9b3479e..34b1a3bc64 100644 --- a/tests/basics/class_misc.py +++ b/tests/basics/class_misc.py @@ -4,6 +4,6 @@ class C: c = C() try: - d = bytearray(c) + d = bytes(c) except TypeError: print('TypeError') diff --git a/tests/basics/subclass_native_buffer.py b/tests/basics/subclass_native_buffer.py index 43c3819657..00717a70e7 100644 --- a/tests/basics/subclass_native_buffer.py +++ b/tests/basics/subclass_native_buffer.py @@ -12,5 +12,5 @@ print(b1 + b2) print(b1 + b3) print(b3 + b1) -# bytearray construction will use the buffer protocol -print(bytearray(b1)) +# bytes construction will use the buffer protocol +print(bytes(b1)) From ecb77e40e079c6caef1391f48ff1ba7fab8fa68d Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 29 Oct 2019 21:44:22 +1100 Subject: [PATCH 0916/1788] tests: Add feature check for slice and skip corresponding tests. --- tests/feature_check/slice.py | 5 +++++ tests/feature_check/slice.py.exp | 0 tests/run-tests | 8 ++++++++ 3 files changed, 13 insertions(+) create mode 100644 tests/feature_check/slice.py create mode 100644 tests/feature_check/slice.py.exp diff --git a/tests/feature_check/slice.py b/tests/feature_check/slice.py new file mode 100644 index 0000000000..cdd42701af --- /dev/null +++ b/tests/feature_check/slice.py @@ -0,0 +1,5 @@ +try: + slice + print("slice") +except NameError: + print("no") diff --git a/tests/feature_check/slice.py.exp b/tests/feature_check/slice.py.exp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/run-tests b/tests/run-tests index 9e98125797..0fb72f3f68 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -223,6 +223,7 @@ def run_tests(pyb, tests, args, base_path="."): skip_int_big = False skip_bytearray = False skip_set_type = False + skip_slice = False skip_async = False skip_const = False skip_revops = False @@ -255,6 +256,11 @@ def run_tests(pyb, tests, args, base_path="."): if output == b'CRASH': skip_set_type = True + # Check if slice is supported, and skip such tests if it's not + output = run_feature_check(pyb, args, base_path, 'slice.py') + if output != b'slice\n': + skip_slice = True + # Check if async/await keywords are supported, and skip such tests if it's not output = run_feature_check(pyb, args, base_path, 'async_check.py') if output == b'CRASH': @@ -405,6 +411,7 @@ def run_tests(pyb, tests, args, base_path="."): is_int_big = test_name.startswith("int_big") or test_name.endswith("_intbig") is_bytearray = test_name.startswith("bytearray") or test_name.endswith("_bytearray") is_set_type = test_name.startswith("set_") or test_name.startswith("frozenset") + is_slice = test_name.find("slice") != -1 is_async = test_name.startswith("async_") is_const = test_name.startswith("const") @@ -414,6 +421,7 @@ def run_tests(pyb, tests, args, base_path="."): skip_it |= skip_int_big and is_int_big skip_it |= skip_bytearray and is_bytearray skip_it |= skip_set_type and is_set_type + skip_it |= skip_slice and is_slice skip_it |= skip_async and is_async skip_it |= skip_const and is_const skip_it |= skip_revops and test_name.startswith("class_reverse_op") From b5186c9271d85c1105309ad4bf8c7d68b0d8efa7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 29 Oct 2019 21:44:48 +1100 Subject: [PATCH 0917/1788] tests/basics: Split out specific slice tests to separate files. So they can be automatically skipped if slice is not enabled. --- tests/basics/list1.py | 4 ---- tests/basics/list_slice.py | 5 +++++ tests/basics/tuple1.py | 4 ---- tests/basics/tuple_slice.py | 7 +++++++ 4 files changed, 12 insertions(+), 8 deletions(-) create mode 100644 tests/basics/tuple_slice.py diff --git a/tests/basics/list1.py b/tests/basics/list1.py index fa426c0e58..0697c9e3a7 100644 --- a/tests/basics/list1.py +++ b/tests/basics/list1.py @@ -19,10 +19,6 @@ print(x) x += [2, 1] print(x) -print(x[1:]) -print(x[:-1]) -print(x[2:3]) - # unsupported type on RHS of add try: [] + None diff --git a/tests/basics/list_slice.py b/tests/basics/list_slice.py index fc08e580a1..6b2d2ad059 100644 --- a/tests/basics/list_slice.py +++ b/tests/basics/list_slice.py @@ -1,6 +1,11 @@ # test list slices, getting values x = list(range(10)) + +print(x[1:]) +print(x[:-1]) +print(x[2:3]) + a = 2 b = 4 c = 3 diff --git a/tests/basics/tuple1.py b/tests/basics/tuple1.py index a7956c1072..72bb3f01bf 100644 --- a/tests/basics/tuple1.py +++ b/tests/basics/tuple1.py @@ -11,10 +11,6 @@ try: except AttributeError: print("AttributeError") -print(x[1:]) -print(x[:-1]) -print(x[2:3]) - print(x + (10, 100, 10000)) # inplace add operator diff --git a/tests/basics/tuple_slice.py b/tests/basics/tuple_slice.py new file mode 100644 index 0000000000..1b11957c7a --- /dev/null +++ b/tests/basics/tuple_slice.py @@ -0,0 +1,7 @@ +# tuple slicing + +x = (1, 2, 3 * 4) + +print(x[1:]) +print(x[:-1]) +print(x[2:3]) From 52299ed3f011b50feb58c226764e08a995fad305 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 29 Oct 2019 22:01:17 +1100 Subject: [PATCH 0918/1788] tests/run-tests: Add misc list of tests that use slice, to skip them. --- tests/run-tests | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tests/run-tests b/tests/run-tests index 0fb72f3f68..5a2086c5a8 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -288,6 +288,22 @@ def run_tests(pyb, tests, args, base_path="."): cpy_byteorder = subprocess.check_output([CPYTHON3, base_path + '/feature_check/byteorder.py']) skip_endian = (upy_byteorder != cpy_byteorder) + # These tests don't test slice explicitly but rather use it to perform the test + misc_slice_tests = ( + 'builtin_range', + 'class_super', + 'containment', + 'errno1', + 'fun_str', + 'generator1', + 'globals_del', + 'memoryview1', + 'memoryview_gc', + 'object1', + 'python34', + 'struct_endian', + ) + # Some tests shouldn't be run under Travis CI if os.getenv('TRAVIS') == 'true': skip_tests.add('basics/memoryerror.py') @@ -411,7 +427,7 @@ def run_tests(pyb, tests, args, base_path="."): is_int_big = test_name.startswith("int_big") or test_name.endswith("_intbig") is_bytearray = test_name.startswith("bytearray") or test_name.endswith("_bytearray") is_set_type = test_name.startswith("set_") or test_name.startswith("frozenset") - is_slice = test_name.find("slice") != -1 + is_slice = test_name.find("slice") != -1 or test_name in misc_slice_tests is_async = test_name.startswith("async_") is_const = test_name.startswith("const") From eebffb2b5b46dae65eeef8290146112348415221 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 29 Oct 2019 22:01:47 +1100 Subject: [PATCH 0919/1788] tests/basics: Automatically skip tests that use str/bytes modulo-format. --- tests/basics/bytes_format_modulo.py | 7 +++++++ tests/basics/string_format_modulo.py | 6 ++++++ tests/basics/string_format_modulo_int.py | 6 ++++++ 3 files changed, 19 insertions(+) diff --git a/tests/basics/bytes_format_modulo.py b/tests/basics/bytes_format_modulo.py index 70246e72dc..b928f593e0 100644 --- a/tests/basics/bytes_format_modulo.py +++ b/tests/basics/bytes_format_modulo.py @@ -1,4 +1,11 @@ # This test requires CPython3.5 + +try: + b'' % () +except TypeError: + print("SKIP") + raise SystemExit + print(b"%%" % ()) print(b"=%d=" % 1) print(b"=%d=%d=" % (1, 2)) diff --git a/tests/basics/string_format_modulo.py b/tests/basics/string_format_modulo.py index 77bbcfbe36..021b5f08d2 100644 --- a/tests/basics/string_format_modulo.py +++ b/tests/basics/string_format_modulo.py @@ -1,3 +1,9 @@ +try: + '' % () +except TypeError: + print("SKIP") + raise SystemExit + print("%%" % ()) print("=%s=" % 1) print("=%s=%s=" % (1, 2)) diff --git a/tests/basics/string_format_modulo_int.py b/tests/basics/string_format_modulo_int.py index d1f29db220..d057522bfc 100644 --- a/tests/basics/string_format_modulo_int.py +++ b/tests/basics/string_format_modulo_int.py @@ -1,5 +1,11 @@ # test string modulo formatting with int values +try: + '' % () +except TypeError: + print("SKIP") + raise SystemExit + # basic cases print("%d" % 10) print("%+d" % 10) From 1d511152467ad2d21f874c9bbe05f8f117424d3e Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 29 Oct 2019 22:13:38 +1100 Subject: [PATCH 0920/1788] tests: Add feature check for uio module and skip corresponding tests. --- tests/feature_check/uio_module.py | 5 +++++ tests/feature_check/uio_module.py.exp | 0 tests/run-tests | 8 ++++++++ 3 files changed, 13 insertions(+) create mode 100644 tests/feature_check/uio_module.py create mode 100644 tests/feature_check/uio_module.py.exp diff --git a/tests/feature_check/uio_module.py b/tests/feature_check/uio_module.py new file mode 100644 index 0000000000..1031cba909 --- /dev/null +++ b/tests/feature_check/uio_module.py @@ -0,0 +1,5 @@ +try: + import uio + print("uio") +except ImportError: + print("no") diff --git a/tests/feature_check/uio_module.py.exp b/tests/feature_check/uio_module.py.exp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/run-tests b/tests/run-tests index 5a2086c5a8..77667c2711 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -227,6 +227,7 @@ def run_tests(pyb, tests, args, base_path="."): skip_async = False skip_const = False skip_revops = False + skip_io_module = False skip_endian = False has_complex = True has_coverage = False @@ -276,6 +277,11 @@ def run_tests(pyb, tests, args, base_path="."): if output == b'TypeError\n': skip_revops = True + # Check if uio module exists, and skip such tests if it doesn't + output = run_feature_check(pyb, args, base_path, 'uio_module.py') + if output != b'uio\n': + skip_io_module = True + # Check if emacs repl is supported, and skip such tests if it's not t = run_feature_check(pyb, args, base_path, 'repl_emacs_check.py') if not 'True' in str(t, 'ascii'): @@ -430,6 +436,7 @@ def run_tests(pyb, tests, args, base_path="."): is_slice = test_name.find("slice") != -1 or test_name in misc_slice_tests is_async = test_name.startswith("async_") is_const = test_name.startswith("const") + is_io_module = test_name.startswith("io_") skip_it = test_file in skip_tests skip_it |= skip_native and is_native @@ -441,6 +448,7 @@ def run_tests(pyb, tests, args, base_path="."): skip_it |= skip_async and is_async skip_it |= skip_const and is_const skip_it |= skip_revops and test_name.startswith("class_reverse_op") + skip_it |= skip_io_module and is_io_module if args.list_tests: if not skip_it: From 943dd33b5fd36c54990ccebbd6fc30189d5373ac Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 29 Oct 2019 22:16:19 +1100 Subject: [PATCH 0921/1788] tests/basics: Split sys.exit test to separate file so it can be skipped. --- tests/basics/sys1.py | 15 --------------- tests/basics/sys_exit.py | 24 ++++++++++++++++++++++++ 2 files changed, 24 insertions(+), 15 deletions(-) create mode 100644 tests/basics/sys_exit.py diff --git a/tests/basics/sys1.py b/tests/basics/sys1.py index 30e36f81a8..ab91380246 100644 --- a/tests/basics/sys1.py +++ b/tests/basics/sys1.py @@ -18,18 +18,3 @@ try: except AttributeError: # Effectively skip subtests print(True) - -try: - raise SystemExit -except SystemExit as e: - print("SystemExit", e.args) - -try: - sys.exit() -except SystemExit as e: - print("SystemExit", e.args) - -try: - sys.exit(42) -except SystemExit as e: - print("SystemExit", e.args) diff --git a/tests/basics/sys_exit.py b/tests/basics/sys_exit.py new file mode 100644 index 0000000000..b1f71549db --- /dev/null +++ b/tests/basics/sys_exit.py @@ -0,0 +1,24 @@ +# test sys module's exit function + +import sys + +try: + sys.exit +except AttributeError: + print("SKIP") + raise SystemExit + +try: + raise SystemExit +except SystemExit as e: + print("SystemExit", e.args) + +try: + sys.exit() +except SystemExit as e: + print("SystemExit", e.args) + +try: + sys.exit(42) +except SystemExit as e: + print("SystemExit", e.args) From 162016ad9c824df023e9870fd8d072e806d5ad96 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 29 Oct 2019 22:23:00 +1100 Subject: [PATCH 0922/1788] travis: Add job to build and test unix minimal port. To test that unix minimal port builds, and that test-suite can run with minimal features enabled. --- .travis.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.travis.yml b/.travis.yml index 5923cb2b96..0f57bc3fe8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -128,6 +128,13 @@ jobs: after_failure: - (cd tests && for exp in *.exp; do testbase=$(basename $exp .exp); echo -e "\nFAILURE $testbase"; diff -u $testbase.exp $testbase.out; done) + # minimal unix port with tests + - stage: test + env: NAME="minimal unix port build and tests" + script: + - make ${MAKEOPTS} -C ports/unix minimal + - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_minimal ./run-tests -e exception_chain -e self_type_check -e subclass_native_init -d basics) + # windows port via mingw - stage: test env: NAME="windows port build via mingw" From a8138b75b1d3ca8af01e4ad717c6cdb3f733c61d Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 29 Oct 2019 22:53:34 +1100 Subject: [PATCH 0923/1788] examples/embedding: Replace symlink of mpconfigport.h with real file. --- examples/embedding/mpconfigport.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 120000 => 100644 examples/embedding/mpconfigport.h diff --git a/examples/embedding/mpconfigport.h b/examples/embedding/mpconfigport.h deleted file mode 120000 index 142e5d6f43..0000000000 --- a/examples/embedding/mpconfigport.h +++ /dev/null @@ -1 +0,0 @@ -mpconfigport_minimal.h \ No newline at end of file diff --git a/examples/embedding/mpconfigport.h b/examples/embedding/mpconfigport.h new file mode 100644 index 0000000000..89c180b2a8 --- /dev/null +++ b/examples/embedding/mpconfigport.h @@ -0,0 +1 @@ +#include "mpconfigport_minimal.h" From 53f3cbc2c4f07236fe022c9c7af20b33443c60b1 Mon Sep 17 00:00:00 2001 From: Kamil Klimek Date: Fri, 25 Oct 2019 17:28:29 +0200 Subject: [PATCH 0924/1788] zephyr/main: Use mp_stack API instead of local pointer for stack top. The MP_STATE_THREAD(stack_top) is always available so use it instead of creating a separate variable. This also allows gc_collect() to be used as an independent function, without real_main() being called. --- ports/zephyr/main.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ports/zephyr/main.c b/ports/zephyr/main.c index a28fb37923..00dc71e28b 100644 --- a/ports/zephyr/main.c +++ b/ports/zephyr/main.c @@ -48,7 +48,6 @@ #include TEST #endif -static char *stack_top; static char heap[MICROPY_HEAP_SIZE]; void init_zephyr(void) { @@ -79,9 +78,7 @@ void init_zephyr(void) { } int real_main(void) { - int stack_dummy; - stack_top = (char*)&stack_dummy; - mp_stack_set_top(stack_top); + mp_stack_ctrl_init(); // Make MicroPython's stack limit somewhat smaller than full stack available mp_stack_set_limit(CONFIG_MAIN_STACK_SIZE - 512); @@ -130,7 +127,7 @@ void gc_collect(void) { // pointers from CPU registers, and thus may function incorrectly. void *dummy; gc_collect_start(); - gc_collect_root(&dummy, ((mp_uint_t)stack_top - (mp_uint_t)&dummy) / sizeof(mp_uint_t)); + gc_collect_root(&dummy, ((mp_uint_t)MP_STATE_THREAD(stack_top) - (mp_uint_t)&dummy) / sizeof(mp_uint_t)); gc_collect_end(); //gc_dump_info(); } From d16a27da5197e2369611bef4f18b47c183880510 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 28 Oct 2019 17:27:31 +1100 Subject: [PATCH 0925/1788] extmod/modbluetooth: Add gatts_set_buffer. - Adds an explicit way to set the size of a value's internal buffer, replacing `ble.gatts_write(handle, bytes(size))` (although that still works). - Add an "append" mode for values, which means that remote writes will append to the buffer. --- extmod/modbluetooth.c | 9 +++++++++ extmod/modbluetooth.h | 4 ++++ extmod/modbluetooth_nimble.c | 31 +++++++++++++++++++++++++++++-- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index d1a7d576e1..1e5eafc895 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -557,6 +557,14 @@ STATIC mp_obj_t bluetooth_ble_gatts_notify(size_t n_args, const mp_obj_t *args) } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gatts_notify_obj, 3, 4, bluetooth_ble_gatts_notify); +STATIC mp_obj_t bluetooth_ble_gatts_set_buffer(size_t n_args, const mp_obj_t *args) { + mp_int_t value_handle = mp_obj_get_int(args[1]); + mp_int_t len = mp_obj_get_int(args[2]); + bool append = n_args >= 4 && mp_obj_is_true(args[3]); + return bluetooth_handle_errno(mp_bluetooth_gatts_set_buffer(value_handle, len, append)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gatts_set_buffer_obj, 3, 4, bluetooth_ble_gatts_set_buffer); + // ---------------------------------------------------------------------------- // Bluetooth object: GATTC (Central/Scanner role) // ---------------------------------------------------------------------------- @@ -626,6 +634,7 @@ STATIC const mp_rom_map_elem_t bluetooth_ble_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_gatts_read), MP_ROM_PTR(&bluetooth_ble_gatts_read_obj) }, { MP_ROM_QSTR(MP_QSTR_gatts_write), MP_ROM_PTR(&bluetooth_ble_gatts_write_obj) }, { MP_ROM_QSTR(MP_QSTR_gatts_notify), MP_ROM_PTR(&bluetooth_ble_gatts_notify_obj) }, + { MP_ROM_QSTR(MP_QSTR_gatts_set_buffer), MP_ROM_PTR(&bluetooth_ble_gatts_set_buffer_obj) }, #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE // GATT Client (i.e. central/scanner role) { MP_ROM_QSTR(MP_QSTR_gattc_discover_services), MP_ROM_PTR(&bluetooth_ble_gattc_discover_services_obj) }, diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h index 20476b183c..bce28a6d15 100644 --- a/extmod/modbluetooth.h +++ b/extmod/modbluetooth.h @@ -183,6 +183,10 @@ int mp_bluetooth_gatts_notify_send(uint16_t conn_handle, uint16_t value_handle, // Indicate the central. int mp_bluetooth_gatts_indicate(uint16_t conn_handle, uint16_t value_handle); +// Resize and enable/disable append-mode on a value. +// Append-mode means that remote writes will append and local reads will clear after reading. +int mp_bluetooth_gatts_set_buffer(uint16_t value_handle, size_t len, bool append); + // Disconnect from a central or peripheral. int mp_bluetooth_gap_disconnect(uint16_t conn_handle); diff --git a/extmod/modbluetooth_nimble.c b/extmod/modbluetooth_nimble.c index 6287ca89ee..33dac5a425 100644 --- a/extmod/modbluetooth_nimble.c +++ b/extmod/modbluetooth_nimble.c @@ -154,9 +154,14 @@ STATIC ble_addr_t create_nimble_addr(uint8_t addr_type, const uint8_t *addr) { #endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE typedef struct { + // Pointer to heap-allocated data. uint8_t *data; + // Allocated size of data. size_t data_alloc; + // Current bytes in use. size_t data_len; + // Whether new writes append or replace existing data (default false). + bool append; } gatts_db_entry_t; volatile int mp_bluetooth_nimble_ble_state = MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF; @@ -206,6 +211,7 @@ STATIC void create_gatts_db_entry(uint16_t handle) { entry->data = m_new(uint8_t, MP_BLUETOOTH_MAX_ATTR_SIZE); entry->data_alloc = MP_BLUETOOTH_MAX_ATTR_SIZE; entry->data_len = 0; + entry->append = false; elem->value = MP_OBJ_FROM_PTR(entry); } @@ -430,8 +436,13 @@ static int characteristic_access_cb(uint16_t conn_handle, uint16_t value_handle, return BLE_ATT_ERR_ATTR_NOT_FOUND; } entry = MP_OBJ_TO_PTR(elem->value); - entry->data_len = MIN(entry->data_alloc, OS_MBUF_PKTLEN(ctxt->om)); - os_mbuf_copydata(ctxt->om, 0, entry->data_len, entry->data); + + size_t offset = 0; + if (entry->append) { + offset = entry->data_len; + } + entry->data_len = MIN(entry->data_alloc, OS_MBUF_PKTLEN(ctxt->om) + offset); + os_mbuf_copydata(ctxt->om, 0, entry->data_len - offset, entry->data + offset); mp_bluetooth_gatts_on_write(conn_handle, value_handle); @@ -547,6 +558,9 @@ int mp_bluetooth_gatts_read(uint16_t value_handle, uint8_t **value, size_t *valu gatts_db_entry_t *entry = MP_OBJ_TO_PTR(elem->value); *value = entry->data; *value_len = entry->data_len; + if (entry->append) { + entry->data_len = 0; + } return 0; } @@ -587,6 +601,19 @@ int mp_bluetooth_gatts_indicate(uint16_t conn_handle, uint16_t value_handle) { return ble_hs_err_to_errno(ble_gattc_indicate(conn_handle, value_handle)); } +int mp_bluetooth_gatts_set_buffer(uint16_t value_handle, size_t len, bool append) { + mp_map_elem_t *elem = mp_map_lookup(MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db, MP_OBJ_NEW_SMALL_INT(value_handle), MP_MAP_LOOKUP); + if (!elem) { + return MP_EINVAL; + } + gatts_db_entry_t *entry = MP_OBJ_TO_PTR(elem->value); + entry->data = m_renew(uint8_t, entry->data, entry->data_alloc, len); + entry->data_alloc = len; + entry->data_len = 0; + entry->append = append; + return 0; +} + #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE STATIC int gap_scan_cb(struct ble_gap_event *event, void *arg) { From ca3d4c84e4722edefde586d7978f5a216c8febad Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 28 Oct 2019 17:29:08 +1100 Subject: [PATCH 0926/1788] docs/library/ubluetooth: Add docs for gatts_set_buffer. --- docs/library/ubluetooth.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/library/ubluetooth.rst b/docs/library/ubluetooth.rst index 831c64a95f..5d44ffdb29 100644 --- a/docs/library/ubluetooth.rst +++ b/docs/library/ubluetooth.rst @@ -246,6 +246,17 @@ writes from a central to a given characteristic, use of the notification, avoiding the need for a separate read request. Note that this will not update the local value stored. +.. method:: BLE.gatts_set_buffer(value_handle, len, append=False) + + Sets the internal buffer size for a value in bytes. This will limit the + largest possible write that can be received. The default is 20. + + Setting *append* to ``True`` will make all remote writes append to, rather + than replace, the current value. At most *len* bytes can be buffered in + this way. When you use :meth:`gatts_read `, the value will + be cleared after reading. This feature is useful when implementing something + like the Nordic UART Service. + Central Role (GATT Client) -------------------------- From 25946d1ef4c20439368b37ec27acf2184b25be28 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 28 Oct 2019 17:33:29 +1100 Subject: [PATCH 0927/1788] examples/bluetooth/ble_uart_peripheral: Use append mode for RX char. --- examples/bluetooth/ble_uart_peripheral.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/bluetooth/ble_uart_peripheral.py b/examples/bluetooth/ble_uart_peripheral.py index 90cdbcaf52..14f7102725 100644 --- a/examples/bluetooth/ble_uart_peripheral.py +++ b/examples/bluetooth/ble_uart_peripheral.py @@ -22,8 +22,8 @@ class BLEUART: self._ble.active(True) self._ble.irq(handler=self._irq) ((self._tx_handle, self._rx_handle,),) = self._ble.gatts_register_services((_UART_SERVICE,)) - # Increase the size of the rx buffer. - self._ble.gatts_write(self._rx_handle, bytes(rxbuf)) + # Increase the size of the rx buffer and enable append mode. + self._ble.gatts_set_buffer(self._rx_handle, rxbuf, True) self._connections = set() self._rx_buffer = bytearray() self._handler = None From 323d47887f0e407b6560a5957ea934049e70d2aa Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 29 Oct 2019 12:08:07 +1100 Subject: [PATCH 0928/1788] py/runtime: Reorder some binary ops so they don't require conditionals. runtime0.h is part of the MicroPython ABI so it's simpler if it's independent of config options, like MICROPY_PY_REVERSE_SPECIAL_METHODS. What's effectively done here is to move MP_BINARY_OP_DIVMOD and MP_BINARY_OP_CONTAINS up in the enum, then remove the #if MICROPY_PY_REVERSE_SPECIAL_METHODS conditional. Without this change .mpy files would need to have a feature flag for MICROPY_PY_REVERSE_SPECIAL_METHODS (when embedding native code that uses this enum). This commit has no effect when MICROPY_PY_REVERSE_SPECIAL_METHODS is disabled. With this option enabled this commit reduces code size by about 60 bytes. --- py/runtime.c | 13 +++++++------ py/runtime0.h | 52 ++++++++++++++++++++++++++------------------------- 2 files changed, 34 insertions(+), 31 deletions(-) diff --git a/py/runtime.c b/py/runtime.c index 6b7a9ce3c6..deb82e9355 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -570,16 +570,17 @@ generic_binary_op: } #if MICROPY_PY_REVERSE_SPECIAL_METHODS - if (op >= MP_BINARY_OP_OR && op <= MP_BINARY_OP_REVERSE_POWER) { + if (op >= MP_BINARY_OP_OR && op <= MP_BINARY_OP_POWER) { mp_obj_t t = rhs; rhs = lhs; lhs = t; - if (op <= MP_BINARY_OP_POWER) { - op += MP_BINARY_OP_REVERSE_OR - MP_BINARY_OP_OR; - goto generic_binary_op; - } - + op += MP_BINARY_OP_REVERSE_OR - MP_BINARY_OP_OR; + goto generic_binary_op; + } else if (op >= MP_BINARY_OP_REVERSE_OR) { // Convert __rop__ back to __op__ for error message + mp_obj_t t = rhs; + rhs = lhs; + lhs = t; op -= MP_BINARY_OP_REVERSE_OR - MP_BINARY_OP_OR; } #endif diff --git a/py/runtime0.h b/py/runtime0.h index 797ae00e60..364f237f66 100644 --- a/py/runtime0.h +++ b/py/runtime0.h @@ -46,6 +46,18 @@ #define MP_NATIVE_TYPE_PTR16 (0x06) #define MP_NATIVE_TYPE_PTR32 (0x07) +// Bytecode and runtime boundaries for unary ops +#define MP_UNARY_OP_NUM_BYTECODE (MP_UNARY_OP_NOT + 1) +#define MP_UNARY_OP_NUM_RUNTIME (MP_UNARY_OP_SIZEOF + 1) + +// Bytecode and runtime boundaries for binary ops +#define MP_BINARY_OP_NUM_BYTECODE (MP_BINARY_OP_POWER + 1) +#if MICROPY_PY_REVERSE_SPECIAL_METHODS +#define MP_BINARY_OP_NUM_RUNTIME (MP_BINARY_OP_REVERSE_POWER + 1) +#else +#define MP_BINARY_OP_NUM_RUNTIME (MP_BINARY_OP_CONTAINS + 1) +#endif + typedef enum { // These ops may appear in the bytecode. Changing this group // in any way requires changing the bytecode version. @@ -55,21 +67,18 @@ typedef enum { MP_UNARY_OP_NOT, // Following ops cannot appear in the bytecode - MP_UNARY_OP_NUM_BYTECODE, - - MP_UNARY_OP_BOOL = MP_UNARY_OP_NUM_BYTECODE, // __bool__ + MP_UNARY_OP_BOOL, // __bool__ MP_UNARY_OP_LEN, // __len__ MP_UNARY_OP_HASH, // __hash__; must return a small int MP_UNARY_OP_ABS, // __abs__ MP_UNARY_OP_INT, // __int__ MP_UNARY_OP_SIZEOF, // for sys.getsizeof() - - MP_UNARY_OP_NUM_RUNTIME, } mp_unary_op_t; -// Note: the first 9+12+12 of these are used in bytecode and changing -// them requires changing the bytecode version. typedef enum { + // The following 9+13+13 ops are used in bytecode and changing + // them requires changing the bytecode version. + // 9 relational operations, should return a bool; order of first 6 matches corresponding mp_token_kind_t MP_BINARY_OP_LESS, MP_BINARY_OP_MORE, @@ -113,11 +122,18 @@ typedef enum { // Operations below this line don't appear in bytecode, they // just identify special methods. - MP_BINARY_OP_NUM_BYTECODE, - // MP_BINARY_OP_REVERSE_* must follow immediately after MP_BINARY_OP_* -#if MICROPY_PY_REVERSE_SPECIAL_METHODS - MP_BINARY_OP_REVERSE_OR = MP_BINARY_OP_NUM_BYTECODE, + // This is not emitted by the compiler but is supported by the runtime. + // It must follow immediately after MP_BINARY_OP_POWER. + MP_BINARY_OP_DIVMOD, + + // 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, + + // 13 MP_BINARY_OP_REVERSE_* operations must be in the same order as MP_BINARY_OP_*, + // and be the last ones supported by the runtime. + MP_BINARY_OP_REVERSE_OR, MP_BINARY_OP_REVERSE_XOR, MP_BINARY_OP_REVERSE_AND, MP_BINARY_OP_REVERSE_LSHIFT, @@ -130,20 +146,6 @@ typedef enum { MP_BINARY_OP_REVERSE_TRUE_DIVIDE, MP_BINARY_OP_REVERSE_MODULO, MP_BINARY_OP_REVERSE_POWER, -#endif - - // This is not emitted by the compiler but is supported by the runtime - MP_BINARY_OP_DIVMOD - #if !MICROPY_PY_REVERSE_SPECIAL_METHODS - = MP_BINARY_OP_NUM_BYTECODE - #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 MP_BINARY_OP_NOT_IN, From 660a61a38830b67cb4f2b6f921d1db60f51c41a4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 30 Oct 2019 12:08:58 +1100 Subject: [PATCH 0929/1788] extmod/vfs_lfs: Allow compiling in VfsLfs1 and VfsLfs2 separately. These classes are enabled via the config options MICROPY_VFS_LFS1 and MICROPY_VFS_LFS2, which are disabled by default. --- extmod/extmod.mk | 15 +++++++++++---- extmod/vfs_lfs.c | 12 ++++++++++-- ports/unix/Makefile | 2 +- ports/unix/moduos_vfs.c | 4 +++- 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/extmod/extmod.mk b/extmod/extmod.mk index 8e63b25f90..e714b60287 100644 --- a/extmod/extmod.mk +++ b/extmod/extmod.mk @@ -6,14 +6,21 @@ CFLAGS_MOD += -DFFCONF_H=\"lib/oofatfs/ffconf.h\" ################################################################################ # VFS littlefs -ifeq ($(MICROPY_VFS_LFS),1) -CFLAGS_MOD += -DMICROPY_VFS_LFS=1 -CFLAGS_MOD += -DLFS1_NO_MALLOC -DLFS1_NO_DEBUG -DLFS1_NO_WARN -DLFS1_NO_ERROR -DLFS1_NO_ASSERT -CFLAGS_MOD += -DLFS2_NO_MALLOC -DLFS2_NO_DEBUG -DLFS2_NO_WARN -DLFS2_NO_ERROR -DLFS2_NO_ASSERT LITTLEFS_DIR = lib/littlefs + +ifeq ($(MICROPY_VFS_LFS1),1) +CFLAGS_MOD += -DMICROPY_VFS_LFS1=1 +CFLAGS_MOD += -DLFS1_NO_MALLOC -DLFS1_NO_DEBUG -DLFS1_NO_WARN -DLFS1_NO_ERROR -DLFS1_NO_ASSERT SRC_MOD += $(addprefix $(LITTLEFS_DIR)/,\ lfs1.c \ lfs1_util.c \ + ) +endif + +ifeq ($(MICROPY_VFS_LFS2),1) +CFLAGS_MOD += -DMICROPY_VFS_LFS2=1 +CFLAGS_MOD += -DLFS2_NO_MALLOC -DLFS2_NO_DEBUG -DLFS2_NO_WARN -DLFS2_NO_ERROR -DLFS2_NO_ASSERT +SRC_MOD += $(addprefix $(LITTLEFS_DIR)/,\ lfs2.c \ lfs2_util.c \ ) diff --git a/extmod/vfs_lfs.c b/extmod/vfs_lfs.c index 72f501abbf..d776849980 100644 --- a/extmod/vfs_lfs.c +++ b/extmod/vfs_lfs.c @@ -28,7 +28,7 @@ #include "extmod/vfs.h" #include "extmod/vfs_lfs.h" -#if MICROPY_VFS && MICROPY_VFS_LFS +#if MICROPY_VFS && (MICROPY_VFS_LFS1 || MICROPY_VFS_LFS2) enum { LFS_MAKE_ARG_bdev, LFS_MAKE_ARG_readsize, LFS_MAKE_ARG_progsize, LFS_MAKE_ARG_lookahead }; @@ -39,6 +39,8 @@ static const mp_arg_t lfs_make_allowed_args[] = { { MP_QSTR_lookahead, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} }, }; +#if MICROPY_VFS_LFS1 + #include "lib/littlefs/lfs1.h" #define LFS_BUILD_VERSION (1) @@ -81,6 +83,10 @@ mp_obj_t mp_vfs_lfs1_file_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode #undef MP_TYPE_VFS_LFSx #undef MP_TYPE_VFS_LFSx_ +#endif // MICROPY_VFS_LFS1 + +#if MICROPY_VFS_LFS2 + #include "lib/littlefs/lfs2.h" #define LFS_BUILD_VERSION (2) @@ -114,4 +120,6 @@ mp_obj_t mp_vfs_lfs2_file_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode #include "extmod/vfs_lfsx.c" #include "extmod/vfs_lfsx_file.c" -#endif // MICROPY_VFS && MICROPY_VFS_LFS +#endif // MICROPY_VFS_LFS2 + +#endif // MICROPY_VFS && (MICROPY_VFS_LFS1 || MICROPY_VFS_LFS2) diff --git a/ports/unix/Makefile b/ports/unix/Makefile index 5a21bd6b2a..9a4453261c 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -257,7 +257,7 @@ coverage: -Wold-style-definition -Wpointer-arith -Wshadow -Wuninitialized -Wunused-parameter \ -DMICROPY_UNIX_COVERAGE' \ LDFLAGS_EXTRA='-fprofile-arcs -ftest-coverage' \ - MICROPY_VFS_LFS=1 \ + MICROPY_VFS_LFS1=1 MICROPY_VFS_LFS2=1 \ FROZEN_MANIFEST=manifest_coverage.py \ BUILD=build-coverage PROG=micropython_coverage diff --git a/ports/unix/moduos_vfs.c b/ports/unix/moduos_vfs.c index 7abd0d150b..7f38e6a8e0 100644 --- a/ports/unix/moduos_vfs.c +++ b/ports/unix/moduos_vfs.c @@ -72,8 +72,10 @@ STATIC const mp_rom_map_elem_t uos_vfs_module_globals_table[] = { #if MICROPY_VFS_FAT { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) }, #endif - #if MICROPY_VFS_LFS + #if MICROPY_VFS_LFS1 { MP_ROM_QSTR(MP_QSTR_VfsLfs1), MP_ROM_PTR(&mp_type_vfs_lfs1) }, + #endif + #if MICROPY_VFS_LFS2 { MP_ROM_QSTR(MP_QSTR_VfsLfs2), MP_ROM_PTR(&mp_type_vfs_lfs2) }, #endif }; From 4e1b03d45c4d6be9ad9615f63a1146c46a4136d7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 30 Oct 2019 12:14:52 +1100 Subject: [PATCH 0930/1788] lib/libc/string0: Add simple implementations of strspn and strcspn. They are needed for littlefs. --- lib/libc/string0.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lib/libc/string0.c b/lib/libc/string0.c index c2f2abd0f9..8c86bf65f7 100644 --- a/lib/libc/string0.c +++ b/lib/libc/string0.c @@ -217,3 +217,19 @@ char *strstr(const char *haystack, const char *needle) return (char *) haystack; return 0; } + +size_t strspn(const char *s, const char *accept) { + const char *ss = s; + while (*s && strchr(accept, *s) != NULL) { + ++s; + } + return s - ss; +} + +size_t strcspn(const char *s, const char *reject) { + const char *ss = s; + while (*s && strchr(reject, *s) == NULL) { + ++s; + } + return s - ss; +} From 9ec73aedb4fedafce93a018c26cfbc79686be34b Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 31 Oct 2019 12:49:18 +1100 Subject: [PATCH 0931/1788] stm32/timer: Fix Timer.freq() calc so mult doesn't overflow uint32_t. Fixes issue #5280. --- ports/stm32/timer.c | 20 +++++++++++++------- tests/pyb/timer.py | 6 ++++++ tests/pyb/timer.py.exp | 2 ++ 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/ports/stm32/timer.c b/ports/stm32/timer.c index 3b9f1dc400..834ebd9c85 100644 --- a/ports/stm32/timer.c +++ b/ports/stm32/timer.c @@ -1269,15 +1269,21 @@ STATIC mp_obj_t pyb_timer_freq(size_t n_args, const mp_obj_t *args) { uint32_t prescaler = self->tim.Instance->PSC & 0xffff; 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)); + uint32_t divide_a = prescaler + 1; + uint32_t divide_b = period + 1; #if MICROPY_PY_BUILTINS_FLOAT - if (source_freq % divide != 0) { - return mp_obj_new_float((float)source_freq / (float)divide); - } else - #endif - { - return mp_obj_new_int(source_freq / divide); + if (source_freq % divide_a != 0) { + return mp_obj_new_float((mp_float_t)source_freq / (mp_float_t)divide_a / (mp_float_t)divide_b); } + source_freq /= divide_a; + if (source_freq % divide_b != 0) { + return mp_obj_new_float((mp_float_t)source_freq / (mp_float_t)divide_b); + } else { + return mp_obj_new_int(source_freq / divide_b); + } + #else + return mp_obj_new_int(source_freq / divide_a / divide_b); + #endif } else { // set uint32_t period; diff --git a/tests/pyb/timer.py b/tests/pyb/timer.py index 61320690a6..e83550abd8 100644 --- a/tests/pyb/timer.py +++ b/tests/pyb/timer.py @@ -11,3 +11,9 @@ tim.prescaler(300) print(tim.prescaler()) tim.period(400) print(tim.period()) + +# Setting and printing frequency +tim = Timer(2, freq=100) +print(tim.freq()) +tim.freq(0.001) +print(tim.freq()) diff --git a/tests/pyb/timer.py.exp b/tests/pyb/timer.py.exp index 5c46230303..7602bbd70d 100644 --- a/tests/pyb/timer.py.exp +++ b/tests/pyb/timer.py.exp @@ -2,3 +2,5 @@ 200 300 400 +100 +0.001 From 71401d5065e20da59a1cc740d760002794b008e0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 16 Oct 2019 16:26:20 +1100 Subject: [PATCH 0932/1788] extmod/modlwip: Unconditionally return POLLHUP when polling new socket. POSIX poll should always return POLLERR and POLLHUP in revents, regardless of whether they were requested in the input events flags. See issues #4290 and #5172. --- extmod/modlwip.c | 2 +- tests/net_hosted/connect_poll.py | 3 +-- tests/net_hosted/connect_poll.py.exp | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index 050937750a..cd0f6946cd 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -1468,7 +1468,7 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ if (socket->state == STATE_NEW) { // New sockets are not connected so set HUP - ret |= flags & MP_STREAM_POLL_HUP; + ret |= 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 diff --git a/tests/net_hosted/connect_poll.py b/tests/net_hosted/connect_poll.py index ece6aa0da9..7aeba8f6d4 100644 --- a/tests/net_hosted/connect_poll.py +++ b/tests/net_hosted/connect_poll.py @@ -12,9 +12,8 @@ def test(peer_addr): 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)) + print(len(p), p[0][-1]) s.connect(peer_addr) diff --git a/tests/net_hosted/connect_poll.py.exp b/tests/net_hosted/connect_poll.py.exp index cdf520e090..d18a39a12a 100644 --- a/tests/net_hosted/connect_poll.py.exp +++ b/tests/net_hosted/connect_poll.py.exp @@ -1,3 +1,3 @@ -1 4 +1 20 1 1 4 From d3c383de79bd25b42339cc7a4c68b79e39eccc7c Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 16 Oct 2019 17:24:19 +1100 Subject: [PATCH 0933/1788] py/stream.h: Add MP_STREAM_POLL_NVAL constant. --- py/stream.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/py/stream.h b/py/stream.h index b6019bb38a..3ebd4e0421 100644 --- a/py/stream.h +++ b/py/stream.h @@ -45,10 +45,11 @@ #define MP_STREAM_GET_FILENO (10) // Get fileno of underlying file // These poll ioctl values are compatible with Linux -#define MP_STREAM_POLL_RD (0x0001) -#define MP_STREAM_POLL_WR (0x0004) -#define MP_STREAM_POLL_ERR (0x0008) -#define MP_STREAM_POLL_HUP (0x0010) +#define MP_STREAM_POLL_RD (0x0001) +#define MP_STREAM_POLL_WR (0x0004) +#define MP_STREAM_POLL_ERR (0x0008) +#define MP_STREAM_POLL_HUP (0x0010) +#define MP_STREAM_POLL_NVAL (0x0020) // Argument structure for MP_STREAM_SEEK struct mp_stream_seek_t { From feaa2516742ed4f9032a0233dcec922ac6a4e80c Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 16 Oct 2019 17:24:40 +1100 Subject: [PATCH 0934/1788] extmod/modlwip: Make socket poll return POLLNVAL in case of bad file. --- extmod/modlwip.c | 2 ++ tests/extmod/uselect_poll_basic.py | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index cd0f6946cd..1e9b8c4590 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -1477,6 +1477,8 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ } 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 == _ERR_BADF) { + ret |= MP_STREAM_POLL_NVAL; } 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 diff --git a/tests/extmod/uselect_poll_basic.py b/tests/extmod/uselect_poll_basic.py index df52471ac3..82a7195c03 100644 --- a/tests/extmod/uselect_poll_basic.py +++ b/tests/extmod/uselect_poll_basic.py @@ -33,3 +33,9 @@ try: poller.modify(s, select.POLLIN) except OSError as e: assert e.args[0] == errno.ENOENT + +# poll after closing the socket, should return POLLNVAL +poller.register(s) +s.close() +p = poller.poll(0) +print(len(p), p[0][-1]) From 26d8fd2c0a1385a7c22363ea0695e6a0c828dc8d Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 16 Oct 2019 17:34:11 +1100 Subject: [PATCH 0935/1788] extmod/modlwip: Unconditionally return POLLHUP/POLLERR when polling. POSIX poll should always return POLLERR and POLLHUP in revents, regardless of whether they were requested in the input events flags. See issues #4290 and #5172. --- extmod/modlwip.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index 1e9b8c4590..4358544bab 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -1476,13 +1476,14 @@ 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 (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); + ret |= flags & MP_STREAM_POLL_WR; + ret |= MP_STREAM_POLL_HUP; } else if (socket->state == _ERR_BADF) { ret |= MP_STREAM_POLL_NVAL; } 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; + ret |= MP_STREAM_POLL_ERR; } } else if (request == MP_STREAM_CLOSE) { From 07ea81fbc57dc52c52de32ab4088fe7e29de4e0d Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 31 Oct 2019 13:42:24 +1100 Subject: [PATCH 0936/1788] extmod/modussl_mbedtls: Fix getpeercert to return None if no cert avail. --- extmod/modussl_mbedtls.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/extmod/modussl_mbedtls.c b/extmod/modussl_mbedtls.c index 6759f11fa5..4105d3fa02 100644 --- a/extmod/modussl_mbedtls.c +++ b/extmod/modussl_mbedtls.c @@ -219,6 +219,9 @@ STATIC mp_obj_t mod_ssl_getpeercert(mp_obj_t o_in, mp_obj_t binary_form) { mp_raise_NotImplementedError(NULL); } const mbedtls_x509_crt* peer_cert = mbedtls_ssl_get_peer_cert(&o->ssl); + if (peer_cert == NULL) { + return mp_const_none; + } return mp_obj_new_bytes(peer_cert->raw.p, peer_cert->raw.len); } STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_ssl_getpeercert_obj, mod_ssl_getpeercert); From 9dd9f9ff06c15b06b4b35959196610d5cb952cf0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 31 Oct 2019 16:22:42 +1100 Subject: [PATCH 0937/1788] extmod/modussl_mbedtls: Check for invalid key/cert data. --- extmod/modussl_mbedtls.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/extmod/modussl_mbedtls.c b/extmod/modussl_mbedtls.c index 4105d3fa02..a71adc5b36 100644 --- a/extmod/modussl_mbedtls.c +++ b/extmod/modussl_mbedtls.c @@ -169,21 +169,29 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { mbedtls_ssl_set_bio(&o->ssl, &o->sock, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL); - if (args->key.u_obj != MP_OBJ_NULL) { + if (args->key.u_obj != mp_const_none) { size_t key_len; const byte *key = (const byte*)mp_obj_str_get_data(args->key.u_obj, &key_len); // len should include terminating null ret = mbedtls_pk_parse_key(&o->pkey, key, key_len + 1, NULL, 0); - assert(ret == 0); + if (ret != 0) { + ret = MBEDTLS_ERR_PK_BAD_INPUT_DATA; // use general error for all key errors + goto cleanup; + } size_t cert_len; const byte *cert = (const byte*)mp_obj_str_get_data(args->cert.u_obj, &cert_len); // len should include terminating null ret = mbedtls_x509_crt_parse(&o->cert, cert, cert_len + 1); - assert(ret == 0); + if (ret != 0) { + ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA; // use general error for all cert errors + goto cleanup; + } ret = mbedtls_ssl_conf_own_cert(&o->conf, &o->cert, &o->pkey); - assert(ret == 0); + if (ret != 0) { + goto cleanup; + } } if (args->do_handshake.u_bool) { @@ -208,6 +216,10 @@ cleanup: if (ret == MBEDTLS_ERR_SSL_ALLOC_FAILED) { mp_raise_OSError(MP_ENOMEM); + } else if (ret == MBEDTLS_ERR_PK_BAD_INPUT_DATA) { + mp_raise_ValueError("invalid key"); + } else if (ret == MBEDTLS_ERR_X509_BAD_INPUT_DATA) { + mp_raise_ValueError("invalid cert"); } else { mp_raise_OSError(MP_EIO); } @@ -334,8 +346,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_OBJ_NULL} }, - { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, { 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_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, { MP_QSTR_do_handshake, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, From 43f53a2bbd4668dc196ebda5d0ccc1aa37312418 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 31 Oct 2019 16:38:20 +1100 Subject: [PATCH 0938/1788] tests/extmod: Add test for ussl when passing in key/cert params. --- tests/extmod/ussl_keycert.py | 28 ++++++++++++++++++++++++++++ tests/extmod/ussl_keycert.py.exp | 3 +++ 2 files changed, 31 insertions(+) create mode 100644 tests/extmod/ussl_keycert.py create mode 100644 tests/extmod/ussl_keycert.py.exp diff --git a/tests/extmod/ussl_keycert.py b/tests/extmod/ussl_keycert.py new file mode 100644 index 0000000000..9b3eae6027 --- /dev/null +++ b/tests/extmod/ussl_keycert.py @@ -0,0 +1,28 @@ +# Test ussl with key/cert passed in + +try: + import uio as io + import ussl as ssl +except ImportError: + print("SKIP") + raise SystemExit + +key = b'0\x82\x019\x02\x01\x00\x02A\x00\xf9\xe0}\xbd\xd7\x9cI\x18\x06\xc3\xcb\xb5\xec@r\xfbD\x18\x80\xaaWoZ{\xcc\xa3\xeb!"\x0fY\x9e]-\xee\xe4\t!BY\x9f{7\xf3\xf2\x8f}}\r|.\xa8<\ta\xb2\xd7W\xb3\xc9\x19A\xc39\x02\x03\x01\x00\x01\x02@\x07:\x9fh\xa6\x9c6\xe1#\x10\xf7\x0b\xc4Q\xf9\x01\x9b\xee\xb9\x8a4\r\\\xa8\xc8:\xd5\xca\x97\x99\xaa\x16\x04)\xa8\xf9\x13\xdeq\x0ev`\xa7\x83\xc5\x8b`\xdb\xef \x9d\x93\xe8g\x84\x96\xfaV\\\xf4R\xda\xd0\xa1\x02!\x00\xfeR\xbf\n\x91Su\x87L\x98{\xeb%\xed\xfb\x06u)@\xfe\x1b\xde\xa0\xc6@\xab\xc5\xedg\x8e\x10[\x02!\x00\xfb\x86=\x85\xa4\'\xde\x85\xb5L\xe0)\x99\xfaL\x8c3A\x02\xa8<\xdew\xad\x00\xe3\x1d\x05\xd8\xb4N\xfb\x02 \x08\xb0M\x04\x90hx\x88q\xcew\xd5U\xcbf\x9b\x16\xdf\x9c\xef\xd1\x85\xee\x9a7Ug\x02\xb0Z\x03\'\x02 9\xa0D\xe2$|\xf9\xefz]5\x92rs\xb5+\xfd\xe6,\x1c\xadmn\xcf\xd5?3|\x0em)\x17\x02 5Z\xcc/\xa5?\n\x04%\x9b{N\x9dX\xddI\xbe\xd2\xb0\xa0\x03BQ\x02\x82\xc2\xe0u)\xbd\xb8\xaf' + +# Invalid key +try: + ssl.wrap_socket(io.BytesIO(), key=b'!') +except ValueError as er: + print(repr(er)) + +# Valid key, no cert +try: + ssl.wrap_socket(io.BytesIO(), key=key) +except TypeError as er: + print(repr(er)) + +# Valid key, invalid cert +try: + ssl.wrap_socket(io.BytesIO(), key=key, cert=b'!') +except ValueError as er: + print(repr(er)) diff --git a/tests/extmod/ussl_keycert.py.exp b/tests/extmod/ussl_keycert.py.exp new file mode 100644 index 0000000000..b72d319c6a --- /dev/null +++ b/tests/extmod/ussl_keycert.py.exp @@ -0,0 +1,3 @@ +ValueError('invalid key',) +TypeError("can't convert 'NoneType' object to str implicitly",) +ValueError('invalid cert',) From a5d97f1db95fff3c33fbb69300ad7e31cb6d0dd1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 23 Oct 2019 16:56:14 +1100 Subject: [PATCH 0939/1788] stm32: Add soft timer implementation, using SysTick at 1ms resolution. This commit adds an implementation of a "software timer" with a 1ms resolution, using SysTick. It allows unlimited number of concurrent timers (limited only by memory needed for each timer entry). They can be one-shot or periodic, and associated with a Python callback. There is a very small overhead added to the SysTick IRQ, which could be further optimised in the future, eg by patching SysTick_Handler code dynamically. --- ports/stm32/Makefile | 1 + ports/stm32/main.c | 2 + ports/stm32/mpconfigport.h | 2 + ports/stm32/pendsv.h | 3 +- ports/stm32/softtimer.c | 112 +++++++++++++++++++++++++++++++++++++ ports/stm32/softtimer.h | 50 +++++++++++++++++ ports/stm32/systick.c | 6 ++ 7 files changed, 174 insertions(+), 2 deletions(-) create mode 100644 ports/stm32/softtimer.c create mode 100644 ports/stm32/softtimer.h diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index fca92f841e..82711eca62 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -249,6 +249,7 @@ SRC_C = \ irq.c \ pendsv.c \ systick.c \ + softtimer.c \ powerctrl.c \ powerctrlboot.c \ pybthread.c \ diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 685dbd10c7..a00bdf3bdb 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -55,6 +55,7 @@ #include "gccollect.h" #include "factoryreset.h" #include "modmachine.h" +#include "softtimer.h" #include "i2c.h" #include "spi.h" #include "uart.h" @@ -743,6 +744,7 @@ soft_reset_exit: #if MICROPY_PY_NETWORK mod_network_deinit(); #endif + soft_timer_deinit(); timer_deinit(); uart_deinit_all(); #if MICROPY_HW_ENABLE_CAN diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index b31eed2932..11c2372385 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -282,6 +282,8 @@ struct _mp_bluetooth_nimble_root_pointers_t; \ mp_obj_t pyb_extint_callback[PYB_EXTI_NUM_VECTORS]; \ \ + struct _soft_timer_entry_t *soft_timer_head; \ + \ /* pointers to all Timer objects (if they have been created) */ \ struct _pyb_timer_obj_t *pyb_timer_obj_all[MICROPY_HW_MAX_TIMER]; \ \ diff --git a/ports/stm32/pendsv.h b/ports/stm32/pendsv.h index 9851a5ece7..dd3f8f2cb3 100644 --- a/ports/stm32/pendsv.h +++ b/ports/stm32/pendsv.h @@ -27,6 +27,7 @@ #define MICROPY_INCLUDED_STM32_PENDSV_H enum { + PENDSV_DISPATCH_SOFT_TIMER, #if MICROPY_PY_NETWORK && MICROPY_PY_LWIP PENDSV_DISPATCH_LWIP, #if MICROPY_PY_NETWORK_CYW43 @@ -39,9 +40,7 @@ enum { PENDSV_DISPATCH_MAX }; -#if (MICROPY_PY_NETWORK && MICROPY_PY_LWIP) || (MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE) #define PENDSV_DISPATCH_NUM_SLOTS PENDSV_DISPATCH_MAX -#endif typedef void (*pendsv_dispatch_t)(void); diff --git a/ports/stm32/softtimer.c b/ports/stm32/softtimer.c new file mode 100644 index 0000000000..c598bac177 --- /dev/null +++ b/ports/stm32/softtimer.c @@ -0,0 +1,112 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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 "irq.h" +#include "softtimer.h" + +#define TICKS_PERIOD 0x80000000 +#define TICKS_DIFF(t1, t0) ((int32_t)(((t1 - t0 + TICKS_PERIOD / 2) & (TICKS_PERIOD - 1)) - TICKS_PERIOD / 2)) + +extern __IO uint32_t uwTick; + +volatile uint32_t soft_timer_next; + +void soft_timer_deinit(void) { + MP_STATE_PORT(soft_timer_head) = NULL; +} + +STATIC void soft_timer_schedule_systick(uint32_t ticks_ms) { + uint32_t irq_state = disable_irq(); + uint32_t uw_tick = uwTick; + if (TICKS_DIFF(ticks_ms, uw_tick) <= 0) { + soft_timer_next = uw_tick + 1; + } else { + soft_timer_next = ticks_ms; + } + enable_irq(irq_state); +} + +// Must be executed at IRQ_PRI_PENDSV +void soft_timer_handler(void) { + uint32_t ticks_ms = uwTick; + soft_timer_entry_t *head = MP_STATE_PORT(soft_timer_head); + while (head != NULL && TICKS_DIFF(head->expiry_ms, ticks_ms) <= 0) { + mp_sched_schedule(head->callback, MP_OBJ_FROM_PTR(head)); + if (head->mode == SOFT_TIMER_MODE_PERIODIC) { + head->expiry_ms += head->delta_ms; + // Shift this node along to its new position + soft_timer_entry_t *cur = head; + while (cur->next != NULL && TICKS_DIFF(head->expiry_ms, cur->next->expiry_ms) >= 0) { + cur = cur->next; + } + if (cur != head) { + soft_timer_entry_t *next = head->next; + head->next = cur->next; + cur->next = head; + head = next; + } + } else { + head = head->next; + } + } + MP_STATE_PORT(soft_timer_head) = head; + if (head == NULL) { + // No more timers left, set largest delay possible + soft_timer_next = uwTick; + } else { + // Set soft_timer_next so SysTick calls us back at the correct time + soft_timer_schedule_systick(head->expiry_ms); + } +} + +void soft_timer_insert(soft_timer_entry_t *entry) { + uint32_t irq_state = raise_irq_pri(IRQ_PRI_PENDSV); + soft_timer_entry_t **head_ptr = &MP_STATE_PORT(soft_timer_head); + while (*head_ptr != NULL && TICKS_DIFF(entry->expiry_ms, (*head_ptr)->expiry_ms) >= 0) { + head_ptr = &(*head_ptr)->next; + } + entry->next = *head_ptr; + *head_ptr = entry; + if (head_ptr == &MP_STATE_PORT(soft_timer_head)) { + // This new timer became the earliest one so set soft_timer_next + soft_timer_schedule_systick((*head_ptr)->expiry_ms); + } + restore_irq_pri(irq_state); +} + +void soft_timer_remove(soft_timer_entry_t *entry) { + uint32_t irq_state = raise_irq_pri(IRQ_PRI_PENDSV); + soft_timer_entry_t **cur = &MP_STATE_PORT(soft_timer_head); + while (*cur != NULL) { + if (*cur == entry) { + *cur = entry->next; + break; + } + } + restore_irq_pri(irq_state); +} diff --git a/ports/stm32/softtimer.h b/ports/stm32/softtimer.h new file mode 100644 index 0000000000..2550446d83 --- /dev/null +++ b/ports/stm32/softtimer.h @@ -0,0 +1,50 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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_SOFTTIMER_H +#define MICROPY_INCLUDED_STM32_SOFTTIMER_H + +#include "py/obj.h" + +#define SOFT_TIMER_MODE_ONE_SHOT (1) +#define SOFT_TIMER_MODE_PERIODIC (2) + +typedef struct _soft_timer_entry_t { + mp_obj_base_t base; // so struct can be used as an object and still be traced by GC + struct _soft_timer_entry_t *next; + uint32_t mode; + uint32_t expiry_ms; + uint32_t delta_ms; // for periodic mode + mp_obj_t callback; +} soft_timer_entry_t; + +extern volatile uint32_t soft_timer_next; + +void soft_timer_deinit(void); +void soft_timer_handler(void); +void soft_timer_insert(soft_timer_entry_t *entry); +void soft_timer_remove(soft_timer_entry_t *entry); + +#endif // MICROPY_INCLUDED_STM32_SOFTTIMER_H diff --git a/ports/stm32/systick.c b/ports/stm32/systick.c index d92f9d75dc..85c99b9aeb 100644 --- a/ports/stm32/systick.c +++ b/ports/stm32/systick.c @@ -27,7 +27,9 @@ #include "py/runtime.h" #include "py/mphal.h" #include "irq.h" +#include "pendsv.h" #include "systick.h" +#include "softtimer.h" #include "pybthread.h" extern __IO uint32_t uwTick; @@ -52,6 +54,10 @@ void SysTick_Handler(void) { f(uw_tick); } + if (soft_timer_next == uw_tick) { + pendsv_schedule_dispatch(PENDSV_DISPATCH_SOFT_TIMER, soft_timer_handler); + } + #if MICROPY_PY_THREAD if (pyb_thread_enabled) { if (pyb_thread_cur->timeslice == 0) { From 48b25a841b04108d4dc399fad87b413f9f52c6bb Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 23 Oct 2019 16:56:38 +1100 Subject: [PATCH 0940/1788] stm32: Add machine.Timer with soft timer implementation. This commit adds an implementation of machine.Timer backed by the soft timer mechanism. It allows an arbitrary number of timers with 1ms resolution, with an associated Python callback. The Python-level API matches existing ports that have a soft timer, and is used as: from machine import Timer t = Timer(freq=10, callback=lambda t:print(t)) ... t = Timer(mode=Timer.ONE_SHOT, period=2000, callback=lambda t:print(t)) ... t.deinit() --- ports/stm32/Makefile | 1 + ports/stm32/machine_timer.c | 132 ++++++++++++++++++++++++++++++++++++ ports/stm32/modmachine.c | 2 +- ports/stm32/modmachine.h | 1 + 4 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 ports/stm32/machine_timer.c diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 82711eca62..2a3b14d046 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -278,6 +278,7 @@ SRC_C = \ machine_adc.c \ machine_i2c.c \ machine_spi.c \ + machine_timer.c \ machine_uart.c \ modmachine.c \ modpyb.c \ diff --git a/ports/stm32/machine_timer.c b/ports/stm32/machine_timer.c new file mode 100644 index 0000000000..49e3a54d01 --- /dev/null +++ b/ports/stm32/machine_timer.c @@ -0,0 +1,132 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/mphal.h" +#include "softtimer.h" + +typedef soft_timer_entry_t machine_timer_obj_t; + +const mp_obj_type_t machine_timer_type; + +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; + qstr mode = self->mode == SOFT_TIMER_MODE_ONE_SHOT ? MP_QSTR_ONE_SHOT : MP_QSTR_PERIODIC; + mp_printf(print, "Timer(mode=%q, period=%u)", mode, self->delta_ms); +} + +STATIC mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_mode, ARG_callback, ARG_period, ARG_tick_hz, ARG_freq, }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SOFT_TIMER_MODE_PERIODIC} }, + { MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, + { MP_QSTR_tick_hz, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000} }, + { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + + // 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); + + self->mode = args[ARG_mode].u_int; + if (args[ARG_freq].u_obj != mp_const_none) { + // Frequency specified in Hz + #if MICROPY_PY_BUILTINS_FLOAT + self->delta_ms = 1000 / mp_obj_get_float(args[ARG_freq].u_obj); + #else + self->delta_ms = 1000 / mp_obj_get_int(args[ARG_freq].u_obj); + #endif + } else { + // Period specified + self->delta_ms = args[ARG_period].u_int * 1000 / args[ARG_tick_hz].u_int; + } + if (self->delta_ms < 1) { + self->delta_ms = 1; + } + self->expiry_ms = mp_hal_ticks_ms() + self->delta_ms; + + self->callback = args[ARG_callback].u_obj; + soft_timer_insert(self); + + return mp_const_none; +} + +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) { + machine_timer_obj_t *self = m_new_obj(machine_timer_obj_t); + self->base.type = &machine_timer_type; + + // Get timer id (only soft timer (-1) supported at the moment) + mp_int_t id = -1; + if (n_args > 0) { + id = mp_obj_get_int(args[0]); + --n_args; + ++args; + } + if (id != -1) { + mp_raise_ValueError("Timer doesn't exist"); + } + + if (n_args > 0 || n_kw > 0) { + // Start the timer + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + machine_timer_init_helper(self, n_args, args, &kw_args); + } + + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t machine_timer_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + machine_timer_obj_t *self = MP_OBJ_TO_PTR(args[0]); + soft_timer_remove(self); + return machine_timer_init_helper(self, 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_deinit(mp_obj_t self_in) { + machine_timer_obj_t *self = MP_OBJ_TO_PTR(self_in); + soft_timer_remove(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_deinit_obj, machine_timer_deinit); + +STATIC const mp_rom_map_elem_t machine_timer_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_timer_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_timer_deinit_obj) }, + + { MP_ROM_QSTR(MP_QSTR_ONE_SHOT), MP_ROM_INT(SOFT_TIMER_MODE_ONE_SHOT) }, + { MP_ROM_QSTR(MP_QSTR_PERIODIC), MP_ROM_INT(SOFT_TIMER_MODE_PERIODIC) }, +}; +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_dict_t*)&machine_timer_locals_dict, +}; diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index eaa536a1db..7db8e29643 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -399,8 +399,8 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { 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) }, + { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&machine_timer_type) }, #if 0 - { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&pyb_timer_type) }, { MP_ROM_QSTR(MP_QSTR_HeartBeat), MP_ROM_PTR(&pyb_heartbeat_type) }, { MP_ROM_QSTR(MP_QSTR_SD), MP_ROM_PTR(&pyb_sd_type) }, diff --git a/ports/stm32/modmachine.h b/ports/stm32/modmachine.h index 4b727d3cb9..f04bfb486b 100644 --- a/ports/stm32/modmachine.h +++ b/ports/stm32/modmachine.h @@ -29,6 +29,7 @@ #include "py/obj.h" extern const mp_obj_type_t machine_adc_type; +extern const mp_obj_type_t machine_timer_type; void machine_init(void); void machine_deinit(void); From 78145b98ef6c755c5cf7745ea643766bec6f9045 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 1 Nov 2019 12:15:07 +1100 Subject: [PATCH 0941/1788] extmod/nimble: Remove unneeded nimble_sprintf wrapper function. --- extmod/nimble/nimble.mk | 1 - extmod/nimble/nimble/misc.c | 44 ------------------------------------- 2 files changed, 45 deletions(-) delete mode 100644 extmod/nimble/nimble/misc.c diff --git a/extmod/nimble/nimble.mk b/extmod/nimble/nimble.mk index 274fcdb9f3..e554e9ff06 100644 --- a/extmod/nimble/nimble.mk +++ b/extmod/nimble/nimble.mk @@ -72,7 +72,6 @@ SRC_LIB += $(addprefix $(NIMBLE_LIB_DIR)/, \ ) EXTMOD_SRC_C += $(addprefix $(NIMBLE_EXTMOD_DIR)/, \ - nimble/misc.c \ nimble/npl_os.c \ nimble/hci_uart.c \ ) diff --git a/extmod/nimble/nimble/misc.c b/extmod/nimble/nimble/misc.c deleted file mode 100644 index 0e7d8a42a8..0000000000 --- a/extmod/nimble/nimble/misc.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018-2019 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" - -#if MICROPY_BLUETOOTH_NIMBLE - -/******************************************************************************/ -// Misc functions needed by Nimble - -#include - -int nimble_sprintf(char *str, const char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - int ret = vsnprintf(str, 65535, fmt, ap); - va_end(ap); - return ret; -} - -#endif From 40ea1915fc06b7abc4fac6649c70f9b89dc51e2b Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 1 Nov 2019 12:41:37 +1100 Subject: [PATCH 0942/1788] extmod/nimble: Factor out stm32-specific HCI UART RX/TX code. --- extmod/nimble/nimble/hci_uart.c | 36 +------------------------ extmod/nimble/nimble/hci_uart.h | 5 ++-- ports/stm32/nimble_hci_uart.c | 47 +++++++++++++++++++++++++++++---- 3 files changed, 46 insertions(+), 42 deletions(-) diff --git a/extmod/nimble/nimble/hci_uart.c b/extmod/nimble/nimble/hci_uart.c index 801291def4..b4ac4e7388 100644 --- a/extmod/nimble/nimble/hci_uart.c +++ b/extmod/nimble/nimble/hci_uart.c @@ -42,8 +42,6 @@ static void *hal_uart_tx_arg; static hal_uart_rx_cb_t hal_uart_rx_cb; static void *hal_uart_rx_arg; -static uint32_t bt_sleep_ticks; - int hal_uart_init_cbs(uint32_t port, hal_uart_tx_cb_t tx_cb, void *tx_arg, hal_uart_rx_cb_t rx_cb, void *rx_arg) { hal_uart_tx_cb = tx_cb; hal_uart_tx_arg = tx_arg; @@ -76,16 +74,6 @@ void hal_uart_start_tx(uint32_t port) { printf("\n"); #endif - bt_sleep_ticks = mp_hal_ticks_ms(); - - #ifdef pyb_pin_BT_DEV_WAKE - if (mp_hal_pin_read(pyb_pin_BT_DEV_WAKE) == 1) { - //printf("BT WAKE for TX\n"); - mp_hal_pin_low(pyb_pin_BT_DEV_WAKE); // wake up - mp_hal_delay_ms(5); // can't go lower than this - } - #endif - nimble_hci_uart_tx_strn((void*)bt_hci_cmd_buf, len); } @@ -94,29 +82,7 @@ int hal_uart_close(uint32_t port) { } void nimble_uart_process(void) { - int host_wake = 0; - #ifdef pyb_pin_BT_HOST_WAKE - host_wake = mp_hal_pin_read(pyb_pin_BT_HOST_WAKE); - #endif - /* - // this is just for info/tracing purposes - static int last_host_wake = 0; - if (host_wake != last_host_wake) { - printf("HOST_WAKE change %d -> %d\n", last_host_wake, host_wake); - last_host_wake = host_wake; - } - */ - while (nimble_hci_uart_rx_any()) { - uint8_t data = nimble_hci_uart_rx_char(); - //printf("UART RX: %02x\n", data); - hal_uart_rx_cb(hal_uart_rx_arg, data); - } - if (host_wake == 1 && mp_hal_pin_read(pyb_pin_BT_DEV_WAKE) == 0) { - if (mp_hal_ticks_ms() - bt_sleep_ticks > 500) { - //printf("BT SLEEP\n"); - mp_hal_pin_high(pyb_pin_BT_DEV_WAKE); // let sleep - } - } + nimble_hci_uart_rx(hal_uart_rx_cb, hal_uart_rx_arg); } #endif // MICROPY_BLUETOOTH_NIMBLE diff --git a/extmod/nimble/nimble/hci_uart.h b/extmod/nimble/nimble/hci_uart.h index e184210830..3d4a2a9835 100644 --- a/extmod/nimble/nimble/hci_uart.h +++ b/extmod/nimble/nimble/hci_uart.h @@ -26,6 +26,8 @@ #ifndef MICROPY_INCLUDED_EXTMOD_NIMBLE_NIMBLE_HCI_UART_H #define MICROPY_INCLUDED_EXTMOD_NIMBLE_NIMBLE_HCI_UART_H +#include "extmod/nimble/hal/hal_uart.h" + // To be implemented by the port. int nimble_hci_uart_configure(uint32_t port); @@ -35,8 +37,7 @@ int nimble_hci_uart_set_baudrate(uint32_t baudrate); int nimble_hci_uart_activate(void); -mp_uint_t nimble_hci_uart_rx_any(); -int nimble_hci_uart_rx_char(); +void nimble_hci_uart_rx(hal_uart_rx_cb_t rx_cb, void *rx_arg); void nimble_hci_uart_tx_strn(const char *str, uint len); #endif // MICROPY_INCLUDED_EXTMOD_NIMBLE_NIMBLE_HCI_UART_H diff --git a/ports/stm32/nimble_hci_uart.c b/ports/stm32/nimble_hci_uart.c index 104a64b732..251f15e3b4 100644 --- a/ports/stm32/nimble_hci_uart.c +++ b/ports/stm32/nimble_hci_uart.c @@ -28,6 +28,7 @@ #include "py/mphal.h" #include "uart.h" #include "pendsv.h" +#include "extmod/nimble/nimble/hci_uart.h" #include "drivers/cyw43/cywbt.h" #if MICROPY_BLUETOOTH_NIMBLE @@ -37,6 +38,10 @@ pyb_uart_obj_t bt_hci_uart_obj; static uint8_t hci_uart_rxbuf[512]; +#ifdef pyb_pin_BT_DEV_WAKE +static uint32_t bt_sleep_ticks; +#endif + extern void nimble_poll(void); mp_obj_t mp_uart_interrupt(mp_obj_t self_in) { @@ -81,15 +86,47 @@ int nimble_hci_uart_activate(void) { return 0; } -mp_uint_t nimble_hci_uart_rx_any() { - return uart_rx_any(&bt_hci_uart_obj); -} +void nimble_hci_uart_rx(hal_uart_rx_cb_t rx_cb, void *rx_arg) { + #ifdef pyb_pin_BT_HOST_WAKE + int host_wake = 0; + host_wake = mp_hal_pin_read(pyb_pin_BT_HOST_WAKE); + /* + // this is just for info/tracing purposes + static int last_host_wake = 0; + if (host_wake != last_host_wake) { + printf("HOST_WAKE change %d -> %d\n", last_host_wake, host_wake); + last_host_wake = host_wake; + } + */ + #endif -int nimble_hci_uart_rx_char() { - return uart_rx_char(&bt_hci_uart_obj); + while (uart_rx_any(&bt_hci_uart_obj)) { + uint8_t data = uart_rx_char(&bt_hci_uart_obj); + //printf("UART RX: %02x\n", data); + rx_cb(rx_arg, data); + } + + #ifdef pyb_pin_BT_DEV_WAKE + if (host_wake == 1 && mp_hal_pin_read(pyb_pin_BT_DEV_WAKE) == 0) { + if (mp_hal_ticks_ms() - bt_sleep_ticks > 500) { + //printf("BT SLEEP\n"); + mp_hal_pin_high(pyb_pin_BT_DEV_WAKE); // let sleep + } + } + #endif } void nimble_hci_uart_tx_strn(const char *str, uint len) { + #ifdef pyb_pin_BT_DEV_WAKE + bt_sleep_ticks = mp_hal_ticks_ms(); + + if (mp_hal_pin_read(pyb_pin_BT_DEV_WAKE) == 1) { + //printf("BT WAKE for TX\n"); + mp_hal_pin_low(pyb_pin_BT_DEV_WAKE); // wake up + mp_hal_delay_ms(5); // can't go lower than this + } + #endif + uart_tx_strn(&bt_hci_uart_obj, str, len); } From 6a64b280d03755ecb0c58f42f6b649e931fd2018 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 1 Nov 2019 14:52:17 +1100 Subject: [PATCH 0943/1788] stm32: Add support for RF coprocessor on WB55 MCUs. This requires a BLE wireless stack firmware to be already programmed in the secure flash area of the device. --- ports/stm32/Makefile | 1 + ports/stm32/boards/stm32wb55xg.ld | 11 + ports/stm32/main.c | 4 + ports/stm32/nimble_hci_uart.c | 49 +++- ports/stm32/rfcore.c | 425 ++++++++++++++++++++++++++++++ ports/stm32/rfcore.h | 37 +++ 6 files changed, 523 insertions(+), 4 deletions(-) create mode 100644 ports/stm32/rfcore.c create mode 100644 ports/stm32/rfcore.h diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 2a3b14d046..99d2248fd4 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -252,6 +252,7 @@ SRC_C = \ softtimer.c \ powerctrl.c \ powerctrlboot.c \ + rfcore.c \ pybthread.c \ factoryreset.c \ timer.c \ diff --git a/ports/stm32/boards/stm32wb55xg.ld b/ports/stm32/boards/stm32wb55xg.ld index bdbf7e447e..77596d7759 100644 --- a/ports/stm32/boards/stm32wb55xg.ld +++ b/ports/stm32/boards/stm32wb55xg.ld @@ -8,6 +8,7 @@ MEMORY FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K /* sectors 0-127 */ FLASH_FS (r) : ORIGIN = 0x08080000, LENGTH = 256K /* sectors 128-191 */ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 192K /* SRAM1 */ + RAM2A (xrw) : ORIGIN = 0x20030020, LENGTH = 8K /* SRAM2A */ } /* produce a link error if there is not this amount of RAM for these sections */ @@ -31,3 +32,13 @@ _heap_end = _sstack; _flash_fs_start = ORIGIN(FLASH_FS); _flash_fs_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); + +SECTIONS +{ + .ram2a_bss : + { + . = ALIGN(4); + *rfcore.o(.bss.ipcc_mem_*) + . = ALIGN(4); + } >RAM2A +} diff --git a/ports/stm32/main.c b/ports/stm32/main.c index a00bdf3bdb..3c6420d50d 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -48,6 +48,7 @@ #endif #include "mpu.h" +#include "rfcore.h" #include "systick.h" #include "pendsv.h" #include "powerctrl.h" @@ -466,6 +467,9 @@ void stm32_main(uint32_t reset_mode) { #endif // basic sub-system init + #if defined(STM32WB) + rfcore_init(); + #endif #if MICROPY_HW_SDRAM_SIZE sdram_init(); #if MICROPY_HW_SDRAM_STARTUP_TEST diff --git a/ports/stm32/nimble_hci_uart.c b/ports/stm32/nimble_hci_uart.c index 251f15e3b4..defda1581e 100644 --- a/ports/stm32/nimble_hci_uart.c +++ b/ports/stm32/nimble_hci_uart.c @@ -26,15 +26,54 @@ #include "py/runtime.h" #include "py/mphal.h" -#include "uart.h" -#include "pendsv.h" #include "extmod/nimble/nimble/hci_uart.h" -#include "drivers/cyw43/cywbt.h" #if MICROPY_BLUETOOTH_NIMBLE +#if defined(STM32WB) + /******************************************************************************/ -// UART +// HCI over IPCC + +#include "rfcore.h" + +int nimble_hci_uart_configure(uint32_t port) { + (void)port; + return 0; +} + +int nimble_hci_uart_set_baudrate(uint32_t baudrate) { + (void)baudrate; + return 0; +} + +int nimble_hci_uart_activate(void) { + rfcore_ble_init(); + return 0; +} + +void nimble_hci_uart_rx(hal_uart_rx_cb_t rx_cb, void *rx_arg) { + // Protect in case it's called from ble_npl_sem_pend at thread-level + MICROPY_PY_LWIP_ENTER + rfcore_ble_check_msg(rx_cb, rx_arg); + MICROPY_PY_LWIP_EXIT +} + +void nimble_hci_uart_tx_strn(const char *str, uint len) { + MICROPY_PY_LWIP_ENTER + rfcore_ble_hci_cmd(len, (const uint8_t*)str); + MICROPY_PY_LWIP_EXIT +} + +#else + +/******************************************************************************/ +// HCI over UART + +#include "pendsv.h" +#include "uart.h" +#include "drivers/cyw43/cywbt.h" + pyb_uart_obj_t bt_hci_uart_obj; static uint8_t hci_uart_rxbuf[512]; @@ -130,4 +169,6 @@ void nimble_hci_uart_tx_strn(const char *str, uint len) { uart_tx_strn(&bt_hci_uart_obj, str, len); } +#endif // defined(STM32WB) + #endif // MICROPY_BLUETOOTH_NIMBLE diff --git a/ports/stm32/rfcore.c b/ports/stm32/rfcore.c new file mode 100644 index 0000000000..2b45bb2eeb --- /dev/null +++ b/ports/stm32/rfcore.c @@ -0,0 +1,425 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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/mperrno.h" +#include "py/mphal.h" +#include "rtc.h" +#include "rfcore.h" + +#if defined(STM32WB) + +// Define to 1 to print traces of HCI packets +#define HCI_TRACE (0) + +#define IPCC_CH_BLE (0x01) // BLE HCI command and response +#define IPCC_CH_SYS (0x02) // system HCI command and response +#define IPCC_CH_MM (0x08) // release buffer +#define IPCC_CH_HCI_ACL (0x20) // HCI ACL outgoing data + +#define OGF_VENDOR (0x3f) +#define OCF_WRITE_CONFIG (0x0c) +#define OCF_SET_TX_POWER (0x0f) +#define OCF_BLE_INIT (0x66) + +#define HCI_OPCODE(ogf, ocf) ((ogf) << 10 | (ocf)) + +typedef struct _tl_list_node_t { + volatile struct _tl_list_node_t *next; + volatile struct _tl_list_node_t *prev; + uint8_t body[0]; +} tl_list_node_t; + +typedef struct _parse_hci_info_t { + int (*cb_fun)(void*, uint8_t); + void *cb_env; + bool was_hci_reset_evt; +} parse_hci_info_t; + +static volatile uint32_t ipcc_mem_dev_info_tab[8]; +static volatile uint32_t ipcc_mem_ble_tab[4]; +static volatile uint32_t ipcc_mem_sys_tab[2]; +static volatile uint32_t ipcc_mem_memmgr_tab[7]; + +static volatile uint32_t ipcc_mem_sys_cmd_buf[272 / 4]; +static volatile tl_list_node_t ipcc_mem_sys_queue; + +static volatile tl_list_node_t ipcc_mem_memmgr_free_buf_queue; +static volatile uint32_t ipcc_mem_memmgr_ble_spare_evt_buf[272 / 4]; +static volatile uint32_t ipcc_mem_memmgr_sys_spare_evt_buf[272 / 4]; +static volatile uint32_t ipcc_mem_memmgr_evt_pool[6 * 272 / 4]; + +static volatile uint32_t ipcc_mem_ble_cmd_buf[272 / 4]; +static volatile uint32_t ipcc_mem_ble_cs_buf[272 / 4]; +static volatile tl_list_node_t ipcc_mem_ble_evt_queue; +static volatile uint32_t ipcc_mem_ble_hci_acl_data_buf[272 / 4]; + +/******************************************************************************/ +// Transport layer linked list + +STATIC void tl_list_init(volatile tl_list_node_t *n) { + n->next = n; + n->prev = n; +} + +STATIC volatile tl_list_node_t *tl_list_unlink(volatile tl_list_node_t *n) { + volatile tl_list_node_t *next = n->next; + volatile tl_list_node_t *prev = n->prev; + prev->next = next; + next->prev = prev; + return next; +} + +STATIC void tl_list_append(volatile tl_list_node_t *head, volatile tl_list_node_t *n) { + n->next = head; + n->prev = head->prev; + head->prev->next = n; + head->prev = n; +} + +/******************************************************************************/ +// IPCC interface + +STATIC uint32_t get_ipccdba(void) { + return *(uint32_t*)(OPTION_BYTE_BASE + 0x68) & 0x3fff; +} + +STATIC volatile void **get_buffer_table(void) { + return (volatile void**)(SRAM2A_BASE + get_ipccdba()); +} + +void ipcc_init(uint32_t irq_pri) { + // Setup buffer table pointers + volatile void **tab = get_buffer_table(); + tab[0] = &ipcc_mem_dev_info_tab[0]; + tab[1] = &ipcc_mem_ble_tab[0]; + tab[3] = &ipcc_mem_sys_tab[0]; + tab[4] = &ipcc_mem_memmgr_tab[0]; + + // Start IPCC peripheral + __HAL_RCC_IPCC_CLK_ENABLE(); + + // Enable wanted IRQs + IPCC->C1CR = 0;//IPCC_C1CR_RXOIE; + IPCC->C1MR = 0xffffffff; + NVIC_SetPriority(IPCC_C1_RX_IRQn, irq_pri); + HAL_NVIC_EnableIRQ(IPCC_C1_RX_IRQn); + + // Device info table will be populated by FUS/WS + + // Populate system table + tl_list_init(&ipcc_mem_sys_queue); + ipcc_mem_sys_tab[0] = (uint32_t)&ipcc_mem_sys_cmd_buf[0]; + ipcc_mem_sys_tab[1] = (uint32_t)&ipcc_mem_sys_queue; + + // Populate memory manager table + tl_list_init(&ipcc_mem_memmgr_free_buf_queue); + ipcc_mem_memmgr_tab[0] = (uint32_t)&ipcc_mem_memmgr_ble_spare_evt_buf[0]; + ipcc_mem_memmgr_tab[1] = (uint32_t)&ipcc_mem_memmgr_sys_spare_evt_buf[0]; + ipcc_mem_memmgr_tab[2] = (uint32_t)&ipcc_mem_memmgr_evt_pool[0]; + ipcc_mem_memmgr_tab[3] = sizeof(ipcc_mem_memmgr_evt_pool); + ipcc_mem_memmgr_tab[4] = (uint32_t)&ipcc_mem_memmgr_free_buf_queue; + ipcc_mem_memmgr_tab[5] = 0; + ipcc_mem_memmgr_tab[6] = 0; + + // Populate BLE table + tl_list_init(&ipcc_mem_ble_evt_queue); + ipcc_mem_ble_tab[0] = (uint32_t)&ipcc_mem_ble_cmd_buf[0]; + ipcc_mem_ble_tab[1] = (uint32_t)&ipcc_mem_ble_cs_buf[0]; + ipcc_mem_ble_tab[2] = (uint32_t)&ipcc_mem_ble_evt_queue; + ipcc_mem_ble_tab[3] = (uint32_t)&ipcc_mem_ble_hci_acl_data_buf[0]; +} + +STATIC int ipcc_wait_ack(unsigned int ch, uint32_t timeout_ms) { + uint32_t t0 = mp_hal_ticks_ms(); + while (IPCC->C1TOC2SR & ch) { + if (mp_hal_ticks_ms() - t0 > timeout_ms) { + printf("ipcc_wait_ack: timeout\n"); + return -MP_ETIMEDOUT; + } + } + // C2 cleared IPCC flag + return 0; +} + +STATIC int ipcc_wait_msg(unsigned int ch, uint32_t timeout_ms) { + uint32_t t0 = mp_hal_ticks_ms(); + while (!(IPCC->C2TOC1SR & ch)) { + if (mp_hal_ticks_ms() - t0 > timeout_ms) { + printf("ipcc_wait_msg: timeout\n"); + return -MP_ETIMEDOUT; + } + } + // C2 set IPCC flag + return 0; +} + +/******************************************************************************/ +// Transport layer HCI interface + +STATIC void tl_parse_hci_msg(const uint8_t *buf, parse_hci_info_t *parse) { + const char *kind; + size_t len = 3 + buf[2]; + switch (buf[0]) { + case 0x02: { + // Standard BT HCI ACL packet + kind = "HCI_ACL"; + if (parse != NULL) { + for (size_t i = 0; i < len; ++i) { + parse->cb_fun(parse->cb_env, buf[i]); + } + } + break; + } + case 0x04: { + // Standard BT HCI event packet + kind = "HCI_EVT"; + if (parse != NULL) { + bool fix = false; + if (buf[1] == 0x0e && len == 7 && buf[3] == 0x01 && buf[4] == 0x63 && buf[5] == 0x0c && buf[6] == 0x01) { + len -= 1; + fix = true; + } + for (size_t i = 0; i < len; ++i) { + parse->cb_fun(parse->cb_env, buf[i]); + } + if (fix) { + len += 1; + parse->cb_fun(parse->cb_env, 0x00); // success + } + // Check for successful HCI_Reset event + parse->was_hci_reset_evt = buf[1] == 0x0e && buf[2] == 0x04 && buf[3] == 0x01 + && buf[4] == 0x03 && buf[5] == 0x0c && buf[6] == 0x00; + } + break; + } + case 0x11: { + // Response packet + // assert(buf[1] == 0x0e); + kind = "VEND_RESP"; + //uint16_t cmd = buf[4] | buf[5] << 8; + //uint8_t status = buf[6]; + break; + } + case 0x12: { + // Event packet + // assert(buf[1] == 0xff); + kind = "VEND_EVT"; + //uint16_t evt = buf[3] | buf[4] << 8; + break; + } + default: + kind = "HCI_UNKNOWN"; + break; + } + + #if HCI_TRACE + printf("[% 8d] %s(%02x", mp_hal_ticks_ms(), kind, buf[0]); + for (int i = 1; i < len; ++i) { + printf(":%02x", buf[i]); + } + printf(")\n"); + #else + (void)kind; + #endif +} + +STATIC void tl_check_msg(volatile tl_list_node_t *head, unsigned int ch, parse_hci_info_t *parse) { + if (IPCC->C2TOC1SR & ch) { + // Message available on CH2 + volatile tl_list_node_t *cur = head->next; + bool free = false; + while (cur != head) { + tl_parse_hci_msg((uint8_t*)cur->body, parse); + volatile tl_list_node_t *next = tl_list_unlink(cur); + if ((void*)&ipcc_mem_memmgr_evt_pool[0] <= (void*)cur + && (void*)cur < (void*)&ipcc_mem_memmgr_evt_pool[MP_ARRAY_SIZE(ipcc_mem_memmgr_evt_pool)]) { + // Place memory back in free pool + tl_list_append(&ipcc_mem_memmgr_free_buf_queue, cur); + free = true; + } + cur = next; + } + if (free) { + // Notify change in free pool + IPCC->C1SCR = IPCC_CH_MM << 16; + } + // Clear receive channel + IPCC->C1SCR = ch; + } +} + +STATIC void tl_hci_cmd(uint8_t *cmd, unsigned int ch, uint8_t hdr, uint16_t opcode, size_t len, const uint8_t *buf) { + tl_list_node_t *n = (tl_list_node_t*)cmd; + n->next = n; + n->prev = n; + cmd[8] = hdr; + cmd[9] = opcode; + cmd[10] = opcode >> 8; + cmd[11] = len; + memcpy(&cmd[12], buf, len); + // IPCC indicate + IPCC->C1SCR = ch << 16; +} + +STATIC void tl_sys_wait_resp(const uint8_t *buf, unsigned int ch) { + if (ipcc_wait_ack(ch, 250) == 0) { + tl_parse_hci_msg(buf, NULL); + } +} + +STATIC void tl_sys_hci_cmd_resp(uint16_t opcode, size_t len, const uint8_t *buf) { + tl_hci_cmd((uint8_t*)&ipcc_mem_sys_cmd_buf, IPCC_CH_SYS, 0x10, opcode, len, buf); + tl_sys_wait_resp((uint8_t*)&ipcc_mem_sys_cmd_buf, IPCC_CH_SYS); +} + +STATIC void tl_ble_hci_cmd_resp(uint16_t opcode, size_t len, const uint8_t *buf) { + tl_hci_cmd((uint8_t*)&ipcc_mem_ble_cmd_buf[0], IPCC_CH_BLE, 0x01, opcode, len, buf); + ipcc_wait_msg(IPCC_CH_BLE, 250); + tl_check_msg(&ipcc_mem_ble_evt_queue, IPCC_CH_BLE, NULL); +} + +/******************************************************************************/ +// RF core interface + +void rfcore_init(void) { + // Ensure LSE is running + rtc_init_finalise(); + + // Select LSE as RF wakeup source + RCC->CSR = (RCC->CSR & ~RCC_CSR_RFWKPSEL) | 1 << RCC_CSR_RFWKPSEL_Pos; + + // Initialise IPCC and shared memory structures + ipcc_init(IRQ_PRI_SDIO); + + // Boot the second core + __SEV(); + __WFE(); + PWR->CR4 |= PWR_CR4_C2BOOT; +} + +static const struct { + uint8_t* pBleBufferAddress; // unused + uint32_t BleBufferSize; // unused + uint16_t NumAttrRecord; + uint16_t NumAttrServ; + uint16_t AttrValueArrSize; + uint8_t NumOfLinks; + uint8_t ExtendedPacketLengthEnable; + uint8_t PrWriteListSize; + uint8_t MblockCount; + uint16_t AttMtu; + uint16_t SlaveSca; + uint8_t MasterSca; + uint8_t LsSource; // 0=LSE 1=internal RO + uint32_t MaxConnEventLength; + uint16_t HsStartupTime; + uint8_t ViterbiEnable; + uint8_t LlOnly; // 0=LL+Host, 1=LL only + uint8_t HwVersion; +} ble_init_params = { + 0, + 0, + 0, // NumAttrRecord + 0, // NumAttrServ + 0, // AttrValueArrSize + 1, // NumOfLinks + 1, // ExtendedPacketLengthEnable + 0, // PrWriteListSize + 0x79, // MblockCount + 0, // AttMtu + 0, // SlaveSca + 0, // MasterSca + 1, // LsSource + 0xffffffff, // MaxConnEventLength + 0x148, // HsStartupTime + 0, // ViterbiEnable + 1, // LlOnly + 0, // HwVersion +}; + +void rfcore_ble_init(void) { + // Clear any outstanding messages from ipcc_init + tl_check_msg(&ipcc_mem_sys_queue, IPCC_CH_SYS, NULL); + tl_check_msg(&ipcc_mem_ble_evt_queue, IPCC_CH_BLE, NULL); + + // Configure and reset the BLE controller + tl_sys_hci_cmd_resp(HCI_OPCODE(OGF_VENDOR, OCF_BLE_INIT), sizeof(ble_init_params), (const uint8_t*)&ble_init_params); + tl_ble_hci_cmd_resp(HCI_OPCODE(0x03, 0x0003), 0, NULL); +} + +void rfcore_ble_hci_cmd(size_t len, const uint8_t *src) { + #if HCI_TRACE + printf("[% 8d] HCI_CMD(%02x", mp_hal_ticks_ms(), src[0]); + for (int i = 1; i < len; ++i) { + printf(":%02x", src[i]); + } + printf(")\n"); + #endif + + tl_list_node_t *n; + uint32_t ch; + if (src[0] == 0x01) { + n = (tl_list_node_t*)&ipcc_mem_ble_cmd_buf[0]; + ch = IPCC_CH_BLE; + } else if (src[0] == 0x02) { + n = (tl_list_node_t*)&ipcc_mem_ble_hci_acl_data_buf[0]; + ch = IPCC_CH_HCI_ACL; + } else { + printf("** UNEXPECTED HCI HDR: 0x%02x **\n", src[0]); + return; + } + + n->next = n; + n->prev = n; + memcpy(n->body, src, len); + + // IPCC indicate + IPCC->C1SCR = ch << 16; +} + +void rfcore_ble_check_msg(int (*cb)(void*, uint8_t), void *env) { + parse_hci_info_t parse = { cb, env, false }; + tl_check_msg(&ipcc_mem_ble_evt_queue, IPCC_CH_BLE, &parse); + + // Intercept HCI_Reset events and reconfigure the controller following the reset + if (parse.was_hci_reset_evt) { + uint8_t buf[8]; + buf[0] = 0; // config offset + buf[1] = 6; // config length + mp_hal_get_mac(MP_HAL_MAC_BDADDR, &buf[2]); + #define SWAP_UINT8(a, b) { uint8_t temp = a; a = b; b = temp; } + SWAP_UINT8(buf[2], buf[7]); + SWAP_UINT8(buf[3], buf[6]); + SWAP_UINT8(buf[4], buf[5]); + tl_ble_hci_cmd_resp(HCI_OPCODE(OGF_VENDOR, OCF_WRITE_CONFIG), 8, buf); // set BDADDR + tl_ble_hci_cmd_resp(HCI_OPCODE(OGF_VENDOR, OCF_SET_TX_POWER), 2, (const uint8_t*)"\x00\x06"); // 0 dBm + } +} + +#endif // defined(STM32WB) diff --git a/ports/stm32/rfcore.h b/ports/stm32/rfcore.h new file mode 100644 index 0000000000..ef12707b7d --- /dev/null +++ b/ports/stm32/rfcore.h @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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_RFCORE_H +#define MICROPY_INCLUDED_STM32_RFCORE_H + +#include + +void rfcore_init(void); + +void rfcore_ble_init(void); +void rfcore_ble_hci_cmd(size_t len, const uint8_t *src); +void rfcore_ble_check_msg(int (*cb)(void*, uint8_t), void *env); + +#endif // MICROPY_INCLUDED_STM32_RFCORE_H From 32eae53fbc94a1d91fe67025aeef05ad3e20b187 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 1 Nov 2019 14:56:48 +1100 Subject: [PATCH 0944/1788] stm32/boards: Enable support for bluetooth on WB55 boards. --- ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h | 4 ++++ ports/stm32/boards/NUCLEO_WB55/mpconfigboard.mk | 4 ++++ ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.h | 4 ++++ ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.mk | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h b/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h index beca216569..54747cb04d 100644 --- a/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h @@ -61,3 +61,7 @@ #define MICROPY_HW_USB_FS (1) #define USBD_CDC_RX_DATA_SIZE (512) #define USBD_CDC_TX_DATA_SIZE (512) + +// Bluetooth config +#define MICROPY_HW_BLE_UART_ID (0) +#define MICROPY_HW_BLE_UART_BAUDRATE (115200) diff --git a/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.mk index b0f93c006f..cd9f104ef5 100644 --- a/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.mk @@ -3,3 +3,7 @@ CMSIS_MCU = STM32WB55xx AF_FILE = boards/stm32wb55_af.csv LD_FILES = boards/stm32wb55xg.ld boards/common_basic.ld STARTUP_FILE = lib/stm32lib/CMSIS/STM32WBxx/Source/Templates/gcc/startup_stm32wb55xx_cm4.o + +# MicroPython settings +MICROPY_PY_BLUETOOTH = 1 +MICROPY_BLUETOOTH_NIMBLE = 1 diff --git a/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.h b/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.h index eebf30f628..eeedfb0844 100644 --- a/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.h +++ b/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.h @@ -40,3 +40,7 @@ #define MICROPY_HW_USB_FS (1) #define USBD_CDC_RX_DATA_SIZE (512) #define USBD_CDC_TX_DATA_SIZE (512) + +// Bluetooth config +#define MICROPY_HW_BLE_UART_ID (0) +#define MICROPY_HW_BLE_UART_BAUDRATE (115200) diff --git a/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.mk b/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.mk index b0f93c006f..cd9f104ef5 100644 --- a/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.mk +++ b/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.mk @@ -3,3 +3,7 @@ CMSIS_MCU = STM32WB55xx AF_FILE = boards/stm32wb55_af.csv LD_FILES = boards/stm32wb55xg.ld boards/common_basic.ld STARTUP_FILE = lib/stm32lib/CMSIS/STM32WBxx/Source/Templates/gcc/startup_stm32wb55xx_cm4.o + +# MicroPython settings +MICROPY_PY_BLUETOOTH = 1 +MICROPY_BLUETOOTH_NIMBLE = 1 From 2ee9e1a4edf31824f2ff4ba6fb73129c798dcb36 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 1 Nov 2019 17:25:40 +1100 Subject: [PATCH 0945/1788] extmod/modbtree: Make FILEVTABLE const to put it in ROM. --- extmod/modbtree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extmod/modbtree.c b/extmod/modbtree.c index a2bff06d44..2a08a9cab0 100644 --- a/extmod/modbtree.c +++ b/extmod/modbtree.c @@ -320,7 +320,7 @@ STATIC const mp_obj_type_t btree_type = { .locals_dict = (void*)&btree_locals_dict, }; -STATIC FILEVTABLE btree_stream_fvtable = { +STATIC const FILEVTABLE btree_stream_fvtable = { mp_stream_posix_read, mp_stream_posix_write, mp_stream_posix_lseek, From f2ecfe8b83b4efe24d721778e324a31237653627 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 1 Nov 2019 17:26:10 +1100 Subject: [PATCH 0946/1788] py/nativeglue: Remove unused mp_obj_new_cell from mp_fun_table. It has been unused since 9988618e0e0f5c319e31b135d993e22efb593093 --- py/emitnx86.c | 1 - py/nativeglue.c | 1 - py/runtime0.h | 1 - 3 files changed, 3 deletions(-) diff --git a/py/emitnx86.c b/py/emitnx86.c index 7c96c3b82b..0122e46bab 100644 --- a/py/emitnx86.c +++ b/py/emitnx86.c @@ -60,7 +60,6 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = { [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_ARG_CHECK_NUM_SIG] = 3, [MP_F_SETUP_CODE_STATE] = 4, diff --git a/py/nativeglue.c b/py/nativeglue.c index 4405b2d116..08fbd3c309 100644 --- a/py/nativeglue.c +++ b/py/nativeglue.c @@ -259,7 +259,6 @@ const void *const mp_fun_table[MP_F_NUMBER_OF] = { mp_unpack_ex, mp_delete_name, mp_delete_global, - mp_obj_new_cell, mp_make_closure_from_raw_code, mp_arg_check_num_sig, mp_setup_code_state, diff --git a/py/runtime0.h b/py/runtime0.h index 364f237f66..f588110c0d 100644 --- a/py/runtime0.h +++ b/py/runtime0.h @@ -196,7 +196,6 @@ typedef enum { MP_F_UNPACK_EX, MP_F_DELETE_NAME, MP_F_DELETE_GLOBAL, - MP_F_NEW_CELL, MP_F_MAKE_CLOSURE_FROM_RAW_CODE, MP_F_ARG_CHECK_NUM_SIG, MP_F_SETUP_CODE_STATE, From 36c9be6f60314684edf131f554efec7120e20f30 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 4 Nov 2019 15:31:42 +1100 Subject: [PATCH 0947/1788] tools/mpy-tool.py: Use "@progbits #" attribute for native xtensa code. --- tools/mpy-tool.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index 39362bc092..9b0b8e8cd2 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -422,7 +422,8 @@ class RawCodeNative(RawCode): self.prelude = prelude self.qstr_links = qstr_links self.type_sig = type_sig - if config.native_arch in (MP_NATIVE_ARCH_X86, MP_NATIVE_ARCH_X64): + if config.native_arch in (MP_NATIVE_ARCH_X86, MP_NATIVE_ARCH_X64, + MP_NATIVE_ARCH_XTENSA, MP_NATIVE_ARCH_XTENSAWIN): self.fun_data_attributes = '__attribute__((section(".text,\\"ax\\",@progbits # ")))' else: self.fun_data_attributes = '__attribute__((section(".text,\\"ax\\",%progbits @ ")))' From 742030945c779c57c30c62c7b1353758d29dc228 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 4 Nov 2019 15:32:20 +1100 Subject: [PATCH 0948/1788] esp32/Makefile: Add correct arch to MPY_CROSS_FLAGS for native code. --- ports/esp32/Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 37261d17bd..42b01a4e60 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -275,6 +275,9 @@ COPT += -Os -DNDEBUG #LDFLAGS += --gc-sections endif +# Options for mpy-cross +MPY_CROSS_FLAGS += -march=xtensawin + # Enable SPIRAM support if CONFIG_ESP32_SPIRAM_SUPPORT=y in sdkconfig ifeq ($(CONFIG_ESP32_SPIRAM_SUPPORT),y) CFLAGS_COMMON += -mfix-esp32-psram-cache-issue From 576ed8922472f41dd603da9bd719bd9f1adbf31e Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 29 Oct 2019 17:28:11 +1100 Subject: [PATCH 0949/1788] py/objgenerator: Remove globals from mp_obj_gen_instance_t. This wasn't necessary as the wrapped function already has a reference to its globals. But it had a dual purpose of tracking whether the function was currently running, so replace it with a bool. --- py/objgenerator.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/py/objgenerator.c b/py/objgenerator.c index 2cfdb12f63..1850377cb9 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -43,7 +43,7 @@ const mp_obj_exception_t mp_const_GeneratorExit_obj = {{&mp_type_GeneratorExit}, typedef struct _mp_obj_gen_instance_t { mp_obj_base_t base; - mp_obj_dict_t *globals; + bool is_running; mp_code_state_t code_state; } mp_obj_gen_instance_t; @@ -60,7 +60,7 @@ STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_kw, cons n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t)); o->base.type = &mp_type_gen_instance; - o->globals = self_fun->globals; + o->is_running = false; o->code_state.fun_bc = self_fun; o->code_state.ip = 0; o->code_state.n_state = n_state; @@ -105,7 +105,7 @@ STATIC mp_obj_t native_gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_k o->base.type = &mp_type_gen_instance; // Parse the input arguments and set up the code state - o->globals = self_fun->globals; + o->is_running = false; o->code_state.fun_bc = self_fun; o->code_state.ip = (const byte*)prelude_offset; o->code_state.n_state = n_state; @@ -168,16 +168,15 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ } } - // We set self->globals=NULL while executing, for a sentinel to ensure the generator - // cannot be reentered during execution - if (self->globals == NULL) { + // Ensure the generator cannot be reentered during execution + if (self->is_running) { mp_raise_ValueError("generator already executing"); } + self->is_running = true; // 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_globals_set(self->code_state.fun_bc->globals); mp_vm_return_kind_t ret_kind; @@ -194,9 +193,10 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ ret_kind = mp_execute_bytecode(&self->code_state, throw_value); } - self->globals = mp_globals_get(); mp_globals_set(self->code_state.old_globals); + self->is_running = false; + switch (ret_kind) { case MP_VM_RETURN_NORMAL: default: From 5578182ec97509dcc37521b78da5ee31b96f6b4e Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 29 Oct 2019 21:04:55 +1100 Subject: [PATCH 0950/1788] py/objgenerator: Allow pend_throw to an unstarted generator. Replace the is_running field with a tri-state variable to indicate running/not-running/pending-exception. Update tests to cover the various cases. This allows cancellation in uasyncio even if the coroutine hasn't been executed yet. Fixes #5242 --- py/objgenerator.c | 52 +++++++++------- tests/basics/generator_pend_throw.py | 76 +++++++++++++++++++++++- tests/basics/generator_pend_throw.py.exp | 12 +++- 3 files changed, 113 insertions(+), 27 deletions(-) diff --git a/py/objgenerator.c b/py/objgenerator.c index 1850377cb9..903a6469cc 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -43,7 +43,10 @@ const mp_obj_exception_t mp_const_GeneratorExit_obj = {{&mp_type_GeneratorExit}, typedef struct _mp_obj_gen_instance_t { mp_obj_base_t base; - bool is_running; + // mp_const_none: Not-running, no exception. + // MP_OBJ_NULL: Running, no exception. + // other: Not running, pending exception. + mp_obj_t pend_exc; mp_code_state_t code_state; } mp_obj_gen_instance_t; @@ -60,7 +63,7 @@ STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_kw, cons n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t)); o->base.type = &mp_type_gen_instance; - o->is_running = false; + o->pend_exc = mp_const_none; o->code_state.fun_bc = self_fun; o->code_state.ip = 0; o->code_state.n_state = n_state; @@ -105,7 +108,7 @@ STATIC mp_obj_t native_gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_k o->base.type = &mp_type_gen_instance; // Parse the input arguments and set up the code state - o->is_running = false; + o->pend_exc = mp_const_none; o->code_state.fun_bc = self_fun; o->code_state.ip = (const byte*)prelude_offset; o->code_state.n_state = n_state; @@ -151,28 +154,30 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ *ret_val = MP_OBJ_STOP_ITERATION; return MP_VM_RETURN_NORMAL; } + + // Ensure the generator cannot be reentered during execution + if (self->pend_exc == MP_OBJ_NULL) { + mp_raise_ValueError("generator already executing"); + } + + #if MICROPY_PY_GENERATOR_PEND_THROW + // If exception is pending (set using .pend_throw()), process it now. + if (self->pend_exc != mp_const_none) { + throw_value = self->pend_exc; + } + #endif + + // If the generator is started, allow sending a value. if (self->code_state.sp == self->code_state.state - 1) { if (send_value != mp_const_none) { mp_raise_TypeError("can't send non-None value to a just-started generator"); } } else { - #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; - } + *self->code_state.sp = send_value; } - // Ensure the generator cannot be reentered during execution - if (self->is_running) { - mp_raise_ValueError("generator already executing"); - } - self->is_running = true; + // Mark as running + self->pend_exc = MP_OBJ_NULL; // Set up the correct globals context for the generator and execute it self->code_state.old_globals = mp_globals_get(); @@ -195,7 +200,8 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ mp_globals_set(self->code_state.old_globals); - self->is_running = false; + // Mark as not running + self->pend_exc = mp_const_none; switch (ret_kind) { case MP_VM_RETURN_NORMAL: @@ -313,11 +319,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(gen_instance_close_obj, gen_instance_close); #if MICROPY_PY_GENERATOR_PEND_THROW 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"); + if (self->pend_exc == MP_OBJ_NULL) { + mp_raise_ValueError("generator already executing"); } - mp_obj_t prev = *self->code_state.sp; - *self->code_state.sp = exc_in; + mp_obj_t prev = self->pend_exc; + self->pend_exc = exc_in; return prev; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(gen_instance_pend_throw_obj, gen_instance_pend_throw); diff --git a/tests/basics/generator_pend_throw.py b/tests/basics/generator_pend_throw.py index f00ff793b6..ae8c21189e 100644 --- a/tests/basics/generator_pend_throw.py +++ b/tests/basics/generator_pend_throw.py @@ -13,6 +13,7 @@ except AttributeError: raise SystemExit +# Verify that an injected exception will be raised from next(). print(next(g)) print(next(g)) g.pend_throw(ValueError()) @@ -25,7 +26,76 @@ except Exception as e: print("ret was:", v) + +# Verify that pend_throw works on an unstarted coroutine. +g = gen() +g.pend_throw(OSError()) try: - gen().pend_throw(ValueError()) -except TypeError: - print("TypeError") + next(g) +except Exception as e: + print("raised", repr(e)) + + +# Verify that you can't resume the coroutine from within the running coroutine. +def gen_next(): + next(g) + yield 1 + +g = gen_next() + +try: + next(g) +except Exception as e: + print("raised", repr(e)) + + +# Verify that you can't pend_throw from within the running coroutine. +def gen_pend_throw(): + g.pend_throw(ValueError()) + yield 1 + +g = gen_pend_throw() + +try: + next(g) +except Exception as e: + print("raised", repr(e)) + + +# Verify that the pend_throw exception can be ignored. +class CancelledError(Exception): + pass + +def gen_cancelled(): + for i in range(5): + try: + yield i + except CancelledError: + print('ignore CancelledError') + +g = gen_cancelled() +print(next(g)) +g.pend_throw(CancelledError()) +print(next(g)) +# ...but not if the generator hasn't started. +g = gen_cancelled() +g.pend_throw(CancelledError()) +try: + next(g) +except Exception as e: + print("raised", repr(e)) + + +# Verify that calling pend_throw returns the previous exception. +g = gen() +next(g) +print(repr(g.pend_throw(CancelledError()))) +print(repr(g.pend_throw(OSError))) + + +# Verify that you can pend_throw(None) to cancel a previous pend_throw. +g = gen() +next(g) +g.pend_throw(CancelledError()) +print(repr(g.pend_throw(None))) +print(next(g)) diff --git a/tests/basics/generator_pend_throw.py.exp b/tests/basics/generator_pend_throw.py.exp index ed4d882958..8a3dadfec7 100644 --- a/tests/basics/generator_pend_throw.py.exp +++ b/tests/basics/generator_pend_throw.py.exp @@ -2,4 +2,14 @@ 1 raised ValueError() ret was: None -TypeError +raised OSError() +raised ValueError('generator already executing',) +raised ValueError('generator already executing',) +0 +ignore CancelledError +1 +raised CancelledError() +None +CancelledError() +CancelledError() +1 From f4601af10a4e1f1a588596ed1bb76cb7578ab726 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 1 Nov 2019 21:04:07 +1100 Subject: [PATCH 0951/1788] py/persistentcode: Move declarations for .mpy header from .c to .h file. --- py/persistentcode.c | 37 ------------------------------------- py/persistentcode.h | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/py/persistentcode.c b/py/persistentcode.c index d55e371592..84385c1713 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -40,43 +40,6 @@ #define QSTR_LAST_STATIC MP_QSTR_zip -// Macros to encode/decode flags to/from the feature byte -#define MPY_FEATURE_ENCODE_FLAGS(flags) (flags) -#define MPY_FEATURE_DECODE_FLAGS(feat) ((feat) & 3) - -// Macros to encode/decode native architecture to/from the feature byte -#define MPY_FEATURE_ENCODE_ARCH(arch) ((arch) << 2) -#define MPY_FEATURE_DECODE_ARCH(feat) ((feat) >> 2) - -// The feature flag bits encode the compile-time config options that -// affect the generate bytecode. -#define MPY_FEATURE_FLAGS ( \ - ((MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) << 0) \ - | ((MICROPY_PY_BUILTINS_STR_UNICODE) << 1) \ - ) -// This is a version of the flags that can be configured at runtime. -#define MPY_FEATURE_FLAGS_DYNAMIC ( \ - ((MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) << 0) \ - | ((MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC) << 1) \ - ) - -// Define the host architecture -#if MICROPY_EMIT_X86 -#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_X86) -#elif MICROPY_EMIT_X64 -#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_X64) -#elif MICROPY_EMIT_THUMB -#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7M) -#elif MICROPY_EMIT_ARM -#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV6) -#elif MICROPY_EMIT_XTENSA -#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_XTENSA) -#elif MICROPY_EMIT_XTENSAWIN -#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_XTENSAWIN) -#else -#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_NONE) -#endif - #if MICROPY_DYNAMIC_COMPILER #define MPY_FEATURE_ARCH_DYNAMIC mp_dynamic_compiler.native_arch #else diff --git a/py/persistentcode.h b/py/persistentcode.h index aba44ea2db..a6978c2a33 100644 --- a/py/persistentcode.h +++ b/py/persistentcode.h @@ -33,6 +33,43 @@ // The current version of .mpy files #define MPY_VERSION 5 +// Macros to encode/decode flags to/from the feature byte +#define MPY_FEATURE_ENCODE_FLAGS(flags) (flags) +#define MPY_FEATURE_DECODE_FLAGS(feat) ((feat) & 3) + +// Macros to encode/decode native architecture to/from the feature byte +#define MPY_FEATURE_ENCODE_ARCH(arch) ((arch) << 2) +#define MPY_FEATURE_DECODE_ARCH(feat) ((feat) >> 2) + +// The feature flag bits encode the compile-time config options that +// affect the generate bytecode. +#define MPY_FEATURE_FLAGS ( \ + ((MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) << 0) \ + | ((MICROPY_PY_BUILTINS_STR_UNICODE) << 1) \ + ) +// This is a version of the flags that can be configured at runtime. +#define MPY_FEATURE_FLAGS_DYNAMIC ( \ + ((MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) << 0) \ + | ((MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC) << 1) \ + ) + +// Define the host architecture +#if MICROPY_EMIT_X86 +#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_X86) +#elif MICROPY_EMIT_X64 +#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_X64) +#elif MICROPY_EMIT_THUMB +#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7M) +#elif MICROPY_EMIT_ARM +#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV6) +#elif MICROPY_EMIT_XTENSA +#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_XTENSA) +#elif MICROPY_EMIT_XTENSAWIN +#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_XTENSAWIN) +#else +#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_NONE) +#endif + enum { MP_NATIVE_ARCH_NONE = 0, MP_NATIVE_ARCH_X86, From 80df377e9512ac839ab19192ff1897ba30be098b Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 30 Oct 2019 16:26:11 +1100 Subject: [PATCH 0952/1788] py/modsys: Report .mpy version in sys.implementation. This commit adds a sys.implementation.mpy entry when the system supports importing .mpy files. This entry is a 16-bit integer which encodes two bytes of information from the header of .mpy files that are supported by the system being run: the second and third bytes, .mpy version, and flags and native architecture. This allows determining the supported .mpy file dynamically by code, and also for the user to find it out by inspecting this value. It's further possible to dynamically detect if the system supports importing .mpy files by `hasattr(sys.implementation, 'mpy')`. --- py/modsys.c | 29 ++++++++++++++++++++++------- py/persistentcode.h | 4 ++++ tests/basics/sys1.py | 6 ++++++ 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/py/modsys.c b/py/modsys.c index 4886419d0e..29fac7c319 100644 --- a/py/modsys.c +++ b/py/modsys.c @@ -34,6 +34,7 @@ #include "py/stream.h" #include "py/smallint.h" #include "py/runtime.h" +#include "py/persistentcode.h" #if MICROPY_PY_SYS_SETTRACE #include "py/objmodule.h" @@ -66,22 +67,36 @@ STATIC const mp_obj_tuple_t mp_sys_implementation_version_info_obj = { 3, { I(MICROPY_VERSION_MAJOR), I(MICROPY_VERSION_MINOR), I(MICROPY_VERSION_MICRO) } }; +#if MICROPY_PERSISTENT_CODE_LOAD +#define SYS_IMPLEMENTATION_ELEMS \ + MP_ROM_QSTR(MP_QSTR_micropython), \ + MP_ROM_PTR(&mp_sys_implementation_version_info_obj), \ + MP_ROM_INT(MPY_FILE_HEADER_INT) +#else +#define SYS_IMPLEMENTATION_ELEMS \ + MP_ROM_QSTR(MP_QSTR_micropython), \ + MP_ROM_PTR(&mp_sys_implementation_version_info_obj) +#endif #if MICROPY_PY_ATTRTUPLE -STATIC const qstr impl_fields[] = { MP_QSTR_name, MP_QSTR_version }; +STATIC const qstr impl_fields[] = { + MP_QSTR_name, + MP_QSTR_version, + #if MICROPY_PERSISTENT_CODE_LOAD + MP_QSTR_mpy, + #endif +}; STATIC MP_DEFINE_ATTRTUPLE( mp_sys_implementation_obj, impl_fields, - 2, - MP_ROM_QSTR(MP_QSTR_micropython), - MP_ROM_PTR(&mp_sys_implementation_version_info_obj) + 2 + MICROPY_PERSISTENT_CODE_LOAD, + SYS_IMPLEMENTATION_ELEMS ); #else STATIC const mp_rom_obj_tuple_t mp_sys_implementation_obj = { {&mp_type_tuple}, - 2, + 2 + MICROPY_PERSISTENT_CODE_LOAD, { - MP_ROM_QSTR(MP_QSTR_micropython), - MP_ROM_PTR(&mp_sys_implementation_version_info_obj), + SYS_IMPLEMENTATION_ELEMS } }; #endif diff --git a/py/persistentcode.h b/py/persistentcode.h index a6978c2a33..07e018f8a6 100644 --- a/py/persistentcode.h +++ b/py/persistentcode.h @@ -70,6 +70,10 @@ #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_NONE) #endif +// 16-bit little-endian integer with the second and third bytes of supported .mpy files +#define MPY_FILE_HEADER_INT (MPY_VERSION \ + | (MPY_FEATURE_ENCODE_FLAGS(MPY_FEATURE_FLAGS) | MPY_FEATURE_ENCODE_ARCH(MPY_FEATURE_ARCH)) << 8) + enum { MP_NATIVE_ARCH_NONE = 0, MP_NATIVE_ARCH_X86, diff --git a/tests/basics/sys1.py b/tests/basics/sys1.py index ab91380246..095824afaf 100644 --- a/tests/basics/sys1.py +++ b/tests/basics/sys1.py @@ -18,3 +18,9 @@ try: except AttributeError: # Effectively skip subtests print(True) + +if hasattr(sys.implementation, 'mpy'): + print(type(sys.implementation.mpy)) +else: + # Effectively skip subtests + print(int) From c13f9f209d7a343fe306a24a04eb934ce905b631 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 5 Nov 2019 11:33:03 +1100 Subject: [PATCH 0953/1788] all: Convert nlr_raise(mp_obj_new_exception_msg(x)) to mp_raise_msg(x). This helper function was added a while ago and these are the remaining cases to convert, to save a bit of code size. --- extmod/moductypes.c | 2 +- extmod/moduheapq.c | 2 +- extmod/modutimeq.c | 4 ++-- extmod/network_cyw43.c | 2 +- extmod/vfs_posix_file.c | 2 +- ports/esp32/modesp32.c | 6 +++--- ports/esp32/modmachine.c | 2 +- ports/esp32/modnetwork.c | 4 ++-- ports/esp32/mpthreadport.c | 3 ++- ports/esp8266/esp_mphal.c | 3 +-- ports/esp8266/machine_pin.c | 2 +- ports/esp8266/modesp.c | 2 +- ports/esp8266/modnetwork.c | 8 +++----- ports/nrf/boards/microbit/modules/microbitimage.c | 13 +++++-------- ports/stm32/modnetwork.c | 2 +- ports/stm32/modnwcc3k.c | 2 +- ports/stm32/modusocket.c | 2 +- ports/stm32/mpthreadport.c | 2 +- py/objint.c | 2 +- 19 files changed, 30 insertions(+), 35 deletions(-) diff --git a/extmod/moductypes.c b/extmod/moductypes.c index cf83f43e33..62bbcbac22 100644 --- a/extmod/moductypes.c +++ b/extmod/moductypes.c @@ -558,7 +558,7 @@ STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_ob uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS); arr_sz &= VALUE_MASK(VAL_TYPE_BITS); if (index >= arr_sz) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "struct: index out of range")); + mp_raise_msg(&mp_type_IndexError, "struct: index out of range"); } if (t->len == 2) { diff --git a/extmod/moduheapq.c b/extmod/moduheapq.c index 1574eb8627..f633052105 100644 --- a/extmod/moduheapq.c +++ b/extmod/moduheapq.c @@ -81,7 +81,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_uheapq_heappush_obj, mod_uheapq_heappush); STATIC mp_obj_t mod_uheapq_heappop(mp_obj_t heap_in) { mp_obj_list_t *heap = uheapq_get_heap(heap_in); if (heap->len == 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "empty heap")); + mp_raise_msg(&mp_type_IndexError, "empty heap"); } mp_obj_t item = heap->items[0]; heap->len -= 1; diff --git a/extmod/modutimeq.c b/extmod/modutimeq.c index 28a2a70c5e..0183a0f4b4 100644 --- a/extmod/modutimeq.c +++ b/extmod/modutimeq.c @@ -142,7 +142,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_utimeq_heappush_obj, 4, 4, mod_ut STATIC mp_obj_t mod_utimeq_heappop(mp_obj_t heap_in, mp_obj_t list_ref) { mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in); if (heap->len == 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "empty heap")); + mp_raise_msg(&mp_type_IndexError, "empty heap"); } mp_obj_list_t *ret = MP_OBJ_TO_PTR(list_ref); if (!mp_obj_is_type(list_ref, &mp_type_list) || ret->len < 3) { @@ -167,7 +167,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_utimeq_heappop_obj, mod_utimeq_heappop); STATIC mp_obj_t mod_utimeq_peektime(mp_obj_t heap_in) { mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in); if (heap->len == 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "empty heap")); + mp_raise_msg(&mp_type_IndexError, "empty heap"); } struct qentry *item = &heap->items[0]; diff --git a/extmod/network_cyw43.c b/extmod/network_cyw43.c index fe73b07153..45bb6163e7 100644 --- a/extmod/network_cyw43.c +++ b/extmod/network_cyw43.c @@ -196,7 +196,7 @@ STATIC mp_obj_t network_cyw43_scan(size_t n_args, const mp_obj_t *pos_args, mp_m int scan_res = cyw43_wifi_scan(self->cyw, &opts, MP_OBJ_TO_PTR(res), network_cyw43_scan_cb); if (scan_res < 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "STA must be active")); + mp_raise_msg(&mp_type_OSError, "STA must be active"); } // Wait for scan to finish, with a 10s timeout diff --git a/extmod/vfs_posix_file.c b/extmod/vfs_posix_file.c index 6f7ce814f3..30fde818eb 100644 --- a/extmod/vfs_posix_file.c +++ b/extmod/vfs_posix_file.c @@ -44,7 +44,7 @@ typedef struct _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")); + mp_raise_msg(&mp_type_ValueError, "I/O operation on closed file"); } } #else diff --git a/ports/esp32/modesp32.c b/ports/esp32/modesp32.c index ada8811676..ddc030e3fb 100644 --- a/ports/esp32/modesp32.c +++ b/ports/esp32/modesp32.c @@ -48,7 +48,7 @@ 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")); + //mp_raise_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; @@ -74,7 +74,7 @@ STATIC mp_obj_t esp32_wake_on_ext0(size_t n_args, const mp_obj_t *pos_args, mp_m 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")); + mp_raise_msg(&mp_type_ValueError, "invalid pin"); } machine_rtc_config.ext0_pin = pin_id; } @@ -109,7 +109,7 @@ STATIC mp_obj_t esp32_wake_on_ext1(size_t n_args, const mp_obj_t *pos_args, mp_m 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")); + mp_raise_msg(&mp_type_ValueError, "invalid pin"); break; } ext1_pins |= (1ll << pin_id); diff --git a/ports/esp32/modmachine.c b/ports/esp32/modmachine.c index 0c803d0960..e722ed2c5b 100644 --- a/ports/esp32/modmachine.c +++ b/ports/esp32/modmachine.c @@ -119,7 +119,7 @@ STATIC mp_obj_t machine_sleep_helper(wake_type_t wake_type, size_t n_args, const 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")); + mp_raise_msg(&mp_type_RuntimeError, "esp_sleep_enable_touchpad_wakeup() failed"); } } diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index 012dc5bce8..ba967b8cbd 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -233,7 +233,7 @@ static esp_err_t event_handler(void *ctx, system_event_t *event) { /*void error_check(bool status, const char *msg) { if (!status) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, msg)); + mp_raise_msg(&mp_type_OSError, msg); } } */ @@ -441,7 +441,7 @@ STATIC mp_obj_t esp_scan(mp_obj_t self_in) { 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_raise_msg(&mp_type_OSError, "STA must be active"); } mp_obj_t list = mp_obj_new_list(0, NULL); diff --git a/ports/esp32/mpthreadport.c b/ports/esp32/mpthreadport.c index 1c0d889e98..d7db0ff615 100644 --- a/ports/esp32/mpthreadport.c +++ b/ports/esp32/mpthreadport.c @@ -27,6 +27,7 @@ #include "stdio.h" +#include "py/runtime.h" #include "py/gc.h" #include "py/mpthread.h" #include "py/mphal.h" @@ -135,7 +136,7 @@ void mp_thread_create_ex(void *(*entry)(void*), void *arg, size_t *stack_size, i BaseType_t result = xTaskCreatePinnedToCore(freertos_entry, name, *stack_size / sizeof(StackType_t), arg, priority, &th->id, MP_TASK_COREID); if (result != pdPASS) { mp_thread_mutex_unlock(&thread_mutex); - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread")); + mp_raise_msg(&mp_type_OSError, "can't create thread"); } // adjust the stack_size to provide room to recover from hitting the limit diff --git a/ports/esp8266/esp_mphal.c b/ports/esp8266/esp_mphal.c index 2ce288ea3f..25201425b3 100644 --- a/ports/esp8266/esp_mphal.c +++ b/ports/esp8266/esp_mphal.c @@ -149,8 +149,7 @@ void ets_event_poll(void) { void __assert_func(const char *file, int line, const char *func, const char *expr) { printf("assert:%s:%d:%s: %s\n", file, line, func, expr); - nlr_raise(mp_obj_new_exception_msg(&mp_type_AssertionError, - "C-level assert")); + mp_raise_msg(&mp_type_AssertionError, "C-level assert"); } void mp_hal_signal_input(void) { diff --git a/ports/esp8266/machine_pin.c b/ports/esp8266/machine_pin.c index 14505c8f02..1200aa9dec 100644 --- a/ports/esp8266/machine_pin.c +++ b/ports/esp8266/machine_pin.c @@ -384,7 +384,7 @@ STATIC mp_obj_t pyb_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); if (self->phys_port >= 16) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "pin does not have IRQ capabilities")); + mp_raise_msg(&mp_type_OSError, "pin does not have IRQ capabilities"); } if (n_args > 1 || kw_args->used != 0) { diff --git a/ports/esp8266/modesp.c b/ports/esp8266/modesp.c index 6c9fa9e131..2aeb3d690a 100644 --- a/ports/esp8266/modesp.c +++ b/ports/esp8266/modesp.c @@ -43,7 +43,7 @@ void error_check(bool status, const char *msg) { if (!status) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, msg)); + mp_raise_msg(&mp_type_OSError, msg); } } diff --git a/ports/esp8266/modnetwork.c b/ports/esp8266/modnetwork.c index c58aae1cbd..6bdbe6e23e 100644 --- a/ports/esp8266/modnetwork.c +++ b/ports/esp8266/modnetwork.c @@ -229,8 +229,7 @@ STATIC void esp_scan_cb(void *result, STATUS status) { STATIC mp_obj_t esp_scan(mp_obj_t self_in) { require_if(self_in, STATION_IF); if ((wifi_get_opmode() & STATION_MODE) == 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, - "STA must be active")); + mp_raise_msg(&mp_type_OSError, "STA must be active"); } mp_obj_t list = mp_obj_new_list(0, NULL); esp_scan_list = &list; @@ -247,7 +246,7 @@ STATIC mp_obj_t esp_scan(mp_obj_t self_in) { ets_loop_iter(); } if (list == MP_OBJ_NULL) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "scan failed")); + mp_raise_msg(&mp_type_OSError, "scan failed"); } return list; } @@ -313,8 +312,7 @@ STATIC mp_obj_t esp_ifconfig(size_t n_args, const mp_obj_t *args) { wifi_softap_dhcps_stop(); } if (!wifi_set_ip_info(self->if_id, &info)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, - "wifi_set_ip_info() failed")); + mp_raise_msg(&mp_type_OSError, "wifi_set_ip_info() failed"); } dns_setserver(0, &dns_addr); if (restart_dhcp_server) { diff --git a/ports/nrf/boards/microbit/modules/microbitimage.c b/ports/nrf/boards/microbit/modules/microbitimage.c index fca5075089..ce4a959f08 100644 --- a/ports/nrf/boards/microbit/modules/microbitimage.c +++ b/ports/nrf/boards/microbit/modules/microbitimage.c @@ -227,8 +227,7 @@ STATIC mp_obj_t microbit_image_make_new(const mp_obj_type_t *type_in, mp_uint_t return image_from_parsed_str(str, len); } } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "Image(s) takes a string.")); + mp_raise_msg(&mp_type_TypeError, "Image(s) takes a string."); } } @@ -259,8 +258,7 @@ STATIC mp_obj_t microbit_image_make_new(const mp_obj_type_t *type_in, mp_uint_t } default: { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "Image() takes 0 to 3 arguments")); + mp_raise_msg(&mp_type_TypeError, "Image() takes 0 to 3 arguments"); } } } @@ -365,7 +363,7 @@ MP_DEFINE_CONST_FUN_OBJ_3(microbit_image_get_pixel_obj, microbit_image_get_pixel /* Raise an exception if not mutable */ static void check_mutability(microbit_image_obj_t *self) { if (self->base.five) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "image cannot be modified (try copying first)")); + mp_raise_msg(&mp_type_TypeError, "image cannot be modified (try copying first)"); } } @@ -408,11 +406,10 @@ mp_obj_t microbit_image_blit(mp_uint_t n_args, const mp_obj_t *args) { mp_obj_t src = args[1]; if (mp_obj_get_type(src) != µbit_image_type) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "expecting an image")); + mp_raise_msg(&mp_type_TypeError, "expecting an image"); } if (n_args == 7) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "must specify both offsets")); + mp_raise_msg(&mp_type_TypeError, "must specify both offsets"); } mp_int_t x = mp_obj_get_int(args[2]); mp_int_t y = mp_obj_get_int(args[3]); diff --git a/ports/stm32/modnetwork.c b/ports/stm32/modnetwork.c index 19a60103f8..4b0f77f9af 100644 --- a/ports/stm32/modnetwork.c +++ b/ports/stm32/modnetwork.c @@ -119,7 +119,7 @@ mp_obj_t mod_network_find_nic(const uint8_t *ip) { return nic; } - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "no available NIC")); + mp_raise_msg(&mp_type_OSError, "no available NIC"); } STATIC mp_obj_t network_route(void) { diff --git a/ports/stm32/modnwcc3k.c b/ports/stm32/modnwcc3k.c index 8723994f45..b3fd939228 100644 --- a/ports/stm32/modnwcc3k.c +++ b/ports/stm32/modnwcc3k.c @@ -443,7 +443,7 @@ STATIC mp_obj_t cc3k_make_new(const mp_obj_type_t *type, size_t n_args, size_t n ReadWlanInterruptPin, SpiResumeSpi, SpiPauseSpi, WriteWlanPin); if (wlan_start(0) != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "failed to init CC3000 module")); + mp_raise_msg(&mp_type_OSError, "failed to init CC3000 module"); } // set connection policy. this should be called explicitly by the user diff --git a/ports/stm32/modusocket.c b/ports/stm32/modusocket.c index 5a16331137..46d7240ca8 100644 --- a/ports/stm32/modusocket.c +++ b/ports/stm32/modusocket.c @@ -425,7 +425,7 @@ STATIC mp_obj_t mod_usocket_getaddrinfo(mp_obj_t host_in, mp_obj_t port_in) { } if (!have_ip) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "no available NIC")); + mp_raise_msg(&mp_type_OSError, "no available NIC"); } mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(5, NULL)); diff --git a/ports/stm32/mpthreadport.c b/ports/stm32/mpthreadport.c index 7b3b92934b..0077e13937 100644 --- a/ports/stm32/mpthreadport.c +++ b/ports/stm32/mpthreadport.c @@ -75,7 +75,7 @@ void mp_thread_create(void *(*entry)(void*), void *arg, size_t *stack_size) { uint32_t id = pyb_thread_new(th, stack, stack_len, entry, arg); if (id == 0) { mp_thread_mutex_unlock(&thread_mutex); - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread")); + mp_raise_msg(&mp_type_OSError, "can't create thread"); } mp_thread_mutex_unlock(&thread_mutex); diff --git a/py/objint.c b/py/objint.c index 6473767e41..2fdcf5864f 100644 --- a/py/objint.c +++ b/py/objint.c @@ -137,7 +137,7 @@ STATIC mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val) { mp_obj_t mp_obj_new_int_from_float(mp_float_t val) { int cl = fpclassify(val); if (cl == FP_INFINITE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "can't convert inf to int")); + mp_raise_msg(&mp_type_OverflowError, "can't convert inf to int"); } else if (cl == FP_NAN) { mp_raise_ValueError("can't convert NaN to int"); } else { From cddb2dd0c3f7d55599bdb0e1994f8b81f8b22d10 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 5 Nov 2019 13:20:25 +1100 Subject: [PATCH 0954/1788] stm32/mpthreadport: Include runtime.h to get defn of mp_raise_msg. --- ports/stm32/mpthreadport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/mpthreadport.c b/ports/stm32/mpthreadport.c index 0077e13937..4e1ebf064d 100644 --- a/ports/stm32/mpthreadport.c +++ b/ports/stm32/mpthreadport.c @@ -26,7 +26,7 @@ #include -#include "py/mpstate.h" +#include "py/runtime.h" #include "py/gc.h" #include "py/mpthread.h" #include "gccollect.h" From d209f9ebe72aa2af0af72ed3bba737a47c45e567 Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Mon, 4 Nov 2019 20:50:50 +0100 Subject: [PATCH 0955/1788] esp32: Remove unused "esponewire.c" in favour of extmod/modonewire. --- ports/esp32/esponewire.c | 80 ---------------------------------------- 1 file changed, 80 deletions(-) delete mode 100644 ports/esp32/esponewire.c diff --git a/ports/esp32/esponewire.c b/ports/esp32/esponewire.c deleted file mode 100644 index 781616cbe4..0000000000 --- a/ports/esp32/esponewire.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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); -} From 4f0f3dfb410062db4d41e42c2c7cff6c8b48f071 Mon Sep 17 00:00:00 2001 From: Jeremy Herbert Date: Mon, 4 Nov 2019 01:25:16 -0800 Subject: [PATCH 0956/1788] drivers/sdcard: Raise exception on timeout of readinto. Otherwise the code can get stuck in an infinite loop if the SD card fails to respond to a read. --- drivers/sdcard/sdcard.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/sdcard/sdcard.py b/drivers/sdcard/sdcard.py index ffc551d9ae..fc67875566 100644 --- a/drivers/sdcard/sdcard.py +++ b/drivers/sdcard/sdcard.py @@ -172,10 +172,13 @@ class SDCard: self.cs(0) # read until start byte (0xff) - while True: + for i in range(_CMD_TIMEOUT): self.spi.readinto(self.tokenbuf, 0xff) if self.tokenbuf[0] == _TOKEN_DATA: break + else: + self.cs(1) + raise OSError("timeout waiting for response") # read data mv = self.dummybuf_memoryview From 2f71d66ef7f6bfa93bdc51ab0eaf32cd03a81189 Mon Sep 17 00:00:00 2001 From: Mirko Vogt Date: Mon, 4 Nov 2019 23:16:37 +0000 Subject: [PATCH 0957/1788] tools/makemanifest.py: Follow symlinks when freezing linked directories. While the new manifest.py style got introduced for freezing python code into the resulting binary, the old way - where files and modules within ports/*/modules where baked into the resulting binary - was still supported via `freeze('$(PORT_DIR)/modules')` within manifest.py. However behaviour changed for symlinked directories (=modules), as those links weren't followed anymore. This commit restores the original behaviour by explicitly following symlinks within a modules/ directory --- tools/makemanifest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/makemanifest.py b/tools/makemanifest.py index 9889d50750..a3aa42ca41 100644 --- a/tools/makemanifest.py +++ b/tools/makemanifest.py @@ -147,7 +147,7 @@ def get_timestamp(path, default=None): def get_timestamp_newest(path): ts_newest = 0 - for dirpath, dirnames, filenames in os.walk(path): + for dirpath, dirnames, filenames in os.walk(path, followlinks=True): for f in filenames: ts_newest = max(ts_newest, get_timestamp(os.path.join(dirpath, f))) return ts_newest @@ -171,7 +171,7 @@ def freeze_internal(kind, path, script, opt): raise FreezeError('can only freeze one str directory') manifest_list.append((KIND_AS_STR, path, script, opt)) elif script is None: - for dirpath, dirnames, filenames in os.walk(path): + for dirpath, dirnames, filenames in os.walk(path, followlinks=True): for f in filenames: freeze_internal(kind, path, (dirpath + '/' + f)[len(path) + 1:], opt) elif not isinstance(script, str): From 9b27069e2f6d5e754adc62b3aa20e14f5b10de66 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 29 Oct 2019 17:16:30 +1100 Subject: [PATCH 0958/1788] extmod/vfs: Add autodetect of littlefs filesystem when mounting. --- extmod/vfs.c | 47 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/extmod/vfs.c b/extmod/vfs.c index f99be3098b..5f5fc633d8 100644 --- a/extmod/vfs.c +++ b/extmod/vfs.c @@ -38,6 +38,10 @@ #include "extmod/vfs_fat.h" #endif +#if MICROPY_VFS_LFS1 || MICROPY_VFS_LFS2 +#include "extmod/vfs_lfs.h" +#endif + #if MICROPY_VFS_POSIX #include "extmod/vfs_posix.h" #endif @@ -156,6 +160,44 @@ mp_import_stat_t mp_vfs_import_stat(const char *path) { } } +STATIC mp_obj_t mp_vfs_autodetect(mp_obj_t bdev_obj) { + #if MICROPY_VFS_LFS1 || MICROPY_VFS_LFS2 + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_t vfs = MP_OBJ_NULL; + mp_vfs_blockdev_t blockdev; + mp_vfs_blockdev_init(&blockdev, bdev_obj); + uint8_t buf[44]; + mp_vfs_blockdev_read_ext(&blockdev, 0, 8, sizeof(buf), buf); + #if MICROPY_VFS_LFS1 + if (memcmp(&buf[32], "littlefs", 8) == 0) { + // LFS1 + vfs = mp_type_vfs_lfs1.make_new(&mp_type_vfs_lfs1, 1, 0, &bdev_obj); + nlr_pop(); + return vfs; + } + #endif + #if MICROPY_VFS_LFS2 + if (memcmp(&buf[0], "littlefs", 8) == 0) { + // LFS2 + vfs = mp_type_vfs_lfs2.make_new(&mp_type_vfs_lfs2, 1, 0, &bdev_obj); + nlr_pop(); + return vfs; + } + #endif + nlr_pop(); + } else { + // Ignore exception (eg block device doesn't support extended readblocks) + } + #endif + + #if MICROPY_VFS_FAT + return mp_fat_vfs_type.make_new(&mp_fat_vfs_type, 1, 0, &bdev_obj); + #endif + + return bdev_obj; +} + 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[] = { @@ -178,10 +220,7 @@ mp_obj_t mp_vfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args if (dest[0] == MP_OBJ_NULL) { // Input object has no mount method, assume it's a block device and try to // auto-detect the filesystem and create the corresponding VFS entity. - // (At the moment we only support FAT filesystems.) - #if MICROPY_VFS_FAT - vfs_obj = mp_fat_vfs_type.make_new(&mp_fat_vfs_type, 1, 0, &vfs_obj); - #endif + vfs_obj = mp_vfs_autodetect(vfs_obj); } // create new object From d01ca7888b8eeeed026270742c40efe442cdd6ef Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 29 Oct 2019 17:17:10 +1100 Subject: [PATCH 0959/1788] esp32/esp32_partition: Support extended block protocol. --- ports/esp32/esp32_partition.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/ports/esp32/esp32_partition.c b/ports/esp32/esp32_partition.c index 52b3859ff0..e5bd31af0e 100644 --- a/ports/esp32/esp32_partition.c +++ b/ports/esp32/esp32_partition.c @@ -148,26 +148,33 @@ STATIC mp_obj_t esp32_partition_info(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_partition_info_obj, esp32_partition_info); -STATIC mp_obj_t esp32_partition_readblocks(mp_obj_t self_in, mp_obj_t block_num, mp_obj_t buf_in) { - esp32_partition_obj_t *self = MP_OBJ_TO_PTR(self_in); - uint32_t offset = mp_obj_get_int(block_num) * BLOCK_SIZE_BYTES; +STATIC mp_obj_t esp32_partition_readblocks(size_t n_args, const mp_obj_t *args) { + esp32_partition_obj_t *self = MP_OBJ_TO_PTR(args[0]); + uint32_t offset = mp_obj_get_int(args[1]) * BLOCK_SIZE_BYTES; mp_buffer_info_t bufinfo; - mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE); + mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_WRITE); + if (n_args == 4) { + offset += mp_obj_get_int(args[3]); + } check_esp_err(esp_partition_read(self->part, offset, bufinfo.buf, bufinfo.len)); return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp32_partition_readblocks_obj, esp32_partition_readblocks); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_partition_readblocks_obj, 3, 4, esp32_partition_readblocks); -STATIC mp_obj_t esp32_partition_writeblocks(mp_obj_t self_in, mp_obj_t block_num, mp_obj_t buf_in) { - esp32_partition_obj_t *self = MP_OBJ_TO_PTR(self_in); - uint32_t offset = mp_obj_get_int(block_num) * BLOCK_SIZE_BYTES; +STATIC mp_obj_t esp32_partition_writeblocks(size_t n_args, const mp_obj_t *args) { + esp32_partition_obj_t *self = MP_OBJ_TO_PTR(args[0]); + uint32_t offset = mp_obj_get_int(args[1]) * BLOCK_SIZE_BYTES; mp_buffer_info_t bufinfo; - mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); - check_esp_err(esp_partition_erase_range(self->part, offset, bufinfo.len)); + mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ); + if (n_args == 3) { + check_esp_err(esp_partition_erase_range(self->part, offset, bufinfo.len)); + } else { + offset += mp_obj_get_int(args[3]); + } check_esp_err(esp_partition_write(self->part, offset, bufinfo.buf, bufinfo.len)); return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp32_partition_writeblocks_obj, esp32_partition_writeblocks); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_partition_writeblocks_obj, 3, 4, esp32_partition_writeblocks); STATIC mp_obj_t esp32_partition_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t arg_in) { esp32_partition_obj_t *self = MP_OBJ_TO_PTR(self_in); @@ -178,6 +185,11 @@ STATIC mp_obj_t esp32_partition_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_ case MP_BLOCKDEV_IOCTL_SYNC: return MP_OBJ_NEW_SMALL_INT(0); case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: return MP_OBJ_NEW_SMALL_INT(self->part->size / BLOCK_SIZE_BYTES); case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: return MP_OBJ_NEW_SMALL_INT(BLOCK_SIZE_BYTES); + case MP_BLOCKDEV_IOCTL_BLOCK_ERASE: { + uint32_t offset = mp_obj_get_int(arg_in) * BLOCK_SIZE_BYTES; + check_esp_err(esp_partition_erase_range(self->part, offset, BLOCK_SIZE_BYTES)); + return MP_OBJ_NEW_SMALL_INT(0); + } default: return mp_const_none; } } From 4be316fb072ab7c2f28da815ead970ebf705c328 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 29 Oct 2019 17:17:22 +1100 Subject: [PATCH 0960/1788] esp32/moduos: Enable uos.VfsLfs2 for littlefs filesystems. This commit adds support for littlefs (v2) on all esp32 boards. The original FAT filesystem still works and any board with a preexisting FAT filesystem will still work as normal. It's possible to switch to littlefs by reformatting the block device using: import uos, flashbdev uos.VfsLfs2.mkfs(flashbdev.bdev) Then when the board reboots (soft or hard) the new littlefs filesystem will be mounted. It's possible to switch back to a FAT filesystem by formatting with uos.VfsFat.mkfs(flashbdev.bdev). --- ports/esp32/Makefile | 1 + ports/esp32/moduos.c | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 42b01a4e60..86e8cd3b26 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -31,6 +31,7 @@ MICROPY_PY_USSL = 0 MICROPY_SSL_AXTLS = 0 MICROPY_FATFS = 1 MICROPY_PY_BTREE = 1 +MICROPY_VFS_LFS2 = 1 FROZEN_MANIFEST ?= boards/manifest.py diff --git a/ports/esp32/moduos.c b/ports/esp32/moduos.c index dc85136f3d..d68df28fd5 100644 --- a/ports/esp32/moduos.c +++ b/ports/esp32/moduos.c @@ -38,6 +38,7 @@ #include "extmod/misc.h" #include "extmod/vfs.h" #include "extmod/vfs_fat.h" +#include "extmod/vfs_lfs.h" #include "genhdr/mpversion.h" extern const mp_obj_type_t mp_fat_vfs_type; @@ -123,6 +124,12 @@ STATIC const mp_rom_map_elem_t os_module_globals_table[] = { #if MICROPY_VFS_FAT { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) }, #endif + #if MICROPY_VFS_LFS1 + { MP_ROM_QSTR(MP_QSTR_VfsLfs1), MP_ROM_PTR(&mp_type_vfs_lfs1) }, + #endif + #if MICROPY_VFS_LFS2 + { MP_ROM_QSTR(MP_QSTR_VfsLfs2), MP_ROM_PTR(&mp_type_vfs_lfs2) }, + #endif #endif }; From f0e4677f0dafa027d3f534795a1849ad5430e98f Mon Sep 17 00:00:00 2001 From: Thea Flowers Date: Tue, 5 Nov 2019 17:11:10 -0800 Subject: [PATCH 0961/1788] py/emitnative: Fix typo, REG_PARENT_ARG_RET should be REG_PARENT_RET. --- py/emitnative.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/emitnative.c b/py/emitnative.c index e038b87785..fbf6659140 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -2696,7 +2696,7 @@ STATIC void emit_native_return_value(emit_t *emit) { } if (return_vtype != VTYPE_PYOBJ) { emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, return_vtype, REG_ARG_2); - #if REG_RET != REG_PARENT_ARG_RET + #if REG_RET != REG_PARENT_RET ASM_MOV_REG_REG(emit->as, REG_PARENT_RET, REG_RET); #endif } From d2e6cfd8fd1044dead49cd95795a30c42c66463c Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Wed, 6 Nov 2019 12:06:10 +1100 Subject: [PATCH 0962/1788] tools/makemanifest.py: Skip freezing unsupported files with warning. --- tools/makemanifest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/makemanifest.py b/tools/makemanifest.py index a3aa42ca41..3a5e230d8a 100644 --- a/tools/makemanifest.py +++ b/tools/makemanifest.py @@ -185,7 +185,8 @@ def freeze_internal(kind, path, script, opt): kind = k break else: - raise FreezeError('unsupported file type {}'.format(script)) + print('warn: unsupported file type, skipped freeze: {}'.format(script)) + return wanted_extension = extension_kind[kind] if not script.endswith(wanted_extension): raise FreezeError('expecting a {} file, got {}'.format(wanted_extension, script)) From 1295146a6f639091db854a6c3228ce84a35bf994 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Wed, 6 Nov 2019 17:08:28 +1100 Subject: [PATCH 0963/1788] docs/conf.py: Fix path to favicon.ico. --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 71e561c9c0..dbd1d0c562 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -159,7 +159,7 @@ else: # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -html_favicon = 'favicon.ico' +html_favicon = 'static/favicon.ico' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, From 59850c0b83e738880c8ce56c39748ae2fcb7dce1 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Wed, 6 Nov 2019 17:09:29 +1100 Subject: [PATCH 0964/1788] docs/templates/topindex.html: Replace usage of deprecated defindex.html. defindex.html (used by topindex.html) is deprecated, but topindex.html was already identical other than setting the title, so just inherit directly from layout.html. --- docs/templates/topindex.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/templates/topindex.html b/docs/templates/topindex.html index 08bf4c73e7..ff766b0cf2 100644 --- a/docs/templates/topindex.html +++ b/docs/templates/topindex.html @@ -1,4 +1,5 @@ -{% extends "defindex.html" %} +{% extends "layout.html" %} +{% set title = _('Overview') %} {% block body %}

MicroPython documentation

From d30b75e8f28b6e1593424b88b586072be4db6857 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Wed, 6 Nov 2019 17:09:51 +1100 Subject: [PATCH 0965/1788] docs/library/machine.SDCard.rst: Fix various typos. --- docs/library/machine.SDCard.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/library/machine.SDCard.rst b/docs/library/machine.SDCard.rst index 8398624c15..cf86b1fcb2 100644 --- a/docs/library/machine.SDCard.rst +++ b/docs/library/machine.SDCard.rst @@ -5,8 +5,8 @@ class SDCard -- secure digital memory card ========================================== SD cards are one of the most common small form factor removable storage media. -SD cards come in a variety of sizes and phsyical form factors. MMC cards are -similar removable storage devices while eMMC devices are electically similar +SD cards come in a variety of sizes and physical form factors. MMC cards are +similar removable storage devices while eMMC devices are electrically similar storage devices designed to be embedded into other systems. All three form share a common protocol for communication with their host system and high-level support looks the same for them all. As such in MicroPython they are implemented @@ -15,12 +15,12 @@ in a single class called :class:`machine.SDCard` . Both SD and MMC interfaces support being accessed with a variety of bus widths. When being accessed with a 1-bit wide interface they can be accessed using the SPI protocol. Different MicroPython hardware platforms support different widths -and pin configurations but for most platforms there is a standard configuation -for any given hardware. In general constructing an `SDCard`` object with without +and pin configurations but for most platforms there is a standard configuration +for any given hardware. In general constructing an ``SDCard`` object with without passing any parameters will initialise the interface to the default card slot for the current hardware. The arguments listed below represent the common -arguments that might need to be set in order to use either a non-stanard slot -or a non-standard pin assignment. The exact subset of arguments suported will +arguments that might need to be set in order to use either a non-standard slot +or a non-standard pin assignment. The exact subset of arguments supported will vary from platform to platform. .. class:: SDCard(slot=1, width=1, cd=None, wp=None, sck=None, miso=None, mosi=None, cs=None) @@ -32,7 +32,7 @@ vary from platform to platform. uos.mount(machine.SDCard(), "/sd") - The constrcutor takes the following paramters: + The constructor takes the following parameters: - *slot* selects which of the available interfaces to use. Leaving this unset will select the default interface. From 6eee5413ff10a5e60ffd797d78a090c7edc6268e Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 7 Nov 2019 18:43:37 +1100 Subject: [PATCH 0966/1788] esp8266/modules/flashbdev.py: Support extended block protocol. --- ports/esp8266/modules/flashbdev.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/ports/esp8266/modules/flashbdev.py b/ports/esp8266/modules/flashbdev.py index 80ddcfbf91..4273b2639c 100644 --- a/ports/esp8266/modules/flashbdev.py +++ b/ports/esp8266/modules/flashbdev.py @@ -10,15 +10,17 @@ class FlashBdev: def __init__(self, blocks=NUM_BLK): 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 readblocks(self, n, buf, off=0): + #print("readblocks(%s, %x(%d), %d)" % (n, id(buf), len(buf), off)) + esp.flash_read((n + self.START_SEC) * self.SEC_SIZE + off, buf) - def writeblocks(self, n, buf): - #print("writeblocks(%s, %x(%d))" % (n, id(buf), len(buf))) + def writeblocks(self, n, buf, off=None): + #print("writeblocks(%s, %x(%d), %d)" % (n, id(buf), len(buf), off)) #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) + if off is None: + esp.flash_erase(n + self.START_SEC) + off = 0 + esp.flash_write((n + self.START_SEC) * self.SEC_SIZE + off, buf) def ioctl(self, op, arg): #print("ioctl(%d, %r)" % (op, arg)) @@ -26,6 +28,9 @@ class FlashBdev: return self.blocks if op == 5: # MP_BLOCKDEV_IOCTL_BLOCK_SIZE return self.SEC_SIZE + if op == 6: # MP_BLOCKDEV_IOCTL_BLOCK_ERASE + esp.flash_erase(arg + self.START_SEC) + return 0 size = esp.flash_size() if size < 1024*1024: From cea9209e0f16d0849426f418316eeafbc91f60dc Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 7 Nov 2019 18:44:16 +1100 Subject: [PATCH 0967/1788] esp8266/moduos: Add optional support for VfsLfs1 and VfsLfs2. With this commit an esp8266-based board can now be built with littlefs support via, eg "make MICROPY_VFS_LFS2=1". --- ports/esp8266/boards/esp8266_common.ld | 1 + ports/esp8266/moduos.c | 13 +++++++++++-- ports/esp8266/mpconfigport.h | 8 ++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/ports/esp8266/boards/esp8266_common.ld b/ports/esp8266/boards/esp8266_common.ld index ce67e48048..09896d5229 100644 --- a/ports/esp8266/boards/esp8266_common.ld +++ b/ports/esp8266/boards/esp8266_common.ld @@ -132,6 +132,7 @@ SECTIONS *lib/axtls/*.o(.literal*, .text*) *lib/berkeley-db-1.xx/*.o(.literal*, .text*) *lib/libm/*.o*(.literal*, .text*) + *lib/littlefs/*.o*(.literal*, .text*) *lib/mp-readline/*.o(.literal*, .text*) *lib/netutils/*.o*(.literal*, .text*) *lib/timeutils/*.o*(.literal*, .text*) diff --git a/ports/esp8266/moduos.c b/ports/esp8266/moduos.c index eab70e0638..b66d5ccf4a 100644 --- a/ports/esp8266/moduos.c +++ b/ports/esp8266/moduos.c @@ -32,6 +32,7 @@ #include "extmod/misc.h" #include "extmod/vfs.h" #include "extmod/vfs_fat.h" +#include "extmod/vfs_lfs.h" #include "genhdr/mpversion.h" #include "esp_mphal.h" #include "user_interface.h" @@ -105,8 +106,7 @@ STATIC const mp_rom_map_elem_t os_module_globals_table[] = { { 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 - { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) }, + #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) }, @@ -119,6 +119,15 @@ STATIC const mp_rom_map_elem_t os_module_globals_table[] = { { 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 + #if MICROPY_VFS_LFS1 + { MP_ROM_QSTR(MP_QSTR_VfsLfs1), MP_ROM_PTR(&mp_type_vfs_lfs1) }, + #endif + #if MICROPY_VFS_LFS2 + { MP_ROM_QSTR(MP_QSTR_VfsLfs2), MP_ROM_PTR(&mp_type_vfs_lfs2) }, + #endif #endif }; diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h index 7263193928..22ca99b2b1 100644 --- a/ports/esp8266/mpconfigport.h +++ b/ports/esp8266/mpconfigport.h @@ -137,8 +137,16 @@ void *esp_native_code_commit(void*, size_t); // printer for debugging output, goes to UART only extern const struct _mp_print_t mp_debug_print; +#if MICROPY_VFS_FAT #define mp_type_fileio mp_type_vfs_fat_fileio #define mp_type_textio mp_type_vfs_fat_textio +#elif MICROPY_VFS_LFS1 +#define mp_type_fileio mp_type_vfs_lfs1_fileio +#define mp_type_textio mp_type_vfs_lfs1_textio +#elif MICROPY_VFS_LFS2 +#define mp_type_fileio mp_type_vfs_lfs2_fileio +#define mp_type_textio mp_type_vfs_lfs2_textio +#endif // use vfs's functions for import stat and builtin open #define mp_import_stat mp_vfs_import_stat From 7e374d2317d869b3471c980e1e3cd65f2f43e450 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 7 Nov 2019 19:43:23 +1100 Subject: [PATCH 0968/1788] py/emitnx86: Make mp_f_n_args table match order of mp_fun_kind_t. --- py/emitnx86.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/py/emitnx86.c b/py/emitnx86.c index 0122e46bab..790cae04c2 100644 --- a/py/emitnx86.c +++ b/py/emitnx86.c @@ -34,13 +34,11 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = { [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_LIST_APPEND] = 2, + [MP_F_STORE_MAP] = 3, [MP_F_MAKE_FUNCTION_FROM_RAW_CODE] = 3, [MP_F_NATIVE_CALL_FUNCTION_N_KW] = 3, [MP_F_CALL_METHOD_N_KW] = 3, @@ -53,9 +51,7 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = { [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, @@ -66,6 +62,7 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = { [MP_F_SMALL_INT_FLOOR_DIVIDE] = 2, [MP_F_SMALL_INT_MODULO] = 2, [MP_F_NATIVE_YIELD_FROM] = 3, + [MP_F_SETJMP] = 1, }; #define N_X86 (1) From 1266ba97545b66c93e33a2d4c4e665cdbd14228c Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 7 Nov 2019 18:22:42 +1100 Subject: [PATCH 0969/1788] examples/embedding: Remove obsolete fatfs files from build. --- examples/embedding/Makefile.upylib | 7 ------- 1 file changed, 7 deletions(-) diff --git a/examples/embedding/Makefile.upylib b/examples/embedding/Makefile.upylib index 6d6302050c..0e388332e6 100644 --- a/examples/embedding/Makefile.upylib +++ b/examples/embedding/Makefile.upylib @@ -149,13 +149,6 @@ LIB_SRC_C = $(addprefix lib/,\ timeutils/timeutils.c \ ) -ifeq ($(MICROPY_FATFS),1) -LIB_SRC_C += $(addprefix lib/,\ - fatfs/ff.c \ - fatfs/option/ccsbcs.c \ - ) -endif - OBJ = $(PY_O) OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) From 799b6d1e0c5bfb2392b7978f549ab2c7d2e0cc29 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 7 Nov 2019 18:27:51 +1100 Subject: [PATCH 0970/1788] extmod: Consolidate FAT FS config to MICROPY_VFS_FAT across all ports. This commit removes the Makefile-level MICROPY_FATFS config and moves the MICROPY_VFS_FAT config to the Makefile level to replace it. It also moves the include of the oofatfs source files in the build from each port to a central place in extmod/extmod.mk. For a port to enabled VFS FAT support it should now set MICROPY_VFS_FAT=1 at the level of the Makefile. This will include the relevant oofatfs files in the build and set MICROPY_VFS_FAT=1 at the C (preprocessor) level. --- extmod/extmod.mk | 15 ++++++++++++++- ports/esp32/Makefile | 8 +------- ports/esp32/mpconfigport.h | 1 - ports/esp8266/Makefile | 7 ------- ports/esp8266/boards/GENERIC/mpconfigboard.h | 1 - ports/esp8266/boards/GENERIC/mpconfigboard.mk | 1 + .../esp8266/boards/GENERIC_512K/mpconfigboard.mk | 2 +- ports/nrf/Makefile | 5 ++--- ports/nrf/README.md | 6 +++--- ports/nrf/mpconfigport.h | 1 - ports/stm32/Makefile | 5 +---- ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.h | 1 - .../stm32/boards/B_L072Z_LRWAN1/mpconfigboard.mk | 3 +++ ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h | 1 - ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.mk | 3 +++ ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.h | 1 - ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.mk | 3 +++ ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h | 1 - ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.mk | 3 +++ ports/stm32/mpconfigport.h | 3 --- ports/stm32/mpconfigport.mk | 3 +++ ports/unix/Makefile | 8 +------- ports/unix/mpconfigport.h | 1 - ports/unix/mpconfigport_coverage.h | 2 -- 24 files changed, 39 insertions(+), 46 deletions(-) create mode 100644 ports/esp8266/boards/GENERIC/mpconfigboard.mk diff --git a/extmod/extmod.mk b/extmod/extmod.mk index e714b60287..69d8cfad32 100644 --- a/extmod/extmod.mk +++ b/extmod/extmod.mk @@ -1,7 +1,20 @@ # This makefile fragment provides rules to build 3rd-party components for extmod modules +################################################################################ +# VFS FAT FS + +OOFATFS_DIR = lib/oofatfs + # this sets the config file for FatFs -CFLAGS_MOD += -DFFCONF_H=\"lib/oofatfs/ffconf.h\" +CFLAGS_MOD += -DFFCONF_H=\"$(OOFATFS_DIR)/ffconf.h\" + +ifeq ($(MICROPY_VFS_FAT),1) +CFLAGS_MOD += -DMICROPY_VFS_FAT=1 +SRC_MOD += $(addprefix $(OOFATFS_DIR)/,\ + ff.c \ + ffunicode.c \ + ) +endif ################################################################################ # VFS littlefs diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 86e8cd3b26..e3b14495d5 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -29,8 +29,8 @@ QSTR_GLOBAL_REQUIREMENTS = $(SDKCONFIG_H) MICROPY_PY_USSL = 0 MICROPY_SSL_AXTLS = 0 -MICROPY_FATFS = 1 MICROPY_PY_BTREE = 1 +MICROPY_VFS_FAT = 1 MICROPY_VFS_LFS2 = 1 FROZEN_MANIFEST ?= boards/manifest.py @@ -348,12 +348,6 @@ LIB_SRC_C = $(addprefix lib/,\ utils/sys_stdio_mphal.c \ ) -ifeq ($(MICROPY_FATFS), 1) -LIB_SRC_C += \ - lib/oofatfs/ff.c \ - lib/oofatfs/ffunicode.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 6cf86446b2..da62beb4c1 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -61,7 +61,6 @@ void *esp_native_code_commit(void*, size_t); #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) diff --git a/ports/esp8266/Makefile b/ports/esp8266/Makefile index f1b718c781..f534eb6895 100644 --- a/ports/esp8266/Makefile +++ b/ports/esp8266/Makefile @@ -22,7 +22,6 @@ QSTR_GLOBAL_DEPENDENCIES = $(BOARD_DIR)/mpconfigboard.h MICROPY_PY_USSL = 1 MICROPY_SSL_AXTLS = 1 AXTLS_DEFS_EXTRA = -Dabort=abort_ -DRT_MAX_PLAIN_LENGTH=1024 -DRT_EXTRA=4096 -MICROPY_FATFS ?= 1 MICROPY_PY_BTREE ?= 1 BTREE_DEFS_EXTRA = -DDEFPSIZE=1024 -DMINCACHE=3 @@ -147,12 +146,6 @@ LIB_SRC_C = $(addprefix lib/,\ utils/sys_stdio_mphal.c \ ) -ifeq ($(MICROPY_FATFS), 1) -LIB_SRC_C += \ - lib/oofatfs/ff.c \ - lib/oofatfs/ffunicode.c -endif - DRIVERS_SRC_C = $(addprefix drivers/,\ bus/softspi.c \ dht/dht.c \ diff --git a/ports/esp8266/boards/GENERIC/mpconfigboard.h b/ports/esp8266/boards/GENERIC/mpconfigboard.h index a7cacb815e..8f0505d074 100644 --- a/ports/esp8266/boards/GENERIC/mpconfigboard.h +++ b/ports/esp8266/boards/GENERIC/mpconfigboard.h @@ -10,7 +10,6 @@ #define MICROPY_READER_VFS (MICROPY_VFS) #define MICROPY_VFS (1) -#define MICROPY_VFS_FAT (1) #define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) #define MICROPY_PY_ALL_SPECIAL_METHODS (1) diff --git a/ports/esp8266/boards/GENERIC/mpconfigboard.mk b/ports/esp8266/boards/GENERIC/mpconfigboard.mk new file mode 100644 index 0000000000..86593ff60e --- /dev/null +++ b/ports/esp8266/boards/GENERIC/mpconfigboard.mk @@ -0,0 +1 @@ +MICROPY_VFS_FAT = 1 diff --git a/ports/esp8266/boards/GENERIC_512K/mpconfigboard.mk b/ports/esp8266/boards/GENERIC_512K/mpconfigboard.mk index 90f3c1773d..32fd4e0077 100644 --- a/ports/esp8266/boards/GENERIC_512K/mpconfigboard.mk +++ b/ports/esp8266/boards/GENERIC_512K/mpconfigboard.mk @@ -1,3 +1,3 @@ -MICROPY_FATFS = 0 MICROPY_PY_BTREE = 0 +MICROPY_VFS_FAT = 0 LD_FILES = boards/esp8266_512k.ld diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index 62208525fe..2ac654911e 100644 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -43,8 +43,7 @@ include ../../py/py.mk GIT_SUBMODULES = lib/nrfx lib/tinyusb -MICROPY_FATFS ?= 0 -FATFS_DIR = lib/oofatfs +MICROPY_VFS_FAT ?= 0 MPY_CROSS = ../../mpy-cross/mpy-cross MPY_TOOL = ../../tools/mpy-tool.py @@ -318,7 +317,7 @@ OBJ += $(addprefix $(BUILD)/, $(SYSTEM_C_SRC:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_LIB:.c=.o)) OBJ += $(BUILD)/pins_gen.o -$(BUILD)/$(FATFS_DIR)/ff.o: COPT += -Os +$(BUILD)/$(OOFATFS_DIR)/ff.o: COPT += -Os $(filter $(PY_BUILD)/../extmod/vfs_fat_%.o, $(PY_O)): COPT += -Os .PHONY: all flash deploy sd binary hex diff --git a/ports/nrf/README.md b/ports/nrf/README.md index 3c177c705c..b5f39267eb 100644 --- a/ports/nrf/README.md +++ b/ports/nrf/README.md @@ -107,12 +107,12 @@ To use frozen modules, put them in a directory (e.g. `freeze/`) and supply make BOARD=pca10040 FROZEN_MPY_DIR=freeze -## Enable MICROPY_FATFS -As the `oofatfs` module is not having header guards that can exclude the implementation compile time, this port provides a flag to enable it explicitly. The MICROPY_FATFS is by default set to 0 and has to be set to 1 if `oofatfs` files should be compiled. This will be in addition of setting `MICROPY_VFS` and `MICROPY_VFS_FAT` in mpconfigport.h. +## Enable MICROPY_VFS_FAT +As the `oofatfs` module is not having header guards that can exclude the implementation compile time, this port provides a flag to enable it explicitly. The MICROPY_VFS_FAT is by default set to 0 and has to be set to 1 if `oofatfs` files should be compiled. This will be in addition of setting `MICROPY_VFS` in mpconfigport.h. For example: - make BOARD=pca10040 MICROPY_FATFS=1 + make BOARD=pca10040 MICROPY_VFS_FAT=1 ## Target Boards and Make Flags diff --git a/ports/nrf/mpconfigport.h b/ports/nrf/mpconfigport.h index 71f9f6804d..e5fa1579c5 100644 --- a/ports/nrf/mpconfigport.h +++ b/ports/nrf/mpconfigport.h @@ -33,7 +33,6 @@ #ifndef MICROPY_VFS #define MICROPY_VFS (0) #endif -#define MICROPY_VFS_FAT (MICROPY_VFS) #define MICROPY_ALLOC_PATH_MAX (512) #define MICROPY_PERSISTENT_CODE_LOAD (0) #define MICROPY_EMIT_THUMB (0) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 99d2248fd4..61ce06ca8c 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -34,7 +34,6 @@ CMSIS_DIR=$(TOP)/lib/stm32lib/CMSIS/STM32$(MCU_SERIES_UPPER)xx/Include HAL_DIR=lib/stm32lib/STM32$(MCU_SERIES_UPPER)xx_HAL_Driver USBDEV_DIR=usbdev #USBHOST_DIR=usbhost -FATFS_DIR=lib/oofatfs DFU=$(TOP)/tools/dfu.py # may need to prefix dfu-util with sudo USE_PYDFU ?= 1 @@ -128,8 +127,6 @@ MPY_CROSS_FLAGS += -march=armv7m SRC_LIB = $(addprefix lib/,\ libc/string0.c \ - oofatfs/ff.c \ - oofatfs/ffunicode.c \ mp-readline/readline.c \ netutils/netutils.c \ netutils/trace.c \ @@ -480,7 +477,7 @@ $(BUILD)/lib/libc/string0.o: COPT += -O2 # 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) # and comment out the following lines. -$(BUILD)/$(FATFS_DIR)/ff.o: COPT += -Os +$(BUILD)/$(OOFATFS_DIR)/ff.o: COPT += -Os $(filter $(PY_BUILD)/../extmod/vfs_fat_%.o, $(PY_O)): COPT += -Os $(PY_BUILD)/formatfloat.o: COPT += -Os $(PY_BUILD)/parsenum.o: COPT += -Os diff --git a/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.h b/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.h index 7a80f26356..25cfcbde76 100644 --- a/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.h +++ b/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.h @@ -14,7 +14,6 @@ #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) diff --git a/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.mk b/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.mk index e2ced61183..03561f90ad 100644 --- a/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.mk +++ b/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.mk @@ -4,5 +4,8 @@ MICROPY_FLOAT_IMPL = none AF_FILE = boards/stm32l072_af.csv LD_FILES = boards/stm32l072xz.ld boards/common_basic.ld +# MicroPython settings +MICROPY_VFS_FAT = 0 + # Don't include default frozen modules because MCU is tight on flash space FROZEN_MANIFEST ?= diff --git a/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h index 366822d0d4..fb8de60221 100644 --- a/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h @@ -7,7 +7,6 @@ #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) diff --git a/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.mk index 5efa0d4a5d..984fe2f900 100644 --- a/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.mk @@ -3,5 +3,8 @@ CMSIS_MCU = STM32F091xC AF_FILE = boards/stm32f091_af.csv LD_FILES = boards/stm32f091xc.ld boards/common_basic.ld +# MicroPython settings +MICROPY_VFS_FAT = 0 + # Don't include default frozen modules because MCU is tight on flash space FROZEN_MANIFEST ?= diff --git a/ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.h b/ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.h index e20dff6771..e9753958dd 100644 --- a/ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.h @@ -14,7 +14,6 @@ #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) diff --git a/ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.mk index 5afe134ba0..f3673f0060 100644 --- a/ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.mk @@ -3,5 +3,8 @@ CMSIS_MCU = STM32L073xx AF_FILE = boards/stm32l072_af.csv LD_FILES = boards/stm32l072xz.ld boards/common_basic.ld +# MicroPython settings +MICROPY_VFS_FAT = 0 + # Don't include default frozen modules because MCU is tight on flash space FROZEN_MANIFEST ?= diff --git a/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h b/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h index e7202efe02..945cccb506 100644 --- a/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h @@ -8,7 +8,6 @@ #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) diff --git a/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.mk index 7c7cd34f0e..6e220a4370 100644 --- a/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.mk @@ -4,5 +4,8 @@ AF_FILE = boards/stm32l432_af.csv LD_FILES = boards/stm32l432.ld boards/common_basic.ld OPENOCD_CONFIG = boards/openocd_stm32l4.cfg +# MicroPython settings +MICROPY_VFS_FAT = 0 + # Don't include default frozen modules because MCU is tight on flash space FROZEN_MANIFEST ?= diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 11c2372385..fc54026f6b 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -84,9 +84,6 @@ #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) diff --git a/ports/stm32/mpconfigport.mk b/ports/stm32/mpconfigport.mk index e708de6c1b..c6b3ddc74f 100644 --- a/ports/stm32/mpconfigport.mk +++ b/ports/stm32/mpconfigport.mk @@ -8,3 +8,6 @@ MICROPY_PY_WIZNET5K ?= 0 # cc3k module for wifi support MICROPY_PY_CC3K ?= 0 + +# VFS FAT FS support +MICROPY_VFS_FAT ?= 1 diff --git a/ports/unix/Makefile b/ports/unix/Makefile index 9a4453261c..2fa1373e73 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -163,12 +163,6 @@ LIB_SRC_C = $(addprefix lib/,\ timeutils/timeutils.c \ ) -# FatFS VFS support -LIB_SRC_C += $(addprefix lib/,\ - oofatfs/ff.c \ - oofatfs/ffunicode.c \ - ) - OBJ = $(PY_O) OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) @@ -257,7 +251,7 @@ coverage: -Wold-style-definition -Wpointer-arith -Wshadow -Wuninitialized -Wunused-parameter \ -DMICROPY_UNIX_COVERAGE' \ LDFLAGS_EXTRA='-fprofile-arcs -ftest-coverage' \ - MICROPY_VFS_LFS1=1 MICROPY_VFS_LFS2=1 \ + MICROPY_VFS_FAT=1 MICROPY_VFS_LFS1=1 MICROPY_VFS_LFS2=1 \ FROZEN_MANIFEST=manifest_coverage.py \ BUILD=build-coverage PROG=micropython_coverage diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h index e42ad5e49c..40cd1f5702 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -152,7 +152,6 @@ #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 MICROPY_VFS_FAT (0) // Define to MICROPY_ERROR_REPORTING_DETAILED to get function, etc. // names in exception messages (may require more RAM). diff --git a/ports/unix/mpconfigport_coverage.h b/ports/unix/mpconfigport_coverage.h index afd3646490..8a0bf3be48 100644 --- a/ports/unix/mpconfigport_coverage.h +++ b/ports/unix/mpconfigport_coverage.h @@ -55,8 +55,6 @@ #define MICROPY_PY_URE_MATCH_SPAN_START_END (1) #define MICROPY_PY_URE_SUB (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) #define MICROPY_PY_UCRYPTOLIB (1) From 71299d3224b6f8422f540c91cc0d3f0e89408e90 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Thu, 7 Nov 2019 22:00:01 +1100 Subject: [PATCH 0971/1788] esp32/boards/sdkconfig.base: Resize SSL output buffer from 16 to 4kiB. The IDF heap is more fragmented with IDF 4 and mbedtls cannot allocate enough RAM with 16+16kiB for both in and out buffers, so reduce output buffer size. Fixes issue #5303. --- ports/esp32/boards/sdkconfig.base | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/esp32/boards/sdkconfig.base b/ports/esp32/boards/sdkconfig.base index 9348f40632..2c77c20907 100644 --- a/ports/esp32/boards/sdkconfig.base +++ b/ports/esp32/boards/sdkconfig.base @@ -28,6 +28,10 @@ CONFIG_LWIP_PPP_SUPPORT=y CONFIG_LWIP_PPP_PAP_SUPPORT=y CONFIG_LWIP_PPP_CHAP_SUPPORT=y +# SSL +# Use 4kiB output buffer instead of default 16kiB (because IDF heap is fragmented in 4.0) +CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y + # v3.3-only (renamed in 4.0) CONFIG_LOG_BOOTLOADER_LEVEL_WARN=y CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=n From 258b1478307c1f9d89ed67309e145b9a55aeaadc Mon Sep 17 00:00:00 2001 From: Mike Causer Date: Fri, 8 Nov 2019 13:21:10 +1100 Subject: [PATCH 0972/1788] stm32/boards/stm32f405_af.csv: Fix typo in ETH_RMII_REF_CLK on PA1. --- ports/stm32/boards/stm32f405_af.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/boards/stm32f405_af.csv b/ports/stm32/boards/stm32f405_af.csv index e6d8fcc2b5..2602db8775 100644 --- a/ports/stm32/boards/stm32f405_af.csv +++ b/ports/stm32/boards/stm32f405_af.csv @@ -1,7 +1,7 @@ Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15, ,,SYS,TIM1/2,TIM3/4/5,TIM8/9/10/11,I2C1/2/3,SPI1/SPI2/I2S2/I2S2ext,SPI3/I2Sext/I2S3,USART1/2/3/I2S3ext,UART4/5/USART6,CAN1/CAN2/TIM12/13/14,OTG_FS/OTG_HS,ETH,FSMC/SDIO/OTG_FS,DCMI,,,ADC PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,,ETH_MII_CRS,,,,EVENTOUT,ADC123_IN0 -PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,,,ETH_MII_RX_CLK/ETH_RMII__REF_CLK,,,,EVENTOUT,ADC123_IN1 +PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,,,ETH_MII_RX_CLK/ETH_RMII_REF_CLK,,,,EVENTOUT,ADC123_IN1 PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,,,,ETH_MDIO,,,,EVENTOUT,ADC123_IN2 PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,,OTG_HS_ULPI_D0,ETH_MII_COL,,,,EVENTOUT,ADC123_IN3 PortA,PA4,,,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,USART2_CK,,,,,OTG_HS_SOF,DCMI_HSYNC,,EVENTOUT,ADC12_IN4 From d667bc642ffb9603e85f50be73a32871427c5fa6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 12 Nov 2019 15:15:12 +1100 Subject: [PATCH 0973/1788] docs/library/ubluetooth: Fix name and link to FLAG_xxx constants. --- docs/library/ubluetooth.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/library/ubluetooth.rst b/docs/library/ubluetooth.rst index 5d44ffdb29..6e95a9e92e 100644 --- a/docs/library/ubluetooth.rst +++ b/docs/library/ubluetooth.rst @@ -203,8 +203,8 @@ writes from a central to a given characteristic, use value. The **flags** are a bitwise-OR combination of the - :data:`ubluetooth.FLAGS_READ`, :data:`bluetooth.FLAGS_WRITE` and - :data:`ubluetooth.FLAGS_NOTIFY` values defined below. + :data:`ubluetooth.FLAG_READ`, :data:`ubluetooth.FLAG_WRITE` and + :data:`ubluetooth.FLAG_NOTIFY` values defined below. The return value is a list (one element per service) of tuples (each element is a value handle). Characteristics and descriptor handles are flattened From b2dd443d927ecd739111cdb0a0e94fe89c848312 Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Mon, 11 Nov 2019 15:46:11 +0200 Subject: [PATCH 0974/1788] tools/makemanifest.py: Use sys.executable when invoking Python scripts. So the version of Python used to run makemanifest.py is also used for the sub-scripts. --- tools/makemanifest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/makemanifest.py b/tools/makemanifest.py index 3a5e230d8a..90cec2bb48 100644 --- a/tools/makemanifest.py +++ b/tools/makemanifest.py @@ -270,13 +270,13 @@ def main(): return # Freeze paths as strings - res, output_str = system([MAKE_FROZEN] + str_paths) + res, output_str = system([sys.executable, MAKE_FROZEN] + str_paths) if res != 0: print('error freezing strings {}: {}'.format(str_paths, output_str)) sys.exit(1) # Freeze .mpy files - res, output_mpy = system([MPY_TOOL, '-f', '-q', args.build_dir + '/genhdr/qstrdefs.preprocessed.h'] + mpy_files) + res, output_mpy = system([sys.executable, MPY_TOOL, '-f', '-q', args.build_dir + '/genhdr/qstrdefs.preprocessed.h'] + mpy_files) if res != 0: print('error freezing mpy {}: {}'.format(mpy_files, output_mpy)) sys.exit(1) From 82d358510b38b092dac204786c193d8109dcf886 Mon Sep 17 00:00:00 2001 From: Josh Lloyd Date: Mon, 11 Nov 2019 15:57:34 +1300 Subject: [PATCH 0975/1788] esp32/rtc: Set system microseconds when setting time via RTC.datetime(). --- ports/esp32/machine_rtc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/esp32/machine_rtc.c b/ports/esp32/machine_rtc.c index 08c7b02bfd..2cb30e75e2 100644 --- a/ports/esp32/machine_rtc.c +++ b/ports/esp32/machine_rtc.c @@ -103,6 +103,7 @@ STATIC mp_obj_t machine_rtc_datetime_helper(mp_uint_t n_args, const mp_obj_t *ar 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])); + tv.tv_usec = mp_obj_get_int(items[7]); settimeofday(&tv, NULL); return mp_const_none; From 1e87f11d3f2673ace3f36dd24bdc095bb25583e4 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Mon, 11 Nov 2019 15:44:04 +1100 Subject: [PATCH 0976/1788] py/objdict: Support ujson.dump() of OrderedDict objects. Following CPython, OrderedDict are dumped with the syntax of dict. --- py/objdict.c | 4 ++-- tests/extmod/ujson_dumps_ordereddict.py | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 tests/extmod/ujson_dumps_ordereddict.py diff --git a/py/objdict.c b/py/objdict.c index 02a2346fde..7a43a85485 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -60,7 +60,7 @@ STATIC void dict_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_ if (!(MICROPY_PY_UJSON && kind == PRINT_JSON)) { kind = PRINT_REPR; } - if (MICROPY_PY_COLLECTIONS_ORDEREDDICT && self->base.type != &mp_type_dict) { + if (MICROPY_PY_COLLECTIONS_ORDEREDDICT && self->base.type != &mp_type_dict && kind != PRINT_JSON) { mp_printf(print, "%q(", self->base.type->name); } mp_print_str(print, "{"); @@ -83,7 +83,7 @@ STATIC void dict_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_ mp_obj_print_helper(print, next->value, kind); } mp_print_str(print, "}"); - if (MICROPY_PY_COLLECTIONS_ORDEREDDICT && self->base.type != &mp_type_dict) { + if (MICROPY_PY_COLLECTIONS_ORDEREDDICT && self->base.type != &mp_type_dict && kind != PRINT_JSON) { mp_print_str(print, ")"); } } diff --git a/tests/extmod/ujson_dumps_ordereddict.py b/tests/extmod/ujson_dumps_ordereddict.py new file mode 100644 index 0000000000..c6f4a8fcb7 --- /dev/null +++ b/tests/extmod/ujson_dumps_ordereddict.py @@ -0,0 +1,12 @@ +try: + import ujson as json + from ucollections import OrderedDict +except ImportError: + try: + import json + from collections import OrderedDict + except ImportError: + print("SKIP") + raise SystemExit + +print(json.dumps(OrderedDict(((1, 2), (3, 4))))) From 973f68780d2eb974e4921ffdf513079efc19e0a4 Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Mon, 11 Nov 2019 12:51:23 +0200 Subject: [PATCH 0977/1788] qemu-arm: Add ldscript dependency in the final firmware.elf target. So that the target is rebuilt if the linker script changes. --- ports/qemu-arm/Makefile | 8 ++++++-- ports/qemu-arm/Makefile.test | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/ports/qemu-arm/Makefile b/ports/qemu-arm/Makefile index 92574d0e11..e06e5dd5ee 100644 --- a/ports/qemu-arm/Makefile +++ b/ports/qemu-arm/Makefile @@ -104,10 +104,14 @@ OBJ_COMMON += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) OBJ_RUN = OBJ_RUN += $(addprefix $(BUILD)/, $(SRC_RUN_C:.c=.o)) +ALL_OBJ_RUN = $(OBJ_COMMON) $(OBJ_RUN) + OBJ_TEST = OBJ_TEST += $(addprefix $(BUILD)/, $(SRC_TEST_C:.c=.o)) OBJ_TEST += $(BUILD)/tinytest.o +ALL_OBJ_TEST = $(OBJ_COMMON) $(OBJ_TEST) + # All object files, needed to get dependencies correct OBJ = $(OBJ_COMMON) $(OBJ_RUN) $(OBJ_TEST) @@ -127,8 +131,8 @@ run: $(BUILD)/firmware.elf qemu-system-arm -machine $(BOARD) $(QEMU_EXTRA) -nographic -monitor null -semihosting -kernel $< ## `$(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)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS) +$(BUILD)/firmware.elf: $(LDSCRIPT) $(ALL_OBJ_RUN) + $(Q)$(LD) $(LDFLAGS) -o $@ $(ALL_OBJ_RUN) $(LIBS) $(Q)$(SIZE) $@ include $(TOP)/py/mkrules.mk diff --git a/ports/qemu-arm/Makefile.test b/ports/qemu-arm/Makefile.test index 4204a84f0d..df0ba9939d 100644 --- a/ports/qemu-arm/Makefile.test +++ b/ports/qemu-arm/Makefile.test @@ -16,8 +16,8 @@ $(BUILD)/genhdr/tests.h: $(BUILD)/tinytest.o: $(Q)$(CC) $(CFLAGS) -DNO_FORKING -o $@ -c $(TINYTEST)/tinytest.c -$(BUILD)/firmware-test.elf: $(OBJ_COMMON) $(OBJ_TEST) - $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS) +$(BUILD)/firmware-test.elf: $(LDSCRIPT) $(ALL_OBJ_TEST) + $(Q)$(LD) $(LDFLAGS) -o $@ $(ALL_OBJ_TEST) $(LIBS) $(Q)$(SIZE) $@ # Note: Using timeout(1) to handle cases where qemu hangs (e.g. this can happen with alignment errors). From 4f966892813b1b0c43f7ad1d97a7dcd77c646302 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 11 Nov 2019 17:07:11 +1100 Subject: [PATCH 0978/1788] py/ringbuf: Add peek16 method. --- py/ringbuf.c | 19 +++++++++++++------ py/ringbuf.h | 1 + 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/py/ringbuf.c b/py/ringbuf.c index 8795e1eda9..83887b300b 100644 --- a/py/ringbuf.c +++ b/py/ringbuf.c @@ -26,6 +26,18 @@ #include "ringbuf.h" int ringbuf_get16(ringbuf_t *r) { + int v = ringbuf_peek16(r); + if (v == -1) { + return v; + } + r->iget += 2; + if (r->iget >= r->size) { + r->iget -= r->size; + } + return v; +} + +int ringbuf_peek16(ringbuf_t *r) { if (r->iget == r->iput) { return -1; } @@ -36,12 +48,7 @@ int ringbuf_get16(ringbuf_t *r) { if (iget_a == r->iput) { return -1; } - uint16_t v = (r->buf[r->iget] << 8) | (r->buf[iget_a]); - r->iget = iget_a + 1; - if (r->iget == r->size) { - r->iget = 0; - } - return v; + return (r->buf[r->iget] << 8) | (r->buf[iget_a]); } int ringbuf_put16(ringbuf_t *r, uint16_t v) { diff --git a/py/ringbuf.h b/py/ringbuf.h index 6b0d209bd1..8d4ed16433 100644 --- a/py/ringbuf.h +++ b/py/ringbuf.h @@ -82,6 +82,7 @@ static inline size_t ringbuf_avail(ringbuf_t *r) { // Note: big-endian. No-op if not enough room available for both bytes. int ringbuf_get16(ringbuf_t *r); +int ringbuf_peek16(ringbuf_t *r); int ringbuf_put16(ringbuf_t *r, uint16_t v); #endif // MICROPY_INCLUDED_PY_RINGBUF_H From 334ba01c9078658d24e06b6ea68b7dc2ec02c506 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 11 Nov 2019 17:07:17 +1100 Subject: [PATCH 0979/1788] extmod/modbluetooth: Prioritise non-scan-result events. Remove existing scan result events from the ringbuf if the ringbuf is full and we're trying to enqueue any other event. This is needed so that events such as SCAN_COMPLETE are always put on the ringbuf. --- extmod/modbluetooth.c | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index 1e5eafc895..e919a672e8 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -792,13 +792,40 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(bluetooth_ble_invoke_irq_obj, bluetooth_ble_inv STATIC bool enqueue_irq(mp_obj_bluetooth_ble_t *o, size_t len, uint16_t event, bool *sched) { *sched = false; - if (o && ringbuf_free(&o->ringbuf) >= len + 2 && (o->irq_trigger & event) && o->irq_handler != mp_const_none) { - *sched = ringbuf_avail(&o->ringbuf) == 0; - ringbuf_put16(&o->ringbuf, event); - return true; - } else { + if (!o || !(o->irq_trigger & event) || o->irq_handler == mp_const_none) { return false; } + + if (ringbuf_free(&o->ringbuf) < len + 2) { + // Ringbuffer doesn't have room (and is therefore non-empty). + + // If this is another scan result, or the front of the ringbuffer isn't a scan result, then nothing to do. + if (event == MP_BLUETOOTH_IRQ_SCAN_RESULT || ringbuf_peek16(&o->ringbuf) != MP_BLUETOOTH_IRQ_SCAN_RESULT) { + return false; + } + + // Front of the queue is a scan result, remove it. + + // event, addr_type, addr, connectable, rssi + int n = 2 + 1 + 6 + 1 + 1; + for (int i = 0; i < n; ++i) { + ringbuf_get(&o->ringbuf); + } + // adv_data + n = ringbuf_get(&o->ringbuf); + for (int i = 0; i < n; ++i) { + ringbuf_get(&o->ringbuf); + } + + // No need to schedule the handler, as the ringbuffer was non-empty. + } else { + // Schedule the handler only if this is the first thing in the ringbuffer. + *sched = ringbuf_avail(&o->ringbuf) == 0; + } + + // Append this event, the caller will then append the arguments. + ringbuf_put16(&o->ringbuf, event); + return true; } STATIC void schedule_ringbuf(bool sched) { From 2679c9e11608bb37360008ebed7336f8a231d09d Mon Sep 17 00:00:00 2001 From: Laurens Valk Date: Fri, 15 Nov 2019 14:15:15 +0100 Subject: [PATCH 0980/1788] unix/modtermios: Fix output speed setter in tcsetattr. The input speed was being set twice and the output speed was not set. --- ports/unix/modtermios.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/unix/modtermios.c b/ports/unix/modtermios.c index d8a742a00e..85eabf399d 100644 --- a/ports/unix/modtermios.c +++ b/ports/unix/modtermios.c @@ -96,7 +96,7 @@ STATIC mp_obj_t mod_termios_tcsetattr(mp_obj_t fd_in, mp_obj_t when_in, mp_obj_t int res = cfsetispeed(&term, mp_obj_get_int(attrs->items[4])); RAISE_ERRNO(res, errno); - res = cfsetispeed(&term, mp_obj_get_int(attrs->items[5])); + res = cfsetospeed(&term, mp_obj_get_int(attrs->items[5])); RAISE_ERRNO(res, errno); res = tcsetattr(fd, when, &term); From 57c18fdd386064387a19271a3dbd3182ee5c44b0 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Wed, 25 Sep 2019 17:11:56 +0200 Subject: [PATCH 0981/1788] py/compile: Coalesce error message for break/continue outside loop. To reduce code size. --- py/compile.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/py/compile.c b/py/compile.c index 2c818a9340..0d36aef8b3 100644 --- a/py/compile.c +++ b/py/compile.c @@ -1028,16 +1028,13 @@ STATIC void compile_del_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { 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); + compile_syntax_error(comp, (mp_parse_node_t)pns, "'break'/'continue' outside loop"); } assert(comp->cur_except_level >= comp->break_continue_except_level); EMIT_ARG(unwind_jump, label, comp->cur_except_level - comp->break_continue_except_level); From ed2314f35afc2d921e25e032f6b6b5556f43d5b1 Mon Sep 17 00:00:00 2001 From: Josh Lloyd Date: Mon, 12 Aug 2019 13:21:47 +1200 Subject: [PATCH 0982/1788] esp32/machine_rtc: Make RTC.memory size and availability configurable. The compile-time configuration value MICROPY_HW_RTC_USER_MEM_MAX can now be used to define the amount of memory set aside for RTC.memory(). If this value is configured to zero then the RTC.memory functionality is not included in the build. --- ports/esp32/machine_rtc.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/ports/esp32/machine_rtc.c b/ports/esp32/machine_rtc.c index 2cb30e75e2..b0268cd57f 100644 --- a/ports/esp32/machine_rtc.c +++ b/ports/esp32/machine_rtc.c @@ -44,17 +44,29 @@ 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: + If the MICROPY_HW_RTC_USER_MEM_MAX is set too 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 + + You can also change this max length at compile time by defining MICROPY_HW_RTC_USER_MEM_MAX + either on your make line, or in your board config. + + If MICROPY_HW_RTC_USER_MEM_MAX is set to 0, the RTC.memory() functionality will be not + be compiled which frees some extra flash and RTC memory. */ -#define MEM_USER_MAXLEN 2048 +#ifndef MICROPY_HW_RTC_USER_MEM_MAX +#define MICROPY_HW_RTC_USER_MEM_MAX 2048 +#endif + +// Optionally compile user memory functionality if the size of memory is greater than 0 +#if MICROPY_HW_RTC_USER_MEM_MAX > 0 +#define MEM_MAGIC 0x75507921 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]; +RTC_DATA_ATTR uint8_t rtc_user_mem_data[MICROPY_HW_RTC_USER_MEM_MAX]; +#endif // singleton RTC object STATIC const machine_rtc_obj_t machine_rtc_obj = {{&machine_rtc_type}}; @@ -118,19 +130,23 @@ 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 MICROPY_HW_RTC_USER_MEM_MAX > 0 if (rtc_user_mem_magic != MEM_MAGIC) { rtc_user_mem_magic = MEM_MAGIC; rtc_user_mem_len = 0; } + #endif + return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_rtc_init_obj, machine_rtc_init); +#if MICROPY_HW_RTC_USER_MEM_MAX > 0 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]; + uint8_t rtcram[MICROPY_HW_RTC_USER_MEM_MAX]; memcpy( (char *) rtcram, (char *) rtc_user_mem_data, len); return mp_obj_new_bytes(rtcram, len); } else { @@ -138,7 +154,7 @@ STATIC mp_obj_t machine_rtc_memory(mp_uint_t n_args, const mp_obj_t *args) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); - if (bufinfo.len > MEM_USER_MAXLEN) { + if (bufinfo.len > MICROPY_HW_RTC_USER_MEM_MAX) { mp_raise_ValueError("buffer too long"); } memcpy( (char *) rtc_user_mem_data, (char *) bufinfo.buf, bufinfo.len); @@ -147,11 +163,14 @@ 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); +#endif STATIC const mp_rom_map_elem_t machine_rtc_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_rtc_init_obj) }, { MP_ROM_QSTR(MP_QSTR_datetime), MP_ROM_PTR(&machine_rtc_datetime_obj) }, + #if MICROPY_HW_RTC_USER_MEM_MAX > 0 { MP_ROM_QSTR(MP_QSTR_memory), MP_ROM_PTR(&machine_rtc_memory_obj) }, + #endif }; STATIC MP_DEFINE_CONST_DICT(machine_rtc_locals_dict, machine_rtc_locals_dict_table); From 1530fda9cf27d793917ea00ad28fbe8d4955b232 Mon Sep 17 00:00:00 2001 From: Josh Lloyd Date: Thu, 21 Nov 2019 15:09:01 +1300 Subject: [PATCH 0983/1788] esp32/machine_rtc: Reduce memory footprint of user mem functionality. --- ports/esp32/machine_rtc.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ports/esp32/machine_rtc.c b/ports/esp32/machine_rtc.c index b0268cd57f..eaa70e2448 100644 --- a/ports/esp32/machine_rtc.c +++ b/ports/esp32/machine_rtc.c @@ -64,7 +64,7 @@ typedef struct _machine_rtc_obj_t { #if MICROPY_HW_RTC_USER_MEM_MAX > 0 #define MEM_MAGIC 0x75507921 RTC_DATA_ATTR uint32_t rtc_user_mem_magic; -RTC_DATA_ATTR uint32_t rtc_user_mem_len; +RTC_DATA_ATTR uint16_t rtc_user_mem_len; RTC_DATA_ATTR uint8_t rtc_user_mem_data[MICROPY_HW_RTC_USER_MEM_MAX]; #endif @@ -145,10 +145,9 @@ 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[MICROPY_HW_RTC_USER_MEM_MAX]; - memcpy( (char *) rtcram, (char *) rtc_user_mem_data, len); - return mp_obj_new_bytes(rtcram, len); + memcpy((char*)rtcram, (char*)rtc_user_mem_data, rtc_user_mem_len); + return mp_obj_new_bytes(rtcram, rtc_user_mem_len); } else { // write RTC memory mp_buffer_info_t bufinfo; From d19c6d0519634851517bcf9e77f5d54d69084a5c Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 12 Nov 2019 15:29:24 +1100 Subject: [PATCH 0984/1788] extmod/modbluetooth: Create UUID from bytes and allow comparison ops. This allows construction of UUID objects from advertising data payloads and matching against known UUIDs. --- extmod/modbluetooth.c | 93 ++++++++++++++++++++++++++++--------------- 1 file changed, 60 insertions(+), 33 deletions(-) diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index e919a672e8..621b702f2e 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -79,37 +79,6 @@ STATIC mp_obj_t bluetooth_handle_errno(int err) { // UUID object // ---------------------------------------------------------------------------- -// Parse string UUIDs, which are expected to be 128-bit UUIDs. -STATIC void mp_bluetooth_parse_uuid_128bit_str(mp_obj_t obj, uint8_t *uuid) { - size_t str_len; - const char *str_data = mp_obj_str_get_data(obj, &str_len); - int uuid_i = 32; - for (int i = 0; i < str_len; i++) { - char c = str_data[i]; - if (c == '-') { - continue; - } - if (!unichar_isxdigit(c)) { - mp_raise_ValueError("invalid char in UUID"); - } - c = unichar_xdigit_value(c); - uuid_i--; - if (uuid_i < 0) { - mp_raise_ValueError("UUID too long"); - } - if (uuid_i % 2 == 0) { - // lower nibble - uuid[uuid_i/2] |= c; - } else { - // upper nibble - uuid[uuid_i/2] = c << 4; - } - } - if (uuid_i > 0) { - mp_raise_ValueError("UUID too short"); - } -} - STATIC mp_obj_t bluetooth_uuid_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { mp_arg_check_num(n_args, n_kw, 1, 1, false); @@ -125,8 +94,41 @@ STATIC mp_obj_t bluetooth_uuid_make_new(const mp_obj_type_t *type, size_t n_args self->data[0] = value & 0xff; self->data[1] = (value >> 8) & 0xff; } else { - self->type = MP_BLUETOOTH_UUID_TYPE_128; - mp_bluetooth_parse_uuid_128bit_str(all_args[0], self->data); + mp_buffer_info_t uuid_bufinfo = {0}; + mp_get_buffer_raise(all_args[0], &uuid_bufinfo, MP_BUFFER_READ); + if (uuid_bufinfo.len == 2 || uuid_bufinfo.len == 4 || uuid_bufinfo.len == 16) { + // Bytes data -- infer UUID type from length and copy data. + self->type = uuid_bufinfo.len; + memcpy(self->data, uuid_bufinfo.buf, self->type); + } else { + // Assume UUID string (e.g. '6E400001-B5A3-F393-E0A9-E50E24DCCA9E') + self->type = MP_BLUETOOTH_UUID_TYPE_128; + int uuid_i = 32; + for (int i = 0; i < uuid_bufinfo.len; i++) { + char c = ((char*)uuid_bufinfo.buf)[i]; + if (c == '-') { + continue; + } + if (!unichar_isxdigit(c)) { + mp_raise_ValueError("invalid char in UUID"); + } + c = unichar_xdigit_value(c); + uuid_i--; + if (uuid_i < 0) { + mp_raise_ValueError("UUID too long"); + } + if (uuid_i % 2 == 0) { + // lower nibble + self->data[uuid_i/2] |= c; + } else { + // upper nibble + self->data[uuid_i/2] = c << 4; + } + } + if (uuid_i > 0) { + mp_raise_ValueError("UUID too short"); + } + } } return self; @@ -143,6 +145,30 @@ STATIC mp_obj_t bluetooth_uuid_unary_op(mp_unary_op_t op, mp_obj_t self_in) { } } +STATIC mp_obj_t bluetooth_uuid_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + if (!mp_obj_is_type(rhs_in, &bluetooth_uuid_type)) { + return MP_OBJ_NULL; + } + + mp_obj_bluetooth_uuid_t *lhs = MP_OBJ_TO_PTR(lhs_in); + mp_obj_bluetooth_uuid_t *rhs = MP_OBJ_TO_PTR(rhs_in); + switch (op) { + case MP_BINARY_OP_EQUAL: + case MP_BINARY_OP_LESS: + case MP_BINARY_OP_LESS_EQUAL: + case MP_BINARY_OP_MORE: + case MP_BINARY_OP_MORE_EQUAL: + if (lhs->type == rhs->type) { + return mp_obj_new_bool(mp_seq_cmp_bytes(op, lhs->data, lhs->type, rhs->data, rhs->type)); + } else { + return mp_binary_op(op, MP_OBJ_NEW_SMALL_INT(lhs->type), MP_OBJ_NEW_SMALL_INT(rhs->type)); + } + + default: + return MP_OBJ_NULL; // op not supported + } +} + STATIC void bluetooth_uuid_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { mp_obj_bluetooth_uuid_t *self = MP_OBJ_TO_PTR(self_in); mp_printf(print, "UUID%u(%s", self->type * 8, self->type <= 4 ? "0x" : "'"); @@ -196,6 +222,7 @@ STATIC const mp_obj_type_t bluetooth_uuid_type = { .name = MP_QSTR_UUID, .make_new = bluetooth_uuid_make_new, .unary_op = bluetooth_uuid_unary_op, + .binary_op = bluetooth_uuid_binary_op, .locals_dict = NULL, .print = bluetooth_uuid_print, .buffer_p = { .get_buffer = bluetooth_uuid_get_buffer }, From 2ae755d9e1971437181097dbbf43e116ba8383d0 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Wed, 13 Nov 2019 11:53:41 +1100 Subject: [PATCH 0985/1788] extmod/modbluetooth_nimble: Make gap_scan_stop no-op if no scan ongoing. No need for this to throw an exception if the intent (don't be scanning) is clear, and avoids a race with the scan duration timeout. --- extmod/modbluetooth_nimble.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/extmod/modbluetooth_nimble.c b/extmod/modbluetooth_nimble.c index 33dac5a425..d0c3a3d81d 100644 --- a/extmod/modbluetooth_nimble.c +++ b/extmod/modbluetooth_nimble.c @@ -659,6 +659,9 @@ int mp_bluetooth_gap_scan_start(int32_t duration_ms, int32_t interval_us, int32_ } int mp_bluetooth_gap_scan_stop(void) { + if (!ble_gap_disc_active()) { + return 0; + } int err = ble_gap_disc_cancel(); if (err == 0) { mp_bluetooth_gap_on_scan_complete(); From 438c0dc2a4ab27883bab80a40372a44d7f5fe963 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Wed, 13 Nov 2019 16:59:23 +1100 Subject: [PATCH 0986/1788] extmod/modbluetooh_nimble: Fix UUID conversion for 16 and 32 bit values. --- extmod/modbluetooth_nimble.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/extmod/modbluetooth_nimble.c b/extmod/modbluetooth_nimble.c index d0c3a3d81d..f86ab70bf1 100644 --- a/extmod/modbluetooth_nimble.c +++ b/extmod/modbluetooth_nimble.c @@ -117,14 +117,14 @@ STATIC mp_obj_bluetooth_uuid_t create_mp_uuid(const ble_uuid_any_t *uuid) { case BLE_UUID_TYPE_16: result.type = MP_BLUETOOTH_UUID_TYPE_16; result.data[0] = uuid->u16.value & 0xff; - result.data[1] = (uuid->u16.value << 8) & 0xff; + result.data[1] = (uuid->u16.value >> 8) & 0xff; break; case BLE_UUID_TYPE_32: result.type = MP_BLUETOOTH_UUID_TYPE_32; result.data[0] = uuid->u32.value & 0xff; - result.data[1] = (uuid->u32.value << 8) & 0xff; - result.data[2] = (uuid->u32.value << 16) & 0xff; - result.data[3] = (uuid->u32.value << 24) & 0xff; + result.data[1] = (uuid->u32.value >> 8) & 0xff; + result.data[2] = (uuid->u32.value >> 16) & 0xff; + result.data[3] = (uuid->u32.value >> 24) & 0xff; break; case BLE_UUID_TYPE_128: result.type = MP_BLUETOOTH_UUID_TYPE_128; From fbb7646e3bd6fd17b2c39ac40d537cc0b07af188 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Wed, 13 Nov 2019 17:02:50 +1100 Subject: [PATCH 0987/1788] stm32/nimble_hci_uart.c: Prevent scheduler running during CYW-BT wakeup. Using mp_hal_delay_ms allows the scheduler to run, which might result in another transmit operation happening, which would bypass the sleep (and fail). Use mp_hal_delay_us instead. --- ports/stm32/nimble_hci_uart.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ports/stm32/nimble_hci_uart.c b/ports/stm32/nimble_hci_uart.c index defda1581e..69e89e6abf 100644 --- a/ports/stm32/nimble_hci_uart.c +++ b/ports/stm32/nimble_hci_uart.c @@ -162,7 +162,9 @@ void nimble_hci_uart_tx_strn(const char *str, uint len) { if (mp_hal_pin_read(pyb_pin_BT_DEV_WAKE) == 1) { //printf("BT WAKE for TX\n"); mp_hal_pin_low(pyb_pin_BT_DEV_WAKE); // wake up - mp_hal_delay_ms(5); // can't go lower than this + // Use delay_us rather than delay_ms to prevent running the scheduler (which + // might result in more BLE operations). + mp_hal_delay_us(5000); // can't go lower than this } #endif From e873d352ada8c392985e9f248271c5cf0fcd32ed Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Wed, 20 Nov 2019 10:45:14 +1100 Subject: [PATCH 0988/1788] extmod/modbluetooth: Simplify management of pre-allocated event data. The address, adv payload and uuid fields of the event are pre-allocated by modbluetooth, and reused in the IRQ handler. Simplify this and move all storage into the `mp_obj_bluetooth_ble_t` instance. This now allows users to hold on to a reference to these instances without crashes, although they may be overwritten by future events. If they want to hold onto the values longer term they need to copy them. --- docs/library/ubluetooth.rst | 6 +++++ extmod/modbluetooth.c | 46 +++++++++++++++++++++---------------- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/docs/library/ubluetooth.rst b/docs/library/ubluetooth.rst index 6e95a9e92e..2d3af1bb6b 100644 --- a/docs/library/ubluetooth.rst +++ b/docs/library/ubluetooth.rst @@ -52,6 +52,12 @@ Event Handling The optional *trigger* parameter allows you to set a mask of events that your program is interested in. The default is all events. + Note: the ``addr``, ``adv_data`` and ``uuid`` entries in the tuples are + references to data managed by the :mod:`ubluetooth` module (i.e. the same + instance will be re-used across multiple calls to the event handler). If + your program wants to use this data outside of the handler, then it must + copy them first, e.g. by using ``bytes(addr)`` or ``bluetooth.UUID(uuid)``. + An event handler showing all possible events:: def bt_irq(event, data): diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index 621b702f2e..bac7c07cbe 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -59,11 +59,13 @@ STATIC const mp_obj_type_t bluetooth_uuid_type; typedef struct { mp_obj_base_t base; mp_obj_t irq_handler; - mp_obj_t irq_data_tuple; - uint8_t irq_addr_bytes[6]; - uint8_t irq_data_bytes[MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN]; - mp_obj_t irq_data_uuid; uint16_t irq_trigger; + mp_obj_t irq_data_tuple; + uint8_t irq_data_addr_bytes[6]; + uint8_t irq_data_data_bytes[MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN]; + mp_obj_str_t irq_data_addr; + mp_obj_str_t irq_data_data; + mp_obj_bluetooth_uuid_t irq_data_uuid; ringbuf_t ringbuf; } mp_obj_bluetooth_ble_t; @@ -234,16 +236,25 @@ STATIC const mp_obj_type_t bluetooth_uuid_type = { STATIC mp_obj_t bluetooth_ble_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { if (MP_STATE_VM(bluetooth) == MP_OBJ_NULL) { - mp_obj_bluetooth_ble_t *o = m_new_obj(mp_obj_bluetooth_ble_t); + mp_obj_bluetooth_ble_t *o = m_new0(mp_obj_bluetooth_ble_t, 1); o->base.type = &bluetooth_ble_type; + o->irq_handler = mp_const_none; + o->irq_trigger = 0; + // Pre-allocate the event data tuple to prevent needing to allocate in the IRQ handler. o->irq_data_tuple = mp_obj_new_tuple(MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_TUPLE_LEN, NULL); - mp_obj_bluetooth_uuid_t *uuid = m_new_obj(mp_obj_bluetooth_uuid_t); - uuid->base.type = &bluetooth_uuid_type; - o->irq_data_uuid = MP_OBJ_FROM_PTR(uuid); - o->irq_trigger = 0; + + // Pre-allocated buffers for address, payload and uuid. + o->irq_data_addr.base.type = &mp_type_bytes; + o->irq_data_addr.data = o->irq_data_addr_bytes; + o->irq_data_data.base.type = &mp_type_bytes; + o->irq_data_data.data = o->irq_data_data_bytes; + o->irq_data_uuid.base.type = &bluetooth_uuid_type; + + // Allocate the ringbuf. TODO: Consider making the size user-specified. ringbuf_alloc(&o->ringbuf, MICROPY_PY_BLUETOOTH_RINGBUF_SIZE); + MP_STATE_VM(bluetooth) = MP_OBJ_FROM_PTR(o); } return MP_STATE_VM(bluetooth); @@ -764,36 +775,31 @@ STATIC mp_obj_t bluetooth_ble_invoke_irq(mp_obj_t none_in) { mp_obj_t handler = handler = o->irq_handler; mp_obj_tuple_t *data_tuple = MP_OBJ_TO_PTR(o->irq_data_tuple); - // Some events need to pass bytes objects to their handler, using the - // pre-allocated bytes array. - mp_obj_str_t irq_data_bytes_addr = {{&mp_type_bytes}, 0, 6, o->irq_addr_bytes}; - mp_obj_str_t irq_data_bytes_data = {{&mp_type_bytes}, 0, 0, o->irq_data_bytes}; - if (event == MP_BLUETOOTH_IRQ_CENTRAL_CONNECT || event == MP_BLUETOOTH_IRQ_PERIPHERAL_CONNECT || event == MP_BLUETOOTH_IRQ_CENTRAL_DISCONNECT || event == MP_BLUETOOTH_IRQ_PERIPHERAL_DISCONNECT) { // conn_handle, addr_type, addr - ringbuf_extract(&o->ringbuf, data_tuple, 1, 1, &irq_data_bytes_addr, 0, 0, NULL, NULL); + ringbuf_extract(&o->ringbuf, data_tuple, 1, 1, &o->irq_data_addr, 0, 0, NULL, NULL); } else if (event == MP_BLUETOOTH_IRQ_GATTS_WRITE) { // conn_handle, value_handle ringbuf_extract(&o->ringbuf, data_tuple, 2, 0, NULL, 0, 0, NULL, NULL); #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE } else if (event == MP_BLUETOOTH_IRQ_SCAN_RESULT) { // addr_type, addr, connectable, rssi, adv_data - ringbuf_extract(&o->ringbuf, data_tuple, 0, 1, &irq_data_bytes_addr, 1, 1, NULL, &irq_data_bytes_data); + ringbuf_extract(&o->ringbuf, data_tuple, 0, 1, &o->irq_data_addr, 1, 1, NULL, &o->irq_data_data); } else if (event == MP_BLUETOOTH_IRQ_SCAN_COMPLETE) { // No params required. data_tuple->len = 0; } else if (event == MP_BLUETOOTH_IRQ_GATTC_SERVICE_RESULT) { // conn_handle, start_handle, end_handle, uuid - ringbuf_extract(&o->ringbuf, data_tuple, 3, 0, NULL, 0, 0, MP_OBJ_TO_PTR(o->irq_data_uuid), NULL); + ringbuf_extract(&o->ringbuf, data_tuple, 3, 0, NULL, 0, 0, &o->irq_data_uuid, NULL); } else if (event == MP_BLUETOOTH_IRQ_GATTC_CHARACTERISTIC_RESULT) { // conn_handle, def_handle, value_handle, properties, uuid - ringbuf_extract(&o->ringbuf, data_tuple, 3, 1, NULL, 0, 0, MP_OBJ_TO_PTR(o->irq_data_uuid), NULL); + ringbuf_extract(&o->ringbuf, data_tuple, 3, 1, NULL, 0, 0, &o->irq_data_uuid, NULL); } else if (event == MP_BLUETOOTH_IRQ_GATTC_DESCRIPTOR_RESULT) { // conn_handle, handle, uuid - ringbuf_extract(&o->ringbuf, data_tuple, 2, 0, NULL, 0, 0, MP_OBJ_TO_PTR(o->irq_data_uuid), NULL); + ringbuf_extract(&o->ringbuf, data_tuple, 2, 0, NULL, 0, 0, &o->irq_data_uuid, NULL); } else if (event == MP_BLUETOOTH_IRQ_GATTC_READ_RESULT || event == MP_BLUETOOTH_IRQ_GATTC_NOTIFY || event == MP_BLUETOOTH_IRQ_GATTC_INDICATE) { // conn_handle, value_handle, data - ringbuf_extract(&o->ringbuf, data_tuple, 2, 0, NULL, 0, 0, NULL, &irq_data_bytes_data); + ringbuf_extract(&o->ringbuf, data_tuple, 2, 0, NULL, 0, 0, NULL, &o->irq_data_data); } else if (event == MP_BLUETOOTH_IRQ_GATTC_WRITE_STATUS) { // conn_handle, value_handle, status ringbuf_extract(&o->ringbuf, data_tuple, 3, 0, NULL, 0, 0, NULL, NULL); From 3436223630751c770c04b2dca35ef0002143f033 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Wed, 13 Nov 2019 17:00:35 +1100 Subject: [PATCH 0989/1788] examples/bluetooth: Add helpers for decoding advertising payloads. Extracts name and service UUID fields. --- examples/bluetooth/ble_advertising.py | 37 +++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/examples/bluetooth/ble_advertising.py b/examples/bluetooth/ble_advertising.py index b57d5e031c..3a06beb740 100644 --- a/examples/bluetooth/ble_advertising.py +++ b/examples/bluetooth/ble_advertising.py @@ -2,6 +2,7 @@ from micropython import const import struct +import bluetooth # Advertising payloads are repeated packets of the following form: # 1 byte data length (N + 1) @@ -46,3 +47,39 @@ def advertising_payload(limited_disc=False, br_edr=False, name=None, services=No _append(_ADV_TYPE_APPEARANCE, struct.pack(' Date: Wed, 13 Nov 2019 17:33:14 +1100 Subject: [PATCH 0990/1788] examples/bluetooth: Add example for reading temperature sensor. --- examples/bluetooth/ble_temperature_central.py | 222 ++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 examples/bluetooth/ble_temperature_central.py diff --git a/examples/bluetooth/ble_temperature_central.py b/examples/bluetooth/ble_temperature_central.py new file mode 100644 index 0000000000..3d609f13ca --- /dev/null +++ b/examples/bluetooth/ble_temperature_central.py @@ -0,0 +1,222 @@ +# This example finds and connects to a BLE temperature sensor (e.g. the one in ble_temperature.py). + +import bluetooth +import random +import struct +import time +import micropython + +from ble_advertising import decode_services, decode_name + +from micropython import const +_IRQ_CENTRAL_CONNECT = const(1 << 0) +_IRQ_CENTRAL_DISCONNECT = const(1 << 1) +_IRQ_GATTS_WRITE = const(1 << 2) +_IRQ_GATTS_READ_REQUEST = const(1 << 3) +_IRQ_SCAN_RESULT = const(1 << 4) +_IRQ_SCAN_COMPLETE = const(1 << 5) +_IRQ_PERIPHERAL_CONNECT = const(1 << 6) +_IRQ_PERIPHERAL_DISCONNECT = const(1 << 7) +_IRQ_GATTC_SERVICE_RESULT = const(1 << 8) +_IRQ_GATTC_CHARACTERISTIC_RESULT = const(1 << 9) +_IRQ_GATTC_DESCRIPTOR_RESULT = const(1 << 10) +_IRQ_GATTC_READ_RESULT = const(1 << 11) +_IRQ_GATTC_WRITE_STATUS = const(1 << 12) +_IRQ_GATTC_NOTIFY = const(1 << 13) +_IRQ_GATTC_INDICATE = const(1 << 14) +_IRQ_ALL = const(0xffff) + +# org.bluetooth.service.environmental_sensing +_ENV_SENSE_UUID = bluetooth.UUID(0x181A) +# org.bluetooth.characteristic.temperature +_TEMP_UUID = bluetooth.UUID(0x2A6E) +_TEMP_CHAR = (_TEMP_UUID, bluetooth.FLAG_READ|bluetooth.FLAG_NOTIFY,) +_ENV_SENSE_SERVICE = (_ENV_SENSE_UUID, (_TEMP_CHAR,),) + +# org.bluetooth.characteristic.gap.appearance.xml +_ADV_APPEARANCE_GENERIC_THERMOMETER = const(768) + +class BLETemperatureCentral: + def __init__(self, ble): + self._ble = ble + self._ble.active(True) + self._ble.irq(handler=self._irq) + + self._reset() + + def _reset(self): + # Cached name and address from a successful scan. + self._name = None + self._addr_type = None + self._addr = None + + # Cached value (if we have one) + self._value = None + + # Callbacks for completion of various operations. + # These reset back to None after being invoked. + self._scan_callback = None + self._conn_callback = None + self._read_callback = None + + # Persistent callback for when new data is notified from the device. + self._notify_callback = None + + # Connected device. + self._conn_handle = None + self._value_handle = None + + def _irq(self, event, data): + if event == _IRQ_SCAN_RESULT: + addr_type, addr, connectable, rssi, adv_data = data + if connectable and _ENV_SENSE_UUID in decode_services(adv_data): + # Found a potential device, remember it and stop scanning. + self._addr_type = addr_type + self._addr = bytes(addr) # Note: The addr buffer is owned by modbluetooth, need to copy it. + self._name = decode_name(adv_data) or '?' + self._ble.gap_scan(None) + + elif event == _IRQ_SCAN_COMPLETE: + if self._scan_callback: + if self._addr: + # Found a device during the scan (and the scan was explicitly stopped). + self._scan_callback(self._addr_type, self._addr, self._name) + self._scan_callback = None + else: + # Scan timed out. + self._scan_callback(None, None, None) + + elif event == _IRQ_PERIPHERAL_CONNECT: + # Connect successful. + conn_handle, addr_type, addr, = data + if addr_type == self._addr_type and addr == self._addr: + self._conn_handle = conn_handle + self._ble.gattc_discover_services(self._conn_handle) + + elif event == _IRQ_PERIPHERAL_DISCONNECT: + # Disconnect (either initiated by us or the remote end). + conn_handle, _, _, = data + if conn_handle == self._conn_handle: + # If it was initiated by us, it'll already be reset. + self._reset() + + elif event == _IRQ_GATTC_SERVICE_RESULT: + # Connected device returned a service. + conn_handle, start_handle, end_handle, uuid = data + if conn_handle == self._conn_handle and uuid == _ENV_SENSE_UUID: + self._ble.gattc_discover_characteristics(self._conn_handle, start_handle, end_handle) + + elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT: + # Connected device returned a characteristic. + conn_handle, def_handle, value_handle, properties, uuid = data + if conn_handle == self._conn_handle and uuid == _TEMP_UUID: + self._value_handle = value_handle + # We've finished connecting and discovering device, fire the connect callback. + if self._conn_callback: + self._conn_callback() + + elif event == _IRQ_GATTC_READ_RESULT: + # A read completed successfully. + conn_handle, value_handle, char_data = data + if conn_handle == self._conn_handle and value_handle == self._value_handle: + self._update_value(char_data) + if self._read_callback: + self._read_callback(self._value) + self._read_callback = None + + elif event == _IRQ_GATTC_NOTIFY: + # The ble_temperature.py demo periodically notifies its value. + conn_handle, value_handle, notify_data = data + if conn_handle == self._conn_handle and value_handle == self._value_handle: + self._update_value(notify_data) + if self._notify_callback: + self._notify_callback(self._value) + + + # Returns true if we've successfully connected and discovered characteristics. + def is_connected(self): + return self._conn_handle is not None and self._value_handle is not None + + # Find a device advertising the environmental sensor service. + def scan(self, callback=None): + self._addr_type = None + self._addr = None + self._scan_callback = callback + self._ble.gap_scan(2000, 30000, 30000) + + # Connect to the specified device (otherwise use cached address from a scan). + def connect(self, addr_type=None, addr=None, callback=None): + self._addr_type = addr_type or self._addr_type + self._addr = addr or self._addr + self._conn_callback = callback + if self._addr_type is None or self._addr is None: + return False + self._ble.gap_connect(self._addr_type, self._addr) + return True + + # Disconnect from current device. + def disconnect(self): + if not self._conn_handle: + return + self._ble.gap_disconnect(self._conn_handle) + self._reset() + + # Issues an (asynchronous) read, will invoke callback with data. + def read(self, callback): + if not self.is_connected(): + return + self._read_callback = callback + self._ble.gattc_read(self._conn_handle, self._value_handle) + + # Sets a callback to be invoked when the device notifies us. + def on_notify(self, callback): + self._notify_callback = callback + + def _update_value(self, data): + # Data is sint16 in degrees Celsius with a resolution of 0.01 degrees Celsius. + self._value = struct.unpack(' Date: Wed, 6 Nov 2019 13:48:35 +1100 Subject: [PATCH 0991/1788] stm32: Generalise flash mounting code so it supports arbitrary FS. This commit refactors and generalises the boot-mount routine on stm32 so that it can mount filesystems of arbitrary type. That is, it no longer assumes that the filesystem is FAT. It does this by using mp_vfs_mount() which does auto-detection of the filesystem type. --- ports/stm32/factoryreset.c | 32 ++++++++++++++ ports/stm32/factoryreset.h | 1 + ports/stm32/main.c | 91 ++++++++++++++++---------------------- ports/stm32/storage.c | 2 +- ports/stm32/storage.h | 1 + 5 files changed, 72 insertions(+), 55 deletions(-) diff --git a/ports/stm32/factoryreset.c b/ports/stm32/factoryreset.c index 24e0ff88cf..513b521631 100644 --- a/ports/stm32/factoryreset.c +++ b/ports/stm32/factoryreset.c @@ -25,6 +25,11 @@ */ #include "py/runtime.h" +#include "py/mperrno.h" +#include "extmod/vfs_fat.h" +#include "systick.h" +#include "led.h" +#include "storage.h" #include "factoryreset.h" #if MICROPY_HW_ENABLE_STORAGE @@ -96,4 +101,31 @@ MP_WEAK void factory_reset_make_files(FATFS *fatfs) { } } +MP_WEAK int factory_reset_create_filesystem(void) { + // LED on to indicate creation of local filesystem + led_state(PYB_LED_GREEN, 1); + uint32_t start_tick = HAL_GetTick(); + + fs_user_mount_t vfs; + pyb_flash_init_vfs(&vfs); + uint8_t working_buf[FF_MAX_SS]; + FRESULT res = f_mkfs(&vfs.fatfs, FM_FAT, 0, working_buf, sizeof(working_buf)); + if (res != FR_OK) { + mp_printf(&mp_plat_print, "MPY: can't create flash filesystem\n"); + return -MP_ENODEV; + } + + // Set label + f_setlabel(&vfs.fatfs, MICROPY_HW_FLASH_FS_LABEL); + + // Populate the filesystem with factory files + factory_reset_make_files(&vfs.fatfs); + + // Keep LED on for at least 200ms + systick_wait_at_least(start_tick, 200); + led_state(PYB_LED_GREEN, 0); + + return 0; // success +} + #endif // MICROPY_HW_ENABLE_STORAGE diff --git a/ports/stm32/factoryreset.h b/ports/stm32/factoryreset.h index 85226f880b..1d1f4b8571 100644 --- a/ports/stm32/factoryreset.h +++ b/ports/stm32/factoryreset.h @@ -29,5 +29,6 @@ #include "lib/oofatfs/ff.h" void factory_reset_make_files(FATFS *fatfs); +int factory_reset_create_filesystem(void); #endif // MICROPY_INCLUDED_STM32_FACTORYRESET_H diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 3c6420d50d..707b1fc68e 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -30,6 +30,7 @@ #include "py/runtime.h" #include "py/stackctrl.h" #include "py/gc.h" +#include "py/mperrno.h" #include "py/mphal.h" #include "lib/mp-readline/readline.h" #include "lib/utils/pyexec.h" @@ -81,10 +82,6 @@ STATIC pyb_thread_t pyb_thread_main; #endif -#if MICROPY_HW_ENABLE_STORAGE -STATIC fs_user_mount_t fs_user_mount_flash; -#endif - #if defined(MICROPY_HW_UART_REPL) #ifndef MICROPY_HW_UART_REPL_RXBUF #define MICROPY_HW_UART_REPL_RXBUF (260) @@ -159,65 +156,51 @@ 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 int vfs_mount_and_chdir(mp_obj_t bdev, mp_obj_t mount_point) { + nlr_buf_t nlr; + mp_int_t ret = -MP_EIO; + if (nlr_push(&nlr) == 0) { + mp_obj_t args[] = { bdev, mount_point }; + mp_vfs_mount(2, args, (mp_map_t*)&mp_const_empty_map); + mp_vfs_chdir(mount_point); + ret = 0; // success + nlr_pop(); + } else { + mp_obj_base_t *exc = nlr.ret_val; + if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(exc->type), MP_OBJ_FROM_PTR(&mp_type_OSError))) { + mp_obj_t v = mp_obj_exception_get_value(MP_OBJ_FROM_PTR(exc)); + mp_obj_get_int_maybe(v, &ret); // get errno value + ret = -ret; + } + } + return ret; +} + // avoid inlining to avoid stack usage within main() MP_NOINLINE STATIC bool init_flash_fs(uint reset_mode) { - // init the vfs object - fs_user_mount_t *vfs_fat = &fs_user_mount_flash; - vfs_fat->blockdev.flags = 0; - pyb_flash_init_vfs(vfs_fat); + if (reset_mode == 3) { + // Asked by user to reset filesystem + factory_reset_create_filesystem(); + } - // try to mount the flash - FRESULT res = f_mount(&vfs_fat->fatfs); + // Try to mount the flash on "/flash" and chdir to it for the boot-up directory. + mp_obj_t bdev = MP_OBJ_FROM_PTR(&pyb_flash_obj); + mp_obj_t mount_point = MP_OBJ_NEW_QSTR(MP_QSTR__slash_flash); + int ret = vfs_mount_and_chdir(bdev, mount_point); - if (reset_mode == 3 || res == FR_NO_FILESYSTEM) { - // no filesystem, or asked to reset it, so create a fresh one - - // LED on to indicate creation of LFS - led_state(PYB_LED_GREEN, 1); - uint32_t start_tick = HAL_GetTick(); - - uint8_t working_buf[FF_MAX_SS]; - res = f_mkfs(&vfs_fat->fatfs, FM_FAT, 0, working_buf, sizeof(working_buf)); - if (res == FR_OK) { - // success creating fresh LFS - } else { - printf("MPY: can't create flash filesystem\n"); - return false; + if (ret == -MP_ENODEV && reset_mode != 3) { + // No filesystem (and didn't already create one), try to create a fresh one + ret = factory_reset_create_filesystem(); + if (ret == 0) { + ret = vfs_mount_and_chdir(bdev, mount_point); } + } - // set label - f_setlabel(&vfs_fat->fatfs, MICROPY_HW_FLASH_FS_LABEL); - - // populate the filesystem with factory files - factory_reset_make_files(&vfs_fat->fatfs); - - // keep LED on for at least 200ms - systick_wait_at_least(start_tick, 200); - led_state(PYB_LED_GREEN, 0); - } else if (res == FR_OK) { - // mount sucessful - } else { - fail: + if (ret != 0) { printf("MPY: can't mount flash\n"); return false; } - // mount the flash device (there should be no other devices mounted at this point) - // we allocate this structure on the heap because vfs->next is a root pointer - mp_vfs_mount_t *vfs = m_new_obj_maybe(mp_vfs_mount_t); - if (vfs == NULL) { - goto fail; - } - vfs->str = "/flash"; - vfs->len = 6; - vfs->obj = MP_OBJ_FROM_PTR(vfs_fat); - vfs->next = NULL; - MP_STATE_VM(vfs_mount_table) = vfs; - - // The current directory is used as the boot up directory. - // It is set to the internal flash filesystem by default. - MP_STATE_PORT(vfs_cur) = vfs; - return true; } #endif @@ -616,7 +599,7 @@ soft_reset: // 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 - if (!mounted_flash || f_stat(&fs_user_mount_flash.fatfs, "/SKIPSD", NULL) != FR_OK) { + if (!mounted_flash || mp_vfs_import_stat("SKIPSD") == MP_IMPORT_STAT_FILE) { mounted_sdcard = init_sdcard_fs(); } } diff --git a/ports/stm32/storage.c b/ports/stm32/storage.c index d9d5464855..905d51f325 100644 --- a/ports/stm32/storage.c +++ b/ports/stm32/storage.c @@ -234,7 +234,7 @@ mp_uint_t storage_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t // Expose the flash as an object with the block protocol. // there is a singleton Flash object -STATIC const mp_obj_base_t pyb_flash_obj = {&pyb_flash_type}; +const mp_obj_base_t pyb_flash_obj = {&pyb_flash_type}; STATIC mp_obj_t pyb_flash_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { // check arguments diff --git a/ports/stm32/storage.h b/ports/stm32/storage.h index 826b465a66..0ba3497a17 100644 --- a/ports/stm32/storage.h +++ b/ports/stm32/storage.h @@ -63,6 +63,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); extern const struct _mp_obj_type_t pyb_flash_type; +extern const struct _mp_obj_base_t pyb_flash_obj; struct _fs_user_mount_t; void pyb_flash_init_vfs(struct _fs_user_mount_t *vfs); From c169094f615c9337610703399be1cfb02a6ff120 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 13 Nov 2019 17:31:35 +1100 Subject: [PATCH 0992/1788] stm32/storage: Make pyb.Flash configurable, and support ext block proto. The pyb.Flash() class can now be used to construct objects which reference sections of the flash storage, starting at a certain offset and going for a certain length. Such objects also support the extended block protocol. The signature for the constructor is: pyb.Flash(start=-1, len=-1). --- ports/stm32/flashbdev.c | 40 ++++++++ ports/stm32/spibdev.c | 23 +++++ ports/stm32/storage.c | 196 ++++++++++++++++++++++++++++++++++++---- ports/stm32/storage.h | 11 ++- 4 files changed, 249 insertions(+), 21 deletions(-) diff --git a/ports/stm32/flashbdev.c b/ports/stm32/flashbdev.c index 15bf0d6b0a..beb28c4925 100644 --- a/ports/stm32/flashbdev.c +++ b/ports/stm32/flashbdev.c @@ -292,4 +292,44 @@ bool flash_bdev_writeblock(const uint8_t *src, uint32_t block) { return true; } +int flash_bdev_readblocks_ext(uint8_t *dest, uint32_t block, uint32_t offset, uint32_t len) { + // Get data from flash memory, possibly via cache + while (len) { + uint32_t l = MIN(len, FLASH_BLOCK_SIZE - offset); + uint32_t flash_addr = convert_block_to_flash_addr(block); + if (flash_addr == -1) { + // bad block number + return -1; + } + uint8_t *src = flash_cache_get_addr_for_read(flash_addr + offset); + memcpy(dest, src, l); + dest += l; + block += 1; + offset = 0; + len -= l; + } + return 0; +} + +int flash_bdev_writeblocks_ext(const uint8_t *src, uint32_t block, uint32_t offset, uint32_t len) { + // Copy to cache + while (len) { + uint32_t l = MIN(len, FLASH_BLOCK_SIZE - offset); + uint32_t flash_addr = convert_block_to_flash_addr(block); + if (flash_addr == -1) { + // bad block number + return -1; + } + uint32_t basepri = raise_irq_pri(IRQ_PRI_FLASH); // prevent cache flushing and USB access + uint8_t *dest = flash_cache_get_addr_for_write(flash_addr + offset); + memcpy(dest, src, l); + restore_irq_pri(basepri); + src += l; + block += 1; + offset = 0; + len -= l; + } + return 0; +} + #endif // MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE diff --git a/ports/stm32/spibdev.c b/ports/stm32/spibdev.c index 9b5a10b400..97ce885d45 100644 --- a/ports/stm32/spibdev.c +++ b/ports/stm32/spibdev.c @@ -55,6 +55,13 @@ int32_t spi_bdev_ioctl(spi_bdev_t *bdev, uint32_t op, uint32_t arg) { restore_irq_pri(basepri); } return 0; + + case BDEV_IOCTL_BLOCK_ERASE: { + uint32_t basepri = raise_irq_pri(IRQ_PRI_FLASH); // prevent cache flushing and USB access + mp_spiflash_erase_block(&bdev->spiflash, arg * MP_SPIFLASH_ERASE_BLOCK_SIZE); + restore_irq_pri(basepri); + return 0; + } } return -MP_EINVAL; } @@ -79,4 +86,20 @@ int spi_bdev_writeblocks(spi_bdev_t *bdev, const uint8_t *src, uint32_t block_nu return ret; } +int spi_bdev_readblocks_raw(spi_bdev_t *bdev, uint8_t *dest, uint32_t block_num, uint32_t block_offset, uint32_t num_bytes) { + uint32_t basepri = raise_irq_pri(IRQ_PRI_FLASH); // prevent cache flushing and USB access + mp_spiflash_read(&bdev->spiflash, block_num * MP_SPIFLASH_ERASE_BLOCK_SIZE + block_offset, num_bytes, dest); + restore_irq_pri(basepri); + + return 0; +} + +int spi_bdev_writeblocks_raw(spi_bdev_t *bdev, const uint8_t *src, uint32_t block_num, uint32_t block_offset, uint32_t num_bytes) { + uint32_t basepri = raise_irq_pri(IRQ_PRI_FLASH); // prevent cache flushing and USB access + int ret = mp_spiflash_write(&bdev->spiflash, block_num * MP_SPIFLASH_ERASE_BLOCK_SIZE + block_offset, num_bytes, src); + restore_irq_pri(basepri); + + return ret; +} + #endif diff --git a/ports/stm32/storage.c b/ports/stm32/storage.c index 905d51f325..0d3285ba05 100644 --- a/ports/stm32/storage.c +++ b/ports/stm32/storage.c @@ -28,6 +28,7 @@ #include #include "py/runtime.h" +#include "py/mperrno.h" #include "extmod/vfs_fat.h" #include "systick.h" @@ -233,41 +234,197 @@ mp_uint_t storage_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t // // Expose the flash as an object with the block protocol. -// there is a singleton Flash object -const mp_obj_base_t pyb_flash_obj = {&pyb_flash_type}; +#ifdef MICROPY_HW_BDEV_SPIFLASH_EXTENDED +// Board defined an external SPI flash for use with extended block protocol +#define SPIFLASH (MICROPY_HW_BDEV_SPIFLASH_EXTENDED) +#define PYB_FLASH_NATIVE_BLOCK_SIZE (MP_SPIFLASH_ERASE_BLOCK_SIZE) +#define MICROPY_HW_BDEV_READBLOCKS_EXT(dest, bl, off, len) (spi_bdev_readblocks_raw(SPIFLASH, (dest), (bl), (off), (len))) +#define MICROPY_HW_BDEV_WRITEBLOCKS_EXT(dest, bl, off, len) (spi_bdev_writeblocks_raw(SPIFLASH, (dest), (bl), (off), (len))) -STATIC mp_obj_t pyb_flash_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); +#elif (MICROPY_VFS_LFS1 || MICROPY_VFS_LFS2) && MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE +// Board uses littlefs and internal flash, so enable extended block protocol on internal flash +#define PYB_FLASH_NATIVE_BLOCK_SIZE (FLASH_BLOCK_SIZE) +#define MICROPY_HW_BDEV_READBLOCKS_EXT(dest, bl, off, len) (flash_bdev_readblocks_ext((dest), (bl), (off), (len))) +#define MICROPY_HW_BDEV_WRITEBLOCKS_EXT(dest, bl, off, len) (flash_bdev_writeblocks_ext((dest), (bl), (off), (len))) +#endif - // return singleton object - return MP_OBJ_FROM_PTR(&pyb_flash_obj); +#ifndef PYB_FLASH_NATIVE_BLOCK_SIZE +#define PYB_FLASH_NATIVE_BLOCK_SIZE (FLASH_BLOCK_SIZE) +#endif + +typedef struct _pyb_flash_obj_t { + mp_obj_base_t base; + uint32_t start; // in bytes + uint32_t len; // in bytes + #if defined(SPIFLASH) + bool use_native_block_size; + #endif +} pyb_flash_obj_t; + +// This Flash object represents the entire available flash, with emulated partition table at start +const pyb_flash_obj_t pyb_flash_obj = { + { &pyb_flash_type }, + -(FLASH_PART1_START_BLOCK * FLASH_BLOCK_SIZE), // to offset FLASH_PART1_START_BLOCK + 0, // actual size handled in ioctl, MP_BLOCKDEV_IOCTL_BLOCK_COUNT case +}; + +STATIC void pyb_flash_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_flash_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self == &pyb_flash_obj) { + mp_printf(print, "Flash()"); + } else { + mp_printf(print, "Flash(start=%u, len=%u)", self->start, self->len); + } } -STATIC mp_obj_t pyb_flash_readblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) { +STATIC mp_obj_t pyb_flash_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + // Parse arguments + enum { ARG_start, ARG_len }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_start, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_len, MP_ARG_INT, {.u_int = -1} }, + }; + 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); + + if (args[ARG_start].u_int == -1 && args[ARG_len].u_int == -1) { + // Default singleton object that accesses entire flash, including virtual partition table + return MP_OBJ_FROM_PTR(&pyb_flash_obj); + } + + pyb_flash_obj_t *self = m_new_obj(pyb_flash_obj_t); + self->base.type = &pyb_flash_type; + #if defined(SPIFLASH) + self->use_native_block_size = false; + #endif + + uint32_t bl_len = (storage_get_block_count() - FLASH_PART1_START_BLOCK) * FLASH_BLOCK_SIZE; + + mp_int_t start = args[ARG_start].u_int; + if (start == -1) { + start = 0; + } else if (!(0 <= start && start < bl_len && start % PYB_FLASH_NATIVE_BLOCK_SIZE == 0)) { + mp_raise_ValueError(NULL); + } + + mp_int_t len = args[ARG_len].u_int; + if (len == -1) { + len = bl_len - start; + } else if (!(0 < len && start + len <= bl_len && len % PYB_FLASH_NATIVE_BLOCK_SIZE == 0)) { + mp_raise_ValueError(NULL); + } + + self->start = start; + self->len = len; + + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t pyb_flash_readblocks(size_t n_args, const mp_obj_t *args) { + pyb_flash_obj_t *self = MP_OBJ_TO_PTR(args[0]); + uint32_t block_num = mp_obj_get_int(args[1]); mp_buffer_info_t bufinfo; - mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_WRITE); - mp_uint_t ret = storage_read_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / FLASH_BLOCK_SIZE); + mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_WRITE); + mp_uint_t ret = -MP_EIO; + if (n_args == 3) { + // Cast self->start to signed in case it's pyb_flash_obj with negative start + block_num += FLASH_PART1_START_BLOCK + (int32_t)self->start / FLASH_BLOCK_SIZE; + ret = storage_read_blocks(bufinfo.buf, block_num, bufinfo.len / FLASH_BLOCK_SIZE); + } + #if defined(MICROPY_HW_BDEV_READBLOCKS_EXT) + else if (self != &pyb_flash_obj) { + // Extended block read on a sub-section of the flash storage + uint32_t offset = mp_obj_get_int(args[3]); + block_num += self->start / PYB_FLASH_NATIVE_BLOCK_SIZE; + ret = MICROPY_HW_BDEV_READBLOCKS_EXT(bufinfo.buf, block_num, offset, bufinfo.len); + } + #endif return MP_OBJ_NEW_SMALL_INT(ret); } -STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_flash_readblocks_obj, pyb_flash_readblocks); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_flash_readblocks_obj, 3, 4, pyb_flash_readblocks); -STATIC mp_obj_t pyb_flash_writeblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) { +STATIC mp_obj_t pyb_flash_writeblocks(size_t n_args, const mp_obj_t *args) { + pyb_flash_obj_t *self = MP_OBJ_TO_PTR(args[0]); + uint32_t block_num = mp_obj_get_int(args[1]); mp_buffer_info_t bufinfo; - mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ); - mp_uint_t ret = storage_write_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / FLASH_BLOCK_SIZE); + mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ); + mp_uint_t ret = -MP_EIO; + if (n_args == 3) { + // Cast self->start to signed in case it's pyb_flash_obj with negative start + block_num += FLASH_PART1_START_BLOCK + (int32_t)self->start / FLASH_BLOCK_SIZE; + ret = storage_write_blocks(bufinfo.buf, block_num, bufinfo.len / FLASH_BLOCK_SIZE); + } + #if defined(MICROPY_HW_BDEV_WRITEBLOCKS_EXT) + else if (self != &pyb_flash_obj) { + // Extended block write on a sub-section of the flash storage + uint32_t offset = mp_obj_get_int(args[3]); + block_num += self->start / PYB_FLASH_NATIVE_BLOCK_SIZE; + ret = MICROPY_HW_BDEV_WRITEBLOCKS_EXT(bufinfo.buf, block_num, offset, bufinfo.len); + } + #endif return MP_OBJ_NEW_SMALL_INT(ret); } -STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_flash_writeblocks_obj, pyb_flash_writeblocks); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_flash_writeblocks_obj, 3, 4, pyb_flash_writeblocks); -STATIC mp_obj_t pyb_flash_ioctl(mp_obj_t self, mp_obj_t cmd_in, mp_obj_t arg_in) { +STATIC mp_obj_t pyb_flash_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t arg_in) { + pyb_flash_obj_t *self = self_in; mp_int_t cmd = mp_obj_get_int(cmd_in); switch (cmd) { - case MP_BLOCKDEV_IOCTL_INIT: storage_init(); return MP_OBJ_NEW_SMALL_INT(0); + case MP_BLOCKDEV_IOCTL_INIT: { + mp_int_t ret = 0; + storage_init(); + if (mp_obj_get_int(arg_in) == 1) { + // Will be using extended block protocol + if (self == &pyb_flash_obj) { + ret = -1; + #if defined(SPIFLASH) + } else { + // Switch to use native block size of SPI flash + self->use_native_block_size = true; + #endif + } + } + return MP_OBJ_NEW_SMALL_INT(ret); + } case MP_BLOCKDEV_IOCTL_DEINIT: storage_flush(); return MP_OBJ_NEW_SMALL_INT(0); // TODO properly case MP_BLOCKDEV_IOCTL_SYNC: storage_flush(); return MP_OBJ_NEW_SMALL_INT(0); - case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: return MP_OBJ_NEW_SMALL_INT(storage_get_block_count()); - case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: return MP_OBJ_NEW_SMALL_INT(storage_get_block_size()); + + case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: { + mp_int_t n; + if (self == &pyb_flash_obj) { + // Get true size + n = storage_get_block_count(); + #if defined(SPIFLASH) + } else if (self->use_native_block_size) { + n = self->len / PYB_FLASH_NATIVE_BLOCK_SIZE; + #endif + } else { + n = self->len / FLASH_BLOCK_SIZE; + } + return MP_OBJ_NEW_SMALL_INT(n); + } + + case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: { + mp_int_t n = FLASH_BLOCK_SIZE; + #if defined(SPIFLASH) + if (self->use_native_block_size) { + n = PYB_FLASH_NATIVE_BLOCK_SIZE; + } + #endif + return MP_OBJ_NEW_SMALL_INT(n); + } + + case MP_BLOCKDEV_IOCTL_BLOCK_ERASE: { + int ret = 0; + #if defined(SPIFLASH) + if (self->use_native_block_size) { + mp_int_t block_num = self->start / PYB_FLASH_NATIVE_BLOCK_SIZE + mp_obj_get_int(arg_in); + ret = spi_bdev_ioctl(SPIFLASH, BDEV_IOCTL_BLOCK_ERASE, block_num); + } + #endif + return MP_OBJ_NEW_SMALL_INT(ret); + } + default: return mp_const_none; } } @@ -284,6 +441,7 @@ STATIC MP_DEFINE_CONST_DICT(pyb_flash_locals_dict, pyb_flash_locals_dict_table); const mp_obj_type_t pyb_flash_type = { { &mp_type_type }, .name = MP_QSTR_Flash, + .print = pyb_flash_print, .make_new = pyb_flash_make_new, .locals_dict = (mp_obj_dict_t*)&pyb_flash_locals_dict, }; diff --git a/ports/stm32/storage.h b/ports/stm32/storage.h index 0ba3497a17..3a343b3275 100644 --- a/ports/stm32/storage.h +++ b/ports/stm32/storage.h @@ -35,7 +35,8 @@ enum { BDEV_IOCTL_INIT = 1, BDEV_IOCTL_SYNC = 3, BDEV_IOCTL_NUM_BLOCKS = 4, - BDEV_IOCTL_IRQ_HANDLER = 6, + BDEV_IOCTL_BLOCK_ERASE = 6, + BDEV_IOCTL_IRQ_HANDLER = 7, }; void storage_init(void); @@ -52,6 +53,8 @@ mp_uint_t storage_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t 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); +int flash_bdev_readblocks_ext(uint8_t *dest, uint32_t block, uint32_t offset, uint32_t len); +int flash_bdev_writeblocks_ext(const uint8_t *src, uint32_t block, uint32_t offset, uint32_t len); typedef struct _spi_bdev_t { mp_spiflash_t spiflash; @@ -62,8 +65,12 @@ 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); +// These raw functions bypass the cache and go directly to SPI flash +int spi_bdev_readblocks_raw(spi_bdev_t *bdev, uint8_t *dest, uint32_t block_num, uint32_t block_offset, uint32_t num_bytes); +int spi_bdev_writeblocks_raw(spi_bdev_t *bdev, const uint8_t *src, uint32_t block_num, uint32_t block_offset, uint32_t num_bytes); + extern const struct _mp_obj_type_t pyb_flash_type; -extern const struct _mp_obj_base_t pyb_flash_obj; +extern const struct _pyb_flash_obj_t pyb_flash_obj; struct _fs_user_mount_t; void pyb_flash_init_vfs(struct _fs_user_mount_t *vfs); From 7897f5d9bea22a3a0d7474805af624d0683c6d52 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 13 Nov 2019 22:04:39 +1100 Subject: [PATCH 0993/1788] stm32/main: Auto detect block device used for main filesystem. --- ports/stm32/main.c | 51 ++++++++++++++++++++++++++++++++++++++++--- ports/stm32/storage.c | 2 -- ports/stm32/storage.h | 1 + 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 707b1fc68e..e2b3f3c361 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -35,8 +35,13 @@ #include "lib/mp-readline/readline.h" #include "lib/utils/pyexec.h" #include "lib/oofatfs/ff.h" +#include "lib/littlefs/lfs1.h" +#include "lib/littlefs/lfs1_util.h" +#include "lib/littlefs/lfs2.h" +#include "lib/littlefs/lfs2_util.h" #include "extmod/vfs.h" #include "extmod/vfs_fat.h" +#include "extmod/vfs_lfs.h" #if MICROPY_PY_LWIP #include "lwip/init.h" @@ -183,13 +188,53 @@ MP_NOINLINE STATIC bool init_flash_fs(uint reset_mode) { factory_reset_create_filesystem(); } - // Try to mount the flash on "/flash" and chdir to it for the boot-up directory. + // Default block device to entire flash storage mp_obj_t bdev = MP_OBJ_FROM_PTR(&pyb_flash_obj); + + #if MICROPY_VFS_LFS1 || MICROPY_VFS_LFS2 + + // Try to detect the block device used for the main filesystem, based on the first block + + uint8_t buf[FLASH_BLOCK_SIZE]; + storage_read_blocks(buf, FLASH_PART1_START_BLOCK, 1); + + mp_int_t len = -1; + + #if MICROPY_VFS_LFS1 + if (memcmp(&buf[40], "littlefs", 8) == 0) { + // LFS1 + lfs1_superblock_t *superblock = (void*)&buf[12]; + uint32_t block_size = lfs1_fromle32(superblock->d.block_size); + uint32_t block_count = lfs1_fromle32(superblock->d.block_count); + len = block_count * block_size; + } + #endif + + #if MICROPY_VFS_LFS2 + if (memcmp(&buf[8], "littlefs", 8) == 0) { + // LFS2 + lfs2_superblock_t *superblock = (void*)&buf[20]; + uint32_t block_size = lfs2_fromle32(superblock->block_size); + uint32_t block_count = lfs2_fromle32(superblock->block_count); + len = block_count * block_size; + } + #endif + + if (len != -1) { + // Detected a littlefs filesystem so create correct block device for it + mp_obj_t args[] = { MP_OBJ_NEW_SMALL_INT(0), MP_OBJ_NEW_SMALL_INT(len) }; + bdev = pyb_flash_type.make_new(&pyb_flash_type, 2, 0, args); + } + + #endif + + // Try to mount the flash on "/flash" and chdir to it for the boot-up directory. mp_obj_t mount_point = MP_OBJ_NEW_QSTR(MP_QSTR__slash_flash); int ret = vfs_mount_and_chdir(bdev, mount_point); - if (ret == -MP_ENODEV && reset_mode != 3) { - // No filesystem (and didn't already create one), try to create a fresh one + if (ret == -MP_ENODEV && bdev == MP_OBJ_FROM_PTR(&pyb_flash_obj) && reset_mode != 3) { + // No filesystem, bdev is still the default (so didn't detect a possibly corrupt littlefs), + // and didn't already create a filesystem, so try to create a fresh one now. ret = factory_reset_create_filesystem(); if (ret == 0) { ret = vfs_mount_and_chdir(bdev, mount_point); diff --git a/ports/stm32/storage.c b/ports/stm32/storage.c index 0d3285ba05..06dc8d6859 100644 --- a/ports/stm32/storage.c +++ b/ports/stm32/storage.c @@ -41,8 +41,6 @@ #define STORAGE_SYSTICK_MASK (0x1ff) // 512ms #define STORAGE_IDLE_TICK(tick) (((tick) & ~(SYSTICK_DISPATCH_NUM_SLOTS - 1) & STORAGE_SYSTICK_MASK) == 0) -#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 diff --git a/ports/stm32/storage.h b/ports/stm32/storage.h index 3a343b3275..2766ac59b3 100644 --- a/ports/stm32/storage.h +++ b/ports/stm32/storage.h @@ -29,6 +29,7 @@ #include "drivers/memory/spiflash.h" #define FLASH_BLOCK_SIZE (512) +#define FLASH_PART1_START_BLOCK (0x100) // Try to match Python-level VFS block protocol where possible for these constants enum { From 715e4fc25f7b103da48c9bc9513ee76e12a1471a Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 13 Nov 2019 22:04:52 +1100 Subject: [PATCH 0994/1788] stm32/moduos: Add VfsLfs1 and VfsLfs2 to uos module, if enabled. --- ports/stm32/moduos.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ports/stm32/moduos.c b/ports/stm32/moduos.c index ead2380b33..8bf58623c9 100644 --- a/ports/stm32/moduos.c +++ b/ports/stm32/moduos.c @@ -36,6 +36,7 @@ #include "extmod/misc.h" #include "extmod/vfs.h" #include "extmod/vfs_fat.h" +#include "extmod/vfs_lfs.h" #include "genhdr/mpversion.h" #include "rng.h" #include "usb.h" @@ -174,6 +175,12 @@ STATIC const mp_rom_map_elem_t os_module_globals_table[] = { #if MICROPY_VFS_FAT { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) }, #endif + #if MICROPY_VFS_LFS1 + { MP_ROM_QSTR(MP_QSTR_VfsLfs1), MP_ROM_PTR(&mp_type_vfs_lfs1) }, + #endif + #if MICROPY_VFS_LFS2 + { MP_ROM_QSTR(MP_QSTR_VfsLfs2), MP_ROM_PTR(&mp_type_vfs_lfs2) }, + #endif }; STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table); From 5634a31a9835ead5bdf7bbff5380c878f16db56d Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 14 Nov 2019 16:30:10 +1100 Subject: [PATCH 0995/1788] extmod/vfs_lfs: Pass flag along to ioctl when init'ing bdev for lfs. To hint to the block device that the extended block protocol will be used. --- extmod/vfs_lfsx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extmod/vfs_lfsx.c b/extmod/vfs_lfsx.c index e5826803b2..4f5ad5fdf7 100644 --- a/extmod/vfs_lfsx.c +++ b/extmod/vfs_lfsx.c @@ -73,7 +73,7 @@ STATIC void MP_VFS_LFSx(init_config)(MP_OBJ_VFS_LFSx *self, mp_obj_t bdev, size_ config->erase = MP_VFS_LFSx(dev_erase); config->sync = MP_VFS_LFSx(dev_sync); - MP_VFS_LFSx(dev_ioctl)(config, MP_BLOCKDEV_IOCTL_INIT, 0, false); // initialise block device + MP_VFS_LFSx(dev_ioctl)(config, MP_BLOCKDEV_IOCTL_INIT, 1, false); // initialise block device int bs = MP_VFS_LFSx(dev_ioctl)(config, MP_BLOCKDEV_IOCTL_BLOCK_SIZE, 0, true); // get block size int bc = MP_VFS_LFSx(dev_ioctl)(config, MP_BLOCKDEV_IOCTL_BLOCK_COUNT, 0, true); // get block count self->blockdev.block_size = bs; From 120368ba1ab444b2f1c17d1eb69bc6f09072ec5d Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 14 Nov 2019 16:36:05 +1100 Subject: [PATCH 0996/1788] stm32/boards: Enable LFS2 on PYBv1.x and PYBD boards. --- ports/stm32/boards/PYBD_SF2/mpconfigboard.h | 1 + ports/stm32/boards/PYBD_SF2/mpconfigboard.mk | 1 + ports/stm32/boards/PYBV10/mpconfigboard.mk | 3 +++ ports/stm32/boards/PYBV11/mpconfigboard.mk | 3 +++ 4 files changed, 8 insertions(+) diff --git a/ports/stm32/boards/PYBD_SF2/mpconfigboard.h b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h index 8926ec081b..8e116bd02a 100644 --- a/ports/stm32/boards/PYBD_SF2/mpconfigboard.h +++ b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h @@ -84,6 +84,7 @@ extern struct _spi_bdev_t spi_bdev; ) #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)) +#define MICROPY_HW_BDEV_SPIFLASH_EXTENDED (&spi_bdev) // for extended block protocol // SPI flash #2, to be memory mapped #define MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2 (24) diff --git a/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk b/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk index 834a60b029..9c0121f313 100644 --- a/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk +++ b/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk @@ -16,3 +16,4 @@ MICROPY_PY_LWIP = 1 MICROPY_PY_NETWORK_CYW43 = 1 MICROPY_PY_USSL = 1 MICROPY_SSL_MBEDTLS = 1 +MICROPY_VFS_LFS2 = 1 diff --git a/ports/stm32/boards/PYBV10/mpconfigboard.mk b/ports/stm32/boards/PYBV10/mpconfigboard.mk index a4430cc1df..cb78a7846d 100644 --- a/ports/stm32/boards/PYBV10/mpconfigboard.mk +++ b/ports/stm32/boards/PYBV10/mpconfigboard.mk @@ -11,3 +11,6 @@ LD_FILES = boards/stm32f405.ld boards/common_ifs.ld TEXT0_ADDR = 0x08000000 TEXT1_ADDR = 0x08020000 endif + +# MicroPython settings +MICROPY_VFS_LFS2 = 1 diff --git a/ports/stm32/boards/PYBV11/mpconfigboard.mk b/ports/stm32/boards/PYBV11/mpconfigboard.mk index a4430cc1df..cb78a7846d 100644 --- a/ports/stm32/boards/PYBV11/mpconfigboard.mk +++ b/ports/stm32/boards/PYBV11/mpconfigboard.mk @@ -11,3 +11,6 @@ LD_FILES = boards/stm32f405.ld boards/common_ifs.ld TEXT0_ADDR = 0x08000000 TEXT1_ADDR = 0x08020000 endif + +# MicroPython settings +MICROPY_VFS_LFS2 = 1 From d8057c325a63d87b3e37cf4a6cdb04cb4eeba124 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 21 Nov 2019 16:11:59 +1100 Subject: [PATCH 0997/1788] stm32/storage: Change storage_read/write_blocks to return int type. And return -MP_EIO if calling storage_read_block/storage_write_block fails. This lines up with the return type and value (negative for error) of the calls to MICROPY_HW_BDEV_READBLOCKS (and WRITEBLOCKS, and BDEV2 versions). --- ports/stm32/storage.c | 8 ++++---- ports/stm32/storage.h | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ports/stm32/storage.c b/ports/stm32/storage.c index 06dc8d6859..aecef8acc6 100644 --- a/ports/stm32/storage.c +++ b/ports/stm32/storage.c @@ -185,7 +185,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) { +int storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t 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); @@ -200,13 +200,13 @@ mp_uint_t storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_bl for (size_t i = 0; i < num_blocks; i++) { if (!storage_read_block(dest + i * FLASH_BLOCK_SIZE, block_num + i)) { - return 1; // error + return -MP_EIO; // error } } return 0; // success } -mp_uint_t storage_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) { +int storage_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t 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); @@ -221,7 +221,7 @@ mp_uint_t storage_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t for (size_t i = 0; i < num_blocks; i++) { if (!storage_write_block(src + i * FLASH_BLOCK_SIZE, block_num + i)) { - return 1; // error + return -MP_EIO; // error } } return 0; // success diff --git a/ports/stm32/storage.h b/ports/stm32/storage.h index 2766ac59b3..490fc4a09b 100644 --- a/ports/stm32/storage.h +++ b/ports/stm32/storage.h @@ -47,9 +47,9 @@ void storage_flush(void); bool storage_read_block(uint8_t *dest, uint32_t block); bool storage_write_block(const uint8_t *src, uint32_t block); -// these return 0 on success, non-zero on error -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); +// these return 0 on success, negative errno on error +int storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks); +int storage_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks); int32_t flash_bdev_ioctl(uint32_t op, uint32_t arg); bool flash_bdev_readblock(uint8_t *dest, uint32_t block); From 6b3404f25e3d901d9b1313f2827a760093cddd92 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 22 Nov 2019 15:14:24 +1100 Subject: [PATCH 0998/1788] extmod/vfs_lfs: Fix bug when passing no args to constructor and mkfs. --- extmod/vfs_lfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extmod/vfs_lfs.c b/extmod/vfs_lfs.c index d776849980..f34d160f00 100644 --- a/extmod/vfs_lfs.c +++ b/extmod/vfs_lfs.c @@ -33,7 +33,7 @@ enum { LFS_MAKE_ARG_bdev, LFS_MAKE_ARG_readsize, LFS_MAKE_ARG_progsize, LFS_MAKE_ARG_lookahead }; static const mp_arg_t lfs_make_allowed_args[] = { - { MP_QSTR_, MP_ARG_OBJ }, + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_readsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} }, { MP_QSTR_progsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} }, { MP_QSTR_lookahead, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} }, From a7bc4d1a1455a8a5cdea53d7a2caf03c9320f460 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 22 Nov 2019 14:06:49 +0100 Subject: [PATCH 0999/1788] py/builtinimport: Raise exception on empty module name. To prevent a crash returning MP_OBJ_NULL. A test is added for this case. --- py/builtinimport.c | 4 ++++ tests/import/builtin_import.py | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/py/builtinimport.c b/py/builtinimport.c index b9f6c2ab2d..9d91b20599 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -334,6 +334,10 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { mod_len = new_mod_l; } + if (mod_len == 0) { + mp_raise_ValueError(NULL); + } + // check if module already exists qstr module_name_qstr = mp_obj_str_get_qstr(module_name); mp_obj_t module_obj = mp_module_get(module_name_qstr); diff --git a/tests/import/builtin_import.py b/tests/import/builtin_import.py index 088f631fcd..157da98398 100644 --- a/tests/import/builtin_import.py +++ b/tests/import/builtin_import.py @@ -9,6 +9,12 @@ try: except TypeError: print('TypeError') +# module name should not be empty +try: + __import__("") +except ValueError: + print('ValueError') + # level argument should be non-negative try: __import__('xyz', None, None, None, -1) From bc129f1b84cc05ad92e6743b4f298e8aea5cbe50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 22 Nov 2019 10:07:08 +0100 Subject: [PATCH 1000/1788] py/qstr: Raise exception in qstr_from_strn if str to intern is too long. The string length being longer than the allowed qstr length can happen in many locations, for example in the parser with very long variable names. Without an explicit check that the length is within range (as done in this patch) the code would exhibit crashes and strange behaviour with truncated strings. --- py/qstr.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/py/qstr.c b/py/qstr.c index e6f86401a0..29ffcae408 100644 --- a/py/qstr.c +++ b/py/qstr.c @@ -31,6 +31,7 @@ #include "py/mpstate.h" #include "py/qstr.h" #include "py/gc.h" +#include "py/runtime.h" // NOTE: we are using linear arrays to store and search for qstr's (unique strings, interned strings) // ultimately we will replace this with a static hash table of some kind @@ -192,12 +193,17 @@ qstr qstr_from_str(const char *str) { } qstr qstr_from_strn(const char *str, size_t len) { - assert(len < (1 << (8 * MICROPY_QSTR_BYTES_IN_LEN))); QSTR_ENTER(); qstr q = qstr_find_strn(str, len); if (q == 0) { // qstr does not exist in interned pool so need to add it + // check that len is not too big + if (len >= (1 << (8 * MICROPY_QSTR_BYTES_IN_LEN))) { + QSTR_EXIT(); + mp_raise_msg(&mp_type_RuntimeError, "name too long"); + } + // compute number of bytes needed to intern this string size_t n_bytes = MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN + len + 1; From 1675b98e74e6af0bd5edaf236a275dcb7735069e Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 22 Nov 2019 16:18:25 +1100 Subject: [PATCH 1001/1788] tests/stress: Add test for maximum length limit of qstrs. --- tests/stress/qstr_limit.py | 85 ++++++++++++++++++++++++++++++++++ tests/stress/qstr_limit.py.exp | 43 +++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 tests/stress/qstr_limit.py create mode 100644 tests/stress/qstr_limit.py.exp diff --git a/tests/stress/qstr_limit.py b/tests/stress/qstr_limit.py new file mode 100644 index 0000000000..90c85dae96 --- /dev/null +++ b/tests/stress/qstr_limit.py @@ -0,0 +1,85 @@ +# Test interning qstrs that go over the limit of the maximum qstr length +# (which is 255 bytes for the default configuration) + +def make_id(n, base='a'): + return ''.join(chr(ord(base) + i % 26) for i in range(n)) + +# identifiers in parser +for l in range(254, 259): + g = {} + var = make_id(l) + try: + exec(var + '=1', g) + except RuntimeError: + print('RuntimeError', l) + continue + print(var in g) + +# calling a function with kwarg +def f(**k): + print(k) +for l in range(254, 259): + try: + exec('f({}=1)'.format(make_id(l))) + except RuntimeError: + print('RuntimeError', l) + +# type construction +for l in range(254, 259): + id = make_id(l) + try: + print(type(id, (), {}).__name__) + except RuntimeError: + print('RuntimeError', l) + +# hasattr, setattr, getattr +class A: + pass +for l in range(254, 259): + id = make_id(l) + a = A() + try: + setattr(a, id, 123) + except RuntimeError: + print('RuntimeError', l) + try: + print(hasattr(a, id), getattr(a, id)) + except RuntimeError: + print('RuntimeError', l) + +# format with keys +for l in range(254, 259): + id = make_id(l) + try: + print(('{' + id + '}').format(**{id: l})) + except RuntimeError: + print('RuntimeError', l) + +# modulo format with keys +for l in range(254, 259): + id = make_id(l) + try: + print(('%(' + id + ')d') % {id: l}) + except RuntimeError: + print('RuntimeError', l) + +# import module +# (different OS's have different results so only print those that are consistent) +for l in range(150, 259): + try: + __import__(make_id(l)) + except ImportError: + if l < 152: + print('ok', l) + except RuntimeError: + if l > 255: + print('RuntimeError', l) + +# import package +for l in range(125, 130): + try: + exec('import ' + make_id(l) + '.' + make_id(l, 'A')) + except ImportError: + print('ok', l) + except RuntimeError: + print('RuntimeError', l) diff --git a/tests/stress/qstr_limit.py.exp b/tests/stress/qstr_limit.py.exp new file mode 100644 index 0000000000..516c9d7f6c --- /dev/null +++ b/tests/stress/qstr_limit.py.exp @@ -0,0 +1,43 @@ +True +True +RuntimeError 256 +RuntimeError 257 +RuntimeError 258 +{'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrst': 1} +{'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstu': 1} +RuntimeError 256 +RuntimeError 257 +RuntimeError 258 +abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrst +abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstu +RuntimeError 256 +RuntimeError 257 +RuntimeError 258 +True 123 +True 123 +RuntimeError 256 +RuntimeError 256 +RuntimeError 257 +RuntimeError 257 +RuntimeError 258 +RuntimeError 258 +254 +255 +RuntimeError 256 +RuntimeError 257 +RuntimeError 258 +254 +255 +RuntimeError 256 +RuntimeError 257 +RuntimeError 258 +ok 150 +ok 151 +RuntimeError 256 +RuntimeError 257 +RuntimeError 258 +ok 125 +ok 126 +ok 127 +RuntimeError 128 +RuntimeError 129 From 4318a6d755b8365e4dfd4842c994003176cf6b70 Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Mon, 25 Nov 2019 17:21:54 +0200 Subject: [PATCH 1002/1788] py/objstringio: Slightly optimize stringio_copy_on_write for code size. With the memcpy() call placed last it avoids the effects of registers clobbering. It's definitely effective in non-inlined functions, but even here it is still making a small difference. For example, on stm32, this saves an extra `ldr` instruction to load `o->vstr` after the memcpy() returns. --- py/objstringio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/objstringio.c b/py/objstringio.c index 8f1f761138..cca4a81297 100644 --- a/py/objstringio.c +++ b/py/objstringio.c @@ -70,9 +70,9 @@ STATIC mp_uint_t stringio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *er STATIC void stringio_copy_on_write(mp_obj_stringio_t *o) { const void *buf = o->vstr->buf; o->vstr->buf = m_new(char, o->vstr->len); - memcpy(o->vstr->buf, buf, o->vstr->len); o->vstr->fixed_buf = false; o->ref_obj = MP_OBJ_NULL; + memcpy(o->vstr->buf, buf, o->vstr->len); } STATIC mp_uint_t stringio_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) { From 797c2e8fc23ceeb9d6ce5079e2f82ee7b3431bee Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 26 Nov 2019 21:35:00 +1100 Subject: [PATCH 1003/1788] stm32/storage: Make start/len args of pyb.Flash keyword only. To allow the future possibility of initial positional args, like flash id. --- ports/stm32/storage.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/stm32/storage.c b/ports/stm32/storage.c index aecef8acc6..ebb62e44cf 100644 --- a/ports/stm32/storage.c +++ b/ports/stm32/storage.c @@ -279,8 +279,8 @@ STATIC mp_obj_t pyb_flash_make_new(const mp_obj_type_t *type, size_t n_args, siz // Parse arguments enum { ARG_start, ARG_len }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_start, MP_ARG_INT, {.u_int = -1} }, - { MP_QSTR_len, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_len, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, }; 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); From 01e5802ee39d8c5c18b2f24291776b6e9128d077 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 26 Nov 2019 21:36:41 +1100 Subject: [PATCH 1004/1788] py: Remove 3 obsolete commented-out lines from header files. --- py/lexer.h | 2 -- py/obj.h | 1 - py/runtime.h | 1 - 3 files changed, 4 deletions(-) diff --git a/py/lexer.h b/py/lexer.h index 34126a08fc..b9f97013a1 100644 --- a/py/lexer.h +++ b/py/lexer.h @@ -184,8 +184,6 @@ void mp_lexer_to_next(mp_lexer_t *lex); // platform specific import function; must be implemented for a specific port // TODO tidy up, rename, or put elsewhere -//mp_lexer_t *mp_import_open_file(qstr mod_name); - typedef enum { MP_IMPORT_STAT_NO_EXIST, MP_IMPORT_STAT_DIR, diff --git a/py/obj.h b/py/obj.h index a22d5f8b81..5b54892ce8 100644 --- a/py/obj.h +++ b/py/obj.h @@ -691,7 +691,6 @@ mp_float_t mp_obj_get_float(mp_obj_t self_in); bool mp_obj_get_float_maybe(mp_obj_t arg, mp_float_t *value); void mp_obj_get_complex(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag); #endif -//qstr mp_obj_get_qstr(mp_obj_t arg); void mp_obj_get_array(mp_obj_t o, size_t *len, mp_obj_t **items); // *items may point inside a GC block void mp_obj_get_array_fixed_n(mp_obj_t o, size_t len, mp_obj_t **items); // *items may point inside a GC block size_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool is_slice); diff --git a/py/runtime.h b/py/runtime.h index 1ac383ca71..b54b17b683 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -151,7 +151,6 @@ mp_obj_t mp_import_from(mp_obj_t module, qstr name); void mp_import_all(mp_obj_t module); NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, const char *msg); -//NORETURN void nlr_raise_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...); NORETURN void mp_raise_ValueError(const char *msg); NORETURN void mp_raise_TypeError(const char *msg); NORETURN void mp_raise_NotImplementedError(const char *msg); From 77b8f86a5eae397c42c4c68fd9f86bbfa0311c82 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 27 Nov 2019 21:48:00 +1100 Subject: [PATCH 1005/1788] stm32/qstrdefsport.h: Remove unused qstrs and make USB ones conditional. qstrs in this file are always included in all builds, even if not used anywhere. So remove those that are never needed, and make USB names conditional on having USB enabled. --- ports/stm32/qstrdefsport.h | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/ports/stm32/qstrdefsport.h b/ports/stm32/qstrdefsport.h index 31220c5a42..857dc709c9 100644 --- a/ports/stm32/qstrdefsport.h +++ b/ports/stm32/qstrdefsport.h @@ -26,22 +26,18 @@ // qstrs specific to this port -Q(boot.py) -Q(main.py) // Entries for sys.path Q(/flash) Q(/flash/lib) Q(/sd) Q(/sd/lib) + +// For uos.sep +Q(/) + +#if MICROPY_HW_ENABLE_USB // for usb modes Q(MSC+HID) Q(VCP+MSC) Q(VCP+HID) -Q(CDC+MSC) -Q(CDC+HID) -Q(/) - - -// The following qstrings not referenced from anywhere in the sources -Q(CDC) -Q(flash) +#endif From 11c22430d4efe7eb8c87163faaae647b1e99abf8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 27 Nov 2019 21:50:30 +1100 Subject: [PATCH 1006/1788] stm32/boards/NUCLEO_L073RZ: Skip board-pin names for CPU only pins. This board doesn't have much flash and removing these unneeded names saves about 900 bytes of code size. --- ports/stm32/boards/NUCLEO_L073RZ/pins.csv | 104 +++++++++++----------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/ports/stm32/boards/NUCLEO_L073RZ/pins.csv b/ports/stm32/boards/NUCLEO_L073RZ/pins.csv index 36d3141083..7386425acf 100644 --- a/ports/stm32/boards/NUCLEO_L073RZ/pins.csv +++ b/ports/stm32/boards/NUCLEO_L073RZ/pins.csv @@ -33,55 +33,55 @@ 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 +,PA0 +,PA1 +,PA2 +,PA3 +,PA4 +,PA5 +,PA6 +,PA7 +,PA8 +,PA9 +,PA10 +,PA11 +,PA12 +,PA13 +,PA14 +,PA15 +,PB0 +,PB1 +,PB2 +,PB3 +,PB4 +,PB5 +,PB6 +,PB7 +,PB8 +,PB9 +,PB10 +,PB11 +,PB12 +,PB13 +,PB14 +,PB15 +,PC0 +,PC1 +,PC2 +,PC3 +,PC4 +,PC5 +,PC6 +,PC7 +,PC8 +,PC9 +,PC10 +,PC11 +,PC12 +,PC13 +,PC14 +,PC15 +,PD2 +,PF0 +,PF1 +,PF11 From ba5e4841ecdfc83b6473bf4c5d1725c6069c6567 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 27 Nov 2019 22:47:05 +1100 Subject: [PATCH 1007/1788] stm32/main: Fix auto creation of pyb.Flash on boot with kw-only args. --- ports/stm32/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index e2b3f3c361..8cb6ed1e3b 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -222,8 +222,8 @@ MP_NOINLINE STATIC bool init_flash_fs(uint reset_mode) { if (len != -1) { // Detected a littlefs filesystem so create correct block device for it - mp_obj_t args[] = { MP_OBJ_NEW_SMALL_INT(0), MP_OBJ_NEW_SMALL_INT(len) }; - bdev = pyb_flash_type.make_new(&pyb_flash_type, 2, 0, args); + mp_obj_t args[] = { MP_OBJ_NEW_QSTR(MP_QSTR_len), MP_OBJ_NEW_SMALL_INT(len) }; + bdev = pyb_flash_type.make_new(&pyb_flash_type, 0, 1, args); } #endif From 7f24c297787cd4bd92647f407017acbecdb0f949 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 28 Nov 2019 13:11:51 +1100 Subject: [PATCH 1008/1788] tools/mpy-tool.py: Support qstr linking when freezing Xtensa native mpy. --- tools/mpy-tool.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index 9b0b8e8cd2..581603249d 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -428,9 +428,11 @@ class RawCodeNative(RawCode): else: self.fun_data_attributes = '__attribute__((section(".text,\\"ax\\",%progbits @ ")))' - # Allow single-byte alignment by default for x86/x64/xtensa, but on ARM we need halfword- or word- alignment. - if config.native_arch == MP_NATIVE_ARCH_ARMV6: - # ARMV6 -- four byte align. + # Allow single-byte alignment by default for x86/x64. + # ARM needs word alignment, ARM Thumb needs halfword, due to instruction size. + # Xtensa needs word alignment due to the 32-bit constant table embedded in the code. + if config.native_arch in (MP_NATIVE_ARCH_ARMV6, MP_NATIVE_ARCH_XTENSA, MP_NATIVE_ARCH_XTENSAWIN): + # ARMV6 or Xtensa -- four byte align. self.fun_data_attributes += ' __attribute__ ((aligned (4)))' elif MP_NATIVE_ARCH_ARMV6M <= config.native_arch <= MP_NATIVE_ARCH_ARMV7EMDP: # ARMVxxM -- two byte align. @@ -452,8 +454,11 @@ class RawCodeNative(RawCode): is_obj = kind == 2 if is_obj: qst = '((uintptr_t)MP_OBJ_NEW_QSTR(%s))' % qst - if config.native_arch in (MP_NATIVE_ARCH_X86, MP_NATIVE_ARCH_X64): - print(' %s & 0xff, %s >> 8, 0, 0,' % (qst, qst)) + if config.native_arch in ( + MP_NATIVE_ARCH_X86, MP_NATIVE_ARCH_X64, + MP_NATIVE_ARCH_XTENSA, MP_NATIVE_ARCH_XTENSAWIN + ): + print(' %s & 0xff, (%s >> 8) & 0xff, (%s >> 16) & 0xff, %s >> 24,' % (qst, qst, qst, qst)) return 4 elif MP_NATIVE_ARCH_ARMV6M <= config.native_arch <= MP_NATIVE_ARCH_ARMV7EMDP: if is_obj: From d6e051082af51566d4a16dc90f89da75a5007c06 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 29 Nov 2019 11:33:29 +1100 Subject: [PATCH 1009/1788] extmod/modbluetooth: Simplify how BLE IRQ callback is scheduled. Instead of enqueue_irq() inspecting the ringbuf to decide whether to schedule the IRQ callback (if ringbuf is empty), maintain a flag that knows if the callback is on the schedule queue or not. This saves about 150 bytes of code (for stm32 builds), and simplifies all uses of enqueue_irq() and schedule_ringbuf(). --- extmod/modbluetooth.c | 66 ++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 38 deletions(-) diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index bac7c07cbe..cb014bd9ed 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -60,6 +60,7 @@ typedef struct { mp_obj_base_t base; mp_obj_t irq_handler; uint16_t irq_trigger; + bool irq_scheduled; mp_obj_t irq_data_tuple; uint8_t irq_data_addr_bytes[6]; uint8_t irq_data_data_bytes[MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN]; @@ -757,9 +758,12 @@ STATIC void ringbuf_extract(ringbuf_t* ringbuf, mp_obj_tuple_t *data_tuple, size STATIC mp_obj_t bluetooth_ble_invoke_irq(mp_obj_t none_in) { // This is always executing in schedule context. + + mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); + o->irq_scheduled = false; + for (;;) { MICROPY_PY_BLUETOOTH_ENTER - mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); mp_int_t event = event = ringbuf_get16(&o->ringbuf); if (event < 0) { @@ -822,9 +826,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(bluetooth_ble_invoke_irq_obj, bluetooth_ble_inv // Callbacks are called in interrupt context (i.e. can't allocate), so we need to push the data // into the ringbuf and schedule the callback via mp_sched_schedule. -STATIC bool enqueue_irq(mp_obj_bluetooth_ble_t *o, size_t len, uint16_t event, bool *sched) { - *sched = false; - +STATIC bool enqueue_irq(mp_obj_bluetooth_ble_t *o, size_t len, uint16_t event) { if (!o || !(o->irq_trigger & event) || o->irq_handler == mp_const_none) { return false; } @@ -849,11 +851,6 @@ STATIC bool enqueue_irq(mp_obj_bluetooth_ble_t *o, size_t len, uint16_t event, b for (int i = 0; i < n; ++i) { ringbuf_get(&o->ringbuf); } - - // No need to schedule the handler, as the ringbuffer was non-empty. - } else { - // Schedule the handler only if this is the first thing in the ringbuffer. - *sched = ringbuf_avail(&o->ringbuf) == 0; } // Append this event, the caller will then append the arguments. @@ -861,8 +858,10 @@ STATIC bool enqueue_irq(mp_obj_bluetooth_ble_t *o, size_t len, uint16_t event, b return true; } -STATIC void schedule_ringbuf(bool sched) { - if (sched) { +STATIC void schedule_ringbuf(void) { + mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); + if (!o->irq_scheduled) { + o->irq_scheduled = true; mp_sched_schedule(MP_OBJ_FROM_PTR(MP_ROM_PTR(&bluetooth_ble_invoke_irq_obj)), mp_const_none); } } @@ -870,47 +869,43 @@ STATIC void schedule_ringbuf(bool sched) { void mp_bluetooth_gap_on_connected_disconnected(uint16_t event, uint16_t conn_handle, uint8_t addr_type, const uint8_t *addr) { MICROPY_PY_BLUETOOTH_ENTER mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); - bool sched; - if (enqueue_irq(o, 2 + 1 + 6, event, &sched)) { + if (enqueue_irq(o, 2 + 1 + 6, event)) { ringbuf_put16(&o->ringbuf, conn_handle); ringbuf_put(&o->ringbuf, addr_type); for (int i = 0; i < 6; ++i) { ringbuf_put(&o->ringbuf, addr[i]); } } + schedule_ringbuf(); MICROPY_PY_BLUETOOTH_EXIT - schedule_ringbuf(sched); } void mp_bluetooth_gatts_on_write(uint16_t conn_handle, uint16_t value_handle) { MICROPY_PY_BLUETOOTH_ENTER mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); - bool sched; - if (enqueue_irq(o, 2 + 2, MP_BLUETOOTH_IRQ_GATTS_WRITE, &sched)) { + if (enqueue_irq(o, 2 + 2, MP_BLUETOOTH_IRQ_GATTS_WRITE)) { ringbuf_put16(&o->ringbuf, conn_handle); ringbuf_put16(&o->ringbuf, value_handle); } + schedule_ringbuf(); MICROPY_PY_BLUETOOTH_EXIT - schedule_ringbuf(sched); } #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE void mp_bluetooth_gap_on_scan_complete(void) { MICROPY_PY_BLUETOOTH_ENTER mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); - bool sched; - if (enqueue_irq(o, 0, MP_BLUETOOTH_IRQ_SCAN_COMPLETE, &sched)) { + if (enqueue_irq(o, 0, MP_BLUETOOTH_IRQ_SCAN_COMPLETE)) { } + schedule_ringbuf(); MICROPY_PY_BLUETOOTH_EXIT - schedule_ringbuf(sched); } void mp_bluetooth_gap_on_scan_result(uint8_t addr_type, const uint8_t *addr, bool connectable, const int8_t rssi, const uint8_t *data, size_t data_len) { MICROPY_PY_BLUETOOTH_ENTER mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); - bool sched; data_len = MIN(MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN, data_len); - if (enqueue_irq(o, 1 + 6 + 1 + 1 + 1 + data_len, MP_BLUETOOTH_IRQ_SCAN_RESULT, &sched)) { + if (enqueue_irq(o, 1 + 6 + 1 + 1 + 1 + data_len, MP_BLUETOOTH_IRQ_SCAN_RESULT)) { ringbuf_put(&o->ringbuf, addr_type); for (int i = 0; i < 6; ++i) { ringbuf_put(&o->ringbuf, addr[i]); @@ -923,58 +918,54 @@ void mp_bluetooth_gap_on_scan_result(uint8_t addr_type, const uint8_t *addr, boo ringbuf_put(&o->ringbuf, data[i]); } } + schedule_ringbuf(); MICROPY_PY_BLUETOOTH_EXIT - schedule_ringbuf(sched); } void mp_bluetooth_gattc_on_primary_service_result(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, mp_obj_bluetooth_uuid_t *service_uuid) { MICROPY_PY_BLUETOOTH_ENTER mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); - bool sched; - if (enqueue_irq(o, 2 + 2 + 2 + 1 + service_uuid->type, MP_BLUETOOTH_IRQ_GATTC_SERVICE_RESULT, &sched)) { + if (enqueue_irq(o, 2 + 2 + 2 + 1 + service_uuid->type, MP_BLUETOOTH_IRQ_GATTC_SERVICE_RESULT)) { ringbuf_put16(&o->ringbuf, conn_handle); ringbuf_put16(&o->ringbuf, start_handle); ringbuf_put16(&o->ringbuf, end_handle); ringbuf_put_uuid(&o->ringbuf, service_uuid); } + schedule_ringbuf(); MICROPY_PY_BLUETOOTH_EXIT - schedule_ringbuf(sched); } void mp_bluetooth_gattc_on_characteristic_result(uint16_t conn_handle, uint16_t def_handle, uint16_t value_handle, uint8_t properties, mp_obj_bluetooth_uuid_t *characteristic_uuid) { MICROPY_PY_BLUETOOTH_ENTER mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); - bool sched; - if (enqueue_irq(o, 2 + 2 + 2 + 1 + characteristic_uuid->type, MP_BLUETOOTH_IRQ_GATTC_CHARACTERISTIC_RESULT, &sched)) { + if (enqueue_irq(o, 2 + 2 + 2 + 1 + characteristic_uuid->type, MP_BLUETOOTH_IRQ_GATTC_CHARACTERISTIC_RESULT)) { ringbuf_put16(&o->ringbuf, conn_handle); ringbuf_put16(&o->ringbuf, def_handle); ringbuf_put16(&o->ringbuf, value_handle); ringbuf_put(&o->ringbuf, properties); ringbuf_put_uuid(&o->ringbuf, characteristic_uuid); } + schedule_ringbuf(); MICROPY_PY_BLUETOOTH_EXIT - schedule_ringbuf(sched); } void mp_bluetooth_gattc_on_descriptor_result(uint16_t conn_handle, uint16_t handle, mp_obj_bluetooth_uuid_t *descriptor_uuid) { MICROPY_PY_BLUETOOTH_ENTER mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); - bool sched; - if (enqueue_irq(o, 2 + 2 + 1 + descriptor_uuid->type, MP_BLUETOOTH_IRQ_GATTC_DESCRIPTOR_RESULT, &sched)) { + if (enqueue_irq(o, 2 + 2 + 1 + descriptor_uuid->type, MP_BLUETOOTH_IRQ_GATTC_DESCRIPTOR_RESULT)) { ringbuf_put16(&o->ringbuf, conn_handle); ringbuf_put16(&o->ringbuf, handle); ringbuf_put_uuid(&o->ringbuf, descriptor_uuid); } + schedule_ringbuf(); MICROPY_PY_BLUETOOTH_EXIT - schedule_ringbuf(sched); } void mp_bluetooth_gattc_on_data_available(uint16_t event, uint16_t conn_handle, uint16_t value_handle, const uint8_t *data, size_t data_len) { MICROPY_PY_BLUETOOTH_ENTER mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); - bool sched; data_len = MIN(MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN, data_len); - if (enqueue_irq(o, 2 + 2 + 1 + data_len, event, &sched)) { + if (enqueue_irq(o, 2 + 2 + 1 + data_len, event)) { ringbuf_put16(&o->ringbuf, conn_handle); ringbuf_put16(&o->ringbuf, value_handle); ringbuf_put(&o->ringbuf, data_len); @@ -982,21 +973,20 @@ void mp_bluetooth_gattc_on_data_available(uint16_t event, uint16_t conn_handle, ringbuf_put(&o->ringbuf, data[i]); } } + schedule_ringbuf(); MICROPY_PY_BLUETOOTH_EXIT - schedule_ringbuf(sched); } void mp_bluetooth_gattc_on_write_status(uint16_t conn_handle, uint16_t value_handle, uint16_t status) { MICROPY_PY_BLUETOOTH_ENTER mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); - bool sched; - if (enqueue_irq(o, 2 + 2 + 2, MP_BLUETOOTH_IRQ_GATTC_WRITE_STATUS, &sched)) { + if (enqueue_irq(o, 2 + 2 + 2, MP_BLUETOOTH_IRQ_GATTC_WRITE_STATUS)) { ringbuf_put16(&o->ringbuf, conn_handle); ringbuf_put16(&o->ringbuf, value_handle); ringbuf_put16(&o->ringbuf, status); } + schedule_ringbuf(); MICROPY_PY_BLUETOOTH_EXIT - schedule_ringbuf(sched); } #endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE From 8ce69288e9151d6bd5c218cde171d7d7dad9afd2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 29 Nov 2019 12:36:32 +1100 Subject: [PATCH 1010/1788] extmod/modbluetooth: Remove limit on data coming from gattc data input. This removes the limit on data coming in from a BLE.gattc_read() request, or a notify with payload (coming in to a central). In both cases the data coming in to the BLE callback is now limited only by the available data in the ringbuf, whereas before it was capped at (default hard coded) 20 bytes. --- extmod/modbluetooth.c | 26 ++++++++++++++------------ extmod/modbluetooth.h | 12 +++++++++++- extmod/modbluetooth_nimble.c | 33 +++++++++++++++++++-------------- 3 files changed, 44 insertions(+), 27 deletions(-) diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index cb014bd9ed..96cd41ae45 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -42,12 +42,6 @@ #error modbluetooth requires MICROPY_ENABLE_SCHEDULER #endif -// This is used to protect the ringbuffer. -#ifndef MICROPY_PY_BLUETOOTH_ENTER -#define MICROPY_PY_BLUETOOTH_ENTER mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); -#define MICROPY_PY_BLUETOOTH_EXIT MICROPY_END_ATOMIC_SECTION(atomic_state); -#endif - #define MP_BLUETOOTH_CONNECT_DEFAULT_SCAN_DURATION_MS 2000 #define MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_TUPLE_LEN 5 @@ -961,20 +955,28 @@ void mp_bluetooth_gattc_on_descriptor_result(uint16_t conn_handle, uint16_t hand MICROPY_PY_BLUETOOTH_EXIT } -void mp_bluetooth_gattc_on_data_available(uint16_t event, uint16_t conn_handle, uint16_t value_handle, const uint8_t *data, size_t data_len) { - MICROPY_PY_BLUETOOTH_ENTER +size_t mp_bluetooth_gattc_on_data_available_start(uint16_t event, uint16_t conn_handle, uint16_t value_handle, size_t data_len) { mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); data_len = MIN(MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN, data_len); if (enqueue_irq(o, 2 + 2 + 1 + data_len, event)) { ringbuf_put16(&o->ringbuf, conn_handle); ringbuf_put16(&o->ringbuf, value_handle); ringbuf_put(&o->ringbuf, data_len); - for (int i = 0; i < data_len; ++i) { - ringbuf_put(&o->ringbuf, data[i]); - } + return data_len; + } else { + return 0; } +} + +void mp_bluetooth_gattc_on_data_available_chunk(const uint8_t *data, size_t data_len) { + mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); + for (int i = 0; i < data_len; ++i) { + ringbuf_put(&o->ringbuf, data[i]); + } +} + +void mp_bluetooth_gattc_on_data_available_end(void) { schedule_ringbuf(); - MICROPY_PY_BLUETOOTH_EXIT } void mp_bluetooth_gattc_on_write_status(uint16_t conn_handle, uint16_t value_handle, uint16_t status) { diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h index bce28a6d15..8a3ab414fd 100644 --- a/extmod/modbluetooth.h +++ b/extmod/modbluetooth.h @@ -47,6 +47,12 @@ #define MICROPY_PY_BLUETOOTH_GATTS_ON_READ_CALLBACK (0) #endif +// This is used to protect the ringbuffer. +#ifndef MICROPY_PY_BLUETOOTH_ENTER +#define MICROPY_PY_BLUETOOTH_ENTER mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); +#define MICROPY_PY_BLUETOOTH_EXIT MICROPY_END_ATOMIC_SECTION(atomic_state); +#endif + // Common constants. #ifndef MP_BLUETOOTH_MAX_ATTR_SIZE #define MP_BLUETOOTH_MAX_ATTR_SIZE (20) @@ -247,7 +253,11 @@ void mp_bluetooth_gattc_on_characteristic_result(uint16_t conn_handle, uint16_t void mp_bluetooth_gattc_on_descriptor_result(uint16_t conn_handle, uint16_t handle, mp_obj_bluetooth_uuid_t *descriptor_uuid); // Notify modbluetooth that a read has completed with data (or notify/indicate data available, use `event` to disambiguate). -void mp_bluetooth_gattc_on_data_available(uint16_t event, uint16_t conn_handle, uint16_t value_handle, const uint8_t *data, size_t data_len); +// Note: these functions are to be called in a group protected by MICROPY_PY_BLUETOOTH_ENTER/EXIT. +// _start returns the number of bytes to submit to the calls to _chunk, followed by a call to _end. +size_t mp_bluetooth_gattc_on_data_available_start(uint16_t event, uint16_t conn_handle, uint16_t value_handle, size_t data_len); +void mp_bluetooth_gattc_on_data_available_chunk(const uint8_t *data, size_t data_len); +void mp_bluetooth_gattc_on_data_available_end(void); // Notify modbluetooth that a write has completed. void mp_bluetooth_gattc_on_write_status(uint16_t conn_handle, uint16_t value_handle, uint16_t status); diff --git a/extmod/modbluetooth_nimble.c b/extmod/modbluetooth_nimble.c index f86ab70bf1..83eb4b88a6 100644 --- a/extmod/modbluetooth_nimble.c +++ b/extmod/modbluetooth_nimble.c @@ -616,6 +616,20 @@ int mp_bluetooth_gatts_set_buffer(uint16_t value_handle, size_t len, bool append #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE +STATIC void gattc_on_data_available(uint16_t event, uint16_t conn_handle, uint16_t value_handle, const struct os_mbuf *om) { + MICROPY_PY_BLUETOOTH_ENTER + size_t len = OS_MBUF_PKTLEN(om); + len = mp_bluetooth_gattc_on_data_available_start(event, conn_handle, value_handle, len); + while (len > 0 && om != NULL) { + size_t n = MIN(om->om_len, len); + mp_bluetooth_gattc_on_data_available_chunk(OS_MBUF_DATA(om, const uint8_t*), n); + len -= n; + om = SLIST_NEXT(om, om_next); + } + mp_bluetooth_gattc_on_data_available_end(); + MICROPY_PY_BLUETOOTH_EXIT +} + STATIC int gap_scan_cb(struct ble_gap_event *event, void *arg) { DEBUG_EVENT_printf("gap_scan_cb: event=%d type=%d\n", event->type, event->type == BLE_GAP_EVENT_DISC ? event->disc.event_type : -1); @@ -674,8 +688,6 @@ int mp_bluetooth_gap_scan_stop(void) { STATIC int peripheral_gap_event_cb(struct ble_gap_event *event, void *arg) { DEBUG_EVENT_printf("peripheral_gap_event_cb: event=%d\n", event->type); struct ble_gap_conn_desc desc; - uint8_t buf[MP_BLUETOOTH_MAX_ATTR_SIZE]; - size_t len; uint8_t addr[6] = {0}; switch (event->type) { @@ -698,15 +710,11 @@ STATIC int peripheral_gap_event_cb(struct ble_gap_event *event, void *arg) { break; - case BLE_GAP_EVENT_NOTIFY_RX: - len = MIN(MP_BLUETOOTH_MAX_ATTR_SIZE, OS_MBUF_PKTLEN(event->notify_rx.om)); - os_mbuf_copydata(event->notify_rx.om, 0, len, buf); - if (event->notify_rx.indication == 0) { - mp_bluetooth_gattc_on_data_available(MP_BLUETOOTH_IRQ_GATTC_NOTIFY, event->notify_rx.conn_handle, event->notify_rx.attr_handle, buf, len); - } else { - mp_bluetooth_gattc_on_data_available(MP_BLUETOOTH_IRQ_GATTC_INDICATE, event->notify_rx.conn_handle, event->notify_rx.attr_handle, buf, len); - } + case BLE_GAP_EVENT_NOTIFY_RX: { + uint16_t ev = event->notify_rx.indication == 0 ? MP_BLUETOOTH_IRQ_GATTC_NOTIFY : MP_BLUETOOTH_IRQ_GATTC_INDICATE; + gattc_on_data_available(ev, event->notify_rx.conn_handle, event->notify_rx.attr_handle, event->notify_rx.om); break; + } case BLE_GAP_EVENT_CONN_UPDATE: // TODO @@ -790,10 +798,7 @@ STATIC int ble_gatt_attr_read_cb(uint16_t conn_handle, const struct ble_gatt_err DEBUG_EVENT_printf("ble_gatt_attr_read_cb: conn_handle=%d status=%d handle=%d\n", conn_handle, error->status, attr ? attr->handle : -1); // TODO: Maybe send NULL if error->status non-zero. if (error->status == 0) { - uint8_t buf[MP_BLUETOOTH_MAX_ATTR_SIZE]; - size_t len = MIN(MP_BLUETOOTH_MAX_ATTR_SIZE, OS_MBUF_PKTLEN(attr->om)); - os_mbuf_copydata(attr->om, 0, len, buf); - mp_bluetooth_gattc_on_data_available(MP_BLUETOOTH_IRQ_GATTC_READ_RESULT, conn_handle, attr->handle, buf, len); + gattc_on_data_available(MP_BLUETOOTH_IRQ_GATTC_READ_RESULT, conn_handle, attr->handle, attr->om); } return 0; } From 82a19cb39f1312a6349c481663905477c878a38d Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 3 Dec 2019 12:32:29 +1100 Subject: [PATCH 1011/1788] mpy-cross: Support armv7em, armv7emsp, armv7emdp architectures. --- mpy-cross/main.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/mpy-cross/main.c b/mpy-cross/main.c index 4a4fccb3b7..e82277220b 100644 --- a/mpy-cross/main.c +++ b/mpy-cross/main.c @@ -109,7 +109,7 @@ STATIC int usage(char **argv) { "-msmall-int-bits=number : set the maximum bits used to encode a small-int\n" "-mno-unicode : don't support unicode in compiled strings\n" "-mcache-lookup-bc : cache map lookups in the bytecode\n" -"-march= : set architecture for native emitter; x86, x64, armv6, armv7m, xtensa, xtensawin\n" +"-march= : set architecture for native emitter; x86, x64, armv6, armv7m, armv7em, armv7emsp, armv7emdp, xtensa, xtensawin\n" "\n" "Implementation specific options:\n", argv[0] ); @@ -285,6 +285,15 @@ MP_NOINLINE int main_(int argc, char **argv) { } else if (strcmp(arch, "armv7m") == 0) { mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_ARMV7M; mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_ARM_THUMB_FP; + } else if (strcmp(arch, "armv7em") == 0) { + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_ARMV7EM; + mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_ARM_THUMB_FP; + } else if (strcmp(arch, "armv7emsp") == 0) { + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_ARMV7EMSP; + mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_ARM_THUMB_FP; + } else if (strcmp(arch, "armv7emdp") == 0) { + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_ARMV7EMDP; + mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_ARM_THUMB_FP; } else if (strcmp(arch, "xtensa") == 0) { mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_XTENSA; mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_XTENSA; From 40cc7ec677e962c47db567479e42c27ed8911ff6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 29 Nov 2019 12:57:07 +1100 Subject: [PATCH 1012/1788] stm32/mpconfigport.h: Use IRQ_PRI_PENDSV to protect bluetooth ringbuf. The default protection for the BLE ringbuf is to use MICROPY_BEGIN_ATOMIC_SECTION, which disables all interrupts. On stm32 it only needs to disable the lowest priority IRQ, pendsv, because that's the IRQ level at which the BLE stack is driven. --- extmod/modbluetooth.c | 1 + ports/stm32/mpconfigport.h | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index 96cd41ae45..2293e03673 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -33,6 +33,7 @@ #include "py/objarray.h" #include "py/qstr.h" #include "py/runtime.h" +#include "py/mphal.h" #include "extmod/modbluetooth.h" #include diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index fc54026f6b..becde2b919 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -366,6 +366,10 @@ static inline mp_uint_t disable_irq(void) { #define MICROPY_PY_LWIP_REENTER irq_state = raise_irq_pri(IRQ_PRI_PENDSV); #define MICROPY_PY_LWIP_EXIT restore_irq_pri(irq_state); +// Bluetooth calls must run at a raised IRQ priority +#define MICROPY_PY_BLUETOOTH_ENTER MICROPY_PY_LWIP_ENTER +#define MICROPY_PY_BLUETOOTH_EXIT MICROPY_PY_LWIP_EXIT + // We need an implementation of the log2 function which is not a macro #define MP_NEED_LOG2 (1) From 90c524c1141ed9ad8fa882dba6f36199a7768e32 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 4 Dec 2019 15:02:54 +1100 Subject: [PATCH 1013/1788] docs: Remove spaces on lines that are empty. --- docs/esp32/quickref.rst | 4 ++-- docs/esp8266/tutorial/network_tcp.rst | 2 +- docs/library/lcd160cr.rst | 2 +- docs/library/machine.RTC.rst | 2 +- docs/library/machine.TimerWiPy.rst | 6 +++--- docs/library/pyb.ADC.rst | 2 +- docs/library/pyb.Accel.rst | 2 +- docs/library/pyb.CAN.rst | 2 +- docs/library/pyb.ExtInt.rst | 2 +- docs/library/pyb.LCD.rst | 8 ++++---- docs/library/pyb.LED.rst | 2 +- docs/library/pyb.RTC.rst | 6 +++--- docs/library/pyb.Timer.rst | 4 ++-- docs/library/pyb.USB_HID.rst | 4 ++-- docs/library/pyb.USB_VCP.rst | 8 ++++---- docs/library/pyb.rst | 12 ++++++------ docs/pyboard/quickref.rst | 2 +- docs/pyboard/tutorial/amp_skin.rst | 2 +- docs/pyboard/tutorial/fading_led.rst | 18 +++++++++--------- docs/pyboard/tutorial/leds.rst | 2 +- docs/pyboard/tutorial/repl.rst | 4 ++-- docs/reference/asm_thumb2_float.rst | 4 ++-- docs/wipy/quickref.rst | 4 ++-- docs/wipy/tutorial/repl.rst | 2 +- 24 files changed, 53 insertions(+), 53 deletions(-) diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst index 20e728d1c7..ef9b0a2e8c 100644 --- a/docs/esp32/quickref.rst +++ b/docs/esp32/quickref.rst @@ -359,10 +359,10 @@ Notes: To further reduce power consumption it is possible to disable the internal pullups:: p1 = Pin(4, Pin.IN, Pin.PULL_HOLD) - + After leaving deepsleep it may be necessary to un-hold the pin explicitly (e.g. if it is an output pin) via:: - + p1 = Pin(4, Pin.OUT, None) OneWire driver diff --git a/docs/esp8266/tutorial/network_tcp.rst b/docs/esp8266/tutorial/network_tcp.rst index 852fc82f39..d479f62e6a 100644 --- a/docs/esp8266/tutorial/network_tcp.rst +++ b/docs/esp8266/tutorial/network_tcp.rst @@ -44,7 +44,7 @@ Now that we are connected we can download and display the data:: ... data = s.recv(500) ... print(str(data, 'utf8'), end='') ... - + When this loop executes it should start showing the animation (use ctrl-C to interrupt it). diff --git a/docs/library/lcd160cr.rst b/docs/library/lcd160cr.rst index bb8e6da22c..e31ed94651 100644 --- a/docs/library/lcd160cr.rst +++ b/docs/library/lcd160cr.rst @@ -340,7 +340,7 @@ Advanced commands .. method:: LCD160CR.set_scroll_win_param(win, param, value) Set a single parameter of a scrolling window region: - + - *win* is the window id, 0..8. - *param* is the parameter number to configure, 0..7, and corresponds to the parameters in the `set_scroll_win` method. diff --git a/docs/library/machine.RTC.rst b/docs/library/machine.RTC.rst index 95fa2b4ce6..548ad007e0 100644 --- a/docs/library/machine.RTC.rst +++ b/docs/library/machine.RTC.rst @@ -27,7 +27,7 @@ Methods .. method:: RTC.init(datetime) Initialise the RTC. Datetime is a tuple of the form: - + ``(year, month, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]])`` .. method:: RTC.now() diff --git a/docs/library/machine.TimerWiPy.rst b/docs/library/machine.TimerWiPy.rst index abbcc28ff7..904a958c69 100644 --- a/docs/library/machine.TimerWiPy.rst +++ b/docs/library/machine.TimerWiPy.rst @@ -47,9 +47,9 @@ Methods tim.init(Timer.ONE_SHOT, width=32) # one shot 32-bit timer Keyword arguments: - + - ``mode`` can be one of: - + - ``TimerWiPy.ONE_SHOT`` - The timer runs once until the configured period of the channel expires. - ``TimerWiPy.PERIODIC`` - The timer runs periodically at the configured @@ -70,7 +70,7 @@ Methods object is returned (or ``None`` if there is no previous channel). Otherwise, a TimerChannel object is initialized and returned. - + The operating mode is is the one configured to the Timer object that was used to create the channel. diff --git a/docs/library/pyb.ADC.rst b/docs/library/pyb.ADC.rst index a95f2d537c..1b16e0c2fc 100644 --- a/docs/library/pyb.ADC.rst +++ b/docs/library/pyb.ADC.rst @@ -19,7 +19,7 @@ Usage:: val = adc.read_core_vref() # read MCU VREF val = adc.read_vref() # read MCU supply voltage - + Constructors ------------ diff --git a/docs/library/pyb.Accel.rst b/docs/library/pyb.Accel.rst index 9ade5c5c81..d5c0ca8634 100644 --- a/docs/library/pyb.Accel.rst +++ b/docs/library/pyb.Accel.rst @@ -19,7 +19,7 @@ Constructors .. class:: pyb.Accel() Create and return an accelerometer object. - + Methods ------- diff --git a/docs/library/pyb.CAN.rst b/docs/library/pyb.CAN.rst index 09b97a187c..ba935abfd5 100644 --- a/docs/library/pyb.CAN.rst +++ b/docs/library/pyb.CAN.rst @@ -92,7 +92,7 @@ Methods 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, diff --git a/docs/library/pyb.ExtInt.rst b/docs/library/pyb.ExtInt.rst index 814217cef0..7741cc51e2 100644 --- a/docs/library/pyb.ExtInt.rst +++ b/docs/library/pyb.ExtInt.rst @@ -54,7 +54,7 @@ Constructors .. class:: pyb.ExtInt(pin, mode, pull, callback) Create an ExtInt object: - + - ``pin`` is the pin on which to enable the interrupt (can be a pin object or any valid pin name). - ``mode`` can be one of: - ``ExtInt.IRQ_RISING`` - trigger on a rising edge; diff --git a/docs/library/pyb.LCD.rst b/docs/library/pyb.LCD.rst index 5ab127edcd..018902ca68 100644 --- a/docs/library/pyb.LCD.rst +++ b/docs/library/pyb.LCD.rst @@ -63,13 +63,13 @@ Methods .. method:: LCD.fill(colour) Fill the screen with the given colour (0 or 1 for white or black). - + This method writes to the hidden buffer. Use ``show()`` to show the buffer. .. method:: LCD.get(x, y) Get the pixel at the position ``(x, y)``. Returns 0 or 1. - + This method reads from the visible buffer. .. method:: LCD.light(value) @@ -79,7 +79,7 @@ Methods .. method:: LCD.pixel(x, y, colour) Set the pixel at ``(x, y)`` to the given colour (0 or 1). - + This method writes to the hidden buffer. Use ``show()`` to show the buffer. .. method:: LCD.show() @@ -89,7 +89,7 @@ Methods .. method:: LCD.text(str, x, y, colour) Draw the given text to the position ``(x, y)`` using the given colour (0 or 1). - + This method writes to the hidden buffer. Use ``show()`` to show the buffer. .. method:: LCD.write(str) diff --git a/docs/library/pyb.LED.rst b/docs/library/pyb.LED.rst index 1ab73a69c9..d3ab965e7e 100644 --- a/docs/library/pyb.LED.rst +++ b/docs/library/pyb.LED.rst @@ -13,7 +13,7 @@ Constructors .. class:: pyb.LED(id) Create an LED object associated with the given LED: - + - ``id`` is the LED number, 1-4. diff --git a/docs/library/pyb.RTC.rst b/docs/library/pyb.RTC.rst index 286268655e..4c736597cf 100644 --- a/docs/library/pyb.RTC.rst +++ b/docs/library/pyb.RTC.rst @@ -28,13 +28,13 @@ Methods .. method:: RTC.datetime([datetimetuple]) Get or set the date and time of the RTC. - + 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 ``subseconds`` is reset to 255). - + The 8-tuple has the following format: - + (year, month, day, weekday, hours, minutes, seconds, subseconds) ``weekday`` is 1-7 for Monday through Sunday. diff --git a/docs/library/pyb.Timer.rst b/docs/library/pyb.Timer.rst index 977ba8890d..bb7e7e52d5 100644 --- a/docs/library/pyb.Timer.rst +++ b/docs/library/pyb.Timer.rst @@ -112,7 +112,7 @@ Methods .. method:: Timer.deinit() Deinitialises the timer. - + Disables the callback (and the associated irq). Disables any channel callbacks (and the associated irq). @@ -191,7 +191,7 @@ Methods - Read the encoder value using the timer.counter() method. - Only works on CH1 and CH2 (and not on CH1N or CH2N) - The channel number is ignored when setting the encoder mode. - + PWM Example:: timer = pyb.Timer(2, freq=1000) diff --git a/docs/library/pyb.USB_HID.rst b/docs/library/pyb.USB_HID.rst index 7027044354..649dc3df4a 100644 --- a/docs/library/pyb.USB_HID.rst +++ b/docs/library/pyb.USB_HID.rst @@ -24,11 +24,11 @@ Methods .. method:: USB_HID.recv(data, \*, timeout=5000) Receive data on the bus: - + - ``data`` can be an integer, which is the number of bytes to receive, or a mutable buffer, which will be filled with received bytes. - ``timeout`` is the timeout in milliseconds to wait for the receive. - + Return value: if ``data`` is an integer then a new buffer of the bytes received, otherwise the number of bytes read into ``data`` is returned. diff --git a/docs/library/pyb.USB_VCP.rst b/docs/library/pyb.USB_VCP.rst index 94ea418485..b16924cf60 100644 --- a/docs/library/pyb.USB_VCP.rst +++ b/docs/library/pyb.USB_VCP.rst @@ -92,21 +92,21 @@ Methods .. method:: USB_VCP.recv(data, \*, timeout=5000) Receive data on the bus: - + - ``data`` can be an integer, which is the number of bytes to receive, or a mutable buffer, which will be filled with received bytes. - ``timeout`` is the timeout in milliseconds to wait for the receive. - + Return value: if ``data`` is an integer then a new buffer of the bytes received, otherwise the number of bytes read into ``data`` is returned. .. method:: USB_VCP.send(data, \*, timeout=5000) Send data over the USB VCP: - + - ``data`` is the data to send (an integer to send, or a buffer object). - ``timeout`` is the timeout in milliseconds to wait for the send. - + Return value: number of bytes sent. diff --git a/docs/library/pyb.rst b/docs/library/pyb.rst index 9ba7e991e5..714207ba15 100644 --- a/docs/library/pyb.rst +++ b/docs/library/pyb.rst @@ -20,7 +20,7 @@ Time related functions .. function:: millis() Returns the number of milliseconds since the board was last reset. - + The result is always a MicroPython smallint (31-bit signed number), so after 2^30 milliseconds (about 12.4 days) this will start to return negative numbers. @@ -32,7 +32,7 @@ Time related functions .. function:: micros() Returns the number of microseconds since the board was last reset. - + The result is always a MicroPython smallint (31-bit signed number), so after 2^30 microseconds (about 17.8 minutes) this will start to return negative numbers. @@ -44,10 +44,10 @@ Time related functions .. 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 up to about 12.4 days. - + Example:: start = pyb.millis() @@ -57,10 +57,10 @@ Time related functions .. 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 up to about 17.8 minutes. - + Example:: start = pyb.micros() diff --git a/docs/pyboard/quickref.rst b/docs/pyboard/quickref.rst index b1195ce7c8..3dbd093043 100644 --- a/docs/pyboard/quickref.rst +++ b/docs/pyboard/quickref.rst @@ -66,7 +66,7 @@ See :ref:`pyb.LED `. :: led.toggle() led.on() led.off() - + # LEDs 3 and 4 support PWM intensity (0-255) LED(4).intensity() # get intensity LED(4).intensity(128) # set intensity to half diff --git a/docs/pyboard/tutorial/amp_skin.rst b/docs/pyboard/tutorial/amp_skin.rst index 697637f9d2..bcb5832613 100644 --- a/docs/pyboard/tutorial/amp_skin.rst +++ b/docs/pyboard/tutorial/amp_skin.rst @@ -60,7 +60,7 @@ on your pyboard (either on the flash or the SD card in the top-level directory). or to convert any file you have with the command:: avconv -i original.wav -ar 22050 -codec pcm_u8 test.wav - + Then you can do:: >>> import wave diff --git a/docs/pyboard/tutorial/fading_led.rst b/docs/pyboard/tutorial/fading_led.rst index 8303c96030..79648bee1a 100644 --- a/docs/pyboard/tutorial/fading_led.rst +++ b/docs/pyboard/tutorial/fading_led.rst @@ -27,10 +27,10 @@ For this tutorial, we will use the ``X1`` pin. Connect one end of the resistor t Code ---- By examining the :ref:`pyboard_quickref`, we see that ``X1`` is connected to channel 1 of timer 5 (``TIM5 CH1``). Therefore we will first create a ``Timer`` object for timer 5, then create a ``TimerChannel`` object for channel 1:: - + from pyb import Timer from time import sleep - + # timer 5 will be created with a frequency of 100 Hz tim = pyb.Timer(5, freq=100) tchannel = tim.channel(1, Timer.PWM, pin=pyb.Pin.board.X1, pulse_width=0) @@ -47,16 +47,16 @@ To achieve the fading effect shown at the beginning of this tutorial, we want to # how much to change the pulse-width by each step wstep = 1500 cur_width = min_width - + while True: tchannel.pulse_width(cur_width) - + # this determines how often we change the pulse-width. It is # analogous to frames-per-second sleep(0.01) - + cur_width += wstep - + if cur_width > max_width: cur_width = min_width @@ -67,11 +67,11 @@ If we want to have a breathing effect, where the LED fades from dim to bright th while True: tchannel.pulse_width(cur_width) - + sleep(0.01) - + cur_width += wstep - + if cur_width > max_width: cur_width = max_width wstep *= -1 diff --git a/docs/pyboard/tutorial/leds.rst b/docs/pyboard/tutorial/leds.rst index 2b76d17cde..05f3b619e3 100644 --- a/docs/pyboard/tutorial/leds.rst +++ b/docs/pyboard/tutorial/leds.rst @@ -17,7 +17,7 @@ This is all very well but we would like this process to be automated. Open the f pyb.delay(1000) When you save, the red light on the pyboard should turn on for about a second. To run the script, do a soft reset (CTRL-D). The pyboard will then restart and you should see a green light continuously flashing on and off. Success, the first step on your path to building an army of evil robots! When you are bored of the annoying flashing light then press CTRL-C at your terminal to stop it running. - + So what does this code do? First we need some terminology. Python is an object-oriented language, almost everything in python is a *class* and when you create an instance of a class you get an *object*. Classes have *methods* associated to them. A method (also called a member function) is used to interact with or control the object. The first line of code creates an LED object which we have then called led. When we create the object, it takes a single parameter which must be between 1 and 4, corresponding to the 4 LEDs on the board. The pyb.LED class has three important member functions that we will use: on(), off() and toggle(). The other function that we use is pyb.delay() this simply waits for a given time in milliseconds. Once we have created the LED object, the statement while True: creates an infinite loop which toggles the led between on and off and waits for 1 second. diff --git a/docs/pyboard/tutorial/repl.rst b/docs/pyboard/tutorial/repl.rst index 3853b15785..973d1846a0 100644 --- a/docs/pyboard/tutorial/repl.rst +++ b/docs/pyboard/tutorial/repl.rst @@ -41,7 +41,7 @@ Mac OS X Open a terminal and run:: screen /dev/tty.usbmodem* - + When you are finished and want to exit screen, type CTRL-A CTRL-\\. Linux @@ -50,7 +50,7 @@ Linux Open a terminal and run:: screen /dev/ttyACM0 - + You can also try ``picocom`` or ``minicom`` instead of screen. You may have to use ``/dev/ttyACM1`` or a higher number for ``ttyACM``. And, you may need to give yourself the correct permissions to access this devices (eg group ``uucp`` or ``dialout``, diff --git a/docs/reference/asm_thumb2_float.rst b/docs/reference/asm_thumb2_float.rst index 4acb734eeb..46560413c9 100644 --- a/docs/reference/asm_thumb2_float.rst +++ b/docs/reference/asm_thumb2_float.rst @@ -31,7 +31,7 @@ Arithmetic * vsqrt(Sd, Sm) ``Sd = sqrt(Sm)`` Registers may be identical: ``vmul(S0, S0, S0)`` will execute ``S0 = S0*S0`` - + Move between ARM core and FPU registers --------------------------------------- @@ -40,7 +40,7 @@ Move between ARM core and FPU registers The FPU has a register known as FPSCR, similar to the ARM core's APSR, which stores condition codes plus other data. The following instructions provide access to this. - + * vmrs(APSR\_nzcv, FPSCR) Move the floating-point N, Z, C, and V flags to the APSR N, Z, C, and V flags. diff --git a/docs/wipy/quickref.rst b/docs/wipy/quickref.rst index 6349676cf7..a22ea45b55 100644 --- a/docs/wipy/quickref.rst +++ b/docs/wipy/quickref.rst @@ -62,7 +62,7 @@ Timer ``id``'s take values from 0 to 3.:: tim = Timer(0, mode=Timer.PERIODIC) tim_a = tim.channel(Timer.A, freq=1000) tim_a.freq(5) # 5 Hz - + p_out = Pin('GP2', mode=Pin.OUT) tim_a.irq(trigger=Timer.TIMEOUT, handler=lambda t: p_out.toggle()) @@ -75,7 +75,7 @@ See :ref:`machine.Pin ` and :ref:`machine.Timer `. : # timer 1 in PWM mode and width must be 16 buts tim = Timer(1, mode=Timer.PWM, width=16) - + # enable channel A @1KHz with a 50.55% duty cycle tim_a = tim.channel(Timer.A, freq=1000, duty_cycle=5055) diff --git a/docs/wipy/tutorial/repl.rst b/docs/wipy/tutorial/repl.rst index 8c60e2c1d1..95b545d097 100644 --- a/docs/wipy/tutorial/repl.rst +++ b/docs/wipy/tutorial/repl.rst @@ -51,7 +51,7 @@ Open a terminal and run:: or:: $ screen /dev/tty.usbmodem* 115200 - + When you are finished and want to exit ``screen``, type CTRL-A CTRL-\\. If your keyboard does not have a \\-key (i.e. you need an obscure combination for \\ like ALT-SHIFT-7) you can remap the ``quit`` command: - create ``~/.screenrc`` From d7dbd267e73bf745e985da9155490b5358cb874a Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Wed, 4 Dec 2019 10:40:16 +1100 Subject: [PATCH 1014/1788] docs/reference: Add docs describing use of pyboard.py. --- docs/reference/index.rst | 1 + docs/reference/pyboard.py.rst | 133 ++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 docs/reference/pyboard.py.rst diff --git a/docs/reference/index.rst b/docs/reference/index.rst index d0c7f69de9..4dd52b9c83 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -26,3 +26,4 @@ implementation and the best practices to use them. constrained.rst packages.rst asm_thumb2_index.rst + pyboard.py.rst diff --git a/docs/reference/pyboard.py.rst b/docs/reference/pyboard.py.rst new file mode 100644 index 0000000000..60d7509afe --- /dev/null +++ b/docs/reference/pyboard.py.rst @@ -0,0 +1,133 @@ +.. _pyboard_py: + +The pyboard.py tool +=================== + +This is a standalone Python tool that runs on your PC that provides a way to: + +* Quickly run a Python script or command on a MicroPython device. This is useful + while developing MicroPython programs to quickly test code without needing to + copy files to/from the device. + +* Access the filesystem on a device. This allows you to deploy your code to the + device (even if the board doesn't support USB MSC). + +Despite the name, ``pyboard.py`` works on all MicroPython ports that support the +raw REPL (including STM32, ESP32, ESP8266, NRF). + +You can download the latest version from `GitHub +`_. The +only dependency is the ``pyserial`` library which can be installed from PiPy or +your system package manager. + +Running ``pyboard.py --help`` gives the following output: + +.. code-block:: text + + usage: pyboard [-h] [--device DEVICE] [-b BAUDRATE] [-u USER] + [-p PASSWORD] [-c COMMAND] [-w WAIT] [--follow] [-f] + [files [files ...]] + + Run scripts on the pyboard. + + positional arguments: + files input files + + optional arguments: + -h, --help show this help message and exit + --device DEVICE the serial device or the IP address of the + pyboard + -b BAUDRATE, --baudrate BAUDRATE + the baud rate of the serial device + -u USER, --user USER the telnet login username + -p PASSWORD, --password PASSWORD + the telnet login password + -c COMMAND, --command COMMAND + program passed in as string + -w WAIT, --wait WAIT seconds to wait for USB connected board to become + available + --follow follow the output after running the scripts + [default if no scripts given] + -f, --filesystem perform a filesystem action + +Running a command on the device +------------------------------- + +This is useful for testing short snippets of code, or to script an interaction +with the device.:: + + $ pyboard.py --device /dev/ttyACM0 -c 'print(1+1)' + 2 + +Running a script on the device +------------------------------ + +If you have a script, ``app.py`` that you want to run on a device, then use:: + + $ pyboard.py --device /dev/ttyACM0 app.py + +Note that this doesn't actually copy app.py to the device's filesystem, it just +loads the code into RAM and executes it. Any output generated by the program +will be displayed. + +If the program app.py does not finish then you'll need to stop ``pyboard.py``, +eg with Ctrl-C. The program ``app.py`` will still continue to run on the +MicroPython device. + +Filesystem access +----------------- + +Using the ``-f`` flag, the following filesystem operations are supported: + +* ``cp src [src...] dest`` Copy files to/from the device. +* ``cat path`` Print the contents of a file on the device. +* ``ls [path]`` List contents of a directory (defaults to current working directory). +* ``rm path`` Remove a file. +* ``mkdir path`` Create a directory. +* ``rmdir path`` Remove a directory. + +The ``cp`` command uses a ``ssh``-like convention for referring to local and +remote files. Any path starting with a ``:`` will be interpreted as on the +device, otherwise it will be local. So:: + + $ pyboard.py --device /dev/ttyACM0 -f cp main.py :main.py + +will copy main.py from the current directory on the PC to a file named main.py +on the device. The filename can be omitted, e.g.:: + + $ pyboard.py --device /dev/ttyACM0 -f cp main.py : + +is equivalent to the above. + +Some more examples:: + + # Copy main.py from the device to the local PC. + $ pyboard.py --device /dev/ttyACM0 -f cp :main.py main.py + # Same, but using . instead. + $ pyboard.py --device /dev/ttyACM0 -f cp :main.py . + + # Copy three files to the device, keeping their names + # and paths (note: `lib` must exist on the device) + $ pyboard.py --device /dev/ttyACM0 -f cp main.py app.py lib/foo.py : + + # Remove a file from the device. + $ pyboard.py --device /dev/ttyACM0 -f rm util.py + + # Print the contents of a file on the device. + $ pyboard.py --device /dev/ttyACM0 -f cat boot.py + ...contents of boot.py... + +Using the pyboard library +------------------------- + +You can also use ``pyboard.py`` as a library for scripting interactions with a +MicroPython board. + +.. code-block:: python + + import pyboard + pyb = pyboard.Pyboard('/dev/ttyACM0', 115200) + pyb.enter_raw_repl() + ret = pyb.exec('print(1+1)') + print(ret) + pyb.exit_raw_repl() From f2650be844d73b09b990ec2c0328e0262bb99442 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Wed, 4 Dec 2019 13:50:51 +1100 Subject: [PATCH 1015/1788] docs/library: Add docs for pyb.Flash class. --- docs/library/pyb.Flash.rst | 52 ++++++++++++++++++++++++++++++++++++++ docs/library/pyb.rst | 1 + 2 files changed, 53 insertions(+) create mode 100644 docs/library/pyb.Flash.rst diff --git a/docs/library/pyb.Flash.rst b/docs/library/pyb.Flash.rst new file mode 100644 index 0000000000..2d2f83da1c --- /dev/null +++ b/docs/library/pyb.Flash.rst @@ -0,0 +1,52 @@ +.. currentmodule:: pyb +.. _pyb.Flash: + +class Flash -- access to built-in flash storage +=============================================== + +The Flash class allows direct access to the primary flash device on the pyboard. + +In most cases, to store persistent data on the device, you'll want to use a +higher-level abstraction, for example the filesystem via Python's standard file +API, but this interface is useful to :ref:`customise the filesystem +configuration ` or implement a low-level storage system for your +application. + +Constructors +------------ + +.. class:: pyb.Flash() + + Create and return a block device that represents the flash device presented + to the USB mass storage interface. + + It includes a virtual partition table at the start, and the actual flash + starts at block ``0x100``. + + This constructor is deprecated and will be removed in a future version of MicroPython. + +.. class:: pyb.Flash(\*, start=-1, len=-1) + + Create and return a block device that accesses the flash at the specified offset. The length defaults to the remaining size of the device. + + The *start* and *len* offsets are in bytes, and must be a multiple of the block size (typically 512 for internal flash). + +Methods +------- + +.. method:: Flash.readblocks(block_num, buf) +.. method:: Flash.readblocks(block_num, buf, offset) +.. method:: Flash.writeblocks(block_num, buf) +.. method:: Flash.writeblocks(block_num, buf, offset) +.. method:: Flash.ioctl(cmd, arg) + + These methods implement the simple and :ref:`extended + ` block protocol defined by + :class:`uos.AbstractBlockDev`. + +Hardware Note +------------- + +On boards with external spiflash (e.g. Pyboard D), the MicroPython firmware will +be configured to use that as the primary flash storage. On all other boards, the +internal flash inside the :term:`MCU` will be used. diff --git a/docs/library/pyb.rst b/docs/library/pyb.rst index 714207ba15..34103195dd 100644 --- a/docs/library/pyb.rst +++ b/docs/library/pyb.rst @@ -309,6 +309,7 @@ Classes pyb.CAN.rst pyb.DAC.rst pyb.ExtInt.rst + pyb.Flash.rst pyb.I2C.rst pyb.LCD.rst pyb.LED.rst From 9a849cc7caee63560ecd2455a29615a44e2c809f Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Wed, 4 Dec 2019 10:42:07 +1100 Subject: [PATCH 1016/1788] docs: Add littlefs docs and a filesystem tutorial. --- docs/library/esp32.rst | 6 +- docs/library/uos.rst | 100 +++++------- docs/reference/filesystem.rst | 278 ++++++++++++++++++++++++++++++++++ docs/reference/index.rst | 1 + 4 files changed, 322 insertions(+), 63 deletions(-) create mode 100644 docs/reference/filesystem.rst diff --git a/docs/library/esp32.rst b/docs/library/esp32.rst index a593965ae2..68379624e6 100644 --- a/docs/library/esp32.rst +++ b/docs/library/esp32.rst @@ -56,10 +56,14 @@ This class gives access to the partitions in the device's flash memory. Returns a 6-tuple ``(type, subtype, addr, size, label, encrypted)``. .. method:: Partition.readblocks(block_num, buf) +.. method:: Partition.readblocks(block_num, buf, offset) .. method:: Partition.writeblocks(block_num, buf) +.. method:: Partition.writeblocks(block_num, buf, offset) .. method:: Partition.ioctl(cmd, arg) - These methods implement the block protocol defined by :class:`uos.AbstractBlockDev`. + These methods implement the simple and :ref:`extended + ` block protocol defined by + :class:`uos.AbstractBlockDev`. .. method:: Partition.set_boot() diff --git a/docs/library/uos.rst b/docs/library/uos.rst index d8d8b7a972..84d341ac21 100644 --- a/docs/library/uos.rst +++ b/docs/library/uos.rst @@ -178,6 +178,35 @@ represented by VFS classes. Build a FAT filesystem on *block_dev*. +.. class:: VfsLfs1(block_dev) + + Create a filesystem object that uses the `littlefs v1 filesystem format`_. + Storage of the littlefs filesystem is provided by *block_dev*, which must + support the :ref:`extended interface `. + Objects created by this constructor can be mounted using :func:`mount`. + + See :ref:`filesystem` for more information. + + .. staticmethod:: mkfs(block_dev) + + Build a Lfs1 filesystem on *block_dev*. + +.. class:: VfsLfs2(block_dev) + + Create a filesystem object that uses the `littlefs v2 filesystem format`_. + Storage of the littlefs filesystem is provided by *block_dev*, which must + support the :ref:`extended interface `. + Objects created by this constructor can be mounted using :func:`mount`. + + See :ref:`filesystem` for more information. + + .. staticmethod:: mkfs(block_dev) + + Build a Lfs2 filesystem on *block_dev*. + +.. _littlefs v1 filesystem format: https://github.com/ARMmbed/littlefs/tree/v1 +.. _littlefs v2 filesystem format: https://github.com/ARMmbed/littlefs + Block devices ------------- @@ -187,9 +216,15 @@ 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. +.. _block-device-interface: + +Simple and extended interface +............................. + There are two compatible signatures for the ``readblocks`` and ``writeblocks`` methods (see below), in order to support a variety of use cases. A given block -device may implement one form or the other, or both at the same time. +device may implement one form or the other, or both at the same time. The second +form (with the offset parameter) is referred to as the "extended interface". .. class:: AbstractBlockDev(...) @@ -247,64 +282,5 @@ device may implement one form or the other, or both at the same time. (*arg* is unused) - 6 -- erase a block, *arg* is the block number to erase -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') - -An example of a block device that supports both signatures and behaviours of -the :meth:`readblocks` and :meth:`writeblocks` methods is:: - - 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, buf, offset=0): - addr = block_num * self.block_size + offset - for i in range(len(buf)): - buf[i] = self.data[addr + i] - - def writeblocks(self, block_num, buf, offset=None): - if offset is None: - # do erase, then write - for i in range(len(buf) // self.block_size): - self.ioctl(6, block_num + i) - offset = 0 - addr = block_num * self.block_size + offset - for i in range(len(buf)): - self.data[addr + i] = buf[i] - - def ioctl(self, op, arg): - if op == 4: # block count - return len(self.data) // self.block_size - if op == 5: # block size - return self.block_size - if op == 6: # block erase - return 0 +See :ref:`filesystem` for example implementations of block devices using both +protocols. diff --git a/docs/reference/filesystem.rst b/docs/reference/filesystem.rst new file mode 100644 index 0000000000..71d34e7954 --- /dev/null +++ b/docs/reference/filesystem.rst @@ -0,0 +1,278 @@ +.. _filesystem: + +Working with filesystems +======================== + +.. contents:: + +This tutorial describes how MicroPython provides an on-device filesystem, +allowing standard Python file I/O methods to be used with persistent storage. + +MicroPython automatically creates a default configuration and auto-detects the +primary filesystem, so this tutorial will be mostly useful if you want to modify +the partitioning, filesystem type, or use custom block devices. + +The filesystem is typically backed by internal flash memory on the device, but +can also use external flash, RAM, or a custom block device. + +On some ports (e.g. STM32), the filesystem may also be available over USB MSC to +a host PC. :ref:`pyboard_py` also provides a way for the host PC to access to +the filesystem on all ports. + +Note: This is mainly for use on bare-metal ports like STM32 and ESP32. On ports +with an operating system (e.g. the Unix port) the filesystem is provided by the +host OS. + +VFS +--- + +MicroPython implements a Unix-like Virtual File System (VFS) layer. All mounted +filesystems are combined into a single virtual filesystem, starting at the root +``/``. Filesystems are mounted into directories in this structure, and at +startup the working directory is changed to where the primary filesystem is +mounted. + +On STM32 / Pyboard, the internal flash is mounted at ``/flash``, and optionally +the SDCard at ``/sd``. On ESP8266/ESP32, the primary filesystem is mounted at +``/``. + +Block devices +------------- + +A block device is an instance of a class that implements the +:class:`uos.AbstractBlockDev` protocol. + +Built-in block devices +~~~~~~~~~~~~~~~~~~~~~~ + +Ports provide built-in block devices to access their primary flash. + +On power-on, MicroPython will attempt to detect the filesystem on the default +flash and configure and mount it automatically. If no filesystem is found, +MicroPython will attempt to create a FAT filesystem spanning the entire flash. +Ports can also provide a mechanism to "factory reset" the primary flash, usually +by some combination of button presses at power on. + +STM32 / Pyboard +............... + +The :ref:`pyb.Flash ` class provides access to the internal flash. On some +boards which have larger external flash (e.g. Pyboard D), it will use that +instead. The ``start`` kwarg should always be specified, i.e. +``pyb.Flash(start=0)``. + +Note: For backwards compatibility, when constructed with no arguments (i.e. +``pyb.Flash()``), it only implements the simple block interface and reflects the +virtual device presented to USB MSC (i.e. it includes a virtual partition table +at the start). + +ESP8266 +....... + +The internal flash is exposed as a block device object which is created in the +``flashbdev`` module on start up. This object is by default added as a global +variable so it can usually be accessed simply as ``bdev``. This implements the +extended interface. + +ESP32 +..... + +The :class:`esp32.Partition` class implements a block device for partitions +defined for the board. Like ESP8266, there is a global variable ``bdev`` which +points to the default partition. This implements the extended interface. + +Custom block devices +~~~~~~~~~~~~~~~~~~~~ + +The following class implements a simple 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 os + + bdev = RAMBlockDev(512, 50) + os.VfsFat.mkfs(bdev) + os.mount(bdev, '/ramdisk') + +An example of a block device that supports both the simple and extended +interface (i.e. both signatures and behaviours of the +:meth:`uos.AbstractBlockDev.readblocks` and +:meth:`uos.AbstractBlockDev.writeblocks` methods) is:: + + 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, buf, offset=0): + addr = block_num * self.block_size + offset + for i in range(len(buf)): + buf[i] = self.data[addr + i] + + def writeblocks(self, block_num, buf, offset=None): + if offset is None: + # do erase, then write + for i in range(len(buf) // self.block_size): + self.ioctl(6, block_num + i) + offset = 0 + addr = block_num * self.block_size + offset + for i in range(len(buf)): + self.data[addr + i] = buf[i] + + def ioctl(self, op, arg): + if op == 4: # block count + return len(self.data) // self.block_size + if op == 5: # block size + return self.block_size + if op == 6: # block erase + return 0 + +As it supports the extended interface, it can be used with :class:`littlefs +`:: + + import os + + bdev = RAMBlockDev(512, 50) + os.VfsLfs2.mkfs(bdev) + os.mount(bdev, '/ramdisk') + +Filesystems +----------- + +MicroPython ports can provide implementations of :class:`FAT `, +:class:`littlefs v1 ` and :class:`littlefs v2 `. + +The following table shows which filesystems are included in the firmware by +default for given port/board combinations, however they can be optionally +enabled in a custom firmware build. + +==================== ===== =========== =========== +Board FAT littlefs v1 littlefs v2 +==================== ===== =========== =========== +pyboard 1.0, 1.1, D Yes No Yes +Other STM32 Yes No No +ESP8266 Yes No No +ESP32 Yes No Yes +==================== ===== =========== =========== + +FAT +~~~ + +The main advantage of the FAT filesystem is that it can be accessed over USB MSC +on supported boards (e.g. STM32) without any additional drivers required on the +host PC. + +However, FAT is not tolerant to power failure during writes and this can lead to +filesystem corruption. For applications that do not require USB MSC, it is +recommended to use littlefs instead. + +To format the entire flash using FAT:: + + # ESP8266 and ESP32 + import os + os.umount('/') + os.VfsFat.mkfs(bdev) + os.mount(bdev, '/') + + # STM32 + import os, pyb + os.umount('/flash') + os.VfsFat.mkfs(pyb.Flash(start=0)) + os.mount(pyb.Flash(start=0), '/flash') + os.chdir('/flash') + +Littlefs +~~~~~~~~ + +Littlefs_ is a filesystem designed for flash-based devices, and is much more +resistant to filesystem corruption. + +Note: It can be still be accessed over USB MSC using the `littlefs FUSE +driver`_. Note that you must use the ``-b=4096`` option to override the block +size. + +.. _littlefs FUSE driver: https://github.com/ARMmbed/littlefs-fuse/tree/master/littlefs + +.. _Littlefs: https://github.com/ARMmbed/littlefs + +To format the entire flash using littlefs v2:: + + # ESP8266 and ESP32 + import os + os.umount('/') + os.VfsLfs2.mkfs(bdev) + os.mount(bdev, '/') + + # STM32 + import os, pyb + os.umount('/flash') + os.VfsLfs2.mkfs(pyb.Flash(start=0)) + os.mount(pyb.Flash(start=0), '/flash') + os.chdir('/flash') + +Hybrid (STM32) +~~~~~~~~~~~~~~ + +By using the ``start`` and ``len`` kwargs to :class:`pyb.Flash`, you can create +block devices spanning a subset of the flash device. + +For example, to configure the first 256kiB as FAT (and available over USB MSC), +and the remainder as littlefs:: + + import os, pyb + os.umount('/flash') + p1 = pyb.Flash(start=0, len=256*1024) + p2 = pyb.Flash(start=256*1024) + os.VfsFat.mkfs(p1) + os.VfsLfs2.mkfs(p2) + os.mount(p1, '/flash') + os.mount(p2, '/data') + os.chdir('/flash') + +This might be useful to make your Python files, configuration and other +rarely-modified content available over USB MSC, but allowing for frequently +changing application data to reside on littlefs with better resilience to power +failure, etc. + +The partition at offset ``0`` will be mounted automatically (and the filesystem +type automatically detected), but you can add:: + + import os, pyb + p2 = pyb.Flash(start=256*1024) + os.mount(p2, '/data') + +to ``boot.py`` to mount the data partition. + +Hybrid (ESP32) +~~~~~~~~~~~~~~ + +On ESP32, if you build custom firmware, you can modify ``partitions.csv`` to +define an arbitrary partition layout. + +At boot, the partition named "vfs" will be mounted at ``/`` by default, but any +additional partitions can be mounted in your ``boot.py`` using:: + + import esp32, os + p = esp32.Partition.find(esp32.Partition.TYPE_DATA, label='foo') + os.mount(p, '/foo') + diff --git a/docs/reference/index.rst b/docs/reference/index.rst index 4dd52b9c83..1eaaa85c85 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -26,4 +26,5 @@ implementation and the best practices to use them. constrained.rst packages.rst asm_thumb2_index.rst + filesystem.rst pyboard.py.rst From 7aeafe2ae9f16af74d22604b3090641a664b2da2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 29 Nov 2019 12:48:38 +1100 Subject: [PATCH 1017/1788] extmod/modbluetooth: Add optional 4th arg to gattc_write for write mode. This allows the user to explicitly select the behaviour of the write to the remote peripheral. This is needed for peripherals that have characteristics with WRITE_NO_RESPONSE set (instead of normal WRITE). The function's signature is now: BLE.gattc_write(conn_handle, value_handle, data, mode=0) mode=0 means write without response, while mode=1 means write with response. The latter was the original behaviour so this commit is a change in behaviour of this method, and one should specify 1 as the 4th argument to get back the old behaviour. In the future there could be more modes supported, such as long writes. --- docs/library/ubluetooth.rst | 15 +++++++++++++-- extmod/modbluetooth.c | 8 ++++++-- extmod/modbluetooth.h | 6 +++++- extmod/modbluetooth_nimble.c | 11 +++++++++-- 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/docs/library/ubluetooth.rst b/docs/library/ubluetooth.rst index 2d3af1bb6b..fd4c012d29 100644 --- a/docs/library/ubluetooth.rst +++ b/docs/library/ubluetooth.rst @@ -310,12 +310,23 @@ Central Role (GATT Client) On success, the ``_IRQ_GATTC_READ_RESULT`` event will be raised. -.. method:: BLE.gattc_write(conn_handle, value_handle, data) +.. method:: BLE.gattc_write(conn_handle, value_handle, data, mode=0) Issue a remote write to a connected peripheral for the specified characteristic or descriptor handle. - On success, the ``_IRQ_GATTC_WRITE_STATUS`` event will be raised. + The argument *mode* specifies the write behaviour, with the currently + supported values being: + + * ``mode=0`` (default) is a write-without-response: the write will + be sent to the remote peripheral but no confirmation will be + returned, and no event will be raised. + * ``mode=1`` is a write-with-response: the remote peripheral is + requested to send a response/acknowledgement that it received the + data. + + If a response is received from the remote peripheral the + ``_IRQ_GATTC_WRITE_STATUS`` event will be raised. class UUID diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index 2293e03673..74f73c1f2b 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -641,9 +641,13 @@ STATIC mp_obj_t bluetooth_ble_gattc_write(size_t n_args, const mp_obj_t *args) { mp_buffer_info_t bufinfo = {0}; mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ); size_t len = bufinfo.len; - return bluetooth_handle_errno(mp_bluetooth_gattc_write(conn_handle, value_handle, bufinfo.buf, &len)); + unsigned int mode = MP_BLUETOOTH_WRITE_MODE_NO_RESPONSE; + if (n_args == 5) { + mode = mp_obj_get_int(args[4]); + } + return bluetooth_handle_errno(mp_bluetooth_gattc_write(conn_handle, value_handle, bufinfo.buf, &len, mode)); } -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gattc_write_obj, 4, 4, bluetooth_ble_gattc_write); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gattc_write_obj, 4, 5, bluetooth_ble_gattc_write); #endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h index 8a3ab414fd..fbae67bc45 100644 --- a/extmod/modbluetooth.h +++ b/extmod/modbluetooth.h @@ -65,6 +65,10 @@ #define MP_BLUETOOTH_CHARACTERISTIC_FLAG_WRITE (1 << 3) #define MP_BLUETOOTH_CHARACTERISTIC_FLAG_NOTIFY (1 << 4) +// For mp_bluetooth_gattc_write, the mode parameter +#define MP_BLUETOOTH_WRITE_MODE_NO_RESPONSE (0) +#define MP_BLUETOOTH_WRITE_MODE_WITH_RESPONSE (1) + // Type value also doubles as length. #define MP_BLUETOOTH_UUID_TYPE_16 (2) #define MP_BLUETOOTH_UUID_TYPE_32 (4) @@ -219,7 +223,7 @@ int mp_bluetooth_gattc_discover_descriptors(uint16_t conn_handle, uint16_t start int mp_bluetooth_gattc_read(uint16_t conn_handle, uint16_t value_handle); // Write the value to the remote peripheral. -int mp_bluetooth_gattc_write(uint16_t conn_handle, uint16_t value_handle, const uint8_t *value, size_t *value_len); +int mp_bluetooth_gattc_write(uint16_t conn_handle, uint16_t value_handle, const uint8_t *value, size_t *value_len, unsigned int mode); #endif ///////////////////////////////////////////////////////////////////////////// diff --git a/extmod/modbluetooth_nimble.c b/extmod/modbluetooth_nimble.c index 83eb4b88a6..930dd06d11 100644 --- a/extmod/modbluetooth_nimble.c +++ b/extmod/modbluetooth_nimble.c @@ -816,8 +816,15 @@ STATIC int ble_gatt_attr_write_cb(uint16_t conn_handle, const struct ble_gatt_er } // Write the value to the remote peripheral. -int mp_bluetooth_gattc_write(uint16_t conn_handle, uint16_t value_handle, const uint8_t *value, size_t *value_len) { - int err = ble_gattc_write_flat(conn_handle, value_handle, value, *value_len, &ble_gatt_attr_write_cb, NULL); +int mp_bluetooth_gattc_write(uint16_t conn_handle, uint16_t value_handle, const uint8_t *value, size_t *value_len, unsigned int mode) { + int err; + if (mode == MP_BLUETOOTH_WRITE_MODE_NO_RESPONSE) { + err = ble_gattc_write_no_rsp_flat(conn_handle, value_handle, value, *value_len); + } else if (mode == MP_BLUETOOTH_WRITE_MODE_WITH_RESPONSE) { + err = ble_gattc_write_flat(conn_handle, value_handle, value, *value_len, &ble_gatt_attr_write_cb, NULL); + } else { + err = BLE_HS_EINVAL; + } return ble_hs_err_to_errno(err); } From 84958a8fe14781d5f678f2d6310cbd324779f50c Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 29 Nov 2019 15:26:57 +1100 Subject: [PATCH 1018/1788] extmod/modbluetooth: Allow setting ringbuf size via BLE.config(rxbuf=). The size of the event ringbuf was previously fixed to compile-time config value, but it's necessary to sometimes increase this for applications that have large characteristic buffers to read, or many events at once. With this commit the size can be set via BLE.config(rxbuf=512), for example. This also resizes the internal event data buffer which sets the maximum size of incoming data passed to the event handler. --- docs/library/ubluetooth.rst | 17 ++++++- extmod/modbluetooth.c | 96 +++++++++++++++++++++++++++++++------ 2 files changed, 96 insertions(+), 17 deletions(-) diff --git a/docs/library/ubluetooth.rst b/docs/library/ubluetooth.rst index fd4c012d29..ddcd28d9e6 100644 --- a/docs/library/ubluetooth.rst +++ b/docs/library/ubluetooth.rst @@ -32,14 +32,27 @@ Configuration The radio must be made active before using any other methods on this class. -.. method:: BLE.config(name) +.. method:: BLE.config('param') + BLE.config(param=value, ...) - Queries a configuration value by *name*. Currently supported values are: + Get or set configuration values of the BLE interface. To get a value the + parameter name should be quoted as a string, and just one parameter is + queried at a time. To set values use the keyword syntax, and one ore more + parameter can be set at a time. + + Currently supported values are: - ``'mac'``: Returns the device MAC address. If a device has a fixed address (e.g. PYBD) then it will be returned. Otherwise (e.g. ESP32) a random address will be generated when the BLE interface is made active. + - ``'rxbuf'``: Set the size in bytes of the internal buffer used to store + incoming events. This buffer is global to the entire BLE driver and so + handles incoming data for all events, including all characteristics. + Increasing this allows better handling of bursty incoming data (for + example scan results) and the ability for a central role to receive + larger characteristic values. + Event Handling -------------- diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index 74f73c1f2b..756d3d6d1c 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -46,7 +46,10 @@ #define MP_BLUETOOTH_CONNECT_DEFAULT_SCAN_DURATION_MS 2000 #define MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_TUPLE_LEN 5 -#define MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN (MICROPY_PY_BLUETOOTH_RINGBUF_SIZE / 2) + +// This formula is intended to allow queuing the data of a large characteristic +// while still leaving room for a couple of normal (small, fixed size) events. +#define MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN(ringbuf_size) (MAX((int)((ringbuf_size) / 2), (int)(ringbuf_size) - 64)) STATIC const mp_obj_type_t bluetooth_ble_type; STATIC const mp_obj_type_t bluetooth_uuid_type; @@ -58,7 +61,8 @@ typedef struct { bool irq_scheduled; mp_obj_t irq_data_tuple; uint8_t irq_data_addr_bytes[6]; - uint8_t irq_data_data_bytes[MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN]; + uint16_t irq_data_data_alloc; + uint8_t *irq_data_data_bytes; mp_obj_str_t irq_data_addr; mp_obj_str_t irq_data_data; mp_obj_bluetooth_uuid_t irq_data_uuid; @@ -244,11 +248,12 @@ STATIC mp_obj_t bluetooth_ble_make_new(const mp_obj_type_t *type, size_t n_args, // Pre-allocated buffers for address, payload and uuid. o->irq_data_addr.base.type = &mp_type_bytes; o->irq_data_addr.data = o->irq_data_addr_bytes; + o->irq_data_data_alloc = MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN(MICROPY_PY_BLUETOOTH_RINGBUF_SIZE); o->irq_data_data.base.type = &mp_type_bytes; - o->irq_data_data.data = o->irq_data_data_bytes; + o->irq_data_data.data = m_new(uint8_t, o->irq_data_data_alloc); o->irq_data_uuid.base.type = &bluetooth_uuid_type; - // Allocate the ringbuf. TODO: Consider making the size user-specified. + // Allocate the default ringbuf. ringbuf_alloc(&o->ringbuf, MICROPY_PY_BLUETOOTH_RINGBUF_SIZE); MP_STATE_VM(bluetooth) = MP_OBJ_FROM_PTR(o); @@ -273,16 +278,77 @@ STATIC mp_obj_t bluetooth_ble_active(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_active_obj, 1, 2, bluetooth_ble_active); -STATIC mp_obj_t bluetooth_ble_config(mp_obj_t self_in, mp_obj_t param) { - if (param == MP_OBJ_NEW_QSTR(MP_QSTR_mac)) { - uint8_t addr[6]; - mp_bluetooth_get_device_addr(addr); - return mp_obj_new_bytes(addr, MP_ARRAY_SIZE(addr)); +STATIC mp_obj_t bluetooth_ble_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + mp_obj_bluetooth_ble_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 addr[6]; + mp_bluetooth_get_device_addr(addr); + return mp_obj_new_bytes(addr, MP_ARRAY_SIZE(addr)); + } + default: + mp_raise_ValueError("unknown config param"); + } } else { - mp_raise_ValueError("unknown config param"); + // Set config value(s) + if (n_args != 1) { + mp_raise_TypeError("can't specify pos and kw args"); + } + + for (size_t i = 0; i < kwargs->alloc; ++i) { + if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) { + mp_map_elem_t *e = &kwargs->table[i]; + switch (mp_obj_str_get_qstr(e->key)) { + case MP_QSTR_rxbuf: { + // Determine new buffer sizes + mp_int_t ringbuf_alloc = mp_obj_get_int(e->value); + if (ringbuf_alloc < 16 || ringbuf_alloc > 0xffff) { + mp_raise_ValueError(NULL); + } + size_t irq_data_alloc = MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN(ringbuf_alloc); + + // Allocate new buffers + uint8_t *ringbuf = m_new(uint8_t, ringbuf_alloc); + uint8_t *irq_data = m_new(uint8_t, irq_data_alloc); + + // Get old buffer sizes and pointers + uint8_t *old_ringbuf_buf = self->ringbuf.buf; + size_t old_ringbuf_alloc = self->ringbuf.size; + uint8_t *old_irq_data_buf = (uint8_t*)self->irq_data_data.data; + size_t old_irq_data_alloc = self->irq_data_data_alloc; + + // Atomically update the ringbuf and irq data + MICROPY_PY_BLUETOOTH_ENTER + self->ringbuf.size = ringbuf_alloc; + self->ringbuf.buf = ringbuf; + self->ringbuf.iget = 0; + self->ringbuf.iput = 0; + self->irq_data_data_alloc = irq_data_alloc; + self->irq_data_data.data = irq_data; + MICROPY_PY_BLUETOOTH_EXIT + + // Free old buffers + m_del(uint8_t, old_ringbuf_buf, old_ringbuf_alloc); + m_del(uint8_t, old_irq_data_buf, old_irq_data_alloc); + break; + } + default: + mp_raise_ValueError("unknown config param"); + } + } + } + + return mp_const_none; } } -STATIC MP_DEFINE_CONST_FUN_OBJ_2(bluetooth_ble_config_obj, bluetooth_ble_config); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bluetooth_ble_config_obj, 1, bluetooth_ble_config); STATIC mp_obj_t bluetooth_ble_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_handler, ARG_trigger }; @@ -741,8 +807,8 @@ STATIC void ringbuf_extract(ringbuf_t* ringbuf, mp_obj_tuple_t *data_tuple, size data_tuple->items[j++] = MP_OBJ_FROM_PTR(uuid); } // The code that enqueues into the ringbuf should ensure that it doesn't - // put more than MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN bytes into - // the ringbuf. + // put more than bt->irq_data_data_alloc bytes into the ringbuf, because + // that's what's available here in bt->irq_data_bytes. if (bytes_data) { bytes_data->len = ringbuf_get(ringbuf); for (int i = 0; i < bytes_data->len; ++i) { @@ -903,7 +969,7 @@ void mp_bluetooth_gap_on_scan_complete(void) { void mp_bluetooth_gap_on_scan_result(uint8_t addr_type, const uint8_t *addr, bool connectable, const int8_t rssi, const uint8_t *data, size_t data_len) { MICROPY_PY_BLUETOOTH_ENTER mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); - data_len = MIN(MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN, data_len); + data_len = MIN(o->irq_data_data_alloc, data_len); if (enqueue_irq(o, 1 + 6 + 1 + 1 + 1 + data_len, MP_BLUETOOTH_IRQ_SCAN_RESULT)) { ringbuf_put(&o->ringbuf, addr_type); for (int i = 0; i < 6; ++i) { @@ -962,7 +1028,7 @@ void mp_bluetooth_gattc_on_descriptor_result(uint16_t conn_handle, uint16_t hand size_t mp_bluetooth_gattc_on_data_available_start(uint16_t event, uint16_t conn_handle, uint16_t value_handle, size_t data_len) { mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); - data_len = MIN(MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN, data_len); + data_len = MIN(o->irq_data_data_alloc, data_len); if (enqueue_irq(o, 2 + 2 + 1 + data_len, event)) { ringbuf_put16(&o->ringbuf, conn_handle); ringbuf_put16(&o->ringbuf, value_handle); From 9ca8a503ed3d7b31fc1cfe0e2e51925d3c0c3396 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Wed, 4 Dec 2019 22:44:49 +1100 Subject: [PATCH 1019/1788] esp32/boards: Enable ULP in base sdk configuration. Fixes issue #5159. --- ports/esp32/boards/sdkconfig.base | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/esp32/boards/sdkconfig.base b/ports/esp32/boards/sdkconfig.base index 2c77c20907..dcb7742d3d 100644 --- a/ports/esp32/boards/sdkconfig.base +++ b/ports/esp32/boards/sdkconfig.base @@ -32,6 +32,9 @@ CONFIG_LWIP_PPP_CHAP_SUPPORT=y # Use 4kiB output buffer instead of default 16kiB (because IDF heap is fragmented in 4.0) CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y +# ULP coprocessor support +CONFIG_ESP32_ULP_COPROC_ENABLED=y + # v3.3-only (renamed in 4.0) CONFIG_LOG_BOOTLOADER_LEVEL_WARN=y CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=n @@ -41,3 +44,4 @@ CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK=y CONFIG_PPP_SUPPORT=y CONFIG_PPP_PAP_SUPPORT=y CONFIG_PPP_CHAP_SUPPORT=y +CONFIG_ULP_COPROC_ENABLED=y From d61e7a6d8a146f0dd528ebc398c576d69a78f41c Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Thu, 5 Dec 2019 00:46:24 +1100 Subject: [PATCH 1020/1788] stm32/uart: Add support for UART4/5 on L0 MCUs. --- ports/stm32/mpconfigboard_common.h | 2 +- ports/stm32/stm32_it.c | 9 +++++++++ ports/stm32/uart.c | 8 ++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index e0c77719e3..ce5c715ac5 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -196,7 +196,7 @@ #define PYB_EXTI_NUM_VECTORS (30) // TODO (22 configurable, 7 direct) #define MICROPY_HW_MAX_I2C (3) #define MICROPY_HW_MAX_TIMER (22) -#define MICROPY_HW_MAX_UART (4) +#define MICROPY_HW_MAX_UART (5) // Configuration for STM32L4 series #elif defined(STM32L4) diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index 3a4709d9fc..e12cf4bf29 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -731,6 +731,15 @@ void USART3_8_IRQHandler(void) { IRQ_EXIT(USART3_8_IRQn); } +#elif defined(STM32L0) + +void USART4_5_IRQHandler(void) { + IRQ_ENTER(USART4_5_IRQn); + uart_irq_handler(4); + uart_irq_handler(5); + IRQ_EXIT(USART4_5_IRQn); +} + #else void USART3_IRQHandler(void) { diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c index 72bb53f800..d2d234a2c8 100644 --- a/ports/stm32/uart.c +++ b/ports/stm32/uart.c @@ -247,6 +247,10 @@ bool uart_init(pyb_uart_obj_t *uart_obj, UARTx = USART4; irqn = USART3_8_IRQn; __HAL_RCC_USART4_CLK_ENABLE(); + #elif defined(STM32L0) + UARTx = USART4; + irqn = USART4_5_IRQn; + __HAL_RCC_USART4_CLK_ENABLE(); #else UARTx = UART4; irqn = UART4_IRQn; @@ -274,6 +278,10 @@ bool uart_init(pyb_uart_obj_t *uart_obj, UARTx = USART5; irqn = USART3_8_IRQn; __HAL_RCC_USART5_CLK_ENABLE(); + #elif defined(STM32L0) + UARTx = USART5; + irqn = USART4_5_IRQn; + __HAL_RCC_USART5_CLK_ENABLE(); #else UARTx = UART5; irqn = UART5_IRQn; From 210d05328664ebd2f106d9a3569c5e5e1b4b79ed Mon Sep 17 00:00:00 2001 From: Andrej Krejcir Date: Tue, 3 Dec 2019 23:01:26 +0100 Subject: [PATCH 1021/1788] nrf/main: Execute boot.py/main.py frozen modules without a file system. When the file system is not enabled, the boot.py and main.py modules will still be executed, if they are frozen. --- ports/nrf/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/nrf/main.c b/ports/nrf/main.c index f7d42060e8..9ffe7a285c 100644 --- a/ports/nrf/main.c +++ b/ports/nrf/main.c @@ -230,7 +230,7 @@ pin_init0(); led_state(1, 0); -#if MICROPY_VFS || MICROPY_MBFS +#if MICROPY_VFS || MICROPY_MBFS || MICROPY_MODULE_FROZEN // run boot.py and main.py if they exist. pyexec_file_if_exists("boot.py"); pyexec_file_if_exists("main.py"); From cc634b9e92cffa4ddbc6ccf60e346f550e7b0364 Mon Sep 17 00:00:00 2001 From: Damiano Mazzella Date: Thu, 5 Dec 2019 00:16:10 +0100 Subject: [PATCH 1022/1788] stm32/boards/xxx_WB55: Enable littlefs2 on WB55 boards. --- ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h | 1 + ports/stm32/boards/NUCLEO_WB55/mpconfigboard.mk | 1 + ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.h | 1 + ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.mk | 1 + 4 files changed, 4 insertions(+) diff --git a/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h b/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h index 54747cb04d..2992ccce71 100644 --- a/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h @@ -7,6 +7,7 @@ #define MICROPY_PY_PYB_LEGACY (0) +#define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_ADC (0) diff --git a/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.mk index cd9f104ef5..416364df9e 100644 --- a/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.mk @@ -7,3 +7,4 @@ STARTUP_FILE = lib/stm32lib/CMSIS/STM32WBxx/Source/Templates/gcc/startup_stm32wb # MicroPython settings MICROPY_PY_BLUETOOTH = 1 MICROPY_BLUETOOTH_NIMBLE = 1 +MICROPY_VFS_LFS2 = 1 diff --git a/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.h b/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.h index eeedfb0844..0ff751d613 100644 --- a/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.h +++ b/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.h @@ -7,6 +7,7 @@ #define MICROPY_PY_PYB_LEGACY (0) +#define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_ADC (0) diff --git a/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.mk b/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.mk index cd9f104ef5..416364df9e 100644 --- a/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.mk +++ b/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.mk @@ -7,3 +7,4 @@ STARTUP_FILE = lib/stm32lib/CMSIS/STM32WBxx/Source/Templates/gcc/startup_stm32wb # MicroPython settings MICROPY_PY_BLUETOOTH = 1 MICROPY_BLUETOOTH_NIMBLE = 1 +MICROPY_VFS_LFS2 = 1 From 2df6a0436deaf2cd1587c35140c8f48ec2e3fa6a Mon Sep 17 00:00:00 2001 From: Daniel Mizyrycki Date: Thu, 5 Dec 2019 17:07:51 -0800 Subject: [PATCH 1023/1788] nrf/boards/particle_xenon: Enable USB CDC on Particle Xenon board. --- ports/nrf/boards/particle_xenon/mpconfigboard.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/nrf/boards/particle_xenon/mpconfigboard.h b/ports/nrf/boards/particle_xenon/mpconfigboard.h index c2aabce48d..4d8e8337a5 100644 --- a/ports/nrf/boards/particle_xenon/mpconfigboard.h +++ b/ports/nrf/boards/particle_xenon/mpconfigboard.h @@ -38,6 +38,8 @@ #define MICROPY_PY_MACHINE_TEMP (1) #define MICROPY_PY_RANDOM_HW_RNG (1) +#define MICROPY_HW_USB_CDC (1) + #define MICROPY_HW_HAS_LED (1) #define MICROPY_HW_LED_TRICOLOR (1) #define MICROPY_HW_LED_PULLUP (1) From 50dc5f10a64198d2e3cd16e3b6cc831a241ec6b2 Mon Sep 17 00:00:00 2001 From: Daniel Mizyrycki Date: Fri, 6 Dec 2019 08:28:36 -0800 Subject: [PATCH 1024/1788] docs/reference/filesystem: Fix typo in block device code example. --- docs/reference/filesystem.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/filesystem.rst b/docs/reference/filesystem.rst index 71d34e7954..99e2305313 100644 --- a/docs/reference/filesystem.rst +++ b/docs/reference/filesystem.rst @@ -124,7 +124,7 @@ interface (i.e. both signatures and behaviours of the self.block_size = block_size self.data = bytearray(block_size * num_blocks) - def readblocks(self, block, buf, offset=0): + def readblocks(self, block_num, buf, offset=0): addr = block_num * self.block_size + offset for i in range(len(buf)): buf[i] = self.data[addr + i] From 381be9a745a2895f6333e5d7443f6d32fbe524de Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 9 Dec 2019 14:21:22 +1100 Subject: [PATCH 1025/1788] docs/reference/filesystem: Add note and example about using filesystem. --- docs/reference/filesystem.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/reference/filesystem.rst b/docs/reference/filesystem.rst index 99e2305313..32d0138491 100644 --- a/docs/reference/filesystem.rst +++ b/docs/reference/filesystem.rst @@ -156,6 +156,13 @@ As it supports the extended interface, it can be used with :class:`littlefs os.VfsLfs2.mkfs(bdev) os.mount(bdev, '/ramdisk') +Once mounted, the filesystem (regardless of its type) can be used as it +normally would be used from Python code, for example:: + + with open('/ramdisk/hello.txt', 'w') as f: + f.write('Hello world') + print(open('/ramdisk/hello.txt').read()) + Filesystems ----------- From 193bc3702f35bc7b60ffd79e4f41ecd5db1fd383 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Sat, 7 Dec 2019 22:31:04 +1100 Subject: [PATCH 1026/1788] mpy-cross/README.md: Add notes about -march and -O. --- mpy-cross/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mpy-cross/README.md b/mpy-cross/README.md index e35b28b696..bf743a9031 100644 --- a/mpy-cross/README.md +++ b/mpy-cross/README.md @@ -22,4 +22,10 @@ the unix port of MicroPython requires the following: $ ./mpy-cross -mcache-lookup-bc foo.py +If the Python code contains `@native` or `@viper` annotations, then you must +specify `-march` to match the target architecture. + Run `./mpy-cross -h` to get a full list of options. + +The optimisation level is 0 by default. Optimisation levels are detailed in +https://docs.micropython.org/en/latest/library/micropython.html#micropython.opt_level From 4ebbacd65eec4c0fde8ceb32274c06f5e3de3af6 Mon Sep 17 00:00:00 2001 From: Emil Renner Berthing Date: Sun, 8 Dec 2019 21:43:47 +0100 Subject: [PATCH 1027/1788] py/objenumerate: Check for valid args in enumerate constructor. For the case where MICROPY_CPYTHON_COMPAT is disabled. This fix makes basics/fun_error2.py pass and not crash the interpreter. --- py/objenumerate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/objenumerate.c b/py/objenumerate.c index 493e45c2a2..243c9f83aa 100644 --- a/py/objenumerate.c +++ b/py/objenumerate.c @@ -59,7 +59,7 @@ STATIC mp_obj_t enumerate_make_new(const mp_obj_type_t *type, size_t n_args, siz o->iter = mp_getiter(arg_vals.iterable.u_obj, NULL); o->cur = arg_vals.start.u_int; #else - (void)n_kw; + mp_arg_check_num(n_args, n_kw, 1, 2, false); mp_obj_enumerate_t *o = m_new_obj(mp_obj_enumerate_t); o->base.type = type; o->iter = mp_getiter(args[0], NULL); From b76f0a73bc31d1c8871ff00d2f93b5805b3b6315 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 9 Dec 2019 15:12:51 +1100 Subject: [PATCH 1028/1788] stm32/main: Fix SKIPSD file detection so SD card is mounted by default. The condition for skipping was accidentally inverted in 7723dac3371ccf081c2490b33b69492dc42818bd Fixes issue #5400. --- ports/stm32/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 8cb6ed1e3b..fd9cdd6f67 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -644,7 +644,7 @@ soft_reset: // 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 - if (!mounted_flash || mp_vfs_import_stat("SKIPSD") == MP_IMPORT_STAT_FILE) { + if (!mounted_flash || mp_vfs_import_stat("SKIPSD") == MP_IMPORT_STAT_NO_EXIST) { mounted_sdcard = init_sdcard_fs(); } } From 159388f85072af9aa704f48f6d75bea5b943178b Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 10 Dec 2019 16:58:27 +1100 Subject: [PATCH 1029/1788] docs/library/ubluetooth: Add note about API being under development. --- docs/library/ubluetooth.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/library/ubluetooth.rst b/docs/library/ubluetooth.rst index ddcd28d9e6..1a62d1e4ba 100644 --- a/docs/library/ubluetooth.rst +++ b/docs/library/ubluetooth.rst @@ -12,6 +12,9 @@ roles concurrently. This API is intended to match the low-level Bluetooth protocol and provide building-blocks for higher-level abstractions such as specific device types. +.. note:: This module is still under development and its classes, functions, + methods and constants are subject to change. + class BLE --------- From b310930dba3a35dbe4d790f461caf27d78b4c7b9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 10 Dec 2019 16:58:53 +1100 Subject: [PATCH 1030/1788] docs/library/uos: Add notes and links about littlefs failures. --- docs/library/uos.rst | 8 ++++++++ docs/reference/filesystem.rst | 7 ++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/docs/library/uos.rst b/docs/library/uos.rst index 84d341ac21..5505e6434f 100644 --- a/docs/library/uos.rst +++ b/docs/library/uos.rst @@ -191,6 +191,9 @@ represented by VFS classes. Build a Lfs1 filesystem on *block_dev*. + .. note:: There are reports of littlefs v1 failing in certain situations, + for details see `littlefs issue 347`_. + .. class:: VfsLfs2(block_dev) Create a filesystem object that uses the `littlefs v2 filesystem format`_. @@ -204,8 +207,13 @@ represented by VFS classes. Build a Lfs2 filesystem on *block_dev*. + .. note:: There are reports of littlefs v2 failing in certain situations, + for details see `littlefs issue 295`_. + .. _littlefs v1 filesystem format: https://github.com/ARMmbed/littlefs/tree/v1 .. _littlefs v2 filesystem format: https://github.com/ARMmbed/littlefs +.. _littlefs issue 295: https://github.com/ARMmbed/littlefs/issues/295 +.. _littlefs issue 347: https://github.com/ARMmbed/littlefs/issues/347 Block devices ------------- diff --git a/docs/reference/filesystem.rst b/docs/reference/filesystem.rst index 32d0138491..cd86009287 100644 --- a/docs/reference/filesystem.rst +++ b/docs/reference/filesystem.rst @@ -214,13 +214,18 @@ Littlefs Littlefs_ is a filesystem designed for flash-based devices, and is much more resistant to filesystem corruption. +.. note:: There are reports of littlefs v1 and v2 failing in certain + situations, for details see `littlefs issue 347`_ and + `littlefs issue 295`_. + Note: It can be still be accessed over USB MSC using the `littlefs FUSE driver`_. Note that you must use the ``-b=4096`` option to override the block size. .. _littlefs FUSE driver: https://github.com/ARMmbed/littlefs-fuse/tree/master/littlefs - .. _Littlefs: https://github.com/ARMmbed/littlefs +.. _littlefs issue 295: https://github.com/ARMmbed/littlefs/issues/295 +.. _littlefs issue 347: https://github.com/ARMmbed/littlefs/issues/347 To format the entire flash using littlefs v2:: From b47e155bd07e5765b804c404411825b15378c0b6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 6 Oct 2019 23:29:40 +1100 Subject: [PATCH 1031/1788] py/persistentcode: Add ability to relocate loaded native code. Implements text, rodata and bss generalised relocations, as well as generic qstr-object linking. This allows importing dynamic native modules on all supported architectures in a unified way. --- ports/esp32/main.c | 6 ++- ports/esp32/mpconfigport.h | 4 +- ports/esp8266/modesp.c | 12 +++++- ports/esp8266/mpconfigport.h | 4 +- py/asmbase.h | 2 +- py/bc.h | 2 +- py/persistentcode.c | 80 +++++++++++++++++++++++++++++++++++- py/persistentcode.h | 2 + py/runtime0.h | 6 ++- 9 files changed, 106 insertions(+), 12 deletions(-) diff --git a/ports/esp32/main.c b/ports/esp32/main.c index b0d1b15370..d8705ee735 100644 --- a/ports/esp32/main.c +++ b/ports/esp32/main.c @@ -47,6 +47,7 @@ #include "py/nlr.h" #include "py/compile.h" #include "py/runtime.h" +#include "py/persistentcode.h" #include "py/repl.h" #include "py/gc.h" #include "py/mphal.h" @@ -173,12 +174,15 @@ void mbedtls_debug_set_threshold(int threshold) { (void)threshold; } -void *esp_native_code_commit(void *buf, size_t len) { +void *esp_native_code_commit(void *buf, size_t len, void *reloc) { len = (len + 3) & ~3; uint32_t *p = heap_caps_malloc(len, MALLOC_CAP_EXEC); if (p == NULL) { m_malloc_fail(len); } + if (reloc) { + mp_native_relocate(reloc, buf, (uintptr_t)p); + } memcpy(p, buf, len); return p; } diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index da62beb4c1..1924cf2186 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -21,8 +21,6 @@ // emitters #define MICROPY_PERSISTENT_CODE_LOAD (1) #define MICROPY_EMIT_XTENSAWIN (1) -void *esp_native_code_commit(void*, size_t); -#define MP_PLAT_COMMIT_EXEC(buf, len) esp_native_code_commit(buf, len) // compiler configuration #define MICROPY_COMP_MODULE_CONST (1) @@ -225,6 +223,8 @@ struct mp_bluetooth_nimble_root_pointers_t; #define BYTES_PER_WORD (4) #define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p))) #define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) +void *esp_native_code_commit(void*, size_t, void*); +#define MP_PLAT_COMMIT_EXEC(buf, len, reloc) esp_native_code_commit(buf, len, reloc) #define MP_SSIZE_MAX (0x7fffffff) // Note: these "critical nested" macros do not ensure cross-CPU exclusion, diff --git a/ports/esp8266/modesp.c b/ports/esp8266/modesp.c index 2aeb3d690a..a3cc2eca73 100644 --- a/ports/esp8266/modesp.c +++ b/ports/esp8266/modesp.c @@ -28,6 +28,7 @@ #include "py/gc.h" #include "py/runtime.h" +#include "py/persistentcode.h" #include "py/mperrno.h" #include "py/mphal.h" #include "drivers/dht/dht.h" @@ -282,7 +283,7 @@ void esp_native_code_init(void) { esp_native_code_erased = 0; } -void *esp_native_code_commit(void *buf, size_t len) { +void *esp_native_code_commit(void *buf, size_t len, void *reloc) { //printf("COMMIT(buf=%p, len=%u, start=%08x, cur=%08x, end=%08x, erased=%08x)\n", buf, len, esp_native_code_start, esp_native_code_cur, esp_native_code_end, esp_native_code_erased); len = (len + 3) & ~3; @@ -294,6 +295,14 @@ void *esp_native_code_commit(void *buf, size_t len) { void *dest; if (esp_native_code_location == ESP_NATIVE_CODE_IRAM1) { dest = (void*)esp_native_code_cur; + } else { + dest = (void*)(FLASH_START + esp_native_code_cur); + } + if (reloc) { + mp_native_relocate(reloc, buf, (uintptr_t)dest); + } + + if (esp_native_code_location == ESP_NATIVE_CODE_IRAM1) { memcpy(dest, buf, len); } else { SpiFlashOpResult res; @@ -313,7 +322,6 @@ void *esp_native_code_commit(void *buf, size_t len) { if (res != SPI_FLASH_RESULT_OK) { mp_raise_OSError(res == SPI_FLASH_RESULT_TIMEOUT ? MP_ETIMEDOUT : MP_EIO); } - dest = (void*)(FLASH_START + esp_native_code_cur); } esp_native_code_cur += len; diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h index 22ca99b2b1..81544bb2a3 100644 --- a/ports/esp8266/mpconfigport.h +++ b/ports/esp8266/mpconfigport.h @@ -131,8 +131,8 @@ typedef uint32_t sys_prot_t; // for modlwip #include #define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) -void *esp_native_code_commit(void*, size_t); -#define MP_PLAT_COMMIT_EXEC(buf, len) esp_native_code_commit(buf, len) +void *esp_native_code_commit(void*, size_t, void*); +#define MP_PLAT_COMMIT_EXEC(buf, len, reloc) esp_native_code_commit(buf, len, reloc) // printer for debugging output, goes to UART only extern const struct _mp_print_t mp_debug_print; diff --git a/py/asmbase.h b/py/asmbase.h index d2b4038931..b5e259358d 100644 --- a/py/asmbase.h +++ b/py/asmbase.h @@ -60,7 +60,7 @@ static inline size_t mp_asm_base_get_code_size(mp_asm_base_t *as) { static inline void *mp_asm_base_get_code(mp_asm_base_t *as) { #if defined(MP_PLAT_COMMIT_EXEC) - return MP_PLAT_COMMIT_EXEC(as->code_base, as->code_size); + return MP_PLAT_COMMIT_EXEC(as->code_base, as->code_size, NULL); #else return as->code_base; #endif diff --git a/py/bc.h b/py/bc.h index fd52571fda..a96d17a0db 100644 --- a/py/bc.h +++ b/py/bc.h @@ -74,7 +74,7 @@ #define MP_BC_PRELUDE_SIG_ENCODE(S, E, scope, out_byte, out_env) \ do { \ /*// Get values to store in prelude */ \ - size_t F = scope->scope_flags & 0x0f; /* only need to store lower 4 flag bits */ \ + size_t F = scope->scope_flags & MP_SCOPE_FLAG_ALL_SIG; \ size_t A = scope->num_pos_args; \ size_t K = scope->num_kwonly_args; \ size_t D = scope->num_def_pos_args; \ diff --git a/py/persistentcode.c b/py/persistentcode.c index 84385c1713..353fa268e5 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -33,6 +33,7 @@ #include "py/emitglue.h" #include "py/persistentcode.h" #include "py/bc0.h" +#include "py/objstr.h" #if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE @@ -145,8 +146,16 @@ STATIC byte *extract_prelude(const byte **ip, bytecode_prelude_t *prelude) { #include "py/parsenum.h" +STATIC int read_byte(mp_reader_t *reader); +STATIC size_t read_uint(mp_reader_t *reader, byte **out); + #if MICROPY_EMIT_MACHINE_CODE +typedef struct _reloc_info_t { + mp_reader_t *reader; + mp_uint_t *const_table; +} reloc_info_t; + #if MICROPY_EMIT_THUMB STATIC void asm_thumb_rewrite_mov(uint8_t *pc, uint16_t val) { // high part @@ -179,6 +188,52 @@ STATIC void arch_link_qstr(uint8_t *pc, bool is_obj, qstr qst) { #endif } +void mp_native_relocate(void *ri_in, uint8_t *text, uintptr_t reloc_text) { + // Relocate native code + reloc_info_t *ri = ri_in; + uint8_t op; + uintptr_t *addr_to_adjust = NULL; + while ((op = read_byte(ri->reader)) != 0xff) { + if (op & 1) { + // Point to new location to make adjustments + size_t addr = read_uint(ri->reader, NULL); + if ((addr & 1) == 0) { + // Point to somewhere in text + addr_to_adjust = &((uintptr_t*)text)[addr >> 1]; + } else { + // Point to somewhere in rodata + addr_to_adjust = &((uintptr_t*)ri->const_table[1])[addr >> 1]; + } + } + op >>= 1; + uintptr_t dest; + size_t n = 1; + if (op <= 5) { + if (op & 1) { + // Read in number of adjustments to make + n = read_uint(ri->reader, NULL); + } + op >>= 1; + if (op == 0) { + // Destination is text + dest = reloc_text; + } else { + // Destination is rodata (op=1) or bss (op=1 if no rodata, else op=2) + dest = ri->const_table[op]; + } + } else if (op == 6) { + // Destination is mp_fun_table itself + dest = (uintptr_t)&mp_fun_table; + } else { + // Destination is an entry in mp_fun_table + dest = ((uintptr_t*)&mp_fun_table)[op - 7]; + } + while (n--) { + *addr_to_adjust++ += dest; + } + } +} + #endif STATIC int read_byte(mp_reader_t *reader) { @@ -340,6 +395,9 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { // Generic 16-bit link dest[0] = qst & 0xff; dest[1] = (qst >> 8) & 0xff; + } else if ((off & 3) == 3) { + // Generic, aligned qstr-object link + *(mp_obj_t*)dest = MP_OBJ_NEW_QSTR(qst); } else { // Architecture-specific link arch_link_qstr(dest, (off & 3) == 2, qst); @@ -423,8 +481,26 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { #if MICROPY_EMIT_MACHINE_CODE } else { + mp_uint_t *ct = &const_table[1]; + if (prelude.scope_flags & MP_SCOPE_FLAG_VIPERRODATA) { + size_t size = read_uint(reader, NULL); + uint8_t *rodata = m_new(uint8_t, size); + read_bytes(reader, rodata, size); + *ct++ = (uintptr_t)rodata; + } + if (prelude.scope_flags & MP_SCOPE_FLAG_VIPERBSS) { + size_t size = read_uint(reader, NULL); + uint8_t *bss = m_new0(uint8_t, size); + *ct++ = (uintptr_t)bss; + } + reloc_info_t ri = {reader, const_table}; #if defined(MP_PLAT_COMMIT_EXEC) - fun_data = MP_PLAT_COMMIT_EXEC(fun_data, fun_data_len); + void *opt_ri = (prelude.scope_flags & MP_SCOPE_FLAG_VIPERRELOC) ? &ri : NULL; + fun_data = MP_PLAT_COMMIT_EXEC(fun_data, fun_data_len, opt_ri); + #else + if (prelude.scope_flags & MP_SCOPE_FLAG_VIPERRELOC) { + mp_native_relocate(&ri, fun_data, (uintptr_t)fun_data); + } #endif mp_emit_glue_assign_native(rc, kind, @@ -624,7 +700,7 @@ STATIC void save_raw_code(mp_print_t *print, mp_raw_code_t *rc, qstr_window_t *q save_prelude_qstrs(print, qstr_window, ip_info); } else { // Save basic scope info for viper and asm - mp_print_uint(print, rc->scope_flags); + mp_print_uint(print, rc->scope_flags & MP_SCOPE_FLAG_ALL_SIG); prelude.n_pos_args = 0; prelude.n_kwonly_args = 0; if (rc->kind == MP_CODE_NATIVE_ASM) { diff --git a/py/persistentcode.h b/py/persistentcode.h index 07e018f8a6..fde7a4625d 100644 --- a/py/persistentcode.h +++ b/py/persistentcode.h @@ -95,4 +95,6 @@ mp_raw_code_t *mp_raw_code_load_file(const char *filename); void mp_raw_code_save(mp_raw_code_t *rc, mp_print_t *print); void mp_raw_code_save_file(mp_raw_code_t *rc, const char *filename); +void mp_native_relocate(void *reloc, uint8_t *text, uintptr_t reloc_text); + #endif // MICROPY_INCLUDED_PY_PERSISTENTCODE_H diff --git a/py/runtime0.h b/py/runtime0.h index f588110c0d..b433c716f7 100644 --- a/py/runtime0.h +++ b/py/runtime0.h @@ -28,13 +28,17 @@ // The first four must fit in 8 bits, see emitbc.c // The remaining must fit in 16 bits, see scope.h +#define MP_SCOPE_FLAG_ALL_SIG (0x0f) #define MP_SCOPE_FLAG_GENERATOR (0x01) #define MP_SCOPE_FLAG_VARKEYWORDS (0x02) #define MP_SCOPE_FLAG_VARARGS (0x04) #define MP_SCOPE_FLAG_DEFKWARGS (0x08) #define MP_SCOPE_FLAG_REFGLOBALS (0x10) // used only if native emitter enabled #define MP_SCOPE_FLAG_HASCONSTS (0x20) // used only if native emitter enabled -#define MP_SCOPE_FLAG_VIPERRET_POS (6) // 3 bits used for viper return type +#define MP_SCOPE_FLAG_VIPERRET_POS (6) // 3 bits used for viper return type, to pass from compiler to native emitter +#define MP_SCOPE_FLAG_VIPERRELOC (0x10) // used only when loading viper from .mpy +#define MP_SCOPE_FLAG_VIPERRODATA (0x20) // used only when loading viper from .mpy +#define MP_SCOPE_FLAG_VIPERBSS (0x40) // used only when loading viper from .mpy // types for native (viper) function signature #define MP_NATIVE_TYPE_OBJ (0x00) From 360d972c16dd818462be7699badb6478639924c1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 7 Oct 2019 11:56:24 +1100 Subject: [PATCH 1032/1788] py/nativeglue: Add new header file with native function table typedef. --- py/emitnative.c | 4 +- py/emitnx86.c | 2 +- py/nativeglue.c | 5 +- py/nativeglue.h | 141 ++++++++++++++++++++++++++++++++++++++++++++ py/persistentcode.c | 4 +- py/runtime0.h | 56 ------------------ tools/mpy-tool.py | 3 +- 7 files changed, 150 insertions(+), 65 deletions(-) create mode 100644 py/nativeglue.h diff --git a/py/emitnative.c b/py/emitnative.c index fbf6659140..07b984b780 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -47,7 +47,7 @@ #include #include "py/emit.h" -#include "py/bc.h" +#include "py/nativeglue.h" #include "py/objstr.h" #if MICROPY_DEBUG_VERBOSE // print debugging info @@ -687,7 +687,7 @@ STATIC void emit_native_end_pass(emit_t *emit) { #if !MICROPY_DYNAMIC_COMPILER // Store mp_fun_table pointer just after qstrs // (but in dynamic-compiler mode eliminate dependency on mp_fun_table) - emit->const_table[nqstr] = (mp_uint_t)(uintptr_t)mp_fun_table; + emit->const_table[nqstr] = (mp_uint_t)(uintptr_t)&mp_fun_table; #endif #if MICROPY_PERSISTENT_CODE_SAVE diff --git a/py/emitnx86.c b/py/emitnx86.c index 790cae04c2..f0553f0682 100644 --- a/py/emitnx86.c +++ b/py/emitnx86.c @@ -1,7 +1,7 @@ // x86 specific stuff #include "py/mpconfig.h" -#include "py/runtime0.h" +#include "py/nativeglue.h" #if MICROPY_EMIT_X86 diff --git a/py/nativeglue.c b/py/nativeglue.c index 08fbd3c309..9991151a34 100644 --- a/py/nativeglue.c +++ b/py/nativeglue.c @@ -30,8 +30,7 @@ #include "py/runtime.h" #include "py/smallint.h" -#include "py/emitglue.h" -#include "py/bc.h" +#include "py/nativeglue.h" #if MICROPY_DEBUG_VERBOSE // print debugging info #define DEBUG_printf DEBUG_printf @@ -211,7 +210,7 @@ STATIC bool mp_native_yield_from(mp_obj_t gen, mp_obj_t send_value, mp_obj_t *re } // these must correspond to the respective enum in runtime0.h -const void *const mp_fun_table[MP_F_NUMBER_OF] = { +const mp_fun_table_t mp_fun_table = { &mp_const_none_obj, &mp_const_false_obj, &mp_const_true_obj, diff --git a/py/nativeglue.h b/py/nativeglue.h new file mode 100644 index 0000000000..200093b3cc --- /dev/null +++ b/py/nativeglue.h @@ -0,0 +1,141 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2019 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_NATIVEGLUE_H +#define MICROPY_INCLUDED_PY_NATIVEGLUE_H + +#include "py/obj.h" +#include "py/persistentcode.h" + +typedef enum { + MP_F_CONST_NONE_OBJ = 0, + MP_F_CONST_FALSE_OBJ, + MP_F_CONST_TRUE_OBJ, + MP_F_CONVERT_OBJ_TO_NATIVE, + MP_F_CONVERT_NATIVE_TO_OBJ, + MP_F_NATIVE_SWAP_GLOBALS, + MP_F_LOAD_NAME, + MP_F_LOAD_GLOBAL, + MP_F_LOAD_BUILD_CLASS, + MP_F_LOAD_ATTR, + MP_F_LOAD_METHOD, + MP_F_LOAD_SUPER_METHOD, + MP_F_STORE_NAME, + MP_F_STORE_GLOBAL, + MP_F_STORE_ATTR, + MP_F_OBJ_SUBSCR, + MP_F_OBJ_IS_TRUE, + MP_F_UNARY_OP, + MP_F_BINARY_OP, + MP_F_BUILD_TUPLE, + MP_F_BUILD_LIST, + MP_F_BUILD_MAP, + MP_F_BUILD_SET, + MP_F_STORE_SET, + MP_F_LIST_APPEND, + MP_F_STORE_MAP, + MP_F_MAKE_FUNCTION_FROM_RAW_CODE, + MP_F_NATIVE_CALL_FUNCTION_N_KW, + MP_F_CALL_METHOD_N_KW, + MP_F_CALL_METHOD_N_KW_VAR, + MP_F_NATIVE_GETITER, + MP_F_NATIVE_ITERNEXT, + MP_F_NLR_PUSH, + MP_F_NLR_POP, + MP_F_NATIVE_RAISE, + MP_F_IMPORT_NAME, + MP_F_IMPORT_FROM, + MP_F_IMPORT_ALL, + MP_F_NEW_SLICE, + MP_F_UNPACK_SEQUENCE, + MP_F_UNPACK_EX, + MP_F_DELETE_NAME, + MP_F_DELETE_GLOBAL, + MP_F_MAKE_CLOSURE_FROM_RAW_CODE, + MP_F_ARG_CHECK_NUM_SIG, + MP_F_SETUP_CODE_STATE, + MP_F_SMALL_INT_FLOOR_DIVIDE, + MP_F_SMALL_INT_MODULO, + MP_F_NATIVE_YIELD_FROM, + MP_F_SETJMP, + MP_F_NUMBER_OF, +} mp_fun_kind_t; + +typedef struct _mp_fun_table_t { + mp_const_obj_t const_none; + mp_const_obj_t const_false; + mp_const_obj_t const_true; + mp_uint_t (*native_from_obj)(mp_obj_t obj, mp_uint_t type); + mp_obj_t (*native_to_obj)(mp_uint_t val, mp_uint_t type); + mp_obj_dict_t *(*swap_globals)(mp_obj_dict_t *new_globals); + mp_obj_t (*load_name)(qstr qst); + mp_obj_t (*load_global)(qstr qst); + mp_obj_t (*load_build_class)(void); + mp_obj_t (*load_attr)(mp_obj_t base, qstr attr); + void (*load_method)(mp_obj_t base, qstr attr, mp_obj_t *dest); + void (*load_super_method)(qstr attr, mp_obj_t *dest); + void (*store_name)(qstr qst, mp_obj_t obj); + void (*store_global)(qstr qst, mp_obj_t obj); + void (*store_attr)(mp_obj_t base, qstr attr, mp_obj_t val); + mp_obj_t (*obj_subscr)(mp_obj_t base, mp_obj_t index, mp_obj_t val); + bool (*obj_is_true)(mp_obj_t arg); + mp_obj_t (*unary_op)(mp_unary_op_t op, mp_obj_t arg); + mp_obj_t (*binary_op)(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs); + mp_obj_t (*new_tuple)(size_t n, const mp_obj_t *items); + mp_obj_t (*new_list)(size_t n, mp_obj_t *items); + mp_obj_t (*new_dict)(size_t n_args); + mp_obj_t (*new_set)(size_t n_args, mp_obj_t *items); + void (*set_store)(mp_obj_t self_in, mp_obj_t item); + mp_obj_t (*list_append)(mp_obj_t self_in, mp_obj_t arg); + mp_obj_t (*dict_store)(mp_obj_t self_in, mp_obj_t key, mp_obj_t value); + mp_obj_t (*make_function_from_raw_code)(const mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args); + mp_obj_t (*call_function_n_kw)(mp_obj_t fun_in, size_t n_args_kw, const mp_obj_t *args); + mp_obj_t (*call_method_n_kw)(size_t n_args, size_t n_kw, const mp_obj_t *args); + mp_obj_t (*call_method_n_kw_var)(bool have_self, size_t n_args_n_kw, const mp_obj_t *args); + mp_obj_t (*getiter)(mp_obj_t obj, mp_obj_iter_buf_t *iter); + mp_obj_t (*iternext)(mp_obj_iter_buf_t *iter); + unsigned int (*nlr_push)(nlr_buf_t *); + void (*nlr_pop)(void); + void (*raise)(mp_obj_t o); + mp_obj_t (*import_name)(qstr name, mp_obj_t fromlist, mp_obj_t level); + mp_obj_t (*import_from)(mp_obj_t module, qstr name); + void (*import_all)(mp_obj_t module); + mp_obj_t (*new_slice)(mp_obj_t start, mp_obj_t stop, mp_obj_t step); + void (*unpack_sequence)(mp_obj_t seq, size_t num, mp_obj_t *items); + void (*unpack_ex)(mp_obj_t seq, size_t num, mp_obj_t *items); + void (*delete_name)(qstr qst); + void (*delete_global)(qstr qst); + mp_obj_t (*make_closure_from_raw_code)(const mp_raw_code_t *rc, mp_uint_t n_closed_over, const mp_obj_t *args); + void (*arg_check_num_sig)(size_t n_args, size_t n_kw, uint32_t sig); + void (*setup_code_state)(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args); + mp_int_t (*small_int_floor_divide)(mp_int_t num, mp_int_t denom); + mp_int_t (*small_int_modulo)(mp_int_t dividend, mp_int_t divisor); + bool (*yield_from)(mp_obj_t gen, mp_obj_t send_value, mp_obj_t *ret_value); + void *setjmp; +} mp_fun_table_t; + +extern const mp_fun_table_t mp_fun_table; + +#endif // MICROPY_INCLUDED_PY_NATIVEGLUE_H diff --git a/py/persistentcode.c b/py/persistentcode.c index 353fa268e5..1e3b5368b4 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -30,7 +30,7 @@ #include #include "py/reader.h" -#include "py/emitglue.h" +#include "py/nativeglue.h" #include "py/persistentcode.h" #include "py/bc0.h" #include "py/objstr.h" @@ -453,7 +453,7 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { #if MICROPY_EMIT_MACHINE_CODE if (kind != MP_CODE_BYTECODE) { // Populate mp_fun_table entry - *ct++ = (mp_uint_t)(uintptr_t)mp_fun_table; + *ct++ = (mp_uint_t)(uintptr_t)&mp_fun_table; } #endif diff --git a/py/runtime0.h b/py/runtime0.h index b433c716f7..e6eeff97d6 100644 --- a/py/runtime0.h +++ b/py/runtime0.h @@ -156,60 +156,4 @@ typedef enum { MP_BINARY_OP_IS_NOT, } mp_binary_op_t; -typedef enum { - MP_F_CONST_NONE_OBJ = 0, - MP_F_CONST_FALSE_OBJ, - MP_F_CONST_TRUE_OBJ, - MP_F_CONVERT_OBJ_TO_NATIVE, - MP_F_CONVERT_NATIVE_TO_OBJ, - MP_F_NATIVE_SWAP_GLOBALS, - MP_F_LOAD_NAME, - MP_F_LOAD_GLOBAL, - MP_F_LOAD_BUILD_CLASS, - MP_F_LOAD_ATTR, - MP_F_LOAD_METHOD, - MP_F_LOAD_SUPER_METHOD, - MP_F_STORE_NAME, - MP_F_STORE_GLOBAL, - MP_F_STORE_ATTR, - MP_F_OBJ_SUBSCR, - MP_F_OBJ_IS_TRUE, - MP_F_UNARY_OP, - MP_F_BINARY_OP, - MP_F_BUILD_TUPLE, - MP_F_BUILD_LIST, - MP_F_BUILD_MAP, - MP_F_BUILD_SET, - MP_F_STORE_SET, - MP_F_LIST_APPEND, - MP_F_STORE_MAP, - MP_F_MAKE_FUNCTION_FROM_RAW_CODE, - MP_F_NATIVE_CALL_FUNCTION_N_KW, - MP_F_CALL_METHOD_N_KW, - MP_F_CALL_METHOD_N_KW_VAR, - MP_F_NATIVE_GETITER, - MP_F_NATIVE_ITERNEXT, - MP_F_NLR_PUSH, - MP_F_NLR_POP, - MP_F_NATIVE_RAISE, - MP_F_IMPORT_NAME, - MP_F_IMPORT_FROM, - MP_F_IMPORT_ALL, - MP_F_NEW_SLICE, - MP_F_UNPACK_SEQUENCE, - MP_F_UNPACK_EX, - MP_F_DELETE_NAME, - MP_F_DELETE_GLOBAL, - MP_F_MAKE_CLOSURE_FROM_RAW_CODE, - MP_F_ARG_CHECK_NUM_SIG, - MP_F_SETUP_CODE_STATE, - MP_F_SMALL_INT_FLOOR_DIVIDE, - MP_F_SMALL_INT_MODULO, - MP_F_NATIVE_YIELD_FROM, - MP_F_SETJMP, - MP_F_NUMBER_OF, -} mp_fun_kind_t; - -extern const void *const mp_fun_table[MP_F_NUMBER_OF]; - #endif // MICROPY_INCLUDED_PY_RUNTIME0_H diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index 581603249d..cd36c909f4 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -314,7 +314,7 @@ class RawCode(object): print(' MP_ROM_QSTR(%s),' % global_qstrs[qst].qstr_id) for i in range(len(self.objs)): if self.objs[i] is MPFunTable: - print(' mp_fun_table,') + print(' &mp_fun_table,') elif type(self.objs[i]) is float: print('#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B') print(' MP_ROM_PTR(&const_obj_%s_%u),' % (self.escaped_name, i)) @@ -711,6 +711,7 @@ def freeze_mpy(base_qstrs, raw_codes): print('#include "py/objint.h"') print('#include "py/objstr.h"') print('#include "py/emitglue.h"') + print('#include "py/nativeglue.h"') print() print('#if MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE != %u' % config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) From 3690f79afc4e32acbd1db243fd7af7fa518fa27f Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 8 Oct 2019 23:00:34 +1100 Subject: [PATCH 1033/1788] py/nativeglue: Add funcs/types to native glue table for dynamic runtime. These allow discovery of symbols by native code that is loaded dynamically. --- py/nativeglue.c | 29 +++++++++++++++++++++++++++++ py/nativeglue.h | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/py/nativeglue.c b/py/nativeglue.c index 9991151a34..a88d8c1b9b 100644 --- a/py/nativeglue.c +++ b/py/nativeglue.c @@ -24,6 +24,7 @@ * THE SOFTWARE. */ +#include #include #include #include @@ -31,6 +32,7 @@ #include "py/runtime.h" #include "py/smallint.h" #include "py/nativeglue.h" +#include "py/gc.h" #if MICROPY_DEBUG_VERBOSE // print debugging info #define DEBUG_printf DEBUG_printf @@ -269,6 +271,33 @@ const mp_fun_table_t mp_fun_table = { #else NULL, #endif + // Additional entries for dynamic runtime, starts at index 50 + memset, + memmove, + gc_realloc, + mp_printf, + mp_vprintf, + mp_raise_msg, + mp_obj_get_type, + mp_obj_new_str, + mp_obj_new_bytes, + mp_obj_new_bytearray_by_ref, + mp_get_buffer_raise, + mp_get_stream_raise, + &mp_plat_print, + &mp_type_type, + &mp_type_str, + &mp_type_list, + &mp_type_dict, + &mp_type_fun_builtin_0, + &mp_type_fun_builtin_1, + &mp_type_fun_builtin_2, + &mp_type_fun_builtin_3, + &mp_type_fun_builtin_var, + &mp_stream_read_obj, + &mp_stream_readinto_obj, + &mp_stream_unbuffered_readline_obj, + &mp_stream_write_obj, }; #endif // MICROPY_EMIT_NATIVE diff --git a/py/nativeglue.h b/py/nativeglue.h index 200093b3cc..9abae89df2 100644 --- a/py/nativeglue.h +++ b/py/nativeglue.h @@ -26,8 +26,10 @@ #ifndef MICROPY_INCLUDED_PY_NATIVEGLUE_H #define MICROPY_INCLUDED_PY_NATIVEGLUE_H +#include #include "py/obj.h" #include "py/persistentcode.h" +#include "py/stream.h" typedef enum { MP_F_CONST_NONE_OBJ = 0, @@ -134,6 +136,36 @@ typedef struct _mp_fun_table_t { mp_int_t (*small_int_modulo)(mp_int_t dividend, mp_int_t divisor); bool (*yield_from)(mp_obj_t gen, mp_obj_t send_value, mp_obj_t *ret_value); void *setjmp; + // Additional entries for dynamic runtime, starts at index 50 + void *(*memset_)(void *s, int c, size_t n); + void *(*memmove_)(void *dest, const void *src, size_t n); + void *(*realloc_)(void *ptr, size_t n_bytes, bool allow_move); + int (*printf_)(const mp_print_t *print, const char *fmt, ...); + int (*vprintf_)(const mp_print_t *print, const char *fmt, va_list args); + #if defined(__GNUC__) + NORETURN // Only certain compilers support no-return attributes in function pointer declarations + #endif + void (*raise_msg)(const mp_obj_type_t *exc_type, const char *msg); + mp_obj_type_t *(*obj_get_type)(mp_const_obj_t o_in); + mp_obj_t (*obj_new_str)(const char* data, size_t len); + mp_obj_t (*obj_new_bytes)(const byte* data, size_t len); + mp_obj_t (*obj_new_bytearray_by_ref)(size_t n, void *items); + void (*get_buffer_raise)(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags); + const mp_stream_p_t *(*get_stream_raise)(mp_obj_t self_in, int flags); + const mp_print_t *plat_print; + const mp_obj_type_t *type_type; + const mp_obj_type_t *type_str; + const mp_obj_type_t *type_list; + const mp_obj_type_t *type_dict; + const mp_obj_type_t *type_fun_builtin_0; + const mp_obj_type_t *type_fun_builtin_1; + const mp_obj_type_t *type_fun_builtin_2; + const mp_obj_type_t *type_fun_builtin_3; + const mp_obj_type_t *type_fun_builtin_var; + const mp_obj_fun_builtin_var_t *stream_read_obj; + const mp_obj_fun_builtin_var_t *stream_readinto_obj; + const mp_obj_fun_builtin_var_t *stream_unbuffered_readline_obj; + const mp_obj_fun_builtin_var_t *stream_write_obj; } mp_fun_table_t; extern const mp_fun_table_t mp_fun_table; From 27879844d24f276b0d15b27bd60c3a0391a9099e Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 9 Oct 2019 14:23:15 +1100 Subject: [PATCH 1034/1788] tools/mpy-tool.py: Add ability to merge multiple .mpy files into one. Usage: mpy-tool.py -o merged.mpy --merge mod1.mpy mod2.mpy The constituent .mpy files are executed sequentially when the merged file is imported, and they all use the same global namespace. --- tools/mpy-tool.py | 60 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index cd36c909f4..8bc37734c7 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -691,7 +691,10 @@ def read_mpy(filename): raise Exception('native architecture mismatch') config.mp_small_int_bits = header[3] qstr_win = QStrWindow(qw_size) - return read_raw_code(f, qstr_win) + rc = read_raw_code(f, qstr_win) + rc.mpy_source_file = filename + rc.qstr_win_size = qw_size + return rc def dump_mpy(raw_codes): for rc in raw_codes: @@ -789,6 +792,55 @@ def freeze_mpy(base_qstrs, raw_codes): print(' &raw_code_%s,' % rc.escaped_name) print('};') +def merge_mpy(raw_codes, output_file): + assert len(raw_codes) <= 31 # so var-uints all fit in 1 byte + merged_mpy = bytearray() + + if len(raw_codes) == 1: + with open(raw_codes[0].mpy_source_file, 'rb') as f: + merged_mpy.extend(f.read()) + else: + header = bytearray(5) + header[0] = ord('M') + header[1] = config.MPY_VERSION + header[2] = (config.native_arch << 2 + | config.MICROPY_PY_BUILTINS_STR_UNICODE << 1 + | config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) + header[3] = config.mp_small_int_bits + header[4] = 32 # qstr_win_size + merged_mpy.extend(header) + + bytecode = bytearray() + bytecode_len = 6 + len(raw_codes) * 4 + 2 + bytecode.append(bytecode_len << 2) # kind and length + bytecode.append(0b00000000) # signature prelude + bytecode.append(0b00001000) # size prelude + bytecode.extend(b'\x00\x01') # MP_QSTR_ + bytecode.extend(b'\x00\x01') # MP_QSTR_ + for idx in range(len(raw_codes)): + bytecode.append(0x32) # MP_BC_MAKE_FUNCTION + bytecode.append(idx) # index raw code + bytecode.extend(b'\x34\x00') # MP_BC_CALL_FUNCTION, 0 args + bytecode.extend(b'\x51\x63') # MP_BC_LOAD_NONE, MP_BC_RETURN_VALUE + + bytecode.append(0) # n_obj + bytecode.append(len(raw_codes)) # n_raw_code + + merged_mpy.extend(bytecode) + + for rc in raw_codes: + with open(rc.mpy_source_file, 'rb') as f: + f.read(4) # skip header + read_uint(f) # skip qstr_win_size + data = f.read() # read rest of mpy file + merged_mpy.extend(data) + + if output_file is None: + sys.stdout.buffer.write(merged_mpy) + else: + with open(output_file, 'wb') as f: + f.write(merged_mpy) + def main(): import argparse cmd_parser = argparse.ArgumentParser(description='A tool to work with MicroPython .mpy files.') @@ -796,12 +848,16 @@ def main(): help='dump contents of files') cmd_parser.add_argument('-f', '--freeze', action='store_true', help='freeze files') + cmd_parser.add_argument('--merge', action='store_true', + help='merge multiple .mpy files into one') cmd_parser.add_argument('-q', '--qstr-header', help='qstr header file to freeze against') cmd_parser.add_argument('-mlongint-impl', choices=['none', 'longlong', 'mpz'], default='mpz', help='long-int implementation used by target (default mpz)') cmd_parser.add_argument('-mmpz-dig-size', metavar='N', type=int, default=16, help='mpz digit size used by target (default 16)') + cmd_parser.add_argument('-o', '--output', default=None, + help='output file') cmd_parser.add_argument('files', nargs='+', help='input .mpy files') args = cmd_parser.parse_args() @@ -835,6 +891,8 @@ def main(): except FreezeError as er: print(er, file=sys.stderr) sys.exit(1) + elif args.merge: + merged_mpy = merge_mpy(raw_codes, args.output) if __name__ == '__main__': main() From aad79adab7285cbe1c1b975fcd490542fd3ab85c Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 28 Aug 2019 17:03:08 +1000 Subject: [PATCH 1035/1788] tools/mpy_ld.py: Add new mpy_ld.py tool and associated build files. This commit adds a new tool called mpy_ld.py which is essentially a linker that builds .mpy files directly from .o files. A new header file (dynruntime.h) and makefile fragment (dynruntime.mk) are also included which allow building .mpy files from C source code. Such .mpy files can then be dynamically imported as though they were a normal Python module, even though they are implemented in C. Converting .o files directly (rather than pre-linked .elf files) allows the resulting .mpy to be more efficient because it has more control over the relocations; for example it can skip PLT indirection. Doing it this way also allows supporting more architectures, such as Xtensa which has specific needs for position-independent code and the GOT. The tool supports targets of x86, x86-64, ARM Thumb and Xtensa (windowed and non-windowed). BSS, text and rodata sections are supported, with relocations to all internal sections and symbols, as well as relocations to some external symbols (defined by dynruntime.h), and linking of qstrs. --- py/dynruntime.h | 193 ++++++++++ py/dynruntime.mk | 134 +++++++ tools/mpy_ld.py | 978 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1305 insertions(+) create mode 100644 py/dynruntime.h create mode 100644 py/dynruntime.mk create mode 100755 tools/mpy_ld.py diff --git a/py/dynruntime.h b/py/dynruntime.h new file mode 100644 index 0000000000..34cf6010c4 --- /dev/null +++ b/py/dynruntime.h @@ -0,0 +1,193 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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_DYNRUNTIME_H +#define MICROPY_INCLUDED_PY_DYNRUNTIME_H + +// This header file contains definitions to dynamically implement the static +// MicroPython runtime API defined in py/obj.h and py/runtime.h. + +#include "py/nativeglue.h" +#include "py/objstr.h" + +#undef MP_ROM_QSTR +#undef MP_OBJ_QSTR_VALUE +#undef MP_OBJ_NEW_QSTR +#undef mp_const_none +#undef mp_const_false +#undef mp_const_true +#undef mp_const_empty_tuple +#undef nlr_raise + +/******************************************************************************/ +// Memory allocation + +#define m_malloc(n) (m_malloc_dyn((n))) +#define m_free(ptr) (m_free_dyn((ptr))) +#define m_realloc(ptr, new_num_bytes) (m_realloc_dyn((ptr), (new_num_bytes))) + +static inline void *m_malloc_dyn(size_t n) { + // TODO won't raise on OOM + return mp_fun_table.realloc_(NULL, n, false); +} + +static inline void m_free_dyn(void *ptr) { + mp_fun_table.realloc_(ptr, 0, false); +} + +static inline void *m_realloc_dyn(void *ptr, size_t new_num_bytes) { + // TODO won't raise on OOM + return mp_fun_table.realloc_(ptr, new_num_bytes, true); +} + +/******************************************************************************/ +// Printing + +#define mp_plat_print (*mp_fun_table.plat_print) +#define mp_printf(p, ...) (mp_fun_table.printf_((p), __VA_ARGS__)) +#define mp_vprintf(p, fmt, args) (mp_fun_table.vprintf_((p), (fmt), (args))) + +/******************************************************************************/ +// Types and objects + +#define MP_OBJ_NEW_QSTR(x) MP_OBJ_NEW_QSTR_ ## x + +#define mp_type_type (*mp_fun_table.type_type) +#define mp_type_str (*mp_fun_table.type_str) +#define mp_type_list (*mp_fun_table.type_list) +#define mp_type_EOFError (*(mp_obj_type_t*)(mp_load_global(MP_QSTR_EOFError))) +#define mp_type_IndexError (*(mp_obj_type_t*)(mp_load_global(MP_QSTR_IndexError))) +#define mp_type_KeyError (*(mp_obj_type_t*)(mp_load_global(MP_QSTR_KeyError))) +#define mp_type_NotImplementedError (*(mp_obj_type_t*)(mp_load_global(MP_QSTR_NotImplementedError))) +#define mp_type_RuntimeError (*(mp_obj_type_t*)(mp_load_global(MP_QSTR_RuntimeError))) +#define mp_type_TypeError (*(mp_obj_type_t*)(mp_load_global(MP_QSTR_TypeError))) +#define mp_type_ValueError (*(mp_obj_type_t*)(mp_load_global(MP_QSTR_ValueError))) + +#define mp_stream_read_obj (*mp_fun_table.stream_read_obj) +#define mp_stream_readinto_obj (*mp_fun_table.stream_readinto_obj) +#define mp_stream_unbuffered_readline_obj (*mp_fun_table.stream_unbuffered_readline_obj) +#define mp_stream_write_obj (*mp_fun_table.stream_write_obj) + +#define mp_const_none ((mp_obj_t)mp_fun_table.const_none) +#define mp_const_false ((mp_obj_t)mp_fun_table.const_false) +#define mp_const_true ((mp_obj_t)mp_fun_table.const_true) +#define mp_const_empty_tuple (mp_fun_table.new_tuple(0, NULL)) + +#define mp_obj_new_bool(b) ((b) ? (mp_obj_t)mp_fun_table.const_true : (mp_obj_t)mp_fun_table.const_false) +#define mp_obj_new_int(i) (mp_fun_table.native_to_obj(i, MP_NATIVE_TYPE_INT)) +#define mp_obj_new_str(data, len) (mp_fun_table.obj_new_str((data), (len))) +#define mp_obj_new_str_of_type(t, d, l) (mp_obj_new_str_of_type_dyn((t), (d), (l))) +#define mp_obj_new_bytes(data, len) (mp_fun_table.obj_new_bytes((data), (len))) +#define mp_obj_new_bytearray_by_ref(n, i) (mp_fun_table.obj_new_bytearray_by_ref((n), (i))) +#define mp_obj_new_tuple(n, items) (mp_fun_table.new_tuple((n), (items))) +#define mp_obj_new_list(n, items) (mp_fun_table.new_list((n), (items))) + +#define mp_obj_get_type(o) (mp_fun_table.obj_get_type((o))) +#define mp_obj_get_int(o) (mp_fun_table.native_from_obj(o, MP_NATIVE_TYPE_INT)) +#define mp_obj_str_get_str(s) ((void*)mp_fun_table.native_from_obj(s, MP_NATIVE_TYPE_PTR)) +#define mp_obj_str_get_data(o, len) (mp_obj_str_get_data_dyn((o), (len))) +#define mp_get_buffer_raise(o, bufinfo, fl) (mp_fun_table.get_buffer_raise((o), (bufinfo), (fl))) +#define mp_get_stream_raise(s, flags) (mp_fun_table.get_stream_raise((s), (flags))) + +#define mp_obj_list_append(list, item) (mp_fun_table.list_append((list), (item))) + +static inline mp_obj_t mp_obj_new_str_of_type_dyn(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); + } +} + +static inline void *mp_obj_str_get_data_dyn(mp_obj_t o, size_t *l) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(o, &bufinfo, MP_BUFFER_READ); + *l = bufinfo.len; + return bufinfo.buf; +} + +/******************************************************************************/ +// General runtime functions + +#define mp_load_name(qst) (mp_fun_table.load_name(qst)) +#define mp_load_global(qst) (mp_fun_table.load_global(qst)) +#define mp_store_global(qst, obj) (mp_fun_table.store_global((qst), (obj))) +#define mp_unary_op(op, obj) (mp_fun_table.unary_op((op), (obj))) +#define mp_binary_op(op, lhs, rhs) (mp_fun_table.binary_op((op), (lhs), (rhs))) + +#define mp_make_function_from_raw_code(rc, def_args, def_kw_args) \ + (mp_fun_table.make_function_from_raw_code((rc), (def_args), (def_kw_args))) + +#define mp_call_function_n_kw(fun, n_args, n_kw, args) \ + (mp_fun_table.call_function_n_kw((fun), (n_args) | ((n_kw) << 8), args)) + +#define mp_arg_check_num(n_args, n_kw, n_args_min, n_args_max, takes_kw) \ + (mp_fun_table.arg_check_num_sig((n_args), (n_kw), MP_OBJ_FUN_MAKE_SIG((n_args_min), (n_args_max), (takes_kw)))) + +#define MP_DYNRUNTIME_INIT_ENTRY \ + mp_obj_t old_globals = mp_fun_table.swap_globals(self->globals); \ + mp_raw_code_t rc; \ + rc.kind = MP_CODE_NATIVE_VIPER; \ + rc.scope_flags = 0; \ + rc.const_table = (void*)self->const_table; \ + (void)rc; + +#define MP_DYNRUNTIME_INIT_EXIT \ + mp_fun_table.swap_globals(old_globals); \ + return mp_const_none; + +#define MP_DYNRUNTIME_MAKE_FUNCTION(f) \ + (mp_make_function_from_raw_code((rc.fun_data = (f), &rc), MP_OBJ_NULL, MP_OBJ_NULL)) + +/******************************************************************************/ +// Exceptions + +#define mp_obj_new_exception(o) ((mp_obj_t)(o)) // Assumes returned object will be raised, will create instance then +#define mp_obj_new_exception_arg1(e_type, arg) (mp_obj_new_exception_arg1_dyn((e_type), (arg))) + +#define nlr_raise(o) (mp_raise_dyn(o)) +#define mp_raise_msg(type, msg) (mp_fun_table.raise_msg((type), (msg))) +#define mp_raise_OSError(er) (mp_raise_OSError_dyn(er)) +#define mp_raise_NotImplementedError(msg) (mp_raise_msg(&mp_type_NotImplementedError, (msg))) +#define mp_raise_TypeError(msg) (mp_raise_msg(&mp_type_TypeError, (msg))) +#define mp_raise_ValueError(msg) (mp_raise_msg(&mp_type_ValueError, (msg))) + +static inline mp_obj_t mp_obj_new_exception_arg1_dyn(const mp_obj_type_t *exc_type, mp_obj_t arg) { + mp_obj_t args[1] = { arg }; + return mp_call_function_n_kw(MP_OBJ_FROM_PTR(exc_type), 1, 0, &args[0]); +} + +static NORETURN inline void mp_raise_dyn(mp_obj_t o) { + mp_fun_table.raise(o); + for (;;) { + } +} + +static inline void mp_raise_OSError_dyn(int er) { + mp_obj_t args[1] = { MP_OBJ_NEW_SMALL_INT(er) }; + nlr_raise(mp_call_function_n_kw(mp_load_global(MP_QSTR_OSError), 1, 0, &args[0])); +} + +#endif // MICROPY_INCLUDED_PY_DYNRUNTIME_H diff --git a/py/dynruntime.mk b/py/dynruntime.mk new file mode 100644 index 0000000000..b01b80e0dd --- /dev/null +++ b/py/dynruntime.mk @@ -0,0 +1,134 @@ +# Makefile fragment for generating native .mpy files from C source +# MPY_DIR must be set to the top of the MicroPython source tree + +BUILD ?= build + +ECHO = @echo +RM = /bin/rm +MKDIR = /bin/mkdir +PYTHON = python3 +MPY_CROSS = $(MPY_DIR)/mpy-cross/mpy-cross +MPY_TOOL = $(PYTHON) $(MPY_DIR)/tools/mpy-tool.py +MPY_LD = $(PYTHON) $(MPY_DIR)/tools/mpy_ld.py + +Q = @ +ifeq ("$(origin V)", "command line") +ifeq ($(V),1) +Q = +MPY_LD += '-vvv' +endif +endif + +ARCH_UPPER = $(shell echo $(ARCH) | tr '[:lower:]' '[:upper:]') +CONFIG_H = $(BUILD)/$(MOD).config.h + +CFLAGS += -I. -I$(MPY_DIR) +CFLAGS += -std=c99 +CFLAGS += -Os +CFLAGS += -Wall -Werror -DNDEBUG +CFLAGS += -DNO_QSTR +CFLAGS += -DMP_CONFIGFILE='<$(CONFIG_H)>' +CFLAGS += -fpic -fno-common +CFLAGS += -U _FORTIFY_SOURCE # prevent use of __*_chk libc functions +#CFLAGS += -fdata-sections -ffunction-sections + +MPY_CROSS_FLAGS += -march=$(ARCH) + +SRC_O += $(addprefix $(BUILD)/, $(patsubst %.c,%.o,$(filter %.c,$(SRC)))) +SRC_MPY += $(addprefix $(BUILD)/, $(patsubst %.py,%.mpy,$(filter %.py,$(SRC)))) + +################################################################################ +# Architecture configuration + +ifeq ($(ARCH),x86) + +# x86 +CROSS = +CFLAGS += -m32 -fno-stack-protector +MPY_CROSS_FLAGS += -mcache-lookup-bc + +else ifeq ($(ARCH),x64) + +# x64 +CROSS = +CFLAGS += -fno-stack-protector +MPY_CROSS_FLAGS += -mcache-lookup-bc + +else ifeq ($(ARCH),armv7m) + +# thumb +CROSS = arm-none-eabi- +CFLAGS += -mthumb -mcpu=cortex-m3 + +else ifeq ($(ARCH),armv7emsp) + +# thumb +CROSS = arm-none-eabi- +CFLAGS += -mthumb -mcpu=cortex-m4 +CFLAGS += -mfpu=fpv4-sp-d16 -mfloat-abi=hard + +else ifeq ($(ARCH),armv7emdp) + +# thumb +CROSS = arm-none-eabi- +CFLAGS += -mthumb -mcpu=cortex-m7 +CFLAGS += -mfpu=fpv5-d16 -mfloat-abi=hard + +else ifeq ($(ARCH),xtensa) + +# xtensa +CROSS = xtensa-lx106-elf- +CFLAGS += -mforce-l32 + +else ifeq ($(ARCH),xtensawin) + +# xtensawin +CROSS = xtensa-esp32-elf- +CFLAGS += + +else +$(error architecture '$(ARCH)' not supported) +endif + +CFLAGS += $(CFLAGS_EXTRA) + +################################################################################ +# Build rules + +.PHONY: all clean + +all: $(MOD).mpy + +clean: + $(RM) -rf $(BUILD) $(CLEAN_EXTRA) + +# Create build destination directories first +BUILD_DIRS = $(sort $(dir $(CONFIG_H) $(SRC_O) $(SRC_MPY))) +$(CONFIG_H) $(SRC_O) $(SRC_MPY): | $(BUILD_DIRS) +$(BUILD_DIRS): + $(Q)$(MKDIR) -p $@ + +# Preprocess all source files to generate $(CONFIG_H) +$(CONFIG_H): $(SRC) + $(ECHO) "GEN $@" + $(Q)$(MPY_LD) --arch $(ARCH) --preprocess -o $@ $^ + +# Build .o from .c source files +$(BUILD)/%.o: %.c $(CONFIG_H) Makefile + $(ECHO) "CC $<" + $(Q)$(CROSS)gcc $(CFLAGS) -o $@ -c $< + +# Build .mpy from .py source files +$(BUILD)/%.mpy: %.py + $(ECHO) "MPY $<" + $(Q)$(MPY_CROSS) $(MPY_CROSS_FLAGS) -o $@ $< + +# Build native .mpy from object files +$(BUILD)/$(MOD).native.mpy: $(SRC_O) + $(ECHO) "LINK $<" + $(Q)$(MPY_LD) --arch $(ARCH) --qstrs $(CONFIG_H) -o $@ $^ + +# Build final .mpy from all intermediate .mpy files +$(MOD).mpy: $(BUILD)/$(MOD).native.mpy $(SRC_MPY) + $(ECHO) "GEN $@" + $(Q)$(MPY_TOOL) --merge -o $@ $^ diff --git a/tools/mpy_ld.py b/tools/mpy_ld.py new file mode 100755 index 0000000000..07105caac9 --- /dev/null +++ b/tools/mpy_ld.py @@ -0,0 +1,978 @@ +#!/usr/bin/env python3 +# +# This file is part of the MicroPython project, http://micropython.org/ +# +# The MIT License (MIT) +# +# Copyright (c) 2019 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. + +""" +Link .o files to .mpy +""" + +import sys, os, struct, re +from elftools.elf import elffile + +sys.path.append(os.path.dirname(__file__) + '/../py') +import makeqstrdata as qstrutil + +# MicroPython constants +MPY_VERSION = 5 +MP_NATIVE_ARCH_X86 = 1 +MP_NATIVE_ARCH_X64 = 2 +MP_NATIVE_ARCH_ARMV7M = 5 +MP_NATIVE_ARCH_ARMV7EMSP = 7 +MP_NATIVE_ARCH_ARMV7EMDP = 8 +MP_NATIVE_ARCH_XTENSA = 9 +MP_NATIVE_ARCH_XTENSAWIN = 10 +MP_CODE_BYTECODE = 2 +MP_CODE_NATIVE_VIPER = 4 +MP_SCOPE_FLAG_VIPERRELOC = 0x10 +MP_SCOPE_FLAG_VIPERRODATA = 0x20 +MP_SCOPE_FLAG_VIPERBSS = 0x40 +MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE = 1 +MICROPY_PY_BUILTINS_STR_UNICODE = 2 +MP_SMALL_INT_BITS = 31 +QSTR_WINDOW_SIZE = 32 + +# ELF constants +R_386_32 = 1 +R_X86_64_64 = 1 +R_XTENSA_32 = 1 +R_386_PC32 = 2 +R_X86_64_PC32 = 2 +R_ARM_ABS32 = 2 +R_386_GOT32 = 3 +R_ARM_REL32 = 3 +R_386_PLT32 = 4 +R_X86_64_PLT32 = 4 +R_XTENSA_PLT = 6 +R_386_GOTOFF = 9 +R_386_GOTPC = 10 +R_ARM_THM_CALL = 10 +R_XTENSA_DIFF32 = 19 +R_XTENSA_SLOT0_OP = 20 +R_ARM_BASE_PREL = 25 # aka R_ARM_GOTPC +R_ARM_GOT_BREL = 26 # aka R_ARM_GOT32 +R_ARM_THM_JUMP24 = 30 +R_X86_64_REX_GOTPCRELX = 42 +R_386_GOT32X = 43 + +################################################################################ +# Architecture configuration + +def asm_jump_x86(entry): + return struct.pack('> 11 == 0 or b_off >> 11 == -1: + # Signed value fits in 12 bits + b0 = 0xe000 | (b_off >> 1 & 0x07ff) + b1 = 0 + else: + # Use large jump + b0 = 0xf000 | (b_off >> 12 & 0x07ff) + b1 = 0xb800 | (b_off >> 1 & 0x7ff) + return struct.pack('> 8) + +class ArchData: + def __init__(self, name, mpy_feature, qstr_entry_size, word_size, arch_got, asm_jump): + self.name = name + self.mpy_feature = mpy_feature + self.qstr_entry_size = qstr_entry_size + self.word_size = word_size + self.arch_got = arch_got + self.asm_jump = asm_jump + self.separate_rodata = name == 'EM_XTENSA' and qstr_entry_size == 4 + +ARCH_DATA = { + 'x86': ArchData( + 'EM_386', + MP_NATIVE_ARCH_X86 << 2 | MICROPY_PY_BUILTINS_STR_UNICODE | MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE, + 2, 4, (R_386_PC32, R_386_GOT32, R_386_GOT32X), asm_jump_x86, + ), + 'x64': ArchData( + 'EM_X86_64', + MP_NATIVE_ARCH_X64 << 2 | MICROPY_PY_BUILTINS_STR_UNICODE | MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE, + 2, 8, (R_X86_64_REX_GOTPCRELX,), asm_jump_x86, + ), + 'armv7m': ArchData( + 'EM_ARM', + MP_NATIVE_ARCH_ARMV7M << 2 | MICROPY_PY_BUILTINS_STR_UNICODE, + 2, 4, (R_ARM_GOT_BREL,), asm_jump_arm, + ), + 'armv7emsp': ArchData( + 'EM_ARM', + MP_NATIVE_ARCH_ARMV7EMSP << 2 | MICROPY_PY_BUILTINS_STR_UNICODE, + 2, 4, (R_ARM_GOT_BREL,), asm_jump_arm, + ), + 'armv7emdp': ArchData( + 'EM_ARM', + MP_NATIVE_ARCH_ARMV7EMDP << 2 | MICROPY_PY_BUILTINS_STR_UNICODE, + 2, 4, (R_ARM_GOT_BREL,), asm_jump_arm, + ), + 'xtensa': ArchData( + 'EM_XTENSA', + MP_NATIVE_ARCH_XTENSA << 2 | MICROPY_PY_BUILTINS_STR_UNICODE, + 2, 4, (R_XTENSA_32, R_XTENSA_PLT), asm_jump_xtensa, + ), + 'xtensawin': ArchData( + 'EM_XTENSA', + MP_NATIVE_ARCH_XTENSAWIN << 2 | MICROPY_PY_BUILTINS_STR_UNICODE, + 4, 4, (R_XTENSA_32, R_XTENSA_PLT), asm_jump_xtensa, + ), +} + +################################################################################ +# Helper functions + +def align_to(value, align): + return (value + align - 1) & ~(align - 1) + +def unpack_u24le(data, offset): + return data[offset] | data[offset + 1] << 8 | data[offset + 2] << 16 + +def pack_u24le(data, offset, value): + data[offset] = value & 0xff + data[offset + 1] = value >> 8 & 0xff + data[offset + 2] = value >> 16 & 0xff + +def xxd(text): + for i in range(0, len(text), 16): + print('{:08x}:'.format(i), end='') + for j in range(4): + off = i + j * 4 + if off < len(text): + d = int.from_bytes(text[off:off + 4], 'little') + print(' {:08x}'.format(d), end='') + print() + +# Smaller numbers are enabled first +LOG_LEVEL_1 = 1 +LOG_LEVEL_2 = 2 +LOG_LEVEL_3 = 3 +log_level = LOG_LEVEL_1 + +def log(level, msg): + if level <= log_level: + print(msg) + +################################################################################ +# Qstr extraction + +def extract_qstrs(source_files): + def read_qstrs(f): + with open(f) as f: + vals = set() + objs = set() + for line in f: + while line: + m = re.search(r'MP_OBJ_NEW_QSTR\((MP_QSTR_[A-Za-z0-9_]*)\)', line) + if m: + objs.add(m.group(1)) + else: + m = re.search(r'MP_QSTR_[A-Za-z0-9_]*', line) + if m: + vals.add(m.group()) + if m: + s = m.span() + line = line[:s[0]] + line[s[1]:] + else: + line = '' + return vals, objs + + static_qstrs = ['MP_QSTR_' + qstrutil.qstr_escape(q) for q in qstrutil.static_qstr_list] + + qstr_vals = set() + qstr_objs = set() + for f in source_files: + vals, objs = read_qstrs(f) + qstr_vals.update(vals) + qstr_objs.update(objs) + qstr_vals.difference_update(static_qstrs) + + return static_qstrs, qstr_vals, qstr_objs + +################################################################################ +# Linker + +class LinkError(Exception): + pass + +class Section: + def __init__(self, name, data, alignment, filename=None): + self.filename = filename + self.name = name + self.data = data + self.alignment = alignment + self.addr = 0 + self.reloc = [] + + @staticmethod + def from_elfsec(elfsec, filename): + assert elfsec.header.sh_addr == 0 + return Section(elfsec.name, elfsec.data(), elfsec.data_alignment, filename) + +class GOTEntry: + def __init__(self, name, sym, link_addr=0): + self.name = name + self.sym = sym + self.offset = None + self.link_addr = link_addr + + def isexternal(self): + return self.sec_name.startswith('.external') + + def istext(self): + return self.sec_name.startswith('.text') + + def isrodata(self): + return self.sec_name.startswith(('.rodata', '.data.rel.ro')) + + def isbss(self): + return self.sec_name.startswith('.bss') + +class LiteralEntry: + def __init__(self, value, offset): + self.value = value + self.offset = offset + +class LinkEnv: + def __init__(self, arch): + self.arch = ARCH_DATA[arch] + self.sections = [] # list of sections in order of output + self.literal_sections = [] # list of literal sections (xtensa only) + self.known_syms = {} # dict of symbols that are defined + self.unresolved_syms = [] # list of unresolved symbols + self.mpy_relocs = [] # list of relocations needed in the output .mpy file + + def check_arch(self, arch_name): + if arch_name != self.arch.name: + raise LinkError('incompatible arch') + + def print_sections(self): + log(LOG_LEVEL_2, 'sections:') + for sec in self.sections: + log(LOG_LEVEL_2, ' {:08x} {} size={}'.format(sec.addr, sec.name, len(sec.data))) + + def find_addr(self, name): + if name in self.known_syms: + s = self.known_syms[name] + return s.section.addr + s['st_value'] + raise LinkError('unknown symbol: {}'.format(name)) + +def build_got_generic(env): + env.got_entries = {} + for sec in env.sections: + for r in sec.reloc: + s = r.sym + if not (s.entry['st_info']['bind'] == 'STB_GLOBAL' and r['r_info_type'] in env.arch.arch_got): + continue + s_type = s.entry['st_info']['type'] + assert s_type in ('STT_NOTYPE', 'STT_FUNC', 'STT_OBJECT'), s_type + assert s.name + if s.name in env.got_entries: + continue + env.got_entries[s.name] = GOTEntry(s.name, s) + +def build_got_xtensa(env): + env.got_entries = {} + env.lit_entries = {} + env.xt_literals = {} + + # Extract the values from the literal table + for sec in env.literal_sections: + assert len(sec.data) % env.arch.word_size == 0 + + # Look through literal relocations to find any global pointers that should be GOT entries + for r in sec.reloc: + s = r.sym + s_type = s.entry['st_info']['type'] + assert s_type in ('STT_NOTYPE', 'STT_FUNC', 'STT_OBJECT', 'STT_SECTION'), s_type + assert r['r_info_type'] in env.arch.arch_got + assert r['r_offset'] % env.arch.word_size == 0 + # This entry is a global pointer + existing = struct.unpack_from(' {}+{:08x}'.format(g.offset, g.name, g.sec_name, g.link_addr)) + +def populate_lit(env): + log(LOG_LEVEL_2, 'LIT: {:08x}'.format(env.lit_section.addr)) + for lit_entry in env.lit_entries.values(): + value = lit_entry.value + log(LOG_LEVEL_2, ' {:08x} = {:08x}'.format(lit_entry.offset, value)) + o = env.lit_section.addr + lit_entry.offset + env.full_text[o:o + env.arch.word_size] = value.to_bytes(env.arch.word_size, 'little') + +def do_relocation_text(env, text_addr, r): + # Extract relevant info about symbol that's being relocated + s = r.sym + s_bind = s.entry['st_info']['bind'] + s_shndx = s.entry['st_shndx'] + s_type = s.entry['st_info']['type'] + r_offset = r['r_offset'] + text_addr + r_info_type = r['r_info_type'] + try: + # only for RELA sections + r_addend = r['r_addend'] + except KeyError: + r_addend = 0 + + # Default relocation type and name for logging + reloc_type = 'le32' + log_name = None + + if (env.arch.name == 'EM_386' and r_info_type in (R_386_PC32, R_386_PLT32) + or env.arch.name == 'EM_X86_64' and r_info_type in (R_X86_64_PC32, R_X86_64_PLT32) + or env.arch.name == 'EM_ARM' and r_info_type in (R_ARM_REL32, R_ARM_THM_CALL, R_ARM_THM_JUMP24) + or s_bind == 'STB_LOCAL' and env.arch.name == 'EM_XTENSA' and r_info_type == R_XTENSA_32 # not GOT + ): + # Standard relocation to fixed location within text/rodata + if hasattr(s, 'resolved'): + s = s.resolved + + sec = s.section + + if env.arch.separate_rodata and sec.name.startswith('.rodata'): + raise LinkError('fixed relocation to rodata with rodata referenced via GOT') + + if sec.name.startswith('.bss'): + raise LinkError('{}: fixed relocation to bss (bss variables can\'t be static)'.format(s.filename)) + + if sec.name.startswith('.external'): + raise LinkError('{}: fixed relocation to external symbol: {}'.format(s.filename, s.name)) + + addr = sec.addr + s['st_value'] + reloc = addr - r_offset + r_addend + + if r_info_type in (R_ARM_THM_CALL, R_ARM_THM_JUMP24): + # Both relocations have the same bit pattern to rewrite: + # R_ARM_THM_CALL: bl + # R_ARM_THM_JUMP24: b.w + reloc_type = 'thumb_b' + + elif (env.arch.name == 'EM_386' and r_info_type == R_386_GOTPC + or env.arch.name == 'EM_ARM' and r_info_type == R_ARM_BASE_PREL + ): + # Relocation to GOT address itself + assert s.name == '_GLOBAL_OFFSET_TABLE_' + addr = env.got_section.addr + reloc = addr - r_offset + r_addend + + elif (env.arch.name == 'EM_386' and r_info_type in (R_386_GOT32, R_386_GOT32X) + or env.arch.name == 'EM_ARM' and r_info_type == R_ARM_GOT_BREL + ): + # Relcation pointing to GOT + reloc = addr = env.got_entries[s.name].offset + + elif env.arch.name == 'EM_X86_64' and r_info_type == R_X86_64_REX_GOTPCRELX: + # Relcation pointing to GOT + got_entry = env.got_entries[s.name] + addr = env.got_section.addr + got_entry.offset + reloc = addr - r_offset + r_addend + + elif env.arch.name == 'EM_386' and r_info_type == R_386_GOTOFF: + # Relocation relative to GOT + addr = s.section.addr + s['st_value'] + reloc = addr - env.got_section.addr + r_addend + + elif env.arch.name == 'EM_XTENSA' and r_info_type == R_XTENSA_SLOT0_OP: + # Relocation pointing to GOT, xtensa specific + sec = s.section + if sec.name.startswith('.text'): + # it looks like R_XTENSA_SLOT0_OP into .text is already correctly relocated + return + assert sec.name.startswith('.literal'), sec.name + lit_idx = '{}+0x{:x}'.format(sec.filename, r_addend) + lit_ptr = env.xt_literals[lit_idx] + if isinstance(lit_ptr, str): + addr = env.got_section.addr + env.got_entries[lit_ptr].offset + log_name = 'GOT {}'.format(lit_ptr) + else: + addr = env.lit_section.addr + env.lit_entries[lit_ptr].offset + log_name = 'LIT' + reloc = addr - r_offset + reloc_type = 'xtensa_l32r' + + elif env.arch.name == 'EM_XTENSA' and r_info_type == R_XTENSA_DIFF32: + if s.section.name.startswith('.text'): + # it looks like R_XTENSA_DIFF32 into .text is already correctly relocated + return + assert 0 + + else: + # Unknown/unsupported relocation + assert 0, r_info_type + + # Write relocation + if reloc_type == 'le32': + existing, = struct.unpack_from('= 0x400000: # 2's complement + existing -= 0x800000 + new = existing + reloc + b_h = (b_h & 0xf800) | (new >> 12) & 0x7ff + b_l = (b_l & 0xf800) | (new >> 1) & 0x7ff + struct.pack_into('> 8 + l32r_imm16 = (l32r_imm16 + reloc >> 2) & 0xffff + l32r = l32r & 0xff | l32r_imm16 << 8 + pack_u24le(env.full_text, r_offset, l32r) + else: + assert 0, reloc_type + + # Log information about relocation + if log_name is None: + if s_type == 'STT_SECTION': + log_name = s.section.name + else: + log_name = s.name + log(LOG_LEVEL_3, ' {:08x} {} -> {:08x}'.format(r_offset, log_name, addr)) + +def do_relocation_data(env, text_addr, r): + s = r.sym + s_type = s.entry['st_info']['type'] + r_offset = r['r_offset'] + text_addr + r_info_type = r['r_info_type'] + try: + # only for RELA sections + r_addend = r['r_addend'] + except KeyError: + r_addend = 0 + + if (env.arch.name == 'EM_386' and r_info_type == R_386_32 + or env.arch.name == 'EM_X86_64' and r_info_type == R_X86_64_64 + or env.arch.name == 'EM_ARM' and r_info_type == R_ARM_ABS32 + or env.arch.name == 'EM_XTENSA' and r_info_type == R_XTENSA_32): + # Relocation in data.rel.ro to internal/external symbol + if env.arch.word_size == 4: + struct_type = ' {} {:08x}'.format(r_offset, log_name, addr)) + if env.arch.separate_rodata: + data = env.full_rodata + else: + data = env.full_text + existing, = struct.unpack_from(struct_type, data, r_offset) + if sec.name.startswith(('.text', '.rodata', '.data.rel.ro', '.bss')): + struct.pack_into(struct_type, data, r_offset, existing + addr) + kind = sec.name + elif sec.name == '.external.mp_fun_table': + assert addr == 0 + kind = s.mp_fun_table_offset + else: + assert 0, sec.name + if env.arch.separate_rodata: + base = '.rodata' + else: + base = '.text' + env.mpy_relocs.append((base, r_offset, kind)) + + else: + # Unknown/unsupported relocation + assert 0, r_info_type + +def load_object_file(env, felf): + with open(felf, 'rb') as f: + elf = elffile.ELFFile(f) + env.check_arch(elf['e_machine']) + + # Get symbol table + symtab = list(elf.get_section_by_name('.symtab').iter_symbols()) + + # Load needed sections from ELF file + sections_shndx = {} # maps elf shndx to Section object + for idx, s in enumerate(elf.iter_sections()): + if s.header.sh_type in ('SHT_PROGBITS', 'SHT_NOBITS'): + if s.data_size == 0: + # Ignore empty sections + pass + elif s.name.startswith(('.literal', '.text', '.rodata', '.data.rel.ro', '.bss')): + sec = Section.from_elfsec(s, felf) + sections_shndx[idx] = sec + if s.name.startswith('.literal'): + env.literal_sections.append(sec) + else: + env.sections.append(sec) + elif s.name.startswith('.data'): + raise LinkError('{}: {} non-empty'.format(felf, s.name)) + else: + # Ignore section + pass + elif s.header.sh_type in ('SHT_REL', 'SHT_RELA'): + shndx = s.header.sh_info + if shndx in sections_shndx: + sec = sections_shndx[shndx] + sec.reloc_name = s.name + sec.reloc = list(s.iter_relocations()) + for r in sec.reloc: + r.sym = symtab[r['r_info_sym']] + + # Link symbols to their sections, and update known and unresolved symbols + for sym in symtab: + sym.filename = felf + shndx = sym.entry['st_shndx'] + if shndx in sections_shndx: + # Symbol with associated section + sym.section = sections_shndx[shndx] + if sym['st_info']['bind'] == 'STB_GLOBAL': + # Defined global symbol + if sym.name in env.known_syms and not sym.name.startswith('__x86.get_pc_thunk.'): + raise LinkError('duplicate symbol: {}'.format(sym.name)) + env.known_syms[sym.name] = sym + elif sym.entry['st_shndx'] == 'SHN_UNDEF' and sym['st_info']['bind'] == 'STB_GLOBAL': + # Undefined global symbol, needs resolving + env.unresolved_syms.append(sym) + +def link_objects(env, native_qstr_vals_len, native_qstr_objs_len): + # Build GOT information + if env.arch.name == 'EM_XTENSA': + build_got_xtensa(env) + else: + build_got_generic(env) + + # Creat GOT section + got_size = len(env.got_entries) * env.arch.word_size + env.got_section = Section('GOT', bytearray(got_size), env.arch.word_size) + if env.arch.name == 'EM_XTENSA': + env.sections.insert(0, env.got_section) + else: + env.sections.append(env.got_section) + + # Create optional literal section + if env.arch.name == 'EM_XTENSA': + lit_size = len(env.lit_entries) * env.arch.word_size + env.lit_section = Section('LIT', bytearray(lit_size), env.arch.word_size) + env.sections.insert(1, env.lit_section) + + # Create section to contain mp_native_qstr_val_table + env.qstr_val_section = Section('.text.QSTR_VAL', bytearray(native_qstr_vals_len * env.arch.qstr_entry_size), env.arch.qstr_entry_size) + env.sections.append(env.qstr_val_section) + + # Create section to contain mp_native_qstr_obj_table + env.qstr_obj_section = Section('.text.QSTR_OBJ', bytearray(native_qstr_objs_len * env.arch.word_size), env.arch.word_size) + env.sections.append(env.qstr_obj_section) + + # Resolve unknown symbols + mp_fun_table_sec = Section('.external.mp_fun_table', b'', 0) + fun_table = {key: 63 + idx + for idx, key in enumerate([ + 'mp_type_type', + 'mp_type_str', + 'mp_type_list', + 'mp_type_dict', + 'mp_type_fun_builtin_0', + 'mp_type_fun_builtin_1', + 'mp_type_fun_builtin_2', + 'mp_type_fun_builtin_3', + 'mp_type_fun_builtin_var', + 'mp_stream_read_obj', + 'mp_stream_readinto_obj', + 'mp_stream_unbuffered_readline_obj', + 'mp_stream_write_obj', + ]) + } + for sym in env.unresolved_syms: + assert sym['st_value'] == 0 + if sym.name == '_GLOBAL_OFFSET_TABLE_': + pass + elif sym.name == 'mp_fun_table': + sym.section = Section('.external', b'', 0) + elif sym.name == 'mp_native_qstr_val_table': + sym.section = env.qstr_val_section + elif sym.name == 'mp_native_qstr_obj_table': + sym.section = env.qstr_obj_section + elif sym.name in env.known_syms: + sym.resolved = env.known_syms[sym.name] + else: + if sym.name in fun_table: + sym.section = mp_fun_table_sec + sym.mp_fun_table_offset = fun_table[sym.name] + else: + raise LinkError('{}: undefined symbol: {}'.format(sym.filename, sym.name)) + + # Align sections, assign their addresses, and create full_text + env.full_text = bytearray(env.arch.asm_jump(8)) # dummy, to be filled in later + env.full_rodata = bytearray(0) + env.full_bss = bytearray(0) + for sec in env.sections: + if env.arch.separate_rodata and sec.name.startswith(('.rodata', '.data.rel.ro')): + data = env.full_rodata + elif sec.name.startswith('.bss'): + data = env.full_bss + else: + data = env.full_text + sec.addr = align_to(len(data), sec.alignment) + data.extend(b'\x00' * (sec.addr - len(data))) + data.extend(sec.data) + + env.print_sections() + + populate_got(env) + if env.arch.name == 'EM_XTENSA': + populate_lit(env) + + # Fill in relocations + for sec in env.sections: + if not sec.reloc: + continue + log(LOG_LEVEL_3, '{}: {} relocations via {}:'.format(sec.filename, sec.name, sec.reloc_name)) + for r in sec.reloc: + if sec.name.startswith(('.text', '.rodata')): + do_relocation_text(env, sec.addr, r) + elif sec.name.startswith('.data.rel.ro'): + do_relocation_data(env, sec.addr, r) + else: + assert 0, sec.name + +################################################################################ +# .mpy output + +class MPYOutput: + def open(self, fname): + self.f = open(fname, 'wb') + self.prev_base = -1 + self.prev_offset = -1 + + def close(self): + self.f.close() + + def write_bytes(self, buf): + self.f.write(buf) + + def write_uint(self, val): + b = bytearray() + b.insert(0, val & 0x7f) + val >>= 7 + while val: + b.insert(0, 0x80 | (val & 0x7f)) + val >>= 7 + self.write_bytes(b) + + def write_qstr(self, s): + if s in qstrutil.static_qstr_list: + self.write_bytes(bytes([0, qstrutil.static_qstr_list.index(s) + 1])) + else: + s = bytes(s, 'ascii') + self.write_uint(len(s) << 1) + self.write_bytes(s) + + def write_obj(self, o): + if o is Ellipsis: + self.write_bytes(b'e') + return + else: + # Other Python types not implemented + assert 0 + + def write_reloc(self, base, offset, dest, n): + need_offset = not (base == self.prev_base and offset == self.prev_offset + 1) + self.prev_offset = offset + n - 1 + if dest <= 2: + dest = (dest << 1) | (n > 1) + else: + assert 6 <= dest <= 127 + assert n == 1 + dest = dest << 1 | need_offset + assert 0 <= dest <= 0xfe, dest + self.write_bytes(bytes([dest])) + if need_offset: + if base == '.text': + base = 0 + elif base == '.rodata': + base = 1 + self.write_uint(offset << 1 | base) + if n > 1: + self.write_uint(n) + +def build_mpy(env, entry_offset, fmpy, native_qstr_vals, native_qstr_objs): + # Write jump instruction to start of text + jump = env.arch.asm_jump(entry_offset) + env.full_text[:len(jump)] = jump + + log(LOG_LEVEL_1, 'arch: {}'.format(env.arch.name)) + log(LOG_LEVEL_1, 'text size: {}'.format(len(env.full_text))) + if len(env.full_rodata): + log(LOG_LEVEL_1, 'rodata size: {}'.format(len(env.full_rodata))) + log(LOG_LEVEL_1, 'bss size: {}'.format(len(env.full_bss))) + log(LOG_LEVEL_1, 'GOT entries: {}'.format(len(env.got_entries))) + + #xxd(env.full_text) + + out = MPYOutput() + out.open(fmpy) + + # MPY: header + out.write_bytes(bytearray([ + ord('M'), + MPY_VERSION, + env.arch.mpy_feature, + MP_SMALL_INT_BITS, + QSTR_WINDOW_SIZE, + ])) + + # MPY: kind/len + out.write_uint(len(env.full_text) << 2 | (MP_CODE_NATIVE_VIPER - MP_CODE_BYTECODE)) + + # MPY: machine code + out.write_bytes(env.full_text) + + # MPY: n_qstr_link (assumes little endian) + out.write_uint(len(native_qstr_vals) + len(native_qstr_objs)) + for q in range(len(native_qstr_vals)): + off = env.qstr_val_section.addr + q * env.arch.qstr_entry_size + out.write_uint(off << 2) + out.write_qstr(native_qstr_vals[q]) + for q in range(len(native_qstr_objs)): + off = env.qstr_obj_section.addr + q * env.arch.word_size + out.write_uint(off << 2 | 3) + out.write_qstr(native_qstr_objs[q]) + + # MPY: scope_flags + scope_flags = MP_SCOPE_FLAG_VIPERRELOC + if len(env.full_rodata): + scope_flags |= MP_SCOPE_FLAG_VIPERRODATA + if len(env.full_bss): + scope_flags |= MP_SCOPE_FLAG_VIPERBSS + out.write_uint(scope_flags) + + # MPY: n_obj + out.write_uint(bool(len(env.full_rodata)) + bool(len(env.full_bss))) + + # MPY: n_raw_code + out.write_uint(0) + + # MPY: optional bytes object with rodata + if len(env.full_rodata): + out.write_obj(Ellipsis) + if len(env.full_bss): + out.write_obj(Ellipsis) + + # MPY: rodata and/or bss + if len(env.full_rodata): + rodata_const_table_idx = 1 + out.write_uint(len(env.full_rodata)) + out.write_bytes(env.full_rodata) + if len(env.full_bss): + bss_const_table_idx = bool(env.full_rodata) + 1 + out.write_uint(len(env.full_bss)) + + # MPY: relocation information + prev_kind = None + for base, addr, kind in env.mpy_relocs: + if isinstance(kind, str) and kind.startswith('.text'): + kind = 0 + elif kind in ('.rodata', '.data.rel.ro'): + if env.arch.separate_rodata: + kind = rodata_const_table_idx + else: + kind = 0 + elif isinstance(kind, str) and kind.startswith('.bss'): + kind = bss_const_table_idx + elif kind == 'mp_fun_table': + kind = 6 + else: + kind = 7 + kind + assert addr % env.arch.word_size == 0, addr + offset = addr // env.arch.word_size + if kind == prev_kind and base == prev_base and offset == prev_offset + 1: + prev_n += 1 + prev_offset += 1 + else: + if prev_kind is not None: + out.write_reloc(prev_base, prev_offset - prev_n + 1, prev_kind, prev_n) + prev_kind = kind + prev_base = base + prev_offset = offset + prev_n = 1 + if prev_kind is not None: + out.write_reloc(prev_base, prev_offset - prev_n + 1, prev_kind, prev_n) + + # MPY: sentinel for end of relocations + out.write_bytes(b'\xff') + + out.close() + +################################################################################ +# main + +def do_preprocess(args): + if args.output is None: + assert args.files[0].endswith('.c') + args.output = args.files[0][:-1] + 'config.h' + static_qstrs, qstr_vals, qstr_objs = extract_qstrs(args.files) + with open(args.output, 'w') as f: + print('#include \n' + 'typedef uintptr_t mp_uint_t;\n' + 'typedef intptr_t mp_int_t;\n' + 'typedef uintptr_t mp_off_t;', file=f) + for i, q in enumerate(static_qstrs): + print('#define %s (%u)' % (q, i + 1), file=f) + for i, q in enumerate(sorted(qstr_vals)): + print('#define %s (mp_native_qstr_val_table[%d])' % (q, i), file=f) + for i, q in enumerate(sorted(qstr_objs)): + print('#define MP_OBJ_NEW_QSTR_%s ((mp_obj_t)mp_native_qstr_obj_table[%d])' % (q, i), file=f) + if args.arch == 'xtensawin': + qstr_type = 'uint32_t' # esp32 can only read 32-bit values from IRAM + else: + qstr_type = 'uint16_t' + print('extern const {} mp_native_qstr_val_table[];'.format(qstr_type), file=f) + print('extern const mp_uint_t mp_native_qstr_obj_table[];', file=f) + +def do_link(args): + if args.output is None: + assert args.files[0].endswith('.o') + args.output = args.files[0][:-1] + 'mpy' + native_qstr_vals = [] + native_qstr_objs = [] + if args.qstrs is not None: + with open(args.qstrs) as f: + for l in f: + m = re.match(r'#define MP_QSTR_([A-Za-z0-9_]*) \(mp_native_', l) + if m: + native_qstr_vals.append(m.group(1)) + else: + m = re.match(r'#define MP_OBJ_NEW_QSTR_MP_QSTR_([A-Za-z0-9_]*)', l) + if m: + native_qstr_objs.append(m.group(1)) + log(LOG_LEVEL_2, 'qstr vals: ' + ', '.join(native_qstr_vals)) + log(LOG_LEVEL_2, 'qstr objs: ' + ', '.join(native_qstr_objs)) + env = LinkEnv(args.arch) + try: + for file in args.files: + load_object_file(env, file) + link_objects(env, len(native_qstr_vals), len(native_qstr_objs)) + build_mpy(env, env.find_addr('mpy_init'), args.output, native_qstr_vals, native_qstr_objs) + except LinkError as er: + print('LinkError:', er.args[0]) + sys.exit(1) + +def main(): + import argparse + cmd_parser = argparse.ArgumentParser(description='Run scripts on the pyboard.') + cmd_parser.add_argument('--verbose', '-v', action='count', default=1, help='increase verbosity') + cmd_parser.add_argument('--arch', default='x64', help='architecture') + cmd_parser.add_argument('--preprocess', action='store_true', help='preprocess source files') + cmd_parser.add_argument('--qstrs', default=None, help='file defining additional qstrs') + cmd_parser.add_argument('--output', '-o', default=None, help='output .mpy file (default to input with .o->.mpy)') + cmd_parser.add_argument('files', nargs='+', help='input files') + args = cmd_parser.parse_args() + + global log_level + log_level = args.verbose + + if args.preprocess: + do_preprocess(args) + else: + do_link(args) + +if __name__ == '__main__': + main() From e5acd06ad5b7cc144fb26d29baaa041ced065d45 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 5 Nov 2019 11:37:36 +1100 Subject: [PATCH 1036/1788] extmod/modbtree: Use mp_printf instead of printf. --- extmod/modbtree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extmod/modbtree.c b/extmod/modbtree.c index 2a08a9cab0..88129e2102 100644 --- a/extmod/modbtree.c +++ b/extmod/modbtree.c @@ -60,7 +60,7 @@ STATIC const mp_obj_type_t btree_type; } void __dbpanic(DB *db) { - printf("__dbpanic(%p)\n", db); + mp_printf(&mp_plat_print, "__dbpanic(%p)\n", db); } STATIC mp_obj_btree_t *btree_new(DB *db) { From bbeaafd9aa0378a4478b0e82d355bd0eee953c84 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 5 Nov 2019 11:38:01 +1100 Subject: [PATCH 1037/1788] extmod: Add dynamic-runtime guards to btree/framebuf/uheapq/ure/uzlib. So they can be built as dynamic native modules, as well as existing static native modules. --- extmod/modbtree.c | 6 ++++++ extmod/modframebuf.c | 4 ++++ extmod/moduheapq.c | 2 ++ extmod/modure.c | 6 ++++++ extmod/moduzlib.c | 6 ++++++ 5 files changed, 24 insertions(+) diff --git a/extmod/modbtree.c b/extmod/modbtree.c index 88129e2102..a1d576fda9 100644 --- a/extmod/modbtree.c +++ b/extmod/modbtree.c @@ -52,7 +52,9 @@ typedef struct _mp_obj_btree_t { byte next_flags; } mp_obj_btree_t; +#if !MICROPY_ENABLE_DYNRUNTIME STATIC const mp_obj_type_t btree_type; +#endif #define CHECK_ERROR(res) \ if (res == RET_ERROR) { \ @@ -295,6 +297,7 @@ STATIC mp_obj_t btree_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs } } +#if !MICROPY_ENABLE_DYNRUNTIME STATIC const mp_rom_map_elem_t btree_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&btree_close_obj) }, { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&btree_flush_obj) }, @@ -319,6 +322,7 @@ STATIC const mp_obj_type_t btree_type = { .subscr = btree_subscr, .locals_dict = (void*)&btree_locals_dict, }; +#endif STATIC const FILEVTABLE btree_stream_fvtable = { mp_stream_posix_read, @@ -327,6 +331,7 @@ STATIC const FILEVTABLE btree_stream_fvtable = { mp_stream_posix_fsync }; +#if !MICROPY_ENABLE_DYNRUNTIME STATIC mp_obj_t mod_btree_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { { MP_QSTR_flags, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, @@ -373,5 +378,6 @@ const mp_obj_module_t mp_module_btree = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_btree_globals, }; +#endif #endif // MICROPY_PY_BTREE diff --git a/extmod/modframebuf.c b/extmod/modframebuf.c index a7f6ba905f..416431cd61 100644 --- a/extmod/modframebuf.c +++ b/extmod/modframebuf.c @@ -580,6 +580,7 @@ STATIC mp_obj_t framebuf_text(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_text_obj, 4, 5, framebuf_text); +#if !MICROPY_ENABLE_DYNRUNTIME STATIC const mp_rom_map_elem_t framebuf_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_fill), MP_ROM_PTR(&framebuf_fill_obj) }, { MP_ROM_QSTR(MP_QSTR_fill_rect), MP_ROM_PTR(&framebuf_fill_rect_obj) }, @@ -601,6 +602,7 @@ STATIC const mp_obj_type_t mp_type_framebuf = { .buffer_p = { .get_buffer = framebuf_get_buffer }, .locals_dict = (mp_obj_dict_t*)&framebuf_locals_dict, }; +#endif // this factory function is provided for backwards compatibility with old FrameBuffer1 class STATIC mp_obj_t legacy_framebuffer1(size_t n_args, const mp_obj_t *args) { @@ -624,6 +626,7 @@ STATIC mp_obj_t legacy_framebuffer1(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(legacy_framebuffer1_obj, 3, 4, legacy_framebuffer1); +#if !MICROPY_ENABLE_DYNRUNTIME STATIC const mp_rom_map_elem_t framebuf_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_framebuf) }, { MP_ROM_QSTR(MP_QSTR_FrameBuffer), MP_ROM_PTR(&mp_type_framebuf) }, @@ -644,5 +647,6 @@ const mp_obj_module_t mp_module_framebuf = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&framebuf_module_globals, }; +#endif #endif // MICROPY_PY_FRAMEBUF diff --git a/extmod/moduheapq.c b/extmod/moduheapq.c index f633052105..2e8010143d 100644 --- a/extmod/moduheapq.c +++ b/extmod/moduheapq.c @@ -103,6 +103,7 @@ STATIC mp_obj_t mod_uheapq_heapify(mp_obj_t heap_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_uheapq_heapify_obj, mod_uheapq_heapify); +#if !MICROPY_ENABLE_DYNRUNTIME STATIC const mp_rom_map_elem_t mp_module_uheapq_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uheapq) }, { MP_ROM_QSTR(MP_QSTR_heappush), MP_ROM_PTR(&mod_uheapq_heappush_obj) }, @@ -116,5 +117,6 @@ const mp_obj_module_t mp_module_uheapq = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_uheapq_globals, }; +#endif #endif //MICROPY_PY_UHEAPQ diff --git a/extmod/modure.c b/extmod/modure.c index 8a60207053..f3a9d88f7d 100644 --- a/extmod/modure.c +++ b/extmod/modure.c @@ -144,6 +144,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(match_end_obj, 1, 2, match_end); #endif +#if !MICROPY_ENABLE_DYNRUNTIME STATIC const mp_rom_map_elem_t match_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_group), MP_ROM_PTR(&match_group_obj) }, #if MICROPY_PY_URE_MATCH_GROUPS @@ -164,6 +165,7 @@ STATIC const mp_obj_type_t match_type = { .print = match_print, .locals_dict = (void*)&match_locals_dict, }; +#endif STATIC void re_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; @@ -363,6 +365,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_sub_obj, 3, 5, re_sub); #endif +#if !MICROPY_ENABLE_DYNRUNTIME STATIC const mp_rom_map_elem_t re_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_match), MP_ROM_PTR(&re_match_obj) }, { MP_ROM_QSTR(MP_QSTR_search), MP_ROM_PTR(&re_search_obj) }, @@ -380,6 +383,7 @@ STATIC const mp_obj_type_t re_type = { .print = re_print, .locals_dict = (void*)&re_locals_dict, }; +#endif STATIC mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) { (void)n_args; @@ -437,6 +441,7 @@ STATIC mp_obj_t mod_re_sub(size_t n_args, const mp_obj_t *args) { MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_sub_obj, 3, 5, mod_re_sub); #endif +#if !MICROPY_ENABLE_DYNRUNTIME STATIC const mp_rom_map_elem_t mp_module_re_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ure) }, { MP_ROM_QSTR(MP_QSTR_compile), MP_ROM_PTR(&mod_re_compile_obj) }, @@ -456,6 +461,7 @@ const mp_obj_module_t mp_module_ure = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_re_globals, }; +#endif // Source files #include'd here to make sure they're compiled in // only if module is enabled by config setting. diff --git a/extmod/moduzlib.c b/extmod/moduzlib.c index f8452c72b9..64327f1f7c 100644 --- a/extmod/moduzlib.c +++ b/extmod/moduzlib.c @@ -122,6 +122,7 @@ STATIC mp_uint_t decompio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *er return o->decomp.dest - (byte*)buf; } +#if !MICROPY_ENABLE_DYNRUNTIME STATIC const mp_rom_map_elem_t decompio_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) }, @@ -129,11 +130,13 @@ STATIC const mp_rom_map_elem_t decompio_locals_dict_table[] = { }; STATIC MP_DEFINE_CONST_DICT(decompio_locals_dict, decompio_locals_dict_table); +#endif STATIC const mp_stream_p_t decompio_stream_p = { .read = decompio_read, }; +#if !MICROPY_ENABLE_DYNRUNTIME STATIC const mp_obj_type_t decompio_type = { { &mp_type_type }, .name = MP_QSTR_DecompIO, @@ -141,6 +144,7 @@ STATIC const mp_obj_type_t decompio_type = { .protocol = &decompio_stream_p, .locals_dict = (void*)&decompio_locals_dict, }; +#endif STATIC mp_obj_t mod_uzlib_decompress(size_t n_args, const mp_obj_t *args) { mp_obj_t data = args[0]; @@ -201,6 +205,7 @@ error: } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_uzlib_decompress_obj, 1, 3, mod_uzlib_decompress); +#if !MICROPY_ENABLE_DYNRUNTIME STATIC const mp_rom_map_elem_t mp_module_uzlib_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uzlib) }, { MP_ROM_QSTR(MP_QSTR_decompress), MP_ROM_PTR(&mod_uzlib_decompress_obj) }, @@ -213,6 +218,7 @@ const mp_obj_module_t mp_module_uzlib = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_uzlib_globals, }; +#endif // Source files #include'd here to make sure they're compiled in // only if module is enabled by config setting. From 37817ab4ba5fa84624dc9715e01d6bd5a8d187b0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 5 Nov 2019 11:40:54 +1100 Subject: [PATCH 1038/1788] examples/natmod: Add btree example. --- examples/natmod/btree/Makefile | 37 ++++++++ examples/natmod/btree/btree_c.c | 148 ++++++++++++++++++++++++++++++ examples/natmod/btree/btree_py.py | 3 + 3 files changed, 188 insertions(+) create mode 100644 examples/natmod/btree/Makefile create mode 100644 examples/natmod/btree/btree_c.c create mode 100644 examples/natmod/btree/btree_py.py diff --git a/examples/natmod/btree/Makefile b/examples/natmod/btree/Makefile new file mode 100644 index 0000000000..d795102b4a --- /dev/null +++ b/examples/natmod/btree/Makefile @@ -0,0 +1,37 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module (different to built-in btree so it can coexist) +MOD = btree_$(ARCH) + +# Source files (.c or .py) +SRC = btree_c.c btree_py.py + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) +ARCH = x64 + +BTREE_DIR = $(MPY_DIR)/lib/berkeley-db-1.xx +BTREE_DEFS = -D__DBINTERFACE_PRIVATE=1 -Dmpool_error="(void)" -Dabort=abort_ "-Dvirt_fd_t=void*" $(BTREE_DEFS_EXTRA) +CFLAGS += -I$(BTREE_DIR)/PORT/include +CFLAGS += -Wno-old-style-definition -Wno-sign-compare -Wno-unused-parameter $(BTREE_DEFS) + +SRC += $(addprefix $(realpath $(BTREE_DIR))/,\ + btree/bt_close.c \ + btree/bt_conv.c \ + btree/bt_delete.c \ + btree/bt_get.c \ + btree/bt_open.c \ + btree/bt_overflow.c \ + btree/bt_page.c \ + btree/bt_put.c \ + btree/bt_search.c \ + btree/bt_seq.c \ + btree/bt_split.c \ + btree/bt_utils.c \ + mpool/mpool.c \ + ) + +include $(MPY_DIR)/py/dynruntime.mk + +# btree needs gnu99 defined +CFLAGS += -std=gnu99 diff --git a/examples/natmod/btree/btree_c.c b/examples/natmod/btree/btree_c.c new file mode 100644 index 0000000000..c8c5cef471 --- /dev/null +++ b/examples/natmod/btree/btree_c.c @@ -0,0 +1,148 @@ +#define MICROPY_ENABLE_DYNRUNTIME (1) +#define MICROPY_PY_BTREE (1) + +#include "py/dynruntime.h" + +#include + +#if !defined(__linux__) +void *memcpy(void *dst, const void *src, size_t n) { + return mp_fun_table.memmove_(dst, src, n); +} +void *memset(void *s, int c, size_t n) { + return mp_fun_table.memset_(s, c, n); +} +#endif + +void *memmove(void *dest, const void *src, size_t n) { + return mp_fun_table.memmove_(dest, src, n); +} + +void *malloc(size_t n) { + void *ptr = m_malloc(n); + return ptr; +} +void *realloc(void *ptr, size_t n) { + mp_printf(&mp_plat_print, "UNDEF %d\n", __LINE__); + return NULL; +} +void *calloc(size_t n, size_t m) { + void *ptr = m_malloc(n * m); + // memory already cleared by conservative GC + return ptr; +} + +void free(void *ptr) { + m_free(ptr); +} + +void abort_(void) { + nlr_raise(mp_obj_new_exception(mp_load_global(MP_QSTR_RuntimeError))); +} + +int native_errno; +#if defined(__linux__) +int *__errno_location (void) +#else +int *__errno (void) +#endif +{ + return &native_errno; +} + +ssize_t mp_stream_posix_write(void *stream, const void *buf, size_t len) { + mp_obj_base_t* o = stream; + const mp_stream_p_t *stream_p = o->type->protocol; + mp_uint_t out_sz = stream_p->write(MP_OBJ_FROM_PTR(stream), buf, len, &native_errno); + if (out_sz == MP_STREAM_ERROR) { + return -1; + } else { + return out_sz; + } +} + +ssize_t mp_stream_posix_read(void *stream, void *buf, size_t len) { + mp_obj_base_t* o = stream; + const mp_stream_p_t *stream_p = o->type->protocol; + mp_uint_t out_sz = stream_p->read(MP_OBJ_FROM_PTR(stream), buf, len, &native_errno); + if (out_sz == MP_STREAM_ERROR) { + return -1; + } else { + return out_sz; + } +} + +off_t mp_stream_posix_lseek(void *stream, off_t offset, int whence) { + const mp_obj_base_t* o = stream; + const mp_stream_p_t *stream_p = o->type->protocol; + struct mp_stream_seek_t seek_s; + seek_s.offset = offset; + seek_s.whence = whence; + mp_uint_t res = stream_p->ioctl(MP_OBJ_FROM_PTR(stream), MP_STREAM_SEEK, (mp_uint_t)(uintptr_t)&seek_s, &native_errno); + if (res == MP_STREAM_ERROR) { + return -1; + } + return seek_s.offset; +} + +int mp_stream_posix_fsync(void *stream) { + mp_obj_base_t* o = stream; + const mp_stream_p_t *stream_p = o->type->protocol; + mp_uint_t res = stream_p->ioctl(MP_OBJ_FROM_PTR(stream), MP_STREAM_FLUSH, 0, &native_errno); + if (res == MP_STREAM_ERROR) { + return -1; + } + return res; +} + +mp_obj_type_t btree_type; + +#include "extmod/modbtree.c" + +mp_map_elem_t btree_locals_dict_table[8]; +STATIC MP_DEFINE_CONST_DICT(btree_locals_dict, btree_locals_dict_table); + +STATIC mp_obj_t btree_open(size_t n_args, const mp_obj_t *args) { + // Make sure we got a stream object + mp_get_stream_raise(args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL); + + BTREEINFO openinfo = {0}; + openinfo.flags = mp_obj_get_int(args[1]); + openinfo.cachesize = mp_obj_get_int(args[2]); + openinfo.psize = mp_obj_get_int(args[3]); + openinfo.minkeypage = mp_obj_get_int(args[4]); + DB *db = __bt_open(MP_OBJ_TO_PTR(args[0]), &btree_stream_fvtable, &openinfo, 0); + if (db == NULL) { + mp_raise_OSError(native_errno); + } + + return MP_OBJ_FROM_PTR(btree_new(db)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_open_obj, 5, 5, btree_open); + +mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + MP_DYNRUNTIME_INIT_ENTRY + + btree_type.base.type = (void*)&mp_fun_table.type_type; + btree_type.name = MP_QSTR_btree; + btree_type.print = btree_print; + btree_type.getiter = btree_getiter; + btree_type.iternext = btree_iternext; + btree_type.binary_op = btree_binary_op; + btree_type.subscr = btree_subscr; + btree_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_close), MP_OBJ_FROM_PTR(&btree_close_obj) }; + btree_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_flush), MP_OBJ_FROM_PTR(&btree_flush_obj) }; + btree_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_get), MP_OBJ_FROM_PTR(&btree_get_obj) }; + btree_locals_dict_table[3] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_put), MP_OBJ_FROM_PTR(&btree_put_obj) }; + btree_locals_dict_table[4] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_seq), MP_OBJ_FROM_PTR(&btree_seq_obj) }; + btree_locals_dict_table[5] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_keys), MP_OBJ_FROM_PTR(&btree_keys_obj) }; + btree_locals_dict_table[6] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_values), MP_OBJ_FROM_PTR(&btree_values_obj) }; + btree_locals_dict_table[7] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_items), MP_OBJ_FROM_PTR(&btree_items_obj) }; + btree_type.locals_dict = (void*)&btree_locals_dict; + + mp_store_global(MP_QSTR__open, MP_OBJ_FROM_PTR(&btree_open_obj)); + mp_store_global(MP_QSTR_INCL, MP_OBJ_NEW_SMALL_INT(FLAG_END_KEY_INCL)); + mp_store_global(MP_QSTR_DESC, MP_OBJ_NEW_SMALL_INT(FLAG_DESC)); + + MP_DYNRUNTIME_INIT_EXIT +} diff --git a/examples/natmod/btree/btree_py.py b/examples/natmod/btree/btree_py.py new file mode 100644 index 0000000000..bd53c084a1 --- /dev/null +++ b/examples/natmod/btree/btree_py.py @@ -0,0 +1,3 @@ +# Implemented in Python to support keyword arguments +def open(stream, *, flags=0, cachesize=0, pagesize=0, minkeypage=0): + return _open(stream, flags, cachesize, pagesize, minkeypage) From 83f9fb169e5d9b9304e06237a747a30d3ea53458 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 5 Nov 2019 11:41:39 +1100 Subject: [PATCH 1039/1788] examples/natmod: Add uheapq example. --- examples/natmod/uheapq/Makefile | 13 +++++++++++++ examples/natmod/uheapq/uheapq.c | 17 +++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 examples/natmod/uheapq/Makefile create mode 100644 examples/natmod/uheapq/uheapq.c diff --git a/examples/natmod/uheapq/Makefile b/examples/natmod/uheapq/Makefile new file mode 100644 index 0000000000..55de3cc081 --- /dev/null +++ b/examples/natmod/uheapq/Makefile @@ -0,0 +1,13 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module (different to built-in uheapq so it can coexist) +MOD = uheapq_$(ARCH) + +# Source files (.c or .py) +SRC = uheapq.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) +ARCH = x64 + +include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/uheapq/uheapq.c b/examples/natmod/uheapq/uheapq.c new file mode 100644 index 0000000000..df880bd382 --- /dev/null +++ b/examples/natmod/uheapq/uheapq.c @@ -0,0 +1,17 @@ +#define MICROPY_ENABLE_DYNRUNTIME (1) +#define MICROPY_PY_UHEAPQ (1) + +#include "py/dynruntime.h" + +#include "extmod/moduheapq.c" + +mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + MP_DYNRUNTIME_INIT_ENTRY + + mp_store_global(MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR_uheapq)); + mp_store_global(MP_QSTR_heappush, MP_OBJ_FROM_PTR(&mod_uheapq_heappush_obj)); + mp_store_global(MP_QSTR_heappop, MP_OBJ_FROM_PTR(&mod_uheapq_heappop_obj)); + mp_store_global(MP_QSTR_heapify, MP_OBJ_FROM_PTR(&mod_uheapq_heapify_obj)); + + MP_DYNRUNTIME_INIT_EXIT +} From 16e591e412ec4be511180910f6f293fee01ad615 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 5 Nov 2019 11:42:59 +1100 Subject: [PATCH 1040/1788] examples/natmod: Add uzlib example. --- examples/natmod/uzlib/Makefile | 13 ++++++++++++ examples/natmod/uzlib/uzlib.c | 36 ++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 examples/natmod/uzlib/Makefile create mode 100644 examples/natmod/uzlib/uzlib.c diff --git a/examples/natmod/uzlib/Makefile b/examples/natmod/uzlib/Makefile new file mode 100644 index 0000000000..8761caf2dd --- /dev/null +++ b/examples/natmod/uzlib/Makefile @@ -0,0 +1,13 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module (different to built-in uzlib so it can coexist) +MOD = uzlib_$(ARCH) + +# Source files (.c or .py) +SRC = uzlib.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) +ARCH = x64 + +include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/uzlib/uzlib.c b/examples/natmod/uzlib/uzlib.c new file mode 100644 index 0000000000..4873171e5e --- /dev/null +++ b/examples/natmod/uzlib/uzlib.c @@ -0,0 +1,36 @@ +#define MICROPY_ENABLE_DYNRUNTIME (1) +#define MICROPY_PY_UZLIB (1) + +#include "py/dynruntime.h" + +#if !defined(__linux__) +void *memset(void *s, int c, size_t n) { + return mp_fun_table.memset_(s, c, n); +} +#endif + +mp_obj_type_t decompio_type; + +#include "extmod/moduzlib.c" + +mp_map_elem_t decompio_locals_dict_table[3]; +STATIC MP_DEFINE_CONST_DICT(decompio_locals_dict, decompio_locals_dict_table); + +mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + MP_DYNRUNTIME_INIT_ENTRY + + decompio_type.base.type = mp_fun_table.type_type; + decompio_type.name = MP_QSTR_DecompIO; + decompio_type.make_new = decompio_make_new; + decompio_type.protocol = &decompio_stream_p; + decompio_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_read), MP_OBJ_FROM_PTR(&mp_stream_read_obj) }; + decompio_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_readinto), MP_OBJ_FROM_PTR(&mp_stream_readinto_obj) }; + decompio_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_readline), MP_OBJ_FROM_PTR(&mp_stream_unbuffered_readline_obj) }; + decompio_type.locals_dict = (void*)&decompio_locals_dict; + + mp_store_global(MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR_uzlib)); + mp_store_global(MP_QSTR_decompress, MP_OBJ_FROM_PTR(&mod_uzlib_decompress_obj)); + mp_store_global(MP_QSTR_DecompIO, MP_OBJ_FROM_PTR(&decompio_type)); + + MP_DYNRUNTIME_INIT_EXIT +} From 2a485e1084d8706aae4533900c26307f346c6ca5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 12 Dec 2019 15:01:36 +1100 Subject: [PATCH 1041/1788] examples/natmod: Add framebuf example. --- examples/natmod/framebuf/Makefile | 13 ++++++++ examples/natmod/framebuf/framebuf.c | 50 +++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 examples/natmod/framebuf/Makefile create mode 100644 examples/natmod/framebuf/framebuf.c diff --git a/examples/natmod/framebuf/Makefile b/examples/natmod/framebuf/Makefile new file mode 100644 index 0000000000..2e2b815975 --- /dev/null +++ b/examples/natmod/framebuf/Makefile @@ -0,0 +1,13 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module (different to built-in framebuf so it can coexist) +MOD = framebuf_$(ARCH) + +# Source files (.c or .py) +SRC = framebuf.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) +ARCH = x64 + +include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/framebuf/framebuf.c b/examples/natmod/framebuf/framebuf.c new file mode 100644 index 0000000000..8f322c204a --- /dev/null +++ b/examples/natmod/framebuf/framebuf.c @@ -0,0 +1,50 @@ +#define MICROPY_ENABLE_DYNRUNTIME (1) +#define MICROPY_PY_FRAMEBUF (1) + +#include "py/dynruntime.h" + +#if !defined(__linux__) +void *memset(void *s, int c, size_t n) { + return mp_fun_table.memset_(s, c, n); +} +#endif + +mp_obj_type_t mp_type_framebuf; + +#include "extmod/modframebuf.c" + +mp_map_elem_t framebuf_locals_dict_table[10]; +STATIC MP_DEFINE_CONST_DICT(framebuf_locals_dict, framebuf_locals_dict_table); + +mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + MP_DYNRUNTIME_INIT_ENTRY + + mp_type_framebuf.base.type = (void*)&mp_type_type; + mp_type_framebuf.name = MP_QSTR_FrameBuffer; + mp_type_framebuf.make_new = framebuf_make_new; + mp_type_framebuf.buffer_p.get_buffer = framebuf_get_buffer; + framebuf_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_fill), MP_OBJ_FROM_PTR(&framebuf_fill_obj) }; + framebuf_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_fill_rect), MP_OBJ_FROM_PTR(&framebuf_fill_rect_obj) }; + framebuf_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_pixel), MP_OBJ_FROM_PTR(&framebuf_pixel_obj) }; + framebuf_locals_dict_table[3] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_hline), MP_OBJ_FROM_PTR(&framebuf_hline_obj) }; + framebuf_locals_dict_table[4] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_vline), MP_OBJ_FROM_PTR(&framebuf_vline_obj) }; + framebuf_locals_dict_table[5] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_rect), MP_OBJ_FROM_PTR(&framebuf_rect_obj) }; + framebuf_locals_dict_table[6] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_line), MP_OBJ_FROM_PTR(&framebuf_line_obj) }; + framebuf_locals_dict_table[7] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_blit), MP_OBJ_FROM_PTR(&framebuf_blit_obj) }; + framebuf_locals_dict_table[8] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_scroll), MP_OBJ_FROM_PTR(&framebuf_scroll_obj) }; + framebuf_locals_dict_table[9] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_text), MP_OBJ_FROM_PTR(&framebuf_text_obj) }; + mp_type_framebuf.locals_dict = (void*)&framebuf_locals_dict; + + mp_store_global(MP_QSTR_FrameBuffer, MP_OBJ_FROM_PTR(&mp_type_framebuf)); + mp_store_global(MP_QSTR_FrameBuffer1, MP_OBJ_FROM_PTR(&legacy_framebuffer1_obj)); + mp_store_global(MP_QSTR_MVLSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MVLSB)); + mp_store_global(MP_QSTR_MONO_VLSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MVLSB)); + mp_store_global(MP_QSTR_RGB565, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_RGB565)); + mp_store_global(MP_QSTR_GS2_HMSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_GS2_HMSB)); + mp_store_global(MP_QSTR_GS4_HMSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_GS4_HMSB)); + mp_store_global(MP_QSTR_GS8, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_GS8)); + mp_store_global(MP_QSTR_MONO_HLSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MHLSB)); + mp_store_global(MP_QSTR_MONO_HMSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MHMSB)); + + MP_DYNRUNTIME_INIT_EXIT +} From 42c1aed2bba55b759e54139421044a05ccd4bfc6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 12 Dec 2019 15:02:04 +1100 Subject: [PATCH 1042/1788] examples/natmod: Add ure example. --- examples/natmod/ure/Makefile | 13 ++++++ examples/natmod/ure/ure.c | 79 ++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 examples/natmod/ure/Makefile create mode 100644 examples/natmod/ure/ure.c diff --git a/examples/natmod/ure/Makefile b/examples/natmod/ure/Makefile new file mode 100644 index 0000000000..f5254298fd --- /dev/null +++ b/examples/natmod/ure/Makefile @@ -0,0 +1,13 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module (different to built-in ure so it can coexist) +MOD = ure_$(ARCH) + +# Source files (.c or .py) +SRC = ure.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) +ARCH = x64 + +include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/ure/ure.c b/examples/natmod/ure/ure.c new file mode 100644 index 0000000000..6c9e9e307e --- /dev/null +++ b/examples/natmod/ure/ure.c @@ -0,0 +1,79 @@ +#define MICROPY_ENABLE_DYNRUNTIME (1) +#define MICROPY_STACK_CHECK (1) +#define MICROPY_PY_URE (1) +#define MICROPY_PY_URE_MATCH_GROUPS (1) +#define MICROPY_PY_URE_MATCH_SPAN_START_END (1) +#define MICROPY_PY_URE_SUB (0) // requires vstr interface + +#include +#include "py/dynruntime.h" + +#define STACK_LIMIT (2048) + +const char *stack_top; + +void mp_stack_check(void) { + // Assumes descending stack on target + volatile char dummy; + if (stack_top - &dummy >= STACK_LIMIT) { + mp_raise_msg(&mp_type_RuntimeError, "maximum recursion depth exceeded"); + } +} + +#if !defined(__linux__) +void *memcpy(void *dst, const void *src, size_t n) { + return mp_fun_table.memmove_(dst, src, n); +} +void *memset(void *s, int c, size_t n) { + return mp_fun_table.memset_(s, c, n); +} +#endif + +void *memmove(void *dest, const void *src, size_t n) { + return mp_fun_table.memmove_(dest, src, n); +} + +mp_obj_type_t match_type; +mp_obj_type_t re_type; + +#include "extmod/modure.c" + +mp_map_elem_t match_locals_dict_table[5]; +STATIC MP_DEFINE_CONST_DICT(match_locals_dict, match_locals_dict_table); + +mp_map_elem_t re_locals_dict_table[3]; +STATIC MP_DEFINE_CONST_DICT(re_locals_dict, re_locals_dict_table); + +mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + MP_DYNRUNTIME_INIT_ENTRY + + char dummy; + stack_top = &dummy; + + // Because MP_QSTR_start/end/split are static, xtensa and xtensawin will make a small data section + // to copy in this key/value pair if they are specified as a struct, so assign them separately. + + match_type.base.type = (void*)&mp_fun_table.type_type; + match_type.name = MP_QSTR_match; + match_type.print = match_print; + match_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_group), MP_OBJ_FROM_PTR(&match_group_obj) }; + match_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_groups), MP_OBJ_FROM_PTR(&match_groups_obj) }; + match_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_span), MP_OBJ_FROM_PTR(&match_span_obj) }; + match_locals_dict_table[3] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_start), MP_OBJ_FROM_PTR(&match_start_obj) }; + match_locals_dict_table[4] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_end), MP_OBJ_FROM_PTR(&match_end_obj) }; + match_type.locals_dict = (void*)&match_locals_dict; + + re_type.base.type = (void*)&mp_fun_table.type_type; + re_type.name = MP_QSTR_ure; + re_type.print = re_print; + re_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_match), MP_OBJ_FROM_PTR(&re_match_obj) }; + re_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_search), MP_OBJ_FROM_PTR(&re_search_obj) }; + re_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_split), MP_OBJ_FROM_PTR(&re_split_obj) }; + re_type.locals_dict = (void*)&re_locals_dict; + + mp_store_global(MP_QSTR_compile, MP_OBJ_FROM_PTR(&mod_re_compile_obj)); + mp_store_global(MP_QSTR_match, MP_OBJ_FROM_PTR(&mod_re_match_obj)); + mp_store_global(MP_QSTR_search, MP_OBJ_FROM_PTR(&mod_re_search_obj)); + + MP_DYNRUNTIME_INIT_EXIT +} From 9ac949cdbd78d15f5edeaa651859659e8b382181 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 30 Nov 2019 23:00:56 +1100 Subject: [PATCH 1043/1788] py/persistentcode: Make ARM Thumb archs support multiple sub-archs. --- py/persistentcode.c | 8 +++++--- py/persistentcode.h | 29 ++++++++++++++++++++++------- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/py/persistentcode.c b/py/persistentcode.c index 1e3b5368b4..8bf46202ba 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -526,9 +526,11 @@ mp_raw_code_t *mp_raw_code_load(mp_reader_t *reader) { || read_uint(reader, NULL) > QSTR_WINDOW_SIZE) { mp_raise_ValueError("incompatible .mpy file"); } - if (MPY_FEATURE_DECODE_ARCH(header[2]) != MP_NATIVE_ARCH_NONE - && MPY_FEATURE_DECODE_ARCH(header[2]) != MPY_FEATURE_ARCH) { - mp_raise_ValueError("incompatible .mpy arch"); + if (MPY_FEATURE_DECODE_ARCH(header[2]) != MP_NATIVE_ARCH_NONE) { + byte arch = MPY_FEATURE_DECODE_ARCH(header[2]); + if (!MPY_FEATURE_ARCH_TEST(arch)) { + mp_raise_ValueError("incompatible .mpy arch"); + } } qstr_window_t qw; qw.idx = 0; diff --git a/py/persistentcode.h b/py/persistentcode.h index fde7a4625d..8769ef584d 100644 --- a/py/persistentcode.h +++ b/py/persistentcode.h @@ -55,19 +55,34 @@ // Define the host architecture #if MICROPY_EMIT_X86 -#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_X86) + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_X86) #elif MICROPY_EMIT_X64 -#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_X64) + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_X64) #elif MICROPY_EMIT_THUMB -#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7M) + #if defined(__thumb2__) + #if defined(__ARM_FP) && (__ARM_FP & 8) == 8 + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7EMDP) + #elif defined(__ARM_FP) && (__ARM_FP & 4) == 4 + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7EMSP) + #else + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7EM) + #endif + #else + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7M) + #endif + #define MPY_FEATURE_ARCH_TEST(x) (MP_NATIVE_ARCH_ARMV6M <= (x) && (x) <= MPY_FEATURE_ARCH) #elif MICROPY_EMIT_ARM -#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV6) + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV6) #elif MICROPY_EMIT_XTENSA -#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_XTENSA) + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_XTENSA) #elif MICROPY_EMIT_XTENSAWIN -#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_XTENSAWIN) + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_XTENSAWIN) #else -#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_NONE) + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_NONE) +#endif + +#ifndef MPY_FEATURE_ARCH_TEST +#define MPY_FEATURE_ARCH_TEST(x) ((x) == MPY_FEATURE_ARCH) #endif // 16-bit little-endian integer with the second and third bytes of supported .mpy files From ff58961944f4f2380e9610a4d18c53c08f68060e Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 30 Nov 2019 23:02:50 +1100 Subject: [PATCH 1044/1788] py/nativeglue: Add float new/get functions with both single and double. --- py/nativeglue.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ py/nativeglue.h | 4 ++++ 2 files changed, 50 insertions(+) diff --git a/py/nativeglue.c b/py/nativeglue.c index a88d8c1b9b..1a7f92f945 100644 --- a/py/nativeglue.c +++ b/py/nativeglue.c @@ -211,6 +211,48 @@ STATIC bool mp_native_yield_from(mp_obj_t gen, mp_obj_t send_value, mp_obj_t *re return false; } +#if MICROPY_PY_BUILTINS_FLOAT + +STATIC mp_obj_t mp_obj_new_float_from_f(float f) { + return mp_obj_new_float((mp_float_t)f); +} + +STATIC mp_obj_t mp_obj_new_float_from_d(double d) { + return mp_obj_new_float((mp_float_t)d); +} + +STATIC float mp_obj_get_float_to_f(mp_obj_t o) { + return (float)mp_obj_get_float(o); +} + +STATIC double mp_obj_get_float_to_d(mp_obj_t o) { + return (double)mp_obj_get_float(o); +} + +#else + +STATIC mp_obj_t mp_obj_new_float_from_f(float f) { + (void)f; + mp_raise_msg(&mp_type_RuntimeError, "float unsupported"); +} + +STATIC mp_obj_t mp_obj_new_float_from_d(double d) { + (void)d; + mp_raise_msg(&mp_type_RuntimeError, "float unsupported"); +} + +STATIC float mp_obj_get_float_to_f(mp_obj_t o) { + (void)o; + mp_raise_msg(&mp_type_RuntimeError, "float unsupported"); +} + +STATIC double mp_obj_get_float_to_d(mp_obj_t o) { + (void)o; + mp_raise_msg(&mp_type_RuntimeError, "float unsupported"); +} + +#endif + // these must correspond to the respective enum in runtime0.h const mp_fun_table_t mp_fun_table = { &mp_const_none_obj, @@ -282,6 +324,10 @@ const mp_fun_table_t mp_fun_table = { mp_obj_new_str, mp_obj_new_bytes, mp_obj_new_bytearray_by_ref, + mp_obj_new_float_from_f, + mp_obj_new_float_from_d, + mp_obj_get_float_to_f, + mp_obj_get_float_to_d, mp_get_buffer_raise, mp_get_stream_raise, &mp_plat_print, diff --git a/py/nativeglue.h b/py/nativeglue.h index 9abae89df2..021e7a8ecb 100644 --- a/py/nativeglue.h +++ b/py/nativeglue.h @@ -150,6 +150,10 @@ typedef struct _mp_fun_table_t { mp_obj_t (*obj_new_str)(const char* data, size_t len); mp_obj_t (*obj_new_bytes)(const byte* data, size_t len); mp_obj_t (*obj_new_bytearray_by_ref)(size_t n, void *items); + mp_obj_t (*obj_new_float_from_f)(float f); + mp_obj_t (*obj_new_float_from_d)(double d); + float (*obj_get_float_to_f)(mp_obj_t o); + double (*obj_get_float_to_d)(mp_obj_t o); void (*get_buffer_raise)(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags); const mp_stream_p_t *(*get_stream_raise)(mp_obj_t self_in, int flags); const mp_print_t *plat_print; From abc642973db46fbce7494d34ea0ef2539b339be0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 30 Nov 2019 23:03:09 +1100 Subject: [PATCH 1045/1788] py/dynruntime: Add support for float API to make/get floats. We don't want to add a feature flag to .mpy files that indicate float support because it will get complex and difficult to use. Instead the .mpy is built using whatever precision it chooses (float or double) and the native glue API will convert between this choice and what the host runtime actually uses. --- py/dynruntime.h | 16 ++++++++++++++++ py/dynruntime.mk | 10 ++++++++++ tools/mpy_ld.py | 2 +- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/py/dynruntime.h b/py/dynruntime.h index 34cf6010c4..a83aa905c1 100644 --- a/py/dynruntime.h +++ b/py/dynruntime.h @@ -190,4 +190,20 @@ static inline void mp_raise_OSError_dyn(int er) { nlr_raise(mp_call_function_n_kw(mp_load_global(MP_QSTR_OSError), 1, 0, &args[0])); } +/******************************************************************************/ +// Floating point + +#define mp_obj_new_float_from_f(f) (mp_fun_table.obj_new_float_from_f((f))) +#define mp_obj_new_float_from_d(d) (mp_fun_table.obj_new_float_from_d((d))) +#define mp_obj_get_float_to_f(o) (mp_fun_table.obj_get_float_to_f((o))) +#define mp_obj_get_float_to_d(o) (mp_fun_table.obj_get_float_to_d((o))) + +#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT +#define mp_obj_new_float(f) (mp_obj_new_float_from_f((f))) +#define mp_obj_get_float(o) (mp_obj_get_float_to_f((o))) +#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE +#define mp_obj_new_float(f) (mp_obj_new_float_from_d((f))) +#define mp_obj_get_float(o) (mp_obj_get_float_to_d((o))) +#endif + #endif // MICROPY_INCLUDED_PY_DYNRUNTIME_H diff --git a/py/dynruntime.mk b/py/dynruntime.mk index b01b80e0dd..8b65745afd 100644 --- a/py/dynruntime.mk +++ b/py/dynruntime.mk @@ -46,6 +46,7 @@ ifeq ($(ARCH),x86) CROSS = CFLAGS += -m32 -fno-stack-protector MPY_CROSS_FLAGS += -mcache-lookup-bc +MICROPY_FLOAT_IMPL ?= double else ifeq ($(ARCH),x64) @@ -53,12 +54,14 @@ else ifeq ($(ARCH),x64) CROSS = CFLAGS += -fno-stack-protector MPY_CROSS_FLAGS += -mcache-lookup-bc +MICROPY_FLOAT_IMPL ?= double else ifeq ($(ARCH),armv7m) # thumb CROSS = arm-none-eabi- CFLAGS += -mthumb -mcpu=cortex-m3 +MICROPY_FLOAT_IMPL ?= none else ifeq ($(ARCH),armv7emsp) @@ -66,6 +69,7 @@ else ifeq ($(ARCH),armv7emsp) CROSS = arm-none-eabi- CFLAGS += -mthumb -mcpu=cortex-m4 CFLAGS += -mfpu=fpv4-sp-d16 -mfloat-abi=hard +MICROPY_FLOAT_IMPL ?= float else ifeq ($(ARCH),armv7emdp) @@ -73,23 +77,29 @@ else ifeq ($(ARCH),armv7emdp) CROSS = arm-none-eabi- CFLAGS += -mthumb -mcpu=cortex-m7 CFLAGS += -mfpu=fpv5-d16 -mfloat-abi=hard +MICROPY_FLOAT_IMPL ?= double else ifeq ($(ARCH),xtensa) # xtensa CROSS = xtensa-lx106-elf- CFLAGS += -mforce-l32 +MICROPY_FLOAT_IMPL ?= none else ifeq ($(ARCH),xtensawin) # xtensawin CROSS = xtensa-esp32-elf- CFLAGS += +MICROPY_FLOAT_IMPL ?= float else $(error architecture '$(ARCH)' not supported) endif +MICROPY_FLOAT_IMPL_UPPER = $(shell echo $(MICROPY_FLOAT_IMPL) | tr '[:lower:]' '[:upper:]') +CFLAGS += -DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_$(MICROPY_FLOAT_IMPL_UPPER) + CFLAGS += $(CFLAGS_EXTRA) ################################################################################ diff --git a/tools/mpy_ld.py b/tools/mpy_ld.py index 07105caac9..ec600f9671 100755 --- a/tools/mpy_ld.py +++ b/tools/mpy_ld.py @@ -663,7 +663,7 @@ def link_objects(env, native_qstr_vals_len, native_qstr_objs_len): # Resolve unknown symbols mp_fun_table_sec = Section('.external.mp_fun_table', b'', 0) - fun_table = {key: 63 + idx + fun_table = {key: 67 + idx for idx, key in enumerate([ 'mp_type_type', 'mp_type_str', From 111d1ffb6473950274bb506e1a27c01b33ea3d61 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 2 Dec 2019 16:27:24 +1100 Subject: [PATCH 1046/1788] tests/import: Add test for importing viper code with additional flags. --- tests/import/mpy_native.py | 21 +++++++++++++++++++++ tests/import/mpy_native.py.exp | 1 + 2 files changed, 22 insertions(+) diff --git a/tests/import/mpy_native.py b/tests/import/mpy_native.py index c33b3350c3..4ee537f4af 100644 --- a/tests/import/mpy_native.py +++ b/tests/import/mpy_native.py @@ -73,6 +73,27 @@ user_files = { b'\x00\x00\x00\x00\x00\x00\x00\x00' # dummy machine code b'\x00\x00\x00' # scope_flags, n_pos_args, type_sig ), + + # test loading viper with additional scope flags and relocation + '/mod2.mpy': ( + b'M\x05\x0b\x1f\x20' # header + + b'\x20' # n bytes, bytecode + b'\x00\x08\x02m\x02m' # prelude + b'\x51' # LOAD_CONST_NONE + b'\x63' # RETURN_VALUE + + b'\x00\x01' # n_obj, n_raw_code + + b'\x12' # n bytes(=4), viper code + b'\x00\x00\x00\x00' # dummy machine code + b'\x00' # n_qstr + b'\x70' # scope_flags: VIPERBSS | VIPERRODATA | VIPERRELOC + b'\x00\x00' # n_obj, n_raw_code + b'\x06rodata' # rodata, 6 bytes + b'\x04' # bss, 4 bytes + b'\x03\x01\x00' # dummy relocation of rodata + ), } # create and mount a user filesystem diff --git a/tests/import/mpy_native.py.exp b/tests/import/mpy_native.py.exp index b73812094a..320cac09d8 100644 --- a/tests/import/mpy_native.py.exp +++ b/tests/import/mpy_native.py.exp @@ -1,2 +1,3 @@ mod0 ValueError incompatible .mpy arch mod1 OK +mod2 OK From fc97d6d1b5f4c249e755e9190518aad8020980ba Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 10 Dec 2019 14:57:12 +1100 Subject: [PATCH 1047/1788] tools/mpy-tool.py: Raise exception if trying to freeze relocatable mpy. --- tools/mpy-tool.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index 8bc37734c7..77a129944b 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -474,6 +474,9 @@ class RawCodeNative(RawCode): assert 0 def freeze(self, parent_name): + if self.prelude[2] & ~0x0f: + raise FreezeError('unable to freeze code with relocations') + self.freeze_children(parent_name) # generate native code data From 4eef940edbd3ee4eecead37785cafd9845d763a2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 11 Dec 2019 14:39:27 +1100 Subject: [PATCH 1048/1788] tests: Add script to run dynamic-native-module tests. --- tests/run-natmodtests.py | 187 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100755 tests/run-natmodtests.py diff --git a/tests/run-natmodtests.py b/tests/run-natmodtests.py new file mode 100755 index 0000000000..186c30b831 --- /dev/null +++ b/tests/run-natmodtests.py @@ -0,0 +1,187 @@ +#!/usr/bin/env python3 + +# This file is part of the MicroPython project, http://micropython.org/ +# The MIT License (MIT) +# Copyright (c) 2019 Damien P. George + +import os +import subprocess +import sys +import argparse + +sys.path.append('../tools') +import pyboard + +# Paths for host executables +CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python3') +MICROPYTHON = os.getenv('MICROPY_MICROPYTHON', '../ports/unix/micropython_coverage') + +NATMOD_EXAMPLE_DIR = '../examples/natmod/' + +# Supported tests and their corresponding mpy module +TEST_MAPPINGS = { + 'btree': 'btree/btree_$(ARCH).mpy', + 'framebuf': 'framebuf/framebuf_$(ARCH).mpy', + 'uheapq': 'uheapq/uheapq_$(ARCH).mpy', + 'ure': 'ure/ure_$(ARCH).mpy', + 'uzlib': 'uzlib/uzlib_$(ARCH).mpy', +} + +# Code to allow a target MicroPython to import an .mpy from RAM +injected_import_hook_code = """\ +import sys, uos, uio +class __File(uio.IOBase): + def __init__(self): + self.off = 0 + def ioctl(self, request, arg): + return 0 + def readinto(self, buf): + buf[:] = memoryview(__buf)[self.off:self.off + len(buf)] + self.off += len(buf) + return len(buf) +class __FS: + def mount(self, readonly, mkfs): + pass + def chdir(self, path): + pass + def stat(self, path): + if path == '__injected.mpy': + return tuple(0 for _ in range(10)) + else: + raise OSError(-2) # ENOENT + def open(self, path, mode): + return __File() +uos.mount(__FS(), '/__remote') +uos.chdir('/__remote') +sys.modules['{}'] = __import__('__injected') +""" + +class TargetSubprocess: + def __init__(self, cmd): + self.cmd = cmd + + def close(self): + pass + + def run_script(self, script): + try: + p = subprocess.run(self.cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, input=script) + return p.stdout, None + except subprocess.CalledProcessError as er: + return b'', er + +class TargetPyboard: + def __init__(self, pyb): + self.pyb = pyb + self.pyb.enter_raw_repl() + + def close(self): + self.pyb.exit_raw_repl() + self.pyb.close() + + def run_script(self, script): + try: + self.pyb.enter_raw_repl() + output = self.pyb.exec_(script) + output = output.replace(b'\r\n', b'\n') + return output, None + except pyboard.PyboardError as er: + return b'', er + +def run_tests(target_truth, target, args, stats): + for test_file in args.files: + # Find supported test + for k, v in TEST_MAPPINGS.items(): + if test_file.find(k) != -1: + test_module = k + test_mpy = v.replace('$(ARCH)', args.arch) + break + else: + print('---- {} - no matching mpy'.format(test_file)) + continue + + # Read test script + with open(test_file, 'rb') as f: + test_file_data = f.read() + + # Create full test with embedded .mpy + try: + with open(NATMOD_EXAMPLE_DIR + test_mpy, 'rb') as f: + test_script = b'__buf=' + bytes(repr(f.read()), 'ascii') + b'\n' + except OSError: + print('---- {} - mpy file not compiled'.format(test_file)) + continue + test_script += bytes(injected_import_hook_code.format(test_module), 'ascii') + test_script += test_file_data + + # Run test under MicroPython + result_out, error = target.run_script(test_script) + + # Work out result of test + extra = '' + if error is None and result_out == b'SKIP\n': + result = 'SKIP' + elif error is not None: + result = 'FAIL' + extra = ' - ' + str(error) + else: + # Check result against truth + try: + with open(test_file + '.exp', 'rb') as f: + result_exp = f.read() + error = None + except OSError: + result_exp, error = target_truth.run_script(test_file_data) + if error is not None: + result = 'TRUTH FAIL' + elif result_out != result_exp: + result = 'FAIL' + print(result_out) + else: + result = 'pass' + + # Accumulate statistics + stats['total'] += 1 + if result == 'pass': + stats['pass'] += 1 + elif result == 'SKIP': + stats['skip'] += 1 + else: + stats['fail'] += 1 + + # Print result + print('{:4} {}{}'.format(result, test_file, extra)) + +def main(): + cmd_parser = argparse.ArgumentParser(description='Run dynamic-native-module tests under MicroPython') + cmd_parser.add_argument('-p', '--pyboard', action='store_true', help='run tests via pyboard.py') + cmd_parser.add_argument('-d', '--device', default='/dev/ttyACM0', help='the device for pyboard.py') + cmd_parser.add_argument('-a', '--arch', default='x64', help='native architecture of the target') + cmd_parser.add_argument('files', nargs='*', help='input test files') + args = cmd_parser.parse_args() + + target_truth = TargetSubprocess([CPYTHON3]) + + if args.pyboard: + target = TargetPyboard(pyboard.Pyboard(args.device)) + else: + target = TargetSubprocess([MICROPYTHON]) + + stats = {'total': 0, 'pass': 0, 'fail':0, 'skip': 0} + run_tests(target_truth, target, args, stats) + + target.close() + target_truth.close() + + print('{} tests performed'.format(stats['total'])) + print('{} tests passed'.format(stats['pass'])) + if stats['fail']: + print('{} tests failed'.format(stats['fail'])) + if stats['skip']: + print('{} tests skipped'.format(stats['skip'])) + + if stats['fail']: + sys.exit(1) + +if __name__ == "__main__": + main() From 60c3c22a0dcd5aba9e65ae4c3890889f42a18567 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 12 Dec 2019 15:02:27 +1100 Subject: [PATCH 1049/1788] examples/natmod: Add features1 and features2 examples. --- examples/natmod/features1/Makefile | 14 ++++ examples/natmod/features1/features1.c | 106 ++++++++++++++++++++++++++ examples/natmod/features2/Makefile | 14 ++++ examples/natmod/features2/main.c | 83 ++++++++++++++++++++ examples/natmod/features2/prod.c | 9 +++ examples/natmod/features2/prod.h | 1 + examples/natmod/features2/test.py | 26 +++++++ 7 files changed, 253 insertions(+) create mode 100644 examples/natmod/features1/Makefile create mode 100644 examples/natmod/features1/features1.c create mode 100644 examples/natmod/features2/Makefile create mode 100644 examples/natmod/features2/main.c create mode 100644 examples/natmod/features2/prod.c create mode 100644 examples/natmod/features2/prod.h create mode 100644 examples/natmod/features2/test.py diff --git a/examples/natmod/features1/Makefile b/examples/natmod/features1/Makefile new file mode 100644 index 0000000000..010640daf9 --- /dev/null +++ b/examples/natmod/features1/Makefile @@ -0,0 +1,14 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module +MOD = features1 + +# Source files (.c or .py) +SRC = features1.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) +ARCH = x64 + +# Include to get the rules for compiling and linking the module +include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/features1/features1.c b/examples/natmod/features1/features1.c new file mode 100644 index 0000000000..1bfbe50b95 --- /dev/null +++ b/examples/natmod/features1/features1.c @@ -0,0 +1,106 @@ +/* This example demonstrates the following features in a native module: + - defining simple functions exposed to Python + - defining local, helper C functions + - defining constant integers and strings exposed to Python + - getting and creating integer objects + - creating Python lists + - raising exceptions + - allocating memory + - BSS and constant data (rodata) + - relocated pointers in rodata +*/ + +// Include the header file to get access to the MicroPython API +#include "py/dynruntime.h" + +// BSS (zero) data +uint16_t data16[4]; + +// Constant data (rodata) +const uint8_t table8[] = { 0, 1, 1, 2, 3, 5, 8, 13 }; +const uint16_t table16[] = { 0x1000, 0x2000 }; + +// Constant data pointing to BSS/constant data +uint16_t *const table_ptr16a[] = { &data16[0], &data16[1], &data16[2], &data16[3] }; +const uint16_t *const table_ptr16b[] = { &table16[0], &table16[1] }; + +// A simple function that adds its 2 arguments (must be integers) +STATIC mp_obj_t add(mp_obj_t x_in, mp_obj_t y_in) { + mp_int_t x = mp_obj_get_int(x_in); + mp_int_t y = mp_obj_get_int(y_in); + return mp_obj_new_int(x + y); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(add_obj, add); + +// A local helper function (not exposed to Python) +STATIC mp_int_t fibonacci_helper(mp_int_t x) { + if (x < MP_ARRAY_SIZE(table8)) { + return table8[x]; + } else { + return fibonacci_helper(x - 1) + fibonacci_helper(x - 2); + } +} + +// A function which computes Fibonacci numbers +STATIC mp_obj_t fibonacci(mp_obj_t x_in) { + mp_int_t x = mp_obj_get_int(x_in); + if (x < 0) { + mp_raise_ValueError("can't compute negative Fibonacci number"); + } + return mp_obj_new_int(fibonacci_helper(x)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(fibonacci_obj, fibonacci); + +// A function that accesses the BSS data +STATIC mp_obj_t access(size_t n_args, const mp_obj_t *args) { + if (n_args == 0) { + // Create a list holding all items from data16 + mp_obj_list_t *lst = MP_OBJ_TO_PTR(mp_obj_new_list(MP_ARRAY_SIZE(data16), NULL)); + for (int i = 0; i < MP_ARRAY_SIZE(data16); ++i) { + lst->items[i] = mp_obj_new_int(data16[i]); + } + return MP_OBJ_FROM_PTR(lst); + } else if (n_args == 1) { + // Get one item from data16 + mp_int_t idx = mp_obj_get_int(args[0]) & 3; + return mp_obj_new_int(data16[idx]); + } else { + // Set one item in data16 (via table_ptr16a) + mp_int_t idx = mp_obj_get_int(args[0]) & 3; + *table_ptr16a[idx] = mp_obj_get_int(args[1]); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(access_obj, 0, 2, access); + +// A function that allocates memory and creates a bytearray +STATIC mp_obj_t make_array(void) { + uint16_t *ptr = m_new(uint16_t, MP_ARRAY_SIZE(table_ptr16b)); + for (int i = 0; i < MP_ARRAY_SIZE(table_ptr16b); ++i) { + ptr[i] = *table_ptr16b[i]; + } + return mp_obj_new_bytearray_by_ref(sizeof(uint16_t) * MP_ARRAY_SIZE(table_ptr16b), ptr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(make_array_obj, make_array); + +// This is the entry point and is called when the module is imported +mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + // This must be first, it sets up the globals dict and other things + MP_DYNRUNTIME_INIT_ENTRY + + // Messages can be printed as usualy + mp_printf(&mp_plat_print, "initialising module self=%p\n", self); + + // Make the functions available in the module's namespace + mp_store_global(MP_QSTR_add, MP_OBJ_FROM_PTR(&add_obj)); + mp_store_global(MP_QSTR_fibonacci, MP_OBJ_FROM_PTR(&fibonacci_obj)); + mp_store_global(MP_QSTR_access, MP_OBJ_FROM_PTR(&access_obj)); + mp_store_global(MP_QSTR_make_array, MP_OBJ_FROM_PTR(&make_array_obj)); + + // Add some constants to the module's namespace + mp_store_global(MP_QSTR_VAL, MP_OBJ_NEW_SMALL_INT(42)); + mp_store_global(MP_QSTR_MSG, MP_OBJ_NEW_QSTR(MP_QSTR_HELLO_MICROPYTHON)); + + // This must be last, it restores the globals dict + MP_DYNRUNTIME_INIT_EXIT +} diff --git a/examples/natmod/features2/Makefile b/examples/natmod/features2/Makefile new file mode 100644 index 0000000000..4fd23c6879 --- /dev/null +++ b/examples/natmod/features2/Makefile @@ -0,0 +1,14 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module +MOD = features2 + +# Source files (.c or .py) +SRC = main.c prod.c test.py + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) +ARCH = x64 + +# Include to get the rules for compiling and linking the module +include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/features2/main.c b/examples/natmod/features2/main.c new file mode 100644 index 0000000000..de83bf2bed --- /dev/null +++ b/examples/natmod/features2/main.c @@ -0,0 +1,83 @@ +/* This example demonstrates the following features in a native module: + - using floats + - defining additional code in Python (see test.py) + - have extra C code in a separate file (see prod.c) +*/ + +// Include the header file to get access to the MicroPython API +#include "py/dynruntime.h" + +// Include the header for auxiliary C code for this module +#include "prod.h" + +// Automatically detect if this module should include double-precision code. +// If double precision is supported by the target architecture then it can +// be used in native module regardless of what float setting the target +// MicroPython runtime uses (being none, float or double). +#if defined(__i386__) || defined(__x86_64__) || (defined(__ARM_FP) && (__ARM_FP & 8)) +#define USE_DOUBLE 1 +#else +#define USE_DOUBLE 0 +#endif + +// A function that uses the default float type configured for the current target +// This default can be overridden by specifying MICROPY_FLOAT_IMPL at the make level +STATIC mp_obj_t add(mp_obj_t x, mp_obj_t y) { + return mp_obj_new_float(mp_obj_get_float(x) + mp_obj_get_float(y)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(add_obj, add); + +// A function that explicitly uses single precision floats +STATIC mp_obj_t add_f(mp_obj_t x, mp_obj_t y) { + return mp_obj_new_float_from_f(mp_obj_get_float_to_f(x) + mp_obj_get_float_to_f(y)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(add_f_obj, add_f); + +#if USE_DOUBLE +// A function that explicitly uses double precision floats +STATIC mp_obj_t add_d(mp_obj_t x, mp_obj_t y) { + return mp_obj_new_float_from_d(mp_obj_get_float_to_d(x) + mp_obj_get_float_to_d(y)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(add_d_obj, add_d); +#endif + +// A function that computes the product of floats in an array. +// This function uses the most general C argument interface, which is more difficult +// to use but has access to the globals dict of the module via self->globals. +STATIC mp_obj_t productf(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + // Check number of arguments is valid + mp_arg_check_num(n_args, n_kw, 1, 1, false); + + // Extract buffer pointer and verify typecode + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_RW); + if (bufinfo.typecode != 'f') { + mp_raise_ValueError("expecting float array"); + } + + // Compute product, store result back in first element of array + float *ptr = bufinfo.buf; + float prod = prod_array(bufinfo.len / sizeof(*ptr), ptr); + ptr[0] = prod; + + return mp_const_none; +} + +// This is the entry point and is called when the module is imported +mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + // This must be first, it sets up the globals dict and other things + MP_DYNRUNTIME_INIT_ENTRY + + // Make the functions available in the module's namespace + mp_store_global(MP_QSTR_add, MP_OBJ_FROM_PTR(&add_obj)); + mp_store_global(MP_QSTR_add_f, MP_OBJ_FROM_PTR(&add_f_obj)); + #if USE_DOUBLE + mp_store_global(MP_QSTR_add_d, MP_OBJ_FROM_PTR(&add_d_obj)); + #endif + + // The productf function uses the most general C argument interface + mp_store_global(MP_QSTR_productf, MP_DYNRUNTIME_MAKE_FUNCTION(productf)); + + // This must be last, it restores the globals dict + MP_DYNRUNTIME_INIT_EXIT +} diff --git a/examples/natmod/features2/prod.c b/examples/natmod/features2/prod.c new file mode 100644 index 0000000000..7791dcad1d --- /dev/null +++ b/examples/natmod/features2/prod.c @@ -0,0 +1,9 @@ +#include "prod.h" + +float prod_array(int n, float *ar) { + float ans = 1; + for (int i = 0; i < n; ++i) { + ans *= ar[i]; + } + return ans; +} diff --git a/examples/natmod/features2/prod.h b/examples/natmod/features2/prod.h new file mode 100644 index 0000000000..f27dd8d033 --- /dev/null +++ b/examples/natmod/features2/prod.h @@ -0,0 +1 @@ +float prod_array(int n, float *ar); diff --git a/examples/natmod/features2/test.py b/examples/natmod/features2/test.py new file mode 100644 index 0000000000..2e9db00f44 --- /dev/null +++ b/examples/natmod/features2/test.py @@ -0,0 +1,26 @@ +# This Python code will be merged with the C code in main.c + +import array + +def isclose(a, b): + return abs(a - b) < 1e-3 + +def test(): + tests = [ + isclose(add(0.1, 0.2), 0.3), + isclose(add_f(0.1, 0.2), 0.3), + ] + + ar = array.array('f', [1, 2, 3.5]) + productf(ar) + tests.append(isclose(ar[0], 7)) + + if 'add_d' in globals(): + tests.append(isclose(add_d(0.1, 0.2), 0.3)) + + print(tests) + + if not all(tests): + raise SystemExit(1) + +test() From ac769672fd0b94b237fac6e0bfb411fa92f846cc Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 12 Dec 2019 17:45:02 +1100 Subject: [PATCH 1050/1788] travis: Add tests for building and importing dynamic native modules. --- .travis.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.travis.yml b/.travis.yml index 0f57bc3fe8..fef8bbbcfb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -62,7 +62,10 @@ jobs: - stage: test env: NAME="unix coverage build and tests" install: + - sudo apt-get install python3-pip - sudo pip install cpp-coveralls + - sudo pip3 install setuptools + - sudo pip3 install pyelftools - gcc --version - python3 --version script: @@ -78,6 +81,17 @@ jobs: - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --via-mpy --emit native -d basics float micropython) # test when input script comes from stdin - cat tests/basics/0prelim.py | ports/unix/micropython_coverage | grep -q 'abc' + # test building native mpy modules + - make -C examples/natmod/features1 ARCH=x64 + - make -C examples/natmod/features2 ARCH=x64 + - make -C examples/natmod/btree ARCH=x64 + - make -C examples/natmod/framebuf ARCH=x64 + - make -C examples/natmod/uheapq ARCH=x64 + - make -C examples/natmod/ure ARCH=x64 + - make -C examples/natmod/uzlib ARCH=x64 + # test importing .mpy generated by mpy_ld.py + - MICROPYPATH=examples/natmod/features2 ./ports/unix/micropython_coverage -m features2 + - (cd tests && ./run-natmodtests.py extmod/{btree*,framebuf*,uheapq*,ure*,uzlib*}.py) # 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) after_failure: From cd9de63c0e8ac242148c87869d37dcc295c7497a Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 13 Dec 2019 12:34:42 +1100 Subject: [PATCH 1051/1788] drivers/wiznet5k: Allow selecting maximum fixed buffer size for MACRAW. Enabling WIZCHIP_USE_MAX_BUFFER will make the TX/RX buffers the maximum available size, for use with MACRAW mode. --- drivers/wiznet5k/ethernet/w5200/w5200.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/wiznet5k/ethernet/w5200/w5200.c b/drivers/wiznet5k/ethernet/w5200/w5200.c index 8c3780792e..a84d3c9fa7 100644 --- a/drivers/wiznet5k/ethernet/w5200/w5200.c +++ b/drivers/wiznet5k/ethernet/w5200/w5200.c @@ -52,10 +52,19 @@ #include "w5200.h" +#if WIZCHIP_USE_MAX_BUFFER +// This option is intended to be used when MACRAW mode is enabled, to allow +// the single raw socket to use all the available buffer space. +#define SMASK (16 * 1024 - 1) /* tx buffer mask */ +#define RMASK (16 * 1024 - 1) /* rx buffer mask */ +#define SSIZE (16 * 1024) /* max tx buffer size */ +#define RSIZE (16 * 1024) /* max rx buffer size */ +#else #define SMASK (0x7ff) /* tx buffer mask */ #define RMASK (0x7ff) /* rx buffer mask */ #define SSIZE (2048) /* max tx buffer size */ #define RSIZE (2048) /* max rx buffer size */ +#endif #define TXBUF_BASE (0x8000) #define RXBUF_BASE (0xc000) From c2eaf566349b7aadc0c25ca9817e881b50e606cb Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 13 Dec 2019 12:36:12 +1100 Subject: [PATCH 1052/1788] stm32/Makefile: Enable max buffer size on W5200 NIC when used with lwIP. Because in network_wiznet5k the TX/RX buffers are set to 16k each when in MACRAW mode, which is used with lwIP. --- ports/stm32/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 61ce06ca8c..c9fdc7b0d2 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -408,6 +408,10 @@ 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) +ifeq ($(MICROPY_PY_LWIP),1) +# When using MACRAW mode (with lwIP), maximum buffer space must be used for the raw socket +CFLAGS_MOD += -DWIZCHIP_USE_MAX_BUFFER +endif SRC_MOD += network_wiznet5k.c modnwwiznet5k.c SRC_MOD += $(addprefix $(WIZNET5K_DIR)/,\ ethernet/w$(MICROPY_PY_WIZNET5K)/w$(MICROPY_PY_WIZNET5K).c \ From 48e9262f550ba8c5ff2d7c48c8f8c7f7e5ccfec6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 13 Dec 2019 13:29:11 +1100 Subject: [PATCH 1053/1788] py/dynruntime: Implement uint new/get, mp_obj_len and mp_obj_subscr. --- py/dynruntime.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/py/dynruntime.h b/py/dynruntime.h index a83aa905c1..7092a5dd88 100644 --- a/py/dynruntime.h +++ b/py/dynruntime.h @@ -97,6 +97,7 @@ static inline void *m_realloc_dyn(void *ptr, size_t new_num_bytes) { #define mp_obj_new_bool(b) ((b) ? (mp_obj_t)mp_fun_table.const_true : (mp_obj_t)mp_fun_table.const_false) #define mp_obj_new_int(i) (mp_fun_table.native_to_obj(i, MP_NATIVE_TYPE_INT)) +#define mp_obj_new_int_from_uint(i) (mp_fun_table.native_to_obj(i, MP_NATIVE_TYPE_UINT)) #define mp_obj_new_str(data, len) (mp_fun_table.obj_new_str((data), (len))) #define mp_obj_new_str_of_type(t, d, l) (mp_obj_new_str_of_type_dyn((t), (d), (l))) #define mp_obj_new_bytes(data, len) (mp_fun_table.obj_new_bytes((data), (len))) @@ -106,11 +107,14 @@ static inline void *m_realloc_dyn(void *ptr, size_t new_num_bytes) { #define mp_obj_get_type(o) (mp_fun_table.obj_get_type((o))) #define mp_obj_get_int(o) (mp_fun_table.native_from_obj(o, MP_NATIVE_TYPE_INT)) +#define mp_obj_get_int_truncated(o) (mp_fun_table.native_from_obj(o, MP_NATIVE_TYPE_UINT)) #define mp_obj_str_get_str(s) ((void*)mp_fun_table.native_from_obj(s, MP_NATIVE_TYPE_PTR)) #define mp_obj_str_get_data(o, len) (mp_obj_str_get_data_dyn((o), (len))) #define mp_get_buffer_raise(o, bufinfo, fl) (mp_fun_table.get_buffer_raise((o), (bufinfo), (fl))) #define mp_get_stream_raise(s, flags) (mp_fun_table.get_stream_raise((s), (flags))) +#define mp_obj_len(o) (mp_obj_len_dyn(o)) +#define mp_obj_subscr(base, index, val) (mp_fun_table.obj_subscr((base), (index), (val))) #define mp_obj_list_append(list, item) (mp_fun_table.list_append((list), (item))) static inline mp_obj_t mp_obj_new_str_of_type_dyn(const mp_obj_type_t *type, const byte* data, size_t len) { @@ -128,6 +132,11 @@ static inline void *mp_obj_str_get_data_dyn(mp_obj_t o, size_t *l) { return bufinfo.buf; } +static inline mp_obj_t mp_obj_len_dyn(mp_obj_t o) { + // If bytes implemented MP_UNARY_OP_LEN could use: mp_unary_op(MP_UNARY_OP_LEN, o) + return mp_fun_table.call_function_n_kw(mp_fun_table.load_name(MP_QSTR_len), 1, &o); +} + /******************************************************************************/ // General runtime functions From ba84453f77ed8ce5e8ac128bee80d3923a14e9ad Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 13 Dec 2019 13:30:44 +1100 Subject: [PATCH 1054/1788] examples/natmod: Add urandom native module example. --- examples/natmod/urandom/Makefile | 13 ++++++++++++ examples/natmod/urandom/urandom.c | 34 +++++++++++++++++++++++++++++++ extmod/modurandom.c | 4 ++++ tests/run-natmodtests.py | 1 + 4 files changed, 52 insertions(+) create mode 100644 examples/natmod/urandom/Makefile create mode 100644 examples/natmod/urandom/urandom.c diff --git a/examples/natmod/urandom/Makefile b/examples/natmod/urandom/Makefile new file mode 100644 index 0000000000..3f018baaf7 --- /dev/null +++ b/examples/natmod/urandom/Makefile @@ -0,0 +1,13 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module (different to built-in urandom so it can coexist) +MOD = urandom_$(ARCH) + +# Source files (.c or .py) +SRC = urandom.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) +ARCH = x64 + +include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/urandom/urandom.c b/examples/natmod/urandom/urandom.c new file mode 100644 index 0000000000..732e439eea --- /dev/null +++ b/examples/natmod/urandom/urandom.c @@ -0,0 +1,34 @@ +#define MICROPY_ENABLE_DYNRUNTIME (1) +#define MICROPY_PY_URANDOM (1) +#define MICROPY_PY_URANDOM_EXTRA_FUNCS (1) + +#include "py/dynruntime.h" + +// Dynamic native modules don't support a data section so these must go in the BSS +uint32_t yasmarang_pad, yasmarang_n, yasmarang_d; +uint8_t yasmarang_dat; + +#include "extmod/modurandom.c" + +mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + MP_DYNRUNTIME_INIT_ENTRY + + yasmarang_pad = 0xeda4baba; + yasmarang_n = 69; + yasmarang_d = 233; + + mp_store_global(MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR_urandom)); + mp_store_global(MP_QSTR_getrandbits, MP_OBJ_FROM_PTR(&mod_urandom_getrandbits_obj)); + mp_store_global(MP_QSTR_seed, MP_OBJ_FROM_PTR(&mod_urandom_seed_obj)); + #if MICROPY_PY_URANDOM_EXTRA_FUNCS + mp_store_global(MP_QSTR_randrange, MP_OBJ_FROM_PTR(&mod_urandom_randrange_obj)); + mp_store_global(MP_QSTR_randint, MP_OBJ_FROM_PTR(&mod_urandom_randint_obj)); + mp_store_global(MP_QSTR_choice, MP_OBJ_FROM_PTR(&mod_urandom_choice_obj)); + #if MICROPY_PY_BUILTINS_FLOAT + mp_store_global(MP_QSTR_random, MP_OBJ_FROM_PTR(&mod_urandom_random_obj)); + mp_store_global(MP_QSTR_uniform, MP_OBJ_FROM_PTR(&mod_urandom_uniform_obj)); + #endif + #endif + + MP_DYNRUNTIME_INIT_EXIT +} diff --git a/extmod/modurandom.c b/extmod/modurandom.c index 2e667570d6..e3c7fc7f59 100644 --- a/extmod/modurandom.c +++ b/extmod/modurandom.c @@ -36,8 +36,10 @@ // http://www.literatecode.com/yasmarang // Public Domain +#if !MICROPY_ENABLE_DYNRUNTIME STATIC uint32_t yasmarang_pad = 0xeda4baba, yasmarang_n = 69, yasmarang_d = 233; STATIC uint8_t yasmarang_dat = 0; +#endif STATIC uint32_t yasmarang(void) { @@ -208,6 +210,7 @@ STATIC mp_obj_t mod_urandom___init__() { STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_urandom___init___obj, mod_urandom___init__); #endif +#if !MICROPY_ENABLE_DYNRUNTIME STATIC const mp_rom_map_elem_t mp_module_urandom_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_urandom) }, #ifdef MICROPY_PY_URANDOM_SEED_INIT_FUNC @@ -232,5 +235,6 @@ const mp_obj_module_t mp_module_urandom = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_urandom_globals, }; +#endif #endif //MICROPY_PY_URANDOM diff --git a/tests/run-natmodtests.py b/tests/run-natmodtests.py index 186c30b831..3f49a1d68a 100755 --- a/tests/run-natmodtests.py +++ b/tests/run-natmodtests.py @@ -23,6 +23,7 @@ TEST_MAPPINGS = { 'btree': 'btree/btree_$(ARCH).mpy', 'framebuf': 'framebuf/framebuf_$(ARCH).mpy', 'uheapq': 'uheapq/uheapq_$(ARCH).mpy', + 'urandom': 'urandom/urandom_$(ARCH).mpy', 'ure': 'ure/ure_$(ARCH).mpy', 'uzlib': 'uzlib/uzlib_$(ARCH).mpy', } From 4da763fc49af5d7c6bbcd1af89135320022bffd0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 13 Dec 2019 13:32:15 +1100 Subject: [PATCH 1055/1788] travis: Build urandom native module in coverage job. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index fef8bbbcfb..36998300db 100644 --- a/.travis.yml +++ b/.travis.yml @@ -87,6 +87,7 @@ jobs: - make -C examples/natmod/btree ARCH=x64 - make -C examples/natmod/framebuf ARCH=x64 - make -C examples/natmod/uheapq ARCH=x64 + - make -C examples/natmod/urandom ARCH=x64 - make -C examples/natmod/ure ARCH=x64 - make -C examples/natmod/uzlib ARCH=x64 # test importing .mpy generated by mpy_ld.py From 624f4ca39bbbf9c89fce24f4051dcdd9417e59b1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 13 Dec 2019 13:49:34 +1100 Subject: [PATCH 1056/1788] tests: Add .exp files for basics/parser and import/import_override. Because CPython 3.8.0 now produces different output: - basics/parser.py: CPython does not allow '\\\n' as input. - import/import_override: CPython imports _io. --- tests/basics/parser.py.exp | 3 +++ tests/import/import_override.py.exp | 2 ++ 2 files changed, 5 insertions(+) create mode 100644 tests/basics/parser.py.exp create mode 100644 tests/import/import_override.py.exp diff --git a/tests/basics/parser.py.exp b/tests/basics/parser.py.exp new file mode 100644 index 0000000000..4d9886a09c --- /dev/null +++ b/tests/basics/parser.py.exp @@ -0,0 +1,3 @@ +SyntaxError +SyntaxError +SyntaxError diff --git a/tests/import/import_override.py.exp b/tests/import/import_override.py.exp new file mode 100644 index 0000000000..365248da6d --- /dev/null +++ b/tests/import/import_override.py.exp @@ -0,0 +1,2 @@ +import import1b None 0 +456 From 71c6bfd08a91c942decbfd659cafd2773afb00b4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 13 Dec 2019 14:18:55 +1100 Subject: [PATCH 1057/1788] stm32/modusocket: Handle case of NULL NIC in socket ioctl. --- ports/stm32/modusocket.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ports/stm32/modusocket.c b/ports/stm32/modusocket.c index 46d7240ca8..9af6e371f0 100644 --- a/ports/stm32/modusocket.c +++ b/ports/stm32/modusocket.c @@ -369,6 +369,13 @@ mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int * } return 0; } + if (self->nic == MP_OBJ_NULL) { + if (request == MP_STREAM_POLL) { + return MP_STREAM_POLL_NVAL; + } + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } return self->nic_type->ioctl(self, request, arg, errcode); } From 33b0a7e6019a7058d2eab3c9623096d4b6f7f6b7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 13 Dec 2019 14:49:16 +1100 Subject: [PATCH 1058/1788] tests/stress/qstr_limit: Tune params to run with stm32 port. Because MICROPY_ALLOC_PATH_MAX is only 128 for this port. --- tests/stress/qstr_limit.py | 12 +++++------- tests/stress/qstr_limit.py.exp | 10 +++++----- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/tests/stress/qstr_limit.py b/tests/stress/qstr_limit.py index 90c85dae96..889ab7e51c 100644 --- a/tests/stress/qstr_limit.py +++ b/tests/stress/qstr_limit.py @@ -64,19 +64,17 @@ for l in range(254, 259): print('RuntimeError', l) # import module -# (different OS's have different results so only print those that are consistent) -for l in range(150, 259): +# (different OS's have different results so only run those that are consistent) +for l in (100, 101, 256, 257, 258): try: __import__(make_id(l)) except ImportError: - if l < 152: - print('ok', l) + print('ok', l) except RuntimeError: - if l > 255: - print('RuntimeError', l) + print('RuntimeError', l) # import package -for l in range(125, 130): +for l in (100, 101, 102, 128, 129): try: exec('import ' + make_id(l) + '.' + make_id(l, 'A')) except ImportError: diff --git a/tests/stress/qstr_limit.py.exp b/tests/stress/qstr_limit.py.exp index 516c9d7f6c..455761bc71 100644 --- a/tests/stress/qstr_limit.py.exp +++ b/tests/stress/qstr_limit.py.exp @@ -31,13 +31,13 @@ RuntimeError 258 RuntimeError 256 RuntimeError 257 RuntimeError 258 -ok 150 -ok 151 +ok 100 +ok 101 RuntimeError 256 RuntimeError 257 RuntimeError 258 -ok 125 -ok 126 -ok 127 +ok 100 +ok 101 +ok 102 RuntimeError 128 RuntimeError 129 From 1098d1d630105cc64aae1175a6cc3f40054ba048 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 13 Dec 2019 15:38:03 +1100 Subject: [PATCH 1059/1788] tests/basics/memoryview_itemsize: Make portable to 32- and 64-bit archs. --- tests/basics/memoryview_itemsize.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/basics/memoryview_itemsize.py b/tests/basics/memoryview_itemsize.py index cd7a87c23d..64a8822b8b 100644 --- a/tests/basics/memoryview_itemsize.py +++ b/tests/basics/memoryview_itemsize.py @@ -12,9 +12,12 @@ except ImportError: print("SKIP") raise SystemExit -for code in ['b', 'h', 'i', 'l', 'q', 'f', 'd']: +for code in ['b', 'h', 'i', 'q', 'f', 'd']: print(memoryview(array(code)).itemsize) +# 'l' varies depending on word size of the machine +print(memoryview(array('l')).itemsize in (4, 8)) + # shouldn't be able to store to the itemsize attribute try: memoryview(b'a').itemsize = 1 From 7280bf40d9b43118cca87a7321c088e118a5ebc1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 13 Dec 2019 15:38:45 +1100 Subject: [PATCH 1060/1788] tests/extmod/vfs_lfs_error: Use small ints in seek error test. So accessing the seek offset (at the C level) doesn't cause an OverflowError on 32-bit targets. --- tests/extmod/vfs_lfs_error.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/extmod/vfs_lfs_error.py b/tests/extmod/vfs_lfs_error.py index b97fe6ec15..793fae59e2 100644 --- a/tests/extmod/vfs_lfs_error.py +++ b/tests/extmod/vfs_lfs_error.py @@ -106,8 +106,9 @@ def test(bdev, vfs_class): # error during seek with vfs.open('testfile', 'r') as f: + f.seek(1 << 30) # SEEK_SET try: - f.seek(1 << 31) + f.seek(1 << 30, 1) # SEEK_CUR except OSError: print('seek OSError') From 4b184d12819139fc51073248614111c45a5ac631 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 13 Dec 2019 16:43:17 +1100 Subject: [PATCH 1061/1788] tests/pyb: Refactor pyboard tests to work on PYBv1, PYBLITEv1 and PYBD. --- tests/pyb/accel.py | 4 ++++ tests/pyb/adc.py | 2 +- tests/pyb/adc.py.exp | 2 +- tests/pyb/board_pybv1x.py | 39 +++++++++++++++++++++++++++++++++++ tests/pyb/board_pybv1x.py.exp | 29 ++++++++++++++++++++++++++ tests/pyb/can.py | 25 +++++++--------------- tests/pyb/can.py.exp | 9 +------- tests/pyb/can2.py | 24 +++++++++++++++++++++ tests/pyb/can2.py.exp | 4 ++++ tests/pyb/extint.py | 2 +- tests/pyb/extint.py.exp | 6 +++--- tests/pyb/halerror.py | 15 -------------- tests/pyb/halerror.py.exp | 2 -- tests/pyb/i2c.py | 20 ++---------------- tests/pyb/i2c.py.exp | 8 ------- tests/pyb/i2c_accel.py | 23 +++++++++++++++++++++ tests/pyb/i2c_accel.py.exp | 3 +++ tests/pyb/i2c_error.py | 4 ++++ tests/pyb/led.py | 24 +++++++++++---------- tests/pyb/led.py.exp | 1 - tests/pyb/pin.py | 8 +++---- tests/pyb/pin.py.exp | 12 +++++------ tests/pyb/pyb_f405.py | 8 +++++++ tests/pyb/pyb_f405.py.exp | 1 + tests/pyb/spi.py | 6 +++--- tests/pyb/spi.py.exp | 6 +----- tests/pyb/uart.py | 4 ++-- tests/pyb/uart.py.exp | 7 ------- 28 files changed, 185 insertions(+), 113 deletions(-) create mode 100644 tests/pyb/board_pybv1x.py create mode 100644 tests/pyb/board_pybv1x.py.exp create mode 100644 tests/pyb/can2.py create mode 100644 tests/pyb/can2.py.exp delete mode 100644 tests/pyb/halerror.py delete mode 100644 tests/pyb/halerror.py.exp create mode 100644 tests/pyb/i2c_accel.py create mode 100644 tests/pyb/i2c_accel.py.exp diff --git a/tests/pyb/accel.py b/tests/pyb/accel.py index e5a1a2ed7a..9aa60c1859 100644 --- a/tests/pyb/accel.py +++ b/tests/pyb/accel.py @@ -1,5 +1,9 @@ import pyb +if not hasattr(pyb, 'Accel'): + print('SKIP') + raise SystemExit + accel = pyb.Accel() print(accel) accel.x() diff --git a/tests/pyb/adc.py b/tests/pyb/adc.py index 0bd9b9d53a..ef42065388 100644 --- a/tests/pyb/adc.py +++ b/tests/pyb/adc.py @@ -1,7 +1,7 @@ from pyb import ADC, Timer adct = ADC(16) # Temperature 930 -> 20C -print(adct) +print(str(adct)[:19]) adcv = ADC(17) # Voltage 1500 -> 3.3V print(adcv) diff --git a/tests/pyb/adc.py.exp b/tests/pyb/adc.py.exp index 1aae16fb01..381329cdde 100644 --- a/tests/pyb/adc.py.exp +++ b/tests/pyb/adc.py.exp @@ -1,4 +1,4 @@ - + 50 25 diff --git a/tests/pyb/board_pybv1x.py b/tests/pyb/board_pybv1x.py new file mode 100644 index 0000000000..f4aeeb99eb --- /dev/null +++ b/tests/pyb/board_pybv1x.py @@ -0,0 +1,39 @@ +# Test board-specific items on PYBv1.x + +import os, pyb + +if not 'PYBv1.' in os.uname().machine: + print('SKIP') + raise SystemExit + +# test creating UART by id/name +for bus in (1, 2, 3, 4, 5, 6, 7, "XA", "XB", "YA", "YB", "Z"): + try: + pyb.UART(bus, 9600) + print("UART", bus) + except ValueError: + print("ValueError", bus) + +# test creating SPI by id/name +for bus in (1, 2, 3, "X", "Y", "Z"): + try: + pyb.SPI(bus) + print("SPI", bus) + except ValueError: + print("ValueError", bus) + +# test creating I2C by id/name +for bus in (2, 3, "X", "Y", "Z"): + try: + pyb.I2C(bus) + print("I2C", bus) + except ValueError: + print("ValueError", bus) + +# test creating CAN by id/name +for bus in (1, 2, 3, "YA", "YB", "YC"): + try: + pyb.CAN(bus, pyb.CAN.LOOPBACK) + print("CAN", bus) + except ValueError: + print("ValueError", bus) diff --git a/tests/pyb/board_pybv1x.py.exp b/tests/pyb/board_pybv1x.py.exp new file mode 100644 index 0000000000..6d4a6f63c7 --- /dev/null +++ b/tests/pyb/board_pybv1x.py.exp @@ -0,0 +1,29 @@ +UART 1 +UART 2 +UART 3 +UART 4 +ValueError 5 +UART 6 +ValueError 7 +UART XA +UART XB +UART YA +UART YB +ValueError Z +SPI 1 +SPI 2 +ValueError 3 +SPI X +SPI Y +ValueError Z +I2C 2 +ValueError 3 +I2C X +I2C Y +ValueError Z +CAN 1 +CAN 2 +ValueError 3 +CAN YA +CAN YB +ValueError YC diff --git a/tests/pyb/can.py b/tests/pyb/can.py index 8a08ea9a65..71de724c76 100644 --- a/tests/pyb/can.py +++ b/tests/pyb/can.py @@ -8,8 +8,8 @@ from array import array import micropython import pyb -# test we can correctly create by id or name -for bus in (-1, 0, 1, 2, 3, "YA", "YB", "YC"): +# test we can correctly create by id (2 handled in can2.py test) +for bus in (-1, 0, 1, 3): try: CAN(bus, CAN.LOOPBACK) print("CAN", bus) @@ -273,18 +273,11 @@ while can.any(0): # Testing rtr messages bus1 = CAN(1, CAN.LOOPBACK) -bus2 = CAN(2, CAN.LOOPBACK, extframe = True) while bus1.any(0): bus1.recv(0) -while bus2.any(0): - bus2.recv(0) bus1.setfilter(0, CAN.LIST16, 0, (1, 2, 3, 4)) bus1.setfilter(1, CAN.LIST16, 0, (5, 6, 7, 8), rtr=(True, True, True, True)) bus1.setfilter(2, CAN.MASK16, 0, (64, 64, 32, 32), rtr=(False, True)) -bus2.setfilter(0, CAN.LIST32, 0, (1, 2), rtr=(True, True)) -bus2.setfilter(1, CAN.LIST32, 0, (3, 4), rtr=(True, False)) -bus2.setfilter(2, CAN.MASK32, 0, (16, 16), rtr=(False,)) -bus2.setfilter(2, CAN.MASK32, 0, (32, 32), rtr=(True,)) bus1.send('',1,rtr=True) print(bus1.any(0)) @@ -299,11 +292,9 @@ print(bus1.any(0)) bus1.send('',32,rtr=True) print(bus1.recv(0)) -bus2.send('',1,rtr=True) -print(bus2.recv(0)) -bus2.send('',2,rtr=True) -print(bus2.recv(0)) -bus2.send('',3,rtr=True) -print(bus2.recv(0)) -bus2.send('',4,rtr=True) -print(bus2.any(0)) +# test HAL error, timeout +can = pyb.CAN(1, pyb.CAN.NORMAL) +try: + can.send('1', 1, timeout=50) +except OSError as e: + print(repr(e)) diff --git a/tests/pyb/can.py.exp b/tests/pyb/can.py.exp index 687935e7f4..a27907cc52 100644 --- a/tests/pyb/can.py.exp +++ b/tests/pyb/can.py.exp @@ -1,11 +1,7 @@ ValueError -1 ValueError 0 CAN 1 -CAN 2 ValueError 3 -CAN YA -CAN YB -ValueError YC CAN(1) True CAN(1, CAN.LOOPBACK, extframe=False, auto_restart=False) @@ -70,7 +66,4 @@ False (7, True, 6, b'') False (32, True, 9, b'') -(1, True, 0, b'') -(2, True, 1, b'') -(3, True, 2, b'') -False +OSError(110,) diff --git a/tests/pyb/can2.py b/tests/pyb/can2.py new file mode 100644 index 0000000000..440ae4925b --- /dev/null +++ b/tests/pyb/can2.py @@ -0,0 +1,24 @@ +try: + from pyb import CAN + CAN(2) +except (ImportError, ValueError): + print('SKIP') + raise SystemExit + +# Testing rtr messages +bus2 = CAN(2, CAN.LOOPBACK, extframe=True) +while bus2.any(0): + bus2.recv(0) +bus2.setfilter(0, CAN.LIST32, 0, (1, 2), rtr=(True, True)) +bus2.setfilter(1, CAN.LIST32, 0, (3, 4), rtr=(True, False)) +bus2.setfilter(2, CAN.MASK32, 0, (16, 16), rtr=(False,)) +bus2.setfilter(2, CAN.MASK32, 0, (32, 32), rtr=(True,)) + +bus2.send('',1,rtr=True) +print(bus2.recv(0)) +bus2.send('',2,rtr=True) +print(bus2.recv(0)) +bus2.send('',3,rtr=True) +print(bus2.recv(0)) +bus2.send('',4,rtr=True) +print(bus2.any(0)) diff --git a/tests/pyb/can2.py.exp b/tests/pyb/can2.py.exp new file mode 100644 index 0000000000..371ad2bdc4 --- /dev/null +++ b/tests/pyb/can2.py.exp @@ -0,0 +1,4 @@ +(1, True, 0, b'') +(2, True, 1, b'') +(3, True, 2, b'') +False diff --git a/tests/pyb/extint.py b/tests/pyb/extint.py index ae98ccd5a0..8b6bc56517 100644 --- a/tests/pyb/extint.py +++ b/tests/pyb/extint.py @@ -1,7 +1,7 @@ import pyb # test basic functionality -ext = pyb.ExtInt('Y1', pyb.ExtInt.IRQ_RISING, pyb.Pin.PULL_DOWN, lambda l:print('line:', l)) +ext = pyb.ExtInt('X5', pyb.ExtInt.IRQ_RISING, pyb.Pin.PULL_DOWN, lambda l:print('line:', l)) ext.disable() ext.enable() print(ext.line()) diff --git a/tests/pyb/extint.py.exp b/tests/pyb/extint.py.exp index 1f9da9844a..fbd820ed43 100644 --- a/tests/pyb/extint.py.exp +++ b/tests/pyb/extint.py.exp @@ -1,3 +1,3 @@ -6 -line: 6 -line: 6 +4 +line: 4 +line: 4 diff --git a/tests/pyb/halerror.py b/tests/pyb/halerror.py deleted file mode 100644 index 1a6bce1a7e..0000000000 --- a/tests/pyb/halerror.py +++ /dev/null @@ -1,15 +0,0 @@ -# test hal errors - -import pyb - -i2c = pyb.I2C(2, pyb.I2C.MASTER) -try: - i2c.recv(1, 1) -except OSError as e: - print(repr(e)) - -can = pyb.CAN(1, pyb.CAN.NORMAL) -try: - can.send('1', 1, timeout=50) -except OSError as e: - print(repr(e)) diff --git a/tests/pyb/halerror.py.exp b/tests/pyb/halerror.py.exp deleted file mode 100644 index 0f3f26253d..0000000000 --- a/tests/pyb/halerror.py.exp +++ /dev/null @@ -1,2 +0,0 @@ -OSError(5,) -OSError(110,) diff --git a/tests/pyb/i2c.py b/tests/pyb/i2c.py index 6875e5a5aa..bc9dba8781 100644 --- a/tests/pyb/i2c.py +++ b/tests/pyb/i2c.py @@ -1,8 +1,8 @@ import pyb from pyb import I2C -# test we can correctly create by id or name -for bus in (-1, 0, 1, 2, 3, "X", "Y", "Z"): +# test we can correctly create by id +for bus in (-1, 0, 1): try: I2C(bus) print("I2C", bus) @@ -14,19 +14,3 @@ i2c = I2C(1) i2c.init(I2C.MASTER, baudrate=400000) print(i2c.scan()) i2c.deinit() - -# use accelerometer to test i2c bus - -accel_addr = 76 - -pyb.Accel() # this will init the MMA for us -i2c.init(I2C.MASTER, baudrate=400000) - -print(i2c.scan()) -print(i2c.is_ready(accel_addr)) - -print(i2c.mem_read(1, accel_addr, 7, timeout=500)) -i2c.mem_write(0, accel_addr, 0, timeout=500) - -i2c.send(7, addr=accel_addr) -i2c.recv(1, addr=accel_addr) diff --git a/tests/pyb/i2c.py.exp b/tests/pyb/i2c.py.exp index 709fb412de..bd896ea74e 100644 --- a/tests/pyb/i2c.py.exp +++ b/tests/pyb/i2c.py.exp @@ -1,12 +1,4 @@ ValueError -1 ValueError 0 I2C 1 -I2C 2 -ValueError 3 -I2C X -I2C Y -ValueError Z [] -[76] -True -b'\x01' diff --git a/tests/pyb/i2c_accel.py b/tests/pyb/i2c_accel.py new file mode 100644 index 0000000000..e42cba178a --- /dev/null +++ b/tests/pyb/i2c_accel.py @@ -0,0 +1,23 @@ +# use accelerometer to test i2c bus + +import pyb +from pyb import I2C + +if not hasattr(pyb, 'Accel'): + print('SKIP') + raise SystemExit + +accel_addr = 76 + +pyb.Accel() # this will init the MMA for us + +i2c = I2C(1, I2C.MASTER, baudrate=400000) + +print(i2c.scan()) +print(i2c.is_ready(accel_addr)) + +print(i2c.mem_read(1, accel_addr, 7, timeout=500)) +i2c.mem_write(0, accel_addr, 0, timeout=500) + +i2c.send(7, addr=accel_addr) +i2c.recv(1, addr=accel_addr) diff --git a/tests/pyb/i2c_accel.py.exp b/tests/pyb/i2c_accel.py.exp new file mode 100644 index 0000000000..206a2eb4c2 --- /dev/null +++ b/tests/pyb/i2c_accel.py.exp @@ -0,0 +1,3 @@ +[76] +True +b'\x01' diff --git a/tests/pyb/i2c_error.py b/tests/pyb/i2c_error.py index 3201d6367d..e0f721179f 100644 --- a/tests/pyb/i2c_error.py +++ b/tests/pyb/i2c_error.py @@ -3,6 +3,10 @@ import pyb from pyb import I2C +if not hasattr(pyb, 'Accel'): + print('SKIP') + raise SystemExit + # init accelerometer pyb.Accel() diff --git a/tests/pyb/led.py b/tests/pyb/led.py index d2a17ebc9a..38e9993cb0 100644 --- a/tests/pyb/led.py +++ b/tests/pyb/led.py @@ -1,17 +1,19 @@ -import pyb -from pyb import LED +import os, pyb -l1 = pyb.LED(1) -l2 = pyb.LED(2) -l3 = pyb.LED(3) -l4 = pyb.LED(4) - -leds = [LED(i) for i in range(1, 5)] -pwm_leds = leds[2:] +machine = os.uname().machine +if 'PYBv1.' in machine or 'PYBLITEv1.' in machine: + leds = [pyb.LED(i) for i in range(1, 5)] + pwm_leds = leds[2:] +elif 'PYBD' in machine: + leds = [pyb.LED(i) for i in range(1, 4)] + pwm_leds = [] +else: + print('SKIP') + raise SystemExit # test printing -for l in leds: - print(l) +for i in range(3): + print(leds[i]) # test on and off for l in leds: diff --git a/tests/pyb/led.py.exp b/tests/pyb/led.py.exp index 4e8d856cd9..b4170c41e4 100644 --- a/tests/pyb/led.py.exp +++ b/tests/pyb/led.py.exp @@ -1,4 +1,3 @@ LED(1) LED(2) LED(3) -LED(4) diff --git a/tests/pyb/pin.py b/tests/pyb/pin.py index 9b37883438..ea42cc206f 100644 --- a/tests/pyb/pin.py +++ b/tests/pyb/pin.py @@ -1,14 +1,14 @@ from pyb import Pin -p = Pin('Y1', Pin.IN) +p = Pin('X8', Pin.IN) print(p) print(p.name()) print(p.pin()) print(p.port()) -p = Pin('Y1', Pin.IN, Pin.PULL_UP) -p = Pin('Y1', Pin.IN, pull=Pin.PULL_UP) -p = Pin('Y1', mode=Pin.IN, pull=Pin.PULL_UP) +p = Pin('X8', Pin.IN, Pin.PULL_UP) +p = Pin('X8', Pin.IN, pull=Pin.PULL_UP) +p = Pin('X8', mode=Pin.IN, pull=Pin.PULL_UP) print(p) print(p.value()) diff --git a/tests/pyb/pin.py.exp b/tests/pyb/pin.py.exp index f2f7038fd4..a2a7e42d96 100644 --- a/tests/pyb/pin.py.exp +++ b/tests/pyb/pin.py.exp @@ -1,10 +1,10 @@ -Pin(Pin.cpu.C6, mode=Pin.IN) -C6 -6 -2 -Pin(Pin.cpu.C6, mode=Pin.IN, pull=Pin.PULL_UP) +Pin(Pin.cpu.A7, mode=Pin.IN) +A7 +7 +0 +Pin(Pin.cpu.A7, mode=Pin.IN, pull=Pin.PULL_UP) 1 -Pin(Pin.cpu.C6, mode=Pin.IN, pull=Pin.PULL_DOWN) +Pin(Pin.cpu.A7, mode=Pin.IN, pull=Pin.PULL_DOWN) 0 0 1 diff --git a/tests/pyb/pyb_f405.py b/tests/pyb/pyb_f405.py index 2f161ae099..f49dd1bc75 100644 --- a/tests/pyb/pyb_f405.py +++ b/tests/pyb/pyb_f405.py @@ -8,3 +8,11 @@ if not 'STM32F405' in os.uname().machine: print(pyb.freq()) print(type(pyb.rng())) + +# test HAL error specific to F405 +i2c = pyb.I2C(2, pyb.I2C.MASTER) +try: + i2c.recv(1, 1) +except OSError as e: + print(repr(e)) + diff --git a/tests/pyb/pyb_f405.py.exp b/tests/pyb/pyb_f405.py.exp index a90aa02686..a52f40920d 100644 --- a/tests/pyb/pyb_f405.py.exp +++ b/tests/pyb/pyb_f405.py.exp @@ -1,2 +1,3 @@ (168000000, 168000000, 42000000, 84000000) +OSError(5,) diff --git a/tests/pyb/spi.py b/tests/pyb/spi.py index 88cc975bb6..577737420f 100644 --- a/tests/pyb/spi.py +++ b/tests/pyb/spi.py @@ -1,7 +1,7 @@ from pyb import SPI -# test we can correctly create by id or name -for bus in (-1, 0, 1, 2, 3, "X", "Y", "Z"): +# test we can correctly create by id +for bus in (-1, 0, 1, 2): try: SPI(bus) print("SPI", bus) @@ -14,7 +14,7 @@ print(spi) spi = SPI(1, SPI.MASTER) spi = SPI(1, SPI.MASTER, baudrate=500000) spi = SPI(1, SPI.MASTER, 500000, polarity=1, phase=0, bits=8, firstbit=SPI.MSB, ti=False, crc=None) -print(spi) +print(str(spi)[:28], str(spi)[49:]) # don't print baudrate/prescaler spi.init(SPI.SLAVE, phase=1) print(spi) diff --git a/tests/pyb/spi.py.exp b/tests/pyb/spi.py.exp index a0d835700f..473c173a58 100644 --- a/tests/pyb/spi.py.exp +++ b/tests/pyb/spi.py.exp @@ -2,12 +2,8 @@ ValueError -1 ValueError 0 SPI 1 SPI 2 -ValueError 3 -SPI X -SPI Y -ValueError Z SPI(1) -SPI(1, SPI.MASTER, baudrate=328125, prescaler=256, polarity=1, phase=0, bits=8) +SPI(1, SPI.MASTER, baudrate= , polarity=1, phase=0, bits=8) SPI(1, SPI.SLAVE, polarity=1, phase=1, bits=8) OSError b'\xff' diff --git a/tests/pyb/uart.py b/tests/pyb/uart.py index 836b073a6d..82a66dd2e0 100644 --- a/tests/pyb/uart.py +++ b/tests/pyb/uart.py @@ -1,7 +1,7 @@ from pyb import UART -# test we can correctly create by id or name -for bus in (-1, 0, 1, 2, 3, 4, 5, 6, 7, "XA", "XB", "YA", "YB", "Z"): +# test we can correctly create by id +for bus in (-1, 0, 1, 2, 5, 6, 7): try: UART(bus, 9600) print("UART", bus) diff --git a/tests/pyb/uart.py.exp b/tests/pyb/uart.py.exp index d302468ed2..1a4cbd9381 100644 --- a/tests/pyb/uart.py.exp +++ b/tests/pyb/uart.py.exp @@ -2,16 +2,9 @@ ValueError -1 ValueError 0 UART 1 UART 2 -UART 3 -UART 4 ValueError 5 UART 6 ValueError 7 -UART XA -UART XB -UART YA -UART YB -ValueError Z UART(1, baudrate=9600, bits=8, parity=None, stop=1, flow=0, timeout=0, timeout_char=3, rxbuf=64) UART(1, baudrate=2400, bits=8, parity=None, stop=1, flow=0, timeout=0, timeout_char=7, rxbuf=64) 0 From fb014155996c7568eb55ab06fdeaf6ff414f0280 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 13 Dec 2019 17:26:30 +1100 Subject: [PATCH 1062/1788] stm32/boards/PYBD_SF2: Configure LEDs as inverted, for LED.intensity(). --- ports/stm32/boards/PYBD_SF2/mpconfigboard.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/stm32/boards/PYBD_SF2/mpconfigboard.h b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h index 8e116bd02a..4ce17abd87 100644 --- a/ports/stm32/boards/PYBD_SF2/mpconfigboard.h +++ b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h @@ -154,6 +154,7 @@ extern struct _spi_bdev_t spi_bdev2; #define MICROPY_HW_USRSW_PRESSED (0) // LEDs +#define MICROPY_HW_LED_INVERTED (1) // LEDs are on when pin is driven low #define MICROPY_HW_LED1 (pyb_pin_LED_RED) #define MICROPY_HW_LED2 (pyb_pin_LED_GREEN) #define MICROPY_HW_LED3 (pyb_pin_LED_BLUE) From f3f7eb48da8bbd108e18103a45f9898846d6eb48 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 16 Dec 2019 12:38:27 +1100 Subject: [PATCH 1063/1788] docs/library/uos.rst: Clarify why the extended interface exists. --- docs/library/uos.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/library/uos.rst b/docs/library/uos.rst index 5505e6434f..bb7e491cce 100644 --- a/docs/library/uos.rst +++ b/docs/library/uos.rst @@ -234,6 +234,10 @@ methods (see below), in order to support a variety of use cases. A given block device may implement one form or the other, or both at the same time. The second form (with the offset parameter) is referred to as the "extended interface". +Some filesystems (such as littlefs) that require more control over write +operations, for example writing to sub-block regions without erasing, may require +that the block device supports the extended interface. + .. class:: AbstractBlockDev(...) Construct a block device object. The parameters to the constructor are From 04e7aa056316d7b4400b508caefe26c6b75384f8 Mon Sep 17 00:00:00 2001 From: ketograph Date: Sat, 14 Dec 2019 16:56:14 +0100 Subject: [PATCH 1064/1788] docs/esp8266/quickref: Add note that machine.RTC is not fully supported. See issues #3220 and #3710. --- docs/esp8266/quickref.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/esp8266/quickref.rst b/docs/esp8266/quickref.rst index a197665043..9c7db3205a 100644 --- a/docs/esp8266/quickref.rst +++ b/docs/esp8266/quickref.rst @@ -249,6 +249,10 @@ See :ref:`machine.RTC ` :: ntptime.settime() # set the rtc datetime from the remote server rtc.datetime() # get the date and time in UTC +.. note:: Not all methods are implemented: `RTC.now()`, `RTC.irq(handler=*) ` + (using a custom handler), `RTC.init()` and `RTC.deinit()` are + currently not supported. + Deep-sleep mode --------------- From 0bd7d1f7f03d086a0789caa8e007cf15068c689c Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 16 Dec 2019 21:53:43 +1100 Subject: [PATCH 1065/1788] py/persistentcode: Move loading of rodata/bss to before obj/raw-code. This makes the loading of viper-code-with-relocations a bit neater and easier to understand, by treating the rodata/bss like a special object to be loaded into the constant table (which is how it behaves). --- py/persistentcode.c | 39 +++++++++++++++++++++++++++------------ tools/mpy_ld.py | 16 +--------------- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/py/persistentcode.c b/py/persistentcode.c index 8bf46202ba..7a8a94b5a6 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -438,9 +438,18 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { // Allocate constant table size_t n_alloc = prelude.n_pos_args + prelude.n_kwonly_args + n_obj + n_raw_code; + #if MICROPY_EMIT_MACHINE_CODE if (kind != MP_CODE_BYTECODE) { ++n_alloc; // additional entry for mp_fun_table + if (prelude.scope_flags & MP_SCOPE_FLAG_VIPERRODATA) { + ++n_alloc; // additional entry for rodata + } + if (prelude.scope_flags & MP_SCOPE_FLAG_VIPERBSS) { + ++n_alloc; // additional entry for BSS + } } + #endif + const_table = m_new(mp_uint_t, n_alloc); mp_uint_t *ct = const_table; @@ -454,6 +463,21 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { if (kind != MP_CODE_BYTECODE) { // Populate mp_fun_table entry *ct++ = (mp_uint_t)(uintptr_t)&mp_fun_table; + + // Allocate and load rodata if needed + if (prelude.scope_flags & MP_SCOPE_FLAG_VIPERRODATA) { + size_t size = read_uint(reader, NULL); + uint8_t *rodata = m_new(uint8_t, size); + read_bytes(reader, rodata, size); + *ct++ = (uintptr_t)rodata; + } + + // Allocate BSS if needed + if (prelude.scope_flags & MP_SCOPE_FLAG_VIPERBSS) { + size_t size = read_uint(reader, NULL); + uint8_t *bss = m_new0(uint8_t, size); + *ct++ = (uintptr_t)bss; + } } #endif @@ -469,6 +493,7 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { // Create raw_code and return it mp_raw_code_t *rc = mp_emit_glue_new_raw_code(); if (kind == MP_CODE_BYTECODE) { + // Assign bytecode to raw code object mp_emit_glue_assign_bytecode(rc, fun_data, #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS fun_data_len, @@ -481,18 +506,7 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { #if MICROPY_EMIT_MACHINE_CODE } else { - mp_uint_t *ct = &const_table[1]; - if (prelude.scope_flags & MP_SCOPE_FLAG_VIPERRODATA) { - size_t size = read_uint(reader, NULL); - uint8_t *rodata = m_new(uint8_t, size); - read_bytes(reader, rodata, size); - *ct++ = (uintptr_t)rodata; - } - if (prelude.scope_flags & MP_SCOPE_FLAG_VIPERBSS) { - size_t size = read_uint(reader, NULL); - uint8_t *bss = m_new0(uint8_t, size); - *ct++ = (uintptr_t)bss; - } + // Relocate and commit code to executable address space reloc_info_t ri = {reader, const_table}; #if defined(MP_PLAT_COMMIT_EXEC) void *opt_ri = (prelude.scope_flags & MP_SCOPE_FLAG_VIPERRELOC) ? &ri : NULL; @@ -503,6 +517,7 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { } #endif + // Assign native code to raw code object mp_emit_glue_assign_native(rc, kind, fun_data, fun_data_len, const_table, #if MICROPY_PERSISTENT_CODE_SAVE diff --git a/tools/mpy_ld.py b/tools/mpy_ld.py index ec600f9671..31c3912991 100755 --- a/tools/mpy_ld.py +++ b/tools/mpy_ld.py @@ -765,14 +765,6 @@ class MPYOutput: self.write_uint(len(s) << 1) self.write_bytes(s) - def write_obj(self, o): - if o is Ellipsis: - self.write_bytes(b'e') - return - else: - # Other Python types not implemented - assert 0 - def write_reloc(self, base, offset, dest, n): need_offset = not (base == self.prev_base and offset == self.prev_offset + 1) self.prev_offset = offset + n - 1 @@ -845,17 +837,11 @@ def build_mpy(env, entry_offset, fmpy, native_qstr_vals, native_qstr_objs): out.write_uint(scope_flags) # MPY: n_obj - out.write_uint(bool(len(env.full_rodata)) + bool(len(env.full_bss))) + out.write_uint(0) # MPY: n_raw_code out.write_uint(0) - # MPY: optional bytes object with rodata - if len(env.full_rodata): - out.write_obj(Ellipsis) - if len(env.full_bss): - out.write_obj(Ellipsis) - # MPY: rodata and/or bss if len(env.full_rodata): rodata_const_table_idx = 1 From 1e2f7515917345ee2937f2870827cf15c29509ab Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 17 Dec 2019 13:18:08 +1100 Subject: [PATCH 1066/1788] qemu-arm: Let tinytest.o be built by standard build rules. This makes sure tinytest.o is rebuilt if any of its dependencies change. --- ports/qemu-arm/Makefile | 5 +---- ports/qemu-arm/Makefile.test | 3 +-- ports/qemu-arm/test_main.c | 5 ++--- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/ports/qemu-arm/Makefile b/ports/qemu-arm/Makefile index e06e5dd5ee..4f12173c3f 100644 --- a/ports/qemu-arm/Makefile +++ b/ports/qemu-arm/Makefile @@ -33,12 +33,9 @@ endif CROSS_COMPILE = arm-none-eabi- -TINYTEST = $(TOP)/lib/tinytest - INC += -I. INC += -I$(TOP) INC += -I$(BUILD) -INC += -I$(TINYTEST) CFLAGS += $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 $(COPT) \ -ffunction-sections -fdata-sections @@ -71,6 +68,7 @@ SRC_RUN_C = \ SRC_TEST_C = \ test_main.c \ + lib/tinytest/tinytest.c \ LIB_SRC_C += $(addprefix lib/,\ libc/string0.c \ @@ -108,7 +106,6 @@ ALL_OBJ_RUN = $(OBJ_COMMON) $(OBJ_RUN) OBJ_TEST = OBJ_TEST += $(addprefix $(BUILD)/, $(SRC_TEST_C:.c=.o)) -OBJ_TEST += $(BUILD)/tinytest.o ALL_OBJ_TEST = $(OBJ_COMMON) $(OBJ_TEST) diff --git a/ports/qemu-arm/Makefile.test b/ports/qemu-arm/Makefile.test index df0ba9939d..340e1c3b90 100644 --- a/ports/qemu-arm/Makefile.test +++ b/ports/qemu-arm/Makefile.test @@ -13,8 +13,7 @@ $(BUILD)/genhdr/tests.h: (cd $(TOP)/tests; ./run-tests --target=qemu-arm --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)/lib/tinytest/tinytest.o: CFLAGS += -DNO_FORKING $(BUILD)/firmware-test.elf: $(LDSCRIPT) $(ALL_OBJ_TEST) $(Q)$(LD) $(LDFLAGS) -o $@ $(ALL_OBJ_TEST) $(LIBS) diff --git a/ports/qemu-arm/test_main.c b/ports/qemu-arm/test_main.c index 3a85d65f38..3fd2c01484 100644 --- a/ports/qemu-arm/test_main.c +++ b/ports/qemu-arm/test_main.c @@ -12,9 +12,8 @@ #include "py/gc.h" #include "py/mperrno.h" #include "lib/utils/gchelper.h" - -#include "tinytest.h" -#include "tinytest_macros.h" +#include "lib/tinytest/tinytest.h" +#include "lib/tinytest/tinytest_macros.h" #define HEAP_SIZE (100 * 1024) From ba12cdba851f973044c54becca27735a79312707 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 18 Dec 2019 15:04:00 +1100 Subject: [PATCH 1067/1788] examples/network: Add testing key/cert to SSL HTTP server example. This example will now work on all ports with networking and ssl support, with both axtls and mbedtls. --- examples/network/http_server_ssl.py | 33 ++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/examples/network/http_server_ssl.py b/examples/network/http_server_ssl.py index 9a69ca9d41..47d83bf247 100644 --- a/examples/network/http_server_ssl.py +++ b/examples/network/http_server_ssl.py @@ -1,3 +1,4 @@ +import ubinascii as binascii try: import usocket as socket except: @@ -5,6 +6,35 @@ except: import ussl as ssl +# This self-signed key/cert pair is randomly generated and to be used for +# testing/demonstration only. You should always generate your own key/cert. +key = binascii.unhexlify( + b'3082013b020100024100cc20643fd3d9c21a0acba4f48f61aadd675f52175a9dcf07fbef' + b'610a6a6ba14abb891745cd18a1d4c056580d8ff1a639460f867013c8391cdc9f2e573b0f' + b'872d0203010001024100bb17a54aeb3dd7ae4edec05e775ca9632cf02d29c2a089b563b0' + b'd05cdf95aeca507de674553f28b4eadaca82d5549a86058f9996b07768686a5b02cb240d' + b'd9f1022100f4a63f5549e817547dca97b5c658038e8593cb78c5aba3c4642cc4cd031d86' + b'8f022100d598d870ffe4a34df8de57047a50b97b71f4d23e323f527837c9edae88c79483' + b'02210098560c89a70385c36eb07fd7083235c4c1184e525d838aedf7128958bedfdbb102' + b'2051c0dab7057a8176ca966f3feb81123d4974a733df0f958525f547dfd1c271f9022044' + b'6c2cafad455a671a8cf398e642e1be3b18a3d3aec2e67a9478f83c964c4f1f') +cert = binascii.unhexlify( + b'308201d53082017f020203e8300d06092a864886f70d01010505003075310b3009060355' + b'0406130258583114301206035504080c0b54686550726f76696e63653110300e06035504' + b'070c075468654369747931133011060355040a0c0a436f6d70616e7958595a3113301106' + b'0355040b0c0a436f6d70616e7958595a3114301206035504030c0b546865486f73744e61' + b'6d65301e170d3139313231383033333935355a170d3239313231353033333935355a3075' + b'310b30090603550406130258583114301206035504080c0b54686550726f76696e636531' + b'10300e06035504070c075468654369747931133011060355040a0c0a436f6d70616e7958' + b'595a31133011060355040b0c0a436f6d70616e7958595a3114301206035504030c0b5468' + b'65486f73744e616d65305c300d06092a864886f70d0101010500034b003048024100cc20' + b'643fd3d9c21a0acba4f48f61aadd675f52175a9dcf07fbef610a6a6ba14abb891745cd18' + b'a1d4c056580d8ff1a639460f867013c8391cdc9f2e573b0f872d0203010001300d06092a' + b'864886f70d0101050500034100b0513fe2829e9ecbe55b6dd14c0ede7502bde5d46153c8' + b'e960ae3ebc247371b525caeb41bbcf34686015a44c50d226e66aef0a97a63874ca5944ef' + b'979b57f0b3') + + CONTENT = b"""\ HTTP/1.0 200 OK @@ -31,7 +61,8 @@ def main(use_stream=True): client_addr = res[1] print("Client address:", client_addr) print("Client socket:", client_s) - client_s = ssl.wrap_socket(client_s, server_side=True) + # CPython uses key keyfile/certfile arguments, but MicroPython uses key/cert + client_s = ssl.wrap_socket(client_s, server_side=True, key=key, cert=cert) print(client_s) print("Request:") if use_stream: From 0d82f5d8c868d7f4e93d48e400cd4d769175e3e5 Mon Sep 17 00:00:00 2001 From: Seon Rozenblum Date: Thu, 24 Oct 2019 19:20:39 +1100 Subject: [PATCH 1068/1788] esp32/boards/TINYPICO: Add tinypico.py, dotstar.py with custom manifest. --- ports/esp32/boards/TINYPICO/manifest.py | 2 + .../esp32/boards/TINYPICO/modules/dotstar.py | 228 ++++++++++++++++++ .../esp32/boards/TINYPICO/modules/tinypico.py | 113 +++++++++ ports/esp32/boards/TINYPICO/mpconfigboard.mk | 2 + 4 files changed, 345 insertions(+) create mode 100644 ports/esp32/boards/TINYPICO/manifest.py create mode 100644 ports/esp32/boards/TINYPICO/modules/dotstar.py create mode 100644 ports/esp32/boards/TINYPICO/modules/tinypico.py diff --git a/ports/esp32/boards/TINYPICO/manifest.py b/ports/esp32/boards/TINYPICO/manifest.py new file mode 100644 index 0000000000..81fff1d7c3 --- /dev/null +++ b/ports/esp32/boards/TINYPICO/manifest.py @@ -0,0 +1,2 @@ +include('$(PORT_DIR)/boards/manifest.py') +freeze("modules") diff --git a/ports/esp32/boards/TINYPICO/modules/dotstar.py b/ports/esp32/boards/TINYPICO/modules/dotstar.py new file mode 100644 index 0000000000..a848e8e179 --- /dev/null +++ b/ports/esp32/boards/TINYPICO/modules/dotstar.py @@ -0,0 +1,228 @@ +# DotStar strip driver for MicroPython +# +# The MIT License (MIT) +# +# Copyright (c) 2016 Damien P. George (original Neopixel object) +# Copyright (c) 2017 Ladyada +# Copyright (c) 2017 Scott Shawcroft for Adafruit Industries +# Copyright (c) 2019 Matt Trentini (porting back to MicroPython) +# +# 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. + +START_HEADER_SIZE = 4 +LED_START = 0b11100000 # Three "1" bits, followed by 5 brightness bits + +# Pixel color order constants +RGB = (0, 1, 2) +RBG = (0, 2, 1) +GRB = (1, 0, 2) +GBR = (1, 2, 0) +BRG = (2, 0, 1) +BGR = (2, 1, 0) + + +class DotStar: + """ + A sequence of dotstars. + + :param SPI spi: The SPI object to write output to. + :param int n: The number of dotstars in the chain + :param float brightness: Brightness of the pixels between 0.0 and 1.0 + :param bool auto_write: True if the dotstars should immediately change when + set. If False, `show` must be called explicitly. + :param tuple pixel_order: Set the pixel order on the strip - different + strips implement this differently. If you send red, and it looks blue + or green on the strip, modify this! It should be one of the values above + + + Example for TinyPICO: + + .. code-block:: python + + from dotstar import DotStar + from machine import Pin, SPI + + spi = SPI(sck=Pin(12), mosi=Pin(13), miso=Pin(18)) # Configure SPI - note: miso is unused + dotstar = DotStar(spi, 1) + dotstar[0] = (128, 0, 0) # Red + """ + + def __init__(self, spi, n, *, brightness=1.0, auto_write=True, + pixel_order=BGR): + self._spi = spi + self._n = n + # Supply one extra clock cycle for each two pixels in the strip. + self.end_header_size = n // 16 + if n % 16 != 0: + self.end_header_size += 1 + self._buf = bytearray(n * 4 + START_HEADER_SIZE + self.end_header_size) + self.end_header_index = len(self._buf) - self.end_header_size + self.pixel_order = pixel_order + # Four empty bytes to start. + for i in range(START_HEADER_SIZE): + self._buf[i] = 0x00 + # Mark the beginnings of each pixel. + for i in range(START_HEADER_SIZE, self.end_header_index, 4): + self._buf[i] = 0xff + # 0xff bytes at the end. + for i in range(self.end_header_index, len(self._buf)): + self._buf[i] = 0xff + self._brightness = 1.0 + # Set auto_write to False temporarily so brightness setter does _not_ + # call show() while in __init__. + self.auto_write = False + self.brightness = brightness + self.auto_write = auto_write + + def deinit(self): + """Blank out the DotStars and release the resources.""" + self.auto_write = False + for i in range(START_HEADER_SIZE, self.end_header_index): + if i % 4 != 0: + self._buf[i] = 0 + self.show() + if self._spi: + self._spi.deinit() + + def __enter__(self): + return self + + def __exit__(self, exception_type, exception_value, traceback): + self.deinit() + + def __repr__(self): + return "[" + ", ".join([str(x) for x in self]) + "]" + + def _set_item(self, index, value): + """ + value can be one of three things: + a (r,g,b) list/tuple + a (r,g,b, brightness) list/tuple + a single, longer int that contains RGB values, like 0xFFFFFF + brightness, if specified should be a float 0-1 + + Set a pixel value. You can set per-pixel brightness here, if it's not passed it + will use the max value for pixel brightness value, which is a good default. + + Important notes about the per-pixel brightness - it's accomplished by + PWMing the entire output of the LED, and that PWM is at a much + slower clock than the rest of the LEDs. This can cause problems in + Persistence of Vision Applications + """ + + offset = index * 4 + START_HEADER_SIZE + rgb = value + if isinstance(value, int): + rgb = (value >> 16, (value >> 8) & 0xff, value & 0xff) + + if len(rgb) == 4: + brightness = value[3] + # Ignore value[3] below. + else: + brightness = 1 + + # LED startframe is three "1" bits, followed by 5 brightness bits + # then 8 bits for each of R, G, and B. The order of those 3 are configurable and + # vary based on hardware + # same as math.ceil(brightness * 31) & 0b00011111 + # Idea from https://www.codeproject.com/Tips/700780/Fast-floor-ceiling-functions + brightness_byte = 32 - int(32 - brightness * 31) & 0b00011111 + self._buf[offset] = brightness_byte | LED_START + self._buf[offset + 1] = rgb[self.pixel_order[0]] + self._buf[offset + 2] = rgb[self.pixel_order[1]] + self._buf[offset + 3] = rgb[self.pixel_order[2]] + + def __setitem__(self, index, val): + if isinstance(index, slice): + start, stop, step = index.indices(self._n) + length = stop - start + if step != 0: + # same as math.ceil(length / step) + # Idea from https://fizzbuzzer.com/implement-a-ceil-function/ + length = (length + step - 1) // step + if len(val) != length: + raise ValueError("Slice and input sequence size do not match.") + for val_i, in_i in enumerate(range(start, stop, step)): + self._set_item(in_i, val[val_i]) + else: + self._set_item(index, val) + + if self.auto_write: + self.show() + + def __getitem__(self, index): + if isinstance(index, slice): + out = [] + for in_i in range(*index.indices(self._n)): + out.append( + tuple(self._buf[in_i * 4 + (3 - i) + START_HEADER_SIZE] for i in range(3))) + return out + if index < 0: + index += len(self) + if index >= self._n or index < 0: + raise IndexError + offset = index * 4 + return tuple(self._buf[offset + (3 - i) + START_HEADER_SIZE] + for i in range(3)) + + def __len__(self): + return self._n + + @property + def brightness(self): + """Overall brightness of the pixel""" + return self._brightness + + @brightness.setter + def brightness(self, brightness): + self._brightness = min(max(brightness, 0.0), 1.0) + if self.auto_write: + self.show() + + def fill(self, color): + """Colors all pixels the given ***color***.""" + auto_write = self.auto_write + self.auto_write = False + for i in range(self._n): + self[i] = color + if auto_write: + self.show() + self.auto_write = auto_write + + def show(self): + """Shows the new colors on the pixels themselves if they haven't already + been autowritten. + + The colors may or may not be showing after this function returns because + it may be done asynchronously.""" + # Create a second output buffer if we need to compute brightness + buf = self._buf + if self.brightness < 1.0: + buf = bytearray(self._buf) + # Four empty bytes to start. + for i in range(START_HEADER_SIZE): + buf[i] = 0x00 + for i in range(START_HEADER_SIZE, self.end_header_index): + buf[i] = self._buf[i] if i % 4 == 0 else int(self._buf[i] * self._brightness) + # Four 0xff bytes at the end. + for i in range(self.end_header_index, len(buf)): + buf[i] = 0xff + + if self._spi: + self._spi.write(buf) diff --git a/ports/esp32/boards/TINYPICO/modules/tinypico.py b/ports/esp32/boards/TINYPICO/modules/tinypico.py new file mode 100644 index 0000000000..2fc379ccd4 --- /dev/null +++ b/ports/esp32/boards/TINYPICO/modules/tinypico.py @@ -0,0 +1,113 @@ +# TinyPICO MicroPython Helper Library +# 2019 Seon Rozenblum, Matt Trentini +# +# Project home: +# https://github.com/TinyPICO +# +# 2019-Mar-12 - v0.1 - Initial implementation +# 2019-May-20 - v1.0 - Initial Release +# 2019-Oct-23 - v1.1 - Removed temp sensor code, prep for frozen modules + +# Import required libraries +from micropython import const +from machine import Pin, SPI, ADC +import machine, time, esp32 + +# TinyPICO Hardware Pin Assignments + +# Battery +BAT_VOLTAGE = const(35) +BAT_CHARGE = const(34) + +# APA102 Dotstar pins for production boards +DOTSTAR_CLK = const(12) +DOTSTAR_DATA = const(2) +DOTSTAR_PWR = const(13) + +# SPI +SPI_MOSI = const(23) +SPI_CLK = const(18) +SPI_MISO = const(19) + +#I2C +I2C_SDA = const(21) +I2C_SCL = const(22) + +#DAC +DAC1 = const(25) +DAC2 = const(26) + +# Helper functions + +# Get a *rough* estimate of the current battery voltage +# If the battery is not present, the charge IC will still report it's trying to charge at X voltage +# so it will still show a voltage. +def get_battery_voltage(): + """ + Returns the current battery voltage. If no battery is connected, returns 3.7V + This is an approximation only, but useful to detect of the charge state of the battery is getting low. + """ + adc = ADC(Pin(BAT_VOLTAGE)) # Assign the ADC pin to read + measuredvbat = adc.read() # Read the value + measuredvbat /= 4095 # divide by 4095 as we are using the default ADC voltage range of 0-1V + measuredvbat *= 3.7 # Multiply by 3.7V, our reference voltage + return measuredvbat + +# Return the current charge state of the battery - we need to read the value multiple times +# to eliminate false negatives due to the charge IC not knowing the difference between no battery +# and a full battery not charging - This is why the charge LED flashes +def get_battery_charging(): + """ + Returns the current battery charging state. + This can trigger false positives as the charge IC can't tell the difference between a full battery or no battery connected. + """ + measuredVal = 0 # start our reading at 0 + io = Pin(BAT_CHARGE, Pin.IN) # Assign the pin to read + + for y in range(0, 10): # loop through 10 times adding the read values together to ensure no false positives + measuredVal += io.value() + + return measuredVal == 0 # return True if the value is 0 + + +# Power to the on-board Dotstar is controlled by a PNP transistor, so low is ON and high is OFF +# We also need to set the Dotstar clock and data pins to be inputs to prevent power leakage when power is off +# This might be improved at a future date +# The reason we have power control for the Dotstar is that it has a quiescent current of around 1mA, so we +# need to be able to cut power to it to minimise power consumption during deep sleep or with general battery powered use +# to minimise unneeded battery drain +def set_dotstar_power(state): + """Set the power for the on-board Dostar to allow no current draw when not needed.""" + # Set the power pin to the inverse of state + if state: + Pin(DOTSTAR_PWR, Pin.OUT, None) # Break the PULL_HOLD on the pin + Pin(DOTSTAR_PWR).value(False) # Set the pin to LOW to enable the Transistor + else: + Pin(13, Pin.IN, Pin.PULL_HOLD) # Set PULL_HOLD on the pin to allow the 3V3 pull-up to work + + Pin(DOTSTAR_CLK, Pin.OUT if state else Pin.IN) # If power is on, set CLK to be output, otherwise input + Pin(DOTSTAR_DATA, Pin.OUT if state else Pin.IN) # If power is on, set DATA to be output, otherwise input + + # A small delay to let the IO change state + time.sleep(.035) + +# Dotstar rainbow colour wheel +def dotstar_color_wheel(wheel_pos): + """Color wheel to allow for cycling through the rainbow of RGB colors.""" + wheel_pos = wheel_pos % 255 + + if wheel_pos < 85: + return 255 - wheel_pos * 3, 0, wheel_pos * 3 + elif wheel_pos < 170: + wheel_pos -= 85 + return 0, wheel_pos * 3, 255 - wheel_pos * 3 + else: + wheel_pos -= 170 + return wheel_pos * 3, 255 - wheel_pos * 3, 0 + +# Go into deep sleep but shut down the APA first to save power +# Use this if you want lowest deep sleep current +def go_deepsleep(t): + """Deep sleep helper that also powers down the on-board Dotstar.""" + set_dotstar_power(False) + machine.deepsleep(t) diff --git a/ports/esp32/boards/TINYPICO/mpconfigboard.mk b/ports/esp32/boards/TINYPICO/mpconfigboard.mk index 485b3f1656..5c96ec45a7 100644 --- a/ports/esp32/boards/TINYPICO/mpconfigboard.mk +++ b/ports/esp32/boards/TINYPICO/mpconfigboard.mk @@ -4,3 +4,5 @@ SDKCONFIG += boards/sdkconfig.base SDKCONFIG += boards/sdkconfig.240mhz SDKCONFIG += boards/sdkconfig.spiram SDKCONFIG += boards/TINYPICO/sdkconfig.board + +FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py From 8af139e8a4a01c2eea034df4e3eb96488ec3231b Mon Sep 17 00:00:00 2001 From: roland van straten Date: Mon, 9 Dec 2019 14:53:48 +0100 Subject: [PATCH 1069/1788] stm32/boards/NUCLEO_F767ZI: Add pins and config for using an SD card. The Nucleo board does not have an SD card slot but does have the requisite pins next to each other and labelled, so provide the configuration for convenience. --- ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h | 6 ++++++ ports/stm32/boards/NUCLEO_F767ZI/pins.csv | 8 +++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h index 1ee73c303b..b144ce4668 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_USB (1) +#define MICROPY_HW_ENABLE_SDCARD (1) #define MICROPY_BOARD_EARLY_INIT NUCLEO_F767ZI_board_early_init void NUCLEO_F767ZI_board_early_init(void); @@ -71,6 +72,11 @@ void NUCLEO_F767ZI_board_early_init(void); #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) +// SD card detect switch (actual pin may need to be changed for a particular use) +#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) + // Ethernet via RMII #define MICROPY_HW_ETH_MDC (pin_C1) #define MICROPY_HW_ETH_MDIO (pin_A2) diff --git a/ports/stm32/boards/NUCLEO_F767ZI/pins.csv b/ports/stm32/boards/NUCLEO_F767ZI/pins.csv index d84f8e9d19..ccd90d4475 100644 --- a/ports/stm32/boards/NUCLEO_F767ZI/pins.csv +++ b/ports/stm32/boards/NUCLEO_F767ZI/pins.csv @@ -46,7 +46,13 @@ AUDIO_SCL,PH7 EXT_SDA,PB9 EXT_SCL,PB8 EXT_RST,PG3 -SD_SW,PC13 +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 26a78edb49152db4ab4b22db9ccc25030a706357 Mon Sep 17 00:00:00 2001 From: roland van straten Date: Wed, 11 Dec 2019 11:43:47 +0100 Subject: [PATCH 1070/1788] stm32/boards/NUCLEO_F767ZI: Update pins, peripherals and total flash. - Removed remarks on DFU/OCD in mpconfigboard.h because deploy-stlink works fine too. - Added more UARTs, I2C, corrected SPI, CAN, etc; verified against CubeMX. - Adapted pins.csv to remove errors, add omissions, etc. according to NUCLEO-144 User Manual. - Changed linker file stm32f767.ld to reflect correct size of the Flash. - Tested with LAN and SD card. --- .../boards/NUCLEO_F767ZI/mpconfigboard.h | 29 +++--- ports/stm32/boards/NUCLEO_F767ZI/pins.csv | 98 ++++++++++++++----- ports/stm32/boards/stm32f767.ld | 2 +- 3 files changed, 92 insertions(+), 37 deletions(-) diff --git a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h index b144ce4668..b659223b4d 100644 --- a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h @@ -1,7 +1,5 @@ -// 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. +// Note: if the board shows odd behaviour check the option bits and make sure nDBANK is +// set to make the 2MByte space continuous instead of divided into two 1MByte segments. #define MICROPY_HW_BOARD_NAME "NUCLEO-F767ZI" #define MICROPY_HW_MCU_NAME "STM32F767" @@ -31,16 +29,25 @@ void NUCLEO_F767ZI_board_early_init(void); #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_UART6_TX (pin_C6) +#define MICROPY_HW_UART6_RX (pin_C7) +#define MICROPY_HW_UART5_TX (pin_B6) +#define MICROPY_HW_UART5_RX (pin_B12) +#define MICROPY_HW_UART7_TX (pin_F7) +#define MICROPY_HW_UART7_RX (pin_F6) +#define MICROPY_HW_UART8_TX (pin_E1) +#define MICROPY_HW_UART8_RX (pin_E0) + #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) +#define MICROPY_HW_I2C2_SCL (pin_F1) +#define MICROPY_HW_I2C2_SDA (pin_F0) +#define MICROPY_HW_I2C4_SCL (pin_F14) +#define MICROPY_HW_I2C4_SDA (pin_F15) // SPI #define MICROPY_HW_SPI3_NSS (pin_A4) @@ -49,10 +56,8 @@ void NUCLEO_F767ZI_board_early_init(void); #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) +#define MICROPY_HW_CAN1_TX (pin_D1) +#define MICROPY_HW_CAN1_RX (pin_D0) // USRSW is pulled low. Pressing the button makes the input go high. #define MICROPY_HW_USRSW_PIN (pin_C13) diff --git a/ports/stm32/boards/NUCLEO_F767ZI/pins.csv b/ports/stm32/boards/NUCLEO_F767ZI/pins.csv index ccd90d4475..e447b76b05 100644 --- a/ports/stm32/boards/NUCLEO_F767ZI/pins.csv +++ b/ports/stm32/boards/NUCLEO_F767ZI/pins.csv @@ -33,19 +33,58 @@ D22,PB5 D23,PB3 D24,PA4 D25,PB4 +D26,PB6 +D27,PB2 +D28,PD13 +D29,PD12 +D30,PD11 +D31,PE2 +D32,PA0 +D33,PB0 +D34,PE0 +D35,PB11 +D36,PB10 +D37,PE15 +D38,PE14 +D39,PE12 +D40,PE10 +D41,PE7 +D42,PE8 +D43,PC8 +D44,PC9 +D45,PC10 +D46,PC11 +D47,PC12 +D48,PD2 +D49,PG2 +D50,PG3 +D51,PD7 +D52,PD6 +D53,PD5 +D54,PD4 +D55,PD3 +D56,PE2 +D57,PE4 +D58,PE5 +D59,PE6 +D60,PE3 +D61,PF8 +D62,PF7 +D63,PF9 +D64,PG1 +D65,PG0 +D66,PD1 +D67,PD0 +D68,PF0 +D69,PF1 +D70,PF2 +D71,PA7 +DAC1,PA4 +DAC2,PA5 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,PC8 SD_D1,PC9 SD_D2,PC10 @@ -53,29 +92,38 @@ SD_D3,PC11 SD_CMD,PD2 SD_CK,PC12 SD_SW,PG2 -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 +OTG_FS_POWER,PG6 +OTG_FS_OVER_CURRENT,PG7 USB_VBUS,PA9 USB_ID,PA10 USB_DM,PA11 USB_DP,PA12 -USB_POWER,PG6 -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 +VCP_TX,PD8 +VCP_RX,PD9 +UART3_TX,PD8 +UART3_RX,PD9 +UART5_TX,PB6 +UART5_RX,PB12 +UART6_TX,PC6 +UART6_RX,PC7 +UART7_TX,PF7 +UART7_RX,PF6 +UART8_TX,PE1 +UART8_RX,PE0 +SPI3_NSS,PA4 +SPI3_SCK,PB3 +SPI3_MISO,PB4 +SPI3_MOSI,PB5 +I2C1_SDA,PB9 +I2C1_SCL,PB8 +I2C2_SDA,PF0 +I2C2_SCL,PF1 +I2C4_SCL,PF14 +I2C4_SDA,PF15 ETH_MDC,PC1 ETH_MDIO,PA2 ETH_RMII_REF_CLK,PA1 @@ -85,3 +133,5 @@ ETH_RMII_RXD1,PC5 ETH_RMII_TX_EN,PG11 ETH_RMII_TXD0,PG13 ETH_RMII_TXD1,PB13 +SWDIO,PA13 +SWDCLK,PA14 diff --git a/ports/stm32/boards/stm32f767.ld b/ports/stm32/boards/stm32f767.ld index 9410b9fa6b..d07f2ecbef 100644 --- a/ports/stm32/boards/stm32f767.ld +++ b/ports/stm32/boards/stm32f767.ld @@ -5,7 +5,7 @@ /* Specify the memory areas */ MEMORY { - FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K 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) */ From 43b576d88d3a9802bd38a30bb4266fed889db903 Mon Sep 17 00:00:00 2001 From: roland van straten Date: Tue, 10 Dec 2019 21:52:30 +0100 Subject: [PATCH 1071/1788] stm32/boards/NUCLEO_H743ZI: Add extra pins and peripheral definitions. - Corrected pin assignments and checked with CubeMX. - Added additional I2C and UARTs. - Added Ethernet interface definitions with lwIP and SSL support (but Ethernet is currently unsupported on H7 MCUs so not fully enabled). --- .../boards/NUCLEO_H743ZI/mpconfigboard.h | 26 ++++ .../boards/NUCLEO_H743ZI/mpconfigboard.mk | 5 + ports/stm32/boards/NUCLEO_H743ZI/pins.csv | 145 +++++++++++++----- 3 files changed, 135 insertions(+), 41 deletions(-) diff --git a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h index 40ce889ab9..4e6b162269 100644 --- a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h @@ -31,8 +31,21 @@ void NUCLEO_H743ZI_board_early_init(void); #define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_4 // 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_UART5_TX (pin_B6) +#define MICROPY_HW_UART5_RX (pin_B12) +#define MICROPY_HW_UART6_TX (pin_C6) +#define MICROPY_HW_UART6_RX (pin_C7) +#define MICROPY_HW_UART7_TX (pin_F7) +#define MICROPY_HW_UART7_RX (pin_F6) +#define MICROPY_HW_UART8_TX (pin_E1) +#define MICROPY_HW_UART8_RX (pin_E0) + #define MICROPY_HW_UART_REPL PYB_UART_3 #define MICROPY_HW_UART_REPL_BAUD 115200 @@ -41,6 +54,8 @@ void NUCLEO_H743ZI_board_early_init(void); #define MICROPY_HW_I2C1_SDA (pin_B9) #define MICROPY_HW_I2C2_SCL (pin_F1) #define MICROPY_HW_I2C2_SDA (pin_F0) +#define MICROPY_HW_I2C4_SCL (pin_F14) +#define MICROPY_HW_I2C4_SDA (pin_F15) // SPI #define MICROPY_HW_SPI3_NSS (pin_A4) @@ -75,3 +90,14 @@ void NUCLEO_H743ZI_board_early_init(void); #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) + +// Ethernet via RMII (MDC define disabled for now until eth.c supports H7) +//#define MICROPY_HW_ETH_MDC (pin_C1) +#define MICROPY_HW_ETH_MDIO (pin_A2) +#define MICROPY_HW_ETH_RMII_REF_CLK (pin_A1) +#define MICROPY_HW_ETH_RMII_CRS_DV (pin_A7) +#define MICROPY_HW_ETH_RMII_RXD0 (pin_C4) +#define MICROPY_HW_ETH_RMII_RXD1 (pin_C5) +#define MICROPY_HW_ETH_RMII_TX_EN (pin_G11) +#define MICROPY_HW_ETH_RMII_TXD0 (pin_G13) +#define MICROPY_HW_ETH_RMII_TXD1 (pin_B13) diff --git a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk index 1d232e0803..ce8f83e57d 100644 --- a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk @@ -16,3 +16,8 @@ LD_FILES = boards/stm32h743.ld boards/common_ifs.ld TEXT0_ADDR = 0x08000000 TEXT1_ADDR = 0x08040000 endif + +# MicroPython settings +MICROPY_PY_LWIP = 1 +MICROPY_PY_USSL = 1 +MICROPY_SSL_MBEDTLS = 1 diff --git a/ports/stm32/boards/NUCLEO_H743ZI/pins.csv b/ports/stm32/boards/NUCLEO_H743ZI/pins.csv index daa36691b7..d3647ca42a 100644 --- a/ports/stm32/boards/NUCLEO_H743ZI/pins.csv +++ b/ports/stm32/boards/NUCLEO_H743ZI/pins.csv @@ -1,46 +1,97 @@ -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 +A0,PA3 +A1,PC0 +A2,PC3 +A3,PB1 +A4,PC2 +A5,PF10 +A6,PF4 +A7,PF5 +A8,PF6 +D0,PB7 +D1,PB6 +D2,PG14 +D3,PE13 +D4,PE14 +D5,PE11 +D6,PE9 +D7,PG12 +D8,PF3 +D9,PD15 +D10,PD14 +D11,PB5 +D12,PA6 +D13,PA7 D14,PB9 D15,PB8 +D16,PC6 +D17,PB15 +D18,PB13 +D19,PB12 +D20,PA15 +D21,PC7 D22,PB5 D23,PB3 -D67,PD0 +D24,PA4 +D25,PB4 +D26,PG6 +D27,PB2 +D28,PD13 +D29,PD12 +D30,PD11 +D31,PE2 +D32,PA0 +D33,PB0 +D34,PE0 +D35,PB11 +D36,PB10 +D37,PE15 +D38,PE6 +D39,PE12 +D40,PE10 +D41,PE7 +D42,PE8 +D43,PC8 +D44,PC9 +D45,PC10 +D46,PC11 +D47,PC12 +D48,PD2 +D49,PG2 +D50,PG3 +D51,PD7 +D52,PD6 +D53,PD5 +D54,PD4 +D55,PD3 +D56,PE2 +D57,PE4 +D58,PE5 +D59,PE6 +D60,PE3 +D61,PF8 +D62,PF7 +D63,PF9 +D64,PG1 +D65,PG0 D66,PD1 +D67,PD0 +D68,PF0 +D69,PF1 +D70,PF2 +D71,PE9 +D72,PB2 DAC1,PA4 DAC2,PA5 LED1,PB0 LED2,PB7 LED3,PB14 SW,PC13 -TP1,PH2 -TP2,PI8 -TP3,PH15 -AUDIO_INT,PD6 -AUDIO_SDA,PH8 -AUDIO_SCL,PH7 I2C1_SDA,PB9 I2C1_SCL,PB8 I2C2_SDA,PF0 I2C2_SCL,PF1 -EXT_RST,PG3 +I2C4_SCL,PF14 +I2C4_SDA,PF15 SD_D0,PC8 SD_D1,PC9 SD_D2,PC10 @@ -48,20 +99,32 @@ SD_D3,PC11 SD_CMD,PD2 SD_CK,PC12 SD_SW,PG2 -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 +OTG_FS_POWER,PG6 +OTG_FS_OVER_CURRENT,PG7 +USB_VBUS,PA9 +USB_ID,PA10 USB_DM,PA11 USB_DP,PA12 -UART1_TX,PA9 -UART1_RX,PA10 -UART5_TX,PC12 -UART5_RX,PD2 +UART2_TX,PD5 +UART2_RX,PD6 +UART2_RTS,PD4 +UART2_CTS,PD3 UART3_TX,PD8 UART3_RX,PD9 +UART5_TX,PB6 +UART5_RX,PB12 +UART6_TX,PC6 +UART6_RX,PC7 +UART7_TX,PF7 +UART7_RX,PF6 +UART8_TX,PE1 +UART8_RX,PE0 +ETH_MDC,PC1 +ETH_MDIO,PA2 +ETH_RMII_REF_CLK,PA1 +ETH_RMII_CRS_DV,PA7 +ETH_RMII_RXD0,PC4 +ETH_RMII_RXD1,PC5 +ETH_RMII_TX_EN,PG11 +ETH_RMII_TXD0,PG13 +ETH_RMII_TXD1,PB13 From b3b9b11596b5b4c9a3c45185fd839fa3db63fa12 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 11 Dec 2019 14:56:33 +1100 Subject: [PATCH 1072/1788] tools/pyboard.py: Support executing .mpy files directly. This patch allows executing .mpy files (including native ones) directly on a target, eg a board over a serial connection. So there's no need to copy the file to its filesystem to test it. For example: $ mpy-cross foo.py $ pyboard.py foo.mpy --- tools/pyboard.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tools/pyboard.py b/tools/pyboard.py index c32fb002ca..2a255e91c0 100755 --- a/tools/pyboard.py +++ b/tools/pyboard.py @@ -484,6 +484,33 @@ def filesystem_command(pyb, args): pyb.close() sys.exit(1) +_injected_import_hook_code = """\ +import uos, uio +class _FS: + class File(uio.IOBase): + def __init__(self): + self.off = 0 + def ioctl(self, request, arg): + return 0 + def readinto(self, buf): + buf[:] = memoryview(_injected_buf)[self.off:self.off + len(buf)] + self.off += len(buf) + return len(buf) + mount = umount = chdir = lambda *args: None + def stat(self, path): + if path == '_injected.mpy': + return tuple(0 for _ in range(10)) + else: + raise OSError(-2) # ENOENT + def open(self, path, mode): + return self.File() +uos.mount(_FS(), '/_') +uos.chdir('/_') +from _injected import * +uos.umount('/_') +del _injected_buf, _FS +""" + def main(): import argparse cmd_parser = argparse.ArgumentParser(description='Run scripts on the pyboard.') @@ -544,6 +571,9 @@ def main(): for filename in args.files: with open(filename, 'rb') as f: pyfile = f.read() + if filename.endswith('.mpy') and pyfile[0] == ord('M'): + pyb.exec_('_injected_buf=' + repr(pyfile)) + pyfile = _injected_import_hook_code execbuffer(pyfile) # exiting raw-REPL just drops to friendly-REPL mode From a3df152fef9b2e022bd4b1233df12c261cb9f1a8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 16 Dec 2019 22:40:22 +1100 Subject: [PATCH 1073/1788] examples/natmod: Add very simple features0 example to compute factorial. --- examples/natmod/features0/Makefile | 14 ++++++++++ examples/natmod/features0/features0.c | 40 +++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 examples/natmod/features0/Makefile create mode 100644 examples/natmod/features0/features0.c diff --git a/examples/natmod/features0/Makefile b/examples/natmod/features0/Makefile new file mode 100644 index 0000000000..57490df90a --- /dev/null +++ b/examples/natmod/features0/Makefile @@ -0,0 +1,14 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module +MOD = features0 + +# Source files (.c or .py) +SRC = features0.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) +ARCH = x64 + +# Include to get the rules for compiling and linking the module +include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/features0/features0.c b/examples/natmod/features0/features0.c new file mode 100644 index 0000000000..1b1867a3bc --- /dev/null +++ b/examples/natmod/features0/features0.c @@ -0,0 +1,40 @@ +/* This example demonstrates the following features in a native module: + - defining a simple function exposed to Python + - defining a local, helper C function + - getting and creating integer objects +*/ + +// Include the header file to get access to the MicroPython API +#include "py/dynruntime.h" + +// Helper function to compute factorial +STATIC mp_int_t factorial_helper(mp_int_t x) { + if (x == 0) { + return 1; + } + return x * factorial_helper(x - 1); +} + +// This is the function which will be called from Python, as factorial(x) +STATIC mp_obj_t factorial(mp_obj_t x_obj) { + // Extract the integer from the MicroPython input object + mp_int_t x = mp_obj_get_int(x_obj); + // Calculate the factorial + mp_int_t result = factorial_helper(x); + // Convert the result to a MicroPython integer object and return it + return mp_obj_new_int(result); +} +// Define a Python reference to the function above +STATIC MP_DEFINE_CONST_FUN_OBJ_1(factorial_obj, factorial); + +// This is the entry point and is called when the module is imported +mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + // This must be first, it sets up the globals dict and other things + MP_DYNRUNTIME_INIT_ENTRY + + // Make the function available in the module's namespace + mp_store_global(MP_QSTR_factorial, MP_OBJ_FROM_PTR(&factorial_obj)); + + // This must be last, it restores the globals dict + MP_DYNRUNTIME_INIT_EXIT +} From e58c7ce3d64fe17a58e75616a4992921f6bc5738 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 16 Dec 2019 23:03:38 +1100 Subject: [PATCH 1074/1788] docs/reference: Add documentation describing use of .mpy files. Including information about .mpy versioning and how to debug failed imports of .mpy files. --- docs/reference/index.rst | 1 + docs/reference/mpyfiles.rst | 178 ++++++++++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+) create mode 100644 docs/reference/mpyfiles.rst diff --git a/docs/reference/index.rst b/docs/reference/index.rst index 1eaaa85c85..ed50bf0bf4 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -21,6 +21,7 @@ implementation and the best practices to use them. glossary.rst repl.rst + mpyfiles.rst isr_rules.rst speed_python.rst constrained.rst diff --git a/docs/reference/mpyfiles.rst b/docs/reference/mpyfiles.rst new file mode 100644 index 0000000000..4791784ac3 --- /dev/null +++ b/docs/reference/mpyfiles.rst @@ -0,0 +1,178 @@ +.. _mpy_files: + +MicroPython .mpy files +====================== + +MicroPython defines the concept of an .mpy file which is a binary container +file format that holds precompiled code, and which can be imported like a +normal .py module. The file ``foo.mpy`` can be imported via ``import foo``, +as long as ``foo.mpy`` can be found in the usual way by the import machinery. +Usually, each directory listed in ``sys.path`` is searched in order. When +searching a particular directory ``foo.py`` is looked for first and if that +is not found then ``foo.mpy`` is looked for, then the search continues in the +next directory if neither is found. As such, ``foo.py`` will take precedence +over ``foo.mpy``. + +These .mpy files can contain bytecode which is usually generated from Python +source files (.py files) via the ``mpy-cross`` program. For some architectures +an .mpy file can also contain native machine code, which can be generated in +a variety of ways, most notably from C source code. + +Versioning and compatibility of .mpy files +------------------------------------------ + +A given .mpy file may or may not be compatible with a given MicroPython system. +Compatibility is based on the following: + +* Version of the .mpy file: the version of the file must match the version + supported by the system loading it. + +* Bytecode features used in the .mpy file: there are two bytecode features + which must match between the file and the system: unicode support and + inline caching of map lookups in the bytecode. + +* Small integer bits: the .mpy file will require a minimum number of bits in + a small integer and the system loading it must support at least this many + bits. + +* Qstr compression window size: the .mpy file will require a minimum window + size for qstr decompression and the system loading it must have a window + greater or equal to this size. + +* Native architecture: if the .mpy file contains native machine code then + it will specify the architecture of that machine code and the system + loading it must support execution of that architecture's code. + +If a MicroPython system supports importing .mpy files then the +``sys.implementation.mpy`` field will exist and return an integer which +encodes the version (lower 8 bits), features and native architecture. + +Trying to import an .mpy file that fails one of the first four tests will +raise ``ValueError('incompatible .mpy file')``. Trying to import an .mpy +file that fails the native architecture test (if it contains native machine +code) will raise ``ValueError('incompatible .mpy arch')``. + +If importing an .mpy file fails then try the following: + +* Determine the .mpy version and flags supported by your MicroPython system + by executing:: + + import sys + sys_mpy = sys.implementation.mpy + arch = [None, 'x86', 'x64', + 'armv6', 'armv6m', 'armv7m', 'armv7em', 'armv7emsp', 'armv7emdp', + 'xtensa', 'xtensawin'][sys_mpy >> 10] + print('mpy version:', sys_mpy & 0xff) + print('mpy flags:', end='') + if arch: + print(' -march=' + arch, end='') + if sys_mpy & 0x100: + print(' -mcache-lookup-bc', end='') + if not sys_mpy & 0x200: + print(' -mno-unicode', end='') + print() + +* Check the validity of the .mpy file by inspecting the first two bytes of + the file. The first byte should be an uppercase 'M' and the second byte + will be the version number, which should match the system version from above. + If it doesn't match then rebuild the .mpy file. + +* Check if the system .mpy version matches the version emitted by ``mpy-cross`` + that was used to build the .mpy file, found by ``mpy-cross --version``. + If it doesn't match then recompile ``mpy-cross`` from the Git repository + checked out at the tag (or hash) reported by ``mpy-cross --version``. + +* Make sure you are using the correct ``mpy-cross`` flags, found by the code + above, or by inspecting the ``MPY_CROSS_FLAGS`` Makefile variable for the + port that you are using. + +The following table shows the correspondence between MicroPython release +and .mpy version. + +=================== ============ +MicroPython release .mpy version +=================== ============ +v1.12 and up 5 +v1.11 4 +v1.9.3 - v1.10 3 +v1.9 - v1.9.2 2 +v1.5.1 - v1.8.7 0 +=================== ============ + +For completeness, the next table shows the Git commit of the main +MicroPython repository at which the .mpy version was changed. + +=================== ======================================== +.mpy version change Git commit +=================== ======================================== +4 to 5 5716c5cf65e9b2cb46c2906f40302401bdd27517 +3 to 4 9a5f92ea72754c01cc03e5efcdfe94021120531e +2 to 3 ff93fd4f50321c6190e1659b19e64fef3045a484 +1 to 2 dd11af209d226b7d18d5148b239662e30ed60bad +0 to 1 6a11048af1d01c78bdacddadd1b72dc7ba7c6478 +initial version 0 d8c834c95d506db979ec871417de90b7951edc30 +=================== ======================================== + +Binary encoding of .mpy files +----------------------------- + +MicroPython .mpy files are a binary container format with code objects +stored internally in a nested hierarchy. To keep files small while still +providing a large range of possible values it uses the concept of a +variably-encoded-unsigned-integer (vuint) in many places. Similar to utf-8 +encoding, this encoding stores 7 bits per byte with the 8th bit (MSB) set +if one or more bytes follow. The bits of the unsigned integer are stored +in the vuint in LSB form. + +The top-level of an .mpy file consists of two parts: + +* The header. + +* The raw-code for the outer scope of the module. + This outer scope is executed when the .mpy file is imported. + +The header +~~~~~~~~~~ + +The .mpy header is: + +====== ================================ +size field +====== ================================ +byte value 0x4d (ASCII 'M') +byte .mpy version number +byte feature flags +byte number of bits in a small int +vuint size of qstr window +====== ================================ + +Raw code elements +~~~~~~~~~~~~~~~~~ + +A raw-code element contains code, either bytecode or native machine code. Its +contents are: + +====== ================================ +size field +====== ================================ +vuint type and size +... code (bytecode or machine code) +vuint number of constant objects +vuint number of sub-raw-code elements +... constant objects +... sub-raw-code elements +====== ================================ + +The first vuint in a raw-code element encodes the type of code stored in this +element (the two least-significant bits), and the decompressed length of the code +(the amount of RAM to allocate for it). + +Following the vuint comes the code itself. In the case of bytecode it also contains +compressed qstr values. + +Following the code comes a vuint counting the number of constant objects, and +another vuint counting the number of sub-raw-code elements. + +The constant objects are then stored next. + +Finally any sub-raw-code elements are stored, recursively. From 8449e41818f26c1e3a970d7181bb82ae2d3e2278 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 16 Dec 2019 23:04:01 +1100 Subject: [PATCH 1075/1788] docs/develop: Add documentation on how to build native .mpy modules. --- docs/develop/cmodules.rst | 6 ++ docs/develop/index.rst | 1 + docs/develop/natmod.rst | 202 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 209 insertions(+) create mode 100644 docs/develop/natmod.rst diff --git a/docs/develop/cmodules.rst b/docs/develop/cmodules.rst index ba43c3dc93..a4c4733478 100644 --- a/docs/develop/cmodules.rst +++ b/docs/develop/cmodules.rst @@ -1,3 +1,5 @@ +.. _cmodules: + MicroPython external C modules ============================== @@ -17,6 +19,10 @@ more sense to keep this external to the main MicroPython repository. This chapter describes how to compile such external modules into the MicroPython executable or firmware image. +An alternative approach is to use :ref:`natmod` which allows writing custom C +code that is placed in a .mpy file, which can be imported dynamically in to +a running MicroPython system without the need to recompile the main firmware. + Structure of an external C module --------------------------------- diff --git a/docs/develop/index.rst b/docs/develop/index.rst index fff3e43d74..f1fd0692ec 100644 --- a/docs/develop/index.rst +++ b/docs/develop/index.rst @@ -11,3 +11,4 @@ See the `getting started guide cmodules.rst qstr.rst + natmod.rst diff --git a/docs/develop/natmod.rst b/docs/develop/natmod.rst new file mode 100644 index 0000000000..1ce2381640 --- /dev/null +++ b/docs/develop/natmod.rst @@ -0,0 +1,202 @@ +.. _natmod: + +Native machine code in .mpy files +================================= + +This section describes how to build and work with .mpy files that contain native +machine code from a language other than Python. This allows you to +write code in a language like C, compile and link it into a .mpy file, and then +import this file like a normal Python module. This can be used for implementing +functionality which is performance critical, or for including an existing +library written in another language. + +One of the main advantages of using native .mpy files is that native machine code +can be imported by a script dynamically, without the need to rebuild the main +MicroPython firmware. This is in contrast to :ref:`cmodules` which also allows +defining custom modules in C but they must be compiled into the main firmware image. + +The focus here is on using C to build native modules, but in principle any +language which can be compiled to stand-alone machine code can be put into a +.mpy file. + +A native .mpy module is built using the ``mpy_ld.py`` tool, which is found in the +``tools/`` directory of the project. This tool takes a set of object files +(.o files) and links them together to create a native .mpy files. + +Supported features and limitations +---------------------------------- + +A .mpy file can contain MicroPython bytecode and/or native machine code. If it +contains native machine code then the .mpy file has a specific architecture +associated with it. Current supported architectures are (these are the valid +options for the ``ARCH`` variable, see below): + +* ``x86`` (32 bit) +* ``x64`` (64 bit x86) +* ``armv7m`` (ARM Thumb 2, eg Cortex-M3) +* ``armv7emsp`` (ARM Thumb 2, single precision float, eg Cortex-M4F, Cortex-M7) +* ``armv7emdp`` (ARM Thumb 2, double precision float, eg Cortex-M7) +* ``xtensa`` (non-windowed, eg ESP8266) +* ``xtensawin`` (windowed with window size 8, eg ESP32) + +When compiling and linking the native .mpy file the architecture must be chosen +and the corresponding file can only be imported on that architecture. For more +details about .mpy files see :ref:`mpy_files`. + +Native code must be compiled as position independent code (PIC) and use a global +offset table (GOT), although the details of this varies from architecture to +architecture. When importing .mpy files with native code the import machinery +is able to do some basic relocation of the native code. This includes +relocating text, rodata and BSS sections. + +Supported features of the linker and dynamic loader are: + +* executable code (text) +* read-only data (rodata), including strings and constant data (arrays, structs, etc) +* zeroed data (BSS) +* pointers in text to text, rodata and BSS +* pointers in rodata to text, rodata and BSS + +The known limitations are: + +* data sections are not supported; workaround: use BSS data and initialise the + data values explicitly + +* static BSS variables are not supported; workaround: use global BSS variables + +So, if your C code has writable data, make sure the data is defined globally, +without an initialiser, and only written to within functions. + +Defining a native module +------------------------ + +A native .mpy module is defined by a set of files that are used to build the .mpy. +The filesystem layout consists of two main parts, the source files and the Makefile: + +* In the simplest case only a single C source file is required, which contains all + the code that will be compiled into the .mpy module. This C source code must + include the ``py/dynruntime.h`` file to access the MicroPython dynamic API, and + must at least define a function called ``mpy_init``. This function will be the + entry point of the module, called when the module is imported. + + The module can be split into multiple C source files if desired. Parts of the + module can also be implemented in Python. All source files should be listed in + the Makefile, by adding them to the ``SRC`` variable (see below). This includes + both C source files as well as any Python files which will be included in the + resulting .mpy file. + +* The ``Makefile`` contains the build configuration for the module and list the + source files used to build the .mpy module. It should define ``MPY_DIR`` as the + location of the MicroPython repository (to find header files, the relevant Makefile + fragment, and the ``mpy_ld.py`` tool), ``MOD`` as the name of the module, ``SRC`` + as the list of source files, optionally specify the machine architecture via ``ARCH``, + and then include ``py/dynruntime.mk``. + +Minimal example +--------------- + +This section provides a fully working example of a simple module named ``factorial``. +This module provides a single function ``factorial.factorial(x)`` which computes the +factorial of the input and returns the result. + +Directory layout:: + + factorial/ + ├── factorial.c + └── Makefile + +The file ``factorial.c`` contains: + +.. code-block:: c + + // Include the header file to get access to the MicroPython API + #include "py/dynruntime.h" + + // Helper function to compute factorial + STATIC mp_int_t factorial_helper(mp_int_t x) { + if (x == 0) { + return 1; + } + return x * factorial_helper(x - 1); + } + + // This is the function which will be called from Python, as factorial(x) + STATIC mp_obj_t factorial(mp_obj_t x_obj) { + // Extract the integer from the MicroPython input object + mp_int_t x = mp_obj_get_int(x_obj); + // Calculate the factorial + mp_int_t result = factorial_helper(x); + // Convert the result to a MicroPython integer object and return it + return mp_obj_new_int(result); + } + // Define a Python reference to the function above + STATIC MP_DEFINE_CONST_FUN_OBJ_1(factorial_obj, factorial); + + // This is the entry point and is called when the module is imported + mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + // This must be first, it sets up the globals dict and other things + MP_DYNRUNTIME_INIT_ENTRY + + // Make the function available in the module's namespace + mp_store_global(MP_QSTR_factorial, MP_OBJ_FROM_PTR(&factorial_obj)); + + // This must be last, it restores the globals dict + MP_DYNRUNTIME_INIT_EXIT + } + +The file ``Makefile`` contains: + +.. code-block:: make + + # Location of top-level MicroPython directory + MPY_DIR = ../../.. + + # Name of module + MOD = features0 + + # Source files (.c or .py) + SRC = features0.c + + # Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) + ARCH = x64 + + # Include to get the rules for compiling and linking the module + include $(MPY_DIR)/py/dynruntime.mk + +Compiling the module +-------------------- + +Be sure to select the correct ``ARCH`` for the target you are going to run on. +Then build with:: + + $ make + +Without modifying the Makefile you can specify the target architecture via:: + + $ make ARCH=armv7m + +Module usage in MicroPython +--------------------------- + +Once the module is built there should be a file called ``factorial.mpy``. Copy +this so it is accessible on the filesystem of your MicroPython system and can be +found in the import path. The module con now be accessed in Python just like any +other module, for example:: + + import factorial + print(factorial.factorial(10)) + # should display 3628800 + +Further examples +---------------- + +See ``examples/natmod/`` for further examples which show many of the available +features of native .mpy modules. Such features include: + +* using multiple C source files +* including Python code alongside C code +* rodata and BSS data +* memory allocation +* use of floating point +* exception handling +* including external C libraries From 3078a4b2e233a7c224cd4f337b8fadf5bf53257f Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Tue, 17 Dec 2019 19:43:26 +0200 Subject: [PATCH 1076/1788] stm32/timer: Add missing TIM 1/15/16/17 IRQ handlers for H7 MCUs. --- ports/stm32/stm32_it.c | 28 ++++++++++++++++++++++++++++ ports/stm32/timer.c | 4 +++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index e12cf4bf29..e77642b8ea 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -609,6 +609,14 @@ void TIM1_UP_TIM16_IRQHandler(void) { } #endif +#if defined(STM32H7) +void TIM1_UP_IRQHandler(void) { + IRQ_ENTER(TIM1_UP_IRQn); + timer_irq_handler(1); + IRQ_EXIT(TIM1_UP_IRQn); +} +#endif + void TIM1_TRG_COM_TIM11_IRQHandler(void) { IRQ_ENTER(TIM1_TRG_COM_TIM11_IRQn); timer_irq_handler(11); @@ -705,6 +713,26 @@ void TIM8_TRG_COM_TIM14_IRQHandler(void) { } #endif +#if defined(STM32H7) +void TIM15_IRQHandler(void) { + IRQ_ENTER(TIM15_IRQn); + timer_irq_handler(15); + IRQ_EXIT(TIM15_IRQn); +} + +void TIM16_IRQHandler(void) { + IRQ_ENTER(TIM16_IRQn); + timer_irq_handler(16); + IRQ_EXIT(TIM16_IRQn); +} + +void TIM17_IRQHandler(void) { + IRQ_ENTER(TIM17_IRQn); + timer_irq_handler(17); + IRQ_EXIT(TIM17_IRQn); +} +#endif + // UART/USART IRQ handlers void USART1_IRQHandler(void) { IRQ_ENTER(USART1_IRQn); diff --git a/ports/stm32/timer.c b/ports/stm32/timer.c index 834ebd9c85..2e8f3e05ba 100644 --- a/ports/stm32/timer.c +++ b/ports/stm32/timer.c @@ -759,6 +759,8 @@ STATIC const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = { TIM_ENTRY(1, TIM1_BRK_UP_TRG_COM_IRQn), #elif defined(STM32F4) || defined(STM32F7) TIM_ENTRY(1, TIM1_UP_TIM10_IRQn), + #elif defined(STM32H7) + TIM_ENTRY(1, TIM1_UP_IRQn), #elif defined(STM32L4) TIM_ENTRY(1, TIM1_UP_TIM16_IRQn), #endif @@ -780,7 +782,7 @@ STATIC const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = { TIM_ENTRY(7, TIM7_IRQn), #endif #if defined(TIM8) - #if defined(STM32F4) || defined(STM32F7) + #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) TIM_ENTRY(8, TIM8_UP_TIM13_IRQn), #elif defined(STM32L4) TIM_ENTRY(8, TIM8_UP_IRQn), From 1605c7e5840cf44a11a8e38150be8bb7ce6645d5 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Wed, 18 Dec 2019 12:42:34 -0600 Subject: [PATCH 1077/1788] Revert "lib/tinytest: Clean up test reporting in the presence of std..." This reverts commit f4ed2dfa942339dc1f174e8a83ff0d41073f1972. This lets tinytest work as it was originally designed. An alternate solution for the reverted commit will be implemented in a future commit. --- lib/tinytest/tinytest.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/tinytest/tinytest.c b/lib/tinytest/tinytest.c index 01772f3f8e..1ef957d31b 100644 --- a/lib/tinytest/tinytest.c +++ b/lib/tinytest/tinytest.c @@ -234,9 +234,8 @@ 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; @@ -253,7 +252,6 @@ 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) @@ -265,8 +263,7 @@ testcase_run_one(const struct testgroup_t *group, } else { ++n_bad; if (!opt_forked) - //printf("\n [%s FAILED]\n", testcase->name); - puts("FAILED"); + printf("\n [%s FAILED]\n", testcase->name); } if (opt_forked) { From fd0ba7be0775fe804bc6c20f538d722705b8ea4a Mon Sep 17 00:00:00 2001 From: David Lechner Date: Wed, 18 Dec 2019 12:59:48 -0600 Subject: [PATCH 1078/1788] tools/tinytest-codegen.py: Add extra newline and result message. This is an alternative to f4ed2df that adds a newline so that the output of the test starts on a new line and the result of the test is prefixed with "result: " to distinguish it from the test output. Suggested-by: @dpgeorge --- tools/tinytest-codegen.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/tinytest-codegen.py b/tools/tinytest-codegen.py index 7580522ee6..424f70a9fb 100755 --- a/tools/tinytest-codegen.py +++ b/tools/tinytest-codegen.py @@ -33,8 +33,10 @@ test_function = ( "void {name}(void* data) {{\n" " static const char pystr[] = {script};\n" " static const char exp[] = {output};\n" + ' printf("\\n");\n' " upytest_set_expected_output(exp, sizeof(exp) - 1);\n" " upytest_execute_test(pystr);\n" + ' printf("result: ");\n' "}}" ) From 882533ad9221d4a69c5523b8d04c08970d6c1988 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Wed, 18 Dec 2019 12:26:55 -0600 Subject: [PATCH 1079/1788] qemu-arm/Makefile: Allow overriding CROSS_COMPILE from another makefile. --- ports/qemu-arm/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/qemu-arm/Makefile b/ports/qemu-arm/Makefile index 4f12173c3f..cb7dcb0216 100644 --- a/ports/qemu-arm/Makefile +++ b/ports/qemu-arm/Makefile @@ -31,7 +31,7 @@ LDSCRIPT = mps2.ld SRC_BOARD_O = lib/utils/gchelper_m3.o endif -CROSS_COMPILE = arm-none-eabi- +CROSS_COMPILE ?= arm-none-eabi- INC += -I. INC += -I$(TOP) From 0e0e6132fd90453eafabb71f355012cd82cf05b4 Mon Sep 17 00:00:00 2001 From: Matt Trentini Date: Mon, 23 Sep 2019 13:50:58 +1000 Subject: [PATCH 1080/1788] esp32/esp32_rmt: Add initial support for RMT peripheral. This is an ESP32-specific peripheral so lives in the esp32 module. --- ports/esp32/Makefile | 1 + ports/esp32/esp32_rmt.c | 237 ++++++++++++++++++++++++++++++++++++++++ ports/esp32/modesp32.c | 1 + ports/esp32/modesp32.h | 1 + 4 files changed, 240 insertions(+) create mode 100644 ports/esp32/esp32_rmt.c diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index e3b14495d5..ecaa3e62ac 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -323,6 +323,7 @@ SRC_C = \ modsocket.c \ modesp.c \ esp32_partition.c \ + esp32_rmt.c \ esp32_ulp.c \ modesp32.c \ espneopixel.c \ diff --git a/ports/esp32/esp32_rmt.c b/ports/esp32/esp32_rmt.c new file mode 100644 index 0000000000..1356456bc5 --- /dev/null +++ b/ports/esp32/esp32_rmt.c @@ -0,0 +1,237 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 "Matt Trentini" + * + * 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 "modmachine.h" +#include "mphalport.h" +#include "driver/rmt.h" + +// This exposes the ESP32's RMT module to MicroPython. RMT is provided by the Espressif ESP-IDF: +// +// https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/rmt.html +// +// With some examples provided: +// +// https://github.com/espressif/arduino-esp32/tree/master/libraries/ESP32/examples/RMT +// +// RMT allows accurate (down to 12.5ns resolution) transmit - and receive - of pulse signals. +// Originally designed to generate infrared remote control signals, the module is very +// flexible and quite easy-to-use. +// +// This current MicroPython implementation lacks some major features, notably receive pulses +// and carrier output. + +// Forward declaration +extern const mp_obj_type_t esp32_rmt_type; + +typedef struct _esp32_rmt_obj_t { + mp_obj_base_t base; + uint8_t channel_id; + gpio_num_t pin; + uint8_t clock_div; + mp_uint_t num_items; + rmt_item32_t* items; +} esp32_rmt_obj_t; + +// Defined in machine_time.c; simply added the error message +// Fixme: Should use this updated error hadline more widely in the ESP32 port. +// At least update the method in machine_time.c. +STATIC esp_err_t check_esp_err(esp_err_t code) { + if (code) { + mp_raise_msg(&mp_type_OSError, esp_err_to_name(code)); + } + + return code; +} + +STATIC mp_obj_t esp32_rmt_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_clock_div, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, // 100ns resolution + }; + 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); + mp_uint_t channel_id = args[0].u_int; + gpio_num_t pin_id = machine_pin_get_id(args[1].u_obj); + mp_uint_t clock_div = args[2].u_int; + + if (clock_div < 1 || clock_div > 255) { + mp_raise_ValueError("clock_div must be between 1 and 255"); + } + + esp32_rmt_obj_t *self = m_new_obj_with_finaliser(esp32_rmt_obj_t); + self->base.type = &esp32_rmt_type; + self->channel_id = channel_id; + self->pin = pin_id; + self->clock_div = clock_div; + + rmt_config_t config; + config.rmt_mode = RMT_MODE_TX; + config.channel = (rmt_channel_t) self->channel_id; + config.gpio_num = self->pin; + config.mem_block_num = 1; + config.tx_config.loop_en = 0; + + config.tx_config.carrier_en = 0; + config.tx_config.idle_output_en = 1; + config.tx_config.idle_level = 0; + config.tx_config.carrier_duty_percent = 0; + config.tx_config.carrier_freq_hz = 0; + config.tx_config.carrier_level = 1; + + config.clk_div = self->clock_div; + + check_esp_err(rmt_config(&config)); + check_esp_err(rmt_driver_install(config.channel, 0, 0)); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC void esp32_rmt_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->pin != -1) { + mp_printf(print, "RMT(channel=%u, pin=%u, source_freq=%u, clock_div=%u)", + self->channel_id, self->pin, APB_CLK_FREQ, self->clock_div); + } else { + mp_printf(print, "RMT()"); + } +} + +STATIC mp_obj_t esp32_rmt_deinit(mp_obj_t self_in) { + // fixme: check for valid channel. Return exception if error occurs. + esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->pin != -1) { // Check if channel has already been deinitialised. + rmt_driver_uninstall(self->channel_id); + self->pin = -1; // -1 to indicate RMT is unused + m_free(self->items); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_rmt_deinit_obj, esp32_rmt_deinit); + +// Return the source frequency. +// Currently only the APB clock (80MHz) can be used but it is possible other +// clock sources will added in the future. +STATIC mp_obj_t esp32_rmt_source_freq(mp_obj_t self_in) { + return mp_obj_new_int(APB_CLK_FREQ); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_rmt_source_freq_obj, esp32_rmt_source_freq); + +// Return the clock divider. +STATIC mp_obj_t esp32_rmt_clock_div(mp_obj_t self_in) { + esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_int(self->clock_div); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_rmt_clock_div_obj, esp32_rmt_clock_div); + +// Query whether the channel has finished sending pulses. Takes an optional +// timeout (in ticks of the 80MHz clock), returning true if the pulse stream has +// completed or false if they are still transmitting (or timeout is reached). +STATIC mp_obj_t esp32_rmt_wait_done(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_self, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_timeout, 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); + + esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(args[0].u_obj); + + esp_err_t err = rmt_wait_tx_done(self->channel_id, args[1].u_int); + return err == ESP_OK ? mp_const_true : mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp32_rmt_wait_done_obj, 1, esp32_rmt_wait_done); + +STATIC mp_obj_t esp32_rmt_loop(mp_obj_t self_in, mp_obj_t loop) { + esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_esp_err(rmt_set_tx_loop_mode(self->channel_id, mp_obj_get_int(loop))); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp32_rmt_loop_obj, esp32_rmt_loop); + +STATIC mp_obj_t esp32_rmt_write_pulses(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_self, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_pulses, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_start, MP_ARG_KW_ONLY | 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); + + esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(args[0].u_obj); + mp_obj_t pulses = args[1].u_obj; + mp_uint_t start = args[2].u_int; + + if (start < 0 || start > 1) { + mp_raise_ValueError("start must be 0 or 1"); + } + + size_t pulses_length = 0; + mp_obj_t* pulses_ptr = NULL; + mp_obj_get_array(pulses, &pulses_length, &pulses_ptr); + + mp_uint_t num_items = (pulses_length / 2) + (pulses_length % 2); + if (num_items > self->num_items) { + self->items = (rmt_item32_t*)m_realloc(self->items, num_items * sizeof(rmt_item32_t *)); + self->num_items = num_items; + } + + for (mp_uint_t item_index = 0; item_index < num_items; item_index++) { + mp_uint_t pulse_index = item_index * 2; + self->items[item_index].duration0 = mp_obj_get_int(pulses_ptr[pulse_index++]); + self->items[item_index].level0 = start++; // Note that start _could_ wrap. + if (pulse_index < pulses_length) { + self->items[item_index].duration1 = mp_obj_get_int(pulses_ptr[pulse_index]); + self->items[item_index].level1 = start++; + } + } + check_esp_err(rmt_write_items(self->channel_id, self->items, num_items, false /* non-blocking */)); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp32_rmt_write_pulses_obj, 2, esp32_rmt_write_pulses); + +STATIC const mp_rom_map_elem_t esp32_rmt_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&esp32_rmt_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&esp32_rmt_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_source_freq), MP_ROM_PTR(&esp32_rmt_source_freq_obj) }, + { MP_ROM_QSTR(MP_QSTR_clock_div), MP_ROM_PTR(&esp32_rmt_clock_div_obj) }, + { MP_ROM_QSTR(MP_QSTR_wait_done), MP_ROM_PTR(&esp32_rmt_wait_done_obj) }, + { MP_ROM_QSTR(MP_QSTR_loop), MP_ROM_PTR(&esp32_rmt_loop_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_pulses), MP_ROM_PTR(&esp32_rmt_write_pulses_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(esp32_rmt_locals_dict, esp32_rmt_locals_dict_table); + +const mp_obj_type_t esp32_rmt_type = { + { &mp_type_type }, + .name = MP_QSTR_RMT, + .print = esp32_rmt_print, + .make_new = esp32_rmt_make_new, + .locals_dict = (mp_obj_dict_t*)&esp32_rmt_locals_dict, +}; diff --git a/ports/esp32/modesp32.c b/ports/esp32/modesp32.c index ddc030e3fb..77617113fc 100644 --- a/ports/esp32/modesp32.c +++ b/ports/esp32/modesp32.c @@ -155,6 +155,7 @@ STATIC const mp_rom_map_elem_t esp32_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_hall_sensor), MP_ROM_PTR(&esp32_hall_sensor_obj) }, { MP_ROM_QSTR(MP_QSTR_Partition), MP_ROM_PTR(&esp32_partition_type) }, + { MP_ROM_QSTR(MP_QSTR_RMT), MP_ROM_PTR(&esp32_rmt_type) }, { MP_ROM_QSTR(MP_QSTR_ULP), MP_ROM_PTR(&esp32_ulp_type) }, { MP_ROM_QSTR(MP_QSTR_WAKEUP_ALL_LOW), MP_ROM_PTR(&mp_const_false_obj) }, diff --git a/ports/esp32/modesp32.h b/ports/esp32/modesp32.h index 26eec8ae69..f04bdba676 100644 --- a/ports/esp32/modesp32.h +++ b/ports/esp32/modesp32.h @@ -27,6 +27,7 @@ #define RTC_IS_VALID_EXT_PIN(pin_id) ((1ll << (pin_id)) & RTC_VALID_EXT_PINS) extern const mp_obj_type_t esp32_partition_type; +extern const mp_obj_type_t esp32_rmt_type; extern const mp_obj_type_t esp32_ulp_type; #endif // MICROPY_INCLUDED_ESP32_MODESP32_H From 7f235cbee924305e2d8a8aa86876770af66d7d82 Mon Sep 17 00:00:00 2001 From: Matt Trentini Date: Sun, 29 Sep 2019 23:36:22 +1000 Subject: [PATCH 1081/1788] docs/esp32: Add quickref and full docs for esp32.RMT class. --- docs/esp32/general.rst | 1 + docs/esp32/quickref.rst | 14 +++++++ docs/library/esp32.rst | 87 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+) diff --git a/docs/esp32/general.rst b/docs/esp32/general.rst index 51918d4e18..8137c042d9 100644 --- a/docs/esp32/general.rst +++ b/docs/esp32/general.rst @@ -52,6 +52,7 @@ For your convenience, some of technical specifications are provided below: * I2S: 2 * ADC: 12-bit SAR ADC up to 18 channels * DAC: 2 8-bit DACs +* RMT: 8 channels allowing accurate pulse transmit/receive * Programming: using BootROM bootloader from UART - due to external FlashROM and always-available BootROM bootloader, the ESP32 is not brickable diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst index ef9b0a2e8c..cfe31664e7 100644 --- a/docs/esp32/quickref.rst +++ b/docs/esp32/quickref.rst @@ -365,6 +365,20 @@ Notes: p1 = Pin(4, Pin.OUT, None) +RMT +--- + +The RMT is ESP32-specific and allows generation of accurate digital pulses with +12.5ns resolution. See :ref:`esp32.RMT ` for details. Usage is:: + + import esp32 + from machine import Pin + + r = esp32.RMT(0, pin=Pin(18), clock_div=8) + r # RMT(channel=0, pin=18, source_freq=80000000, clock_div=8) + # The channel resolution is 100ns (1/(source_freq/clock_div)). + r.write_pulses((1, 20, 2, 40), start=0) # Send 0 for 100ns, 1 for 2000ns, 0 for 200ns, 1 for 4000ns + OneWire driver -------------- diff --git a/docs/library/esp32.rst b/docs/library/esp32.rst index 68379624e6..467af0ff0f 100644 --- a/docs/library/esp32.rst +++ b/docs/library/esp32.rst @@ -1,3 +1,5 @@ +.. currentmodule:: esp32 + :mod:`esp32` --- functionality specific to the ESP32 ==================================================== @@ -86,6 +88,91 @@ Constants Used in `Partition.find` to specify the partition type. + +.. _esp32.RMT: + +RMT +--- + +The RMT (Remote Control) module, specific to the ESP32, was originally designed +to send and receive infrared remote control signals. However, due to a flexible +design and very accurate (as low as 12.5ns) pulse generation, it can also be +used to transmit or receive many other types of digital signals:: + + import esp32 + from machine import Pin + + r = esp32.RMT(0, pin=Pin(18), clock_div=8) + r # RMT(channel=0, pin=18, source_freq=80000000, clock_div=8) + # The channel resolution is 100ns (1/(source_freq/clock_div)). + r.write_pulses((1, 20, 2, 40), start=0) # Send 0 for 100ns, 1 for 2000ns, 0 for 200ns, 1 for 4000ns + +The input to the RMT module is an 80MHz clock (in the future it may be able to +configure the input clock but, for now, it's fixed). ``clock_div`` *divides* +the clock input which determines the resolution of the RMT channel. The +numbers specificed in ``write_pulses`` are multiplied by the resolution to +define the pulses. + +``clock_div`` is an 8-bit divider (0-255) and each pulse can be defined by +multiplying the resolution by a 15-bit (0-32,768) number. There are eight +channels (0-7) and each can have a different clock divider. + +So, in the example above, the 80MHz clock is divided by 8. Thus the +resolution is (1/(80Mhz/8)) 100ns. Since the ``start`` level is 0 and toggles +with each number, the bitstream is ``0101`` with durations of [100ns, 2000ns, +100ns, 4000ns]. + +For more details see Espressif's `ESP-IDF RMT documentation. +`_. + +.. Warning:: + The current MicroPython RMT implementation lacks some features, most notably + receiving pulses and carrier transmit. RMT should be considered a + *beta feature* and the interface may change in the future. + + +.. class:: RMT(channel, \*, pin=None, clock_div=8) + + This class provides access to one of the eight RMT channels. *channel* is + required and identifies which RMT channel (0-7) will be configured. *pin*, + also required, configures which Pin is bound to the RMT channel. *clock_div* + is an 8-bit clock divider that divides the source clock (80MHz) to the RMT + channel allowing the resolution to be specified. + +.. method:: RMT.source_freq() + + Returns the source clock frequency. Currently the source clock is not + configurable so this will always return 80MHz. + +.. method:: RMT.clock_div() + + Return the clock divider. Note that the channel resolution is + ``1 / (source_freq / clock_div)``. + +.. method:: RMT.wait_done(timeout=0) + + Returns True if `RMT.write_pulses` has completed. + + If *timeout* (defined in ticks of ``source_freq / clock_div``) is specified + the method will wait for *timeout* or until `RMT.write_pulses` is complete, + returning ``False`` if the channel continues to transmit. + +.. Warning:: + Avoid using ``wait_done()`` if looping is enabled. + +.. method:: RMT.loop(enable_loop) + + Configure looping on the channel, allowing a stream of pulses to be + indefinitely repeated. *enable_loop* is bool, set to True to enable looping. + +.. method:: RMT.write_pulses(pulses, start) + + Begin sending *pulses*, a list or tuple defining the stream of pulses. The + length of each pulse is defined by a number to be multiplied by the channel + resolution ``(1 / (source_freq / clock_div))``. *start* defines whether the + stream starts at 0 or 1. + + The Ultra-Low-Power co-processor -------------------------------- From 7ce1e0b1dc466e48606164aad223c81c93a9cea2 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 21 Oct 2019 15:55:18 +1100 Subject: [PATCH 1082/1788] extmod/webrepl: Move webrepl scripts to common place and use manifest. Move webrepl support code from ports/esp8266/modules into extmod/webrepl (to be alongside extmod/modwebrepl.c), and use frozen manifests to include it in the build on esp8266 and esp32. A small modification is made to webrepl.py to make it work on non-ESP ports, i.e. don't call dupterm_notify if not available. --- extmod/webrepl/manifest.py | 1 + {ports/esp8266/modules => extmod/webrepl}/webrepl.py | 5 +++-- {ports/esp8266/modules => extmod/webrepl}/webrepl_setup.py | 0 .../esp8266/modules => extmod/webrepl}/websocket_helper.py | 0 ports/esp32/boards/manifest.py | 2 +- ports/esp8266/boards/manifest.py | 1 + 6 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 extmod/webrepl/manifest.py rename {ports/esp8266/modules => extmod/webrepl}/webrepl.py (92%) rename {ports/esp8266/modules => extmod/webrepl}/webrepl_setup.py (100%) rename {ports/esp8266/modules => extmod/webrepl}/websocket_helper.py (100%) diff --git a/extmod/webrepl/manifest.py b/extmod/webrepl/manifest.py new file mode 100644 index 0000000000..0f2b440058 --- /dev/null +++ b/extmod/webrepl/manifest.py @@ -0,0 +1 @@ +freeze('.', ('webrepl.py', 'webrepl_setup.py', 'websocket_helper.py',)) diff --git a/ports/esp8266/modules/webrepl.py b/extmod/webrepl/webrepl.py similarity index 92% rename from ports/esp8266/modules/webrepl.py rename to extmod/webrepl/webrepl.py index bbf8bdb320..24c63299d5 100644 --- a/ports/esp8266/modules/webrepl.py +++ b/extmod/webrepl/webrepl.py @@ -43,8 +43,9 @@ def accept_conn(listen_sock): ws = uwebsocket.websocket(cl, True) ws = _webrepl._webrepl(ws) cl.setblocking(False) - # notify REPL on socket incoming data - cl.setsockopt(socket.SOL_SOCKET, 20, uos.dupterm_notify) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(uos, 'dupterm_notify'): + cl.setsockopt(socket.SOL_SOCKET, 20, uos.dupterm_notify) uos.dupterm(ws) diff --git a/ports/esp8266/modules/webrepl_setup.py b/extmod/webrepl/webrepl_setup.py similarity index 100% rename from ports/esp8266/modules/webrepl_setup.py rename to extmod/webrepl/webrepl_setup.py diff --git a/ports/esp8266/modules/websocket_helper.py b/extmod/webrepl/websocket_helper.py similarity index 100% rename from ports/esp8266/modules/websocket_helper.py rename to extmod/webrepl/websocket_helper.py diff --git a/ports/esp32/boards/manifest.py b/ports/esp32/boards/manifest.py index 2b07639ee9..bab2b614ba 100644 --- a/ports/esp32/boards/manifest.py +++ b/ports/esp32/boards/manifest.py @@ -1,6 +1,6 @@ freeze('$(PORT_DIR)/modules') freeze('$(MPY_DIR)/tools', ('upip.py', 'upip_utarfile.py')) freeze('$(MPY_DIR)/ports/esp8266/modules', 'ntptime.py') -freeze('$(MPY_DIR)/ports/esp8266/modules', ('webrepl.py', 'webrepl_setup.py', 'websocket_helper.py',)) freeze('$(MPY_DIR)/drivers/dht', 'dht.py') freeze('$(MPY_DIR)/drivers/onewire') +include('$(MPY_DIR)/extmod/webrepl/manifest.py') diff --git a/ports/esp8266/boards/manifest.py b/ports/esp8266/boards/manifest.py index 779e840880..b6df53fc64 100644 --- a/ports/esp8266/boards/manifest.py +++ b/ports/esp8266/boards/manifest.py @@ -2,3 +2,4 @@ freeze('$(PORT_DIR)/modules') freeze('$(MPY_DIR)/tools', ('upip.py', 'upip_utarfile.py')) freeze('$(MPY_DIR)/drivers/dht', 'dht.py') freeze('$(MPY_DIR)/drivers/onewire') +include('$(MPY_DIR)/extmod/webrepl/manifest.py') From 7ac326c4240776b20cd80956d5e1f6c005c4dc5b Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 20 Dec 2019 13:20:20 +1100 Subject: [PATCH 1083/1788] stm32/boards/PYBD: Include webrepl helper scripts in frozen manifest. --- ports/stm32/boards/PYBD_SF2/manifest.py | 2 ++ ports/stm32/boards/PYBD_SF2/mpconfigboard.mk | 3 +++ ports/stm32/boards/PYBD_SF3/mpconfigboard.mk | 3 +++ ports/stm32/boards/PYBD_SF6/mpconfigboard.mk | 3 +++ 4 files changed, 11 insertions(+) create mode 100644 ports/stm32/boards/PYBD_SF2/manifest.py diff --git a/ports/stm32/boards/PYBD_SF2/manifest.py b/ports/stm32/boards/PYBD_SF2/manifest.py new file mode 100644 index 0000000000..48cc2ce934 --- /dev/null +++ b/ports/stm32/boards/PYBD_SF2/manifest.py @@ -0,0 +1,2 @@ +include('$(PORT_DIR)/boards/manifest.py') +include('$(MPY_DIR)/extmod/webrepl/manifest.py') diff --git a/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk b/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk index 9c0121f313..69407345bd 100644 --- a/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk +++ b/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk @@ -17,3 +17,6 @@ MICROPY_PY_NETWORK_CYW43 = 1 MICROPY_PY_USSL = 1 MICROPY_SSL_MBEDTLS = 1 MICROPY_VFS_LFS2 = 1 + +# PYBD-specific frozen modules +FROZEN_MANIFEST = $(BOARD_DIR)/manifest.py diff --git a/ports/stm32/boards/PYBD_SF3/mpconfigboard.mk b/ports/stm32/boards/PYBD_SF3/mpconfigboard.mk index 7bef5651dd..f6d6e955b6 100644 --- a/ports/stm32/boards/PYBD_SF3/mpconfigboard.mk +++ b/ports/stm32/boards/PYBD_SF3/mpconfigboard.mk @@ -16,3 +16,6 @@ MICROPY_PY_LWIP = 1 MICROPY_PY_NETWORK_CYW43 = 1 MICROPY_PY_USSL = 1 MICROPY_SSL_MBEDTLS = 1 + +# PYBD-specific frozen modules +FROZEN_MANIFEST = boards/PYBD_SF2/manifest.py diff --git a/ports/stm32/boards/PYBD_SF6/mpconfigboard.mk b/ports/stm32/boards/PYBD_SF6/mpconfigboard.mk index f85d9c9973..e33d62d86a 100644 --- a/ports/stm32/boards/PYBD_SF6/mpconfigboard.mk +++ b/ports/stm32/boards/PYBD_SF6/mpconfigboard.mk @@ -13,3 +13,6 @@ MICROPY_PY_LWIP = 1 MICROPY_PY_NETWORK_CYW43 = 1 MICROPY_PY_USSL = 1 MICROPY_SSL_MBEDTLS = 1 + +# PYBD-specific frozen modules +FROZEN_MANIFEST = boards/PYBD_SF2/manifest.py From 95473980ef350174095887451d80690657f3315a Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 20 Dec 2019 14:57:06 +1100 Subject: [PATCH 1084/1788] py/vm: Fix comment to refer to MP_BC_RAISE_OBJ instead of RAISE_VARARGS. --- py/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/vm.c b/py/vm.c index 7c702f3863..11dbffaffc 100644 --- a/py/vm.c +++ b/py/vm.c @@ -269,7 +269,7 @@ outer_dispatch_loop: MICROPY_VM_HOOK_INIT // If we have exception to inject, now that we finish setting up - // execution context, raise it. This works as if RAISE_VARARGS + // execution context, raise it. This works as if MP_BC_RAISE_OBJ // bytecode was executed. // Injecting exc into yield from generator is a special case, // handled by MP_BC_YIELD_FROM itself From 073c5f3a40abd4bd7691f5468f0106ed4379ebfb Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 20 Dec 2019 14:57:44 +1100 Subject: [PATCH 1085/1788] py/profile: Fix debug opcode decoding of MP_BC_RAISE_xxx opcodes. --- py/profile.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/py/profile.c b/py/profile.c index f16d4d701e..72726cdf52 100644 --- a/py/profile.c +++ b/py/profile.c @@ -875,10 +875,16 @@ STATIC const byte *mp_prof_opcode_decode(const byte *ip, const mp_uint_t *const_ instruction->qstr_opname = MP_QSTR_RETURN_VALUE; break; - case MP_BC_RAISE_VARARGS: - unum = *ip++; - instruction->qstr_opname = MP_QSTR_RAISE_VARARGS; - instruction->arg = unum; + case MP_BC_RAISE_LAST: + instruction->qstr_opname = MP_QSTR_RAISE_LAST; + break; + + case MP_BC_RAISE_OBJ: + instruction->qstr_opname = MP_QSTR_RAISE_OBJ; + break; + + case MP_BC_RAISE_FROM: + instruction->qstr_opname = MP_QSTR_RAISE_FROM; break; case MP_BC_YIELD_VALUE: From 39bc430e44173430776e7336c9e622d52affe59a Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 20 Dec 2019 16:42:38 +1100 Subject: [PATCH 1086/1788] tests/pyb: Adjust UART and Timer tests to work on PYBD_SF6. --- tests/pyb/timer.py | 2 +- tests/pyb/uart.py | 2 +- tests/pyb/uart.py.exp | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/pyb/timer.py b/tests/pyb/timer.py index e83550abd8..0e24ff4ad4 100644 --- a/tests/pyb/timer.py +++ b/tests/pyb/timer.py @@ -16,4 +16,4 @@ print(tim.period()) tim = Timer(2, freq=100) print(tim.freq()) tim.freq(0.001) -print(tim.freq()) +print('{:.3f}'.format(tim.freq())) diff --git a/tests/pyb/uart.py b/tests/pyb/uart.py index 82a66dd2e0..9dcb1f75cd 100644 --- a/tests/pyb/uart.py +++ b/tests/pyb/uart.py @@ -1,7 +1,7 @@ from pyb import UART # test we can correctly create by id -for bus in (-1, 0, 1, 2, 5, 6, 7): +for bus in (-1, 0, 1, 2, 5, 6): try: UART(bus, 9600) print("UART", bus) diff --git a/tests/pyb/uart.py.exp b/tests/pyb/uart.py.exp index 1a4cbd9381..70e4ab8509 100644 --- a/tests/pyb/uart.py.exp +++ b/tests/pyb/uart.py.exp @@ -4,7 +4,6 @@ UART 1 UART 2 ValueError 5 UART 6 -ValueError 7 UART(1, baudrate=9600, bits=8, parity=None, stop=1, flow=0, timeout=0, timeout_char=3, rxbuf=64) UART(1, baudrate=2400, bits=8, parity=None, stop=1, flow=0, timeout=0, timeout_char=7, rxbuf=64) 0 From 1f371947309c5ea6023b6d9065415697cbc75578 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 20 Dec 2019 16:58:17 +1100 Subject: [PATCH 1087/1788] all: Bump version to 1.12. --- docs/conf.py | 2 +- py/mpconfig.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index dbd1d0c562..36f99cd2c4 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -74,7 +74,7 @@ copyright = '2014-2019, 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.11' +version = release = '1.12' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/py/mpconfig.h b/py/mpconfig.h index e46da3e83c..1e786f753b 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -28,7 +28,7 @@ // Current version of MicroPython #define MICROPY_VERSION_MAJOR 1 -#define MICROPY_VERSION_MINOR 11 +#define MICROPY_VERSION_MINOR 12 #define MICROPY_VERSION_MICRO 0 // Combined version as a 32-bit number for convenience From 035180ca015d01934094adea52affbf867e4cdc6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 20 Dec 2019 23:34:46 +1100 Subject: [PATCH 1088/1788] py: Remove commented-out debug printf's from emitbc and objlist. Any debugging prints should use a macro like DEBUG_printf. --- py/emitbc.c | 4 ---- py/objlist.c | 2 -- 2 files changed, 6 deletions(-) diff --git a/py/emitbc.c b/py/emitbc.c index 34f6362ff0..ee4a7d5f8a 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -110,7 +110,6 @@ STATIC void emit_write_uint(emit_t *emit, emit_allocator_t allocator, mp_uint_t // all functions must go through this one to emit code info STATIC byte *emit_get_cur_to_write_code_info(emit_t *emit, int num_bytes_to_write) { - //printf("emit %d\n", num_bytes_to_write); if (emit->pass < MP_PASS_EMIT) { emit->code_info_offset += num_bytes_to_write; return emit->dummy_data; @@ -140,7 +139,6 @@ STATIC void emit_write_code_info_qstr(emit_t *emit, qstr qst) { #if MICROPY_ENABLE_SOURCE_LINE STATIC void emit_write_code_info_bytes_lines(emit_t *emit, mp_uint_t bytes_to_skip, mp_uint_t lines_to_skip) { assert(bytes_to_skip > 0 || lines_to_skip > 0); - //printf(" %d %d\n", bytes_to_skip, lines_to_skip); while (bytes_to_skip > 0 || lines_to_skip > 0) { mp_uint_t b, l; if (lines_to_skip <= 6 || bytes_to_skip > 0xf) { @@ -169,7 +167,6 @@ STATIC void emit_write_code_info_bytes_lines(emit_t *emit, mp_uint_t bytes_to_sk // all functions must go through this one to emit byte code STATIC byte *emit_get_cur_to_write_bytecode(emit_t *emit, int num_bytes_to_write) { - //printf("emit %d\n", num_bytes_to_write); if (emit->pass < MP_PASS_EMIT) { emit->bytecode_offset += num_bytes_to_write; return emit->dummy_data; @@ -470,7 +467,6 @@ 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 source_line) { - //printf("source: line %d -> %d offset %d -> %d\n", emit->last_source_line, source_line, emit->last_source_line_offset, emit->bytecode_offset); #if MICROPY_ENABLE_SOURCE_LINE if (MP_STATE_VM(mp_optimise_value) >= 3) { // If we compile with -O3, don't store line numbers. diff --git a/py/objlist.c b/py/objlist.c index ec9d57fc7b..29a1d8b1a4 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -162,7 +162,6 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { } mp_int_t len_adj = slice.start - slice.stop; - //printf("Len adj: %d\n", len_adj); assert(len_adj <= 0); mp_seq_replace_slice_no_grow(self->items, self->len, slice.start, slice.stop, self->items/*NULL*/, 0, sizeof(*self->items)); // Clear "freed" elements at the end of list @@ -201,7 +200,6 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { mp_raise_NotImplementedError(NULL); } mp_int_t len_adj = value_len - (slice_out.stop - slice_out.start); - //printf("Len adj: %d\n", len_adj); if (len_adj > 0) { if (self->len + len_adj > self->alloc) { // TODO: Might optimize memory copies here by checking if block can From 5e431188db5e23a6fef5e6b3892e17354f1aac59 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 20 Dec 2019 23:36:17 +1100 Subject: [PATCH 1089/1788] py/obj.h: Remove comments about additional mp_buffer_info_t entries. These entries are unlikely to be needed, so remove them to clean up the struct definition. --- py/obj.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/py/obj.h b/py/obj.h index 5b54892ce8..7c6815a3c2 100644 --- a/py/obj.h +++ b/py/obj.h @@ -435,18 +435,9 @@ typedef mp_obj_t (*mp_getiter_fun_t)(mp_obj_t self_in, mp_obj_iter_buf_t *iter_b // Buffer protocol typedef struct _mp_buffer_info_t { - // if we'd bother to support various versions of structure - // (with different number of fields), we can distinguish - // them with ver = sizeof(struct). Cons: overkill for *micro*? - //int ver; // ? - void *buf; // can be NULL if len == 0 size_t len; // in bytes int typecode; // as per binary.h - - // Rationale: to load arbitrary-sized sprites directly to LCD - // Cons: a bit adhoc usecase - // int stride; } mp_buffer_info_t; #define MP_BUFFER_READ (1) #define MP_BUFFER_WRITE (2) From 90f286465b670feb94c3ce8857c81bad3df18b96 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Thu, 7 Nov 2019 22:15:33 +1100 Subject: [PATCH 1090/1788] stm32/mbedtls: Resize mbedtls output buffer from 16 down to 4 kiB. To reduce the size of the SSL context on the heap. See issue #5303. --- ports/stm32/mbedtls/mbedtls_config.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ports/stm32/mbedtls/mbedtls_config.h b/ports/stm32/mbedtls/mbedtls_config.h index 4820140766..338c8b3541 100644 --- a/ports/stm32/mbedtls/mbedtls_config.h +++ b/ports/stm32/mbedtls/mbedtls_config.h @@ -54,6 +54,11 @@ #define MBEDTLS_SSL_PROTO_TLS1_2 #define MBEDTLS_SSL_SERVER_NAME_INDICATION +// Use a smaller output buffer to reduce size of SSL context +#define MBEDTLS_SSL_MAX_CONTENT_LEN (16384) +#define MBEDTLS_SSL_IN_CONTENT_LEN (MBEDTLS_SSL_MAX_CONTENT_LEN) +#define MBEDTLS_SSL_OUT_CONTENT_LEN (4096) + // Enable mbedtls modules #define MBEDTLS_AES_C #define MBEDTLS_ASN1_PARSE_C From 07ccb5588c4abcffa28f25907e699d1727d38bae Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Mon, 9 Dec 2019 18:31:35 +0200 Subject: [PATCH 1091/1788] py/objobject: Add object.__setattr__ function. Allows assigning attributes on class instances that implement their own __setattr__. Both object.__setattr__ and super(A, b).__setattr__ will work with this commit. --- py/objobject.c | 22 +++++++++++++++++++++- py/runtime.c | 4 +++- tests/basics/class_delattr_setattr.py | 26 ++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/py/objobject.c b/py/objobject.c index 45228347e9..ae8436bc88 100644 --- a/py/objobject.c +++ b/py/objobject.c @@ -50,7 +50,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(object___init___obj, object___init__); 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_raise_TypeError("arg must be user-type"); } // This executes only "__new__" part of instance creation. // TODO: This won't work well for classes with native bases. @@ -62,6 +62,23 @@ STATIC mp_obj_t object___new__(mp_obj_t cls) { 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)); +#if MICROPY_PY_DELATTR_SETATTR +STATIC mp_obj_t object___setattr__(mp_obj_t self_in, mp_obj_t attr, mp_obj_t value) { + if (!mp_obj_is_instance_type(mp_obj_get_type(MP_OBJ_TO_PTR(self_in)))) { + mp_raise_TypeError("arg must be user-type"); + } + + if (!mp_obj_is_str(attr)) { + mp_raise_TypeError(NULL); + } + + mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in); + mp_map_lookup(&self->members, attr, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(object___setattr___obj, object___setattr__); +#endif + STATIC const mp_rom_map_elem_t object_locals_dict_table[] = { #if MICROPY_CPYTHON_COMPAT { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&object___init___obj) }, @@ -69,6 +86,9 @@ STATIC const mp_rom_map_elem_t object_locals_dict_table[] = { #if MICROPY_CPYTHON_COMPAT { MP_ROM_QSTR(MP_QSTR___new__), MP_ROM_PTR(&object___new___obj) }, #endif + #if MICROPY_PY_DELATTR_SETATTR + { MP_ROM_QSTR(MP_QSTR___setattr__), MP_ROM_PTR(&object___setattr___obj) }, + #endif }; STATIC MP_DEFINE_CONST_DICT(object_locals_dict, object_locals_dict_table); diff --git a/py/runtime.c b/py/runtime.c index deb82e9355..cf4fc5d38f 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -1038,9 +1038,11 @@ void mp_convert_member_lookup(mp_obj_t self, const mp_obj_type_t *type, mp_obj_t || m_type == &mp_type_fun_builtin_1 || m_type == &mp_type_fun_builtin_2 || m_type == &mp_type_fun_builtin_3 - || m_type == &mp_type_fun_builtin_var)) { + || m_type == &mp_type_fun_builtin_var) + && type != &mp_type_object) { // we extracted a builtin method without a first argument, so we must // wrap this function in a type checker + // Note that object will do its own checking so shouldn't be wrapped. dest[0] = mp_obj_new_checked_fun(type, member); } else #endif diff --git a/tests/basics/class_delattr_setattr.py b/tests/basics/class_delattr_setattr.py index 190b4875b9..8fe1bb6fc1 100644 --- a/tests/basics/class_delattr_setattr.py +++ b/tests/basics/class_delattr_setattr.py @@ -60,3 +60,29 @@ try: print(a.a) except AttributeError: print("AttributeError") + +# test object.__setattr__ +class C: + def __init__(self): + pass + + def __setattr__(self, attr, value): + print(attr, "=", value) + +c = C() +c.a = 5 +try: + print(c.a) +except AttributeError: + print("AttributeError") + +object.__setattr__(c, "a", 5) +super(C, c).__setattr__("b", 6) +print(c.a) +print(c.b) + +try: + # attribute name must be string + object.__setattr__(c, 5, 5) +except TypeError: + print("TypeError") From 42e45bd69491e56d4baa681eb34f13ca1c4bd1ba Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Tue, 10 Dec 2019 12:05:22 +0200 Subject: [PATCH 1092/1788] py/objobject: Add object.__delattr__ function. Similar to object.__setattr__. --- py/objobject.c | 18 ++++++++++++++++++ tests/basics/class_delattr_setattr.py | 25 +++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/py/objobject.c b/py/objobject.c index ae8436bc88..fcf0390597 100644 --- a/py/objobject.c +++ b/py/objobject.c @@ -77,6 +77,23 @@ STATIC mp_obj_t object___setattr__(mp_obj_t self_in, mp_obj_t attr, mp_obj_t val return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_3(object___setattr___obj, object___setattr__); + +STATIC mp_obj_t object___delattr__(mp_obj_t self_in, mp_obj_t attr) { + if (!mp_obj_is_instance_type(mp_obj_get_type(MP_OBJ_TO_PTR(self_in)))) { + mp_raise_TypeError("arg must be user-type"); + } + + if (!mp_obj_is_str(attr)) { + mp_raise_TypeError(NULL); + } + + mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in); + if (mp_map_lookup(&self->members, attr, MP_MAP_LOOKUP_REMOVE_IF_FOUND) == NULL) { + mp_raise_msg(&mp_type_AttributeError, "no such attribute"); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(object___delattr___obj, object___delattr__); #endif STATIC const mp_rom_map_elem_t object_locals_dict_table[] = { @@ -88,6 +105,7 @@ STATIC const mp_rom_map_elem_t object_locals_dict_table[] = { #endif #if MICROPY_PY_DELATTR_SETATTR { MP_ROM_QSTR(MP_QSTR___setattr__), MP_ROM_PTR(&object___setattr___obj) }, + { MP_ROM_QSTR(MP_QSTR___delattr__), MP_ROM_PTR(&object___delattr___obj) }, #endif }; diff --git a/tests/basics/class_delattr_setattr.py b/tests/basics/class_delattr_setattr.py index 8fe1bb6fc1..3389c091ab 100644 --- a/tests/basics/class_delattr_setattr.py +++ b/tests/basics/class_delattr_setattr.py @@ -69,6 +69,9 @@ class C: def __setattr__(self, attr, value): print(attr, "=", value) + def __delattr__(self, attr): + print("del", attr) + c = C() c.a = 5 try: @@ -86,3 +89,25 @@ try: object.__setattr__(c, 5, 5) except TypeError: print("TypeError") + + +# test object.__delattr__ +del c.a +print(c.a) + +object.__delattr__(c, "a") +try: + print(c.a) +except AttributeError: + print("AttributeError") + +super(C, c).__delattr__("b") +try: + print(c.b) +except AttributeError: + print("AttributeError") + +try: + object.__delattr__(c, "c") +except AttributeError: + print("AttributeError") From 300eb65ae75857b247fc39fbe677f6e28a7a259d Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 22 Dec 2019 22:04:45 +1100 Subject: [PATCH 1093/1788] py/nlrx86: Silence possible warnings about unused nlr argument. --- py/nlrx86.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/py/nlrx86.c b/py/nlrx86.c index 6195db63cd..461b459e21 100644 --- a/py/nlrx86.c +++ b/py/nlrx86.c @@ -56,9 +56,7 @@ __attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr); __attribute__((naked)) #endif unsigned int nlr_push(nlr_buf_t *nlr) { - #if !USE_NAKED (void)nlr; - #endif __asm volatile ( #if UNDO_PRELUDE From ed2be79b4930f620083256fcb5b4faf9091c9ffc Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 22 Dec 2019 22:16:32 +1100 Subject: [PATCH 1094/1788] extmod/uzlib: Explicitly cast ptr-diff-expr to unsigned. The struct member "dest" should never be less than "destStart", so their difference is never negative. Cast as such to make the comparison explicitly unsigned, ensuring the compiler produces the correct comparison instruction, and avoiding any compiler warnings. --- extmod/uzlib/tinflate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extmod/uzlib/tinflate.c b/extmod/uzlib/tinflate.c index b93bc1fa36..045952c755 100644 --- a/extmod/uzlib/tinflate.c +++ b/extmod/uzlib/tinflate.c @@ -464,7 +464,7 @@ static int tinf_inflate_block_data(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt) } } else { /* catch trying to point before the start of dest buffer */ - if (offs > d->dest - d->destStart) { + if (offs > (unsigned int)(d->dest - d->destStart)) { return TINF_DATA_ERROR; } d->lzOff = -offs; From b97fb683d0923d29f55cf54fc2fd5cc19186536e Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 22 Dec 2019 23:10:55 +1100 Subject: [PATCH 1095/1788] py/asmx86: Fix stack to be 16-byte aligned for entry and sub-call. --- py/asmx86.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/py/asmx86.c b/py/asmx86.c index 23160c9c20..e4736251f8 100644 --- a/py/asmx86.c +++ b/py/asmx86.c @@ -403,7 +403,7 @@ void asm_x86_entry(asm_x86_t *as, int num_locals) { asm_x86_push_r32(as, ASM_X86_REG_EBX); asm_x86_push_r32(as, ASM_X86_REG_ESI); asm_x86_push_r32(as, ASM_X86_REG_EDI); - num_locals |= 1; // make it odd so stack is aligned on 16 byte boundary + num_locals |= 3; // make it odd so stack is aligned on 16 byte boundary asm_x86_sub_r32_i32(as, ASM_X86_REG_ESP, num_locals * WORD_SIZE); as->num_locals = num_locals; } @@ -497,8 +497,14 @@ void asm_x86_push_local_addr(asm_x86_t *as, int local_num, int temp_r32) #endif void asm_x86_call_ind(asm_x86_t *as, size_t fun_id, mp_uint_t n_args, int temp_r32) { - // TODO align stack on 16-byte boundary before the call assert(n_args <= 5); + + // Align stack on 16-byte boundary during the call + unsigned int align = ((n_args + 3) & ~3) - n_args; + if (align) { + asm_x86_sub_r32_i32(as, ASM_X86_REG_ESP, align * WORD_SIZE); + } + if (n_args > 4) { asm_x86_push_r32(as, ASM_X86_REG_ARG_5); } @@ -521,7 +527,7 @@ void asm_x86_call_ind(asm_x86_t *as, size_t fun_id, mp_uint_t n_args, int temp_r // the caller must clean up the stack if (n_args > 0) { - asm_x86_add_i32_to_r32(as, WORD_SIZE * n_args, ASM_X86_REG_ESP); + asm_x86_add_i32_to_r32(as, (n_args + align) * WORD_SIZE, ASM_X86_REG_ESP); } } From ab75210e3338fbcc975b3c04e047ac553690f429 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 22 Dec 2019 23:13:01 +1100 Subject: [PATCH 1096/1788] py/asmx86: Remove unused 5th argument facility. In commit 71a3d6ec3bd02c5bd13334537e1bd146bb643bad mp_setup_code_state was changed from a 5-arg function to a 4-arg function, and at that point 5-arg calls in native code were no longer needed. See also commit 4f9842ad80c235188955fd83317f715033a596c0. --- py/asmx86.c | 5 +---- py/asmx86.h | 2 -- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/py/asmx86.c b/py/asmx86.c index e4736251f8..e69d06d8bb 100644 --- a/py/asmx86.c +++ b/py/asmx86.c @@ -497,7 +497,7 @@ void asm_x86_push_local_addr(asm_x86_t *as, int local_num, int temp_r32) #endif void asm_x86_call_ind(asm_x86_t *as, size_t fun_id, mp_uint_t n_args, int temp_r32) { - assert(n_args <= 5); + assert(n_args <= 4); // Align stack on 16-byte boundary during the call unsigned int align = ((n_args + 3) & ~3) - n_args; @@ -505,9 +505,6 @@ void asm_x86_call_ind(asm_x86_t *as, size_t fun_id, mp_uint_t n_args, int temp_r asm_x86_sub_r32_i32(as, ASM_X86_REG_ESP, align * WORD_SIZE); } - if (n_args > 4) { - asm_x86_push_r32(as, ASM_X86_REG_ARG_5); - } if (n_args > 3) { asm_x86_push_r32(as, ASM_X86_REG_ARG_4); } diff --git a/py/asmx86.h b/py/asmx86.h index 7ba677b2c2..abcea18030 100644 --- a/py/asmx86.h +++ b/py/asmx86.h @@ -60,7 +60,6 @@ #define ASM_X86_REG_ARG_2 ASM_X86_REG_ECX #define ASM_X86_REG_ARG_3 ASM_X86_REG_EDX #define ASM_X86_REG_ARG_4 ASM_X86_REG_EBX -#define ASM_X86_REG_ARG_5 ASM_X86_REG_ESI // condition codes, used for jcc and setcc (despite their j-name!) #define ASM_X86_CC_JB (0x2) // below, unsigned @@ -129,7 +128,6 @@ void asm_x86_call_ind(asm_x86_t* as, size_t fun_id, mp_uint_t n_args, int temp_r #define REG_ARG_2 ASM_X86_REG_ARG_2 #define REG_ARG_3 ASM_X86_REG_ARG_3 #define REG_ARG_4 ASM_X86_REG_ARG_4 -#define REG_ARG_5 ASM_X86_REG_ARG_5 // caller-save, so can be used as temporaries #define REG_TEMP0 ASM_X86_REG_EAX From 865827ed8e423cd89309b8bdd45a13902de56c4e Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 22 Dec 2019 23:51:57 +1100 Subject: [PATCH 1097/1788] tests/run-tests: Add "--mpy-cross-flags" arg to specify mpy-cross flags. --- tests/run-tests | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/run-tests b/tests/run-tests index 77667c2711..789a6f06c0 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -130,7 +130,7 @@ def run_micropython(pyb, args, test_file, is_special=False): # if running via .mpy, first compile the .py file if args.via_mpy: - subprocess.check_output([MPYCROSS, '-mcache-lookup-bc', '-o', 'mpytest.mpy', '-X', 'emit=' + args.emit, test_file]) + subprocess.check_output([MPYCROSS] + args.mpy_cross_flags.split() + ['-o', 'mpytest.mpy', '-X', 'emit=' + args.emit, test_file]) cmdlist.extend(['-m', 'mpytest']) else: cmdlist.append(test_file) @@ -566,6 +566,7 @@ the last matching regex is used: cmd_parser.add_argument('--emit', default='bytecode', help='MicroPython emitter to use (bytecode or native)') cmd_parser.add_argument('--heapsize', help='heapsize to use (use default if not specified)') cmd_parser.add_argument('--via-mpy', action='store_true', help='compile .py files to .mpy first') + cmd_parser.add_argument('--mpy-cross-flags', default='-mcache-lookup-bc', help='flags to pass to mpy-cross') cmd_parser.add_argument('--keep-path', action='store_true', help='do not clear MICROPYPATH when running tests') cmd_parser.add_argument('files', nargs='*', help='input test files') args = cmd_parser.parse_args() From 99a04b8060864bb80e6443d601342595f23ea7c4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 27 Dec 2019 12:20:15 +1100 Subject: [PATCH 1098/1788] tests/extmod: Split out VfsFat finaliser tests to separate test file. It tests independent functionality and may need to be skipped for a given port. --- tests/extmod/vfs_fat_fileio1.py | 26 ----------- tests/extmod/vfs_fat_fileio1.py.exp | 5 -- tests/extmod/vfs_fat_finaliser.py | 66 +++++++++++++++++++++++++++ tests/extmod/vfs_fat_finaliser.py.exp | 5 ++ 4 files changed, 71 insertions(+), 31 deletions(-) create mode 100644 tests/extmod/vfs_fat_finaliser.py create mode 100644 tests/extmod/vfs_fat_finaliser.py.exp diff --git a/tests/extmod/vfs_fat_fileio1.py b/tests/extmod/vfs_fat_fileio1.py index d0a5e4b73c..7fe040d539 100644 --- a/tests/extmod/vfs_fat_fileio1.py +++ b/tests/extmod/vfs_fat_fileio1.py @@ -109,29 +109,3 @@ 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() - -# 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 4eb50402c4..8da96e16bd 100644 --- a/tests/extmod/vfs_fat_fileio1.py.exp +++ b/tests/extmod/vfs_fat_fileio1.py.exp @@ -11,8 +11,3 @@ o d True [('foo_dir', 16384, 0, 0)] -MemoryError -x0 -x1 -x2 -x3 diff --git a/tests/extmod/vfs_fat_finaliser.py b/tests/extmod/vfs_fat_finaliser.py new file mode 100644 index 0000000000..c7254c5f05 --- /dev/null +++ b/tests/extmod/vfs_fat_finaliser.py @@ -0,0 +1,66 @@ +# Test VfsFat class and its finaliser + +try: + import uerrno, uos + uos.VfsFat +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + + +class RAMBlockDevice: + def __init__(self, blocks, sec_size=512): + self.sec_size = sec_size + self.data = bytearray(blocks * self.sec_size) + + def readblocks(self, n, buf): + for i in range(len(buf)): + buf[i] = self.data[n * self.sec_size + i] + + def writeblocks(self, n, buf): + for i in range(len(buf)): + self.data[n * self.sec_size + i] = buf[i] + + def ioctl(self, op, arg): + if op == 4: # MP_BLOCKDEV_IOCTL_BLOCK_COUNT + return len(self.data) // self.sec_size + if op == 5: # MP_BLOCKDEV_IOCTL_BLOCK_SIZE + return self.sec_size + + +# Create block device, and skip test if not enough RAM +try: + bdev = RAMBlockDevice(50) +except MemoryError: + print("SKIP") + raise SystemExit + +# Format block device and create VFS object +uos.VfsFat.mkfs(bdev) +vfs = uos.VfsFat(bdev) + +# 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() + +# 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_finaliser.py.exp b/tests/extmod/vfs_fat_finaliser.py.exp new file mode 100644 index 0000000000..cc51daf2a3 --- /dev/null +++ b/tests/extmod/vfs_fat_finaliser.py.exp @@ -0,0 +1,5 @@ +MemoryError +x0 +x1 +x2 +x3 From 11b4524b39482736b84de585cf683ff5c7ba4e9b Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 22 Dec 2019 22:22:14 +1100 Subject: [PATCH 1099/1788] travis: Add new job to build and test unix coverage in 32-bit mode. --- .travis.yml | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/.travis.yml b/.travis.yml index 36998300db..8ecc9f09bb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -98,6 +98,44 @@ jobs: after_failure: - (cd tests && for exp in *.exp; do testbase=$(basename $exp .exp); echo -e "\nFAILURE $testbase"; diff -u $testbase.exp $testbase.out; done) + # unix coverage 32-bit + - stage: test + env: NAME="unix coverage 32-bit build and tests" + install: + - sudo apt-get install gcc-multilib libffi-dev:i386 + - sudo apt-get install python3-pip + - sudo pip3 install setuptools + - sudo pip3 install pyelftools + - gcc --version + - python3 --version + script: + - make ${MAKEOPTS} -C mpy-cross + - make ${MAKEOPTS} -C ports/unix MICROPY_FORCE_32BIT=1 submodules + - make ${MAKEOPTS} -C ports/unix MICROPY_FORCE_32BIT=1 deplibs + - make ${MAKEOPTS} -C ports/unix MICROPY_FORCE_32BIT=1 coverage + # run the main test suite + - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests) + - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests -d thread) + - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --emit native) + - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --via-mpy --mpy-cross-flags='-mcache-lookup-bc -march=x86' -d basics float micropython) + - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --via-mpy --emit native --mpy-cross-flags='-mcache-lookup-bc -march=x86' -d basics float micropython) + # test when input script comes from stdin + - cat tests/basics/0prelim.py | ports/unix/micropython_coverage | grep -q 'abc' + # test building native mpy modules + - make -C examples/natmod/features1 ARCH=x86 + - make -C examples/natmod/features2 ARCH=x86 + - make -C examples/natmod/btree ARCH=x86 + - make -C examples/natmod/framebuf ARCH=x86 + - make -C examples/natmod/uheapq ARCH=x86 + - make -C examples/natmod/urandom ARCH=x86 + - make -C examples/natmod/ure ARCH=x86 + - make -C examples/natmod/uzlib ARCH=x86 + # test importing .mpy generated by mpy_ld.py + - MICROPYPATH=examples/natmod/features2 ./ports/unix/micropython_coverage -m features2 + - (cd tests && ./run-natmodtests.py --arch x86 extmod/{btree*,framebuf*,uheapq*,ure*,uzlib*}.py) + after_failure: + - (cd tests && for exp in *.exp; do testbase=$(basename $exp .exp); echo -e "\nFAILURE $testbase"; diff -u $testbase.exp $testbase.out; done) + # standard unix port - stage: test env: NAME="unix port build and tests" From aacd61893952af24049fd64f3735551ff9fc14ea Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 13 Nov 2019 21:05:34 +1100 Subject: [PATCH 1100/1788] py/runtime: Don't allocate iter buf for user-defined types. A user-defined type that defines __iter__ doesn't need any memory to be pre-allocated for its iterator (because it can't use such memory). So optimise for this case by not allocating the iter-buf. --- py/objtype.c | 8 ++++++-- py/objtype.h | 3 +++ py/runtime.c | 15 ++++++++++----- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/py/objtype.c b/py/objtype.c index bf089dc490..5d4dd7d2ff 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -882,7 +882,8 @@ mp_obj_t mp_obj_instance_call(mp_obj_t self_in, size_t n_args, size_t n_kw, cons return mp_call_method_self_n_kw(member[0], member[1], n_args, n_kw, args); } -STATIC mp_obj_t instance_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) { +// Note that iter_buf may be NULL, and needs to be allocated if needed +mp_obj_t mp_obj_instance_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) { mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t member[2] = {MP_OBJ_NULL}; struct class_lookup_data lookup = { @@ -897,6 +898,9 @@ STATIC mp_obj_t instance_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) return MP_OBJ_NULL; } else if (member[0] == MP_OBJ_SENTINEL) { mp_obj_type_t *type = mp_obj_get_type(self->subobj[0]); + if (iter_buf == NULL) { + iter_buf = m_new_obj(mp_obj_iter_buf_t); + } return type->getiter(self->subobj[0], iter_buf); } else { return mp_call_method_n_kw(0, 0, member); @@ -1136,7 +1140,7 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) o->binary_op = instance_binary_op; o->attr = mp_obj_instance_attr; o->subscr = instance_subscr; - o->getiter = instance_getiter; + o->getiter = mp_obj_instance_getiter; //o->iternext = ; not implemented o->buffer_p.get_buffer = instance_get_buffer; diff --git a/py/objtype.h b/py/objtype.h index 3fc8c6e1b0..2c613b9045 100644 --- a/py/objtype.h +++ b/py/objtype.h @@ -51,4 +51,7 @@ mp_obj_t mp_obj_instance_call(mp_obj_t self_in, size_t n_args, size_t n_kw, cons // this needs to be exposed for the above macros to work correctly mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self_in, size_t n_args, size_t n_kw, const mp_obj_t *args); +// this needs to be exposed for mp_getiter +mp_obj_t mp_obj_instance_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf); + #endif // MICROPY_INCLUDED_PY_OBJTYPE_H diff --git a/py/runtime.c b/py/runtime.c index cf4fc5d38f..d5511236d4 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -34,6 +34,7 @@ #include "py/objstr.h" #include "py/objtuple.h" #include "py/objlist.h" +#include "py/objtype.h" #include "py/objmodule.h" #include "py/objgenerator.h" #include "py/smallint.h" @@ -1165,13 +1166,13 @@ mp_obj_t mp_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) { return o_in; } - // if caller did not provide a buffer then allocate one on the heap - if (iter_buf == NULL) { - iter_buf = m_new_obj(mp_obj_iter_buf_t); - } - // check for native getiter (corresponds to __iter__) if (type->getiter != NULL) { + if (iter_buf == NULL && type->getiter != mp_obj_instance_getiter) { + // if caller did not provide a buffer then allocate one on the heap + // mp_obj_instance_getiter is special, it will allocate only if needed + iter_buf = m_new_obj(mp_obj_iter_buf_t); + } mp_obj_t iter = type->getiter(o_in, iter_buf); if (iter != MP_OBJ_NULL) { return iter; @@ -1183,6 +1184,10 @@ mp_obj_t mp_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) { mp_load_method_maybe(o_in, MP_QSTR___getitem__, dest); if (dest[0] != MP_OBJ_NULL) { // __getitem__ exists, create and return an iterator + if (iter_buf == NULL) { + // if caller did not provide a buffer then allocate one on the heap + iter_buf = m_new_obj(mp_obj_iter_buf_t); + } return mp_obj_new_getitem_iter(dest, iter_buf); } From de8c04317be76222d2fbe7c5bf50ffd5ff2fd140 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 22 Dec 2019 23:47:15 +1100 Subject: [PATCH 1101/1788] tests/micropython: Add test for yield-from while heap is locked. --- tests/micropython/heapalloc_yield_from.py | 31 +++++++++++++++++++ tests/micropython/heapalloc_yield_from.py.exp | 4 +++ 2 files changed, 35 insertions(+) create mode 100644 tests/micropython/heapalloc_yield_from.py create mode 100644 tests/micropython/heapalloc_yield_from.py.exp diff --git a/tests/micropython/heapalloc_yield_from.py b/tests/micropython/heapalloc_yield_from.py new file mode 100644 index 0000000000..8443210f3a --- /dev/null +++ b/tests/micropython/heapalloc_yield_from.py @@ -0,0 +1,31 @@ +# Check that yield-from can work without heap allocation + +import micropython + +# Yielding from a function generator +def sub_gen(a): + for i in range(a): + yield i +def gen(g): + yield from g +g = gen(sub_gen(4)) +micropython.heap_lock() +print(next(g)) +print(next(g)) +micropython.heap_unlock() + +# Yielding from a user iterator +class G: + def __init__(self): + self.value = 0 + def __iter__(self): + return self + def __next__(self): + v = self.value + self.value += 1 + return v +g = gen(G()) +micropython.heap_lock() +print(next(g)) +print(next(g)) +micropython.heap_unlock() diff --git a/tests/micropython/heapalloc_yield_from.py.exp b/tests/micropython/heapalloc_yield_from.py.exp new file mode 100644 index 0000000000..5565ed6787 --- /dev/null +++ b/tests/micropython/heapalloc_yield_from.py.exp @@ -0,0 +1,4 @@ +0 +1 +0 +1 From f5eec903fa961135296e2656821450979e413248 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 23 Dec 2019 00:00:53 +1100 Subject: [PATCH 1102/1788] py/objsingleton: Use mp_generic_unary_op for singleton objects. So these types more closely match NoneType, eg they can be hashed, like in CPython. --- py/objsingleton.c | 1 + tests/basics/builtin_ellipsis.py | 3 +++ tests/basics/class_notimpl.py | 3 +++ 3 files changed, 7 insertions(+) diff --git a/py/objsingleton.c b/py/objsingleton.c index 67535391ea..2b896305cf 100644 --- a/py/objsingleton.c +++ b/py/objsingleton.c @@ -47,6 +47,7 @@ const mp_obj_type_t mp_type_singleton = { { &mp_type_type }, .name = MP_QSTR_, .print = singleton_print, + .unary_op = mp_generic_unary_op, }; const mp_obj_singleton_t mp_const_ellipsis_obj = {{&mp_type_singleton}, MP_QSTR_Ellipsis}; diff --git a/tests/basics/builtin_ellipsis.py b/tests/basics/builtin_ellipsis.py index d88647a89a..d66e86de4a 100644 --- a/tests/basics/builtin_ellipsis.py +++ b/tests/basics/builtin_ellipsis.py @@ -4,3 +4,6 @@ print(...) print(Ellipsis) print(... == Ellipsis) + +# Test that Ellipsis can be hashed +print(type(hash(Ellipsis))) diff --git a/tests/basics/class_notimpl.py b/tests/basics/class_notimpl.py index 308075f92f..58e790716b 100644 --- a/tests/basics/class_notimpl.py +++ b/tests/basics/class_notimpl.py @@ -48,3 +48,6 @@ except TypeError: # NotImplemented isn't handled specially in unary methods print(-c) + +# Test that NotImplemented can be hashed +print(type(hash(NotImplemented))) From 09376f0e47b3ab4a5a2a3c2c768ff913e1835cc8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 16 Dec 2019 15:40:05 +1100 Subject: [PATCH 1103/1788] py: Introduce MP_ROM_NONE macro for ROM to refer to None object. This helps to prevent mistakes, and allows easily changing the ROM value of None if needed. --- extmod/modussl_axtls.c | 6 +++--- extmod/modussl_mbedtls.c | 6 +++--- extmod/network_cyw43.c | 10 +++++----- extmod/vfs.c | 4 ++-- extmod/vfs_fat_file.c | 4 ++-- extmod/vfs_posix_file.c | 2 +- lib/utils/mpirq.c | 2 +- ports/esp32/esp32_partition.c | 2 +- ports/esp32/network_ppp.c | 4 ++-- ports/stm32/dac.c | 2 +- ports/stm32/machine_uart.c | 2 +- ports/stm32/pin.c | 4 ++-- ports/stm32/pyb_can.c | 2 +- ports/stm32/pyb_spi.c | 2 +- ports/stm32/timer.c | 10 +++++----- ports/stm32/usb.c | 2 +- ports/unix/file.c | 6 +++--- py/obj.h | 4 ++++ py/objlist.c | 2 +- py/objproperty.c | 8 ++++---- 20 files changed, 44 insertions(+), 40 deletions(-) diff --git a/extmod/modussl_axtls.c b/extmod/modussl_axtls.c index 2ea1757287..aae1c86dcb 100644 --- a/extmod/modussl_axtls.c +++ b/extmod/modussl_axtls.c @@ -246,10 +246,10 @@ 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_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, - { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_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_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_do_handshake, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, }; diff --git a/extmod/modussl_mbedtls.c b/extmod/modussl_mbedtls.c index a71adc5b36..5c41ea2d84 100644 --- a/extmod/modussl_mbedtls.c +++ b/extmod/modussl_mbedtls.c @@ -346,10 +346,10 @@ 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_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, - { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_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_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_do_handshake, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, }; diff --git a/extmod/network_cyw43.c b/extmod/network_cyw43.c index 45bb6163e7..ad46714a3e 100644 --- a/extmod/network_cyw43.c +++ b/extmod/network_cyw43.c @@ -166,8 +166,8 @@ STATIC mp_obj_t network_cyw43_scan(size_t n_args, const mp_obj_t *pos_args, mp_m enum { ARG_passive, ARG_essid, ARG_bssid }; static const mp_arg_t allowed_args[] = { { MP_QSTR_passive, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_essid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, - { MP_QSTR_bssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_essid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_bssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, }; network_cyw43_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); @@ -212,10 +212,10 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(network_cyw43_scan_obj, 1, network_cyw43_scan) STATIC mp_obj_t network_cyw43_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_essid, ARG_key, ARG_auth, ARG_bssid, ARG_channel }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_essid, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, - { MP_QSTR_key, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_essid, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_key, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_auth, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, - { MP_QSTR_bssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_bssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_channel, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, }; diff --git a/extmod/vfs.c b/extmod/vfs.c index 5f5fc633d8..e459287d4b 100644 --- a/extmod/vfs.c +++ b/extmod/vfs.c @@ -297,10 +297,10 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_umount_obj, mp_vfs_umount); mp_obj_t mp_vfs_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_file, ARG_mode, ARG_encoding }; 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_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR_r)} }, { MP_QSTR_buffering, MP_ARG_INT, {.u_int = -1} }, - { MP_QSTR_encoding, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_encoding, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, }; // parse args diff --git a/extmod/vfs_fat_file.c b/extmod/vfs_fat_file.c index fb1e582f27..5867c202cd 100644 --- a/extmod/vfs_fat_file.c +++ b/extmod/vfs_fat_file.c @@ -154,9 +154,9 @@ STATIC mp_uint_t file_obj_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, // Note: encoding is ignored for now; it's also not a valid kwarg for CPython's FileIO, // but by adding it here we can use one single mp_arg_t array for open() and FileIO's constructor STATIC const mp_arg_t file_open_args[] = { - { MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_mode, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_QSTR(MP_QSTR_r)} }, - { MP_QSTR_encoding, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_encoding, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE} }, }; #define FILE_OPEN_NUM_ARGS MP_ARRAY_SIZE(file_open_args) diff --git a/extmod/vfs_posix_file.c b/extmod/vfs_posix_file.c index 30fde818eb..87c202e3b0 100644 --- a/extmod/vfs_posix_file.c +++ b/extmod/vfs_posix_file.c @@ -110,7 +110,7 @@ mp_obj_t mp_vfs_posix_file_open(const mp_obj_type_t *type, mp_obj_t file_in, mp_ 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_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR_r)} }, }; diff --git a/lib/utils/mpirq.c b/lib/utils/mpirq.c index d54c15482f..1bfce649d7 100644 --- a/lib/utils/mpirq.c +++ b/lib/utils/mpirq.c @@ -36,7 +36,7 @@ ******************************************************************************/ const mp_arg_t mp_irq_init_args[] = { - { MP_QSTR_handler, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_handler, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_trigger, MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_hard, MP_ARG_BOOL, {.u_bool = false} }, }; diff --git a/ports/esp32/esp32_partition.c b/ports/esp32/esp32_partition.c index e5bd31af0e..50c2173cc7 100644 --- a/ports/esp32/esp32_partition.c +++ b/ports/esp32/esp32_partition.c @@ -109,7 +109,7 @@ STATIC mp_obj_t esp32_partition_find(size_t n_args, const mp_obj_t *pos_args, mp static const mp_arg_t allowed_args[] = { { MP_QSTR_type, MP_ARG_INT, {.u_int = ESP_PARTITION_TYPE_APP} }, { MP_QSTR_subtype, MP_ARG_INT, {.u_int = ESP_PARTITION_SUBTYPE_ANY} }, - { MP_QSTR_label, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_label, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, }; 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); diff --git a/ports/esp32/network_ppp.c b/ports/esp32/network_ppp.c index d868450fd0..eb2181ed17 100644 --- a/ports/esp32/network_ppp.c +++ b/ports/esp32/network_ppp.c @@ -168,8 +168,8 @@ STATIC mp_obj_t ppp_connect_py(size_t n_args, const mp_obj_t *args, mp_map_t *kw enum { ARG_authmode, ARG_username, ARG_password }; static const mp_arg_t allowed_args[] = { { MP_QSTR_authmode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PPPAUTHTYPE_NONE} }, - { MP_QSTR_username, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, - { MP_QSTR_password, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_username, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_password, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, }; mp_arg_val_t parsed_args[MP_ARRAY_SIZE(allowed_args)]; diff --git a/ports/stm32/dac.c b/ports/stm32/dac.c index 485829c59c..9ea6962481 100644 --- a/ports/stm32/dac.c +++ b/ports/stm32/dac.c @@ -229,7 +229,7 @@ STATIC void pyb_dac_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki 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)} }, + { MP_QSTR_buffering, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, }; // parse args diff --git a/ports/stm32/machine_uart.c b/ports/stm32/machine_uart.c index 5dbc133310..0fe7b8bfa3 100644 --- a/ports/stm32/machine_uart.c +++ b/ports/stm32/machine_uart.c @@ -221,7 +221,7 @@ STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, size_t n_args, const static const mp_arg_t allowed_args[] = { { MP_QSTR_baudrate, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 9600} }, { MP_QSTR_bits, MP_ARG_INT, {.u_int = 8} }, - { MP_QSTR_parity, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_parity, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_stop, MP_ARG_INT, {.u_int = 1} }, { MP_QSTR_flow, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_HWCONTROL_NONE} }, { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, diff --git a/ports/stm32/pin.c b/ports/stm32/pin.c index d032d99145..55c4152bb0 100644 --- a/ports/stm32/pin.c +++ b/ports/stm32/pin.c @@ -329,7 +329,7 @@ STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(pin_debug_obj, MP_ROM_PTR(&pin_debug_fun_ STATIC mp_obj_t pin_obj_init_helper(const pin_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_mode, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_pull, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)}}, + { MP_QSTR_pull, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE}}, { MP_QSTR_af, MP_ARG_INT, {.u_int = -1}}, // legacy { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, { MP_QSTR_alt, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1}}, @@ -418,7 +418,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_on_obj, pin_on); STATIC mp_obj_t 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_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_handler, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_trigger, MP_ARG_INT, {.u_int = GPIO_MODE_IT_RISING | GPIO_MODE_IT_FALLING} }, { MP_QSTR_hard, MP_ARG_BOOL, {.u_bool = false} }, }; diff --git a/ports/stm32/pyb_can.c b/ports/stm32/pyb_can.c index 0de99131f0..8b58da2161 100644 --- a/ports/stm32/pyb_can.c +++ b/ports/stm32/pyb_can.c @@ -442,7 +442,7 @@ STATIC mp_obj_t pyb_can_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t * 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_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_list, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, }; diff --git a/ports/stm32/pyb_spi.c b/ports/stm32/pyb_spi.c index e76369973c..a3cacead24 100644 --- a/ports/stm32/pyb_spi.c +++ b/ports/stm32/pyb_spi.c @@ -86,7 +86,7 @@ STATIC mp_obj_t pyb_spi_init_helper(const pyb_spi_obj_t *self, size_t n_args, co { MP_QSTR_nss, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SPI_NSS_SOFT} }, { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SPI_FIRSTBIT_MSB} }, { MP_QSTR_ti, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_crc, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_crc, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, }; // parse args diff --git a/ports/stm32/timer.c b/ports/stm32/timer.c index 2e8f3e05ba..feff93412f 100644 --- a/ports/stm32/timer.c +++ b/ports/stm32/timer.c @@ -594,13 +594,13 @@ STATIC void pyb_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_freq, ARG_prescaler, ARG_period, ARG_tick_hz, ARG_mode, ARG_div, ARG_callback, ARG_deadtime, ARG_brk }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_prescaler, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, { MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, { MP_QSTR_tick_hz, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000} }, { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = TIM_COUNTERMODE_UP} }, { MP_QSTR_div, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, - { MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_deadtime, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_brk, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = BRK_OFF} }, }; @@ -982,10 +982,10 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_deinit_obj, pyb_timer_deinit); STATIC mp_obj_t pyb_timer_channel(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, - { MP_QSTR_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_pulse_width, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_pulse_width_percent, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_pulse_width_percent, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_compare, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, }; diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index f2f3d7458a..8a4b7485bb 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -382,7 +382,7 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * #endif }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_port, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, { 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} }, diff --git a/ports/unix/file.c b/ports/unix/file.c index bb841da209..6c6e26b0b2 100644 --- a/ports/unix/file.c +++ b/ports/unix/file.c @@ -148,10 +148,10 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(fdfile_fileno_obj, fdfile_fileno); // Note: encoding is ignored for now; it's also not a valid kwarg for CPython's FileIO, // but by adding it here we can use one single mp_arg_t array for open() and FileIO's constructor STATIC const mp_arg_t file_open_args[] = { - { MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_mode, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_QSTR(MP_QSTR_r)} }, - { MP_QSTR_buffering, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, - { MP_QSTR_encoding, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_buffering, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_encoding, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, }; #define FILE_OPEN_NUM_ARGS MP_ARRAY_SIZE(file_open_args) diff --git a/py/obj.h b/py/obj.h index 7c6815a3c2..189f37d076 100644 --- a/py/obj.h +++ b/py/obj.h @@ -242,6 +242,10 @@ typedef union _mp_rom_obj_t { uint64_t u64; struct { const void *lo, *hi; } u32; // Macros to create objects that are stored in ROM. +#ifndef MP_ROM_NONE +#define MP_ROM_NONE MP_ROM_PTR(&mp_const_none_obj) +#endif + #ifndef MP_ROM_INT typedef mp_const_obj_t mp_rom_obj_t; #define MP_ROM_INT(i) MP_OBJ_NEW_SMALL_INT(i) diff --git a/py/objlist.c b/py/objlist.c index 29a1d8b1a4..00afcd56ad 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -312,7 +312,7 @@ STATIC void mp_quicksort(mp_obj_t *head, mp_obj_t *tail, mp_obj_t key_fn, mp_obj // TODO Python defines sort to be stable but ours is not mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { - { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_reverse, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, }; diff --git a/py/objproperty.c b/py/objproperty.c index 49cb9ca1b4..2a7844b609 100644 --- a/py/objproperty.c +++ b/py/objproperty.c @@ -39,10 +39,10 @@ typedef struct _mp_obj_property_t { STATIC mp_obj_t property_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { enum { ARG_fget, ARG_fset, ARG_fdel, ARG_doc }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, - { MP_QSTR_, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, - { MP_QSTR_, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, - { MP_QSTR_doc, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_doc, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, }; mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals); From d97b40bdaaeb96920541e57f6d299fb0c84a7bfd Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 16 Dec 2019 15:42:17 +1100 Subject: [PATCH 1104/1788] py: Introduce MP_ROM_FALSE/MP_ROM_TRUE for ROM to refer to bool objects. This helps to prevent mistakes, and allows easily changing the ROM value of False/True if needed. --- extmod/vfs.c | 4 ++-- ports/esp32/modesp32.c | 4 ++-- py/obj.h | 5 +++++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/extmod/vfs.c b/extmod/vfs.c index e459287d4b..8e3a0f18c6 100644 --- a/extmod/vfs.c +++ b/extmod/vfs.c @@ -201,8 +201,8 @@ STATIC mp_obj_t mp_vfs_autodetect(mp_obj_t bdev_obj) { 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_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)} }, + { MP_QSTR_readonly, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_FALSE} }, + { MP_QSTR_mkfs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_FALSE} }, }; // parse args diff --git a/ports/esp32/modesp32.c b/ports/esp32/modesp32.c index 77617113fc..9597e0cbd8 100644 --- a/ports/esp32/modesp32.c +++ b/ports/esp32/modesp32.c @@ -158,8 +158,8 @@ STATIC const mp_rom_map_elem_t esp32_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_RMT), MP_ROM_PTR(&esp32_rmt_type) }, { MP_ROM_QSTR(MP_QSTR_ULP), MP_ROM_PTR(&esp32_ulp_type) }, - { MP_ROM_QSTR(MP_QSTR_WAKEUP_ALL_LOW), MP_ROM_PTR(&mp_const_false_obj) }, - { MP_ROM_QSTR(MP_QSTR_WAKEUP_ANY_HIGH), MP_ROM_PTR(&mp_const_true_obj) }, + { MP_ROM_QSTR(MP_QSTR_WAKEUP_ALL_LOW), MP_ROM_FALSE }, + { MP_ROM_QSTR(MP_QSTR_WAKEUP_ANY_HIGH), MP_ROM_TRUE }, }; STATIC MP_DEFINE_CONST_DICT(esp32_module_globals, esp32_module_globals_table); diff --git a/py/obj.h b/py/obj.h index 189f37d076..b4ee911084 100644 --- a/py/obj.h +++ b/py/obj.h @@ -246,6 +246,11 @@ typedef union _mp_rom_obj_t { uint64_t u64; struct { const void *lo, *hi; } u32; #define MP_ROM_NONE MP_ROM_PTR(&mp_const_none_obj) #endif +#ifndef MP_ROM_FALSE +#define MP_ROM_FALSE MP_ROM_PTR(&mp_const_false_obj) +#define MP_ROM_TRUE MP_ROM_PTR(&mp_const_true_obj) +#endif + #ifndef MP_ROM_INT typedef mp_const_obj_t mp_rom_obj_t; #define MP_ROM_INT(i) MP_OBJ_NEW_SMALL_INT(i) From 1f499ad2fe8bd53f4666fee0c45870fe65e2e01f Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 27 Dec 2019 22:43:35 +1100 Subject: [PATCH 1105/1788] py/objobject: Fix __setattr__/__delattr__ to build in nanbox mode. --- py/objobject.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/py/objobject.c b/py/objobject.c index fcf0390597..71301dcc4a 100644 --- a/py/objobject.c +++ b/py/objobject.c @@ -64,7 +64,7 @@ STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(object___new___obj, MP_ROM_PTR(&object__ #if MICROPY_PY_DELATTR_SETATTR STATIC mp_obj_t object___setattr__(mp_obj_t self_in, mp_obj_t attr, mp_obj_t value) { - if (!mp_obj_is_instance_type(mp_obj_get_type(MP_OBJ_TO_PTR(self_in)))) { + if (!mp_obj_is_instance_type(mp_obj_get_type(self_in))) { mp_raise_TypeError("arg must be user-type"); } @@ -79,7 +79,7 @@ STATIC mp_obj_t object___setattr__(mp_obj_t self_in, mp_obj_t attr, mp_obj_t val STATIC MP_DEFINE_CONST_FUN_OBJ_3(object___setattr___obj, object___setattr__); STATIC mp_obj_t object___delattr__(mp_obj_t self_in, mp_obj_t attr) { - if (!mp_obj_is_instance_type(mp_obj_get_type(MP_OBJ_TO_PTR(self_in)))) { + if (!mp_obj_is_instance_type(mp_obj_get_type(self_in))) { mp_raise_TypeError("arg must be user-type"); } From 6f872f81d677b91446adb2dc6ebb177f81de9bc5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 27 Dec 2019 22:45:01 +1100 Subject: [PATCH 1106/1788] extmod: Fix modbluetooth and modwebrepl to build in nanbox mode. --- extmod/modbluetooth.c | 18 +++++++++--------- extmod/modwebrepl.c | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index 756d3d6d1c..ef6bdff17d 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -133,7 +133,7 @@ STATIC mp_obj_t bluetooth_uuid_make_new(const mp_obj_type_t *type, size_t n_args } } - return self; + return MP_OBJ_FROM_PTR(self); } STATIC mp_obj_t bluetooth_uuid_unary_op(mp_unary_op_t op, mp_obj_t self_in) { @@ -353,7 +353,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bluetooth_ble_config_obj, 1, bluetooth_ble_con STATIC mp_obj_t bluetooth_ble_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_handler, ARG_trigger }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_handler, MP_ARG_OBJ|MP_ARG_REQUIRED, {.u_obj = mp_const_none} }, + { MP_QSTR_handler, MP_ARG_OBJ|MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_trigger, MP_ARG_INT, {.u_int = MP_BLUETOOTH_IRQ_ALL} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -382,9 +382,9 @@ STATIC mp_obj_t bluetooth_ble_gap_advertise(size_t n_args, const mp_obj_t *pos_a enum { ARG_interval_us, ARG_adv_data, ARG_resp_data, ARG_connectable }; static const mp_arg_t allowed_args[] = { { MP_QSTR_interval_us, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(500000)} }, - { MP_QSTR_adv_data, MP_ARG_OBJ, {.u_obj = mp_const_none } }, - { MP_QSTR_resp_data, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none } }, - { MP_QSTR_connectable, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_true } }, + { MP_QSTR_adv_data, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_resp_data, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_connectable, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_TRUE} }, }; 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); @@ -516,7 +516,7 @@ STATIC mp_obj_t bluetooth_ble_gatts_register_services(mp_obj_t self_in, mp_obj_t mp_obj_t iterable = mp_getiter(services_in, &iter_buf); mp_obj_t service_tuple_obj; - mp_obj_tuple_t *result = mp_obj_new_tuple(len, NULL); + mp_obj_tuple_t *result = MP_OBJ_TO_PTR(mp_obj_new_tuple(len, NULL)); uint16_t **handles = m_new0(uint16_t*, len); size_t *num_handles = m_new0(size_t, len); @@ -550,7 +550,7 @@ STATIC mp_obj_t bluetooth_ble_gatts_register_services(mp_obj_t self_in, mp_obj_t // Return tuple of tuple of value handles. // TODO: Also the Generic Access service characteristics? for (i = 0; i < len; ++i) { - mp_obj_tuple_t *service_handles = mp_obj_new_tuple(num_handles[i], NULL); + mp_obj_tuple_t *service_handles = MP_OBJ_TO_PTR(mp_obj_new_tuple(num_handles[i], NULL)); for (int j = 0; j < num_handles[i]; ++j) { service_handles->items[j] = MP_OBJ_NEW_SMALL_INT(handles[i][j]); } @@ -927,7 +927,7 @@ STATIC void schedule_ringbuf(void) { mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); if (!o->irq_scheduled) { o->irq_scheduled = true; - mp_sched_schedule(MP_OBJ_FROM_PTR(MP_ROM_PTR(&bluetooth_ble_invoke_irq_obj)), mp_const_none); + mp_sched_schedule(MP_OBJ_FROM_PTR(&bluetooth_ble_invoke_irq_obj), mp_const_none); } } @@ -1071,7 +1071,7 @@ bool mp_bluetooth_gatts_on_read_request(uint16_t conn_handle, uint16_t value_han mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); if ((o->irq_trigger & MP_BLUETOOTH_IRQ_GATTS_READ_REQUEST) && o->irq_handler != mp_const_none) { // Use pre-allocated tuple because this is a hard IRQ. - mp_obj_tuple_t *data = MP_OBJ_FROM_PTR(o->irq_data_tuple); + mp_obj_tuple_t *data = MP_OBJ_TO_PTR(o->irq_data_tuple); data->items[0] = MP_OBJ_NEW_SMALL_INT(conn_handle); data->items[1] = MP_OBJ_NEW_SMALL_INT(value_handle); data->len = 2; diff --git a/extmod/modwebrepl.c b/extmod/modwebrepl.c index c92d1dc1b0..b5324316d3 100644 --- a/extmod/modwebrepl.c +++ b/extmod/modwebrepl.c @@ -104,7 +104,7 @@ STATIC mp_obj_t webrepl_make_new(const mp_obj_type_t *type, size_t n_args, size_ o->data_to_recv = 0; o->state = STATE_PASSWD; write_webrepl_str(args[0], SSTR(passwd_prompt)); - return o; + return MP_OBJ_FROM_PTR(o); } STATIC void check_file_op_finished(mp_obj_webrepl_t *self) { @@ -187,7 +187,7 @@ STATIC mp_uint_t webrepl_read(mp_obj_t self_in, void *buf, mp_uint_t size, int * STATIC mp_uint_t _webrepl_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) { // We know that os.dupterm always calls with size = 1 assert(size == 1); - mp_obj_webrepl_t *self = self_in; + mp_obj_webrepl_t *self = MP_OBJ_TO_PTR(self_in); 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); @@ -294,7 +294,7 @@ STATIC mp_uint_t _webrepl_read(mp_obj_t self_in, void *buf, mp_uint_t size, int } STATIC mp_uint_t webrepl_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) { - mp_obj_webrepl_t *self = self_in; + mp_obj_webrepl_t *self = MP_OBJ_TO_PTR(self_in); if (self->state == STATE_PASSWD) { // Don't forward output until passwd is entered return size; From e83fc3260ef81b85a0724276086528a83abea0c8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 27 Dec 2019 22:45:27 +1100 Subject: [PATCH 1107/1788] drivers/cyw43: Fix to build in nanbox mode. --- drivers/cyw43/cyw43_ctrl.c | 2 +- drivers/cyw43/cyw43_lwip.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cyw43/cyw43_ctrl.c b/drivers/cyw43/cyw43_ctrl.c index 3a8bbf8646..53601dac22 100644 --- a/drivers/cyw43/cyw43_ctrl.c +++ b/drivers/cyw43/cyw43_ctrl.c @@ -252,7 +252,7 @@ STATIC const char *cyw43_async_event_name_table[89] = { STATIC void cyw43_dump_async_event(const cyw43_async_event_t *ev) { printf("[% 8d] ASYNC(%04x,", - mp_hal_ticks_ms(), + (int)mp_hal_ticks_ms(), (unsigned int)ev->flags ); if (ev->event_type < MP_ARRAY_SIZE(cyw43_async_event_name_table) diff --git a/drivers/cyw43/cyw43_lwip.c b/drivers/cyw43/cyw43_lwip.c index 8f4223029e..391dfbe900 100644 --- a/drivers/cyw43/cyw43_lwip.c +++ b/drivers/cyw43/cyw43_lwip.c @@ -49,7 +49,7 @@ STATIC void cyw43_ethernet_trace(cyw43_t *self, struct netif *netif, size_t len, } if (self->trace_flags & CYW43_TRACE_MAC) { - printf("[% 8d] ETH%cX itf=%c%c len=%u", mp_hal_ticks_ms(), is_tx ? 'T' : 'R', netif->name[0], netif->name[1], len); + printf("[% 8d] ETH%cX itf=%c%c len=%u", (int)mp_hal_ticks_ms(), is_tx ? 'T' : 'R', netif->name[0], netif->name[1], len); printf(" MAC type=%d subtype=%d data=", buf[0] >> 2 & 3, buf[0] >> 4); for (size_t i = 0; i < len; ++i) { printf(" %02x", buf[i]); From d980d51807465dd0f1e5835d483fe975c94a51a3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 27 Dec 2019 22:46:43 +1100 Subject: [PATCH 1108/1788] stm32: Fix to build in nanbox mode. --- ports/stm32/machine_i2c.c | 2 +- ports/stm32/machine_timer.c | 6 +++--- ports/stm32/mpconfigport.h | 2 +- ports/stm32/mphalport.c | 5 +++-- ports/stm32/nimble_hci_uart.c | 2 +- ports/stm32/pyb_can.c | 2 +- ports/stm32/pyb_i2c.c | 2 +- ports/stm32/storage.c | 2 +- 8 files changed, 12 insertions(+), 11 deletions(-) diff --git a/ports/stm32/machine_i2c.c b/ports/stm32/machine_i2c.c index 5c74745591..9b1f3f77f2 100644 --- a/ports/stm32/machine_i2c.c +++ b/ports/stm32/machine_i2c.c @@ -203,7 +203,7 @@ mp_obj_t machine_hard_i2c_make_new(const mp_obj_type_t *type, size_t n_args, siz { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} }, { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = I2C_POLL_DEFAULT_TIMEOUT_US} }, #if MACHINE_I2C_TIMINGR - { MP_QSTR_timingr, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_timingr, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, #endif }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; diff --git a/ports/stm32/machine_timer.c b/ports/stm32/machine_timer.c index 49e3a54d01..22fa67d7d9 100644 --- a/ports/stm32/machine_timer.c +++ b/ports/stm32/machine_timer.c @@ -33,7 +33,7 @@ typedef soft_timer_entry_t machine_timer_obj_t; const mp_obj_type_t machine_timer_type; 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; + machine_timer_obj_t *self = MP_OBJ_TO_PTR(self_in); qstr mode = self->mode == SOFT_TIMER_MODE_ONE_SHOT ? MP_QSTR_ONE_SHOT : MP_QSTR_PERIODIC; mp_printf(print, "Timer(mode=%q, period=%u)", mode, self->delta_ms); } @@ -42,10 +42,10 @@ STATIC mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, size_t n_ar enum { ARG_mode, ARG_callback, ARG_period, ARG_tick_hz, ARG_freq, }; static const mp_arg_t allowed_args[] = { { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SOFT_TIMER_MODE_PERIODIC} }, - { MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, { MP_QSTR_tick_hz, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000} }, - { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, }; // Parse args diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index becde2b919..4b5b0e054f 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -301,7 +301,7 @@ struct _mp_bluetooth_nimble_root_pointers_t; // type definitions for the specific machine -#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1)) +#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((uint32_t)(p) | 1)) #define MP_SSIZE_MAX (0x7fffffff) diff --git a/ports/stm32/mphalport.c b/ports/stm32/mphalport.c index aa5dc33975..c8d83be0a1 100644 --- a/ports/stm32/mphalport.c +++ b/ports/stm32/mphalport.c @@ -23,9 +23,10 @@ NORETURN void mp_hal_raise(HAL_StatusTypeDef status) { MP_WEAK uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) { uintptr_t ret = 0; if (MP_STATE_PORT(pyb_stdio_uart) != NULL) { + mp_obj_t pyb_stdio_uart = MP_OBJ_FROM_PTR(MP_STATE_PORT(pyb_stdio_uart)); int errcode; - const mp_stream_p_t *stream_p = mp_get_stream(MP_STATE_PORT(pyb_stdio_uart)); - ret = stream_p->ioctl(MP_STATE_PORT(pyb_stdio_uart), MP_STREAM_POLL, poll_flags, &errcode); + const mp_stream_p_t *stream_p = mp_get_stream(pyb_stdio_uart); + ret = stream_p->ioctl(pyb_stdio_uart, MP_STREAM_POLL, poll_flags, &errcode); } return ret | mp_uos_dupterm_poll(poll_flags); } diff --git a/ports/stm32/nimble_hci_uart.c b/ports/stm32/nimble_hci_uart.c index 69e89e6abf..e2ba00c017 100644 --- a/ports/stm32/nimble_hci_uart.c +++ b/ports/stm32/nimble_hci_uart.c @@ -109,7 +109,7 @@ int nimble_hci_uart_configure(uint32_t port) { int nimble_hci_uart_activate(void) { // Interrupt on RX chunk received (idle) // Trigger nimble poll when this happens - mp_obj_t uart_irq_fn = mp_load_attr(&bt_hci_uart_obj, MP_QSTR_irq); + mp_obj_t uart_irq_fn = mp_load_attr(MP_OBJ_FROM_PTR(&bt_hci_uart_obj), MP_QSTR_irq); mp_obj_t uargs[] = { MP_OBJ_FROM_PTR(&mp_uart_interrupt_obj), MP_OBJ_NEW_SMALL_INT(UART_FLAG_IDLE), diff --git a/ports/stm32/pyb_can.c b/ports/stm32/pyb_can.c index 8b58da2161..996816b6a2 100644 --- a/ports/stm32/pyb_can.c +++ b/ports/stm32/pyb_can.c @@ -563,7 +563,7 @@ STATIC mp_obj_t pyb_can_initfilterbanks(mp_obj_t self, mp_obj_t bank_in) { #endif for (int f = 0; f < CAN_MAX_FILTER; f++) { - can_clearfilter(self, f, can2_start_bank); + can_clearfilter(MP_OBJ_TO_PTR(self), f, can2_start_bank); } return mp_const_none; } diff --git a/ports/stm32/pyb_i2c.c b/ports/stm32/pyb_i2c.c index 8b816a25b1..d503e62664 100644 --- a/ports/stm32/pyb_i2c.c +++ b/ports/stm32/pyb_i2c.c @@ -599,7 +599,7 @@ STATIC mp_obj_t pyb_i2c_init_helper(const pyb_i2c_obj_t *self, size_t n_args, co { MP_QSTR_gencall, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, { MP_QSTR_dma, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, #if PYB_I2C_TIMINGR - { MP_QSTR_timingr, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_timingr, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, #endif }; diff --git a/ports/stm32/storage.c b/ports/stm32/storage.c index ebb62e44cf..7e131f02a8 100644 --- a/ports/stm32/storage.c +++ b/ports/stm32/storage.c @@ -365,7 +365,7 @@ STATIC mp_obj_t pyb_flash_writeblocks(size_t n_args, const mp_obj_t *args) { STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_flash_writeblocks_obj, 3, 4, pyb_flash_writeblocks); STATIC mp_obj_t pyb_flash_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t arg_in) { - pyb_flash_obj_t *self = self_in; + pyb_flash_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_int_t cmd = mp_obj_get_int(cmd_in); switch (cmd) { case MP_BLOCKDEV_IOCTL_INIT: { From 93509ac8c7ea7ac92b8b95453e7c5f13dcbc7099 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 27 Dec 2019 22:47:01 +1100 Subject: [PATCH 1109/1788] stm32: Add configuration to build in nanbox mode. Most stm32 boards can now be built in nan-boxing mode via: $ make NANBOX=1 Note that if float is enabled then it will be forced to double-precision. Also, native emitters will be disabled. --- ports/stm32/Makefile | 9 +++++++ ports/stm32/mpconfigport.h | 5 +++- ports/stm32/mpconfigport_nanbox.h | 43 +++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 ports/stm32/mpconfigport_nanbox.h diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index c9fdc7b0d2..6a6242df53 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -95,6 +95,15 @@ CFLAGS += -I$(BOARD_DIR) CFLAGS += -DSTM32_HAL_H='' CFLAGS += -DMICROPY_HW_VTOR=$(TEXT0_ADDR) +# Configure for nan-boxing object model if requested +ifeq ($(NANBOX),1) +CFLAGS += -DMP_CONFIGFILE='"mpconfigport_nanbox.h"' +ifneq ($(MICROPY_FLOAT_IMPL),none) +MICROPY_FLOAT_IMPL = double +endif +endif + +# Configure floating point support ifeq ($(MICROPY_FLOAT_IMPL),double) CFLAGS += -DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_DOUBLE else diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 4b5b0e054f..52cca0dca1 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -305,11 +305,14 @@ struct _mp_bluetooth_nimble_root_pointers_t; #define MP_SSIZE_MAX (0x7fffffff) +// Assume that if we already defined the obj repr then we also defined these items +#ifndef MICROPY_OBJ_REPR #define UINT_FMT "%u" #define INT_FMT "%d" - typedef int mp_int_t; // must be pointer size typedef unsigned int mp_uint_t; // must be pointer size +#endif + typedef long mp_off_t; #define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) diff --git a/ports/stm32/mpconfigport_nanbox.h b/ports/stm32/mpconfigport_nanbox.h new file mode 100644 index 0000000000..f36d55aca9 --- /dev/null +++ b/ports/stm32/mpconfigport_nanbox.h @@ -0,0 +1,43 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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 + +// Select nan-boxing object model +#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_D) + +// Native emitters don't work with nan-boxing +#define MICROPY_EMIT_THUMB (0) +#define MICROPY_EMIT_INLINE_THUMB (0) + +// Types needed for nan-boxing +#define UINT_FMT "%llu" +#define INT_FMT "%lld" +typedef int64_t mp_int_t; +typedef uint64_t mp_uint_t; + +// Include base configuration file for rest of configuration +#include From e83ab7374bf1e8ee7b0644eb35567e30e6c21c36 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 27 Dec 2019 22:48:44 +1100 Subject: [PATCH 1110/1788] travis: Add stm32 build in nanbox mode. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 8ecc9f09bb..376e7b88e3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,6 +37,7 @@ jobs: - make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_F091RC - make ${MAKEOPTS} -C ports/stm32 BOARD=PYBV11 MICROPY_PY_WIZNET5K=5200 MICROPY_PY_CC3K=1 - make ${MAKEOPTS} -C ports/stm32 BOARD=PYBD_SF2 + - make ${MAKEOPTS} -C ports/stm32 BOARD=PYBD_SF6 NANBOX=1 - make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_H743ZI CFLAGS_EXTRA='-DMICROPY_PY_THREAD=1' - make ${MAKEOPTS} -C ports/stm32 BOARD=B_L072Z_LRWAN1 - make ${MAKEOPTS} -C ports/stm32 BOARD=STM32L476DISC From 4c0176d13fbd99196c457cb38633040426efd758 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 27 Dec 2019 23:15:52 +1100 Subject: [PATCH 1111/1788] py/objstr: Don't use inline GET_STR_DATA_LEN for object-repr D. Changing to use the helper function mp_obj_str_get_data_no_check() reduces code size of nan-boxing builds by about 1000 bytes. --- py/objstr.c | 6 +++--- py/objstr.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/py/objstr.c b/py/objstr.c index e221982c57..822c9fc418 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -2153,13 +2153,13 @@ const char *mp_obj_str_get_data(mp_obj_t self_in, size_t *len) { } } -#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C +#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D const byte *mp_obj_str_get_data_no_check(mp_obj_t self_in, size_t *len) { if (mp_obj_is_qstr(self_in)) { return qstr_data(MP_OBJ_QSTR_VALUE(self_in), len); } else { - *len = ((mp_obj_str_t*)self_in)->len; - return ((mp_obj_str_t*)self_in)->data; + *len = ((mp_obj_str_t*)MP_OBJ_TO_PTR(self_in))->len; + return ((mp_obj_str_t*)MP_OBJ_TO_PTR(self_in))->data; } } #endif diff --git a/py/objstr.h b/py/objstr.h index 15ed7a2256..ba300ccf5d 100644 --- a/py/objstr.h +++ b/py/objstr.h @@ -50,7 +50,7 @@ typedef struct _mp_obj_str_t { { str_len = qstr_len(MP_OBJ_QSTR_VALUE(str_obj_in)); } else { str_len = ((mp_obj_str_t*)MP_OBJ_TO_PTR(str_obj_in))->len; } // use this macro to extract the string data and length -#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C +#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D const byte *mp_obj_str_get_data_no_check(mp_obj_t self_in, size_t *len); #define GET_STR_DATA_LEN(str_obj_in, str_data, str_len) \ size_t str_len; const byte *str_data = mp_obj_str_get_data_no_check(str_obj_in, &str_len); From d56bc6e03d842b1a2c91c987ba936752d0c2fe1b Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 27 Dec 2019 23:33:34 +1100 Subject: [PATCH 1112/1788] py/obj.h: Use 32-bit shift in MP_OBJ_NEW_QSTR calc for obj-repr D. The qst value is always small enough to fit in 31-bits (even less) and using a 32-bit shift rather than a 64-bit shift reduces code size by about 300 bytes. --- py/obj.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/obj.h b/py/obj.h index b4ee911084..efeb14b433 100644 --- a/py/obj.h +++ b/py/obj.h @@ -178,7 +178,7 @@ static inline bool mp_obj_is_small_int(mp_const_obj_t o) static inline bool mp_obj_is_qstr(mp_const_obj_t o) { return ((((uint64_t)(o)) & 0xffff000000000000) == 0x0002000000000000); } #define MP_OBJ_QSTR_VALUE(o) ((((uint32_t)(o)) >> 1) & 0xffffffff) -#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 1) | 0x0002000000000001)) +#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)(((uint64_t)(((uint32_t)(qst)) << 1)) | 0x0002000000000001)) #if MICROPY_PY_BUILTINS_FLOAT From e79424d672919bfc59862d14f2d9e78e43e8582e Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sat, 21 Dec 2019 14:22:26 -0600 Subject: [PATCH 1113/1788] ports: Allow overriding CROSS_COMPILE in a custom makefile. Many ports already allow overriding CROSS_COMPILE. This modifies the remaining ports to allow it as well. --- ports/bare-arm/Makefile | 2 +- ports/esp8266/Makefile | 2 +- ports/minimal/Makefile | 2 +- ports/nrf/Makefile | 2 +- ports/pic16bit/Makefile | 2 +- ports/powerpc/Makefile | 2 +- ports/stm32/mboot/Makefile | 2 +- ports/teensy/Makefile | 4 ++-- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ports/bare-arm/Makefile b/ports/bare-arm/Makefile index 7cb3432819..800f4093df 100644 --- a/ports/bare-arm/Makefile +++ b/ports/bare-arm/Makefile @@ -6,7 +6,7 @@ QSTR_DEFS = qstrdefsport.h # include py core make definitions include $(TOP)/py/py.mk -CROSS_COMPILE = arm-none-eabi- +CROSS_COMPILE ?= arm-none-eabi- INC += -I. INC += -I$(TOP) diff --git a/ports/esp8266/Makefile b/ports/esp8266/Makefile index f534eb6895..9a7476c102 100644 --- a/ports/esp8266/Makefile +++ b/ports/esp8266/Makefile @@ -39,7 +39,7 @@ PORT ?= /dev/ttyACM0 BAUD ?= 115200 FLASH_MODE ?= qio FLASH_SIZE ?= detect -CROSS_COMPILE = xtensa-lx106-elf- +CROSS_COMPILE ?= xtensa-lx106-elf- ESP_SDK = $(shell $(CC) -print-sysroot)/usr INC += -I. diff --git a/ports/minimal/Makefile b/ports/minimal/Makefile index f26a7ec97d..d8afa068d8 100644 --- a/ports/minimal/Makefile +++ b/ports/minimal/Makefile @@ -9,7 +9,7 @@ QSTR_DEFS = qstrdefsport.h include $(TOP)/py/py.mk ifeq ($(CROSS), 1) -CROSS_COMPILE = arm-none-eabi- +CROSS_COMPILE ?= arm-none-eabi- endif INC += -I. diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index 2ac654911e..836a89c202 100644 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -47,7 +47,7 @@ MICROPY_VFS_FAT ?= 0 MPY_CROSS = ../../mpy-cross/mpy-cross MPY_TOOL = ../../tools/mpy-tool.py -CROSS_COMPILE = arm-none-eabi- +CROSS_COMPILE ?= arm-none-eabi- INC += -I. INC += -I../.. diff --git a/ports/pic16bit/Makefile b/ports/pic16bit/Makefile index 8a931979d2..fa6de38e39 100644 --- a/ports/pic16bit/Makefile +++ b/ports/pic16bit/Makefile @@ -7,7 +7,7 @@ QSTR_DEFS = qstrdefsport.h include $(TOP)/py/py.mk XC16 = /opt/microchip/xc16/v1.35 -CROSS_COMPILE = $(XC16)/bin/xc16- +CROSS_COMPILE ?= $(XC16)/bin/xc16- PARTFAMILY = dsPIC33F PART = 33FJ256GP506 diff --git a/ports/powerpc/Makefile b/ports/powerpc/Makefile index 30474df1d1..d869ebc4f1 100644 --- a/ports/powerpc/Makefile +++ b/ports/powerpc/Makefile @@ -9,7 +9,7 @@ include $(TOP)/py/py.mk ARCH = $(shell uname -m) ifneq ("$(ARCH)", "ppc64") ifneq ("$(ARCH)", "ppc64le") - CROSS_COMPILE = powerpc64le-linux- + CROSS_COMPILE ?= powerpc64le-linux- endif endif diff --git a/ports/stm32/mboot/Makefile b/ports/stm32/mboot/Makefile index 19635b9183..9e56733005 100755 --- a/ports/stm32/mboot/Makefile +++ b/ports/stm32/mboot/Makefile @@ -34,7 +34,7 @@ OPENOCD ?= openocd OPENOCD_CONFIG ?= boards/openocd_stm32f4.cfg STARTUP_FILE ?= lib/stm32lib/CMSIS/STM32$(MCU_SERIES_UPPER)xx/Source/Templates/gcc/startup_$(CMSIS_MCU_LOWER).o -CROSS_COMPILE = arm-none-eabi- +CROSS_COMPILE ?= arm-none-eabi- INC += -I. INC += -I.. diff --git a/ports/teensy/Makefile b/ports/teensy/Makefile index 663a86fabd..769b7e39d7 100644 --- a/ports/teensy/Makefile +++ b/ports/teensy/Makefile @@ -20,10 +20,10 @@ endif ifeq ($(USE_ARDUINO_TOOLCHAIN),1) $(info Using ARDUINO toolchain) -CROSS_COMPILE = $(ARDUINO)/hardware/tools/arm-none-eabi/bin/arm-none-eabi- +CROSS_COMPILE ?= $(ARDUINO)/hardware/tools/arm-none-eabi/bin/arm-none-eabi- else $(info Using toolchain from PATH) -CROSS_COMPILE = arm-none-eabi- +CROSS_COMPILE ?= arm-none-eabi- endif CFLAGS_TEENSY = -DF_CPU=96000000 -DUSB_SERIAL -D__MK20DX256__ From aca8873bb841860c0b62d36afe42501eb4505199 Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Sun, 1 Dec 2019 01:07:58 +0200 Subject: [PATCH 1114/1788] extmod/modbluetooth: Fix func prototype, empty args should be (void). This fixes a -Wstrict-prototypes error. --- extmod/modbluetooth.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h index fbae67bc45..074f53b978 100644 --- a/extmod/modbluetooth.h +++ b/extmod/modbluetooth.h @@ -180,7 +180,7 @@ int mp_bluetooth_gatts_register_service_begin(bool append); // The value_handles won't be valid until after mp_bluetooth_register_service_end is called. int mp_bluetooth_gatts_register_service(mp_obj_bluetooth_uuid_t *service_uuid, mp_obj_bluetooth_uuid_t **characteristic_uuids, uint8_t *characteristic_flags, mp_obj_bluetooth_uuid_t **descriptor_uuids, uint8_t *descriptor_flags, uint8_t *num_descriptors, uint16_t *handles, size_t num_characteristics); // Register any queued services. -int mp_bluetooth_gatts_register_service_end(); +int mp_bluetooth_gatts_register_service_end(void); // Read the value from the local gatts db (likely this has been written by a central). int mp_bluetooth_gatts_read(uint16_t value_handle, uint8_t **value, size_t *value_len); From 61d2b40ad56243585ac2bebef67aff10d4c5583c Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Wed, 25 Dec 2019 09:27:38 +0200 Subject: [PATCH 1115/1788] lib/utils/pyexec: Introduce MICROPY_REPL_INFO, wrap debug prints in it. For the 3 ports that already make use of this feature (stm32, nrf and teensy) this doesn't make any difference, it just allows to disable it from now on. For other ports that use pyexec, this decreases code size because the debug printing code is dead (it can't be enabled) but the compiler can't deduce that, so code is still emitted. --- lib/utils/pyexec.c | 12 +++++++++++- lib/utils/pyexec.h | 4 +++- ports/nrf/modules/board/modboard.c | 2 ++ ports/nrf/mpconfigport.h | 1 + ports/stm32/modpyb.c | 2 ++ ports/stm32/mpconfigport.h | 1 + ports/teensy/modpyb.c | 2 ++ ports/teensy/mpconfigport.h | 1 + py/mpconfig.h | 5 +++++ 9 files changed, 28 insertions(+), 2 deletions(-) diff --git a/lib/utils/pyexec.c b/lib/utils/pyexec.c index 851b026b6f..747097f157 100644 --- a/lib/utils/pyexec.c +++ b/lib/utils/pyexec.c @@ -45,7 +45,10 @@ pyexec_mode_kind_t pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL; int pyexec_system_exit = 0; + +#if MICROPY_REPL_INFO STATIC bool repl_display_debugging_info = 0; +#endif #define EXEC_FLAG_PRINT_EOF (1) #define EXEC_FLAG_ALLOW_DEBUGGING (2) @@ -61,7 +64,9 @@ STATIC bool repl_display_debugging_info = 0; // EXEC_FLAG_IS_REPL is used for REPL inputs (flag passed on to mp_compile) STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input_kind, int exec_flags) { int ret = 0; + #if MICROPY_REPL_INFO uint32_t start = 0; + #endif // by default a SystemExit exception returns 0 pyexec_system_exit = 0; @@ -97,7 +102,9 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input // execute code mp_hal_set_interrupt_char(CHAR_CTRL_C); // allow ctrl-C to interrupt us + #if MICROPY_REPL_INFO start = mp_hal_ticks_ms(); + #endif mp_call_function_0(module_fun); mp_hal_set_interrupt_char(-1); // disable interrupt nlr_pop(); @@ -123,6 +130,7 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input } } + #if MICROPY_REPL_INFO // display debugging info if wanted if ((exec_flags & EXEC_FLAG_ALLOW_DEBUGGING) && repl_display_debugging_info) { mp_uint_t ticks = mp_hal_ticks_ms() - start; // TODO implement a function that does this properly @@ -142,6 +150,7 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input gc_dump_info(); #endif } + #endif if (exec_flags & EXEC_FLAG_PRINT_EOF) { mp_hal_stdout_tx_strn("\x04", 1); @@ -576,9 +585,10 @@ int pyexec_frozen_module(const char *name) { } #endif +#if MICROPY_REPL_INFO mp_obj_t pyb_set_repl_info(mp_obj_t o_value) { repl_display_debugging_info = mp_obj_get_int(o_value); return mp_const_none; } - MP_DEFINE_CONST_FUN_OBJ_1(pyb_set_repl_info_obj, pyb_set_repl_info); +#endif diff --git a/lib/utils/pyexec.h b/lib/utils/pyexec.h index 9eb490be54..573cb6d452 100644 --- a/lib/utils/pyexec.h +++ b/lib/utils/pyexec.h @@ -51,8 +51,10 @@ int pyexec_frozen_module(const char *name); void pyexec_event_repl_init(void); int pyexec_event_repl_process_char(int c); extern uint8_t pyexec_repl_active; -mp_obj_t pyb_set_repl_info(mp_obj_t o_value); +#if MICROPY_REPL_INFO +mp_obj_t pyb_set_repl_info(mp_obj_t o_value); MP_DECLARE_CONST_FUN_OBJ_1(pyb_set_repl_info_obj); +#endif #endif // MICROPY_INCLUDED_LIB_UTILS_PYEXEC_H diff --git a/ports/nrf/modules/board/modboard.c b/ports/nrf/modules/board/modboard.c index 354a616967..5f59a52a6b 100644 --- a/ports/nrf/modules/board/modboard.c +++ b/ports/nrf/modules/board/modboard.c @@ -40,7 +40,9 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_board) }, + #if MICROPY_REPL_INFO { MP_ROM_QSTR(MP_QSTR_repl_info), MP_ROM_PTR(&pyb_set_repl_info_obj) }, + #endif PYB_LED_MODULE }; diff --git a/ports/nrf/mpconfigport.h b/ports/nrf/mpconfigport.h index e5fa1579c5..281d8111cf 100644 --- a/ports/nrf/mpconfigport.h +++ b/ports/nrf/mpconfigport.h @@ -44,6 +44,7 @@ #define MICROPY_ENABLE_FINALISER (1) #define MICROPY_STACK_CHECK (1) #define MICROPY_HELPER_REPL (1) +#define MICROPY_REPL_INFO (1) #define MICROPY_REPL_EMACS_KEYS (0) #define MICROPY_REPL_AUTO_INDENT (1) #define MICROPY_KBD_EXCEPTION (1) diff --git a/ports/stm32/modpyb.c b/ports/stm32/modpyb.c index 71d7849233..6dbfb1e0bd 100644 --- a/ports/stm32/modpyb.c +++ b/ports/stm32/modpyb.c @@ -142,7 +142,9 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { { 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 + #if MICROPY_REPL_INFO { MP_ROM_QSTR(MP_QSTR_repl_info), MP_ROM_PTR(&pyb_set_repl_info_obj) }, + #endif { MP_ROM_QSTR(MP_QSTR_wfi), MP_ROM_PTR(&pyb_wfi_obj) }, { MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&pyb_disable_irq_obj) }, diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 52cca0dca1..7ae8ee7d72 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -70,6 +70,7 @@ #define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (0) #define MICROPY_KBD_EXCEPTION (1) #define MICROPY_HELPER_REPL (1) +#define MICROPY_REPL_INFO (1) #define MICROPY_REPL_EMACS_KEYS (1) #define MICROPY_REPL_AUTO_INDENT (1) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) diff --git a/ports/teensy/modpyb.c b/ports/teensy/modpyb.c index e4c399fc84..6d637a7c25 100644 --- a/ports/teensy/modpyb.c +++ b/ports/teensy/modpyb.c @@ -283,7 +283,9 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&pyb_info_obj) }, { MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&pyb_unique_id_obj) }, { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&pyb_freq_obj) }, + #if MICROPY_REPL_INFO { MP_ROM_QSTR(MP_QSTR_repl_info), MP_ROM_PTR(&pyb_set_repl_info_obj) }, + #endif { MP_ROM_QSTR(MP_QSTR_wfi), MP_ROM_PTR(&pyb_wfi_obj) }, { MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&pyb_disable_irq_obj) }, diff --git a/ports/teensy/mpconfigport.h b/ports/teensy/mpconfigport.h index b45b5ad4e3..a75bd6849a 100644 --- a/ports/teensy/mpconfigport.h +++ b/ports/teensy/mpconfigport.h @@ -9,6 +9,7 @@ #define MICROPY_ENABLE_FINALISER (1) #define MICROPY_STACK_CHECK (1) #define MICROPY_HELPER_REPL (1) +#define MICROPY_REPL_INFO (1) #define MICROPY_ENABLE_SOURCE_LINE (1) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) diff --git a/py/mpconfig.h b/py/mpconfig.h index 1e786f753b..93d67accdb 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -560,6 +560,11 @@ #define MICROPY_HELPER_REPL (0) #endif +// Allow enabling debug prints after each REPL line +#ifndef MICROPY_REPL_INFO +#define MICROPY_REPL_INFO (0) +#endif + // Whether to include emacs-style readline behavior in REPL #ifndef MICROPY_REPL_EMACS_KEYS #define MICROPY_REPL_EMACS_KEYS (0) From b2e4a57289d17d6d4377880c5fc143b3d51f3678 Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Wed, 25 Dec 2019 09:22:40 +0200 Subject: [PATCH 1116/1788] nrf/main: Remove unnecessary repl_info(0) call. It's statically initialized to 0. --- ports/nrf/main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/ports/nrf/main.c b/ports/nrf/main.c index 9ffe7a285c..af5991281f 100644 --- a/ports/nrf/main.c +++ b/ports/nrf/main.c @@ -121,8 +121,6 @@ soft_reset: mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script) mp_obj_list_init(mp_sys_argv, 0); - pyb_set_repl_info(MP_OBJ_NEW_SMALL_INT(0)); - readline_init0(); From b23bd6433cd68830d32c0c68dbbf554942bb6ad0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 28 Dec 2019 01:01:36 +1100 Subject: [PATCH 1117/1788] py: Clean up commented-out code and comments about exception hierarchy. In CPython, EnvironmentError and IOError are now aliases of OSError so no need to have them listed in the code. OverflowError inherits from ArithmeticError because it's intended to be raised "when the result of an arithmetic operation is too large to be represented" (per CPython docs), and MicroPython aims to match the CPython exception hierarchy. --- py/modbuiltins.c | 2 -- py/objexcept.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/py/modbuiltins.c b/py/modbuiltins.c index a65f3beecf..5a0a3a3380 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -762,8 +762,6 @@ STATIC const mp_rom_map_elem_t mp_module_builtins_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_ViperTypeError), MP_ROM_PTR(&mp_type_ViperTypeError) }, #endif { MP_ROM_QSTR(MP_QSTR_ZeroDivisionError), MP_ROM_PTR(&mp_type_ZeroDivisionError) }, - // Somehow CPython managed to have OverflowError not inherit from ValueError ;-/ - // TODO: For MICROPY_CPYTHON_COMPAT==0 use ValueError to avoid exc proliferation // Extra builtins as defined by a port MICROPY_PORT_BUILTINS diff --git a/py/objexcept.c b/py/objexcept.c index dadbe98ae8..869a80bbe7 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -241,10 +241,8 @@ MP_DEFINE_EXCEPTION(Exception, BaseException) MP_DEFINE_EXCEPTION(AssertionError, Exception) MP_DEFINE_EXCEPTION(AttributeError, Exception) //MP_DEFINE_EXCEPTION(BufferError, Exception) - //MP_DEFINE_EXCEPTION(EnvironmentError, Exception) use OSError instead MP_DEFINE_EXCEPTION(EOFError, Exception) MP_DEFINE_EXCEPTION(ImportError, Exception) - //MP_DEFINE_EXCEPTION(IOError, Exception) use OSError instead MP_DEFINE_EXCEPTION(LookupError, Exception) MP_DEFINE_EXCEPTION(IndexError, LookupError) MP_DEFINE_EXCEPTION(KeyError, LookupError) From 1b844e908c3a867be1e54efdb86a04c6a62b2f26 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Tue, 26 Nov 2019 11:02:19 +1100 Subject: [PATCH 1118/1788] unix/modtime: Add utime.mktime function, to complement utime.localtime. This also adds it to the windows port. --- ports/unix/modtime.c | 32 ++++++++++++++++++++++++++++++++ tests/unix/time.py | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 tests/unix/time.py diff --git a/ports/unix/modtime.c b/ports/unix/modtime.c index 0a463014dc..479d2a79dd 100644 --- a/ports/unix/modtime.c +++ b/ports/unix/modtime.c @@ -161,6 +161,37 @@ STATIC mp_obj_t mod_time_localtime(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_time_localtime_obj, 0, 1, mod_time_localtime); +STATIC mp_obj_t mod_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) { + mp_raise_TypeError("mktime needs a tuple of length 8 or 9"); + } + + struct tm time = { + .tm_year = mp_obj_get_int(elem[0]) - 1900, + .tm_mon = mp_obj_get_int(elem[1]) - 1, + .tm_mday = mp_obj_get_int(elem[2]), + .tm_hour = mp_obj_get_int(elem[3]), + .tm_min = mp_obj_get_int(elem[4]), + .tm_sec = mp_obj_get_int(elem[5]), + }; + if (len == 9) { + time.tm_isdst = mp_obj_get_int(elem[8]); + } else { + time.tm_isdst = -1; // auto-detect + } + time_t ret = mktime(&time); + if (ret == -1) { + mp_raise_msg(&mp_type_OverflowError, "invalid mktime usage"); + } + return mp_obj_new_int(ret); +} +MP_DEFINE_CONST_FUN_OBJ_1(mod_time_mktime_obj, mod_time_mktime); + STATIC const mp_rom_map_elem_t mp_module_time_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) }, { MP_ROM_QSTR(MP_QSTR_clock), MP_ROM_PTR(&mod_time_clock_obj) }, @@ -174,6 +205,7 @@ STATIC const mp_rom_map_elem_t mp_module_time_globals_table[] = { { 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) }, { MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&mod_time_localtime_obj) }, + { MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&mod_time_mktime_obj) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_time_globals, mp_module_time_globals_table); diff --git a/tests/unix/time.py b/tests/unix/time.py new file mode 100644 index 0000000000..a96c3f5b66 --- /dev/null +++ b/tests/unix/time.py @@ -0,0 +1,44 @@ +try: + import utime as time +except ImportError: + import time + +DAYS_PER_MONTH = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] + +tzseconds = -time.mktime((1970, 1, 1, 0, 0, 0, 0, 0, 0)) + +def is_leap(year): + return (year % 4) == 0 + +def test(): + seconds = 0 + wday = 3 # Jan 1, 1970 was a Thursday + for year in range(1970, 2038): + print("Testing %d" % year) + yday = 1 + for month in range(1, 13): + if month == 2 and is_leap(year): + DAYS_PER_MONTH[2] = 29 + else: + DAYS_PER_MONTH[2] = 28 + for day in range(1, DAYS_PER_MONTH[month] + 1): + secs = time.mktime((year, month, day, 0, 0, 0, 0, 0, 0)) + tzseconds + if secs != seconds: + print("mktime failed for %d-%02d-%02d got %d expected %d" % (year, month, day, secs, seconds)) + return + tuple = time.localtime(seconds) + secs = time.mktime(tuple) + if secs != seconds: + print("localtime failed for %d-%02d-%02d got %d expected %d" % (year, month, day, secs, seconds)) + return + seconds += 86400 + if yday != tuple[7]: + print("locatime for %d-%02d-%02d got yday %d, expecting %d" % (year, month, day, tuple[7], yday)) + return + if wday != tuple[6]: + print("locatime for %d-%02d-%02d got wday %d, expecting %d" % (year, month, day, tuple[6], wday)) + return + yday += 1 + wday = (wday + 1) % 7 + +test() From 269c9a08b6ac248b7bd67d4fa56f70791b5b7a73 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 28 Dec 2019 11:54:49 +1100 Subject: [PATCH 1119/1788] unix/modos: Add uos.rename and uos.rmdir. The existing uos.remove cannot be used to remove directories, instead uos.rmdir is needed. And also provide uos.rename to get a good set of filesystem functionality without requiring additional Python-level os functions (eg using ffi). --- ports/unix/modos.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/ports/unix/modos.c b/ports/unix/modos.c index 161918d4dc..c3b0c20b2b 100644 --- a/ports/unix/modos.c +++ b/ports/unix/modos.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -123,6 +124,29 @@ STATIC mp_obj_t mod_os_remove(mp_obj_t path_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_os_remove_obj, mod_os_remove); +STATIC mp_obj_t mod_os_rename(mp_obj_t old_path_in, mp_obj_t new_path_in) { + const char *old_path = mp_obj_str_get_str(old_path_in); + const char *new_path = mp_obj_str_get_str(new_path_in); + + int r = rename(old_path, new_path); + + RAISE_ERRNO(r, errno); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_os_rename_obj, mod_os_rename); + +STATIC mp_obj_t mod_os_rmdir(mp_obj_t path_in) { + const char *path = mp_obj_str_get_str(path_in); + + int r = rmdir(path); + + RAISE_ERRNO(r, errno); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_os_rmdir_obj, mod_os_rmdir); + STATIC mp_obj_t mod_os_system(mp_obj_t cmd_in) { const char *cmd = mp_obj_str_get_str(cmd_in); @@ -236,6 +260,8 @@ STATIC const mp_rom_map_elem_t mp_module_os_globals_table[] = { #endif { MP_ROM_QSTR(MP_QSTR_system), MP_ROM_PTR(&mod_os_system_obj) }, { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mod_os_remove_obj) }, + { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&mod_os_rename_obj) }, + { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&mod_os_rmdir_obj) }, { MP_ROM_QSTR(MP_QSTR_getenv), MP_ROM_PTR(&mod_os_getenv_obj) }, { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mod_os_mkdir_obj) }, { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&mod_os_ilistdir_obj) }, From 007a704d82f07d1482dae6f265fecf5710266767 Mon Sep 17 00:00:00 2001 From: Tim Gates Date: Sat, 28 Dec 2019 10:36:59 +1100 Subject: [PATCH 1120/1788] nrf/examples: Fix typo in mountsd.py, wireing -> wiring. --- ports/nrf/examples/mountsd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/nrf/examples/mountsd.py b/ports/nrf/examples/mountsd.py index 64e1c888be..037b3258c5 100644 --- a/ports/nrf/examples/mountsd.py +++ b/ports/nrf/examples/mountsd.py @@ -4,7 +4,7 @@ Example for pca10040 / nrf52832 to show how mount and list a sdcard connected over SPI. -Direct wireing on SD card (SPI): +Direct wiring on SD card (SPI): ______________________________ | \ | 9. | NC | \ From 4c93955b7b4d3d860aed1551ca6231ac4e388e69 Mon Sep 17 00:00:00 2001 From: Nicko van Someren Date: Sat, 16 Nov 2019 17:07:11 -0700 Subject: [PATCH 1121/1788] py/objslice: Add support for indices() method on slice objects. Instances of the slice class are passed to __getitem__() on objects when the user indexes them with a slice. In practice the majority of the time (other than passing it on untouched) is to work out what the slice means in the context of an array dimension of a particular length. Since Python 2.3 there has been a method on the slice class, indices(), that takes a dimension length and returns the real start, stop and step, accounting for missing or negative values in the slice spec. This commit implements such a indices() method on the slice class. It is configurable at compile-time via MICROPY_PY_BUILTINS_SLICE_INDICES, disabled by default, enabled on unix, stm32 and esp32 ports. This commit also adds new tests for slice indices and for slicing unicode strings. --- ports/esp32/mpconfigport.h | 1 + ports/stm32/mpconfigport.h | 1 + ports/unix/mpconfigport.h | 1 + py/mpconfig.h | 5 ++ py/obj.h | 15 +++--- py/objslice.c | 98 +++++++++++++++++++++++++++++++++- py/sequence.c | 74 +++---------------------- tests/basics/slice_indices.py | 27 ++++++++++ tests/unicode/unicode_slice.py | 12 +++++ 9 files changed, 160 insertions(+), 74 deletions(-) create mode 100644 tests/basics/slice_indices.py create mode 100644 tests/unicode/unicode_slice.py diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 1924cf2186..983c882ae8 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -73,6 +73,7 @@ #define MICROPY_PY_BUILTINS_SET (1) #define MICROPY_PY_BUILTINS_SLICE (1) #define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) +#define MICROPY_PY_BUILTINS_SLICE_INDICES (1) #define MICROPY_PY_BUILTINS_FROZENSET (1) #define MICROPY_PY_BUILTINS_PROPERTY (1) #define MICROPY_PY_BUILTINS_RANGE_ATTRS (1) diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 7ae8ee7d72..55f09f81f0 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -97,6 +97,7 @@ #define MICROPY_PY_BUILTINS_MEMORYVIEW (1) #define MICROPY_PY_BUILTINS_FROZENSET (1) #define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) +#define MICROPY_PY_BUILTINS_SLICE_INDICES (1) #define MICROPY_PY_BUILTINS_ROUND_INT (1) #define MICROPY_PY_ALL_SPECIAL_METHODS (1) #define MICROPY_PY_BUILTINS_COMPILE (MICROPY_ENABLE_COMPILER) diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h index 40cd1f5702..d633726a16 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -90,6 +90,7 @@ #define MICROPY_PY_REVERSE_SPECIAL_METHODS (1) #define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) #define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) +#define MICROPY_PY_BUILTINS_SLICE_INDICES (1) #define MICROPY_PY_SYS_EXIT (1) #define MICROPY_PY_SYS_ATEXIT (1) #if MICROPY_PY_SYS_SETTRACE diff --git a/py/mpconfig.h b/py/mpconfig.h index 93d67accdb..d6f4d92328 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -894,6 +894,11 @@ typedef double mp_float_t; #define MICROPY_PY_BUILTINS_SLICE_ATTRS (0) #endif +// Whether to support the .indices(len) method on slice objects +#ifndef MICROPY_PY_BUILTINS_SLICE_INDICES +#define MICROPY_PY_BUILTINS_SLICE_INDICES (0) +#endif + // Whether to support frozenset object #ifndef MICROPY_PY_BUILTINS_FROZENSET #define MICROPY_PY_BUILTINS_FROZENSET (0) diff --git a/py/obj.h b/py/obj.h index efeb14b433..ab5b1e6ec0 100644 --- a/py/obj.h +++ b/py/obj.h @@ -778,8 +778,16 @@ static inline mp_map_t *mp_obj_dict_get_map(mp_obj_t dict) { // set void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item); +// slice indexes resolved to particular sequence +typedef struct { + mp_int_t start; + mp_int_t stop; + mp_int_t step; +} mp_bound_slice_t; + // slice void mp_obj_slice_get(mp_obj_t self_in, mp_obj_t *start, mp_obj_t *stop, mp_obj_t *step); +void mp_obj_slice_indices(mp_obj_t self_in, mp_int_t length, mp_bound_slice_t *result); // functions @@ -836,13 +844,6 @@ const mp_obj_t *mp_obj_property_get(mp_obj_t self_in); // sequence helpers -// slice indexes resolved to particular sequence -typedef struct { - mp_uint_t start; - mp_uint_t stop; - mp_int_t step; -} mp_bound_slice_t; - void mp_seq_multiply(const void *items, size_t item_sz, size_t len, size_t times, void *dest); #if MICROPY_PY_BUILTINS_SLICE bool mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice_t *indexes); diff --git a/py/objslice.c b/py/objslice.c index cfc819edcc..d17dbf6057 100644 --- a/py/objslice.c +++ b/py/objslice.c @@ -27,7 +27,7 @@ #include #include -#include "py/obj.h" +#include "py/runtime.h" /******************************************************************************/ /* slice object */ @@ -53,6 +53,22 @@ STATIC void slice_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t mp_print_str(print, ")"); } +#if MICROPY_PY_BUILTINS_SLICE_INDICES +STATIC mp_obj_t slice_indices(mp_obj_t self_in, mp_obj_t length_obj) { + mp_int_t length = mp_obj_int_get_checked(length_obj); + mp_bound_slice_t bound_indices; + mp_obj_slice_indices(self_in, length, &bound_indices); + + mp_obj_t results[3] = { + MP_OBJ_NEW_SMALL_INT(bound_indices.start), + MP_OBJ_NEW_SMALL_INT(bound_indices.stop), + MP_OBJ_NEW_SMALL_INT(bound_indices.step), + }; + return mp_obj_new_tuple(3, results); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(slice_indices_obj, slice_indices); +#endif + #if MICROPY_PY_BUILTINS_SLICE_ATTRS STATIC void slice_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { if (dest[0] != MP_OBJ_NULL) { @@ -60,22 +76,37 @@ STATIC void slice_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { return; } mp_obj_slice_t *self = MP_OBJ_TO_PTR(self_in); + if (attr == MP_QSTR_start) { dest[0] = self->start; } else if (attr == MP_QSTR_stop) { dest[0] = self->stop; } else if (attr == MP_QSTR_step) { dest[0] = self->step; + #if MICROPY_PY_BUILTINS_SLICE_INDICES + } else if (attr == MP_QSTR_indices) { + dest[0] = MP_OBJ_FROM_PTR(&slice_indices_obj); + dest[1] = self_in; + #endif } } #endif +#if MICROPY_PY_BUILTINS_SLICE_INDICES && !MICROPY_PY_BUILTINS_SLICE_ATTRS +STATIC const mp_rom_map_elem_t slice_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_indices), MP_ROM_PTR(&slice_indices_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(slice_locals_dict, slice_locals_dict_table); +#endif + const mp_obj_type_t mp_type_slice = { { &mp_type_type }, .name = MP_QSTR_slice, .print = slice_print, #if MICROPY_PY_BUILTINS_SLICE_ATTRS .attr = slice_attr, +#elif MICROPY_PY_BUILTINS_SLICE_INDICES + .locals_dict = (mp_obj_dict_t*)&slice_locals_dict, #endif }; @@ -96,4 +127,69 @@ void mp_obj_slice_get(mp_obj_t self_in, mp_obj_t *start, mp_obj_t *stop, mp_obj_ *step = self->step; } +// Return the real index and step values for a slice when applied to a sequence of +// the given length, resolving missing components, negative values and values off +// the end of the sequence. +void mp_obj_slice_indices(mp_obj_t self_in, mp_int_t length, mp_bound_slice_t *result) { + mp_obj_slice_t *self = MP_OBJ_TO_PTR(self_in); + mp_int_t start, stop, step; + + if (self->step == mp_const_none) { + step = 1; + } else { + step = mp_obj_get_int(self->step); + if (step == 0) { + mp_raise_ValueError("slice step cannot be zero"); + } + } + + if (step > 0) { + // Positive step + if (self->start == mp_const_none) { + start = 0; + } else { + start = mp_obj_get_int(self->start); + if (start < 0) { + start += length; + } + start = MIN(length, MAX(start, 0)); + } + + if (self->stop == mp_const_none) { + stop = length; + } else { + stop = mp_obj_get_int(self->stop); + if (stop < 0) { + stop += length; + } + stop = MIN(length, MAX(stop, 0)); + } + } else { + // Negative step + if (self->start == mp_const_none) { + start = length - 1; + } else { + start = mp_obj_get_int(self->start); + if (start < 0) { + start += length; + } + start = MIN(length - 1, MAX(start, -1)); + } + + if (self->stop == mp_const_none) { + stop = -1; + } else { + stop = mp_obj_get_int(self->stop); + if (stop < 0) { + stop += length; + } + stop = MIN(length - 1, MAX(stop, -1)); + } + } + + result->start = start; + result->stop = stop; + result->step = step; +} + #endif diff --git a/py/sequence.c b/py/sequence.c index 4c19fc69ea..15e925000a 100644 --- a/py/sequence.c +++ b/py/sequence.c @@ -46,78 +46,20 @@ void mp_seq_multiply(const void *items, size_t item_sz, size_t len, size_t times #if MICROPY_PY_BUILTINS_SLICE bool mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice_t *indexes) { - mp_obj_t ostart, ostop, ostep; - mp_int_t start, stop; - mp_obj_slice_get(slice, &ostart, &ostop, &ostep); + mp_obj_slice_indices(slice, len, indexes); - if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) { - indexes->step = mp_obj_get_int(ostep); - if (indexes->step == 0) { - mp_raise_ValueError("slice step cannot be zero"); - } - } else { - indexes->step = 1; - } - - if (ostart == mp_const_none) { - if (indexes->step > 0) { - start = 0; - } else { - start = len - 1; - } - } else { - start = mp_obj_get_int(ostart); - } - if (ostop == mp_const_none) { - if (indexes->step > 0) { - stop = len; - } else { - stop = 0; - } - } else { - stop = mp_obj_get_int(ostop); - if (stop >= 0 && indexes->step < 0) { - stop += 1; - } - } - - // Unlike subscription, out-of-bounds slice indexes are never error - if (start < 0) { - start = len + start; - if (start < 0) { - if (indexes->step < 0) { - start = -1; - } else { - start = 0; - } - } - } else if (indexes->step > 0 && (mp_uint_t)start > len) { - start = len; - } else if (indexes->step < 0 && (mp_uint_t)start >= len) { - start = len - 1; - } - if (stop < 0) { - stop = len + stop; - if (stop < 0) { - stop = -1; - } - if (indexes->step < 0) { - stop += 1; - } - } else if ((mp_uint_t)stop > len) { - stop = len; + // If the index is negative then stop points to the last item, not after it + if (indexes->step < 0) { + indexes->stop++; } // CPython returns empty sequence in such case, or point for assignment is at start - if (indexes->step > 0 && start > stop) { - stop = start; - } else if (indexes->step < 0 && start < stop) { - stop = start + 1; + if (indexes->step > 0 && indexes->start > indexes->stop) { + indexes->stop = indexes->start; + } else if (indexes->step < 0 && indexes->start < indexes->stop) { + indexes->stop = indexes->start + 1; } - indexes->start = start; - indexes->stop = stop; - return indexes->step == 1; } diff --git a/tests/basics/slice_indices.py b/tests/basics/slice_indices.py new file mode 100644 index 0000000000..b7f439ccca --- /dev/null +++ b/tests/basics/slice_indices.py @@ -0,0 +1,27 @@ +# Test builtin slice indices resolution + +# A class that returns an item key +class A: + def __getitem__(self, idx): + return idx + +# Make sure that we have slices and .indices() +try: + A()[2:5].indices(10) +except: + print("SKIP") + raise SystemExit + +print(A()[:].indices(10)) +print(A()[2:].indices(10)) +print(A()[:7].indices(10)) +print(A()[2:7].indices(10)) +print(A()[2:7:2].indices(10)) +print(A()[2:7:-2].indices(10)) +print(A()[7:2:2].indices(10)) +print(A()[7:2:-2].indices(10)) + +print(A()[2:7:2].indices(5)) +print(A()[2:7:-2].indices(5)) +print(A()[7:2:2].indices(5)) +print(A()[7:2:-2].indices(5)) diff --git a/tests/unicode/unicode_slice.py b/tests/unicode/unicode_slice.py new file mode 100644 index 0000000000..d9237088f8 --- /dev/null +++ b/tests/unicode/unicode_slice.py @@ -0,0 +1,12 @@ +# Test slicing of Unicode strings + +s = "Привет" + +print(s[:]) +print(s[2:]) +print(s[:5]) +print(s[2:5]) +print(s[2:5:1]) +print(s[2:10]) +print(s[-3:10]) +print(s[-4:10]) From 10709846f38f8f6519dee27694ce583926a00cb9 Mon Sep 17 00:00:00 2001 From: Nicko van Someren Date: Wed, 20 Nov 2019 18:53:07 -0700 Subject: [PATCH 1122/1788] py/objslice: Inline fetching of slice paramters in str_subscr(). To reduce code size. --- py/obj.h | 7 ++++++- py/objslice.c | 15 --------------- py/objstrunicode.c | 6 +++++- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/py/obj.h b/py/obj.h index ab5b1e6ec0..f144474917 100644 --- a/py/obj.h +++ b/py/obj.h @@ -786,7 +786,12 @@ typedef struct { } mp_bound_slice_t; // slice -void mp_obj_slice_get(mp_obj_t self_in, mp_obj_t *start, mp_obj_t *stop, mp_obj_t *step); +typedef struct _mp_obj_slice_t { + mp_obj_base_t base; + mp_obj_t start; + mp_obj_t stop; + mp_obj_t step; +} mp_obj_slice_t; void mp_obj_slice_indices(mp_obj_t self_in, mp_int_t length, mp_bound_slice_t *result); // functions diff --git a/py/objslice.c b/py/objslice.c index d17dbf6057..86ee03ec51 100644 --- a/py/objslice.c +++ b/py/objslice.c @@ -34,13 +34,6 @@ #if MICROPY_PY_BUILTINS_SLICE -typedef struct _mp_obj_slice_t { - mp_obj_base_t base; - mp_obj_t start; - mp_obj_t stop; - mp_obj_t step; -} mp_obj_slice_t; - STATIC void slice_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { (void)kind; mp_obj_slice_t *o = MP_OBJ_TO_PTR(o_in); @@ -119,14 +112,6 @@ mp_obj_t mp_obj_new_slice(mp_obj_t ostart, mp_obj_t ostop, mp_obj_t ostep) { return MP_OBJ_FROM_PTR(o); } -void mp_obj_slice_get(mp_obj_t self_in, mp_obj_t *start, mp_obj_t *stop, mp_obj_t *step) { - assert(mp_obj_is_type(self_in, &mp_type_slice)); - mp_obj_slice_t *self = MP_OBJ_TO_PTR(self_in); - *start = self->start; - *stop = self->stop; - *step = self->step; -} - // Return the real index and step values for a slice when applied to a sequence of // the given length, resolving missing components, negative values and values off // the end of the sequence. diff --git a/py/objstrunicode.c b/py/objstrunicode.c index 78d0b5006e..5a127243bc 100644 --- a/py/objstrunicode.c +++ b/py/objstrunicode.c @@ -184,7 +184,11 @@ STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { #if MICROPY_PY_BUILTINS_SLICE if (mp_obj_is_type(index, &mp_type_slice)) { mp_obj_t ostart, ostop, ostep; - mp_obj_slice_get(index, &ostart, &ostop, &ostep); + mp_obj_slice_t *slice = MP_OBJ_TO_PTR(index); + ostart = slice->start; + ostop = slice->stop; + ostep = slice->step; + if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) { mp_raise_NotImplementedError("only slices with step=1 (aka None) are supported"); } From de78a9e317d3dd3654424ea70446dedbae9cce52 Mon Sep 17 00:00:00 2001 From: Jason Neal Date: Thu, 2 Jan 2020 00:30:18 +1300 Subject: [PATCH 1123/1788] tools/gen-cpydiff.py: Adjust subsections to sentence case. --- tools/gen-cpydiff.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/gen-cpydiff.py b/tools/gen-cpydiff.py index 8aef375149..356ade89d5 100644 --- a/tools/gen-cpydiff.py +++ b/tools/gen-cpydiff.py @@ -51,7 +51,7 @@ INDEX = 'index.rst' HEADER = '.. This document was generated by tools/gen-cpydiff.py\n\n' UIMPORTLIST = {'struct', 'collections', 'json'} -CLASSMAP = {'Core': 'Core Language', 'Types': 'Builtin Types'} +CLASSMAP = {'Core': 'Core language', 'Types': 'Builtin types'} INDEXPRIORITY = ['syntax', 'core_language', 'builtin_types', 'modules'] RSTCHARS = ['=', '-', '~', '`', ':'] SPLIT = '"""\n|categories: |description: |cause: |workaround: ' From aec88ddf0326187c567d4e4507149fb7c54ba91d Mon Sep 17 00:00:00 2001 From: Jason Neal Date: Thu, 2 Jan 2020 00:51:42 +1300 Subject: [PATCH 1124/1788] docs: More consistent capitalization and use of articles in headings. See issue #3188. --- docs/develop/cmodules.rst | 2 +- docs/esp32/quickref.rst | 2 +- docs/library/esp32.rst | 4 ++-- docs/library/framebuf.rst | 2 +- docs/pyboard/tutorial/switch.rst | 4 ++-- docs/reference/asm_thumb2_directives.rst | 2 +- docs/reference/asm_thumb2_float.rst | 6 +++--- docs/reference/asm_thumb2_index.rst | 4 ++-- docs/reference/asm_thumb2_logical_bit.rst | 2 +- docs/reference/constrained.rst | 14 +++++++------- docs/reference/index.rst | 4 ++-- docs/reference/isr_rules.rst | 8 ++++---- docs/reference/repl.rst | 6 +++--- docs/reference/speed_python.rst | 6 +++--- 14 files changed, 33 insertions(+), 33 deletions(-) diff --git a/docs/develop/cmodules.rst b/docs/develop/cmodules.rst index a4c4733478..e616adad03 100644 --- a/docs/develop/cmodules.rst +++ b/docs/develop/cmodules.rst @@ -54,7 +54,7 @@ A MicroPython user C module is a directory with the following files: See below for full usage example. -Basic Example +Basic example ------------- This simple module named ``example`` provides a single function diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst index cfe31664e7..c58f4aa760 100644 --- a/docs/esp32/quickref.rst +++ b/docs/esp32/quickref.rst @@ -435,7 +435,7 @@ For low-level driving of a NeoPixel:: ``NeoPixel`` object. -Capacitive Touch +Capacitive touch ---------------- Use the ``TouchPad`` class in the ``machine`` module:: diff --git a/docs/library/esp32.rst b/docs/library/esp32.rst index 467af0ff0f..5df1f3c931 100644 --- a/docs/library/esp32.rst +++ b/docs/library/esp32.rst @@ -173,8 +173,8 @@ For more details see Espressif's `ESP-IDF RMT documentation. stream starts at 0 or 1. -The Ultra-Low-Power co-processor --------------------------------- +Ultra-Low-Power co-processor +---------------------------- .. class:: ULP() diff --git a/docs/library/framebuf.rst b/docs/library/framebuf.rst index b6d7dba5de..1ff56e4dae 100644 --- a/docs/library/framebuf.rst +++ b/docs/library/framebuf.rst @@ -1,4 +1,4 @@ -:mod:`framebuf` --- Frame buffer manipulation +:mod:`framebuf` --- frame buffer manipulation ============================================= .. module:: framebuf diff --git a/docs/pyboard/tutorial/switch.rst b/docs/pyboard/tutorial/switch.rst index e2a5eae884..96bb3784e9 100644 --- a/docs/pyboard/tutorial/switch.rst +++ b/docs/pyboard/tutorial/switch.rst @@ -1,7 +1,7 @@ .. _pyboard_tutorial_switch: -The Switch, callbacks and interrupts -==================================== +Switches, callbacks and interrupts +================================== The pyboard has 2 small switches, labelled USR and RST. The RST switch is a hard-reset switch, and if you press it then it restarts the pyboard diff --git a/docs/reference/asm_thumb2_directives.rst b/docs/reference/asm_thumb2_directives.rst index 95acd7781f..6e3ddaa16d 100644 --- a/docs/reference/asm_thumb2_directives.rst +++ b/docs/reference/asm_thumb2_directives.rst @@ -1,4 +1,4 @@ -Assembler Directives +Assembler directives ==================== Labels diff --git a/docs/reference/asm_thumb2_float.rst b/docs/reference/asm_thumb2_float.rst index 46560413c9..4672c4b275 100644 --- a/docs/reference/asm_thumb2_float.rst +++ b/docs/reference/asm_thumb2_float.rst @@ -1,5 +1,5 @@ -Floating Point instructions -============================== +Floating point instructions +=========================== These instructions support the use of the ARM floating point coprocessor (on platforms such as the Pyboard which are equipped with one). The FPU @@ -61,7 +61,7 @@ Where ``[Rn + offset]`` denotes the memory address obtained by adding Rn to the is specified in bytes. Since each float value occupies a 32 bit word, when accessing arrays of floats the offset must always be a multiple of four bytes. -Data Comparison +Data comparison --------------- * vcmp(Sd, Sm) diff --git a/docs/reference/asm_thumb2_index.rst b/docs/reference/asm_thumb2_index.rst index f066e6acec..ccf0201489 100644 --- a/docs/reference/asm_thumb2_index.rst +++ b/docs/reference/asm_thumb2_index.rst @@ -1,6 +1,6 @@ .. _asm_thumb2_index: -Inline Assembler for Thumb2 architectures +Inline assembler for Thumb2 architectures ========================================= This document assumes some familiarity with assembly language programming and should be read after studying @@ -25,7 +25,7 @@ This enables the effect of instructions to be demonstrated in Python. In certain because Python doesn't support concepts such as indirection. The pseudocode employed in such cases is described on the relevant page. -Instruction Categories +Instruction categories ---------------------- The following sections details the subset of the ARM Thumb-2 instruction set supported by MicroPython. diff --git a/docs/reference/asm_thumb2_logical_bit.rst b/docs/reference/asm_thumb2_logical_bit.rst index 8c51feaf45..c57bfa8470 100644 --- a/docs/reference/asm_thumb2_logical_bit.rst +++ b/docs/reference/asm_thumb2_logical_bit.rst @@ -1,4 +1,4 @@ -Logical & Bitwise instructions +Logical & bitwise instructions ============================== Document conventions diff --git a/docs/reference/constrained.rst b/docs/reference/constrained.rst index edac0ae681..9c68bab9a1 100644 --- a/docs/reference/constrained.rst +++ b/docs/reference/constrained.rst @@ -1,6 +1,6 @@ .. _constrained: -MicroPython on Microcontrollers +MicroPython on microcontrollers =============================== MicroPython is designed to be capable of running on microcontrollers. These @@ -12,7 +12,7 @@ based on a variety of architectures, the methods presented are generic: in some cases it will be necessary to obtain detailed information from platform specific documentation. -Flash Memory +Flash memory ------------ On the Pyboard the simple way to address the limited capacity is to fit a micro @@ -58,7 +58,7 @@ heap fragmentation. In general terms it is best to minimise the repeated creation and destruction of objects. The reason for this is covered in the section covering the `heap`_. -Compilation Phase +Compilation phase ~~~~~~~~~~~~~~~~~ When a module is imported, MicroPython compiles the code to bytecode which is @@ -85,7 +85,7 @@ imported in the usual way. Alternatively some or all modules may be implemented as frozen bytecode: on most platforms this saves even more RAM as the bytecode is run directly from flash rather than being stored in RAM. -Execution Phase +Execution phase ~~~~~~~~~~~~~~~ There are a number of coding techniques for reducing RAM usage. @@ -292,7 +292,7 @@ The Q(xxx) lines should be gone. .. _heap: -The Heap +The heap -------- When a running program instantiates an object the necessary RAM is allocated @@ -391,7 +391,7 @@ Symbol Meaning Each letter represents a single block of memory, a block being 16 bytes. So each line of the heap dump represents 0x400 bytes or 1KiB of RAM. -Control of Garbage Collection +Control of garbage collection ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A GC can be demanded at any time by issuing `gc.collect()`. It is advantageous @@ -420,7 +420,7 @@ initialisation the compiler may be starved of RAM when subsequent modules are imported. If modules do instantiate data on import then `gc.collect()` issued after the import will ameliorate the problem. -String Operations +String operations ----------------- MicroPython handles strings in an efficient manner and understanding this can diff --git a/docs/reference/index.rst b/docs/reference/index.rst index ed50bf0bf4..8cd5f03df4 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -1,5 +1,5 @@ -The MicroPython language -======================== +MicroPython language and implementation +======================================= MicroPython aims to implement the Python 3.4 standard (with selected features from later versions) with respect to language syntax, and most diff --git a/docs/reference/isr_rules.rst b/docs/reference/isr_rules.rst index dfdee048c1..57690ac212 100644 --- a/docs/reference/isr_rules.rst +++ b/docs/reference/isr_rules.rst @@ -29,7 +29,7 @@ This summarises the points detailed below and lists the principal recommendation * Allocate an emergency exception buffer (see below). -MicroPython Issues +MicroPython issues ------------------ The emergency exception buffer @@ -214,7 +214,7 @@ Exceptions If an ISR raises an exception it will not propagate to the main loop. The interrupt will be disabled unless the exception is handled by the ISR code. -General Issues +General issues -------------- This is merely a brief introduction to the subject of real time programming. Beginners should note @@ -225,7 +225,7 @@ with an appreciation of the following issues. .. _ISR: -Interrupt Handler Design +Interrupt handler design ~~~~~~~~~~~~~~~~~~~~~~~~ As mentioned above, ISR's should be designed to be as simple as possible. They should always return in a short, @@ -276,7 +276,7 @@ advanced topic beyond the scope of this tutorial. .. _Critical: -Critical Sections +Critical sections ~~~~~~~~~~~~~~~~~ An example of a critical section of code is one which accesses more than one variable which can be affected by an ISR. If diff --git a/docs/reference/repl.rst b/docs/reference/repl.rst index 0c6f04b7c5..06ba918117 100644 --- a/docs/reference/repl.rst +++ b/docs/reference/repl.rst @@ -103,7 +103,7 @@ For example: KeyboardInterrupt: >>> -Paste Mode +Paste mode ---------- If you want to paste some code into your terminal window, the auto-indent feature @@ -143,7 +143,7 @@ the auto-indent feature, and changes the prompt from ``>>>`` to ``===``. For exa Paste Mode allows blank lines to be pasted. The pasted text is compiled as if it were a file. Pressing Ctrl-D exits paste mode and initiates the compilation. -Soft Reset +Soft reset ---------- A soft reset will reset the python interpreter, but tries not to reset the @@ -196,7 +196,7 @@ So you can use the underscore to save the result in a variable. For example: 15 >>> -Raw Mode +Raw mode -------- Raw mode is not something that a person would normally use. It is intended for diff --git a/docs/reference/speed_python.rst b/docs/reference/speed_python.rst index a6951ed334..aa97778592 100644 --- a/docs/reference/speed_python.rst +++ b/docs/reference/speed_python.rst @@ -1,6 +1,6 @@ .. _speed_python: -Maximising MicroPython Speed +Maximising MicroPython speed ============================ .. contents:: @@ -40,7 +40,7 @@ the best algorithm is employed. This is a topic for textbooks rather than for a MicroPython guide but spectacular performance gains can sometimes be achieved by adopting algorithms known for their efficiency. -RAM Allocation +RAM allocation ~~~~~~~~~~~~~~ To design efficient MicroPython code it is necessary to have an understanding of the @@ -69,7 +69,7 @@ example, objects which support stream interface (e.g., file or UART) provide ``r method which allocates new buffer for read data, but also a ``readinto()`` method to read data into an existing buffer. -Floating Point +Floating point ~~~~~~~~~~~~~~ Some MicroPython ports allocate floating point numbers on heap. Some other ports From 1bc9fc80821edea293bc04a4c1c2c462dc546813 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 2 Jan 2020 09:40:54 -0600 Subject: [PATCH 1125/1788] tests/run-tests: Handle 'CRASH' return by float.py feature test. It is possile for `run_feature_check(pyb, args, base_path, 'float.py')` to return `b'CRASH'`. This causes an unhandled exception in `int()`. This commit fixes the problem by first testing for `b'CRASH'` before trying to convert the return value to an integer. --- tests/run-tests | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/run-tests b/tests/run-tests index 789a6f06c0..b02463dc37 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -288,7 +288,11 @@ def run_tests(pyb, tests, args, base_path="."): 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')) + upy_float_precision = run_feature_check(pyb, args, base_path, 'float.py') + if upy_float_precision == b'CRASH': + upy_float_precision = 0 + else: + upy_float_precision = int(upy_float_precision) has_complex = run_feature_check(pyb, args, base_path, 'complex.py') == b'complex\n' has_coverage = run_feature_check(pyb, args, base_path, 'coverage.py') == b'coverage\n' cpy_byteorder = subprocess.check_output([CPYTHON3, base_path + '/feature_check/byteorder.py']) From 99ed431d2840b30f67eae49be96d31c7faeca75e Mon Sep 17 00:00:00 2001 From: Jason Neal Date: Sat, 4 Jan 2020 23:00:27 +1300 Subject: [PATCH 1126/1788] docs/library/machine.I2C.rst: Use positional-only arguments syntax. Addresses issue #5196. --- docs/library/machine.I2C.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/library/machine.I2C.rst b/docs/library/machine.I2C.rst index f589124378..2cbfec1ba8 100644 --- a/docs/library/machine.I2C.rst +++ b/docs/library/machine.I2C.rst @@ -89,7 +89,7 @@ These methods are available on software I2C only. Generate a STOP condition on the bus (SDA transitions to high while SCL is high). -.. method:: I2C.readinto(buf, nack=True) +.. method:: I2C.readinto(buf, nack=True, /) Reads bytes from the bus and stores them into *buf*. The number of bytes read is the length of *buf*. An ACK will be sent on the bus after @@ -109,13 +109,13 @@ Standard bus operations The following methods implement the standard I2C master read and write operations that target a given slave device. -.. method:: I2C.readfrom(addr, nbytes, stop=True) +.. method:: I2C.readfrom(addr, nbytes, stop=True, /) Read *nbytes* from the slave specified by *addr*. If *stop* is true then a STOP condition is generated at the end of the transfer. Returns a `bytes` object with the data read. -.. method:: I2C.readfrom_into(addr, buf, stop=True) +.. method:: I2C.readfrom_into(addr, buf, stop=True, /) Read into *buf* from the slave specified by *addr*. The number of bytes read will be the length of *buf*. @@ -123,7 +123,7 @@ operations that target a given slave device. The method returns ``None``. -.. method:: I2C.writeto(addr, buf, stop=True) +.. method:: I2C.writeto(addr, buf, stop=True, /) Write the bytes from *buf* to the slave specified by *addr*. If a NACK is received following the write of a byte from *buf* then the @@ -131,7 +131,7 @@ operations that target a given slave device. generated at the end of the transfer, even if a NACK is received. The function returns the number of ACKs that were received. -.. method:: I2C.writevto(addr, vector, stop=True) +.. method:: I2C.writevto(addr, vector, stop=True, /) Write the bytes contained in *vector* to the slave specified by *addr*. *vector* should be a tuple or list of objects with the buffer protocol. From 5ef3b6b2d9aa60febe545d6f12a5d1b7300739ce Mon Sep 17 00:00:00 2001 From: Jason Neal Date: Sun, 5 Jan 2020 01:28:12 +1300 Subject: [PATCH 1127/1788] docs/library/machine.UART.rst: Detail timeout behaviour of read methods. Also document existence of "invert" argument to constructor. --- docs/library/machine.UART.rst | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/library/machine.UART.rst b/docs/library/machine.UART.rst index 5fcdc2758e..70984dfb2f 100644 --- a/docs/library/machine.UART.rst +++ b/docs/library/machine.UART.rst @@ -58,6 +58,9 @@ Methods - *rx* specifies the RX pin to use. - *txbuf* specifies the length in characters of the TX buffer. - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. On the WiPy only the following keyword-only parameter is supported: @@ -87,7 +90,8 @@ Methods .. method:: UART.read([nbytes]) Read characters. If ``nbytes`` is specified then read at most that many bytes, - otherwise read as much data as possible. + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. Return value: a bytes object containing the bytes read in. Returns ``None`` on timeout. @@ -95,14 +99,16 @@ Methods .. method:: UART.readinto(buf[, nbytes]) Read bytes into the ``buf``. If ``nbytes`` is specified then read at most - that many bytes. Otherwise, read at most ``len(buf)`` bytes. + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. Return value: number of bytes read and stored into ``buf`` or ``None`` on timeout. .. method:: UART.readline() - Read a line, ending in a newline character. + Read a line, ending in a newline character. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. Return value: the line read or ``None`` on timeout. From 99b8c1a93731771bd7d8801a8ea939922f3d2991 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 6 Jan 2020 23:03:22 +1100 Subject: [PATCH 1128/1788] esp32/Makefile: Assign result of $call to dummy var for older make. Make version 4.1 and lower does not allow $call as the main expression on a line, so assign the result of the $call to a dummy variable. Fixes issue #5426. --- ports/esp32/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index ecaa3e62ac..a9002b6512 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -67,7 +67,7 @@ ESPIDF = $(IDF_PATH) else $(info The ESPIDF variable has not been set, please set it to the root of the esp-idf repository.) $(info See README.md for installation instructions.) -$(call print_supported_git_hash) +dummy := $(call print_supported_git_hash) $(error ESPIDF not set) endif endif @@ -99,7 +99,7 @@ $(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)) -$(call print_supported_git_hash) +dummy := $(call print_supported_git_hash) endif # pretty format of ESP IDF version, used internally by the IDF From 4d528bbaa836b3d6ec0218ca7f7c92e1bf73704c Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 6 Jan 2020 23:26:00 +1100 Subject: [PATCH 1129/1788] tests/cpydiff: Add CPy diff-test for using dict.keys() as a set. See issue #5493. --- tests/cpydiff/types_dict_keys_set.py | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/cpydiff/types_dict_keys_set.py diff --git a/tests/cpydiff/types_dict_keys_set.py b/tests/cpydiff/types_dict_keys_set.py new file mode 100644 index 0000000000..1a9af9d389 --- /dev/null +++ b/tests/cpydiff/types_dict_keys_set.py @@ -0,0 +1,7 @@ +""" +categories: Types,dict +description: Dictionary keys view does not behave as a set. +cause: Not implemented. +workaround: Explicitly convert keys to a set before using set operations. +""" +print({1:2, 3:4}.keys() & {1}) From 54a2584de10103ba3e559de1034cc76962ec681e Mon Sep 17 00:00:00 2001 From: stijn Date: Tue, 7 Jan 2020 01:36:09 +1400 Subject: [PATCH 1130/1788] tests/unix: Make unix time test pass on more platforms. As the mktime documentation for CPython states: "The earliest date for which it can generate a time is platform-dependent". In particular on Windows this depends on the timezone so e.g. for UTC+2 the earliest is 2 hours past midnight January 1970. So change the reference to the earliest possible, for UTC+14. --- tests/unix/time.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unix/time.py b/tests/unix/time.py index a96c3f5b66..35eddbe095 100644 --- a/tests/unix/time.py +++ b/tests/unix/time.py @@ -5,7 +5,7 @@ except ImportError: DAYS_PER_MONTH = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] -tzseconds = -time.mktime((1970, 1, 1, 0, 0, 0, 0, 0, 0)) +tzseconds = -time.mktime((1970, 1, 1, 14, 0, 0, 0, 0, 0)) def is_leap(year): return (year % 4) == 0 @@ -22,7 +22,7 @@ def test(): else: DAYS_PER_MONTH[2] = 28 for day in range(1, DAYS_PER_MONTH[month] + 1): - secs = time.mktime((year, month, day, 0, 0, 0, 0, 0, 0)) + tzseconds + secs = time.mktime((year, month, day, 14, 0, 0, 0, 0, 0)) + tzseconds if secs != seconds: print("mktime failed for %d-%02d-%02d got %d expected %d" % (year, month, day, secs, seconds)) return From e3187b052f14872fdb5e2d2338d359013a544fae Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 7 Jan 2020 23:59:29 +1100 Subject: [PATCH 1131/1788] stm32/boards/PYBD: Change RTC asynch prediv from 1 to 4. This change has the following effects: - Reduces the resolution of the RTC sub-second counter from 30.52us to 122.07us. - Allows RTC.calibration() to now support positive values (as well as negative values). - Reduces VBAT current consumption in standby mode by a small amount. For general purpose use 122us resolution of the sub-second counter is good enough, and the benefits of full range calibration and minor reduction in VBAT consumption are worth the change. --- ports/stm32/boards/PYBD_SF2/mpconfigboard.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/stm32/boards/PYBD_SF2/mpconfigboard.h b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h index 4ce17abd87..757dacf9a7 100644 --- a/ports/stm32/boards/PYBD_SF2/mpconfigboard.h +++ b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h @@ -56,8 +56,8 @@ void board_sleep(int value); #define MICROPY_HW_FLASH_LATENCY (FLASH_LATENCY_3) // There is an external 32kHz oscillator -#define RTC_ASYNCH_PREDIV (0) -#define RTC_SYNCH_PREDIV (0x7fff) +#define RTC_ASYNCH_PREDIV (3) +#define RTC_SYNCH_PREDIV (0x1fff) #define MICROPY_HW_RTC_USE_BYPASS (1) #define MICROPY_HW_RTC_USE_US (1) #define MICROPY_HW_RTC_USE_CALOUT (1) From bfbd94401d9cf658fc50b2e45896aba300a7af71 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 9 Jan 2020 11:01:14 +1100 Subject: [PATCH 1132/1788] py: Make mp_obj_get_type() return a const ptr to mp_obj_type_t. Most types are in rodata/ROM, and mp_obj_base_t.type is a constant pointer, so enforce this const-ness throughout the code base. If a type ever needs to be modified (eg a user type) then a simple cast can be used. --- extmod/modujson.c | 2 +- ports/stm32/moduos.c | 2 +- ports/stm32/usb.c | 2 +- py/builtinhelp.c | 2 +- py/nativeglue.h | 2 +- py/obj.c | 24 ++++++++++++------------ py/obj.h | 2 +- py/objfun.c | 2 +- py/objstr.c | 6 +++--- py/objstrunicode.c | 2 +- py/objtuple.c | 2 +- py/objtype.c | 6 +++--- py/opmethods.c | 8 ++++---- py/runtime.c | 18 +++++++++--------- py/sequence.c | 2 +- py/stream.c | 2 +- 16 files changed, 42 insertions(+), 42 deletions(-) diff --git a/extmod/modujson.c b/extmod/modujson.c index 15ed2f38d8..b7c5121cdd 100644 --- a/extmod/modujson.c +++ b/extmod/modujson.c @@ -96,7 +96,7 @@ STATIC mp_obj_t mod_ujson_load(mp_obj_t stream_obj) { stack.len = 0; stack.items = NULL; mp_obj_t stack_top = MP_OBJ_NULL; - mp_obj_type_t *stack_top_type = NULL; + const mp_obj_type_t *stack_top_type = NULL; mp_obj_t stack_key = MP_OBJ_NULL; S_NEXT(s); for (;;) { diff --git a/ports/stm32/moduos.c b/ports/stm32/moduos.c index 8bf58623c9..cafe2fe326 100644 --- a/ports/stm32/moduos.c +++ b/ports/stm32/moduos.c @@ -111,7 +111,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom); #endif bool mp_uos_dupterm_is_builtin_stream(mp_const_obj_t stream) { - mp_obj_type_t *type = mp_obj_get_type(stream); + const mp_obj_type_t *type = mp_obj_get_type(stream); return type == &pyb_uart_type #if MICROPY_HW_ENABLE_USB || type == &pyb_usb_vcp_type diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index 8a4b7485bb..432d55a31e 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -533,7 +533,7 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * mp_raise_ValueError("too many logical units"); } for (size_t i = 0; i < msc_n; ++i) { - mp_obj_type_t *type = mp_obj_get_type(items[i]); + const mp_obj_type_t *type = mp_obj_get_type(items[i]); if (type == &pyb_flash_type #if MICROPY_HW_ENABLE_SDCARD || type == &pyb_sdcard_type diff --git a/py/builtinhelp.c b/py/builtinhelp.c index 8f162d8858..033242b3df 100644 --- a/py/builtinhelp.c +++ b/py/builtinhelp.c @@ -134,7 +134,7 @@ STATIC void mp_help_print_obj(const mp_obj_t obj) { } #endif - mp_obj_type_t *type = mp_obj_get_type(obj); + const mp_obj_type_t *type = mp_obj_get_type(obj); // try to print something sensible about the given object mp_print_str(MP_PYTHON_PRINTER, "object "); diff --git a/py/nativeglue.h b/py/nativeglue.h index 021e7a8ecb..1b6d9cc7a0 100644 --- a/py/nativeglue.h +++ b/py/nativeglue.h @@ -146,7 +146,7 @@ typedef struct _mp_fun_table_t { NORETURN // Only certain compilers support no-return attributes in function pointer declarations #endif void (*raise_msg)(const mp_obj_type_t *exc_type, const char *msg); - mp_obj_type_t *(*obj_get_type)(mp_const_obj_t o_in); + const mp_obj_type_t *(*obj_get_type)(mp_const_obj_t o_in); mp_obj_t (*obj_new_str)(const char* data, size_t len); mp_obj_t (*obj_new_bytes)(const byte* data, size_t len); mp_obj_t (*obj_new_bytearray_by_ref)(size_t n, void *items); diff --git a/py/obj.c b/py/obj.c index 4588d896a5..f2a8847543 100644 --- a/py/obj.c +++ b/py/obj.c @@ -37,18 +37,18 @@ #include "py/stackctrl.h" #include "py/stream.h" // for mp_obj_print -mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in) { +const mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in) { if (mp_obj_is_small_int(o_in)) { - return (mp_obj_type_t*)&mp_type_int; + return &mp_type_int; } else if (mp_obj_is_qstr(o_in)) { - return (mp_obj_type_t*)&mp_type_str; + return &mp_type_str; #if MICROPY_PY_BUILTINS_FLOAT } else if (mp_obj_is_float(o_in)) { - return (mp_obj_type_t*)&mp_type_float; + return &mp_type_float; #endif } else { const mp_obj_base_t *o = MP_OBJ_TO_PTR(o_in); - return (mp_obj_type_t*)o->type; + return o->type; } } @@ -65,7 +65,7 @@ void mp_obj_print_helper(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t return; } #endif - mp_obj_type_t *type = mp_obj_get_type(o_in); + const mp_obj_type_t *type = mp_obj_get_type(o_in); if (type->print != NULL) { type->print((mp_print_t*)print, o_in, kind); } else { @@ -119,7 +119,7 @@ bool mp_obj_is_true(mp_obj_t arg) { return 1; } } else { - mp_obj_type_t *type = mp_obj_get_type(arg); + const mp_obj_type_t *type = mp_obj_get_type(arg); if (type->unary_op != NULL) { mp_obj_t result = type->unary_op(MP_UNARY_OP_BOOL, arg); if (result != MP_OBJ_NULL) { @@ -139,7 +139,7 @@ bool mp_obj_is_true(mp_obj_t arg) { } bool mp_obj_is_callable(mp_obj_t o_in) { - mp_call_fun_t call = mp_obj_get_type(o_in)->call; + const mp_call_fun_t call = mp_obj_get_type(o_in)->call; if (call != mp_obj_instance_call) { return call != NULL; } @@ -209,7 +209,7 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) { } // generic type, call binary_op(MP_BINARY_OP_EQUAL) - mp_obj_type_t *type = mp_obj_get_type(o1); + const mp_obj_type_t *type = mp_obj_get_type(o1); if (type->binary_op != NULL) { mp_obj_t r = type->binary_op(MP_BINARY_OP_EQUAL, o1, o2); if (r != MP_OBJ_NULL) { @@ -451,7 +451,7 @@ mp_obj_t mp_obj_len_maybe(mp_obj_t o_in) { GET_STR_LEN(o_in, l); return MP_OBJ_NEW_SMALL_INT(l); } else { - mp_obj_type_t *type = mp_obj_get_type(o_in); + const mp_obj_type_t *type = mp_obj_get_type(o_in); if (type->unary_op != NULL) { return type->unary_op(MP_UNARY_OP_LEN, o_in); } else { @@ -461,7 +461,7 @@ mp_obj_t mp_obj_len_maybe(mp_obj_t o_in) { } mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) { - mp_obj_type_t *type = mp_obj_get_type(base); + const mp_obj_type_t *type = mp_obj_get_type(base); if (type->subscr != NULL) { mp_obj_t ret = type->subscr(base, index, value); if (ret != MP_OBJ_NULL) { @@ -506,7 +506,7 @@ mp_obj_t mp_identity_getiter(mp_obj_t self, mp_obj_iter_buf_t *iter_buf) { } bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags) { - mp_obj_type_t *type = mp_obj_get_type(obj); + const mp_obj_type_t *type = mp_obj_get_type(obj); if (type->buffer_p.get_buffer == NULL) { return false; } diff --git a/py/obj.h b/py/obj.h index f144474917..d98a0470da 100644 --- a/py/obj.h +++ b/py/obj.h @@ -669,7 +669,7 @@ mp_obj_t mp_obj_new_getitem_iter(mp_obj_t *args, mp_obj_iter_buf_t *iter_buf); mp_obj_t mp_obj_new_module(qstr module_name); mp_obj_t mp_obj_new_memoryview(byte typecode, size_t nitems, void *items); -mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in); +const mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in); const char *mp_obj_get_type_str(mp_const_obj_t o_in); bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo); // arguments should be type objects mp_obj_t mp_instance_cast_to_native_base(mp_const_obj_t self_in, mp_const_obj_t native_type); diff --git a/py/objfun.c b/py/objfun.c index 7051f3476d..984d2000a8 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -455,7 +455,7 @@ STATIC mp_uint_t convert_obj_for_inline_asm(mp_obj_t obj) { size_t l; return (mp_uint_t)mp_obj_str_get_data(obj, &l); } else { - mp_obj_type_t *type = mp_obj_get_type(obj); + const mp_obj_type_t *type = mp_obj_get_type(obj); #if MICROPY_PY_BUILTINS_FLOAT if (type == &mp_type_float) { // convert float to int (could also pass in float registers) diff --git a/py/objstr.c b/py/objstr.c index 822c9fc418..454d1cbcc5 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -320,7 +320,7 @@ mp_obj_t mp_obj_str_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i } // from now on we need lhs type and data, so extract them - mp_obj_type_t *lhs_type = mp_obj_get_type(lhs_in); + const mp_obj_type_t *lhs_type = mp_obj_get_type(lhs_in); GET_STR_DATA_LEN(lhs_in, lhs_data, lhs_len); // check for multiply @@ -420,7 +420,7 @@ const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, s // This is used for both bytes and 8-bit strings. This is not used for unicode strings. STATIC mp_obj_t bytes_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { - mp_obj_type_t *type = mp_obj_get_type(self_in); + const mp_obj_type_t *type = mp_obj_get_type(self_in); GET_STR_DATA_LEN(self_in, self_data, self_len); if (value == MP_OBJ_SENTINEL) { // load @@ -1743,7 +1743,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_count_obj, 2, 4, str_count); #if MICROPY_PY_BUILTINS_STR_PARTITION STATIC mp_obj_t str_partitioner(mp_obj_t self_in, mp_obj_t arg, int direction) { mp_check_self(mp_obj_is_str_or_bytes(self_in)); - mp_obj_type_t *self_type = mp_obj_get_type(self_in); + const mp_obj_type_t *self_type = mp_obj_get_type(self_in); if (self_type != mp_obj_get_type(arg)) { bad_implicit_conversion(arg); } diff --git a/py/objstrunicode.c b/py/objstrunicode.c index 5a127243bc..e5a57ab942 100644 --- a/py/objstrunicode.c +++ b/py/objstrunicode.c @@ -176,7 +176,7 @@ const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, s } STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { - mp_obj_type_t *type = mp_obj_get_type(self_in); + const mp_obj_type_t *type = mp_obj_get_type(self_in); assert(type == &mp_type_str); GET_STR_DATA_LEN(self_in, self_data, self_len); if (value == MP_OBJ_SENTINEL) { diff --git a/py/objtuple.c b/py/objtuple.c index 740e0795b3..10a5e586f6 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -105,7 +105,7 @@ STATIC mp_obj_t mp_obj_tuple_make_new(const mp_obj_type_t *type_in, size_t n_arg // Don't pass MP_BINARY_OP_NOT_EQUAL here STATIC mp_obj_t tuple_cmp_helper(mp_uint_t op, mp_obj_t self_in, mp_obj_t another_in) { mp_check_self(mp_obj_is_tuple_compatible(self_in)); - mp_obj_type_t *another_type = mp_obj_get_type(another_in); + const mp_obj_type_t *another_type = mp_obj_get_type(another_in); mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); if (another_type->getiter != mp_obj_tuple_getiter) { // Slow path for user subclasses diff --git a/py/objtype.c b/py/objtype.c index 5d4dd7d2ff..2ea3f1c187 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -897,7 +897,7 @@ mp_obj_t mp_obj_instance_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) if (member[0] == MP_OBJ_NULL) { return MP_OBJ_NULL; } else if (member[0] == MP_OBJ_SENTINEL) { - mp_obj_type_t *type = mp_obj_get_type(self->subobj[0]); + const mp_obj_type_t *type = mp_obj_get_type(self->subobj[0]); if (iter_buf == NULL) { iter_buf = m_new_obj(mp_obj_iter_buf_t); } @@ -919,7 +919,7 @@ STATIC mp_int_t instance_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, }; mp_obj_class_lookup(&lookup, self->base.type); if (member[0] == MP_OBJ_SENTINEL) { - mp_obj_type_t *type = mp_obj_get_type(self->subobj[0]); + const mp_obj_type_t *type = mp_obj_get_type(self->subobj[0]); return type->buffer_p.get_buffer(self->subobj[0], bufinfo, flags); } else { return 1; // object does not support buffer protocol @@ -1393,7 +1393,7 @@ STATIC mp_obj_t mp_builtin_isinstance(mp_obj_t object, mp_obj_t classinfo) { MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_isinstance_obj, mp_builtin_isinstance); mp_obj_t mp_instance_cast_to_native_base(mp_const_obj_t self_in, mp_const_obj_t native_type) { - mp_obj_type_t *self_type = mp_obj_get_type(self_in); + const mp_obj_type_t *self_type = mp_obj_get_type(self_in); if (!mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(self_type), native_type)) { return MP_OBJ_NULL; } diff --git a/py/opmethods.c b/py/opmethods.c index 247fa5bbc8..595cc088ba 100644 --- a/py/opmethods.c +++ b/py/opmethods.c @@ -28,25 +28,25 @@ #include "py/builtin.h" STATIC mp_obj_t op_getitem(mp_obj_t self_in, mp_obj_t key_in) { - mp_obj_type_t *type = mp_obj_get_type(self_in); + const mp_obj_type_t *type = mp_obj_get_type(self_in); return type->subscr(self_in, key_in, MP_OBJ_SENTINEL); } MP_DEFINE_CONST_FUN_OBJ_2(mp_op_getitem_obj, op_getitem); STATIC mp_obj_t op_setitem(mp_obj_t self_in, mp_obj_t key_in, mp_obj_t value_in) { - mp_obj_type_t *type = mp_obj_get_type(self_in); + const mp_obj_type_t *type = mp_obj_get_type(self_in); return type->subscr(self_in, key_in, value_in); } MP_DEFINE_CONST_FUN_OBJ_3(mp_op_setitem_obj, op_setitem); STATIC mp_obj_t op_delitem(mp_obj_t self_in, mp_obj_t key_in) { - mp_obj_type_t *type = mp_obj_get_type(self_in); + const mp_obj_type_t *type = mp_obj_get_type(self_in); return type->subscr(self_in, key_in, MP_OBJ_NULL); } 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); + const mp_obj_type_t *type = mp_obj_get_type(lhs_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 d5511236d4..26b473bbe9 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -276,7 +276,7 @@ mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) { } return MP_OBJ_NEW_SMALL_INT(h); } else { - mp_obj_type_t *type = mp_obj_get_type(arg); + const mp_obj_type_t *type = mp_obj_get_type(arg); if (type->unary_op != NULL) { mp_obj_t result = type->unary_op(op, arg); if (result != MP_OBJ_NULL) { @@ -560,7 +560,7 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { } // generic binary_op supplied by type - mp_obj_type_t *type; + const mp_obj_type_t *type; generic_binary_op: type = mp_obj_get_type(lhs); if (type->binary_op != NULL) { @@ -636,7 +636,7 @@ mp_obj_t mp_call_function_n_kw(mp_obj_t fun_in, size_t n_args, size_t n_kw, cons DEBUG_OP_printf("calling function %p(n_args=" UINT_FMT ", n_kw=" UINT_FMT ", args=%p)\n", fun_in, n_args, n_kw, args); // get the type - mp_obj_type_t *type = mp_obj_get_type(fun_in); + const mp_obj_type_t *type = mp_obj_get_type(fun_in); // do the call if (type->call != NULL) { @@ -1067,7 +1067,7 @@ void mp_load_method_maybe(mp_obj_t obj, qstr attr, mp_obj_t *dest) { dest[1] = MP_OBJ_NULL; // get the type - mp_obj_type_t *type = mp_obj_get_type(obj); + const mp_obj_type_t *type = mp_obj_get_type(obj); // look for built-in names #if MICROPY_CPYTHON_COMPAT @@ -1138,7 +1138,7 @@ void mp_load_method_protected(mp_obj_t obj, qstr attr, mp_obj_t *dest, bool catc 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); + const mp_obj_type_t *type = mp_obj_get_type(base); if (type->attr != NULL) { mp_obj_t dest[2] = {MP_OBJ_SENTINEL, value}; type->attr(base, attr, dest); @@ -1158,7 +1158,7 @@ void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t value) { mp_obj_t mp_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) { assert(o_in); - mp_obj_type_t *type = mp_obj_get_type(o_in); + const mp_obj_type_t *type = mp_obj_get_type(o_in); // Check for native getiter which is the identity. We handle this case explicitly // so we don't unnecessarily allocate any RAM for the iter_buf, which won't be used. @@ -1203,7 +1203,7 @@ mp_obj_t mp_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) { // may return MP_OBJ_STOP_ITERATION as an optimisation instead of raise StopIteration() // may also raise StopIteration() mp_obj_t mp_iternext_allow_raise(mp_obj_t o_in) { - mp_obj_type_t *type = mp_obj_get_type(o_in); + const mp_obj_type_t *type = mp_obj_get_type(o_in); if (type->iternext != NULL) { return type->iternext(o_in); } else { @@ -1228,7 +1228,7 @@ mp_obj_t mp_iternext_allow_raise(mp_obj_t o_in) { // may raise other exceptions mp_obj_t mp_iternext(mp_obj_t o_in) { MP_STACK_CHECK(); // enumerate, filter, map and zip can recursively call mp_iternext - mp_obj_type_t *type = mp_obj_get_type(o_in); + const mp_obj_type_t *type = mp_obj_get_type(o_in); if (type->iternext != NULL) { return type->iternext(o_in); } else { @@ -1263,7 +1263,7 @@ mp_obj_t mp_iternext(mp_obj_t o_in) { // TODO: Unclear what to do with StopIterarion exception here. mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val) { assert((send_value != MP_OBJ_NULL) ^ (throw_value != MP_OBJ_NULL)); - mp_obj_type_t *type = mp_obj_get_type(self_in); + const mp_obj_type_t *type = mp_obj_get_type(self_in); if (type == &mp_type_gen_instance) { return mp_obj_gen_resume(self_in, send_value, throw_value, ret_val); diff --git a/py/sequence.c b/py/sequence.c index 15e925000a..94a9bb9d5f 100644 --- a/py/sequence.c +++ b/py/sequence.c @@ -183,7 +183,7 @@ bool mp_seq_cmp_objs(mp_uint_t op, const mp_obj_t *items1, size_t len1, const mp // Special-case of index() which searches for mp_obj_t mp_obj_t mp_seq_index_obj(const mp_obj_t *items, size_t len, size_t n_args, const mp_obj_t *args) { - mp_obj_type_t *type = mp_obj_get_type(args[0]); + const mp_obj_type_t *type = mp_obj_get_type(args[0]); mp_obj_t value = args[1]; size_t start = 0; size_t stop = len; diff --git a/py/stream.c b/py/stream.c index 762cd0fc08..d795681cbc 100644 --- a/py/stream.c +++ b/py/stream.c @@ -85,7 +85,7 @@ mp_uint_t mp_stream_rw(mp_obj_t stream, void *buf_, mp_uint_t size, int *errcode } const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags) { - mp_obj_type_t *type = mp_obj_get_type(self_in); + const mp_obj_type_t *type = mp_obj_get_type(self_in); const mp_stream_p_t *stream_p = type->protocol; if (stream_p == NULL || ((flags & MP_STREAM_OP_READ) && stream_p->read == NULL) From 7d2ccd027fce61642a3a1177220d7f9c69f371f9 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Wed, 23 Oct 2019 11:56:37 +1100 Subject: [PATCH 1133/1788] py/mkenv.mk: Move usage of 32-bit flags to py.mk. This allows ports/variants to configure MICROPY_FORCE_32BIT after including mkenv.mk, but before py.mk. --- py/mkenv.mk | 5 ----- py/py.mk | 7 +++++++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/py/mkenv.mk b/py/mkenv.mk index 3efeb18164..371d320462 100644 --- a/py/mkenv.mk +++ b/py/mkenv.mk @@ -55,11 +55,6 @@ OBJCOPY = $(CROSS_COMPILE)objcopy SIZE = $(CROSS_COMPILE)size STRIP = $(CROSS_COMPILE)strip AR = $(CROSS_COMPILE)ar -ifeq ($(MICROPY_FORCE_32BIT),1) -CC += -m32 -CXX += -m32 -LD += -m32 -endif MAKE_MANIFEST = $(PYTHON) $(TOP)/tools/makemanifest.py MAKE_FROZEN = $(PYTHON) $(TOP)/tools/make-frozen.py diff --git a/py/py.mk b/py/py.mk index 8c2d3c7b80..09de1962d3 100644 --- a/py/py.mk +++ b/py/py.mk @@ -21,6 +21,13 @@ QSTR_GLOBAL_REQUIREMENTS += $(HEADER_BUILD)/mpversion.h # some code is performance bottleneck and compiled with other optimization options CSUPEROPT = -O3 +# Enable building 32-bit code on 64-bit host. +ifeq ($(MICROPY_FORCE_32BIT),1) +CC += -m32 +CXX += -m32 +LD += -m32 +endif + # External modules written in C. ifneq ($(USER_C_MODULES),) # pre-define USERMOD variables as expanded so that variables are immediate From bd2fff66875ed5adab8ce163a7f2bdafbd0332f9 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Wed, 23 Oct 2019 11:20:07 +1100 Subject: [PATCH 1134/1788] unix: Add build variants, analogous to boards on bare-metal. Invoking "make" will still build the standard "micropython" executable, but other variants are now build using, eg, "make VARIANT=minimal". This follows how bare-metal ports specify a particular board, and allows running any make target (eg clean, test) with any variant. Convenience targets (eg "make coverage") are provided to retain the old behaviour, at least for now. See issue #3043. --- ports/unix/Makefile | 105 +++++++----------- ports/unix/mpconfigport.h | 16 ++- .../coverage/mpconfigvariant.h} | 6 +- .../unix/variants/coverage/mpconfigvariant.mk | 17 +++ .../fast/mpconfigvariant.h} | 3 +- ports/unix/variants/fast/mpconfigvariant.mk | 7 ++ .../freedos/mpconfigvariant.h} | 6 +- .../unix/variants/freedos/mpconfigvariant.mk | 20 ++++ .../minimal/mpconfigvariant.h} | 3 + .../unix/variants/minimal/mpconfigvariant.mk | 14 +++ .../nanbox/mpconfigvariant.h} | 6 +- ports/unix/variants/nanbox/mpconfigvariant.mk | 4 + .../unix/variants/standard/mpconfigvariant.h | 26 +++++ .../unix/variants/standard/mpconfigvariant.mk | 16 +++ 14 files changed, 172 insertions(+), 77 deletions(-) rename ports/unix/{mpconfigport_coverage.h => variants/coverage/mpconfigvariant.h} (94%) create mode 100644 ports/unix/variants/coverage/mpconfigvariant.mk rename ports/unix/{mpconfigport_fast.h => variants/fast/mpconfigvariant.h} (97%) create mode 100644 ports/unix/variants/fast/mpconfigvariant.mk rename ports/unix/{mpconfigport_freedos.h => variants/freedos/mpconfigvariant.h} (94%) create mode 100644 ports/unix/variants/freedos/mpconfigvariant.mk rename ports/unix/{mpconfigport_minimal.h => variants/minimal/mpconfigvariant.h} (98%) create mode 100644 ports/unix/variants/minimal/mpconfigvariant.mk rename ports/unix/{mpconfigport_nanbox.h => variants/nanbox/mpconfigvariant.h} (90%) create mode 100644 ports/unix/variants/nanbox/mpconfigvariant.mk create mode 100644 ports/unix/variants/standard/mpconfigvariant.h create mode 100644 ports/unix/variants/standard/mpconfigvariant.mk diff --git a/ports/unix/Makefile b/ports/unix/Makefile index 2fa1373e73..567b1d5c22 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -1,16 +1,29 @@ --include mpconfigport.mk +# Select the variant to build for. +VARIANT ?= standard + +# If the build directory is not given, make it reflect the variant name. +BUILD ?= build-$(VARIANT) + +VARIANT_DIR ?= variants/$(VARIANT) +ifeq ($(wildcard $(VARIANT_DIR)/.),) +$(error Invalid VARIANT specified: $(VARIANT_DIR)) +endif + include ../../py/mkenv.mk +-include mpconfigport.mk +include $(VARIANT_DIR)/mpconfigvariant.mk # use FROZEN_MANIFEST for new projects, others are legacy FROZEN_MANIFEST ?= manifest.py FROZEN_DIR = FROZEN_MPY_DIR = -# define main target -PROG = micropython +# This should be configured by the mpconfigvariant.mk +PROG ?= micropython # qstr definitions (must come before including py.mk) QSTR_DEFS = qstrdefsport.h +QSTR_GLOBAL_DEPENDENCIES = $(VARIANT_DIR)/mpconfigvariant.h # OS name, for simple autoconfig UNAME_S := $(shell uname -s) @@ -27,7 +40,7 @@ INC += -I$(BUILD) # compiler settings CWARN = -Wall -Werror CWARN += -Wpointer-arith -Wuninitialized -CFLAGS = $(INC) $(CWARN) -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) $(CFLAGS_EXTRA) +CFLAGS = $(INC) $(CWARN) -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) -I$(VARIANT_DIR) $(CFLAGS_EXTRA) # Debugging/Optimization ifdef DEBUG @@ -156,7 +169,8 @@ SRC_C = \ alloc.c \ coverage.c \ fatfs_port.c \ - $(SRC_MOD) + $(SRC_MOD) \ + $(wildcard $(VARIANT_DIR)/*.c) LIB_SRC_C = $(addprefix lib/,\ $(LIB_SRC_C_EXTRA) \ @@ -188,83 +202,42 @@ endif include $(TOP)/py/mkrules.mk -.PHONY: test +.PHONY: test test_full test: $(PROG) $(TOP)/tests/run-tests $(eval DIRNAME=ports/$(notdir $(CURDIR))) cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(PROG) ./run-tests -# install micropython in /usr/local/bin -TARGET = micropython -PREFIX = $(DESTDIR)/usr/local -BINDIR = $(PREFIX)/bin +test_full: $(PROG) $(TOP)/tests/run-tests + $(eval DIRNAME=ports/$(notdir $(CURDIR))) + cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(PROG) ./run-tests + cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(PROG) ./run-tests -d thread + cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(PROG) ./run-tests --emit native + cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(PROG) ./run-tests --via-mpy -d basics float micropython + cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(PROG) ./run-tests --via-mpy --emit native -d basics float micropython + cat $(TOP)/tests/basics/0prelim.py | ./$(PROG) | grep -q 'abc' -install: micropython - install -d $(BINDIR) - install $(TARGET) $(BINDIR)/$(TARGET) +test_gcov: test_full + gcov -o $(BUILD)/py $(TOP)/py/*.c + gcov -o $(BUILD)/extmod $(TOP)/extmod/*.c -# uninstall micropython -uninstall: - -rm $(BINDIR)/$(TARGET) - -# build synthetically fast interpreter for benchmarking +# Maintain historical targets from pre-variant configurations. fast: - $(MAKE) COPT="-O2 -DNDEBUG -fno-crossjumping" CFLAGS_EXTRA='-DMP_CONFIGFILE=""' BUILD=build-fast PROG=micropython_fast FROZEN_MANIFEST= + $(MAKE) VARIANT=fast -# build a minimal interpreter minimal: - $(MAKE) COPT="-Os -DNDEBUG" CFLAGS_EXTRA='-DMP_CONFIGFILE=""' \ - BUILD=build-minimal PROG=micropython_minimal FROZEN_MANIFEST= \ - MICROPY_PY_BTREE=0 MICROPY_PY_FFI=0 MICROPY_PY_SOCKET=0 MICROPY_PY_THREAD=0 \ - MICROPY_PY_TERMIOS=0 MICROPY_PY_USSL=0 \ - MICROPY_USE_READLINE=0 + $(MAKE) VARIANT=minimal -# build interpreter with nan-boxing as object model nanbox: - $(MAKE) \ - CFLAGS_EXTRA='-DMP_CONFIGFILE=""' \ - BUILD=build-nanbox \ - PROG=micropython_nanbox \ - MICROPY_FORCE_32BIT=1 + $(MAKE) VARIANT=nanbox freedos: - $(MAKE) \ - CC=i586-pc-msdosdjgpp-gcc \ - STRIP=i586-pc-msdosdjgpp-strip \ - SIZE=i586-pc-msdosdjgpp-size \ - CFLAGS_EXTRA='-DMP_CONFIGFILE="" -DMICROPY_NLR_SETJMP -Dtgamma=gamma -DMICROPY_EMIT_X86=0 -DMICROPY_NO_ALLOCA=1 -DMICROPY_PY_USELECT_POSIX=0' \ - BUILD=build-freedos \ - PROG=micropython_freedos \ - MICROPY_PY_SOCKET=0 \ - MICROPY_PY_FFI=0 \ - MICROPY_PY_JNI=0 \ - MICROPY_PY_BTREE=0 \ - MICROPY_PY_THREAD=0 \ - MICROPY_PY_USSL=0 + $(MAKE) VARIANT=freedos -# build an interpreter for coverage testing and do the testing coverage: - $(MAKE) \ - 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 \ - -DMICROPY_UNIX_COVERAGE' \ - LDFLAGS_EXTRA='-fprofile-arcs -ftest-coverage' \ - MICROPY_VFS_FAT=1 MICROPY_VFS_LFS1=1 MICROPY_VFS_LFS2=1 \ - FROZEN_MANIFEST=manifest_coverage.py \ - BUILD=build-coverage PROG=micropython_coverage - -coverage_test: coverage - $(eval DIRNAME=ports/$(notdir $(CURDIR))) - cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests - 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 micropython - cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests --via-mpy --emit native -d basics float micropython - 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 + $(MAKE) VARIANT=coverage +coverage_test: + $(MAKE) VARIANT=coverage test_gcov # Value of configure's --host= option (required for cross-compilation). # Deduce it from CROSS_COMPILE by default, but can be overridden. diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h index d633726a16..f435c3ff3c 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -24,7 +24,15 @@ * THE SOFTWARE. */ -// options to control how MicroPython is built +// Options to control how MicroPython is built for this port, +// overriding defaults in py/mpconfig.h. + +// Variant-specific definitions. +#include "mpconfigvariant.h" + +// The minimal variant's config covers everything. +// If we're building the minimal variant, ignore the rest of this file. +#ifndef MICROPY_UNIX_MINIMAL #define MICROPY_ALLOC_PATH_MAX (PATH_MAX) #define MICROPY_PERSISTENT_CODE_LOAD (1) @@ -64,7 +72,9 @@ #define MICROPY_ENABLE_SOURCE_LINE (1) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_DOUBLE) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) +#ifndef MICROPY_STREAMS_NON_BLOCK #define MICROPY_STREAMS_NON_BLOCK (1) +#endif #define MICROPY_STREAMS_POSIX_API (1) #define MICROPY_OPT_COMPUTED_GOTO (1) #ifndef MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE @@ -97,11 +107,13 @@ #define MICROPY_PERSISTENT_CODE_SAVE (1) #define MICROPY_COMP_CONST (0) #endif +#ifndef MICROPY_PY_SYS_PLATFORM #if defined(__APPLE__) && defined(__MACH__) #define MICROPY_PY_SYS_PLATFORM "darwin" #else #define MICROPY_PY_SYS_PLATFORM "linux" #endif +#endif #define MICROPY_PY_SYS_MAXSIZE (1) #define MICROPY_PY_SYS_STDFILES (1) #define MICROPY_PY_SYS_EXC_INFO (1) @@ -331,3 +343,5 @@ void mp_unix_mark_exec(void); // For debugging purposes, make printf() available to any source file. #include #endif + +#endif // MICROPY_UNIX_MINIMAL diff --git a/ports/unix/mpconfigport_coverage.h b/ports/unix/variants/coverage/mpconfigvariant.h similarity index 94% rename from ports/unix/mpconfigport_coverage.h rename to ports/unix/variants/coverage/mpconfigvariant.h index 8a0bf3be48..f383a83700 100644 --- a/ports/unix/mpconfigport_coverage.h +++ b/ports/unix/variants/coverage/mpconfigvariant.h @@ -24,14 +24,12 @@ * THE SOFTWARE. */ -// Default unix config while intended to be comprehensive, may still not enable -// all the features, this config should enable more (testable) options. +// This config enables almost all possible features such that it can be used +// for coverage testing. #define MICROPY_VFS (1) #define MICROPY_PY_UOS_VFS (1) -#include - #define MICROPY_OPT_MATH_FACTORIAL (1) #define MICROPY_FLOAT_HIGH_QUALITY_HASH (1) #define MICROPY_ENABLE_SCHEDULER (1) diff --git a/ports/unix/variants/coverage/mpconfigvariant.mk b/ports/unix/variants/coverage/mpconfigvariant.mk new file mode 100644 index 0000000000..e55b22eb92 --- /dev/null +++ b/ports/unix/variants/coverage/mpconfigvariant.mk @@ -0,0 +1,17 @@ +PROG ?= micropython_coverage + +COPT = -O0 + +CFLAGS_EXTRA += \ + -fprofile-arcs -ftest-coverage \ + -Wdouble-promotion -Wformat -Wmissing-declarations -Wmissing-prototypes -Wsign-compare \ + -Wold-style-definition -Wpointer-arith -Wshadow -Wuninitialized -Wunused-parameter \ + -DMICROPY_UNIX_COVERAGE + +LDFLAGS_EXTRA += -fprofile-arcs -ftest-coverage + +FROZEN_MANIFEST = manifest_coverage.py + +MICROPY_VFS_FAT = 1 +MICROPY_VFS_LFS1 = 1 +MICROPY_VFS_LFS2 = 1 diff --git a/ports/unix/mpconfigport_fast.h b/ports/unix/variants/fast/mpconfigvariant.h similarity index 97% rename from ports/unix/mpconfigport_fast.h rename to ports/unix/variants/fast/mpconfigvariant.h index 193567a294..6d73275fde 100644 --- a/ports/unix/mpconfigport_fast.h +++ b/ports/unix/variants/fast/mpconfigvariant.h @@ -28,8 +28,9 @@ // synthetic benchmarking, at the expense of features supported and memory // usage. This config is not intended to be used in production. -#include #define MICROPY_PY___FILE__ (0) // 91 is a magic number proposed by @dpgeorge, which make pystone run ~ at tie // with CPython 3.4. #define MICROPY_MODULE_DICT_SIZE (91) + +#include "variants/DEV/mpconfigvariant.h" diff --git a/ports/unix/variants/fast/mpconfigvariant.mk b/ports/unix/variants/fast/mpconfigvariant.mk new file mode 100644 index 0000000000..60c1d525d3 --- /dev/null +++ b/ports/unix/variants/fast/mpconfigvariant.mk @@ -0,0 +1,7 @@ +# build synthetically fast interpreter for benchmarking + +COPT = "-O2 -DNDEBUG -fno-crossjumping" + +PROG = micropython_fast + +FROZEN_MANIFEST = diff --git a/ports/unix/mpconfigport_freedos.h b/ports/unix/variants/freedos/mpconfigvariant.h similarity index 94% rename from ports/unix/mpconfigport_freedos.h rename to ports/unix/variants/freedos/mpconfigvariant.h index 09c85ab1e3..338b34492d 100644 --- a/ports/unix/mpconfigport_freedos.h +++ b/ports/unix/variants/freedos/mpconfigvariant.h @@ -26,15 +26,15 @@ // options to control how MicroPython is built -#include +#define MICROPY_PY_USELECT_POSIX (0) -#undef MICROPY_STREAMS_NON_BLOCK #define MICROPY_STREAMS_NON_BLOCK (0) -#undef MICROPY_PY_SYS_PLATFORM #define MICROPY_PY_SYS_PLATFORM "freedos" // djgpp dirent struct does not have d_ino field #undef _DIRENT_HAVE_D_INO #define MICROPY_USE_INTERNAL_ERRNO (1) + +#include "variants/DEV/mpconfigvariant.h" diff --git a/ports/unix/variants/freedos/mpconfigvariant.mk b/ports/unix/variants/freedos/mpconfigvariant.mk new file mode 100644 index 0000000000..f1d0ac21b0 --- /dev/null +++ b/ports/unix/variants/freedos/mpconfigvariant.mk @@ -0,0 +1,20 @@ +CC = i586-pc-msdosdjgpp-gcc + +STRIP = i586-pc-msdosdjgpp-strip + +SIZE = i586-pc-msdosdjgpp-size + +CFLAGS_EXTRA = \ + -DMICROPY_NLR_SETJMP \ + -Dtgamma=gamma \ + -DMICROPY_EMIT_X86=0 \ + -DMICROPY_NO_ALLOCA=1 \ + +PROG = micropython_freedos + +MICROPY_PY_SOCKET = 0 +MICROPY_PY_FFI = 0 +MICROPY_PY_JNI = 0 +MICROPY_PY_BTREE = 0 +MICROPY_PY_THREAD = 0 +MICROPY_PY_USSL = 0 diff --git a/ports/unix/mpconfigport_minimal.h b/ports/unix/variants/minimal/mpconfigvariant.h similarity index 98% rename from ports/unix/mpconfigport_minimal.h rename to ports/unix/variants/minimal/mpconfigvariant.h index c49819e742..e961ff4b24 100644 --- a/ports/unix/mpconfigport_minimal.h +++ b/ports/unix/variants/minimal/mpconfigvariant.h @@ -26,6 +26,9 @@ // options to control how MicroPython is built +// Prevent the rest of the default mpconfigport.h being used. +#define MICROPY_UNIX_MINIMAL (1) + #define MICROPY_ALLOC_QSTR_CHUNK_INIT (64) #define MICROPY_ALLOC_PARSE_RULE_INIT (8) #define MICROPY_ALLOC_PARSE_RULE_INC (8) diff --git a/ports/unix/variants/minimal/mpconfigvariant.mk b/ports/unix/variants/minimal/mpconfigvariant.mk new file mode 100644 index 0000000000..19f8ad64a3 --- /dev/null +++ b/ports/unix/variants/minimal/mpconfigvariant.mk @@ -0,0 +1,14 @@ +# build a minimal interpreter +COPT = -Os -DNDEBUG + +PROG = micropython_minimal + +FROZEN_MANIFEST = + +MICROPY_PY_BTREE = 0 +MICROPY_PY_FFI = 0 +MICROPY_PY_SOCKET = 0 +MICROPY_PY_THREAD = 0 +MICROPY_PY_TERMIOS = 0 +MICROPY_PY_USSL = 0 +MICROPY_USE_READLINE = 0 diff --git a/ports/unix/mpconfigport_nanbox.h b/ports/unix/variants/nanbox/mpconfigvariant.h similarity index 90% rename from ports/unix/mpconfigport_nanbox.h rename to ports/unix/variants/nanbox/mpconfigvariant.h index 7da2cf7b80..f827158fb7 100644 --- a/ports/unix/mpconfigport_nanbox.h +++ b/ports/unix/variants/nanbox/mpconfigvariant.h @@ -24,6 +24,10 @@ * THE SOFTWARE. */ +// This config is mostly used to ensure that the nan-boxing object model +// continues to build (i.e. catches usage of mp_obj_t that don't work with +// this representation). + // select nan-boxing object model #define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_D) @@ -39,5 +43,3 @@ typedef int64_t mp_int_t; typedef uint64_t mp_uint_t; #define UINT_FMT "%llu" #define INT_FMT "%lld" - -#include diff --git a/ports/unix/variants/nanbox/mpconfigvariant.mk b/ports/unix/variants/nanbox/mpconfigvariant.mk new file mode 100644 index 0000000000..b7b485b512 --- /dev/null +++ b/ports/unix/variants/nanbox/mpconfigvariant.mk @@ -0,0 +1,4 @@ +# build interpreter with nan-boxing as object model (object repr D) +PROG = micropython_nanbox + +MICROPY_FORCE_32BIT = 1 diff --git a/ports/unix/variants/standard/mpconfigvariant.h b/ports/unix/variants/standard/mpconfigvariant.h new file mode 100644 index 0000000000..79b8fe2a3b --- /dev/null +++ b/ports/unix/variants/standard/mpconfigvariant.h @@ -0,0 +1,26 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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. + */ + diff --git a/ports/unix/variants/standard/mpconfigvariant.mk b/ports/unix/variants/standard/mpconfigvariant.mk new file mode 100644 index 0000000000..28fad7be77 --- /dev/null +++ b/ports/unix/variants/standard/mpconfigvariant.mk @@ -0,0 +1,16 @@ +# This is the default variant when you `make` the Unix port. + +PROG ?= micropython + +# install micropython in /usr/local/bin +TARGET = micropython +PREFIX = $(DESTDIR)/usr/local +BINDIR = $(PREFIX)/bin + +install: micropython + install -d $(BINDIR) + install $(TARGET) $(BINDIR)/$(TARGET) + +# uninstall micropython +uninstall: + -rm $(BINDIR)/$(TARGET) From 2357338e9341d6b45c1379ff9b6cbc04bf7a9241 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 28 Oct 2019 13:33:06 +1100 Subject: [PATCH 1135/1788] unix: Add placeholder DEV variant with settrace enabled. This will eventually become the "full featured" unix binary with more features enabled, specifically useful for development and testing. --- ports/unix/.gitignore | 1 + ports/unix/variants/dev/mpconfigvariant.h | 27 ++++++++++++++++++++++ ports/unix/variants/dev/mpconfigvariant.mk | 1 + 3 files changed, 29 insertions(+) create mode 100644 ports/unix/variants/dev/mpconfigvariant.h create mode 100644 ports/unix/variants/dev/mpconfigvariant.mk diff --git a/ports/unix/.gitignore b/ports/unix/.gitignore index 7179e7bde4..977690827a 100644 --- a/ports/unix/.gitignore +++ b/ports/unix/.gitignore @@ -1,4 +1,5 @@ micropython +micropython_dev micropython_fast micropython_minimal micropython_coverage diff --git a/ports/unix/variants/dev/mpconfigvariant.h b/ports/unix/variants/dev/mpconfigvariant.h new file mode 100644 index 0000000000..84a3edd454 --- /dev/null +++ b/ports/unix/variants/dev/mpconfigvariant.h @@ -0,0 +1,27 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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. + */ + +#define MICROPY_PY_SYS_SETTRACE (1) diff --git a/ports/unix/variants/dev/mpconfigvariant.mk b/ports/unix/variants/dev/mpconfigvariant.mk new file mode 100644 index 0000000000..3b0f2d8967 --- /dev/null +++ b/ports/unix/variants/dev/mpconfigvariant.mk @@ -0,0 +1 @@ +PROG ?= micropython_dev From 7319d546b70c1ba5a34288728506c05fe4cc712d Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Wed, 23 Oct 2019 13:50:09 +1100 Subject: [PATCH 1136/1788] travis: Update travis to specify which unix variant to build. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 376e7b88e3..55c07bec24 100644 --- a/.travis.yml +++ b/.travis.yml @@ -73,7 +73,7 @@ jobs: - make ${MAKEOPTS} -C mpy-cross - make ${MAKEOPTS} -C ports/unix submodules - make ${MAKEOPTS} -C ports/unix deplibs - - make ${MAKEOPTS} -C ports/unix coverage + - make ${MAKEOPTS} -C ports/unix VARIANT=coverage # run the main test suite - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests) - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests -d thread) @@ -157,7 +157,7 @@ jobs: - make ${MAKEOPTS} -C mpy-cross PYTHON=python2 - make ${MAKEOPTS} -C ports/unix submodules - make ${MAKEOPTS} -C ports/unix PYTHON=python2 deplibs - - make ${MAKEOPTS} -C ports/unix PYTHON=python2 nanbox + - make ${MAKEOPTS} -C ports/unix PYTHON=python2 VARIANT=nanbox - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_nanbox ./run-tests) # unix stackless From 977b532c8fcd1a9e12844dd4f9cc2d70341013d7 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Wed, 30 Oct 2019 17:00:09 +1100 Subject: [PATCH 1137/1788] unix: Rename unix binaries to micropython-variant (not _variant). For consistency with mpy-cross, and other unix tools in general. --- .travis.yml | 32 +++++++++---------- ports/unix/.gitignore | 7 +--- .../unix/variants/coverage/mpconfigvariant.mk | 2 +- ports/unix/variants/dev/mpconfigvariant.mk | 2 +- ports/unix/variants/fast/mpconfigvariant.mk | 2 +- .../unix/variants/freedos/mpconfigvariant.mk | 2 +- .../unix/variants/minimal/mpconfigvariant.mk | 2 +- ports/unix/variants/nanbox/mpconfigvariant.mk | 2 +- tests/run-natmodtests.py | 2 +- 9 files changed, 24 insertions(+), 29 deletions(-) diff --git a/.travis.yml b/.travis.yml index 55c07bec24..9e88ecd8fc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -75,13 +75,13 @@ jobs: - make ${MAKEOPTS} -C ports/unix deplibs - make ${MAKEOPTS} -C ports/unix VARIANT=coverage # run the main test suite - - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests) - - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests -d thread) - - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --emit native) - - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --via-mpy -d basics float micropython) - - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --via-mpy --emit native -d basics float micropython) + - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython-coverage ./run-tests) + - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython-coverage ./run-tests -d thread) + - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython-coverage ./run-tests --emit native) + - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython-coverage ./run-tests --via-mpy -d basics float micropython) + - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython-coverage ./run-tests --via-mpy --emit native -d basics float micropython) # test when input script comes from stdin - - cat tests/basics/0prelim.py | ports/unix/micropython_coverage | grep -q 'abc' + - cat tests/basics/0prelim.py | ports/unix/micropython-coverage | grep -q 'abc' # test building native mpy modules - make -C examples/natmod/features1 ARCH=x64 - make -C examples/natmod/features2 ARCH=x64 @@ -92,7 +92,7 @@ jobs: - make -C examples/natmod/ure ARCH=x64 - make -C examples/natmod/uzlib ARCH=x64 # test importing .mpy generated by mpy_ld.py - - MICROPYPATH=examples/natmod/features2 ./ports/unix/micropython_coverage -m features2 + - MICROPYPATH=examples/natmod/features2 ./ports/unix/micropython-coverage -m features2 - (cd tests && ./run-natmodtests.py extmod/{btree*,framebuf*,uheapq*,ure*,uzlib*}.py) # 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) @@ -115,13 +115,13 @@ jobs: - make ${MAKEOPTS} -C ports/unix MICROPY_FORCE_32BIT=1 deplibs - make ${MAKEOPTS} -C ports/unix MICROPY_FORCE_32BIT=1 coverage # run the main test suite - - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests) - - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests -d thread) - - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --emit native) - - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --via-mpy --mpy-cross-flags='-mcache-lookup-bc -march=x86' -d basics float micropython) - - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --via-mpy --emit native --mpy-cross-flags='-mcache-lookup-bc -march=x86' -d basics float micropython) + - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython-coverage ./run-tests) + - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython-coverage ./run-tests -d thread) + - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython-coverage ./run-tests --emit native) + - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython-coverage ./run-tests --via-mpy --mpy-cross-flags='-mcache-lookup-bc -march=x86' -d basics float micropython) + - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython-coverage ./run-tests --via-mpy --emit native --mpy-cross-flags='-mcache-lookup-bc -march=x86' -d basics float micropython) # test when input script comes from stdin - - cat tests/basics/0prelim.py | ports/unix/micropython_coverage | grep -q 'abc' + - cat tests/basics/0prelim.py | ports/unix/micropython-coverage | grep -q 'abc' # test building native mpy modules - make -C examples/natmod/features1 ARCH=x86 - make -C examples/natmod/features2 ARCH=x86 @@ -132,7 +132,7 @@ jobs: - make -C examples/natmod/ure ARCH=x86 - make -C examples/natmod/uzlib ARCH=x86 # test importing .mpy generated by mpy_ld.py - - MICROPYPATH=examples/natmod/features2 ./ports/unix/micropython_coverage -m features2 + - MICROPYPATH=examples/natmod/features2 ./ports/unix/micropython-coverage -m features2 - (cd tests && ./run-natmodtests.py --arch x86 extmod/{btree*,framebuf*,uheapq*,ure*,uzlib*}.py) after_failure: - (cd tests && for exp in *.exp; do testbase=$(basename $exp .exp); echo -e "\nFAILURE $testbase"; diff -u $testbase.exp $testbase.out; done) @@ -158,7 +158,7 @@ jobs: - make ${MAKEOPTS} -C ports/unix submodules - make ${MAKEOPTS} -C ports/unix PYTHON=python2 deplibs - make ${MAKEOPTS} -C ports/unix PYTHON=python2 VARIANT=nanbox - - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_nanbox ./run-tests) + - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython-nanbox ./run-tests) # unix stackless - stage: test @@ -187,7 +187,7 @@ jobs: env: NAME="minimal unix port build and tests" script: - make ${MAKEOPTS} -C ports/unix minimal - - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_minimal ./run-tests -e exception_chain -e self_type_check -e subclass_native_init -d basics) + - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython-minimal ./run-tests -e exception_chain -e self_type_check -e subclass_native_init -d basics) # windows port via mingw - stage: test diff --git a/ports/unix/.gitignore b/ports/unix/.gitignore index 977690827a..6745218688 100644 --- a/ports/unix/.gitignore +++ b/ports/unix/.gitignore @@ -1,9 +1,4 @@ micropython -micropython_dev -micropython_fast -micropython_minimal -micropython_coverage -micropython_nanbox -micropython_freedos* +micropython-* *.py *.gcov diff --git a/ports/unix/variants/coverage/mpconfigvariant.mk b/ports/unix/variants/coverage/mpconfigvariant.mk index e55b22eb92..077e7e11ac 100644 --- a/ports/unix/variants/coverage/mpconfigvariant.mk +++ b/ports/unix/variants/coverage/mpconfigvariant.mk @@ -1,4 +1,4 @@ -PROG ?= micropython_coverage +PROG ?= micropython-coverage COPT = -O0 diff --git a/ports/unix/variants/dev/mpconfigvariant.mk b/ports/unix/variants/dev/mpconfigvariant.mk index 3b0f2d8967..751a748f6d 100644 --- a/ports/unix/variants/dev/mpconfigvariant.mk +++ b/ports/unix/variants/dev/mpconfigvariant.mk @@ -1 +1 @@ -PROG ?= micropython_dev +PROG ?= micropython-dev diff --git a/ports/unix/variants/fast/mpconfigvariant.mk b/ports/unix/variants/fast/mpconfigvariant.mk index 60c1d525d3..e6022291d9 100644 --- a/ports/unix/variants/fast/mpconfigvariant.mk +++ b/ports/unix/variants/fast/mpconfigvariant.mk @@ -2,6 +2,6 @@ COPT = "-O2 -DNDEBUG -fno-crossjumping" -PROG = micropython_fast +PROG = micropython-fast FROZEN_MANIFEST = diff --git a/ports/unix/variants/freedos/mpconfigvariant.mk b/ports/unix/variants/freedos/mpconfigvariant.mk index f1d0ac21b0..f7e5ed5162 100644 --- a/ports/unix/variants/freedos/mpconfigvariant.mk +++ b/ports/unix/variants/freedos/mpconfigvariant.mk @@ -10,7 +10,7 @@ CFLAGS_EXTRA = \ -DMICROPY_EMIT_X86=0 \ -DMICROPY_NO_ALLOCA=1 \ -PROG = micropython_freedos +PROG = micropython-freedos MICROPY_PY_SOCKET = 0 MICROPY_PY_FFI = 0 diff --git a/ports/unix/variants/minimal/mpconfigvariant.mk b/ports/unix/variants/minimal/mpconfigvariant.mk index 19f8ad64a3..58ee64f83d 100644 --- a/ports/unix/variants/minimal/mpconfigvariant.mk +++ b/ports/unix/variants/minimal/mpconfigvariant.mk @@ -1,7 +1,7 @@ # build a minimal interpreter COPT = -Os -DNDEBUG -PROG = micropython_minimal +PROG = micropython-minimal FROZEN_MANIFEST = diff --git a/ports/unix/variants/nanbox/mpconfigvariant.mk b/ports/unix/variants/nanbox/mpconfigvariant.mk index b7b485b512..9752b922c1 100644 --- a/ports/unix/variants/nanbox/mpconfigvariant.mk +++ b/ports/unix/variants/nanbox/mpconfigvariant.mk @@ -1,4 +1,4 @@ # build interpreter with nan-boxing as object model (object repr D) -PROG = micropython_nanbox +PROG = micropython-nanbox MICROPY_FORCE_32BIT = 1 diff --git a/tests/run-natmodtests.py b/tests/run-natmodtests.py index 3f49a1d68a..46f21f81d7 100755 --- a/tests/run-natmodtests.py +++ b/tests/run-natmodtests.py @@ -14,7 +14,7 @@ import pyboard # Paths for host executables CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python3') -MICROPYTHON = os.getenv('MICROPY_MICROPYTHON', '../ports/unix/micropython_coverage') +MICROPYTHON = os.getenv('MICROPY_MICROPYTHON', '../ports/unix/micropython-coverage') NATMOD_EXAMPLE_DIR = '../examples/natmod/' From bc5c993adfa1cfb888014213fb70ef0e6916f36a Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Mon, 6 Jan 2020 09:48:16 -0800 Subject: [PATCH 1138/1788] docs/README: Add short paragraph about using readthedocs. This adds a short paragraph on how to hook readthedocs.org up. The main goal is to make people aware of the option, to help with contributing to the documentation. --- docs/README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/README.md b/docs/README.md index d524f4b67e..1591911c34 100644 --- a/docs/README.md +++ b/docs/README.md @@ -25,6 +25,21 @@ In `micropython/docs`, build the docs: You'll find the index page at `micropython/docs/build/html/index.html`. +Having readthedocs.org build the documentation +---------------------------------------------- + +If you would like to have docs for forks/branches hosted on GitHub, GitLab or +BitBucket an alternative to building the docs locally is to sign up for a free +https://readthedocs.org account. The rough steps to follow are: +1. sign-up for an account, unless you already have one +2. in your account settings: add GitHub as a connected service (assuming +you have forked this repo on github) +3. in your account projects: import your forked/cloned micropython repository +into readthedocs +4. in the project's versions: add the branches you are developing on or +for which you'd like readthedocs to auto-generate docs whenever you +push a change + PDF manual generation --------------------- From df5c3bd97654c3719a62bb66627b4b538aa04b0f Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Sat, 14 Dec 2019 14:38:15 +0200 Subject: [PATCH 1139/1788] py/unicode: Add unichar_isalnum(). --- py/misc.h | 1 + py/unicode.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/py/misc.h b/py/misc.h index 0aa4a5d2c6..12bf7b38eb 100644 --- a/py/misc.h +++ b/py/misc.h @@ -140,6 +140,7 @@ bool unichar_isprint(unichar c); bool unichar_isdigit(unichar c); bool unichar_isxdigit(unichar c); bool unichar_isident(unichar c); +bool unichar_isalnum(unichar c); bool unichar_isupper(unichar c); bool unichar_islower(unichar c); unichar unichar_tolower(unichar c); diff --git a/py/unicode.c b/py/unicode.c index d69b6f56f0..369240e23c 100644 --- a/py/unicode.c +++ b/py/unicode.c @@ -140,6 +140,10 @@ bool unichar_isident(unichar c) { return c < 128 && ((attr[c] & (FL_ALPHA | FL_DIGIT)) != 0 || c == '_'); } +bool unichar_isalnum(unichar c) { + return c < 128 && ((attr[c] & (FL_ALPHA | FL_DIGIT)) != 0); +} + bool unichar_isupper(unichar c) { return c < 128 && (attr[c] & FL_UPPER) != 0; } From dce590c29dbefea253f4034c4bde3508f205364e Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Tue, 17 Dec 2019 22:40:40 +0200 Subject: [PATCH 1140/1788] lib/mp-readline: Add an assert() to catch buffer overflows. During readline development, this function may receive bad `pos` values. It's easier to understand the assert() failing error than to have a "stack smashing detected" message. --- lib/mp-readline/readline.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/mp-readline/readline.c b/lib/mp-readline/readline.c index 9d254d8cfe..1500873f69 100644 --- a/lib/mp-readline/readline.c +++ b/lib/mp-readline/readline.c @@ -74,6 +74,7 @@ STATIC void mp_hal_move_cursor_back(uint pos) { // snprintf needs space for the terminating null character int n = snprintf(&vt100_command[0], sizeof(vt100_command), "\x1b[%u", pos); if (n > 0) { + assert((unsigned)n < sizeof(vt100_command)); vt100_command[n] = 'D'; // replace null char mp_hal_stdout_tx_strn(vt100_command, n + 1); } From 853aaa06f24c98191a44a38eedd4ec2a0e63d3eb Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Sat, 14 Dec 2019 23:42:03 +0200 Subject: [PATCH 1141/1788] lib/mp-readline: Add word-based move/delete EMACS key sequences. This commit adds backward-word, backward-kill-word, forward-word, forward-kill-word sequences for the REPL, with bindings to Alt+F, Alt+B, Alt+D and Alt+Backspace respectively. It is disabled by default and can be enabled via MICROPY_REPL_EMACS_WORDS_MOVE. Further enabling MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE adds extra bindings for these new sequences: Ctrl+Right, Ctrl+Left and Ctrl+W. The features are enabled on unix micropython-coverage and micropython-dev. --- lib/mp-readline/readline.c | 86 +++++++++++++++++++ lib/mp-readline/readline.h | 1 + .../unix/variants/coverage/mpconfigvariant.h | 2 + ports/unix/variants/dev/mpconfigvariant.h | 3 + py/mpconfig.h | 15 ++++ tests/cmdline/repl_words_move.py | 31 +++++++ tests/cmdline/repl_words_move.py.exp | 47 ++++++++++ tests/feature_check/repl_words_move_check.py | 4 + .../repl_words_move_check.py.exp | 7 ++ tests/run-tests | 7 +- 10 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 tests/cmdline/repl_words_move.py create mode 100644 tests/cmdline/repl_words_move.py.exp create mode 100644 tests/feature_check/repl_words_move_check.py create mode 100644 tests/feature_check/repl_words_move_check.py.exp diff --git a/lib/mp-readline/readline.c b/lib/mp-readline/readline.c index 1500873f69..296c8aa4ab 100644 --- a/lib/mp-readline/readline.c +++ b/lib/mp-readline/readline.c @@ -99,6 +99,35 @@ typedef struct _readline_t { STATIC readline_t rl; +#if MICROPY_REPL_EMACS_WORDS_MOVE +STATIC size_t cursor_count_word(int forward) { + const char *line_buf = vstr_str(rl.line); + size_t pos = rl.cursor_pos; + bool in_word = false; + + for (;;) { + // if moving backwards and we've reached 0... break + if (!forward && pos == 0) { + break; + } + // or if moving forwards and we've reached to the end of line... break + else if (forward && pos == vstr_len(rl.line)) { + break; + } + + if (unichar_isalnum(line_buf[pos + (forward - 1)])) { + in_word = true; + } else if (in_word) { + break; + } + + pos += forward ? forward : -1; + } + + return forward ? pos - rl.cursor_pos : rl.cursor_pos - pos; +} +#endif + int readline_process_char(int c) { size_t last_line_len = rl.line->len; int redraw_step_back = 0; @@ -149,6 +178,10 @@ int readline_process_char(int c) { redraw_step_back = rl.cursor_pos - rl.orig_line_len; redraw_from_cursor = true; #endif + #if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE + } else if (c == CHAR_CTRL_W) { + goto backward_kill_word; + #endif } else if (c == '\r') { // newline mp_hal_stdout_tx_str("\r\n"); @@ -222,9 +255,40 @@ int readline_process_char(int c) { case 'O': rl.escape_seq = ESEQ_ESC_O; break; + #if MICROPY_REPL_EMACS_WORDS_MOVE + case 'b': +#if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE +backward_word: +#endif + redraw_step_back = cursor_count_word(0); + rl.escape_seq = ESEQ_NONE; + break; + case 'f': +#if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE +forward_word: +#endif + redraw_step_forward = cursor_count_word(1); + rl.escape_seq = ESEQ_NONE; + break; + case 'd': + vstr_cut_out_bytes(rl.line, rl.cursor_pos, cursor_count_word(1)); + redraw_from_cursor = true; + rl.escape_seq = ESEQ_NONE; + break; + case 127: +#if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE +backward_kill_word: +#endif + redraw_step_back = cursor_count_word(0); + vstr_cut_out_bytes(rl.line, rl.cursor_pos - redraw_step_back, redraw_step_back); + redraw_from_cursor = true; + rl.escape_seq = ESEQ_NONE; + break; + #endif default: DEBUG_printf("(ESC %d)", c); rl.escape_seq = ESEQ_NONE; + break; } } else if (rl.escape_seq == ESEQ_ESC_BRACKET) { if ('0' <= c && c <= '9') { @@ -312,6 +376,24 @@ delete_key: } else { DEBUG_printf("(ESC [ %c %d)", rl.escape_seq_buf[0], c); } + #if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE + } else if (c == ';' && rl.escape_seq_buf[0] == '1') { + // ';' is used to separate parameters. so first parameter was '1', + // that's used for sequences like ctrl+left, which we will try to parse. + // escape_seq state is reset back to ESEQ_ESC_BRACKET, as if we've just received + // the opening bracket, because more parameters are to come. + // we don't track the parameters themselves to keep low on logic and code size. that + // might be required in the future if more complex sequences are added. + rl.escape_seq = ESEQ_ESC_BRACKET; + // goto away from the state-machine, as rl.escape_seq will be overridden. + goto redraw; + } else if (rl.escape_seq_buf[0] == '5' && c == 'C') { + // ctrl+right + goto forward_word; + } else if (rl.escape_seq_buf[0] == '5' && c == 'D') { + // ctrl+left + goto backward_word; + #endif } else { DEBUG_printf("(ESC [ %c %d)", rl.escape_seq_buf[0], c); } @@ -330,6 +412,10 @@ delete_key: rl.escape_seq = ESEQ_NONE; } +#if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE +redraw: +#endif + // redraw command prompt, efficiently if (redraw_step_back > 0) { mp_hal_move_cursor_back(redraw_step_back); diff --git a/lib/mp-readline/readline.h b/lib/mp-readline/readline.h index 00aa9622a8..a19e1209ab 100644 --- a/lib/mp-readline/readline.h +++ b/lib/mp-readline/readline.h @@ -36,6 +36,7 @@ #define CHAR_CTRL_N (14) #define CHAR_CTRL_P (16) #define CHAR_CTRL_U (21) +#define CHAR_CTRL_W (23) void readline_init0(void); int readline(vstr_t *line, const char *prompt); diff --git a/ports/unix/variants/coverage/mpconfigvariant.h b/ports/unix/variants/coverage/mpconfigvariant.h index f383a83700..7192924534 100644 --- a/ports/unix/variants/coverage/mpconfigvariant.h +++ b/ports/unix/variants/coverage/mpconfigvariant.h @@ -34,6 +34,8 @@ #define MICROPY_FLOAT_HIGH_QUALITY_HASH (1) #define MICROPY_ENABLE_SCHEDULER (1) #define MICROPY_READER_VFS (1) +#define MICROPY_REPL_EMACS_WORDS_MOVE (1) +#define MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE (1) #define MICROPY_WARNINGS_CATEGORY (1) #define MICROPY_MODULE_GETATTR (1) #define MICROPY_PY_DELATTR_SETATTR (1) diff --git a/ports/unix/variants/dev/mpconfigvariant.h b/ports/unix/variants/dev/mpconfigvariant.h index 84a3edd454..2b30970106 100644 --- a/ports/unix/variants/dev/mpconfigvariant.h +++ b/ports/unix/variants/dev/mpconfigvariant.h @@ -24,4 +24,7 @@ * THE SOFTWARE. */ +#define MICROPY_REPL_EMACS_WORDS_MOVE (1) +#define MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE (1) + #define MICROPY_PY_SYS_SETTRACE (1) diff --git a/py/mpconfig.h b/py/mpconfig.h index d6f4d92328..2c4169070d 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -570,6 +570,21 @@ #define MICROPY_REPL_EMACS_KEYS (0) #endif +// Whether to include emacs-style word movement/kill readline behavior in REPL. +// This adds Alt+F, Alt+B, Alt+D and Alt+Backspace for forward-word, backward-word, forward-kill-word +// and backward-kill-word, respectively. +#ifndef MICROPY_REPL_EMACS_WORDS_MOVE +#define MICROPY_REPL_EMACS_WORDS_MOVE (0) +#endif + +// Whether to include extra convenience keys for word movement/kill in readline REPL. +// This adds Ctrl+Right, Ctrl+Left and Ctrl+W for forward-word, backward-word and backward-kill-word +// respectively. Ctrl+Delete is not implemented because it's a very different escape sequence. +// Depends on MICROPY_REPL_EMACS_WORDS_MOVE. +#ifndef MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE +#define MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE (0) +#endif + // Whether to implement auto-indent in REPL #ifndef MICROPY_REPL_AUTO_INDENT #define MICROPY_REPL_AUTO_INDENT (0) diff --git a/tests/cmdline/repl_words_move.py b/tests/cmdline/repl_words_move.py new file mode 100644 index 0000000000..e1eb529535 --- /dev/null +++ b/tests/cmdline/repl_words_move.py @@ -0,0 +1,31 @@ +# word movement +# backward-word, start in word +234b1 +# backward-word, don't start in word +234 b1 +# backward-word on start of line. if cursor is moved, this will result in a SyntaxError +1 2 + 3b+ +# forward-word, start in word +1+2 12+f+3 +# forward-word, don't start in word +1+ 12 3f+ +# forward-word on eol. if cursor is moved, this will result in a SyntaxError +1 + 2 3f+ + +# kill word +# backward-kill-word, start in word +100 + 45623 +# backward-kill-word, don't start in word +100 + 456231 +# forward-kill-word, start in word +100 + 256d3 +# forward-kill-word, don't start in word +1 + 256d2 + +# extra move/kill shortcuts +# ctrl-left +2341 +# ctrl-right +123 +# ctrl-w +1231 diff --git a/tests/cmdline/repl_words_move.py.exp b/tests/cmdline/repl_words_move.py.exp new file mode 100644 index 0000000000..86f6b77889 --- /dev/null +++ b/tests/cmdline/repl_words_move.py.exp @@ -0,0 +1,47 @@ +MicroPython \.\+ version +Use \.\+ +>>> # word movement +>>> # backward-word, start in word +>>> \.\+ +1234 +>>> # backward-word, don't start in word +>>> \.\+ +1234 +>>> # backward-word on start of line. if cursor is moved, this will result in a SyntaxError +>>> \.\+ +6 +>>> # forward-word, start in word +>>> \.\+ +18 +>>> # forward-word, don't start in word +>>> \.\+ +16 +>>> # forward-word on eol. if cursor is moved, this will result in a SyntaxError +>>> \.\+ +6 +>>> +>>> # kill word +>>> # backward-kill-word, start in word +>>> \.\+ +123 +>>> # backward-kill-word, don't start in word +>>> \.\+ +101 +>>> # forward-kill-word, start in word +>>> \.\+ +123 +>>> # forward-kill-word, don't start in word +>>> \.\+ +3 +>>> +>>> # extra move/kill shortcuts +>>> # ctrl-left +>>> \.\+ +1234 +>>> # ctrl-right +>>> \.\+ +123 +>>> # ctrl-w +>>> \.\+ +1 +>>> diff --git a/tests/feature_check/repl_words_move_check.py b/tests/feature_check/repl_words_move_check.py new file mode 100644 index 0000000000..e74615e98c --- /dev/null +++ b/tests/feature_check/repl_words_move_check.py @@ -0,0 +1,4 @@ +# just check if ctrl+w is supported, because it makes sure that +# both MICROPY_REPL_EMACS_WORDS_MOVE and MICROPY_REPL_EXTRA_WORDS_MOVE are enabled. +t = 1231 +t == 1 diff --git a/tests/feature_check/repl_words_move_check.py.exp b/tests/feature_check/repl_words_move_check.py.exp new file mode 100644 index 0000000000..82a4e28ee4 --- /dev/null +++ b/tests/feature_check/repl_words_move_check.py.exp @@ -0,0 +1,7 @@ +MicroPython \.\+ version +Use \.\+ +>>> # Check for emacs keys in REPL +>>> t = \.\+ +>>> t == 2 +True +>>> diff --git a/tests/run-tests b/tests/run-tests index b02463dc37..b8f5b6b7a1 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -284,9 +284,14 @@ def run_tests(pyb, tests, args, base_path="."): # 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'): + if 'True' not in str(t, 'ascii'): skip_tests.add('cmdline/repl_emacs_keys.py') + # Check if words movement in repl is supported, and skip such tests if it's not + t = run_feature_check(pyb, args, base_path, 'repl_words_move_check.py') + if 'True' not in str(t, 'ascii'): + skip_tests.add('cmdline/repl_words_move.py') + upy_byteorder = run_feature_check(pyb, args, base_path, 'byteorder.py') upy_float_precision = run_feature_check(pyb, args, base_path, 'float.py') if upy_float_precision == b'CRASH': From 339d0816c55a0c62ec9be810dd3a58d36b952510 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 9 Jan 2020 16:35:13 -0600 Subject: [PATCH 1142/1788] py/runtime: Move MICROPY_PORT_INIT_FUNC near the end of mp_init(). This moves the MICROPY_PORT_INIT_FUNC hook to the end of mp_init(), just before MP_THREAD_GIL_ENTER(), so that everything (in particular the GIL mutex) is intialized before the hook is called. MICROPY_PORT_DEINIT_FUNC is also moved to be symmetric (but there is no functional change there). If a port needs to perform initialisation earlier than MICROPY_PORT_INIT_FUNC then it can do it before calling mp_init(). --- py/runtime.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/py/runtime.c b/py/runtime.c index 26b473bbe9..db044cf7c4 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -81,11 +81,6 @@ void mp_init(void) { MP_STATE_VM(mp_kbd_exception).args = (mp_obj_tuple_t*)&mp_const_empty_tuple_obj; #endif - // call port specific initialization if any -#ifdef MICROPY_PORT_INIT_FUNC - MICROPY_PORT_INIT_FUNC; -#endif - #if MICROPY_ENABLE_COMPILER // optimization disabled by default MP_STATE_VM(mp_optimise_value) = 0; @@ -140,19 +135,24 @@ void mp_init(void) { mp_thread_mutex_init(&MP_STATE_VM(gil_mutex)); #endif + // call port specific initialization if any + #ifdef MICROPY_PORT_INIT_FUNC + MICROPY_PORT_INIT_FUNC; + #endif + MP_THREAD_GIL_ENTER(); } void mp_deinit(void) { MP_THREAD_GIL_EXIT(); + // call port specific deinitialization if any + #ifdef MICROPY_PORT_DEINIT_FUNC + MICROPY_PORT_DEINIT_FUNC; + #endif + //mp_obj_dict_free(&dict_main); //mp_map_deinit(&MP_STATE_VM(mp_loaded_modules_map)); - - // call port specific deinitialization if any -#ifdef MICROPY_PORT_DEINIT_FUNC - MICROPY_PORT_DEINIT_FUNC; -#endif } mp_obj_t mp_load_name(qstr qst) { From 1caede927ab946e989946d78878934a15ed3d487 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Thu, 9 Jan 2020 17:22:03 -0800 Subject: [PATCH 1143/1788] docs/library/machine: Document machine.soft_reset() function. --- docs/library/machine.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/library/machine.rst b/docs/library/machine.rst index 8cc5efe593..747270d936 100644 --- a/docs/library/machine.rst +++ b/docs/library/machine.rst @@ -27,6 +27,12 @@ Reset related functions Resets the device in a manner similar to pushing the external RESET button. +.. function:: soft_reset() + + Performs a soft reset of the interpreter, deleting all Python objects and + resetting the Python heap. It tries to retain the method by which the user + is connected to the MicroPython REPL (eg serial, USB, Wifi). + .. function:: reset_cause() Get the reset cause. See :ref:`constants ` for the possible return values. From 6632dd3981cbdca8e70c0bf19e36338101e9ce0e Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Thu, 9 Jan 2020 17:43:28 -0800 Subject: [PATCH 1144/1788] esp32/modmachine: Add implementation of machine.soft_reset(). --- ports/esp32/modmachine.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ports/esp32/modmachine.c b/ports/esp32/modmachine.c index e722ed2c5b..6e0d0593af 100644 --- a/ports/esp32/modmachine.c +++ b/ports/esp32/modmachine.c @@ -46,6 +46,7 @@ #include "py/obj.h" #include "py/runtime.h" +#include "lib/utils/pyexec.h" #include "extmod/machine_mem.h" #include "extmod/machine_signal.h" #include "extmod/machine_pulse.h" @@ -193,6 +194,12 @@ STATIC mp_obj_t machine_reset(void) { } STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset); +STATIC mp_obj_t machine_soft_reset(void) { + pyexec_system_exit = PYEXEC_FORCED_EXIT; + nlr_raise(mp_obj_new_exception(&mp_type_SystemExit)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_soft_reset_obj, machine_soft_reset); + STATIC mp_obj_t machine_unique_id(void) { uint8_t chipid[6]; esp_efuse_mac_get_default(chipid); @@ -228,6 +235,7 @@ 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_soft_reset), MP_ROM_PTR(&machine_soft_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_lightsleep_obj) }, { MP_ROM_QSTR(MP_QSTR_lightsleep), MP_ROM_PTR(&machine_lightsleep_obj) }, From 7ef2f65114f092be6303c145a2560fdf522dcde0 Mon Sep 17 00:00:00 2001 From: Jason Neal Date: Sat, 11 Jan 2020 19:44:17 +1300 Subject: [PATCH 1145/1788] docs/library: Add / to indicate positional-only args in library docs. Removes the confusion of positional-only arguments which have defaults that look like keyword arguments. --- docs/library/btree.rst | 2 +- docs/library/esp.rst | 2 +- docs/library/framebuf.rst | 2 +- docs/library/machine.rst | 2 +- docs/library/sys.rst | 4 ++-- docs/library/ubluetooth.rst | 6 +++--- docs/library/uctypes.rst | 4 ++-- docs/library/uos.rst | 2 +- docs/library/ure.rst | 6 +++--- docs/library/uselect.rst | 4 ++-- docs/library/usocket.rst | 6 +++--- docs/library/ustruct.rst | 2 +- docs/library/uzlib.rst | 4 ++-- 13 files changed, 23 insertions(+), 23 deletions(-) diff --git a/docs/library/btree.rst b/docs/library/btree.rst index 3578acd8fd..a1f7a5420f 100644 --- a/docs/library/btree.rst +++ b/docs/library/btree.rst @@ -116,7 +116,7 @@ Methods Flush any data in cache to the underlying stream. .. method:: btree.__getitem__(key) - btree.get(key, default=None) + btree.get(key, default=None, /) btree.__setitem__(key, val) btree.__detitem__(key) btree.__contains__(key) diff --git a/docs/library/esp.rst b/docs/library/esp.rst index 867182be99..cb2bc7af8d 100644 --- a/docs/library/esp.rst +++ b/docs/library/esp.rst @@ -31,7 +31,7 @@ Functions The system enters the set sleep mode automatically when possible. -.. function:: deepsleep(time=0) +.. function:: deepsleep(time=0, /) **Note**: ESP8266 only - use `machine.deepsleep()` on ESP32 diff --git a/docs/library/framebuf.rst b/docs/library/framebuf.rst index 1ff56e4dae..43ff0b6e1b 100644 --- a/docs/library/framebuf.rst +++ b/docs/library/framebuf.rst @@ -28,7 +28,7 @@ For example:: Constructors ------------ -.. class:: FrameBuffer(buffer, width, height, format, stride=width) +.. class:: FrameBuffer(buffer, width, height, format, stride=width, /) Construct a FrameBuffer object. The parameters are: diff --git a/docs/library/machine.rst b/docs/library/machine.rst index 747270d936..b580353d6b 100644 --- a/docs/library/machine.rst +++ b/docs/library/machine.rst @@ -111,7 +111,7 @@ Miscellaneous functions varies by hardware (so use substring of a full value if you expect a short ID). In some MicroPython ports, ID corresponds to the network MAC address. -.. function:: time_pulse_us(pin, pulse_level, timeout_us=1000000) +.. function:: time_pulse_us(pin, pulse_level, timeout_us=1000000, /) Time a pulse on the given *pin*, and return the duration of the pulse in microseconds. The *pulse_level* argument should be 0 to time a low pulse diff --git a/docs/library/sys.rst b/docs/library/sys.rst index d3cc308d89..24f9e353bb 100644 --- a/docs/library/sys.rst +++ b/docs/library/sys.rst @@ -9,7 +9,7 @@ Functions --------- -.. function:: exit(retval=0) +.. function:: exit(retval=0, /) Terminate current program with a given exit code. Underlyingly, this function raise as `SystemExit` exception. If an argument is given, its @@ -28,7 +28,7 @@ Functions This function is a MicroPython extension intended to provide similar functionality to the :mod:`atexit` module in CPython. -.. function:: print_exception(exc, file=sys.stdout) +.. function:: print_exception(exc, file=sys.stdout, /) Print exception with a traceback to a file-like object *file* (or `sys.stdout` by default). diff --git a/docs/library/ubluetooth.rst b/docs/library/ubluetooth.rst index 1a62d1e4ba..e3f4e13828 100644 --- a/docs/library/ubluetooth.rst +++ b/docs/library/ubluetooth.rst @@ -268,7 +268,7 @@ writes from a central to a given characteristic, use of the notification, avoiding the need for a separate read request. Note that this will not update the local value stored. -.. method:: BLE.gatts_set_buffer(value_handle, len, append=False) +.. method:: BLE.gatts_set_buffer(value_handle, len, append=False, /) Sets the internal buffer size for a value in bytes. This will limit the largest possible write that can be received. The default is 20. @@ -283,7 +283,7 @@ writes from a central to a given characteristic, use Central Role (GATT Client) -------------------------- -.. method:: BLE.gap_connect(addr_type, addr, scan_duration_ms=2000) +.. method:: BLE.gap_connect(addr_type, addr, scan_duration_ms=2000, /) Connect to a peripheral. @@ -326,7 +326,7 @@ Central Role (GATT Client) On success, the ``_IRQ_GATTC_READ_RESULT`` event will be raised. -.. method:: BLE.gattc_write(conn_handle, value_handle, data, mode=0) +.. method:: BLE.gattc_write(conn_handle, value_handle, data, mode=0, /) Issue a remote write to a connected peripheral for the specified characteristic or descriptor handle. diff --git a/docs/library/uctypes.rst b/docs/library/uctypes.rst index dce8caecb6..0fdc40e484 100644 --- a/docs/library/uctypes.rst +++ b/docs/library/uctypes.rst @@ -180,7 +180,7 @@ Following are encoding examples for various field types: Module contents --------------- -.. class:: struct(addr, descriptor, layout_type=NATIVE) +.. class:: struct(addr, descriptor, layout_type=NATIVE, /) Instantiate a "foreign data structure" object based on structure address in memory, descriptor (encoded as a dictionary), and layout type (see below). @@ -200,7 +200,7 @@ Module contents Layout type for a native structure - with data endianness and alignment conforming to the ABI of the system on which MicroPython runs. -.. function:: sizeof(struct, layout_type=NATIVE) +.. function:: sizeof(struct, layout_type=NATIVE, /) Return size of data structure in bytes. The *struct* argument can be either a structure class or a specific instantiated structure object diff --git a/docs/library/uos.rst b/docs/library/uos.rst index bb7e491cce..cbc1f3e915 100644 --- a/docs/library/uos.rst +++ b/docs/library/uos.rst @@ -112,7 +112,7 @@ Filesystem access Terminal redirection and duplication ------------------------------------ -.. function:: dupterm(stream_object, index=0) +.. function:: dupterm(stream_object, index=0, /) Duplicate or switch the MicroPython terminal (the REPL) on the given `stream`-like object. The *stream_object* argument must be a native stream object, or derive diff --git a/docs/library/ure.rst b/docs/library/ure.rst index ac5f02f9e8..ca5f35b703 100644 --- a/docs/library/ure.rst +++ b/docs/library/ure.rst @@ -124,7 +124,7 @@ Functions string for first position which matches regex (which still may be 0 if regex is anchored). -.. function:: sub(regex_str, replace, string, count=0, flags=0) +.. function:: sub(regex_str, replace, string, count=0, flags=0, /) Compile *regex_str* and search for it in *string*, replacing all matches with *replace*, and returning the new string. @@ -156,14 +156,14 @@ Compiled regular expression. Instances of this class are created using .. method:: regex.match(string) regex.search(string) - regex.sub(replace, string, count=0, flags=0) + regex.sub(replace, string, count=0, flags=0, /) Similar to the module-level functions :meth:`match`, :meth:`search` and :meth:`sub`. Using methods is (much) more efficient if the same regex is applied to multiple strings. -.. method:: regex.split(string, max_split=-1) +.. method:: regex.split(string, max_split=-1, /) Split a *string* using regex. If *max_split* is given, it specifies maximum number of splits to perform. Returns list of strings (there diff --git a/docs/library/uselect.rst b/docs/library/uselect.rst index e1becc60ea..0c3bdfdfd9 100644 --- a/docs/library/uselect.rst +++ b/docs/library/uselect.rst @@ -58,7 +58,7 @@ Methods Modify the *eventmask* for *obj*. If *obj* is not registered, `OSError` is raised with error of ENOENT. -.. method:: poll.poll(timeout=-1) +.. method:: poll.poll(timeout=-1, /) Wait for at least one of the registered objects to become ready or have an exceptional condition, with optional timeout in milliseconds (if *timeout* @@ -81,7 +81,7 @@ Methods Tuples returned may contain more than 2 elements as described above. -.. method:: poll.ipoll(timeout=-1, flags=0) +.. method:: poll.ipoll(timeout=-1, flags=0, /) Like :meth:`poll.poll`, but instead returns an iterator which yields a `callee-owned tuple`. This function provides an efficient, allocation-free diff --git a/docs/library/usocket.rst b/docs/library/usocket.rst index 461e37b353..e3b9d279a0 100644 --- a/docs/library/usocket.rst +++ b/docs/library/usocket.rst @@ -66,7 +66,7 @@ Tuple address format for ``socket`` module: Functions --------- -.. function:: socket(af=AF_INET, type=SOCK_STREAM, proto=IPPROTO_TCP) +.. function:: socket(af=AF_INET, type=SOCK_STREAM, proto=IPPROTO_TCP, /) Create a new socket using the given address family, socket type and protocol number. Note that specifying *proto* in most cases is not @@ -79,7 +79,7 @@ Functions # Create DGRAM UDP socket socket(AF_INET, SOCK_DGRAM) -.. function:: getaddrinfo(host, port, af=0, type=0, proto=0, flags=0) +.. function:: getaddrinfo(host, port, af=0, type=0, proto=0, flags=0, /) Translate the host/port argument into a sequence of 5-tuples that contain all the necessary arguments for creating a socket connected to that service. Arguments @@ -293,7 +293,7 @@ Methods * ``sock.setblocking(True)`` is equivalent to ``sock.settimeout(None)`` * ``sock.setblocking(False)`` is equivalent to ``sock.settimeout(0)`` -.. method:: socket.makefile(mode='rb', buffering=0) +.. method:: socket.makefile(mode='rb', buffering=0, /) Return a file object associated with the socket. The exact returned type depends on the arguments given to makefile(). The support is limited to binary modes only ('rb', 'wb', and 'rwb'). diff --git a/docs/library/ustruct.rst b/docs/library/ustruct.rst index 81915d0a8d..357d622b2b 100644 --- a/docs/library/ustruct.rst +++ b/docs/library/ustruct.rst @@ -35,7 +35,7 @@ Functions Unpack from the *data* according to the format string *fmt*. The return value is a tuple of the unpacked values. -.. function:: unpack_from(fmt, data, offset=0) +.. function:: unpack_from(fmt, data, offset=0, /) Unpack from the *data* starting at *offset* according to the format string *fmt*. *offset* may be negative to count from the end of *buffer*. The return diff --git a/docs/library/uzlib.rst b/docs/library/uzlib.rst index 0b399f228a..d40c46145a 100644 --- a/docs/library/uzlib.rst +++ b/docs/library/uzlib.rst @@ -14,7 +14,7 @@ is not yet implemented. Functions --------- -.. function:: decompress(data, wbits=0, bufsize=0) +.. function:: decompress(data, wbits=0, bufsize=0, /) Return decompressed *data* as bytes. *wbits* is DEFLATE dictionary window size used during compression (8-15, the dictionary size is power of 2 of @@ -23,7 +23,7 @@ Functions to be raw DEFLATE stream. *bufsize* parameter is for compatibility with CPython and is ignored. -.. class:: DecompIO(stream, wbits=0) +.. class:: DecompIO(stream, wbits=0, /) Create a `stream` wrapper which allows transparent decompression of compressed data in another *stream*. This allows to process compressed From ecdb30ea64af18bad44439b6718ddd5b26e7b3f9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 16 Dec 2019 15:42:59 +1100 Subject: [PATCH 1146/1788] py/nativeglue: Use mp_const_X instead of &mp_const_X_obj. --- py/nativeglue.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/py/nativeglue.c b/py/nativeglue.c index 1a7f92f945..9be7449d20 100644 --- a/py/nativeglue.c +++ b/py/nativeglue.c @@ -255,9 +255,9 @@ STATIC double mp_obj_get_float_to_d(mp_obj_t o) { // these must correspond to the respective enum in runtime0.h const mp_fun_table_t mp_fun_table = { - &mp_const_none_obj, - &mp_const_false_obj, - &mp_const_true_obj, + mp_const_none, + mp_const_false, + mp_const_true, mp_native_from_obj, mp_native_to_obj, mp_native_swap_globals, From 6f0c83f6e186eb163c4209f211ab1c959d255e81 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 8 Jan 2020 23:58:40 +1100 Subject: [PATCH 1147/1788] py/obj.h: Redefine qstr object encoding to add immediate obj encoding. This commit adjusts the definition of qstr encoding in all object representations by taking a single bit from the qstr space and using it to distinguish between qstrs and a new kind of literal object: immediate objects. In other words, the qstr space is divided in two pieces, one half for qstrs and the other half for immediate objects. There is still enough room for qstr values (29 bits in representation A on a 32-bit architecture, and 19 bits in representation C) and the new immediate objects can be used for things like None, False and True. --- py/mpconfig.h | 14 +++++++++----- py/obj.h | 38 +++++++++++++++++++++++++++++--------- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/py/mpconfig.h b/py/mpconfig.h index 2c4169070d..d4a9f3c50c 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -70,25 +70,28 @@ // A MicroPython object is a machine word having the following form: // - xxxx...xxx1 : a small int, bits 1 and above are the value -// - xxxx...xx10 : a qstr, bits 2 and above are the value +// - xxxx...x010 : a qstr, bits 3 and above are the value +// - xxxx...x110 : an immediate object, bits 3 and above are the value // - xxxx...xx00 : a pointer to an mp_obj_base_t (unless a fake object) #define MICROPY_OBJ_REPR_A (0) // A MicroPython object is a machine word having the following form: // - xxxx...xx01 : a small int, bits 2 and above are the value -// - xxxx...xx11 : a qstr, bits 2 and above are the value +// - xxxx...x011 : a qstr, bits 3 and above are the value +// - xxxx...x111 : an immediate object, bits 3 and above are the value // - xxxx...xxx0 : a pointer to an mp_obj_base_t (unless a fake object) #define MICROPY_OBJ_REPR_B (1) // A MicroPython object is a machine word having the following form (called R): // - iiiiiiii iiiiiiii iiiiiiii iiiiiii1 small int with 31-bit signed value -// - 01111111 1qqqqqqq qqqqqqqq qqqqq110 str with 20-bit qstr value +// - 01111111 1qqqqqqq qqqqqqqq qqqq0110 str with 19-bit qstr value +// - 01111111 10000000 00000000 ssss1110 immediate object with 4-bit value // - s1111111 10000000 00000000 00000010 +/- inf // - s1111111 1xxxxxxx xxxxxxxx xxxxx010 nan, x != 0 // - seeeeeee efffffff ffffffff ffffff10 30-bit fp, e != 0xff // - pppppppp pppppppp pppppppp pppppp00 ptr (4 byte alignment) -// Str and float stored as O = R + 0x80800000, retrieved as R = O - 0x80800000. -// This makes strs easier to encode/decode as they have zeros in the top 9 bits. +// Str, immediate and float stored as O = R + 0x80800000, retrieved as R = O - 0x80800000. +// This makes strs/immediates easier to encode/decode as they have zeros in the top 9 bits. // This scheme only works with 32-bit word size and float enabled. #define MICROPY_OBJ_REPR_C (2) @@ -98,6 +101,7 @@ // - 01111111 11111000 00000000 00000000 00000000 00000000 00000000 00000000 normalised nan // - 01111111 11111101 iiiiiiii iiiiiiii iiiiiiii iiiiiiii iiiiiiii iiiiiii1 small int // - 01111111 11111110 00000000 00000000 qqqqqqqq qqqqqqqq qqqqqqqq qqqqqqq1 str +// - 01111111 11111111 ss000000 00000000 00000000 00000000 00000000 00000000 immediate object // - 01111111 11111100 00000000 00000000 pppppppp pppppppp pppppppp pppppp00 ptr (4 byte alignment) // Stored as O = R + 0x8004000000000000, retrieved as R = O - 0x8004000000000000. // This makes pointers have all zeros in the top 32 bits. diff --git a/py/obj.h b/py/obj.h index d98a0470da..f0bb44a403 100644 --- a/py/obj.h +++ b/py/obj.h @@ -87,9 +87,14 @@ static inline bool mp_obj_is_small_int(mp_const_obj_t o) #define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 1) | 1)) static inline bool mp_obj_is_qstr(mp_const_obj_t o) - { return ((((mp_int_t)(o)) & 3) == 2); } -#define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 2) -#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 2) | 2)) + { return ((((mp_int_t)(o)) & 7) == 2); } +#define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 3) +#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 3) | 2)) + +static inline bool mp_obj_is_immediate_obj(mp_const_obj_t o) + { return ((((mp_int_t)(o)) & 7) == 6); } +#define MP_OBJ_IMMEDIATE_OBJ_VALUE(o) (((mp_uint_t)(o)) >> 3) +#define MP_OBJ_NEW_IMMEDIATE_OBJ(val) ((mp_obj_t)(((val) << 3) | 6)) #if MICROPY_PY_BUILTINS_FLOAT #define mp_const_float_e MP_ROM_PTR(&mp_const_float_e_obj) @@ -113,9 +118,14 @@ static inline bool mp_obj_is_small_int(mp_const_obj_t o) #define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 2) | 1)) static inline bool mp_obj_is_qstr(mp_const_obj_t o) - { return ((((mp_int_t)(o)) & 3) == 3); } -#define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 2) -#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 2) | 3)) + { return ((((mp_int_t)(o)) & 7) == 3); } +#define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 3) +#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 3) | 3)) + +static inline bool mp_obj_is_immediate_obj(mp_const_obj_t o) + { return ((((mp_int_t)(o)) & 7) == 7); } +#define MP_OBJ_IMMEDIATE_OBJ_VALUE(o) (((mp_uint_t)(o)) >> 3) +#define MP_OBJ_NEW_IMMEDIATE_OBJ(val) ((mp_obj_t)(((val) << 3) | 7)) #if MICROPY_PY_BUILTINS_FLOAT #define mp_const_float_e MP_ROM_PTR(&mp_const_float_e_obj) @@ -161,9 +171,14 @@ static inline mp_obj_t mp_obj_new_float(mp_float_t f) { #endif static inline bool mp_obj_is_qstr(mp_const_obj_t o) - { return (((mp_uint_t)(o)) & 0xff800007) == 0x00000006; } -#define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 3) -#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 3) | 0x00000006)) + { return (((mp_uint_t)(o)) & 0xff80000f) == 0x00000006; } +#define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 4) +#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 4) | 0x00000006)) + +static inline bool mp_obj_is_immediate_obj(mp_const_obj_t o) + { return (((mp_uint_t)(o)) & 0xff80000f) == 0x0000000e; } +#define MP_OBJ_IMMEDIATE_OBJ_VALUE(o) (((mp_uint_t)(o)) >> 4) +#define MP_OBJ_NEW_IMMEDIATE_OBJ(val) ((mp_obj_t)(((val) << 4) | 0xe)) static inline bool mp_obj_is_obj(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 3) == 0); } @@ -180,6 +195,11 @@ static inline bool mp_obj_is_qstr(mp_const_obj_t o) #define MP_OBJ_QSTR_VALUE(o) ((((uint32_t)(o)) >> 1) & 0xffffffff) #define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)(((uint64_t)(((uint32_t)(qst)) << 1)) | 0x0002000000000001)) +static inline bool mp_obj_is_immediate_obj(mp_const_obj_t o) + { return ((((uint64_t)(o)) & 0xffff000000000000) == 0x0003000000000000); } +#define MP_OBJ_IMMEDIATE_OBJ_VALUE(o) ((((uint32_t)(o)) >> 46) & 3) +#define MP_OBJ_NEW_IMMEDIATE_OBJ(val) (((uint64_t)(val) << 46) | 0x0003000000000000) + #if MICROPY_PY_BUILTINS_FLOAT #if MICROPY_FLOAT_IMPL != MICROPY_FLOAT_IMPL_DOUBLE From d96cfd13e3a464862cecffb2718c6286b52c77b0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 9 Jan 2020 00:00:27 +1100 Subject: [PATCH 1148/1788] py/obj: Add MICROPY_OBJ_IMMEDIATE_OBJS option to reduce code size. This option (enabled by default for object representation A, B, C) makes None/False/True objects immediate objects, ie they are no longer a concrete object in ROM but are rather just values, eg None=0x6 for representation A. Doing this saves a considerable amount of code size, due to these objects being widely used: bare-arm: -392 -0.591% minimal x86: -252 -0.170% [incl +52(data)] unix x64: -624 -0.125% [incl -128(data)] unix nanbox: +0 +0.000% stm32: -1940 -0.510% PYBV10 cc3200: -1216 -0.659% esp8266: -404 -0.062% GENERIC esp32: -732 -0.064% GENERIC[incl +48(data)] nrf: -988 -0.675% pca10040 samd: -564 -0.556% ADAFRUIT_ITSYBITSY_M4_EXPRESS Thanks go to @Jongy aka Yonatan Goldschmidt for the idea. --- py/mpconfig.h | 7 +++++++ py/obj.c | 5 +++++ py/obj.h | 29 ++++++++++++++++++++++++----- py/objbool.c | 26 +++++++++++++++++++------- py/objnone.c | 4 ++++ 5 files changed, 59 insertions(+), 12 deletions(-) diff --git a/py/mpconfig.h b/py/mpconfig.h index d4a9f3c50c..5601cc2f77 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -113,6 +113,13 @@ #define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_A) #endif +// Whether to encode None/False/True as immediate objects instead of pointers to +// real objects. Reduces code size by a decent amount without hurting +// performance, for all representations except D on some architectures. +#ifndef MICROPY_OBJ_IMMEDIATE_OBJS +#define MICROPY_OBJ_IMMEDIATE_OBJS (MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_D) +#endif + /*****************************************************************************/ /* Memory allocation policy */ diff --git a/py/obj.c b/py/obj.c index f2a8847543..6aacfb9cf2 100644 --- a/py/obj.c +++ b/py/obj.c @@ -46,6 +46,11 @@ const mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in) { } else if (mp_obj_is_float(o_in)) { return &mp_type_float; #endif + #if MICROPY_OBJ_IMMEDIATE_OBJS + } else if (mp_obj_is_immediate_obj(o_in)) { + static const mp_obj_type_t *const types[2] = {&mp_type_NoneType, &mp_type_bool}; + return types[MP_OBJ_IMMEDIATE_OBJ_VALUE(o_in) & 1]; + #endif } else { const mp_obj_base_t *o = MP_OBJ_TO_PTR(o_in); return o->type; diff --git a/py/obj.h b/py/obj.h index f0bb44a403..93433f924d 100644 --- a/py/obj.h +++ b/py/obj.h @@ -263,13 +263,22 @@ typedef union _mp_rom_obj_t { uint64_t u64; struct { const void *lo, *hi; } u32; // Macros to create objects that are stored in ROM. #ifndef MP_ROM_NONE +#if MICROPY_OBJ_IMMEDIATE_OBJS +#define MP_ROM_NONE mp_const_none +#else #define MP_ROM_NONE MP_ROM_PTR(&mp_const_none_obj) #endif +#endif #ifndef MP_ROM_FALSE +#if MICROPY_OBJ_IMMEDIATE_OBJS +#define MP_ROM_FALSE mp_const_false +#define MP_ROM_TRUE mp_const_true +#else #define MP_ROM_FALSE MP_ROM_PTR(&mp_const_false_obj) #define MP_ROM_TRUE MP_ROM_PTR(&mp_const_true_obj) #endif +#endif #ifndef MP_ROM_INT typedef mp_const_obj_t mp_rom_obj_t; @@ -622,17 +631,27 @@ extern const mp_obj_type_t mp_type_ValueError; extern const mp_obj_type_t mp_type_ViperTypeError; extern const mp_obj_type_t mp_type_ZeroDivisionError; -// Constant objects, globally accessible -// The macros are for convenience only +// Constant objects, globally accessible: None, False, True +// These should always be accessed via the below macros. +#if MICROPY_OBJ_IMMEDIATE_OBJS +// None is even while False/True are odd so their types can be distinguished with 1 bit. +#define mp_const_none MP_OBJ_NEW_IMMEDIATE_OBJ(0) +#define mp_const_false MP_OBJ_NEW_IMMEDIATE_OBJ(1) +#define mp_const_true MP_OBJ_NEW_IMMEDIATE_OBJ(3) +#else #define mp_const_none (MP_OBJ_FROM_PTR(&mp_const_none_obj)) #define mp_const_false (MP_OBJ_FROM_PTR(&mp_const_false_obj)) #define mp_const_true (MP_OBJ_FROM_PTR(&mp_const_true_obj)) -#define mp_const_empty_bytes (MP_OBJ_FROM_PTR(&mp_const_empty_bytes_obj)) -#define mp_const_empty_tuple (MP_OBJ_FROM_PTR(&mp_const_empty_tuple_obj)) -#define mp_const_notimplemented (MP_OBJ_FROM_PTR(&mp_const_notimplemented_obj)) extern const struct _mp_obj_none_t mp_const_none_obj; extern const struct _mp_obj_bool_t mp_const_false_obj; extern const struct _mp_obj_bool_t mp_const_true_obj; +#endif + +// Constant objects, globally accessible: b'', (), Ellipsis, NotImplemented, GeneratorExit() +// The below macros are for convenience only. +#define mp_const_empty_bytes (MP_OBJ_FROM_PTR(&mp_const_empty_bytes_obj)) +#define mp_const_empty_tuple (MP_OBJ_FROM_PTR(&mp_const_empty_tuple_obj)) +#define mp_const_notimplemented (MP_OBJ_FROM_PTR(&mp_const_notimplemented_obj)) 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; diff --git a/py/objbool.c b/py/objbool.c index 5755b188e9..4c046ac8f2 100644 --- a/py/objbool.c +++ b/py/objbool.c @@ -28,21 +28,31 @@ #include "py/runtime.h" +#if MICROPY_OBJ_IMMEDIATE_OBJS + +#define BOOL_VALUE(o) ((o) == mp_const_false ? 0 : 1) + +#else + +#define BOOL_VALUE(o) (((mp_obj_bool_t*)MP_OBJ_TO_PTR(o))->value) + typedef struct _mp_obj_bool_t { mp_obj_base_t base; bool value; } mp_obj_bool_t; +#endif + STATIC void bool_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - mp_obj_bool_t *self = MP_OBJ_TO_PTR(self_in); + bool value = BOOL_VALUE(self_in); if (MICROPY_PY_UJSON && kind == PRINT_JSON) { - if (self->value) { + if (value) { mp_print_str(print, "true"); } else { mp_print_str(print, "false"); } } else { - if (self->value) { + if (value) { mp_print_str(print, "True"); } else { mp_print_str(print, "False"); @@ -65,13 +75,13 @@ STATIC mp_obj_t bool_unary_op(mp_unary_op_t op, mp_obj_t o_in) { if (op == MP_UNARY_OP_LEN) { return MP_OBJ_NULL; } - mp_obj_bool_t *self = MP_OBJ_TO_PTR(o_in); - return mp_unary_op(op, MP_OBJ_NEW_SMALL_INT(self->value)); + bool value = BOOL_VALUE(o_in); + return mp_unary_op(op, MP_OBJ_NEW_SMALL_INT(value)); } STATIC mp_obj_t bool_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { - mp_obj_bool_t *self = MP_OBJ_TO_PTR(lhs_in); - return mp_binary_op(op, MP_OBJ_NEW_SMALL_INT(self->value), rhs_in); + bool value = BOOL_VALUE(lhs_in); + return mp_binary_op(op, MP_OBJ_NEW_SMALL_INT(value), rhs_in); } const mp_obj_type_t mp_type_bool = { @@ -83,5 +93,7 @@ const mp_obj_type_t mp_type_bool = { .binary_op = bool_binary_op, }; +#if !MICROPY_OBJ_IMMEDIATE_OBJS const mp_obj_bool_t mp_const_false_obj = {{&mp_type_bool}, false}; const mp_obj_bool_t mp_const_true_obj = {{&mp_type_bool}, true}; +#endif diff --git a/py/objnone.c b/py/objnone.c index da1031835c..271a8543f9 100644 --- a/py/objnone.c +++ b/py/objnone.c @@ -28,9 +28,11 @@ #include "py/obj.h" +#if !MICROPY_OBJ_IMMEDIATE_OBJS typedef struct _mp_obj_none_t { mp_obj_base_t base; } mp_obj_none_t; +#endif STATIC void none_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)self_in; @@ -48,4 +50,6 @@ const mp_obj_type_t mp_type_NoneType = { .unary_op = mp_generic_unary_op, }; +#if !MICROPY_OBJ_IMMEDIATE_OBJS const mp_obj_none_t mp_const_none_obj = {{&mp_type_NoneType}}; +#endif From 40057600b873b2a802de332d251492a762b32011 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 9 Jan 2020 11:19:26 +1100 Subject: [PATCH 1149/1788] py/obj: Optimise mp_obj_get_type for immediate objs with repr A and C. This function is called often and with immediate objects enabled it has more cases, so optimise it for speed. With this optimisation the runtime is now slightly faster with immediate objects enabled than with them disabled. --- py/obj.c | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/py/obj.c b/py/obj.c index 6aacfb9cf2..55754f9be2 100644 --- a/py/obj.c +++ b/py/obj.c @@ -38,11 +38,47 @@ #include "py/stream.h" // for mp_obj_print const mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in) { + #if MICROPY_OBJ_IMMEDIATE_OBJS && MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A + + if (mp_obj_is_obj(o_in)) { + const mp_obj_base_t *o = MP_OBJ_TO_PTR(o_in); + return o->type; + } else { + static const mp_obj_type_t *const types[] = { + NULL, &mp_type_int, &mp_type_str, &mp_type_int, + NULL, &mp_type_int, &mp_type_NoneType, &mp_type_int, + NULL, &mp_type_int, &mp_type_str, &mp_type_int, + NULL, &mp_type_int, &mp_type_bool, &mp_type_int, + }; + return types[(uintptr_t)o_in & 0xf]; + } + + #elif MICROPY_OBJ_IMMEDIATE_OBJS && MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C + + if (mp_obj_is_small_int(o_in)) { + return &mp_type_int; + } else if (mp_obj_is_obj(o_in)) { + const mp_obj_base_t *o = MP_OBJ_TO_PTR(o_in); + return o->type; + #if MICROPY_PY_BUILTINS_FLOAT + } else if ((((mp_uint_t)(o_in)) & 0xff800007) != 0x00000006) { + return &mp_type_float; + #endif + } else { + static const mp_obj_type_t *const types[] = { + &mp_type_str, &mp_type_NoneType, &mp_type_str, &mp_type_bool, + }; + return types[((uintptr_t)o_in >> 3) & 3]; + } + + #else + if (mp_obj_is_small_int(o_in)) { return &mp_type_int; } else if (mp_obj_is_qstr(o_in)) { return &mp_type_str; - #if MICROPY_PY_BUILTINS_FLOAT + #if MICROPY_PY_BUILTINS_FLOAT && ( \ + MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D) } else if (mp_obj_is_float(o_in)) { return &mp_type_float; #endif @@ -55,6 +91,8 @@ const mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in) { const mp_obj_base_t *o = MP_OBJ_TO_PTR(o_in); return o->type; } + + #endif } const char *mp_obj_get_type_str(mp_const_obj_t o_in) { From 1c849d63a86782f006b73a9d570d542cfd18538e Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Sun, 1 Dec 2019 01:10:12 +0200 Subject: [PATCH 1150/1788] py/mpconfig.h: Define BITS_PER_BYTE only if not already defined. It's a common macro that is possibly defined in headers of systems/SDKs MicroPython is embedded into. --- py/mpconfig.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/py/mpconfig.h b/py/mpconfig.h index 5601cc2f77..8e06153a83 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -1468,7 +1468,9 @@ typedef double mp_float_t; #define BYTES_PER_WORD (sizeof(mp_uint_t)) #endif +#ifndef BITS_PER_BYTE #define BITS_PER_BYTE (8) +#endif #define BITS_PER_WORD (BITS_PER_BYTE * BYTES_PER_WORD) // mp_int_t value with most significant bit set #define WORD_MSBIT_HIGH (((mp_uint_t)1) << (BYTES_PER_WORD * 8 - 1)) From 176ab99180a95eeac8794828f2f751a696571bb5 Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Mon, 13 Jan 2020 23:35:07 +0200 Subject: [PATCH 1151/1788] py/objint: Add mp_obj_int_get_uint_checked() helper. Can be used where mp_obj_int_get_checked() will overflow due to the sign-bit solely. This returns an mp_uint_t, so it also verifies the given integer is not negative. Currently implemented only for mpz configurations. --- py/obj.h | 2 ++ py/objint_mpz.c | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/py/obj.h b/py/obj.h index 93433f924d..ba4f4992ff 100644 --- a/py/obj.h +++ b/py/obj.h @@ -748,6 +748,8 @@ void mp_obj_cell_set(mp_obj_t self_in, mp_obj_t obj); mp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in); // Will raise exception if value doesn't fit into mp_int_t mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in); +// Will raise exception if value is negative or doesn't fit into mp_uint_t +mp_uint_t mp_obj_int_get_uint_checked(mp_const_obj_t self_in); // exception #define mp_obj_is_native_exception_instance(o) (mp_obj_get_type(o)->make_new == mp_obj_exception_make_new) diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 121fd03424..2c09d9bd2b 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -411,6 +411,22 @@ mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) { } } +mp_uint_t mp_obj_int_get_uint_checked(mp_const_obj_t self_in) { + if (mp_obj_is_small_int(self_in)) { + if (MP_OBJ_SMALL_INT_VALUE(self_in) >= 0) { + return MP_OBJ_SMALL_INT_VALUE(self_in); + } + } else { + const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); + mp_uint_t value; + if (mpz_as_uint_checked(&self->mpz, &value)) { + return value; + } + } + + mp_raise_msg(&mp_type_OverflowError, "overflow converting long int to machine word"); +} + #if MICROPY_PY_BUILTINS_FLOAT mp_float_t mp_obj_int_as_float_impl(mp_obj_t self_in) { assert(mp_obj_is_type(self_in, &mp_type_int)); From 3448e69c2d6f6f066907005f56bbd26fffb756e9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 14 Jan 2020 23:45:56 +1100 Subject: [PATCH 1152/1788] tests/unix: Add coverage test for new mp_obj_int_get_uint_checked func. --- ports/unix/coverage.c | 23 +++++++++++++++++++++++ tests/unix/extra_coverage.py.exp | 4 ++++ 2 files changed, 27 insertions(+) diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index 6623cb4642..6cd84dc301 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -334,6 +334,29 @@ STATIC mp_obj_t extra_coverage(void) { 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), mp_obj_new_str("abc", 3)); + + // mp_obj_int_get_uint_checked with non-negative small-int + mp_printf(&mp_plat_print, "%d\n", (int)mp_obj_int_get_uint_checked(MP_OBJ_NEW_SMALL_INT(1))); + + // mp_obj_int_get_uint_checked with non-negative big-int + mp_printf(&mp_plat_print, "%d\n", (int)mp_obj_int_get_uint_checked(mp_obj_new_int_from_ll(2))); + + // mp_obj_int_get_uint_checked with negative small-int (should raise exception) + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_int_get_uint_checked(MP_OBJ_NEW_SMALL_INT(-1)); + nlr_pop(); + } else { + mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); + } + + // mp_obj_int_get_uint_checked with negative big-int (should raise exception) + if (nlr_push(&nlr) == 0) { + mp_obj_int_get_uint_checked(mp_obj_new_int_from_ll(-2)); + nlr_pop(); + } else { + mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); + } } // warning diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index 8922f96162..6aa2da31a4 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -54,6 +54,10 @@ data # runtime utils TypeError: unsupported type for __abs__: 'str' TypeError: unsupported types for __divmod__: 'str', 'str' +1 +2 +OverflowError: overflow converting long int to machine word +OverflowError: overflow converting long int to machine word Warning: test # format float ? From 4ab4bf3ec6e891a49a827b659d5d4764a40ee404 Mon Sep 17 00:00:00 2001 From: Memiks Date: Wed, 8 Jan 2020 09:38:20 +0900 Subject: [PATCH 1153/1788] ports: Modify mp_hal_pin_write macro so it can be used as a function. Even though it doesn't return anything it could still be used like a function. Addresses issue #5501. --- ports/nrf/mphalport.h | 2 +- ports/stm32/mboot/mphalport.h | 2 +- ports/stm32/mphalport.h | 2 +- ports/teensy/teensy_hal.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ports/nrf/mphalport.h b/ports/nrf/mphalport.h index b374da403c..23df0c0cf0 100644 --- a/ports/nrf/mphalport.h +++ b/ports/nrf/mphalport.h @@ -65,7 +65,7 @@ const char * nrfx_error_code_lookup(uint32_t err_code); #define mp_hal_pin_high(p) nrf_gpio_pin_set(p->pin) #define mp_hal_pin_low(p) nrf_gpio_pin_clear(p->pin) #define mp_hal_pin_read(p) (nrf_gpio_pin_dir_get(p->pin) == NRF_GPIO_PIN_DIR_OUTPUT) ? nrf_gpio_pin_out_read(p->pin) : nrf_gpio_pin_read(p->pin) -#define mp_hal_pin_write(p, v) do { if (v) { mp_hal_pin_high(p); } else { mp_hal_pin_low(p); } } while (0) +#define mp_hal_pin_write(p, v) ((v) ? mp_hal_pin_high(p) : mp_hal_pin_low(p)) #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_open_drain(p) nrf_gpio_cfg_input(p->pin, NRF_GPIO_PIN_NOPULL) diff --git a/ports/stm32/mboot/mphalport.h b/ports/stm32/mboot/mphalport.h index 86063c4ef2..0c8cb91a68 100644 --- a/ports/stm32/mboot/mphalport.h +++ b/ports/stm32/mboot/mphalport.h @@ -53,7 +53,7 @@ #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) +#define mp_hal_pin_write(p, v) ((v) ? mp_hal_pin_high(p) : mp_hal_pin_low(p)) 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); diff --git a/ports/stm32/mphalport.h b/ports/stm32/mphalport.h index d73ff8bff3..ce3c51f8d6 100644 --- a/ports/stm32/mphalport.h +++ b/ports/stm32/mphalport.h @@ -68,7 +68,7 @@ static inline mp_uint_t mp_hal_ticks_cpu(void) { #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) -#define mp_hal_pin_write(p, v) do { if (v) { mp_hal_pin_high(p); } else { mp_hal_pin_low(p); } } while (0) +#define mp_hal_pin_write(p, v) ((v) ? mp_hal_pin_high(p) : mp_hal_pin_low(p)) 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); diff --git a/ports/teensy/teensy_hal.h b/ports/teensy/teensy_hal.h index aef38a2ad9..f2e66821dd 100644 --- a/ports/teensy/teensy_hal.h +++ b/ports/teensy/teensy_hal.h @@ -125,4 +125,4 @@ struct _pin_obj_t; #define mp_hal_pin_high(p) (((p)->gpio->PSOR) = (p)->pin_mask) #define mp_hal_pin_low(p) (((p)->gpio->PCOR) = (p)->pin_mask) #define mp_hal_pin_read(p) (((p)->gpio->PDIR >> (p)->pin) & 1) -#define mp_hal_pin_write(p, v) do { if (v) { mp_hal_pin_high(p); } else { mp_hal_pin_low(p); } } while (0) +#define mp_hal_pin_write(p, v) ((v) ? mp_hal_pin_high(p) : mp_hal_pin_low(p)) From c14ff6194c224190c7e6787a2bffbdbb495be4b4 Mon Sep 17 00:00:00 2001 From: JensDiemer Date: Thu, 9 Jan 2020 16:33:31 +0100 Subject: [PATCH 1154/1788] esp8266/modules: Fix AttributeError in _boot.py if flash not formatted. Prior to this commit, if the flash filesystem was not formatted then it would error: "AttributeError: 'FlashBdev' object has no attribute 'mount'". That is due to it not being able to detect the filesystem on the block device and just trying to mount the block device directly. This commit fixes the issue by just catching all exceptions. Also it's not needed to try the mount if `flashbdev.bdev` is None. --- ports/esp8266/modules/_boot.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ports/esp8266/modules/_boot.py b/ports/esp8266/modules/_boot.py index 81eb20dd63..4c2aa87fe5 100644 --- a/ports/esp8266/modules/_boot.py +++ b/ports/esp8266/modules/_boot.py @@ -3,11 +3,11 @@ gc.threshold((gc.mem_free() + gc.mem_alloc()) // 4) import uos from flashbdev import bdev -try: - if bdev: +if bdev: + try: uos.mount(bdev, '/') -except OSError: - import inisetup - inisetup.setup() + except: + import inisetup + inisetup.setup() gc.collect() From 3032ae1155db4bd89786f715f5227967d2cb71cf Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 16 Dec 2019 12:36:38 +1100 Subject: [PATCH 1155/1788] esp32: Enable NimBLE support on all builds (IDF 3.3 and 4.0). This commit updates the IDFv3 version to v3.3.1, and enables the "ubluetooth" module by default on IDFv3 builds. --- .travis.yml | 2 +- ports/esp32/Makefile | 63 ++++++++++++++++++++++++++----- ports/esp32/boards/sdkconfig.base | 1 + ports/esp32/boards/sdkconfig.ble | 10 +++++ 4 files changed, 65 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9e88ecd8fc..c785eb47a1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -213,7 +213,7 @@ jobs: - make ${MAKEOPTS} -C mpy-cross # IDF v3 build - git -C esp-idf checkout $(grep "ESPIDF_SUPHASH_V3 :=" ports/esp32/Makefile | cut -d " " -f 3) - - git -C esp-idf submodule update --init components/json/cJSON components/esp32/lib components/esptool_py/esptool components/expat/expat components/lwip/lwip components/mbedtls/mbedtls components/micro-ecc/micro-ecc components/nghttp/nghttp2 + - git -C esp-idf submodule update --init components/json/cJSON components/esp32/lib components/esptool_py/esptool components/expat/expat components/lwip/lwip components/mbedtls/mbedtls components/micro-ecc/micro-ecc components/nghttp/nghttp2 components/nimble components/bt - make ${MAKEOPTS} -C ports/esp32 submodules - make ${MAKEOPTS} -C ports/esp32 # clean diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index a9002b6512..65907a3ee0 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -51,8 +51,9 @@ OBJDUMP = $(CROSS_COMPILE)objdump SDKCONFIG_COMBINED = $(BUILD)/sdkconfig.combined SDKCONFIG_H = $(BUILD)/sdkconfig.h -# the git hash of the currently supported ESP IDF version -ESPIDF_SUPHASH_V3 := 6ccb4cf5b7d1fdddb8c2492f9cbc926abaf230df +# The git hash of the currently supported ESP IDF version. +# These correspond to v3.3.1 and v4.0-beta1. +ESPIDF_SUPHASH_V3 := 143d26aa49df524e10fb8e41a71d12e731b9b71d ESPIDF_SUPHASH_V4 := 310beae373446ceb9a4ad9b36b5428d7fdf2705f define print_supported_git_hash @@ -112,15 +113,13 @@ $(info Add the xtensa toolchain to your PATH. See README.md) $(error C compiler missing) endif -# Support BLE by default when building with IDF 4.x. +# Support BLE by default. # Can be explicitly disabled on the command line or board config. -ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) MICROPY_PY_BLUETOOTH ?= 1 ifeq ($(MICROPY_PY_BLUETOOTH),1) SDKCONFIG += boards/sdkconfig.ble MICROPY_BLUETOOTH_NIMBLE = 1 endif -endif # include sdkconfig to get needed configuration values include $(SDKCONFIG) @@ -158,6 +157,7 @@ INC_ESPCOMP += -I$(ESPCOMP)/tcpip_adapter/include INC_ESPCOMP += -I$(ESPCOMP)/lwip/lwip/src/include INC_ESPCOMP += -I$(ESPCOMP)/lwip/port/esp32/include INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/apps +INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/apps/sntp INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/mbedtls/include INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/port/include INC_ESPCOMP += -I$(ESPCOMP)/mdns/include @@ -218,9 +218,28 @@ INC_ESPCOMP += -I$(ESPCOMP)/json/port/include INC_ESPCOMP += -I$(ESPCOMP)/micro-ecc/micro-ecc INC_ESPCOMP += -I$(ESPCOMP)/nghttp/port/include INC_ESPCOMP += -I$(ESPCOMP)/nghttp/nghttp2/lib/includes +ifeq ($(CONFIG_NIMBLE_ENABLED),y) +INC_ESPCOMP += -I$(ESPCOMP)/bt/include +INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/porting/nimble/include +INC_ESPCOMP += -I$(ESPCOMP)/nimble/port/include +INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/nimble/include +INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/nimble/host/include +INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/nimble/host/services/ans/include +INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/nimble/host/services/bas/include +INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/nimble/host/services/gap/include +INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/nimble/host/services/gatt/include +INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/nimble/host/services/ias/include +INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/nimble/host/services/lls/include +INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/nimble/host/services/tps/include +INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/nimble/host/util/include +INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/nimble/host/store/ram/include +INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/nimble/host/store/config/include +INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/porting/npl/freertos/include +INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/ext/tinycrypt/include +INC_ESPCOMP += -I$(ESPCOMP)/nimble/esp-hci/include +endif endif -ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) ifeq ($(MICROPY_PY_BLUETOOTH),1) CFLAGS_MOD += -DMICROPY_PY_BLUETOOTH=1 CFLAGS_MOD += -DMICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE=1 @@ -229,7 +248,6 @@ ifeq ($(MICROPY_BLUETOOTH_NIMBLE),1) CFLAGS_MOD += -DMICROPY_BLUETOOTH_NIMBLE=1 endif endif -endif # these flags are common to C and C++ compilation CFLAGS_COMMON = -Os -ffunction-sections -fdata-sections -fstrict-volatile-bitfields \ @@ -421,6 +439,7 @@ ESPIDF_SOC_O = $(patsubst %.c,%.o,\ $(wildcard $(ESPCOMP)/soc/src/hal/*.c) \ ) +$(BUILD)/$(ESPCOMP)/cxx/cxx_guards.o: CXXFLAGS += -Wno-error=sign-compare ESPIDF_CXX_O = $(patsubst %.cpp,%.o,$(wildcard $(ESPCOMP)/cxx/*.cpp)) ESPIDF_PTHREAD_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/pthread/*.c)) @@ -458,6 +477,7 @@ ESPIDF_APP_UPDATE_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/app_update/*.c)) ESPIDF_NEWLIB_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/newlib/*.c)) +$(BUILD)/$(ESPCOMP)/nvs_flash/src/nvs_api.o: CXXFLAGS += -Wno-error=sign-compare ESPIDF_NVS_FLASH_O = $(patsubst %.cpp,%.o,$(wildcard $(ESPCOMP)/nvs_flash/src/*.cpp)) ESPIDF_SMARTCONFIG_ACK_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/smartconfig_ack/*.c)) @@ -546,6 +566,29 @@ ESPIDF_ETHERNET_O = $(patsubst %.c,%.o,\ $(wildcard $(ESPCOMP)/ethernet/*.c) \ $(wildcard $(ESPCOMP)/ethernet/eth_phy/*.c) \ ) + +ifeq ($(CONFIG_NIMBLE_ENABLED),y) +ESPIDF_BT_NIMBLE_O = $(patsubst %.c,%.o,\ + $(wildcard $(ESPCOMP)/bt/*.c) \ + $(wildcard $(ESPCOMP)/nimble/esp-hci/src/*.c) \ + $(wildcard $(ESPCOMP)/nimble/nimble/ext/tinycrypt/src/*.c) \ + $(wildcard $(ESPCOMP)/nimble/nimble/nimble/host/services/ans/src/*.c) \ + $(wildcard $(ESPCOMP)/nimble/nimble/nimble/host/services/bas/src/*.c) \ + $(wildcard $(ESPCOMP)/nimble/nimble/nimble/host/services/gap/src/*.c) \ + $(wildcard $(ESPCOMP)/nimble/nimble/nimble/host/services/gatt/src/*.c) \ + $(wildcard $(ESPCOMP)/nimble/nimble/nimble/host/services/ias/src/*.c) \ + $(wildcard $(ESPCOMP)/nimble/nimble/nimble/host/services/lls/src/*.c) \ + $(wildcard $(ESPCOMP)/nimble/nimble/nimble/host/services/tps/src/*.c) \ + $(wildcard $(ESPCOMP)/nimble/nimble/nimble/host/src/*.c) \ + $(wildcard $(ESPCOMP)/nimble/nimble/nimble/host/store/config/src/ble_store_config.c) \ + $(wildcard $(ESPCOMP)/nimble/nimble/nimble/host/store/config/src/ble_store_nvs.c) \ + $(wildcard $(ESPCOMP)/nimble/nimble/nimble/host/store/ram/src/*.c) \ + $(wildcard $(ESPCOMP)/nimble/nimble/nimble/host/util/src/*.c) \ + $(wildcard $(ESPCOMP)/nimble/nimble/nimble/src/*.c) \ + $(wildcard $(ESPCOMP)/nimble/nimble/porting/nimble/src/*.c) \ + $(wildcard $(ESPCOMP)/nimble/nimble/porting/npl/freertos/src/*.c) \ + ) +endif endif OBJ_ESPIDF = @@ -587,14 +630,12 @@ $(eval $(call gen_espidf_lib_rule,mbedtls,$(ESPIDF_MBEDTLS_O))) $(eval $(call gen_espidf_lib_rule,mdns,$(ESPIDF_MDNS_O))) $(eval $(call gen_espidf_lib_rule,wpa_supplicant,$(ESPIDF_WPA_SUPPLICANT_O))) $(eval $(call gen_espidf_lib_rule,sdmmc,$(ESPIDF_SDMMC_O))) +$(eval $(call gen_espidf_lib_rule,bt_nimble,$(ESPIDF_BT_NIMBLE_O))) ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) $(eval $(call gen_espidf_lib_rule,esp_common,$(ESPIDF_ESP_COMMON_O))) $(eval $(call gen_espidf_lib_rule,esp_event,$(ESPIDF_ESP_EVENT_O))) $(eval $(call gen_espidf_lib_rule,esp_wifi,$(ESPIDF_ESP_WIFI_O))) -ifeq ($(CONFIG_BT_NIMBLE_ENABLED),y) -$(eval $(call gen_espidf_lib_rule,bt_nimble,$(ESPIDF_BT_NIMBLE_O))) -endif $(eval $(call gen_espidf_lib_rule,esp_eth,$(ESPIDF_ESP_ETH_O))) $(eval $(call gen_espidf_lib_rule,xtensa,$(ESPIDF_XTENSA_O))) else @@ -714,6 +755,7 @@ APP_LD_ARGS += -L$(ESPCOMP)/bt/controller/lib -lbtdm_app APP_LD_ARGS += -L$(ESPCOMP)/esp_wifi/lib_esp32 -lcore -lmesh -lnet80211 -lphy -lrtc -lpp -lsmartconfig -lcoexist else APP_LD_ARGS += $(ESPCOMP)/esp32/libhal.a +APP_LD_ARGS += -L$(ESPCOMP)/bt/lib -lbtdm_app APP_LD_ARGS += -L$(ESPCOMP)/esp32/lib -lcore -lmesh -lnet80211 -lphy -lrtc -lpp -lwpa -lsmartconfig -lcoexist -lwps -lwpa2 endif APP_LD_ARGS += $(OBJ) @@ -769,6 +811,7 @@ BOOTLOADER_LIB_BOOTLOADER_SUPPORT_OBJ = $(addprefix $(BUILD)/bootloader/$(ESPCOM bootloader_support/src/bootloader_clock.o \ bootloader_support/src/bootloader_common.o \ bootloader_support/src/bootloader_flash.o \ + bootloader_support/src/bootloader_flash_config.o \ bootloader_support/src/bootloader_init.o \ bootloader_support/src/bootloader_random.o \ bootloader_support/src/bootloader_utility.o \ diff --git a/ports/esp32/boards/sdkconfig.base b/ports/esp32/boards/sdkconfig.base index dcb7742d3d..f44ec4e173 100644 --- a/ports/esp32/boards/sdkconfig.base +++ b/ports/esp32/boards/sdkconfig.base @@ -2,6 +2,7 @@ # The following options override the defaults CONFIG_IDF_TARGET="esp32" +CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000 # Application manager CONFIG_APP_EXCLUDE_PROJECT_VER_VAR=y diff --git a/ports/esp32/boards/sdkconfig.ble b/ports/esp32/boards/sdkconfig.ble index 15422903c1..cdbb621a63 100644 --- a/ports/esp32/boards/sdkconfig.ble +++ b/ports/esp32/boards/sdkconfig.ble @@ -12,3 +12,13 @@ CONFIG_BT_NIMBLE_MAX_CONNECTIONS=4 CONFIG_BT_NIMBLE_PINNED_TO_CORE_0=n CONFIG_BT_NIMBLE_PINNED_TO_CORE_1=y CONFIG_BT_NIMBLE_PINNED_TO_CORE=1 + +# v3.3-only (renamed in 4.0) +CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY=y +CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY= +CONFIG_BTDM_CONTROLLER_MODE_BTDM= +CONFIG_BLUEDROID_ENABLED=n +CONFIG_NIMBLE_ENABLED=y +CONFIG_NIMBLE_MAX_CONNECTIONS=4 +CONFIG_NIMBLE_PINNED_TO_CORE_0=n +CONFIG_NIMBLE_PINNED_TO_CORE_1=y From 5c5f93c1b896a8e73eff2edb3a3f3a2615b3f4de Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Thu, 16 Jan 2020 09:07:50 -0800 Subject: [PATCH 1156/1788] tests: Make run-tests help and README be more descriptive of behaviour. --- tests/README | 9 +++++++++ tests/run-tests | 11 +++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/tests/README b/tests/README index 3458f36a80..f2cd89bb93 100644 --- a/tests/README +++ b/tests/README @@ -13,6 +13,15 @@ condition a test. The run-tests script uses small scripts in the feature_check directory to check whether each such feature is present, and skips the relevant tests if not. +Tests are generally verified by running the test both in MicroPython and +in CPython and comparing the outputs. If the output differs the test fails +and the outputs are saved in a .out and a .exp file respectively. +For tests that cannot be run in CPython, for example because they use +the machine module, a .exp file can be provided next to the test's .py +file. A convenient way to generate that is to run the test, let it fail +(because CPython cannot run it) and then copy the .out file (but not +before checking it manually!) + When creating new tests, anything that relies on float support should go in the float/ subdirectory. Anything that relies on import x, where x is not a built-in module, should go in the import/ subdirectory. diff --git a/tests/run-tests b/tests/run-tests index b8f5b6b7a1..f0fa834070 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -553,7 +553,14 @@ class append_filter(argparse.Action): def main(): cmd_parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, - description='Run and manage tests for MicroPython.', + description='''Run and manage tests for MicroPython. + +When running tests, run-tests compares the MicroPython output of the test with the output +produced by running the test through CPython unless a .exp file is found, in which +case it is used as comparison. +If a test fails, run-tests produces a pair of .out and .exp files in the current +directory with the MicroPython output and the expectations, respectively. +''', epilog='''\ Options -i and -e can be multiple and processed in the order given. Regex "search" (vs "match") operation is used. An action (include/exclude) of @@ -570,7 +577,7 @@ the last matching regex is used: 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('--write-exp', action='store_true', help='use CPython to generate .exp files to run tests w/o CPython') cmd_parser.add_argument('--list-tests', action='store_true', help='list tests instead of running them') cmd_parser.add_argument('--emit', default='bytecode', help='MicroPython emitter to use (bytecode or native)') cmd_parser.add_argument('--heapsize', help='heapsize to use (use default if not specified)') From 59746ac14a7e639b8abd50fe626549e115c19c68 Mon Sep 17 00:00:00 2001 From: Peter Hinch Date: Sun, 12 Jan 2020 09:20:36 +0000 Subject: [PATCH 1157/1788] docs/library/uos.rst: Improve block devices section, and ioctl ret vals. --- docs/library/uos.rst | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/docs/library/uos.rst b/docs/library/uos.rst index cbc1f3e915..c49b13a5f5 100644 --- a/docs/library/uos.rst +++ b/docs/library/uos.rst @@ -218,11 +218,19 @@ represented by VFS classes. 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. +A block device is an object which implements the block protocol. This enables a +device to support MicroPython filesystems. The physical hardware is represented +by a user defined class. The :class:`AbstractBlockDev` class is a template for +the design of such a class: MicroPython does not actually provide that class, +but an actual block device class must implement the methods described below. + +A concrete implementation of this class will usually allow access to the +memory-like functionality of a piece of hardware (like flash memory). A block +device can be formatted to any supported filesystem and mounted using ``uos`` +methods. + +See :ref:`filesystem` for example implementations of block devices using the +two variants of the block protocol described below. .. _block-device-interface: @@ -294,5 +302,12 @@ that the block device supports the extended interface. (*arg* is unused) - 6 -- erase a block, *arg* is the block number to erase -See :ref:`filesystem` for example implementations of block devices using both -protocols. + As a minimum ``ioctl(4, ...)`` must be intercepted; for littlefs + ``ioctl(6, ...)`` must also be intercepted. The need for others is + hardware dependent. + + Unless otherwise stated ``ioctl(op, arg)`` can return ``None``. + Consequently an implementation can ignore unused values of ``op``. Where + ``op`` is intercepted, the return value for operations 4 and 5 are as + detailed above. Other operations should return 0 on success and non-zero + for failure, with the value returned being an ``OSError`` errno code. From a55c17dc69ac43cd41e7efe603e20298a5513b06 Mon Sep 17 00:00:00 2001 From: adzierzanowski Date: Thu, 16 Jan 2020 11:16:43 +0100 Subject: [PATCH 1158/1788] esp32/modnetwork: Add max_clients kw-arg to WLAN.config for AP setting. This allows the user to configure the maximum number of clients that are connected to the access point. Resolves #5125. --- docs/esp32/quickref.rst | 1 + ports/esp32/modnetwork.c | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst index c58f4aa760..8861ca4ac8 100644 --- a/docs/esp32/quickref.rst +++ b/docs/esp32/quickref.rst @@ -82,6 +82,7 @@ The :mod:`network` module:: ap = network.WLAN(network.AP_IF) # create access-point interface ap.config(essid='ESP-AP') # set the ESSID of the access point + ap.config(max_clients=10) # set how many clients can connect to the network ap.active(True) # activate the interface A useful function for connecting to your local WiFi network is:: diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index ba967b8cbd..06aa1c4b16 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -619,6 +619,11 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs ESP_EXCEPTIONS(tcpip_adapter_set_hostname(self->if_id, s)); break; } + case QS(MP_QSTR_max_clients): { + req_if = WIFI_IF_AP; + cfg.ap.max_connection = mp_obj_get_int(kwargs->table[i].value); + break; + } default: goto unknown; } @@ -693,6 +698,10 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs val = mp_obj_new_str(s, strlen(s)); break; } + case QS(MP_QSTR_max_clients): { + val = MP_OBJ_NEW_SMALL_INT(cfg.ap.max_connection); + break; + } default: goto unknown; } From 599371b133ec24c8ccfc3b75dd5a62b94b4b4055 Mon Sep 17 00:00:00 2001 From: stijn Date: Mon, 13 Jan 2020 12:11:27 +0100 Subject: [PATCH 1159/1788] windows: Support word-based move/delete key sequences for REPL. Translate common Ctrl-Left/Right/Delete/Backspace to the EMACS-style sequences (i.e. Alt key based) for forward-word, backward-word, forwad-kill and backward-kill. Requires MICROPY_REPL_EMACS_WORDS_MOVE to be defined so the readline implementation interprets these. --- ports/windows/windows_mphal.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/ports/windows/windows_mphal.c b/ports/windows/windows_mphal.c index 1e3a092910..1ec8e27d6a 100644 --- a/ports/windows/windows_mphal.c +++ b/ports/windows/windows_mphal.c @@ -141,7 +141,7 @@ typedef struct item_t { const char *seq; } item_t; -// map virtual key codes to VT100 escape sequences +// map virtual key codes to key sequences known by MicroPython's readline implementation STATIC item_t keyCodeMap[] = { {VK_UP, "[A"}, {VK_DOWN, "[B"}, @@ -153,10 +153,19 @@ STATIC item_t keyCodeMap[] = { {0, ""} //sentinel }; +// likewise, but with Ctrl key down +STATIC item_t ctrlKeyCodeMap[] = { + {VK_LEFT, "b"}, + {VK_RIGHT, "f"}, + {VK_DELETE, "d"}, + {VK_BACK, "\x7F"}, + {0, ""} //sentinel +}; + STATIC const char *cur_esc_seq = NULL; -STATIC int esc_seq_process_vk(int vk) { - for (item_t *p = keyCodeMap; p->vkey != 0; ++p) { +STATIC int esc_seq_process_vk(WORD vk, bool ctrl_key_down) { + for (item_t *p = (ctrl_key_down ? ctrlKeyCodeMap : keyCodeMap); p->vkey != 0; ++p) { if (p->vkey == vk) { cur_esc_seq = p->seq; return 27; // ESC, start of escape sequence @@ -194,14 +203,16 @@ int mp_hal_stdin_rx_chr(void) { if (rec.EventType != KEY_EVENT || !rec.Event.KeyEvent.bKeyDown) { // only want key down events continue; } + const bool ctrl_key_down = (rec.Event.KeyEvent.dwControlKeyState & LEFT_CTRL_PRESSED) || + (rec.Event.KeyEvent.dwControlKeyState & RIGHT_CTRL_PRESSED); + const int ret = esc_seq_process_vk(rec.Event.KeyEvent.wVirtualKeyCode, ctrl_key_down); + if (ret) { + return ret; + } const char c = rec.Event.KeyEvent.uChar.AsciiChar; if (c) { // plain ascii char, return it return c; } - const int ret = esc_seq_process_vk(rec.Event.KeyEvent.wVirtualKeyCode); - if (ret) { - return ret; - } } } From fe203bb3e2c98239ece07f340b3e745368636bb8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 13 Jan 2020 17:10:41 +1100 Subject: [PATCH 1160/1788] py/pairheap: Add generic implementation of pairing heap data structure. --- py/pairheap.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++ py/pairheap.h | 90 ++++++++++++++++++++++++++++++++ py/py.mk | 1 + 3 files changed, 230 insertions(+) create mode 100644 py/pairheap.c create mode 100644 py/pairheap.h diff --git a/py/pairheap.c b/py/pairheap.c new file mode 100644 index 0000000000..caa51bf797 --- /dev/null +++ b/py/pairheap.c @@ -0,0 +1,139 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 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/pairheap.h" + +// The mp_pairheap_t.next pointer can take one of the following values: +// - NULL: the node is the top of the heap +// - LSB set: the node is the last of the children and points to its parent node +// - other: the node is a child and not the last child +// The macros below help manage this pointer. +#define NEXT_MAKE_RIGHTMOST_PARENT(parent) ((void*)((uintptr_t)(parent) | 1)) +#define NEXT_IS_RIGHTMOST_PARENT(next) ((uintptr_t)(next) & 1) +#define NEXT_GET_RIGHTMOST_PARENT(next) ((void*)((uintptr_t)(next) & ~1)) + +// O(1), stable +mp_pairheap_t *mp_pairheap_meld(mp_pairheap_lt_t lt, mp_pairheap_t *heap1, mp_pairheap_t *heap2) { + if (heap1 == NULL) { + return heap2; + } + if (heap2 == NULL) { + return heap1; + } + if (lt(heap1, heap2)) { + if (heap1->child == NULL) { + heap1->child = heap2; + } else { + heap1->child_last->next = heap2; + } + heap1->child_last = heap2; + heap2->next = NEXT_MAKE_RIGHTMOST_PARENT(heap1); + return heap1; + } else { + heap1->next = heap2->child; + heap2->child = heap1; + if (heap1->next == NULL) { + heap2->child_last = heap1; + heap1->next = NEXT_MAKE_RIGHTMOST_PARENT(heap2); + } + return heap2; + } +} + +// amortised O(log N), stable +mp_pairheap_t *mp_pairheap_pairing(mp_pairheap_lt_t lt, mp_pairheap_t *child) { + if (child == NULL) { + return NULL; + } + mp_pairheap_t *heap = NULL; + while (!NEXT_IS_RIGHTMOST_PARENT(child)) { + mp_pairheap_t *n1 = child; + child = child->next; + if (!NEXT_IS_RIGHTMOST_PARENT(child)) { + mp_pairheap_t *n2 = child; + child = child->next; + n1 = mp_pairheap_meld(lt, n1, n2); + } + heap = mp_pairheap_meld(lt, heap, n1); + } + heap->next = NULL; + return heap; +} + +// amortised O(log N), stable +mp_pairheap_t *mp_pairheap_delete(mp_pairheap_lt_t lt, mp_pairheap_t *heap, mp_pairheap_t *node) { + // Simple case of the top being the node to delete + if (node == heap) { + return mp_pairheap_pairing(lt, heap->child); + } + + // Case where node is not in the heap + if (node->next == NULL) { + return heap; + } + + // Find parent of node + mp_pairheap_t *parent = node; + while (!NEXT_IS_RIGHTMOST_PARENT(parent->next)) { + parent = parent->next; + } + parent = NEXT_GET_RIGHTMOST_PARENT(parent->next); + + // Replace node with pairing of its children + mp_pairheap_t *next; + if (node == parent->child && node->child == NULL) { + if (NEXT_IS_RIGHTMOST_PARENT(node->next)) { + parent->child = NULL; + } else { + parent->child = node->next; + } + node->next = NULL; + return heap; + } else if (node == parent->child) { + next = node->next; + node->next = NULL; + node = mp_pairheap_pairing(lt, node->child); + parent->child = node; + } else { + mp_pairheap_t *n = parent->child; + while (node != n->next) { + n = n->next; + } + next = node->next; + node->next = NULL; + node = mp_pairheap_pairing(lt, node->child); + if (node == NULL) { + node = n; + } else { + n->next = node; + } + } + node->next = next; + if (NEXT_IS_RIGHTMOST_PARENT(next)) { + parent->child_last = node; + } + return heap; +} diff --git a/py/pairheap.h b/py/pairheap.h new file mode 100644 index 0000000000..f9517f281e --- /dev/null +++ b/py/pairheap.h @@ -0,0 +1,90 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 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_PAIRHEAP_H +#define MICROPY_INCLUDED_PY_PAIRHEAP_H + +// This is an implementation of a pairing heap. It is stable and has deletion +// support. Only the less-than operation needs to be defined on elements. +// +// See original paper for details: +// Michael L. Fredman, Robert Sedjewick, Daniel D. Sleator, and Robert E. Tarjan. +// The Pairing Heap: A New Form of Self-Adjusting Heap. +// Algorithmica 1:111-129, 1986. +// https://www.cs.cmu.edu/~sleator/papers/pairing-heaps.pdf + +#include "py/obj.h" + +// This struct forms the nodes of the heap and is intended to be extended, by +// placing it first in another struct, to include additional information for the +// element stored in the heap. It includes "base" so it can be a MicroPython +// object allocated on the heap and the GC can automatically trace all nodes by +// following the tree structure. +typedef struct _mp_pairheap_t { + mp_obj_base_t base; + struct _mp_pairheap_t *child; + struct _mp_pairheap_t *child_last; + struct _mp_pairheap_t *next; +} mp_pairheap_t; + +// This is the function for the less-than operation on nodes/elements. +typedef int (*mp_pairheap_lt_t)(mp_pairheap_t*, mp_pairheap_t*); + +// Core functions. +mp_pairheap_t *mp_pairheap_meld(mp_pairheap_lt_t lt, mp_pairheap_t *heap1, mp_pairheap_t *heap2); +mp_pairheap_t *mp_pairheap_pairing(mp_pairheap_lt_t lt, mp_pairheap_t *child); +mp_pairheap_t *mp_pairheap_delete(mp_pairheap_lt_t lt, mp_pairheap_t *heap, mp_pairheap_t *node); + +// Create a new heap. +static inline mp_pairheap_t *mp_pairheap_new(mp_pairheap_lt_t lt) { + (void)lt; + return NULL; +} + +// Test if the heap is empty. +static inline bool mp_pairheap_is_empty(mp_pairheap_lt_t lt, mp_pairheap_t *heap) { + (void)lt; + return heap == NULL; +} + +// Peek at the top of the heap. Will return NULL if empty. +static inline mp_pairheap_t *mp_pairheap_peek(mp_pairheap_lt_t lt, mp_pairheap_t *heap) { + (void)lt; + return heap; +} + +// Push new node onto existing heap. Returns the new heap. +static inline mp_pairheap_t *mp_pairheap_push(mp_pairheap_lt_t lt, mp_pairheap_t *heap, mp_pairheap_t *node) { + node->child = NULL; + node->next = NULL; + return mp_pairheap_meld(lt, node, heap); // node is first to be stable +} + +// Pop the top off the heap, which must not be empty. Returns the new heap. +static inline mp_pairheap_t *mp_pairheap_pop(mp_pairheap_lt_t lt, mp_pairheap_t *heap) { + return mp_pairheap_pairing(lt, heap->child); +} + +#endif // MICROPY_INCLUDED_PY_PAIRHEAP_H diff --git a/py/py.mk b/py/py.mk index 09de1962d3..1a56dcce8f 100644 --- a/py/py.mk +++ b/py/py.mk @@ -94,6 +94,7 @@ PY_CORE_O_BASENAME = $(addprefix py/,\ runtime_utils.o \ scheduler.o \ nativeglue.o \ + pairheap.o \ ringbuf.o \ stackctrl.o \ argcheck.o \ From f70373c7b255a465300517c41a058909b4d3cea2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 13 Jan 2020 17:12:50 +1100 Subject: [PATCH 1161/1788] stm32/softtimer: Change linear linked list to a pairing heap. --- ports/stm32/machine_timer.c | 2 +- ports/stm32/mpconfigport.h | 2 +- ports/stm32/softtimer.c | 59 ++++++++++++++----------------------- ports/stm32/softtimer.h | 5 ++-- 4 files changed, 26 insertions(+), 42 deletions(-) diff --git a/ports/stm32/machine_timer.c b/ports/stm32/machine_timer.c index 22fa67d7d9..1e9be42627 100644 --- a/ports/stm32/machine_timer.c +++ b/ports/stm32/machine_timer.c @@ -77,7 +77,7 @@ STATIC mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, size_t n_ar 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) { machine_timer_obj_t *self = m_new_obj(machine_timer_obj_t); - self->base.type = &machine_timer_type; + self->pairheap.base.type = &machine_timer_type; // Get timer id (only soft timer (-1) supported at the moment) mp_int_t id = -1; diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 55f09f81f0..2e4fc04061 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -281,7 +281,7 @@ struct _mp_bluetooth_nimble_root_pointers_t; \ mp_obj_t pyb_extint_callback[PYB_EXTI_NUM_VECTORS]; \ \ - struct _soft_timer_entry_t *soft_timer_head; \ + struct _soft_timer_entry_t *soft_timer_heap; \ \ /* pointers to all Timer objects (if they have been created) */ \ struct _pyb_timer_obj_t *pyb_timer_obj_all[MICROPY_HW_MAX_TIMER]; \ diff --git a/ports/stm32/softtimer.c b/ports/stm32/softtimer.c index c598bac177..60c2709d93 100644 --- a/ports/stm32/softtimer.c +++ b/ports/stm32/softtimer.c @@ -37,7 +37,13 @@ extern __IO uint32_t uwTick; volatile uint32_t soft_timer_next; void soft_timer_deinit(void) { - MP_STATE_PORT(soft_timer_head) = NULL; + MP_STATE_PORT(soft_timer_heap) = NULL; +} + +STATIC int soft_timer_lt(mp_pairheap_t *n1, mp_pairheap_t *n2) { + soft_timer_entry_t *e1 = (soft_timer_entry_t*)n1; + soft_timer_entry_t *e2 = (soft_timer_entry_t*)n2; + return TICKS_DIFF(e1->expiry_ms, e2->expiry_ms) < 0; } STATIC void soft_timer_schedule_systick(uint32_t ticks_ms) { @@ -54,59 +60,38 @@ STATIC void soft_timer_schedule_systick(uint32_t ticks_ms) { // Must be executed at IRQ_PRI_PENDSV void soft_timer_handler(void) { uint32_t ticks_ms = uwTick; - soft_timer_entry_t *head = MP_STATE_PORT(soft_timer_head); - while (head != NULL && TICKS_DIFF(head->expiry_ms, ticks_ms) <= 0) { - mp_sched_schedule(head->callback, MP_OBJ_FROM_PTR(head)); - if (head->mode == SOFT_TIMER_MODE_PERIODIC) { - head->expiry_ms += head->delta_ms; - // Shift this node along to its new position - soft_timer_entry_t *cur = head; - while (cur->next != NULL && TICKS_DIFF(head->expiry_ms, cur->next->expiry_ms) >= 0) { - cur = cur->next; - } - if (cur != head) { - soft_timer_entry_t *next = head->next; - head->next = cur->next; - cur->next = head; - head = next; - } - } else { - head = head->next; + soft_timer_entry_t *heap = MP_STATE_PORT(soft_timer_heap); + while (heap != NULL && TICKS_DIFF(heap->expiry_ms, ticks_ms) <= 0) { + soft_timer_entry_t *entry = heap; + heap = (soft_timer_entry_t*)mp_pairheap_pop(soft_timer_lt, &heap->pairheap); + mp_sched_schedule(entry->callback, MP_OBJ_FROM_PTR(entry)); + if (entry->mode == SOFT_TIMER_MODE_PERIODIC) { + entry->expiry_ms += entry->delta_ms; + heap = (soft_timer_entry_t*)mp_pairheap_push(soft_timer_lt, &heap->pairheap, &entry->pairheap); } } - MP_STATE_PORT(soft_timer_head) = head; - if (head == NULL) { + MP_STATE_PORT(soft_timer_heap) = heap; + if (heap == NULL) { // No more timers left, set largest delay possible soft_timer_next = uwTick; } else { // Set soft_timer_next so SysTick calls us back at the correct time - soft_timer_schedule_systick(head->expiry_ms); + soft_timer_schedule_systick(heap->expiry_ms); } } void soft_timer_insert(soft_timer_entry_t *entry) { uint32_t irq_state = raise_irq_pri(IRQ_PRI_PENDSV); - soft_timer_entry_t **head_ptr = &MP_STATE_PORT(soft_timer_head); - while (*head_ptr != NULL && TICKS_DIFF(entry->expiry_ms, (*head_ptr)->expiry_ms) >= 0) { - head_ptr = &(*head_ptr)->next; - } - entry->next = *head_ptr; - *head_ptr = entry; - if (head_ptr == &MP_STATE_PORT(soft_timer_head)) { + MP_STATE_PORT(soft_timer_heap) = (soft_timer_entry_t*)mp_pairheap_push(soft_timer_lt, &MP_STATE_PORT(soft_timer_heap)->pairheap, &entry->pairheap); + if (entry == MP_STATE_PORT(soft_timer_heap)) { // This new timer became the earliest one so set soft_timer_next - soft_timer_schedule_systick((*head_ptr)->expiry_ms); + soft_timer_schedule_systick(entry->expiry_ms); } restore_irq_pri(irq_state); } void soft_timer_remove(soft_timer_entry_t *entry) { uint32_t irq_state = raise_irq_pri(IRQ_PRI_PENDSV); - soft_timer_entry_t **cur = &MP_STATE_PORT(soft_timer_head); - while (*cur != NULL) { - if (*cur == entry) { - *cur = entry->next; - break; - } - } + MP_STATE_PORT(soft_timer_heap) = (soft_timer_entry_t*)mp_pairheap_delete(soft_timer_lt, &MP_STATE_PORT(soft_timer_heap)->pairheap, &entry->pairheap); restore_irq_pri(irq_state); } diff --git a/ports/stm32/softtimer.h b/ports/stm32/softtimer.h index 2550446d83..a80d9087b5 100644 --- a/ports/stm32/softtimer.h +++ b/ports/stm32/softtimer.h @@ -26,14 +26,13 @@ #ifndef MICROPY_INCLUDED_STM32_SOFTTIMER_H #define MICROPY_INCLUDED_STM32_SOFTTIMER_H -#include "py/obj.h" +#include "py/pairheap.h" #define SOFT_TIMER_MODE_ONE_SHOT (1) #define SOFT_TIMER_MODE_PERIODIC (2) typedef struct _soft_timer_entry_t { - mp_obj_base_t base; // so struct can be used as an object and still be traced by GC - struct _soft_timer_entry_t *next; + mp_pairheap_t pairheap; uint32_t mode; uint32_t expiry_ms; uint32_t delta_ms; // for periodic mode From cfddc6a8c773c204bd748124aa7c445cba1d4891 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 13 Jan 2020 17:35:18 +1100 Subject: [PATCH 1162/1788] tests/extmod: Add basic machine.Timer test. --- tests/extmod/machine_timer.py | 37 +++++++++++++++++++++++++++++++ tests/extmod/machine_timer.py.exp | 4 ++++ 2 files changed, 41 insertions(+) create mode 100644 tests/extmod/machine_timer.py create mode 100644 tests/extmod/machine_timer.py.exp diff --git a/tests/extmod/machine_timer.py b/tests/extmod/machine_timer.py new file mode 100644 index 0000000000..b7e6a280f9 --- /dev/null +++ b/tests/extmod/machine_timer.py @@ -0,0 +1,37 @@ +# test machine.Timer + +try: + import utime, umachine as machine + machine.Timer +except: + print("SKIP") + raise SystemExit + +# create and deinit +t = machine.Timer(freq=1) +t.deinit() + +# deinit again +t.deinit() + +# create 2 and deinit +t = machine.Timer(freq=1) +t2 = machine.Timer(freq=1) +t.deinit() +t2.deinit() + +# create 2 and deinit in different order +t = machine.Timer(freq=1) +t2 = machine.Timer(freq=1) +t2.deinit() +t.deinit() + +# create one-shot timer with callback and wait for it to print (should be just once) +t = machine.Timer(period=1, mode=machine.Timer.ONE_SHOT, callback=lambda t:print('one-shot')) +utime.sleep_ms(5) +t.deinit() + +# create periodic timer with callback and wait for it to print +t = machine.Timer(period=4, mode=machine.Timer.PERIODIC, callback=lambda t:print('periodic')) +utime.sleep_ms(14) +t.deinit() diff --git a/tests/extmod/machine_timer.py.exp b/tests/extmod/machine_timer.py.exp new file mode 100644 index 0000000000..2dd85ba67d --- /dev/null +++ b/tests/extmod/machine_timer.py.exp @@ -0,0 +1,4 @@ +one-shot +periodic +periodic +periodic From dccace6f3fdded89dbf8173eb3882205c419f2fb Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 14 Jan 2020 00:02:01 +1100 Subject: [PATCH 1163/1788] tests/unix: Add coverage tests for pairheap data structure. --- ports/unix/coverage.c | 59 ++++++++++++++++++++++++++++++++ tests/unix/extra_coverage.py.exp | 13 +++++++ 2 files changed, 72 insertions(+) diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index 6cd84dc301..233c6211e9 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -11,6 +11,7 @@ #include "py/emit.h" #include "py/formatfloat.h" #include "py/ringbuf.h" +#include "py/pairheap.h" #include "py/stream.h" #include "py/binary.h" #include "py/bc.h" @@ -139,6 +140,35 @@ STATIC const mp_obj_type_t mp_type_stest_textio2 = { STATIC const mp_obj_str_t str_no_hash_obj = {{&mp_type_str}, 0, 10, (const byte*)"0123456789"}; STATIC const mp_obj_str_t bytes_no_hash_obj = {{&mp_type_bytes}, 0, 10, (const byte*)"0123456789"}; +STATIC int pairheap_lt(mp_pairheap_t *a, mp_pairheap_t *b) { + return (uintptr_t)a < (uintptr_t)b; +} + +// ops array contain operations: x>=0 means push(x), x<0 means delete(-x) +STATIC void pairheap_test(size_t nops, int *ops) { + mp_pairheap_t node[8]; + mp_pairheap_t *heap = mp_pairheap_new(pairheap_lt); + printf("create:"); + for (size_t i = 0; i < nops; ++i) { + if (ops[i] >= 0) { + heap = mp_pairheap_push(pairheap_lt, heap, &node[ops[i]]); + } else { + heap = mp_pairheap_delete(pairheap_lt, heap, &node[-ops[i]]); + } + if (mp_pairheap_is_empty(pairheap_lt, heap)) { + mp_printf(&mp_plat_print, " -"); + } else { + mp_printf(&mp_plat_print, " %d", mp_pairheap_peek(pairheap_lt, heap) - &node[0]);; + } + } + printf("\npop all:"); + while (!mp_pairheap_is_empty(pairheap_lt, heap)) { + mp_printf(&mp_plat_print, " %d", mp_pairheap_peek(pairheap_lt, heap) - &node[0]);; + heap = mp_pairheap_pop(pairheap_lt, heap); + } + printf("\n"); +} + // function to run extra tests for things that can't be checked by scripts STATIC mp_obj_t extra_coverage(void) { // mp_printf (used by ports that don't have a native printf) @@ -514,6 +544,35 @@ STATIC mp_obj_t extra_coverage(void) { mp_printf(&mp_plat_print, "%d\n", ringbuf_get16(&ringbuf)); } + // pairheap + { + mp_printf(&mp_plat_print, "# pairheap\n"); + + // Basic case. + int t0[] = {0, 2, 1, 3}; + pairheap_test(MP_ARRAY_SIZE(t0), t0); + + // All pushed in reverse order. + int t1[] = {7, 6, 5, 4, 3, 2, 1, 0}; + pairheap_test(MP_ARRAY_SIZE(t1), t1); + + // Basic deletion. + int t2[] = {1, -1, -1, 1, 2, -2, 2, 3, -3}; + pairheap_test(MP_ARRAY_SIZE(t2), t2); + + // Deletion of first child that has next node (the -3). + int t3[] = {1, 2, 3, 4, -1, -3}; + pairheap_test(MP_ARRAY_SIZE(t3), t3); + + // Deletion of node that's not first child (the -2). + int t4[] = {1, 2, 3, 4, -2}; + pairheap_test(MP_ARRAY_SIZE(t4), t4); + + // Deletion of node that's not first child and has children (the -3). + int t5[] = {3, 4, 5, 1, 2, -3}; + pairheap_test(MP_ARRAY_SIZE(t5), t5); + } + mp_obj_streamtest_t *s = m_new_obj(mp_obj_streamtest_t); s->base.type = &mp_type_stest_fileio; s->buf = NULL; diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index 6aa2da31a4..a41f227be7 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -101,6 +101,19 @@ cc99 22ff -1 -1 +# pairheap +create: 0 0 0 0 +pop all: 0 1 2 3 +create: 7 6 5 4 3 2 1 0 +pop all: 0 1 2 3 4 5 6 7 +create: 1 - - 1 1 1 1 1 1 +pop all: 1 2 +create: 1 1 1 1 2 2 +pop all: 2 4 +create: 1 1 1 1 1 +pop all: 1 3 4 +create: 3 3 3 1 1 1 +pop all: 1 2 4 5 0123456789 b'0123456789' 7300 7300 From a11e3062275685dd80e1202a3dfa5f026d91a7a7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 13 Jan 2020 17:05:46 +1100 Subject: [PATCH 1164/1788] tools: Add metrics.py script to build and compute port sizes/metrics. --- tools/metrics.py | 205 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100755 tools/metrics.py diff --git a/tools/metrics.py b/tools/metrics.py new file mode 100755 index 0000000000..0cc6db5107 --- /dev/null +++ b/tools/metrics.py @@ -0,0 +1,205 @@ +#!/usr/bin/env python3 +# +# This file is part of the MicroPython project, http://micropython.org/ +# +# The MIT License (MIT) +# +# Copyright (c) 2020 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. + +""" +This script is used to compute metrics, like code size, of the various ports. + +Typical usage is: + + $ ./tools/metrics.py build | tee size0 + + $ git switch new-feature-branch + $ ./tools/metrics.py build | tee size1 + + $ ./tools/metrics.py diff size0 size1 + +Other commands: + + $ ./tools/metrics.py sizes # print all firmware sizes + $ ./tools/metrics.py clean # clean all ports + +""" + +import sys, re, subprocess + +MAKE_FLAGS = ['-j3', 'CFLAGS_EXTRA=-DNDEBUG'] + +class PortData: + def __init__(self, name, dir, output, make_flags=None): + self.name = name + self.dir = dir + self.output = output + self.make_flags = make_flags + +port_data = { + 'b': PortData('bare-arm', 'bare-arm', 'build/firmware.elf'), + 'm': PortData('minimal x86', 'minimal', 'build/firmware.elf'), + 'u': PortData('unix x64', 'unix', 'micropython'), + 'n': PortData('unix nanbox', 'unix', 'micropython-nanbox', 'VARIANT=nanbox'), + 's': PortData('stm32', 'stm32', 'build-PYBV10/firmware.elf', 'BOARD=PYBV10'), + 'c': PortData('cc3200', 'cc3200', 'build/WIPY/release/application.axf', 'BTARGET=application'), + '8': PortData('esp8266', 'esp8266', 'build-GENERIC/firmware.elf'), + '3': PortData('esp32', 'esp32', 'build-GENERIC/application.elf'), + 'r': PortData('nrf', 'nrf', 'build-pca10040/firmware.elf'), + 'd': PortData('samd', 'samd', 'build-ADAFRUIT_ITSYBITSY_M4_EXPRESS/firmware.elf'), +} + +def syscmd(*args): + sys.stdout.flush() + a2 = [] + for a in args: + if isinstance(a, str): + a2.append(a) + elif a: + a2.extend(a) + subprocess.run(a2) + +def parse_port_list(args): + if not args: + return list(port_data.values()) + else: + ports = [] + for arg in args: + for port_char in arg: + try: + ports.append(port_data[port_char]) + except KeyError: + print('unknown port:', port_char) + sys.exit(1) + return ports + +def read_build_log(filename): + data = dict() + lines = [] + found_sizes = False + with open(filename) as f: + for line in f: + line = line.strip() + if line.strip() == 'COMPUTING SIZES': + found_sizes = True + elif found_sizes: + lines.append(line) + is_size_line = False + for line in lines: + if is_size_line: + fields = line.split() + data[fields[-1]] = [int(f) for f in fields[:-2]] + is_size_line = False + else: + is_size_line = line.startswith('text\t ') + return data + +def do_diff(args): + """Compute the difference between firmware sizes.""" + + if len(args) != 2: + print('usage: %s diff ' % sys.argv[0]) + sys.exit(1) + + data1 = read_build_log(args[0]) + data2 = read_build_log(args[1]) + + for key, value1 in data1.items(): + value2 = data2[key] + for port in port_data.values(): + if key == 'ports/{}/{}'.format(port.dir, port.output): + name = port.name + break + data = [v2 - v1 for v1, v2 in zip(value1, value2)] + warn = '' + board = re.search(r'/build-([A-Za-z0-9_]+)/', key) + if board: + board = board.group(1) + else: + board = '' + if name == 'cc3200': + delta = data[0] + percent = 100 * delta / value1[0] + if data[1] != 0: + warn += ' %+u(data)' % data[1] + else: + delta = data[3] + percent = 100 * delta / value1[3] + if data[1] != 0: + warn += ' %+u(data)' % data[1] + if data[2] != 0: + warn += ' %+u(bss)' % data[2] + if warn: + warn = '[incl%s]' % warn + print('%11s: %+5u %+.3f%% %s%s' % (name, delta, percent, board, warn)) + +def do_clean(args): + """Clean ports.""" + + ports = parse_port_list(args) + + print('CLEANING') + for port in ports: + syscmd('make', '-C', 'ports/{}'.format(port.dir), port.make_flags, 'clean') + +def do_build(args): + """Build ports and print firmware sizes.""" + + ports = parse_port_list(args) + + print('BUILDING MPY-CROSS') + syscmd('make', '-C', 'mpy-cross', MAKE_FLAGS) + + print('BUILDING PORTS') + for port in ports: + syscmd('make', '-C', 'ports/{}'.format(port.dir), MAKE_FLAGS, port.make_flags) + + do_sizes(args) + +def do_sizes(args): + """Compute and print sizes of firmware.""" + + ports = parse_port_list(args) + + print('COMPUTING SIZES') + for port in ports: + syscmd('size', 'ports/{}/{}'.format(port.dir, port.output)) + +def main(): + # Get command to execute + if len(sys.argv) == 1: + print('Available commands:') + for cmd in globals(): + if cmd.startswith('do_'): + print(' {:9} {}'.format(cmd[3:], globals()[cmd].__doc__)) + sys.exit(1) + cmd = sys.argv.pop(1) + + # Dispatch to desired command + try: + cmd = globals()['do_{}'.format(cmd)] + except KeyError: + print("{}: unknown command '{}'".format(sys.argv[0], cmd)) + sys.exit(1) + cmd(sys.argv[1:]) + +if __name__ == '__main__': + main() From 6db5cede06dfb580c5e4f6cdeb1796256969b4fb Mon Sep 17 00:00:00 2001 From: c0rejump Date: Tue, 21 Jan 2020 21:30:50 +0100 Subject: [PATCH 1165/1788] tools/pydfu.py: Clean up syntax, update comments and docstrings. Some parts of code have been aligned to increase readability. In general '' instead of "" were used wherever possible to keep the same convention for entire file. Import inspect line has been moved to the top according to hints reported by pep8 tools. A few extra spaces were removed, a few missing spaces were added. Comments have been updated, mostly in "read_dfu_file" function. Some other comments have been capitalized and/or slightly updated. A few docstrings were fixed as well. No real code changes intended. --- tools/pydfu.py | 195 ++++++++++++++++++++++++++----------------------- 1 file changed, 104 insertions(+), 91 deletions(-) diff --git a/tools/pydfu.py b/tools/pydfu.py index 658ce59ae6..962ba2b7f0 100755 --- a/tools/pydfu.py +++ b/tools/pydfu.py @@ -15,6 +15,7 @@ from __future__ import print_function import argparse import collections +import inspect import re import struct import sys @@ -67,7 +68,6 @@ __DFU_INTERFACE = 0 # Python 3 deprecated getargspec in favour of getfullargspec, but # Python 2 doesn't have the latter, so detect which one to use -import inspect getargspec = getattr(inspect, 'getfullargspec', inspect.getargspec) if 'length' in getargspec(usb.util.get_string).args: @@ -82,9 +82,17 @@ else: def find_dfu_cfg_descr(descr): if len(descr) == 9 and descr[0] == 9 and descr[1] == _DFU_DESCRIPTOR_TYPE: - nt = collections.namedtuple('CfgDescr', - ['bLength', 'bDescriptorType', 'bmAttributes', - 'wDetachTimeOut', 'wTransferSize', 'bcdDFUVersion']) + nt = collections.namedtuple( + 'CfgDescr', + [ + 'bLength', + 'bDescriptorType', + 'bmAttributes', + 'wDetachTimeOut', + 'wTransferSize', + 'bcdDFUVersion' + ] + ) return nt(*struct.unpack(' 1: - raise ValueError("Multiple DFU devices found") + raise ValueError('Multiple DFU devices found') __dev = devices[0] __dev.set_configuration() @@ -141,57 +149,56 @@ def get_status(): """Get the status of the last operation.""" stat = __dev.ctrl_transfer(0xA1, __DFU_GETSTATUS, 0, __DFU_INTERFACE, 6, 20000) - # print (__DFU_STAT[stat[4]], stat) return stat[4] def mass_erase(): - """Performs a MASS erase (i.e. erases the entire device.""" + """Performs a MASS erase (i.e. erases the entire device).""" # Send DNLOAD with first byte=0x41 __dev.ctrl_transfer(0x21, __DFU_DNLOAD, 0, __DFU_INTERFACE, - "\x41", __TIMEOUT) + '\x41', __TIMEOUT) # Execute last command if get_status() != __DFU_STATE_DFU_DOWNLOAD_BUSY: - raise Exception("DFU: erase failed") + raise Exception('DFU: erase failed') # Check command state if get_status() != __DFU_STATE_DFU_DOWNLOAD_IDLE: - raise Exception("DFU: erase failed") + raise Exception('DFU: erase failed') def page_erase(addr): """Erases a single page.""" if __verbose: - print("Erasing page: 0x%x..." % (addr)) + print('Erasing page: 0x%x...' % (addr)) # Send DNLOAD with first byte=0x41 and page address - buf = struct.pack(" Date: Wed, 22 Jan 2020 11:19:37 -0600 Subject: [PATCH 1166/1788] py/gc: Don't include or init gc_mutex when GIL is enabled. When threads and the GIL are enabled, then the GC mutex is not needed. The gc_mutex field is never used in this case because of: #if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL #define GC_ENTER() mp_thread_mutex_lock(&MP_STATE_MEM(gc_mutex), 1) #define GC_EXIT() mp_thread_mutex_unlock(&MP_STATE_MEM(gc_mutex)) #else #define GC_ENTER() #define GC_EXIT() #endif So, we can completely remove gc_mutex everywhere when MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL. --- py/gc.c | 2 +- py/mpstate.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/py/gc.c b/py/gc.c index c763a839ec..c18cd429f3 100644 --- a/py/gc.c +++ b/py/gc.c @@ -161,7 +161,7 @@ void gc_init(void *start, void *end) { MP_STATE_MEM(gc_alloc_amount) = 0; #endif - #if MICROPY_PY_THREAD + #if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL mp_thread_mutex_init(&MP_STATE_MEM(gc_mutex)); #endif diff --git a/py/mpstate.h b/py/mpstate.h index ab7d8c51b9..9bb87f0ba7 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -98,7 +98,7 @@ typedef struct _mp_state_mem_t { size_t gc_collected; #endif - #if MICROPY_PY_THREAD + #if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL // This is a global mutex used to make the GC thread-safe. mp_thread_mutex_t gc_mutex; #endif From edbb73a411919af954619dcee02bc448912c9e27 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Wed, 22 Jan 2020 11:19:37 -0600 Subject: [PATCH 1167/1788] py/qstr: Don't include or init qstr_mutex when GIL is enabled. When threads and the GIL are enabled, then the qstr mutex is not needed. The qstr_mutex field is never used in this case because of: #if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL #define QSTR_ENTER() mp_thread_mutex_lock(&MP_STATE_VM(qstr_mutex), 1) #define QSTR_EXIT() mp_thread_mutex_unlock(&MP_STATE_VM(qstr_mutex)) #else #define QSTR_ENTER() #define QSTR_EXIT() #endif So, we can completely remove qstr_mutex everywhere when MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL. --- py/mpstate.h | 2 +- py/qstr.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/py/mpstate.h b/py/mpstate.h index 9bb87f0ba7..5f6cf55936 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -203,7 +203,7 @@ typedef struct _mp_state_vm_t { size_t qstr_last_alloc; size_t qstr_last_used; - #if MICROPY_PY_THREAD + #if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL // This is a global mutex used to make qstr interning thread-safe. mp_thread_mutex_t qstr_mutex; #endif diff --git a/py/qstr.c b/py/qstr.c index 29ffcae408..940d09ea40 100644 --- a/py/qstr.c +++ b/py/qstr.c @@ -125,7 +125,7 @@ void qstr_init(void) { MP_STATE_VM(last_pool) = (qstr_pool_t*)&CONST_POOL; // we won't modify the const_pool since it has no allocated room left MP_STATE_VM(qstr_last_chunk) = NULL; - #if MICROPY_PY_THREAD + #if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL mp_thread_mutex_init(&MP_STATE_VM(qstr_mutex)); #endif } From edc7a8bf1d984365ef3f6a1ef3e8238fdb813fed Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 23 Jan 2020 13:01:39 +1100 Subject: [PATCH 1168/1788] py/objgenerator: Use mp_obj_new_exception_arg1 to make StopIteration. --- py/objgenerator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/objgenerator.c b/py/objgenerator.c index 903a6469cc..8b387d8732 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -243,7 +243,7 @@ STATIC mp_obj_t gen_resume_and_raise(mp_obj_t self_in, mp_obj_t send_value, mp_o if (ret == mp_const_none || ret == MP_OBJ_STOP_ITERATION) { return MP_OBJ_STOP_ITERATION; } else { - nlr_raise(mp_obj_new_exception_args(&mp_type_StopIteration, 1, &ret)); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_StopIteration, ret)); } case MP_VM_RETURN_YIELD: From e2c1226da4ed1498c0373c6a262f0b782600e2fe Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 23 Jan 2020 13:03:00 +1100 Subject: [PATCH 1169/1788] py/objexcept: Optimise mp_obj_new_exception[_arg1/_args] functions. This reduces code size by 10-70 bytes on all ports (except cc3200 which has no change). --- py/objexcept.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/py/objexcept.c b/py/objexcept.c index 869a80bbe7..33ad74ee71 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -304,17 +304,19 @@ MP_DEFINE_EXCEPTION(Exception, BaseException) */ mp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type) { - return mp_obj_new_exception_args(exc_type, 0, NULL); + assert(exc_type->make_new == mp_obj_exception_make_new); + return mp_obj_exception_make_new(exc_type, 0, 0, NULL); } // "Optimized" version for common(?) case of having 1 exception arg mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg) { - return mp_obj_new_exception_args(exc_type, 1, &arg); + assert(exc_type->make_new == mp_obj_exception_make_new); + return mp_obj_exception_make_new(exc_type, 1, 0, &arg); } mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, size_t n_args, const mp_obj_t *args) { assert(exc_type->make_new == mp_obj_exception_make_new); - return exc_type->make_new(exc_type, n_args, 0, args); + return mp_obj_exception_make_new(exc_type, n_args, 0, args); } mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg) { From 27f41e624c39f661f917c20b58daf6637ada0982 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 23 Jan 2020 13:18:34 +1100 Subject: [PATCH 1170/1788] tests/unix: Add coverage test for mp_obj_new_exception_args. Because it's no longer called anywhere in the code. --- ports/unix/coverage.c | 3 +++ tests/unix/extra_coverage.py.exp | 1 + 2 files changed, 4 insertions(+) diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index 233c6211e9..e4d2d68fc9 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -387,6 +387,9 @@ STATIC mp_obj_t extra_coverage(void) { } else { mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); } + + // call mp_obj_new_exception_args (it's a part of the public C API and not used in the core) + mp_obj_print_exception(&mp_plat_print, mp_obj_new_exception_args(&mp_type_ValueError, 0, NULL)); } // warning diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index a41f227be7..9c3b036b93 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -58,6 +58,7 @@ TypeError: unsupported types for __divmod__: 'str', 'str' 2 OverflowError: overflow converting long int to machine word OverflowError: overflow converting long int to machine word +ValueError: Warning: test # format float ? From d9433d3e9497a4ec4cd51eb78d6ca602f310ce91 Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Wed, 22 Jan 2020 13:19:14 +0100 Subject: [PATCH 1171/1788] py/obj.h: Add and use mp_obj_is_bool() helper. Commit d96cfd13e3a464862cecffb2718c6286b52c77b0 introduced a regression in testing for bool objects, that such objects were in some cases no longer recognised and bools, eg when using mp_obj_is_type(o, &mp_type_bool), or mp_obj_is_integer(o). This commit fixes that problem by adding mp_obj_is_bool(o). Builds with MICROPY_OBJ_IMMEDIATE_OBJS enabled check if the object is any of the const True or False objects. Builds without it use the old method of ->type checking, which compiles to smaller code (compared with the former mentioned method). Fixes #5538. --- py/obj.h | 8 +++++++- py/objstr.c | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/py/obj.h b/py/obj.h index ba4f4992ff..b052b9fc8b 100644 --- a/py/obj.h +++ b/py/obj.h @@ -665,6 +665,12 @@ extern const struct _mp_obj_exception_t mp_const_GeneratorExit_obj; // 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 +#if MICROPY_OBJ_IMMEDIATE_OBJS +// bool's are immediates, not real objects, so test for the 2 possible values. +#define mp_obj_is_bool(o) ((o) == mp_const_false || (o) == mp_const_true) +#else +#define mp_obj_is_bool(o) mp_obj_is_type(o, &mp_type_bool) +#endif #define mp_obj_is_int(o) (mp_obj_is_small_int(o) || mp_obj_is_type(o, &mp_type_int)) #define mp_obj_is_str(o) (mp_obj_is_qstr(o) || mp_obj_is_type(o, &mp_type_str)) #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)) @@ -721,7 +727,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 +static inline bool mp_obj_is_integer(mp_const_obj_t o) { return mp_obj_is_int(o) || mp_obj_is_bool(o); } // 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); diff --git a/py/objstr.c b/py/objstr.c index 454d1cbcc5..7e7e86dddc 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -910,7 +910,7 @@ STATIC bool istype(char ch) { } STATIC bool arg_looks_integer(mp_obj_t arg) { - return mp_obj_is_type(arg, &mp_type_bool) || mp_obj_is_int(arg); + return mp_obj_is_bool(arg) || mp_obj_is_int(arg); } STATIC bool arg_looks_numeric(mp_obj_t arg) { From 35e664d7790b123dab54faff766f41991f4620d1 Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Wed, 22 Jan 2020 20:44:52 +0100 Subject: [PATCH 1172/1788] tests/unix: Add coverage tests for mp_obj_is_type() and variants. --- ports/unix/coverage.c | 23 ++++++++++++++++++++++- tests/unix/extra_coverage.py.exp | 8 ++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index e4d2d68fc9..1b6132cddd 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -16,6 +16,8 @@ #include "py/binary.h" #include "py/bc.h" +// expected output of this file is found in extra_coverage.py.exp + #if defined(MICROPY_UNIX_COVERAGE) // stream testing object @@ -539,7 +541,7 @@ STATIC mp_obj_t extra_coverage(void) { ringbuf.iput = 0; ringbuf.iget = 0; mp_printf(&mp_plat_print, "%d\n", ringbuf_get16(&ringbuf)); - + // Two-byte get from ringbuf with one byte available. ringbuf.iput = 0; ringbuf.iget = 0; @@ -576,6 +578,25 @@ STATIC mp_obj_t extra_coverage(void) { pairheap_test(MP_ARRAY_SIZE(t5), t5); } + // mp_obj_is_type and derivatives + { + mp_printf(&mp_plat_print, "# mp_obj_is_type\n"); + + // mp_obj_is_bool accepts only booleans + mp_printf(&mp_plat_print, "%d %d\n", mp_obj_is_bool(mp_const_true), mp_obj_is_bool(mp_const_false)); + mp_printf(&mp_plat_print, "%d %d\n", mp_obj_is_bool(MP_OBJ_NEW_SMALL_INT(1)), mp_obj_is_bool(mp_const_none)); + + // mp_obj_is_integer accepts ints and booleans + mp_printf(&mp_plat_print, "%d %d\n", mp_obj_is_integer(MP_OBJ_NEW_SMALL_INT(1)), mp_obj_is_integer(mp_obj_new_int_from_ll(1))); + mp_printf(&mp_plat_print, "%d %d\n", mp_obj_is_integer(mp_const_true), mp_obj_is_integer(mp_const_false)); + mp_printf(&mp_plat_print, "%d %d\n", mp_obj_is_integer(mp_obj_new_str("1", 1)), mp_obj_is_integer(mp_const_none)); + + // mp_obj_is_int accepts small int and object ints + mp_printf(&mp_plat_print, "%d %d\n", mp_obj_is_int(MP_OBJ_NEW_SMALL_INT(1)), mp_obj_is_int(mp_obj_new_int_from_ll(1))); + } + + mp_printf(&mp_plat_print, "# end coverage.c\n"); + mp_obj_streamtest_t *s = m_new_obj(mp_obj_streamtest_t); s->base.type = &mp_type_stest_fileio; s->buf = NULL; diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index 9c3b036b93..6130a06511 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -115,6 +115,14 @@ create: 1 1 1 1 1 pop all: 1 3 4 create: 3 3 3 1 1 1 pop all: 1 2 4 5 +# mp_obj_is_type +1 1 +0 0 +1 1 +1 1 +0 0 +1 1 +# end coverage.c 0123456789 b'0123456789' 7300 7300 From cb4472df42e6f34df2fe57f4f85786f6669171f7 Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Wed, 22 Jan 2020 20:53:54 +0100 Subject: [PATCH 1173/1788] tests: Add boolean-as-integer formatting tests for fixed regression. As suggested by @dpgeorge in #5538. --- tests/basics/string_format.py | 6 ++++++ tests/basics/string_format_modulo.py | 3 +++ tests/float/string_format.py | 3 +++ 3 files changed, 12 insertions(+) diff --git a/tests/basics/string_format.py b/tests/basics/string_format.py index 8b25924067..e8600f5836 100644 --- a/tests/basics/string_format.py +++ b/tests/basics/string_format.py @@ -63,6 +63,12 @@ test("{:>20}", "foo") test("{:^20}", "foo") test("{:<20}", "foo") +# formatting bool as int +test('{:d}', False) +test('{:20}', False) +test('{:d}', True) +test('{:20}', True) + # nested format specifiers print("{:{}}".format(123, '#>10')) print("{:{}{}{}}".format(123, '#', '>', '10')) diff --git a/tests/basics/string_format_modulo.py b/tests/basics/string_format_modulo.py index 021b5f08d2..01f8e7ed24 100644 --- a/tests/basics/string_format_modulo.py +++ b/tests/basics/string_format_modulo.py @@ -40,6 +40,9 @@ print("%c" % 'a') print("%10s" % 'abc') print("%-10s" % 'abc') +print('%c' % False) +print('%c' % True) + # Should be able to print dicts; in this case they aren't used # to lookup keywords in formats like %(foo)s print('%s' % {}) diff --git a/tests/float/string_format.py b/tests/float/string_format.py index 6fb11c35ac..54f1270773 100644 --- a/tests/float/string_format.py +++ b/tests/float/string_format.py @@ -24,6 +24,9 @@ test("{:06e}", float("inf")) test("{:06e}", float("-inf")) test("{:06e}", float("nan")) +test('{:f}', False) +test('{:f}', True) + # The following fails right now #test("{:10.1}", 0.0) From 96716b46e1c4945d3fe08d9ba91920ca28f9c986 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 24 Jan 2020 11:51:21 +1100 Subject: [PATCH 1174/1788] unix/Makefile: Reserve CFLAGS_EXTRA/LDFLAGS_EXTRA for external use. When CFLAGS_EXTRA/LDFLAGS_EXTRA (or anything) is set on the command line of a make invocation then it will completely override any setting or appending of these variables in the makefile(s). This means builds like the coverage variant will have their mpconfigvariant.mk settings overridden. Fix this by using CFLAGS/LDFLAGS exclusively in the makefile(s), reserving the CFLAGS_EXTRA/LDFLAGS_EXTRA variables for external command-line use only. --- ports/unix/Makefile | 4 ++-- ports/unix/variants/coverage/mpconfigvariant.mk | 4 ++-- ports/unix/variants/freedos/mpconfigvariant.mk | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ports/unix/Makefile b/ports/unix/Makefile index 567b1d5c22..23ea6d1fe5 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -40,7 +40,7 @@ INC += -I$(BUILD) # compiler settings CWARN = -Wall -Werror CWARN += -Wpointer-arith -Wuninitialized -CFLAGS = $(INC) $(CWARN) -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) -I$(VARIANT_DIR) $(CFLAGS_EXTRA) +CFLAGS += $(INC) $(CWARN) -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) -I$(VARIANT_DIR) $(CFLAGS_EXTRA) # Debugging/Optimization ifdef DEBUG @@ -91,7 +91,7 @@ else # Use gcc syntax for map file LDFLAGS_ARCH = -Wl,-Map=$@.map,--cref -Wl,--gc-sections endif -LDFLAGS = $(LDFLAGS_MOD) $(LDFLAGS_ARCH) -lm $(LDFLAGS_EXTRA) +LDFLAGS += $(LDFLAGS_MOD) $(LDFLAGS_ARCH) -lm $(LDFLAGS_EXTRA) # Flags to link with pthread library LIBPTHREAD = -lpthread diff --git a/ports/unix/variants/coverage/mpconfigvariant.mk b/ports/unix/variants/coverage/mpconfigvariant.mk index 077e7e11ac..056a5fd3f1 100644 --- a/ports/unix/variants/coverage/mpconfigvariant.mk +++ b/ports/unix/variants/coverage/mpconfigvariant.mk @@ -2,13 +2,13 @@ PROG ?= micropython-coverage COPT = -O0 -CFLAGS_EXTRA += \ +CFLAGS += \ -fprofile-arcs -ftest-coverage \ -Wdouble-promotion -Wformat -Wmissing-declarations -Wmissing-prototypes -Wsign-compare \ -Wold-style-definition -Wpointer-arith -Wshadow -Wuninitialized -Wunused-parameter \ -DMICROPY_UNIX_COVERAGE -LDFLAGS_EXTRA += -fprofile-arcs -ftest-coverage +LDFLAGS += -fprofile-arcs -ftest-coverage FROZEN_MANIFEST = manifest_coverage.py diff --git a/ports/unix/variants/freedos/mpconfigvariant.mk b/ports/unix/variants/freedos/mpconfigvariant.mk index f7e5ed5162..a30db3e0c1 100644 --- a/ports/unix/variants/freedos/mpconfigvariant.mk +++ b/ports/unix/variants/freedos/mpconfigvariant.mk @@ -4,7 +4,7 @@ STRIP = i586-pc-msdosdjgpp-strip SIZE = i586-pc-msdosdjgpp-size -CFLAGS_EXTRA = \ +CFLAGS += \ -DMICROPY_NLR_SETJMP \ -Dtgamma=gamma \ -DMICROPY_EMIT_X86=0 \ From fee7e5617f55b4778de74ee185fcc3950cdc7b6d Mon Sep 17 00:00:00 2001 From: David Lechner Date: Wed, 22 Jan 2020 18:14:03 -0600 Subject: [PATCH 1175/1788] unix: Release GIL during all system calls. Addition of GIL EXIT/ENTER pairs are: - modos: release the GIL during system calls. CPython does this as well. - moduselect: release the GIL during the poll() syscall. This call can be blocking, so it is important to allow other threads to run at this time. - modusocket: release the GIL during system calls. Many of these calls can be blocking, so it is important to allow other threads to run. - unix_mphal: release the GIL during the read and write syscalls in mp_hal_stdin_rx_chr and mp_hal_stdout_tx_strn. If we don't do this threads are blocked when the REPL or the builtin input function are used. - file, main, mpconfigport.h: release GIL during syscalls in built-in functions that could block. --- ports/unix/file.c | 18 +++++++++++++++- ports/unix/main.c | 2 ++ ports/unix/modos.c | 20 ++++++++++++++++++ ports/unix/moduselect.c | 3 +++ ports/unix/modusocket.c | 43 +++++++++++++++++++++++++++++++++++++-- ports/unix/mpconfigport.h | 7 ++++++- ports/unix/unix_mphal.c | 5 +++++ 7 files changed, 94 insertions(+), 4 deletions(-) diff --git a/ports/unix/file.c b/ports/unix/file.c index 6c6e26b0b2..8a165283f7 100644 --- a/ports/unix/file.c +++ b/ports/unix/file.c @@ -35,6 +35,7 @@ #include "py/stream.h" #include "py/builtin.h" #include "py/mphal.h" +#include "py/mpthread.h" #include "fdfile.h" #if MICROPY_PY_IO && !MICROPY_VFS @@ -65,7 +66,9 @@ STATIC void fdfile_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kin STATIC mp_uint_t fdfile_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { mp_obj_fdfile_t *o = MP_OBJ_TO_PTR(o_in); check_fd_is_open(o); + MP_THREAD_GIL_EXIT(); mp_int_t r = read(o->fd, buf, size); + MP_THREAD_GIL_ENTER(); if (r == -1) { *errcode = errno; return MP_STREAM_ERROR; @@ -82,14 +85,18 @@ STATIC mp_uint_t fdfile_write(mp_obj_t o_in, const void *buf, mp_uint_t size, in return size; } #endif + MP_THREAD_GIL_EXIT(); mp_int_t r = write(o->fd, buf, size); + MP_THREAD_GIL_ENTER(); 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); } + MP_THREAD_GIL_EXIT(); r = write(o->fd, buf, size); + MP_THREAD_GIL_ENTER(); } if (r == -1) { *errcode = errno; @@ -104,7 +111,9 @@ STATIC mp_uint_t fdfile_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, i switch (request) { case MP_STREAM_SEEK: { struct mp_stream_seek_t *s = (struct mp_stream_seek_t*)arg; + MP_THREAD_GIL_EXIT(); off_t off = lseek(o->fd, s->offset, s->whence); + MP_THREAD_GIL_ENTER(); if (off == (off_t)-1) { *errcode = errno; return MP_STREAM_ERROR; @@ -113,13 +122,18 @@ STATIC mp_uint_t fdfile_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, i return 0; } case MP_STREAM_FLUSH: - if (fsync(o->fd) < 0) { + MP_THREAD_GIL_EXIT(); + int ret = fsync(o->fd); + MP_THREAD_GIL_ENTER(); + if (ret == -1) { *errcode = errno; return MP_STREAM_ERROR; } return 0; case MP_STREAM_CLOSE: + MP_THREAD_GIL_EXIT(); close(o->fd); + MP_THREAD_GIL_ENTER(); #ifdef MICROPY_CPYTHON_COMPAT o->fd = -1; #endif @@ -198,7 +212,9 @@ STATIC mp_obj_t fdfile_open(const mp_obj_type_t *type, mp_arg_val_t *args) { } const char *fname = mp_obj_str_get_str(fid); + MP_THREAD_GIL_EXIT(); int fd = open(fname, mode_x | mode_rw, 0644); + MP_THREAD_GIL_ENTER(); if (fd == -1) { mp_raise_OSError(errno); } diff --git a/ports/unix/main.c b/ports/unix/main.c index 9147feb32d..fcf8b1558c 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -64,7 +64,9 @@ long heap_size = 1024*1024 * (sizeof(mp_uint_t) / 4); STATIC void stderr_print_strn(void *env, const char *str, size_t len) { (void)env; + MP_THREAD_GIL_EXIT(); ssize_t dummy = write(STDERR_FILENO, str, len); + MP_THREAD_GIL_ENTER(); mp_uos_dupterm_tx_strn(str, len); (void)dummy; } diff --git a/ports/unix/modos.c b/ports/unix/modos.c index c3b0c20b2b..e5bd5da1eb 100644 --- a/ports/unix/modos.c +++ b/ports/unix/modos.c @@ -38,6 +38,7 @@ #include "py/runtime.h" #include "py/objtuple.h" #include "py/mphal.h" +#include "py/mpthread.h" #include "extmod/vfs.h" #include "extmod/misc.h" @@ -49,7 +50,9 @@ STATIC mp_obj_t mod_os_stat(mp_obj_t path_in) { struct stat sb; const char *path = mp_obj_str_get_str(path_in); + MP_THREAD_GIL_EXIT(); int res = stat(path, &sb); + MP_THREAD_GIL_ENTER(); RAISE_ERRNO(res, errno); mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); @@ -89,7 +92,9 @@ STATIC mp_obj_t mod_os_statvfs(mp_obj_t path_in) { STRUCT_STATVFS sb; const char *path = mp_obj_str_get_str(path_in); + MP_THREAD_GIL_EXIT(); int res = STATVFS(path, &sb); + MP_THREAD_GIL_ENTER(); RAISE_ERRNO(res, errno); mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); @@ -116,7 +121,9 @@ STATIC mp_obj_t mod_os_remove(mp_obj_t path_in) { // of that function. But Python remove() follows ANSI C, and explicitly // required to raise exception on attempt to remove a directory. Thus, // call POSIX unlink() here. + MP_THREAD_GIL_EXIT(); int r = unlink(path); + MP_THREAD_GIL_ENTER(); RAISE_ERRNO(r, errno); @@ -128,7 +135,9 @@ STATIC mp_obj_t mod_os_rename(mp_obj_t old_path_in, mp_obj_t new_path_in) { const char *old_path = mp_obj_str_get_str(old_path_in); const char *new_path = mp_obj_str_get_str(new_path_in); + MP_THREAD_GIL_EXIT(); int r = rename(old_path, new_path); + MP_THREAD_GIL_ENTER(); RAISE_ERRNO(r, errno); @@ -139,7 +148,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_os_rename_obj, mod_os_rename); STATIC mp_obj_t mod_os_rmdir(mp_obj_t path_in) { const char *path = mp_obj_str_get_str(path_in); + MP_THREAD_GIL_EXIT(); int r = rmdir(path); + MP_THREAD_GIL_ENTER(); RAISE_ERRNO(r, errno); @@ -150,7 +161,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_os_rmdir_obj, mod_os_rmdir); STATIC mp_obj_t mod_os_system(mp_obj_t cmd_in) { const char *cmd = mp_obj_str_get_str(cmd_in); + MP_THREAD_GIL_EXIT(); int r = system(cmd); + MP_THREAD_GIL_ENTER(); RAISE_ERRNO(r, errno); @@ -170,11 +183,13 @@ 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 const char *path = mp_obj_str_get_str(path_in); + MP_THREAD_GIL_EXIT(); #ifdef _WIN32 int r = mkdir(path); #else int r = mkdir(path, 0777); #endif + MP_THREAD_GIL_ENTER(); RAISE_ERRNO(r, errno); return mp_const_none; } @@ -192,13 +207,16 @@ STATIC mp_obj_t listdir_next(mp_obj_t self_in) { if (self->dir == NULL) { goto done; } + MP_THREAD_GIL_EXIT(); struct dirent *dirent = readdir(self->dir); if (dirent == NULL) { closedir(self->dir); + MP_THREAD_GIL_ENTER(); self->dir = NULL; done: return MP_OBJ_STOP_ITERATION; } + MP_THREAD_GIL_ENTER(); 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)); @@ -235,7 +253,9 @@ STATIC mp_obj_t mod_os_ilistdir(size_t n_args, const mp_obj_t *args) { } mp_obj_listdir_t *o = m_new_obj(mp_obj_listdir_t); o->base.type = &mp_type_polymorph_iter; + MP_THREAD_GIL_EXIT(); o->dir = opendir(path); + MP_THREAD_GIL_ENTER(); o->iternext = listdir_next; return MP_OBJ_FROM_PTR(o); } diff --git a/ports/unix/moduselect.c b/ports/unix/moduselect.c index d9b02ddc62..4a095ec292 100644 --- a/ports/unix/moduselect.c +++ b/ports/unix/moduselect.c @@ -39,6 +39,7 @@ #include "py/objlist.h" #include "py/objtuple.h" #include "py/mphal.h" +#include "py/mpthread.h" #include "fdfile.h" #define DEBUG 0 @@ -188,7 +189,9 @@ STATIC int poll_poll_internal(size_t n_args, const mp_obj_t *args) { self->flags = flags; + MP_THREAD_GIL_EXIT(); int n_ready = poll(self->entries, self->len, timeout); + MP_THREAD_GIL_ENTER(); RAISE_ERRNO(n_ready, errno); return n_ready; } diff --git a/ports/unix/modusocket.c b/ports/unix/modusocket.c index 9b82378bb4..b436ddf7fc 100644 --- a/ports/unix/modusocket.c +++ b/ports/unix/modusocket.c @@ -45,6 +45,7 @@ #include "py/stream.h" #include "py/builtin.h" #include "py/mphal.h" +#include "py/mpthread.h" /* The idea of this module is to implement reasonable minimum of @@ -93,7 +94,9 @@ STATIC void socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kin STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { mp_obj_socket_t *o = MP_OBJ_TO_PTR(o_in); + MP_THREAD_GIL_EXIT(); mp_int_t r = read(o->fd, buf, size); + MP_THREAD_GIL_ENTER(); if (r == -1) { int err = errno; // On blocking socket, we get EAGAIN in case SO_RCVTIMEO/SO_SNDTIMEO @@ -110,7 +113,9 @@ STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errc STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) { mp_obj_socket_t *o = MP_OBJ_TO_PTR(o_in); + MP_THREAD_GIL_EXIT(); mp_int_t r = write(o->fd, buf, size); + MP_THREAD_GIL_ENTER(); if (r == -1) { int err = errno; // On blocking socket, we get EAGAIN in case SO_RCVTIMEO/SO_SNDTIMEO @@ -137,7 +142,9 @@ STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, i // 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. + MP_THREAD_GIL_EXIT(); close(self->fd); + MP_THREAD_GIL_ENTER(); return 0; case MP_STREAM_GET_FILENO: @@ -159,7 +166,9 @@ STATIC mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in); mp_buffer_info_t bufinfo; mp_get_buffer_raise(addr_in, &bufinfo, MP_BUFFER_READ); + MP_THREAD_GIL_EXIT(); int r = connect(self->fd, (const struct sockaddr *)bufinfo.buf, bufinfo.len); + MP_THREAD_GIL_ENTER(); int err = errno; if (r == -1 && self->blocking && err == EINPROGRESS) { // EINPROGRESS on a blocking socket means the operation timed out @@ -174,7 +183,9 @@ STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in); mp_buffer_info_t bufinfo; mp_get_buffer_raise(addr_in, &bufinfo, MP_BUFFER_READ); + MP_THREAD_GIL_EXIT(); int r = bind(self->fd, (const struct sockaddr *)bufinfo.buf, bufinfo.len); + MP_THREAD_GIL_ENTER(); RAISE_ERRNO(r, errno); return mp_const_none; } @@ -182,7 +193,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind); STATIC mp_obj_t socket_listen(mp_obj_t self_in, mp_obj_t backlog_in) { mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in); + MP_THREAD_GIL_EXIT(); int r = listen(self->fd, MP_OBJ_SMALL_INT_VALUE(backlog_in)); + MP_THREAD_GIL_ENTER(); RAISE_ERRNO(r, errno); return mp_const_none; } @@ -194,7 +207,9 @@ STATIC mp_obj_t socket_accept(mp_obj_t self_in) { //struct sockaddr_storage addr; byte addr[32]; socklen_t addr_len = sizeof(addr); + MP_THREAD_GIL_EXIT(); int fd = accept(self->fd, (struct sockaddr*)&addr, &addr_len); + MP_THREAD_GIL_ENTER(); int err = errno; if (fd == -1 && self->blocking && err == EAGAIN) { // EAGAIN on a blocking socket means the operation timed out @@ -223,7 +238,9 @@ STATIC mp_obj_t socket_recv(size_t n_args, const mp_obj_t *args) { } byte *buf = m_new(byte, sz); + MP_THREAD_GIL_EXIT(); int out_sz = recv(self->fd, buf, sz, flags); + MP_THREAD_GIL_ENTER(); RAISE_ERRNO(out_sz, errno); mp_obj_t ret = mp_obj_new_str_of_type(&mp_type_bytes, buf, out_sz); @@ -245,7 +262,9 @@ STATIC mp_obj_t socket_recvfrom(size_t n_args, const mp_obj_t *args) { socklen_t addr_len = sizeof(addr); byte *buf = m_new(byte, sz); + MP_THREAD_GIL_EXIT(); int out_sz = recvfrom(self->fd, buf, sz, flags, (struct sockaddr*)&addr, &addr_len); + MP_THREAD_GIL_ENTER(); RAISE_ERRNO(out_sz, errno); mp_obj_t buf_o = mp_obj_new_str_of_type(&mp_type_bytes, buf, out_sz); @@ -272,7 +291,9 @@ STATIC mp_obj_t socket_send(size_t n_args, const mp_obj_t *args) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); + MP_THREAD_GIL_EXIT(); int out_sz = send(self->fd, bufinfo.buf, bufinfo.len, flags); + MP_THREAD_GIL_ENTER(); RAISE_ERRNO(out_sz, errno); return MP_OBJ_NEW_SMALL_INT(out_sz); @@ -292,8 +313,10 @@ STATIC mp_obj_t socket_sendto(size_t n_args, const mp_obj_t *args) { mp_buffer_info_t bufinfo, addr_bi; mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); mp_get_buffer_raise(dst_addr, &addr_bi, MP_BUFFER_READ); + MP_THREAD_GIL_EXIT(); int out_sz = sendto(self->fd, bufinfo.buf, bufinfo.len, flags, (struct sockaddr *)addr_bi.buf, addr_bi.len); + MP_THREAD_GIL_ENTER(); RAISE_ERRNO(out_sz, errno); return MP_OBJ_NEW_SMALL_INT(out_sz); @@ -319,7 +342,9 @@ STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) { optval = bufinfo.buf; optlen = bufinfo.len; } + MP_THREAD_GIL_EXIT(); int r = setsockopt(self->fd, level, option, optval, optlen); + MP_THREAD_GIL_ENTER(); RAISE_ERRNO(r, errno); return mp_const_none; } @@ -328,14 +353,19 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_s STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) { mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in); int val = mp_obj_is_true(flag_in); + MP_THREAD_GIL_EXIT(); int flags = fcntl(self->fd, F_GETFL, 0); - RAISE_ERRNO(flags, errno); + if (flags == -1) { + MP_THREAD_GIL_ENTER(); + RAISE_ERRNO(flags, errno); + } if (val) { flags &= ~O_NONBLOCK; } else { flags |= O_NONBLOCK; } flags = fcntl(self->fd, F_SETFL, flags); + MP_THREAD_GIL_ENTER(); RAISE_ERRNO(flags, errno); self->blocking = val; return mp_const_none; @@ -368,9 +398,14 @@ STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) { if (new_blocking) { int r; + MP_THREAD_GIL_EXIT(); r = setsockopt(self->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval)); - RAISE_ERRNO(r, errno); + if (r == -1) { + MP_THREAD_GIL_ENTER(); + RAISE_ERRNO(r, errno); + } r = setsockopt(self->fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(struct timeval)); + MP_THREAD_GIL_ENTER(); RAISE_ERRNO(r, errno); } @@ -415,7 +450,9 @@ STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type_in, size_t n_args, siz } } + MP_THREAD_GIL_EXIT(); int fd = socket(family, type, proto); + MP_THREAD_GIL_ENTER(); RAISE_ERRNO(fd, errno); return MP_OBJ_FROM_PTR(socket_new(fd)); } @@ -537,7 +574,9 @@ STATIC mp_obj_t mod_socket_getaddrinfo(size_t n_args, const mp_obj_t *args) { } struct addrinfo *addr_list; + MP_THREAD_GIL_EXIT(); int res = getaddrinfo(host, serv, &hints, &addr_list); + MP_THREAD_GIL_ENTER(); if (res != 0) { // CPython: socket.gaierror diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h index f435c3ff3c..2f01aff0f9 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -285,7 +285,12 @@ void mp_unix_mark_exec(void); #if MICROPY_PY_OS_DUPTERM #define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) #else -#define MP_PLAT_PRINT_STRN(str, len) do { ssize_t ret = write(1, str, len); (void)ret; } while (0) +#define MP_PLAT_PRINT_STRN(str, len) do { \ + MP_THREAD_GIL_EXIT(); \ + ssize_t ret = write(1, str, len); \ + MP_THREAD_GIL_ENTER(); \ + (void)ret; \ +} while (0) #endif #ifdef __linux__ diff --git a/ports/unix/unix_mphal.c b/ports/unix/unix_mphal.c index 9b009dc502..3e14409efb 100644 --- a/ports/unix/unix_mphal.c +++ b/ports/unix/unix_mphal.c @@ -31,6 +31,7 @@ #include #include "py/mphal.h" +#include "py/mpthread.h" #include "py/runtime.h" #include "extmod/misc.h" @@ -160,7 +161,9 @@ int mp_hal_stdin_rx_chr(void) { } else { main_term:; #endif + MP_THREAD_GIL_EXIT(); int ret = read(0, &c, 1); + MP_THREAD_GIL_ENTER(); if (ret == 0) { c = 4; // EOF, ctrl-D } else if (c == '\n') { @@ -173,7 +176,9 @@ int mp_hal_stdin_rx_chr(void) { } void mp_hal_stdout_tx_strn(const char *str, size_t len) { + MP_THREAD_GIL_EXIT(); int ret = write(1, str, len); + MP_THREAD_GIL_ENTER(); mp_uos_dupterm_tx_strn(str, len); (void)ret; // to suppress compiler warning } From 35f66d38b8e153399b5d277b6e02ea1a98eccee1 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 23 Jan 2020 21:50:53 -0600 Subject: [PATCH 1176/1788] extmod/vfs_posix: Release GIL during system calls. This releases the GIL during syscalls that could block. --- extmod/vfs_posix.c | 20 ++++++++++++++++++-- extmod/vfs_posix_file.c | 16 +++++++++++++++- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/extmod/vfs_posix.c b/extmod/vfs_posix.c index d943e0c803..22471e48f3 100644 --- a/extmod/vfs_posix.c +++ b/extmod/vfs_posix.c @@ -26,6 +26,7 @@ #include "py/runtime.h" #include "py/mperrno.h" +#include "py/mpthread.h" #include "extmod/vfs.h" #include "extmod/vfs_posix.h" @@ -170,12 +171,15 @@ STATIC mp_obj_t vfs_posix_ilistdir_it_iternext(mp_obj_t self_in) { } for (;;) { + MP_THREAD_GIL_EXIT(); struct dirent *dirent = readdir(self->dir); if (dirent == NULL) { closedir(self->dir); + MP_THREAD_GIL_ENTER(); self->dir = NULL; return MP_OBJ_STOP_ITERATION; } + MP_THREAD_GIL_ENTER(); const char *fn = dirent->d_name; if (fn[0] == '.' && (fn[1] == 0 || fn[1] == '.')) { @@ -229,7 +233,9 @@ STATIC mp_obj_t vfs_posix_ilistdir(mp_obj_t self_in, mp_obj_t path_in) { if (path[0] == '\0') { path = "."; } + MP_THREAD_GIL_EXIT(); iter->dir = opendir(path); + MP_THREAD_GIL_ENTER(); if (iter->dir == NULL) { mp_raise_OSError(errno); } @@ -245,7 +251,10 @@ typedef struct _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); + const char *path = vfs_posix_get_path_str(self, path_in); + MP_THREAD_GIL_EXIT(); + int ret = mkdir(path, 0777); + MP_THREAD_GIL_ENTER(); if (ret != 0) { mp_raise_OSError(errno); } @@ -262,7 +271,9 @@ STATIC mp_obj_t vfs_posix_rename(mp_obj_t self_in, mp_obj_t old_path_in, mp_obj_ 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); + MP_THREAD_GIL_EXIT(); int ret = rename(old_path, new_path); + MP_THREAD_GIL_ENTER(); if (ret != 0) { mp_raise_OSError(errno); } @@ -278,7 +289,10 @@ 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); + const char *path = vfs_posix_get_path_str(self, path_in); + MP_THREAD_GIL_EXIT(); + int ret = stat(path, &sb); + MP_THREAD_GIL_ENTER(); if (ret != 0) { mp_raise_OSError(errno); } @@ -321,7 +335,9 @@ 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); + MP_THREAD_GIL_EXIT(); int ret = STATVFS(path, &sb); + MP_THREAD_GIL_ENTER(); if (ret != 0) { mp_raise_OSError(errno); } diff --git a/extmod/vfs_posix_file.c b/extmod/vfs_posix_file.c index 87c202e3b0..c817e51b8b 100644 --- a/extmod/vfs_posix_file.c +++ b/extmod/vfs_posix_file.c @@ -24,6 +24,7 @@ * THE SOFTWARE. */ +#include "py/mpthread.h" #include "py/runtime.h" #include "py/stream.h" #include "extmod/vfs_posix.h" @@ -100,7 +101,9 @@ mp_obj_t mp_vfs_posix_file_open(const mp_obj_type_t *type, mp_obj_t file_in, mp_ } const char *fname = mp_obj_str_get_str(fid); + MP_THREAD_GIL_EXIT(); int fd = open(fname, mode_x | mode_rw, 0644); + MP_THREAD_GIL_ENTER(); if (fd == -1) { mp_raise_OSError(errno); } @@ -135,7 +138,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(vfs_posix_file___exit___obj, 4, 4, vf 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_THREAD_GIL_EXIT(); mp_int_t r = read(o->fd, buf, size); + MP_THREAD_GIL_ENTER(); if (r == -1) { *errcode = errno; return MP_STREAM_ERROR; @@ -159,7 +164,9 @@ STATIC mp_uint_t vfs_posix_file_write(mp_obj_t o_in, const void *buf, mp_uint_t MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; nlr_raise(obj); } + MP_THREAD_GIL_EXIT(); r = write(o->fd, buf, size); + MP_THREAD_GIL_ENTER(); } if (r == -1) { *errcode = errno; @@ -173,14 +180,19 @@ STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_ check_fd_is_open(o); switch (request) { case MP_STREAM_FLUSH: - if (fsync(o->fd) < 0) { + MP_THREAD_GIL_EXIT(); + int ret = fsync(o->fd); + MP_THREAD_GIL_ENTER(); + if (ret == -1) { *errcode = errno; return MP_STREAM_ERROR; } return 0; case MP_STREAM_SEEK: { struct mp_stream_seek_t *s = (struct mp_stream_seek_t*)arg; + MP_THREAD_GIL_EXIT(); off_t off = lseek(o->fd, s->offset, s->whence); + MP_THREAD_GIL_ENTER(); if (off == (off_t)-1) { *errcode = errno; return MP_STREAM_ERROR; @@ -189,7 +201,9 @@ STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_ return 0; } case MP_STREAM_CLOSE: + MP_THREAD_GIL_EXIT(); close(o->fd); + MP_THREAD_GIL_ENTER(); #ifdef MICROPY_CPYTHON_COMPAT o->fd = -1; #endif From 62537a18e3743a040e8b673686665f27f7504ca8 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 24 Jan 2020 11:50:31 -0600 Subject: [PATCH 1177/1788] py: Release GIL during syscalls in reader and writer code. This releases the GIL during POSIX system calls that could block. --- py/persistentcode.c | 7 +++++++ py/reader.c | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/py/persistentcode.c b/py/persistentcode.c index 7a8a94b5a6..7039f9f57a 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -34,6 +34,7 @@ #include "py/persistentcode.h" #include "py/bc0.h" #include "py/objstr.h" +#include "py/mpthread.h" #if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE @@ -821,15 +822,21 @@ void mp_raw_code_save(mp_raw_code_t *rc, mp_print_t *print) { STATIC void fd_print_strn(void *env, const char *str, size_t len) { int fd = (intptr_t)env; + MP_THREAD_GIL_EXIT(); ssize_t ret = write(fd, str, len); + MP_THREAD_GIL_ENTER(); (void)ret; } void mp_raw_code_save_file(mp_raw_code_t *rc, const char *filename) { + MP_THREAD_GIL_EXIT(); int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); + MP_THREAD_GIL_ENTER(); mp_print_t fd_print = {(void*)(intptr_t)fd, fd_print_strn}; mp_raw_code_save(rc, &fd_print); + MP_THREAD_GIL_EXIT(); close(fd); + MP_THREAD_GIL_ENTER(); } #else diff --git a/py/reader.c b/py/reader.c index 80364104bb..d99dfc5672 100644 --- a/py/reader.c +++ b/py/reader.c @@ -29,6 +29,7 @@ #include "py/runtime.h" #include "py/mperrno.h" +#include "py/mpthread.h" #include "py/reader.h" typedef struct _mp_reader_mem_t { @@ -86,7 +87,9 @@ STATIC mp_uint_t mp_reader_posix_readbyte(void *data) { if (reader->len == 0) { return MP_READER_EOF; } else { + MP_THREAD_GIL_EXIT(); int n = read(reader->fd, reader->buf, sizeof(reader->buf)); + MP_THREAD_GIL_ENTER(); if (n <= 0) { reader->len = 0; return MP_READER_EOF; @@ -101,7 +104,9 @@ STATIC mp_uint_t mp_reader_posix_readbyte(void *data) { STATIC void mp_reader_posix_close(void *data) { mp_reader_posix_t *reader = (mp_reader_posix_t*)data; if (reader->close_fd) { + MP_THREAD_GIL_EXIT(); close(reader->fd); + MP_THREAD_GIL_ENTER(); } m_del_obj(mp_reader_posix_t, reader); } @@ -110,13 +115,16 @@ void mp_reader_new_file_from_fd(mp_reader_t *reader, int fd, bool close_fd) { mp_reader_posix_t *rp = m_new_obj(mp_reader_posix_t); rp->close_fd = close_fd; rp->fd = fd; + MP_THREAD_GIL_EXIT(); int n = read(rp->fd, rp->buf, sizeof(rp->buf)); if (n == -1) { if (close_fd) { close(fd); } + MP_THREAD_GIL_ENTER(); mp_raise_OSError(errno); } + MP_THREAD_GIL_ENTER(); rp->len = n; rp->pos = 0; reader->data = rp; @@ -127,7 +135,9 @@ void mp_reader_new_file_from_fd(mp_reader_t *reader, int fd, bool close_fd) { #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) { + MP_THREAD_GIL_EXIT(); int fd = open(filename, O_RDONLY, 0644); + MP_THREAD_GIL_ENTER(); if (fd < 0) { mp_raise_OSError(errno); } From bc3499f0103abcae39ad048bb42a518a665b8497 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 24 Jan 2020 11:50:31 -0600 Subject: [PATCH 1178/1788] windows/windows_mphal: Release GIL during system calls. This releases the GIL during syscalls that could block. --- ports/windows/windows_mphal.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ports/windows/windows_mphal.c b/ports/windows/windows_mphal.c index 1ec8e27d6a..6de888085f 100644 --- a/ports/windows/windows_mphal.c +++ b/ports/windows/windows_mphal.c @@ -27,6 +27,7 @@ #include "py/mpstate.h" #include "py/mphal.h" +#include "py/mpthread.h" #include #include @@ -194,10 +195,14 @@ int mp_hal_stdin_rx_chr(void) { // poll until key which we handle is pressed assure_stdin_handle(); + BOOL status; DWORD num_read; INPUT_RECORD rec; for (;;) { - if (!ReadConsoleInput(std_in, &rec, 1, &num_read) || !num_read) { + MP_THREAD_GIL_EXIT(); + status = ReadConsoleInput(std_in, &rec, 1, &num_read) + MP_THREAD_GIL_ENTER(); + if (!status || !num_read) { return CHAR_CTRL_C; // EOF, ctrl-D } if (rec.EventType != KEY_EVENT || !rec.Event.KeyEvent.bKeyDown) { // only want key down events @@ -217,7 +222,9 @@ int mp_hal_stdin_rx_chr(void) { } void mp_hal_stdout_tx_strn(const char *str, size_t len) { + MP_THREAD_GIL_EXIT(); write(1, str, len); + MP_THREAD_GIL_ENTER(); } void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) { From d89ed3e62b152174c3eb5c96713e9b983b11f7ed Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 23 Jan 2020 14:11:13 -0600 Subject: [PATCH 1179/1788] unix/unix_mphal: Add compile check for incompatible GIL+ASYNC_KBD_INTR. It is not safe to enable MICROPY_ASYNC_KBD_INTR and MICROPY_PY_THREAD_GIL at the same time. This will trigger a compiler error to ensure that it is not possible to make this mistake. --- ports/unix/unix_mphal.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ports/unix/unix_mphal.c b/ports/unix/unix_mphal.c index 3e14409efb..25d1b022db 100644 --- a/ports/unix/unix_mphal.c +++ b/ports/unix/unix_mphal.c @@ -41,6 +41,11 @@ STATIC void sighandler(int signum) { if (signum == SIGINT) { #if MICROPY_ASYNC_KBD_INTR + #if MICROPY_PY_THREAD_GIL + // Since signals can occur at any time, we may not be holding the GIL when + // this callback is called, so it is not safe to raise an exception here + #error "MICROPY_ASYNC_KBD_INTR and MICROPY_PY_THREAD_GIL are not compatible" + #endif mp_obj_exception_clear_traceback(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception))); sigset_t mask; sigemptyset(&mask); From 1f4b607116ea0f06111847510ba5b1cd8080bf7f Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Fri, 24 Jan 2020 18:07:32 +1100 Subject: [PATCH 1180/1788] tests: Add tests for generator throw and yield-from with exc handlers. This commit adds a generator test for throwing into a nested exception, and one when using yield-from with a pending exception cleanup. Both these tests currently fail on the native emitter, and are simplified versions of native test failures from uasyncio in #5332. --- tests/basics/gen_yield_from_pending.py | 23 ++++++++++++++++++ tests/basics/generator_throw_nested.py | 33 ++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 tests/basics/gen_yield_from_pending.py create mode 100644 tests/basics/generator_throw_nested.py diff --git a/tests/basics/gen_yield_from_pending.py b/tests/basics/gen_yield_from_pending.py new file mode 100644 index 0000000000..eb88ee6ca7 --- /dev/null +++ b/tests/basics/gen_yield_from_pending.py @@ -0,0 +1,23 @@ +# Tests that the pending exception state is managed correctly +# (previously failed on native emitter). + +def noop_task(): + print('noop task') + yield 1 + +def raise_task(): + print('raise task') + yield 2 + print('raising') + raise Exception + +def main(): + try: + yield from raise_task() + except: + print('main exception') + + yield from noop_task() + +for z in main(): + print('outer iter', z) diff --git a/tests/basics/generator_throw_nested.py b/tests/basics/generator_throw_nested.py new file mode 100644 index 0000000000..5ef1668788 --- /dev/null +++ b/tests/basics/generator_throw_nested.py @@ -0,0 +1,33 @@ +# Tests that the correct nested exception handler is used when +# throwing into a generator (previously failed on native emitter). + +def gen(): + try: + yield 1 + try: + yield 2 + try: + yield 3 + except Exception: + yield 4 + print(0) + yield 5 + except Exception: + yield 6 + print(1) + yield 7 + except Exception: + yield 8 + print(2) + yield 9 + +for i in range(1, 10): + g = gen() + try: + for _ in range(i): + print(next(g)) + print(g.throw(ValueError)) + except ValueError: + print('ValueError') + except StopIteration: + print('StopIteration') From 0de304e7dabbee443dd96935a8045a227eba455b Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Fri, 24 Jan 2020 18:01:20 +1100 Subject: [PATCH 1181/1788] py/emitnative: Use NULL for pending exception (not None). This previously made the native emitter incompatible with the bytecode emitter, and mp_resume (and subsequently mp_obj_generator_resume) expects the bytecode emitter behavior (i.e. throw==NULL). --- py/emitnative.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/py/emitnative.c b/py/emitnative.c index 07b984b780..0affbeb0b2 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -2058,7 +2058,7 @@ STATIC void emit_native_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t exc ASM_MOV_REG_PCREL(emit->as, REG_RET, label & ~MP_EMIT_BREAK_FROM_FOR); ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_UNWIND(emit), REG_RET); // Cancel any active exception (see also emit_native_pop_except_jump) - emit_native_mov_reg_const(emit, REG_RET, MP_F_CONST_NONE_OBJ); + ASM_MOV_REG_IMM(emit->as, REG_RET, (mp_uint_t)MP_OBJ_NULL); ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_RET); // Jump to the innermost active finally label = first_finally->label; @@ -2153,9 +2153,8 @@ STATIC void emit_native_with_cleanup(emit_t *emit, mp_uint_t label) { ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_EXC_VAL(emit)); // get exc - // Check if exc is None and jump to non-exc handler if it is - emit_native_mov_reg_const(emit, REG_ARG_2, MP_F_CONST_NONE_OBJ); - ASM_JUMP_IF_REG_EQ(emit->as, REG_ARG_1, REG_ARG_2, *emit->label_slot + 2); + // Check if exc is MP_OBJ_NULL (i.e. zero) and jump to non-exc handler if it is + ASM_JUMP_IF_REG_ZERO(emit->as, REG_ARG_1, *emit->label_slot + 2, false); ASM_LOAD_REG_REG_OFFSET(emit->as, REG_ARG_2, REG_ARG_1, 0); // get type(exc) emit_post_push_reg(emit, VTYPE_PYOBJ, REG_ARG_2); // push type(exc) @@ -2175,9 +2174,9 @@ STATIC void emit_native_with_cleanup(emit_t *emit, mp_uint_t label) { emit_call(emit, MP_F_OBJ_IS_TRUE); ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, *emit->label_slot + 1, true); - // Replace exception with None + // Replace exception with MP_OBJ_NULL. emit_native_label_assign(emit, *emit->label_slot); - emit_native_mov_reg_const(emit, REG_TEMP0, MP_F_CONST_NONE_OBJ); + ASM_MOV_REG_IMM(emit->as, REG_TEMP0, (mp_uint_t)MP_OBJ_NULL); ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_TEMP0); // end of with cleanup nlr_catch block @@ -2255,7 +2254,7 @@ STATIC void emit_native_for_iter_end(emit_t *emit) { STATIC void emit_native_pop_except_jump(emit_t *emit, mp_uint_t label, bool within_exc_handler) { if (within_exc_handler) { // Cancel any active exception so subsequent handlers don't see it - emit_native_mov_reg_const(emit, REG_TEMP0, MP_F_CONST_NONE_OBJ); + ASM_MOV_REG_IMM(emit->as, REG_TEMP0, (mp_uint_t)MP_OBJ_NULL); ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_TEMP0); } else { emit_native_leave_exc_stack(emit, false); From 888ddb81ddfe9cd43991f8054967a0f0d5911cf1 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Fri, 24 Jan 2020 18:01:55 +1100 Subject: [PATCH 1182/1788] py/emitnative: Stop after finding an unwind target. The loop searches backwards for a target, but doesn't stop after finding the first result, meaning that it'll always end up at the outermost exception handler. --- py/emitnative.c | 1 + 1 file changed, 1 insertion(+) diff --git a/py/emitnative.c b/py/emitnative.c index 0affbeb0b2..d0252560fe 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -2774,6 +2774,7 @@ STATIC void emit_native_yield(emit_t *emit, int kind) { // Found active handler, get its PC ASM_MOV_REG_PCREL(emit->as, REG_RET, e->label); ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_PC(emit), REG_RET); + break; } } } From c3095b37e96aeb69564f53d30a12242ab42bbd02 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Fri, 24 Jan 2020 18:04:51 +1100 Subject: [PATCH 1183/1788] py/nativeglue: Fix typo about where the native fun table enum is. --- py/nativeglue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/nativeglue.c b/py/nativeglue.c index 9be7449d20..2e0ac56ca5 100644 --- a/py/nativeglue.c +++ b/py/nativeglue.c @@ -253,7 +253,7 @@ STATIC double mp_obj_get_float_to_d(mp_obj_t o) { #endif -// these must correspond to the respective enum in runtime0.h +// these must correspond to the respective enum in nativeglue.h const mp_fun_table_t mp_fun_table = { mp_const_none, mp_const_false, From a542c6d7e0340e5ff5364426131bdbd69a64e746 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 29 Jan 2020 16:49:13 +1100 Subject: [PATCH 1184/1788] stm32/powerctrl: For F7, allow PLLM!=HSE when setting PLLSAI to 48MHz. PLLM is shared among all PLL blocks on F7 MCUs, and this calculation to configure PLLSAI to have 48MHz on the P output previously assumed that PLLM is equal to HSE (eg PLLM=25 for HSE=25MHz). This commit relaxes this assumption to allow other values of PLLM. --- ports/stm32/powerctrl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c index dfd9e8262d..1d1792c386 100644 --- a/ports/stm32/powerctrl.c +++ b/ports/stm32/powerctrl.c @@ -94,9 +94,11 @@ int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk if (need_pllsai) { // Configure PLLSAI at 48MHz for those peripherals that need this freq - const uint32_t pllsain = 192; + // (calculation assumes it can get an integral value of PLLSAIN) + const uint32_t pllm = (RCC->PLLCFGR >> RCC_PLLCFGR_PLLM_Pos) & 0x3f; const uint32_t pllsaip = 4; const uint32_t pllsaiq = 2; + const uint32_t pllsain = 48 * pllsaip * pllm / (HSE_VALUE / 1000000); RCC->PLLSAICFGR = pllsaiq << RCC_PLLSAICFGR_PLLSAIQ_Pos | (pllsaip / 2 - 1) << RCC_PLLSAICFGR_PLLSAIP_Pos | pllsain << RCC_PLLSAICFGR_PLLSAIN_Pos; From b72cb0ca1bb27396a5dcba9ce8a6f00dbd3d5f19 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 24 Jan 2020 11:37:53 -0600 Subject: [PATCH 1185/1788] py/mpthread.h: Use strong type for mp_thread_set_state() argument. This modifies the signature of mp_thread_set_state() to use mp_state_thread_t* instead of void*. This matches the return type of mp_thread_get_state(), which returns the same value. `struct _mp_state_thread_t;` had to be moved before `#include ` since the stm32 port uses it in its mpthreadport.h file. --- ports/cc3200/mpthreadport.c | 2 +- ports/esp32/mpthreadport.c | 2 +- ports/stm32/mpthreadport.h | 2 +- ports/unix/mpthreadport.c | 2 +- py/mpthread.h | 6 +++--- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ports/cc3200/mpthreadport.c b/ports/cc3200/mpthreadport.c index 9dbc518e06..f2fc76bdb0 100644 --- a/ports/cc3200/mpthreadport.c +++ b/ports/cc3200/mpthreadport.c @@ -85,7 +85,7 @@ mp_state_thread_t *mp_thread_get_state(void) { return pvTaskGetThreadLocalStoragePointer(NULL, 0); } -void mp_thread_set_state(void *state) { +void mp_thread_set_state(mp_state_thread_t *state) { vTaskSetThreadLocalStoragePointer(NULL, 0, state); } diff --git a/ports/esp32/mpthreadport.c b/ports/esp32/mpthreadport.c index d7db0ff615..febd01a6aa 100644 --- a/ports/esp32/mpthreadport.c +++ b/ports/esp32/mpthreadport.c @@ -92,7 +92,7 @@ mp_state_thread_t *mp_thread_get_state(void) { return pvTaskGetThreadLocalStoragePointer(NULL, 1); } -void mp_thread_set_state(void *state) { +void mp_thread_set_state(mp_state_thread_t *state) { vTaskSetThreadLocalStoragePointer(NULL, 1, state); } diff --git a/ports/stm32/mpthreadport.h b/ports/stm32/mpthreadport.h index 8e2372dcb4..e2b39979fb 100644 --- a/ports/stm32/mpthreadport.h +++ b/ports/stm32/mpthreadport.h @@ -32,7 +32,7 @@ typedef pyb_mutex_t mp_thread_mutex_t; void mp_thread_init(void); void mp_thread_gc_others(void); -static inline void mp_thread_set_state(void *state) { +static inline void mp_thread_set_state(struct _mp_state_thread_t *state) { pyb_thread_set_local(state); } diff --git a/ports/unix/mpthreadport.c b/ports/unix/mpthreadport.c index 4fe5fa9218..b1915f2a6b 100644 --- a/ports/unix/mpthreadport.c +++ b/ports/unix/mpthreadport.c @@ -158,7 +158,7 @@ mp_state_thread_t *mp_thread_get_state(void) { return (mp_state_thread_t*)pthread_getspecific(tls_key); } -void mp_thread_set_state(void *state) { +void mp_thread_set_state(mp_state_thread_t *state) { pthread_setspecific(tls_key, state); } diff --git a/py/mpthread.h b/py/mpthread.h index 602df830c4..f2ab081e70 100644 --- a/py/mpthread.h +++ b/py/mpthread.h @@ -30,16 +30,16 @@ #if MICROPY_PY_THREAD +struct _mp_state_thread_t; + #ifdef MICROPY_MPTHREADPORT_H #include MICROPY_MPTHREADPORT_H #else #include #endif -struct _mp_state_thread_t; - struct _mp_state_thread_t *mp_thread_get_state(void); -void mp_thread_set_state(void *state); +void mp_thread_set_state(struct _mp_state_thread_t *state); void mp_thread_create(void *(*entry)(void*), void *arg, size_t *stack_size); void mp_thread_start(void); void mp_thread_finish(void); From 30501d3f54fa642770faefa117b4c39d95aff549 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Tue, 28 Jan 2020 14:59:05 +1100 Subject: [PATCH 1186/1788] drivers, stm32: Support SPI/QSPI flash chips over 16MB. With a SPI flash that has more than 16MB, 32-bit addressing is required rather than the standard 24-bit. This commit adds support for 32-bit addressing so that the SPI flash commands (read/write/erase) are selected automatically depending on the size of the address being used at each operation. --- drivers/bus/qspi.h | 17 +++++++++++++++ drivers/bus/softqspi.c | 10 +++++---- drivers/memory/spiflash.c | 44 ++++++++++++++++++++++++--------------- ports/stm32/qspi.c | 24 ++++++++++++++++----- 4 files changed, 69 insertions(+), 26 deletions(-) diff --git a/drivers/bus/qspi.h b/drivers/bus/qspi.h index 31c9d14fca..c82796fac5 100644 --- a/drivers/bus/qspi.h +++ b/drivers/bus/qspi.h @@ -28,6 +28,8 @@ #include "py/mphal.h" +#define MP_SPI_ADDR_IS_32B(addr) (addr & 0xff000000) + enum { MP_QSPI_IOCTL_INIT, MP_QSPI_IOCTL_DEINIT, @@ -54,4 +56,19 @@ typedef struct _mp_soft_qspi_obj_t { extern const mp_qspi_proto_t mp_soft_qspi_proto; +static inline uint8_t mp_spi_set_addr_buff(uint8_t *buf, uint32_t addr) { + if (MP_SPI_ADDR_IS_32B(addr)) { + buf[0] = addr >> 24; + buf[1] = addr >> 16; + buf[2] = addr >> 8; + buf[3] = addr; + return 4; + } else { + buf[0] = addr >> 16; + buf[1] = addr >> 8; + buf[2] = addr; + return 3; + } +} + #endif // MICROPY_INCLUDED_DRIVERS_BUS_QSPI_H diff --git a/drivers/bus/softqspi.c b/drivers/bus/softqspi.c index 10c5992466..71ab559768 100644 --- a/drivers/bus/softqspi.c +++ b/drivers/bus/softqspi.c @@ -168,9 +168,10 @@ STATIC void mp_soft_qspi_write_cmd_data(void *self_in, uint8_t cmd, size_t len, 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}; + uint8_t cmd_buf[5] = {cmd}; + uint8_t addr_len = mp_spi_set_addr_buff(&cmd_buf[1], addr); CS_LOW(self); - mp_soft_qspi_transfer(self, 4, cmd_buf, NULL); + mp_soft_qspi_transfer(self, addr_len + 1, cmd_buf, NULL); mp_soft_qspi_transfer(self, len, src, NULL); CS_HIGH(self); } @@ -186,10 +187,11 @@ STATIC uint32_t mp_soft_qspi_read_cmd(void *self_in, uint8_t cmd, size_t len) { 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}; + uint8_t cmd_buf[7] = {cmd}; + uint8_t addr_len = mp_spi_set_addr_buff(&cmd_buf[1], 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_qwrite(self, addr_len + 3, &cmd_buf[1]); // 3/4 addr bytes, 1 extra byte (0), 2 dummy bytes (4 dummy cycles) mp_soft_qspi_qread(self, len, dest); CS_HIGH(self); } diff --git a/drivers/memory/spiflash.c b/drivers/memory/spiflash.c index 0eacc710e3..e870d39f5f 100644 --- a/drivers/memory/spiflash.c +++ b/drivers/memory/spiflash.c @@ -45,6 +45,12 @@ #define CMD_CHIP_ERASE (0xc7) #define CMD_C4READ (0xeb) +// 32 bit addressing commands +#define CMD_WRITE_32 (0x12) +#define CMD_READ_32 (0x13) +#define CMD_SEC_ERASE_32 (0x21) +#define CMD_C4READ_32 (0xec) + #define WAIT_SR_TIMEOUT (1000000) #define PAGE_SIZE (256) // maximum bytes we can write in one SPI transfer @@ -76,18 +82,26 @@ STATIC void mp_spiflash_write_cmd_data(mp_spiflash_t *self, uint8_t cmd, size_t } } -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) { +STATIC void mp_spiflash_transfer_cmd_addr_data(mp_spiflash_t *self, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src, uint8_t *dest) { 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}; + uint8_t buf[5] = {cmd, 0}; + uint8_t buff_len = 1 + mp_spi_set_addr_buff(&buf[1], 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, buff_len, buf, NULL); + if (len && (src != NULL)) { c->bus.u_spi.proto->transfer(c->bus.u_spi.data, len, src, NULL); + } else if (len && (dest != 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->write_cmd_addr_data(c->bus.u_qspi.data, cmd, addr, len, src); + if (dest != NULL) { + c->bus.u_qspi.proto->read_cmd_qaddr_qdata(c->bus.u_qspi.data, cmd, addr, len, dest); + } else { + c->bus.u_qspi.proto->write_cmd_addr_data(c->bus.u_qspi.data, cmd, addr, len, src); + } } } @@ -107,25 +121,19 @@ STATIC uint32_t mp_spiflash_read_cmd(mp_spiflash_t *self, uint8_t cmd, size_t le 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; + uint8_t cmd; 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); + cmd = MP_SPI_ADDR_IS_32B(addr) ? CMD_READ_32 : CMD_READ; } else { - c->bus.u_qspi.proto->read_cmd_qaddr_qdata(c->bus.u_qspi.data, CMD_C4READ, addr, len, dest); + cmd = MP_SPI_ADDR_IS_32B(addr) ? CMD_C4READ_32 : CMD_C4READ; } + mp_spiflash_transfer_cmd_addr_data(self, cmd, addr, len, NULL, 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 sr; do { @@ -210,7 +218,8 @@ STATIC int mp_spiflash_erase_block_internal(mp_spiflash_t *self, uint32_t addr) } // erase the sector - mp_spiflash_write_cmd_addr(self, CMD_SEC_ERASE, addr); + uint8_t cmd = MP_SPI_ADDR_IS_32B(addr) ? CMD_SEC_ERASE_32 : CMD_SEC_ERASE; + mp_spiflash_transfer_cmd_addr_data(self, cmd, addr, 0, NULL, NULL); // wait WIP=0 return mp_spiflash_wait_wip0(self); @@ -227,7 +236,8 @@ STATIC int mp_spiflash_write_page(mp_spiflash_t *self, uint32_t addr, size_t len } // write the page - mp_spiflash_write_cmd_addr_data(self, CMD_WRITE, addr, len, src); + uint8_t cmd = MP_SPI_ADDR_IS_32B(addr) ? CMD_WRITE_32 : CMD_WRITE; + mp_spiflash_transfer_cmd_addr_data(self, cmd, addr, len, src, NULL); // wait WIP=0 return mp_spiflash_wait_wip0(self); diff --git a/ports/stm32/qspi.c b/ports/stm32/qspi.c index 30ee2c9ea7..20cdafb00d 100644 --- a/ports/stm32/qspi.c +++ b/ports/stm32/qspi.c @@ -52,6 +52,14 @@ #define MICROPY_HW_QSPI_CS_HIGH_CYCLES 2 // nCS stays high for 2 cycles #endif +#if (MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2 - 3 - 1) >= 24 +#define QSPI_CMD 0xec +#define QSPI_ADSIZE 3 +#else +#define QSPI_CMD 0xeb +#define QSPI_ADSIZE 2 +#endif + static inline void qspi_mpu_disable_all(void) { // Configure MPU to disable access to entire QSPI region, to prevent CPU // speculative execution from accessing this region and modifying QSPI registers. @@ -116,6 +124,7 @@ void qspi_memory_map(void) { // Enable memory-mapped mode QUADSPI->ABR = 0; // disable continuous read mode + QUADSPI->CCR = 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction @@ -124,10 +133,10 @@ void qspi_memory_map(void) { | 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 + | QSPI_ADSIZE << QUADSPI_CCR_ADSIZE_Pos | 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 + | QSPI_CMD << QUADSPI_CCR_INSTRUCTION_Pos ; qspi_mpu_enable_mapped(); @@ -203,6 +212,8 @@ STATIC void qspi_write_cmd_data(void *self_in, uint8_t cmd, size_t len, uint32_t 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; + uint8_t adsize = MP_SPI_ADDR_IS_32B(addr) ? 3 : 2; + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag if (len == 0) { @@ -213,7 +224,7 @@ STATIC void qspi_write_cmd_addr_data(void *self_in, uint8_t cmd, uint32_t addr, | 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 + | adsize << QUADSPI_CCR_ADSIZE_Pos // 32/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 @@ -230,7 +241,7 @@ STATIC void qspi_write_cmd_addr_data(void *self_in, uint8_t cmd, uint32_t addr, | 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 + | adsize << QUADSPI_CCR_ADSIZE_Pos // 32/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 @@ -285,6 +296,9 @@ 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; + + uint8_t adsize = MP_SPI_ADDR_IS_32B(addr) ? 3 : 2; + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag QUADSPI->DLR = len - 1; // number of bytes to read @@ -297,7 +311,7 @@ STATIC void qspi_read_cmd_qaddr_qdata(void *self_in, uint8_t cmd, uint32_t addr, | 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 + | adsize << QUADSPI_CCR_ADSIZE_Pos // 32 or 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 From 7bb2bf965e529302aececb30d0b42014cac641fa Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 30 Jan 2020 14:39:46 +1100 Subject: [PATCH 1187/1788] stm32/Makefile: Allow a board's .mk file to add things to CFLAGS. --- ports/stm32/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 6a6242df53..96f10fe98a 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -87,7 +87,7 @@ 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_MCU_wb = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 -CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 -nostdlib $(CFLAGS_MOD) $(CFLAGS_EXTRA) +CFLAGS += $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 -nostdlib $(CFLAGS_MOD) $(CFLAGS_EXTRA) CFLAGS += -D$(CMSIS_MCU) CFLAGS += $(CFLAGS_MCU_$(MCU_SERIES)) CFLAGS += $(COPT) From 96a4435be1279dcb7804850311e551f2b06d86bd Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 30 Jan 2020 14:40:38 +1100 Subject: [PATCH 1188/1788] stm32/boards/STM32F769DISC: Add config to use external SPI as filesys. This board now has the following 3 build configurations: - mboot + external QSPI in XIP mode + internal filesystem - mboot + external QSPI with filesystem (the default) - no mboot + external QSPI with filesystem --- ports/stm32/boards/STM32F769DISC/board_init.c | 7 ++++-- .../boards/STM32F769DISC/mpconfigboard.h | 21 ++++++++++++++---- .../boards/STM32F769DISC/mpconfigboard.mk | 22 ++++++++++++------- 3 files changed, 36 insertions(+), 14 deletions(-) diff --git a/ports/stm32/boards/STM32F769DISC/board_init.c b/ports/stm32/boards/STM32F769DISC/board_init.c index b75a00c970..67fad407a0 100644 --- a/ports/stm32/boards/STM32F769DISC/board_init.c +++ b/ports/stm32/boards/STM32F769DISC/board_init.c @@ -1,16 +1,19 @@ -#include "drivers/memory/spiflash.h" +#include "storage.h" #include "qspi.h" // This configuration is needed for mboot to be able to write to the external QSPI flash +STATIC mp_spiflash_cache_t spi_bdev_cache; + const mp_spiflash_config_t spiflash_config = { .bus_kind = MP_SPIFLASH_BUS_QSPI, .bus.u_qspi.data = NULL, .bus.u_qspi.proto = &qspi_proto, .cache = NULL, + .cache = &spi_bdev_cache, }; -mp_spiflash_t spiflash_instance; +spi_bdev_t spi_bdev; // This init function is needed to memory map the QSPI flash early in the boot process diff --git a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h index a34b58e1b2..68e14761ec 100644 --- a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h @@ -26,7 +26,7 @@ void board_early_init(void); #define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_7 // 210-216 MHz needs 7 wait states -// 512MBit external QSPI flash, to be memory mapped +// 512MBit external QSPI flash, used for either the filesystem or XIP memory mapped #define MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2 (29) #define MICROPY_HW_QSPIFLASH_CS (pin_B6) #define MICROPY_HW_QSPIFLASH_SCK (pin_B2) @@ -35,6 +35,21 @@ void board_early_init(void); #define MICROPY_HW_QSPIFLASH_IO2 (pin_E2) #define MICROPY_HW_QSPIFLASH_IO3 (pin_D13) +// SPI flash, block device config (when used as the filesystem) +extern const struct _mp_spiflash_config_t spiflash_config; +extern struct _spi_bdev_t spi_bdev; +#if !USE_QSPI_XIP +#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (0) +#define MICROPY_HW_BDEV_IOCTL(op, arg) ( \ + (op) == BDEV_IOCTL_NUM_BLOCKS ? (64 * 1024 * 1024 / 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)) +#define MICROPY_HW_BDEV_SPIFLASH_EXTENDED (&spi_bdev) // for extended block protocol +#endif + // UART config #define MICROPY_HW_UART1_TX (pin_A9) #define MICROPY_HW_UART1_RX (pin_A10) @@ -199,11 +214,9 @@ void board_early_init(void); // Bootloader configuration // Give Mboot access to the external QSPI flash -extern const struct _mp_spiflash_config_t spiflash_config; -extern struct _mp_spiflash_t spiflash_instance; #define MBOOT_SPIFLASH_ADDR (0x90000000) #define MBOOT_SPIFLASH_BYTE_SIZE (512 * 128 * 1024) #define MBOOT_SPIFLASH_LAYOUT "/0x90000000/512*128Kg" #define MBOOT_SPIFLASH_ERASE_BLOCKS_PER_PAGE (128 / 4) // 128k page, 4k erase block #define MBOOT_SPIFLASH_CONFIG (&spiflash_config) -#define MBOOT_SPIFLASH_SPIFLASH (&spiflash_instance) +#define MBOOT_SPIFLASH_SPIFLASH (&spi_bdev.spiflash) diff --git a/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk index 04f208c5b7..81add8c88e 100644 --- a/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk @@ -1,9 +1,11 @@ # By default this board is configured to use mboot which must be deployed first USE_MBOOT ?= 1 -# By default this board puts some code into external QSPI flash set in XIP mode +# By default the filesystem is in external QSPI flash. But by setting the +# following option this board puts some code into external flash set in XIP mode. # USE_MBOOT must be enabled; see f769_qspi.ld for code that goes in QSPI flash -USE_QSPI ?= 1 +USE_QSPI_XIP ?= 0 +CFLAGS += -DUSE_QSPI_XIP=$(USE_QSPI_XIP) # MCU settings MCU_SERIES = f7 @@ -12,9 +14,11 @@ MICROPY_FLOAT_IMPL = double AF_FILE = boards/stm32f767_af.csv ifeq ($(USE_MBOOT),1) -ifeq ($(USE_QSPI),1) +ifeq ($(USE_QSPI_XIP),1) -# When using Mboot and QSPI the text is split between internal and external flash +# When using Mboot and QSPI-XIP the text is split between internal and external +# QSPI flash, and the filesystem is in internal flash between the bootloader and +# the main program text. LD_FILES = boards/STM32F769DISC/f769_qspi.ld TEXT0_ADDR = 0x08020000 TEXT1_ADDR = 0x90000000 @@ -23,17 +27,19 @@ TEXT1_SECTIONS = .text_qspi else -# When using Mboot but not QSPI all the text goes together after the filesystem +# When using Mboot but not QSPI-XIP all the text goes together after the bootloader +# (at same location as when QSPI-XIP is enabled so the same Mboot can be used for +# either configuration) and the filesystem is in external flash. LD_FILES = boards/stm32f769.ld boards/common_blifs.ld TEXT0_ADDR = 0x08020000 endif else -# When not using Mboot the ISR text goes first, then the rest after the filesystem -LD_FILES = boards/stm32f769.ld boards/common_ifs.ld +# When not using Mboot (and so no ability to load text into QSPI) all the text goes +# together at the start of internal flash, and the filesystem is in external flash. +LD_FILES = boards/stm32f769.ld boards/common_basic.ld TEXT0_ADDR = 0x08000000 -TEXT1_ADDR = 0x08020000 endif From c3450effd4c3a402eeccf44a84a05ef4b36d69a0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 30 Jan 2020 00:15:26 +1100 Subject: [PATCH 1189/1788] py/objtype: Make mp_obj_type_t.flags constants public, moved to obj.h. --- py/obj.h | 4 ++++ py/objtype.c | 21 +++++++++------------ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/py/obj.h b/py/obj.h index b052b9fc8b..2bc72b5867 100644 --- a/py/obj.h +++ b/py/obj.h @@ -444,6 +444,10 @@ typedef mp_obj_t (*mp_fun_var_t)(size_t n, const mp_obj_t *); // this arg to mp_map_lookup(). typedef mp_obj_t (*mp_fun_kw_t)(size_t n, const mp_obj_t *, mp_map_t *); +// Flags for type behaviour (mp_obj_type_t.flags) +#define MP_TYPE_FLAG_IS_SUBCLASSED (0x0001) +#define MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS (0x0002) + typedef enum { PRINT_STR = 0, PRINT_REPR = 1, diff --git a/py/objtype.c b/py/objtype.c index 2ea3f1c187..c574dcdfe2 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -44,9 +44,6 @@ #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); /******************************************************************************/ @@ -615,7 +612,7 @@ 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)) { + if (!(self->base.type->flags & MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) { // Class doesn't have any special accessors to check so return straightaway return; } @@ -680,7 +677,7 @@ 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)) { + if (!(self->base.type->flags & MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) { // Class doesn't have any special accessors so skip their checks goto skip_special_accessors; } @@ -1061,13 +1058,13 @@ STATIC void type_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { } 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 (!(self->flags & MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) { if (check_for_special_accessors(MP_OBJ_NEW_QSTR(attr), dest[1])) { - if (self->flags & TYPE_FLAG_IS_SUBCLASSED) { + if (self->flags & MP_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; + self->flags |= MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS; } } #endif @@ -1123,8 +1120,8 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) } #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; + t->flags |= MP_TYPE_FLAG_IS_SUBCLASSED; + base_flags |= t->flags & MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS; } #endif } @@ -1166,12 +1163,12 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) #if ENABLE_SPECIAL_ACCESSORS // Check if the class has any special accessor methods - if (!(o->flags & TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) { + if (!(o->flags & MP_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; + o->flags |= MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS; break; } } From 3aab54bf434e7f025a91ea05052f1bac439fad8c Mon Sep 17 00:00:00 2001 From: Nicko van Someren Date: Tue, 31 Dec 2019 15:19:12 -0700 Subject: [PATCH 1190/1788] py: Support non-boolean results for equality and inequality tests. This commit implements a more complete replication of CPython's behaviour for equality and inequality testing of objects. This addresses the issues discussed in #5382 and a few other inconsistencies. Improvements over the old code include: - Support for returning non-boolean results from comparisons (as used by numpy and others). - Support for non-reflexive equality tests. - Preferential use of __ne__ methods and MP_BINARY_OP_NOT_EQUAL binary operators for inequality tests, when available. - Fallback to op2 == op1 or op2 != op1 when op1 does not implement the (in)equality operators. The scheme here makes use of a new flag, MP_TYPE_FLAG_NEEDS_FULL_EQ_TEST, in the flags word of mp_obj_type_t to indicate if various shortcuts can or cannot be used when performing equality and inequality tests. Currently four built-in classes have the flag set: float and complex are non-reflexive (since nan != nan) while bytearray and frozenszet instances can equal other builtin class instances (bytes and set respectively). The flag is also set for any new class defined by the user. This commit also includes a more comprehensive set of tests for the behaviour of (in)equality operators implemented in special methods. --- py/obj.c | 114 ++++++++++++++++----------- py/obj.h | 7 ++ py/objarray.c | 1 + py/objcomplex.c | 1 + py/objfloat.c | 1 + py/objset.c | 1 + py/objtype.c | 4 +- py/runtime.c | 15 +--- tests/basics/special_comparisons.py | 33 ++++++++ tests/basics/special_comparisons2.py | 31 ++++++++ 10 files changed, 147 insertions(+), 61 deletions(-) create mode 100644 tests/basics/special_comparisons.py create mode 100644 tests/basics/special_comparisons2.py diff --git a/py/obj.c b/py/obj.c index 55754f9be2..6aa0abf0d3 100644 --- a/py/obj.c +++ b/py/obj.c @@ -189,7 +189,7 @@ bool mp_obj_is_callable(mp_obj_t o_in) { return mp_obj_instance_is_callable(o_in); } -// This function implements the '==' operator (and so the inverse of '!='). +// This function implements the '==' and '!=' operators. // // From the Python language reference: // (https://docs.python.org/3/reference/expressions.html#not-in) @@ -202,67 +202,89 @@ bool mp_obj_is_callable(mp_obj_t o_in) { // Furthermore, from the v3.4.2 code for object.c: "Practical amendments: If rich // comparison returns NotImplemented, == and != are decided by comparing the object // pointer." -bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) { - // Float (and complex) NaN is never equal to anything, not even itself, - // so we must have a special check here to cover those cases. - if (o1 == o2 - #if MICROPY_PY_BUILTINS_FLOAT - && !mp_obj_is_float(o1) - #endif - #if MICROPY_PY_BUILTINS_COMPLEX - && !mp_obj_is_type(o1, &mp_type_complex) - #endif - ) { - return true; - } - if (o1 == mp_const_none || o2 == mp_const_none) { - return false; - } +mp_obj_t mp_obj_equal_not_equal(mp_binary_op_t op, mp_obj_t o1, mp_obj_t o2) { + mp_obj_t local_true = (op == MP_BINARY_OP_NOT_EQUAL) ? mp_const_false : mp_const_true; + mp_obj_t local_false = (op == MP_BINARY_OP_NOT_EQUAL) ? mp_const_true : mp_const_false; + int pass_number = 0; - // fast path for small ints - if (mp_obj_is_small_int(o1)) { - if (mp_obj_is_small_int(o2)) { - // both SMALL_INT, and not equal if we get here - return false; - } else { - mp_obj_t temp = o2; o2 = o1; o1 = temp; - // o2 is now the SMALL_INT, o1 is not - // fall through to generic op - } + // Shortcut for very common cases + if (o1 == o2 && + (mp_obj_is_small_int(o1) || !(mp_obj_get_type(o1)->flags & MP_TYPE_FLAG_NEEDS_FULL_EQ_TEST))) { + return local_true; } // fast path for strings if (mp_obj_is_str(o1)) { if (mp_obj_is_str(o2)) { // both strings, use special function - return mp_obj_str_equal(o1, o2); - } else { - // a string is never equal to anything else - goto str_cmp_err; - } - } else if (mp_obj_is_str(o2)) { - // o1 is not a string (else caught above), so the objects are not equal - str_cmp_err: + return mp_obj_str_equal(o1, o2) ? local_true : local_false; #if MICROPY_PY_STR_BYTES_CMP_WARN - if (mp_obj_is_type(o1, &mp_type_bytes) || mp_obj_is_type(o2, &mp_type_bytes)) { + } else if (mp_obj_is_type(o2, &mp_type_bytes)) { + str_bytes_cmp: mp_warning(MP_WARN_CAT(BytesWarning), "Comparison between bytes and str"); - } + return local_false; #endif - return false; + } else { + goto skip_one_pass; + } + #if MICROPY_PY_STR_BYTES_CMP_WARN + } else if (mp_obj_is_str(o2) && mp_obj_is_type(o1, &mp_type_bytes)) { + // o1 is not a string (else caught above), so the objects are not equal + goto str_bytes_cmp; + #endif + } + + // fast path for small ints + if (mp_obj_is_small_int(o1)) { + if (mp_obj_is_small_int(o2)) { + // both SMALL_INT, and not equal if we get here + return local_false; + } else { + goto skip_one_pass; + } } // generic type, call binary_op(MP_BINARY_OP_EQUAL) - const mp_obj_type_t *type = mp_obj_get_type(o1); - if (type->binary_op != NULL) { - mp_obj_t r = type->binary_op(MP_BINARY_OP_EQUAL, o1, o2); - if (r != MP_OBJ_NULL) { - return r == mp_const_true ? true : false; + while (pass_number < 2) { + const mp_obj_type_t *type = mp_obj_get_type(o1); + // If a full equality test is not needed and the other object is a different + // type then we don't need to bother trying the comparison. + if (type->binary_op != NULL && + ((type->flags & MP_TYPE_FLAG_NEEDS_FULL_EQ_TEST) || mp_obj_get_type(o2) == type)) { + // CPython is asymmetric: it will try __eq__ if there's no __ne__ but not the + // other way around. If the class doesn't need a full test we can skip __ne__. + if (op == MP_BINARY_OP_NOT_EQUAL && (type->flags & MP_TYPE_FLAG_NEEDS_FULL_EQ_TEST)) { + mp_obj_t r = type->binary_op(MP_BINARY_OP_NOT_EQUAL, o1, o2); + if (r != MP_OBJ_NULL) { + return r; + } + } + + // Try calling __eq__. + mp_obj_t r = type->binary_op(MP_BINARY_OP_EQUAL, o1, o2); + if (r != MP_OBJ_NULL) { + if (op == MP_BINARY_OP_EQUAL) { + return r; + } else { + return mp_obj_is_true(r) ? local_true : local_false; + } + } } + + skip_one_pass: + // Try the other way around if none of the above worked + ++pass_number; + mp_obj_t temp = o1; + o1 = o2; + o2 = temp; } - // equality not implemented, and objects are not the same object, so - // they are defined as not equal - return false; + // equality not implemented, so fall back to pointer conparison + return (o1 == o2) ? local_true : local_false; +} + +bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) { + return mp_obj_is_true(mp_obj_equal_not_equal(MP_BINARY_OP_EQUAL, o1, o2)); } mp_int_t mp_obj_get_int(mp_const_obj_t arg) { diff --git a/py/obj.h b/py/obj.h index 2bc72b5867..2e91b6b150 100644 --- a/py/obj.h +++ b/py/obj.h @@ -445,8 +445,14 @@ typedef mp_obj_t (*mp_fun_var_t)(size_t n, const mp_obj_t *); typedef mp_obj_t (*mp_fun_kw_t)(size_t n, const mp_obj_t *, mp_map_t *); // Flags for type behaviour (mp_obj_type_t.flags) +// If MP_TYPE_FLAG_NEEDS_FULL_EQ_TEST is clear then all the following hold: +// (a) the type only implements the __eq__ operator and not the __ne__ operator; +// (b) __eq__ returns a boolean result (False or True); +// (c) __eq__ is reflexive (A==A is True); +// (d) the type can't be equal to an instance of any different class that also clears this flag. #define MP_TYPE_FLAG_IS_SUBCLASSED (0x0001) #define MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS (0x0002) +#define MP_TYPE_FLAG_NEEDS_FULL_EQ_TEST (0x0004) typedef enum { PRINT_STR = 0, @@ -729,6 +735,7 @@ void mp_obj_print_exception(const mp_print_t *print, mp_obj_t exc); bool mp_obj_is_true(mp_obj_t arg); bool mp_obj_is_callable(mp_obj_t o_in); +mp_obj_t mp_obj_equal_not_equal(mp_binary_op_t op, mp_obj_t o1, mp_obj_t o2); 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_bool(o); } // returns true if o is bool, small int or long int diff --git a/py/objarray.c b/py/objarray.c index c19617d4e1..51f924ba4e 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -558,6 +558,7 @@ const mp_obj_type_t mp_type_array = { const mp_obj_type_t mp_type_bytearray = { { &mp_type_type }, .name = MP_QSTR_bytearray, + .flags = MP_TYPE_FLAG_NEEDS_FULL_EQ_TEST, .print = array_print, .make_new = bytearray_make_new, .getiter = array_iterator_new, diff --git a/py/objcomplex.c b/py/objcomplex.c index bf6fb51dc5..0c87f544fb 100644 --- a/py/objcomplex.c +++ b/py/objcomplex.c @@ -148,6 +148,7 @@ STATIC void complex_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { const mp_obj_type_t mp_type_complex = { { &mp_type_type }, .name = MP_QSTR_complex, + .flags = MP_TYPE_FLAG_NEEDS_FULL_EQ_TEST, .print = complex_print, .make_new = complex_make_new, .unary_op = complex_unary_op, diff --git a/py/objfloat.c b/py/objfloat.c index 3da549bb25..6181d5f578 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -186,6 +186,7 @@ STATIC mp_obj_t float_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs const mp_obj_type_t mp_type_float = { { &mp_type_type }, .name = MP_QSTR_float, + .flags = MP_TYPE_FLAG_NEEDS_FULL_EQ_TEST, .print = float_print, .make_new = float_make_new, .unary_op = float_unary_op, diff --git a/py/objset.c b/py/objset.c index 6f5bcc032a..a18b7e051e 100644 --- a/py/objset.c +++ b/py/objset.c @@ -564,6 +564,7 @@ STATIC MP_DEFINE_CONST_DICT(frozenset_locals_dict, frozenset_locals_dict_table); const mp_obj_type_t mp_type_frozenset = { { &mp_type_type }, .name = MP_QSTR_frozenset, + .flags = MP_TYPE_FLAG_NEEDS_FULL_EQ_TEST, .print = set_print, .make_new = set_make_new, .unary_op = set_unary_op, diff --git a/py/objtype.c b/py/objtype.c index c574dcdfe2..ae0fe6caef 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -467,7 +467,7 @@ const byte mp_binary_op_method_name[MP_BINARY_OP_NUM_RUNTIME] = { [MP_BINARY_OP_EQUAL] = MP_QSTR___eq__, [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_NOT_EQUAL] = MP_QSTR___ne__, [MP_BINARY_OP_CONTAINS] = MP_QSTR___contains__, // If an inplace method is not found a normal method will be used as a fallback @@ -1100,7 +1100,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; + uint16_t base_flags = MP_TYPE_FLAG_NEEDS_FULL_EQ_TEST; size_t bases_len; mp_obj_t *bases_items; mp_obj_tuple_get(bases_tuple, &bases_len, &bases_items); diff --git a/py/runtime.c b/py/runtime.c index db044cf7c4..4a718c1e23 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -323,19 +323,8 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { // deal with == and != for all types if (op == MP_BINARY_OP_EQUAL || op == MP_BINARY_OP_NOT_EQUAL) { - if (mp_obj_equal(lhs, rhs)) { - if (op == MP_BINARY_OP_EQUAL) { - return mp_const_true; - } else { - return mp_const_false; - } - } else { - if (op == MP_BINARY_OP_EQUAL) { - return mp_const_false; - } else { - return mp_const_true; - } - } + // mp_obj_equal_not_equal supports a bunch of shortcuts + return mp_obj_equal_not_equal(op, lhs, rhs); } // deal with exception_match for all types diff --git a/tests/basics/special_comparisons.py b/tests/basics/special_comparisons.py new file mode 100644 index 0000000000..2ebd7e224e --- /dev/null +++ b/tests/basics/special_comparisons.py @@ -0,0 +1,33 @@ +class A: + def __eq__(self, other): + print("A __eq__ called") + return True + +class B: + def __ne__(self, other): + print("B __ne__ called") + return True + +class C: + def __eq__(self, other): + print("C __eq__ called") + return False + +class D: + def __ne__(self, other): + print("D __ne__ called") + return False + +a = A() +b = B() +c = C() +d = D() + +def test(s): + print(s) + print(eval(s)) + +for x in 'abcd': + for y in 'abcd': + test('{} == {}'.format(x,y)) + test('{} != {}'.format(x,y)) diff --git a/tests/basics/special_comparisons2.py b/tests/basics/special_comparisons2.py new file mode 100644 index 0000000000..c29dc72ce6 --- /dev/null +++ b/tests/basics/special_comparisons2.py @@ -0,0 +1,31 @@ +class E: + def __repr__(self): + return "E" + + def __eq__(self, other): + print('E eq', other) + return 123 + +class F: + def __repr__(self): + return "F" + + def __ne__(self, other): + print('F ne', other) + return -456 + +print(E() != F()) +print(F() != E()) + +tests = (None, 0, 1, 'a') + +for val in tests: + print('==== testing', val) + print(E() == val) + print(val == E()) + print(E() != val) + print(val != E()) + print(F() == val) + print(val == F()) + print(F() != val) + print(val != F()) From c96a2f636b48b065e8404af6d67fbae5986fd34a Mon Sep 17 00:00:00 2001 From: Nicko van Someren Date: Tue, 14 Jan 2020 21:40:08 -0700 Subject: [PATCH 1191/1788] tests/basics: Expand test cases for equality of subclasses. --- tests/basics/subclass_native2_tuple.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/basics/subclass_native2_tuple.py b/tests/basics/subclass_native2_tuple.py index 9eb69e1575..a02d3a66dc 100644 --- a/tests/basics/subclass_native2_tuple.py +++ b/tests/basics/subclass_native2_tuple.py @@ -19,3 +19,11 @@ a = Ctuple2() print(len(a)) a = Ctuple2([1, 2, 3]) print(len(a)) + +a = tuple([1,2,3]) +b = Ctuple1([1,2,3]) +c = Ctuple2([1,2,3]) + +print(a == b) +print(b == c) +print(c == a) From 29b84ea79856e8ba512ef7ea70b265e9d86e45b6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 30 Jan 2020 16:29:45 +1100 Subject: [PATCH 1192/1788] stm32/powerctrl: Disable HSI if not needed to save a bit of power. --- ports/stm32/powerctrl.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c index 1d1792c386..d1ac85f0e8 100644 --- a/ports/stm32/powerctrl.c +++ b/ports/stm32/powerctrl.c @@ -44,6 +44,13 @@ extern uint32_t _estack[]; #define BL_STATE ((uint32_t*)&_estack) +static inline void powerctrl_disable_hsi_if_unused(void) { + #if !MICROPY_HW_CLK_USE_HSI && (defined(STM32F4) || defined(STM32F7) || defined(STM32H7)) + // Disable HSI if it's not used to save a little bit of power + __HAL_RCC_HSI_DISABLE(); + #endif +} + NORETURN void powerctrl_mcu_reset(void) { BL_STATE[1] = 1; // invalidate bootloader address #if __DCACHE_PRESENT == 1 @@ -155,6 +162,8 @@ int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk return -MP_EIO; } + powerctrl_disable_hsi_if_unused(); + return 0; } @@ -390,6 +399,8 @@ void powerctrl_enter_stop_mode(void) { } #endif + powerctrl_disable_hsi_if_unused(); + #if defined(STM32F7) if (RCC->DCKCFGR2 & RCC_DCKCFGR2_CK48MSEL) { // Enable PLLSAI if it is selected as 48MHz source From 68db7e01d842b0b9b828be6e001e83f78de7a226 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 30 Jan 2020 16:30:03 +1100 Subject: [PATCH 1193/1788] stm32/powerctrl: Enable overdrive on F7 when waking from stop mode. Because if the SYSCLK is set to 180MHz or higher it will require this to be on already. --- ports/stm32/powerctrl.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c index d1ac85f0e8..4c40cffb60 100644 --- a/ports/stm32/powerctrl.c +++ b/ports/stm32/powerctrl.c @@ -381,6 +381,11 @@ void powerctrl_enter_stop_mode(void) { } #endif + #if defined(STM32F7) + // Enable overdrive to reach 216MHz (if needed) + HAL_PWREx_EnableOverDrive(); + #endif + // enable PLL __HAL_RCC_PLL_ENABLE(); while (!__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY)) { From 31ba06ce845938e4fff9a34163311a07d0e22cab Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 30 Jan 2020 16:31:11 +1100 Subject: [PATCH 1194/1788] stm32/boards/stm32f746_af.csv: Add ADC alt functions to correct pins. --- ports/stm32/boards/stm32f746_af.csv | 340 ++++++++++++++-------------- 1 file changed, 170 insertions(+), 170 deletions(-) diff --git a/ports/stm32/boards/stm32f746_af.csv b/ports/stm32/boards/stm32f746_af.csv index 8069edc7b9..d9e42008d6 100644 --- a/ports/stm32/boards/stm32f746_af.csv +++ b/ports/stm32/boards/stm32f746_af.csv @@ -1,170 +1,170 @@ -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/OTG2_HS/OTG1_FS,ETH/OTG1_FS,FMC/SDMMC1/OTG2_FS,DCMI,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,,,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,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 -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,,,OTG_HS_DM,,,EVENTOUT -PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI/I2S2_SD,,,,TIM12_CH2,,,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,,,,SDMMC1_D6,DCMI_D0,LCD_HSYNC,EVENTOUT -PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,I2S3_MCK,,USART6_RX,,,,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,I2S_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 -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,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,PD5,,,,,,,,USART2_TX,,,,,FMC_NWE,,,EVENTOUT -PortD,PD6,,,,,,SPI3_MOSI/I2S3_SD,SAI1_SD_A,USART2_RX,,,,,FMC_NWAIT,DCMI_D10,LCD_B2,EVENTOUT -PortD,PD7,,,,,,,,USART2_CK,SPDIFRX_IN0,,,,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,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,,,,,,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,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,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,,,,,,,,,,,,,,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,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,,,,,,,,,,,,,,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,,FMC_NE2/FMC_NCE,DCMI_VSYNC,,EVENTOUT -PortG,PG10,,,,,,,,,,LCD_G3,SAI2_SD_B,,FMC_NE3,DCMI_D2,LCD_B2,EVENTOUT -PortG,PG11,,,,,,,,SPDIFRX_IN0,,,,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,,,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,,,,,,OTG_HS_ULPI_NXT,,,,,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,,,,,,CAN1_TX,,,FMC_D21,,LCD_G2,EVENTOUT -PortH,PH14,,,,TIM8_CH2N,,,,,,,,,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,,,,,,,,,,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,PI12,,,,,,,,,,,,,,,LCD_HSYNC,EVENTOUT -PortI,PI13,,,,,,,,,,,,,,,LCD_VSYNC,EVENTOUT -PortI,PI14,,,,,,,,,,,,,,,LCD_CLK,EVENTOUT -PortI,PI15,,,,,,,,,,,,,,,LCD_R0,EVENTOUT -PortJ,PJ0,,,,,,,,,,,,,,,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,,,,,,,,,,,,,,,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_B0,EVENTOUT -PortJ,PJ13,,,,,,,,,,,,,,,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,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/OTG2_HS/OTG1_FS,ETH/OTG1_FS,FMC/SDMMC1/OTG2_FS,DCMI,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,,,LCD_R1,EVENTOUT,ADC123_IN2 +PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,,OTG_HS_ULPI_D0,ETH_MII_COL,,,LCD_B5,EVENTOUT,ADC123_IN3 +PortA,PA4,,,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART2_CK,,,,,OTG_HS_SOF,DCMI_HSYNC,LCD_VSYNC,EVENTOUT,ADC12_IN4 +PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK/I2S1_CK,,,,,OTG_HS_ULPI_CK,,,,LCD_R4,EVENTOUT,ADC12_IN5 +PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,,TIM13_CH1,,,,DCMI_PIXCLK,LCD_G2,EVENTOUT,ADC12_IN6 +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,ADC12_IN7 +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,,,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,ADC12_IN8 +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,,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,,,,,,,,,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,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, +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,,,OTG_HS_DM,,,EVENTOUT, +PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI/I2S2_SD,,,,TIM12_CH2,,,OTG_HS_DP,,,EVENTOUT, +PortC,PC0,,,,,,,,,SAI2_FS_B,,OTG_HS_ULPI_STP,,FMC_SDNWE,,LCD_R5,EVENTOUT,ADC123_IN10 +PortC,PC1,TRACED0,,,,,SPI2_MOSI/I2S2_SD,SAI1_SD_A,,,,,ETH_MDC,,,,EVENTOUT,ADC123_IN11 +PortC,PC2,,,,,,SPI2_MISO,,,,,OTG_HS_ULPI_DIR,ETH_MII_TXD2,FMC_SDNE0,,,EVENTOUT,ADC123_IN12 +PortC,PC3,,,,,,SPI2_MOSI/I2S2_SD,,,,,OTG_HS_ULPI_NXT,ETH_MII_TX_CLK,FMC_SDCKE0,,,EVENTOUT,ADC123_IN13 +PortC,PC4,,,,,,I2S1_MCK,,,SPDIFRX_IN2,,,ETH_MII_RXD0/ETH_RMII_RXD0,FMC_SDNE0,,,EVENTOUT,ADC12_IN14 +PortC,PC5,,,,,,,,,SPDIFRX_IN3,,,ETH_MII_RXD1/ETH_RMII_RXD1,FMC_SDCKE0,,,EVENTOUT,ADC12_IN15 +PortC,PC6,,,TIM3_CH1,TIM8_CH1,,I2S2_MCK,,,USART6_TX,,,,SDMMC1_D6,DCMI_D0,LCD_HSYNC,EVENTOUT, +PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,I2S3_MCK,,USART6_RX,,,,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,I2S_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, +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,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,PD5,,,,,,,,USART2_TX,,,,,FMC_NWE,,,EVENTOUT, +PortD,PD6,,,,,,SPI3_MOSI/I2S3_SD,SAI1_SD_A,USART2_RX,,,,,FMC_NWAIT,DCMI_D10,LCD_B2,EVENTOUT, +PortD,PD7,,,,,,,,USART2_CK,SPDIFRX_IN0,,,,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,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,,,,,,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,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,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,,,,,,,,,,,,,,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,,,,,,,,FMC_A7,,,EVENTOUT, +PortF,PF14,,,,,I2C4_SCL,,,,,,,,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,,,,,,,,,,,,,,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,,FMC_NE2/FMC_NCE,DCMI_VSYNC,,EVENTOUT, +PortG,PG10,,,,,,,,,,LCD_G3,SAI2_SD_B,,FMC_NE3,DCMI_D2,LCD_B2,EVENTOUT, +PortG,PG11,,,,,,,,SPDIFRX_IN0,,,,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,,,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,,,,,,OTG_HS_ULPI_NXT,,,,,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,,,,,,CAN1_TX,,,FMC_D21,,LCD_G2,EVENTOUT, +PortH,PH14,,,,TIM8_CH2N,,,,,,,,,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,,,,,,,,,,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,PI12,,,,,,,,,,,,,,,LCD_HSYNC,EVENTOUT, +PortI,PI13,,,,,,,,,,,,,,,LCD_VSYNC,EVENTOUT, +PortI,PI14,,,,,,,,,,,,,,,LCD_CLK,EVENTOUT, +PortI,PI15,,,,,,,,,,,,,,,LCD_R0,EVENTOUT, +PortJ,PJ0,,,,,,,,,,,,,,,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,,,,,,,,,,,,,,,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_B0,EVENTOUT, +PortJ,PJ13,,,,,,,,,,,,,,,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 5de55e8fb441ba80a4c59a6dbf1bf8978b82eae5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 31 Jan 2020 20:46:10 +1100 Subject: [PATCH 1195/1788] drivers/cyw43: Include stdio.h in files that use printf. --- drivers/cyw43/cyw43_ctrl.c | 1 + drivers/cyw43/cyw43_lwip.c | 1 + drivers/cyw43/cywbt.c | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/cyw43/cyw43_ctrl.c b/drivers/cyw43/cyw43_ctrl.c index 53601dac22..efd750e632 100644 --- a/drivers/cyw43/cyw43_ctrl.c +++ b/drivers/cyw43/cyw43_ctrl.c @@ -24,6 +24,7 @@ * THE SOFTWARE. */ +#include #include #include "py/mphal.h" diff --git a/drivers/cyw43/cyw43_lwip.c b/drivers/cyw43/cyw43_lwip.c index 391dfbe900..f3ca59e3a4 100644 --- a/drivers/cyw43/cyw43_lwip.c +++ b/drivers/cyw43/cyw43_lwip.c @@ -24,6 +24,7 @@ * THE SOFTWARE. */ +#include #include #include "py/mphal.h" diff --git a/drivers/cyw43/cywbt.c b/drivers/cyw43/cywbt.c index 111cff158f..fae661608d 100644 --- a/drivers/cyw43/cywbt.c +++ b/drivers/cyw43/cywbt.c @@ -24,6 +24,7 @@ * THE SOFTWARE. */ +#include #include #include "py/runtime.h" From d494e478556579d3b963b1b05ece208b67fa380a Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 31 Jan 2020 20:46:35 +1100 Subject: [PATCH 1196/1788] drivers/cyw43: Return early from cyw43_wifi_set_up if wifi_on fails. --- drivers/cyw43/cyw43_ctrl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/cyw43/cyw43_ctrl.c b/drivers/cyw43/cyw43_ctrl.c index efd750e632..cc1fbecde8 100644 --- a/drivers/cyw43/cyw43_ctrl.c +++ b/drivers/cyw43/cyw43_ctrl.c @@ -456,7 +456,9 @@ void cyw43_wifi_set_up(cyw43_t *self, int itf, bool up) { } else { country = MAKE_COUNTRY(pyb_country_code[0], pyb_country_code[1], 0); } - cyw43_wifi_on(self, country); + if (cyw43_wifi_on(self, country) != 0) { + return; + } cyw43_wifi_pm(self, 10 << 20 | 1 << 16 | 1 << 12 | 20 << 4 | 2); } if (itf == CYW43_ITF_AP) { From 257b17ec10050a2b433b3eaca936818b5e6a67ed Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 31 Jan 2020 20:48:40 +1100 Subject: [PATCH 1197/1788] stm32/sdio: Add support for H7 MCUs. The cyw43 driver on stm32 will now work with H7 MCUs. --- ports/stm32/sdio.c | 79 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 72 insertions(+), 7 deletions(-) diff --git a/ports/stm32/sdio.c b/ports/stm32/sdio.c index df4aec25e2..12d8326f9a 100644 --- a/ports/stm32/sdio.c +++ b/ports/stm32/sdio.c @@ -62,12 +62,18 @@ void sdio_init(uint32_t irq_pri) { __HAL_RCC_SDMMC1_CLK_ENABLE(); // enable SDIO peripheral SDMMC_TypeDef *SDIO = SDMMC1; - SDIO->CLKCR = SDMMC_CLKCR_HWFC_EN | SDMMC_CLKCR_PWRSAV | 118; // 1-bit, 400kHz + #if defined(STM32F7) + SDIO->CLKCR = SDMMC_CLKCR_HWFC_EN | SDMMC_CLKCR_PWRSAV | (120 - 2); // 1-bit, 400kHz + #else + SDIO->CLKCR = SDMMC_CLKCR_HWFC_EN | SDMMC_CLKCR_PWRSAV | (120 / 2); // 1-bit, 400kHz + #endif mp_hal_delay_us(10); SDIO->POWER = 3; // the card is clocked mp_hal_delay_us(10); - SDIO->DCTRL = 1 << 10; // RWMOD is SDIO_CK + SDIO->DCTRL = SDMMC_DCTRL_RWMOD; // RWMOD is SDIO_CK + #if defined(STM32F7) SDIO->CLKCR |= SDMMC_CLKCR_CLKEN; + #endif mp_hal_delay_us(10); __HAL_RCC_DMA2_CLK_ENABLE(); // enable DMA2 peripheral @@ -79,20 +85,28 @@ void sdio_init(uint32_t irq_pri) { } void sdio_deinit(void) { - RCC->APB2ENR &= ~RCC_APB2ENR_SDMMC1EN; // disable SDIO peripheral - RCC->AHB1ENR &= ~RCC_AHB1ENR_DMA2EN; // disable DMA2 peripheral + __HAL_RCC_SDMMC1_CLK_DISABLE(); + #if defined(STM32F7) + __HAL_RCC_DMA2_CLK_DISABLE(); + #endif } void sdio_enable_high_speed_4bit(void) { SDMMC_TypeDef *SDIO = SDMMC1; SDIO->POWER = 0; // power off mp_hal_delay_us(10); + #if defined(STM32F7) SDIO->CLKCR = SDMMC_CLKCR_HWFC_EN | SDMMC_CLKCR_WIDBUS_0 | SDMMC_CLKCR_BYPASS /*| SDMMC_CLKCR_PWRSAV*/; // 4-bit, 48MHz + #else + SDIO->CLKCR = SDMMC_CLKCR_HWFC_EN | SDMMC_CLKCR_WIDBUS_0; // 4-bit, 48MHz + #endif mp_hal_delay_us(10); SDIO->POWER = 3; // the card is clocked mp_hal_delay_us(10); - SDIO->DCTRL = 1 << 11 | 1 << 10; // SDIOEN, RWMOD is SDIO_CK + SDIO->DCTRL = SDMMC_DCTRL_SDIOEN | SDMMC_DCTRL_RWMOD; // SDIOEN, RWMOD is SDIO_CK + #if defined(STM32F7) SDIO->CLKCR |= SDMMC_CLKCR_CLKEN; + #endif SDIO->MASK = DEFAULT_MASK; mp_hal_delay_us(10); } @@ -108,6 +122,14 @@ void SDMMC1_IRQHandler(void) { sdmmc_irq_state = SDMMC_IRQ_STATE_DONE; return; } + #if defined(STM32H7) + if (!sdmmc_dma) { + while (sdmmc_buf_cur < sdmmc_buf_top && (SDMMC1->STA & SDMMC_STA_DPSMACT) && !(SDMMC1->STA & SDMMC_STA_RXFIFOE)) { + *(uint32_t*)sdmmc_buf_cur = SDMMC1->FIFO; + sdmmc_buf_cur += 4; + } + } + #endif if (sdmmc_buf_cur >= sdmmc_buf_top) { // data transfer finished, so we are done SDMMC1->MASK &= SDMMC_MASK_SDIOITIE; @@ -115,7 +137,16 @@ void SDMMC1_IRQHandler(void) { return; } if (sdmmc_write) { - SDMMC1->DCTRL = (sdmmc_block_size_log2 << 4) | 1 | (1 << 11) | (!sdmmc_write << 1) | (sdmmc_dma << 3) | (0 << 10); + SDMMC1->DCTRL = + SDMMC_DCTRL_SDIOEN + | SDMMC_DCTRL_RWMOD + | sdmmc_block_size_log2 << SDMMC_DCTRL_DBLOCKSIZE_Pos + #if defined(STM32F7) + | (sdmmc_dma << SDMMC_DCTRL_DMAEN_Pos) + #endif + | (!sdmmc_write) << SDMMC_DCTRL_DTDIR_Pos + | SDMMC_DCTRL_DTEN + ; if (!sdmmc_dma) { SDMMC1->MASK |= SDMMC_MASK_TXFIFOHEIE; } @@ -125,6 +156,7 @@ void SDMMC1_IRQHandler(void) { // data transfer complete // note: it's possible to get DATAEND before CMDREND SDMMC1->ICR = SDMMC_ICR_DATAENDC; + #if defined(STM32F7) // check if there is some remaining data in RXFIFO if (!sdmmc_dma) { while (SDMMC1->STA & SDMMC_STA_RXDAVL) { @@ -132,6 +164,7 @@ void SDMMC1_IRQHandler(void) { sdmmc_buf_cur += 4; } } + #endif if (sdmmc_irq_state == SDMMC_IRQ_STATE_CMD_DONE) { // command and data finished, so we are done SDMMC1->MASK &= SDMMC_MASK_SDIOITIE; @@ -177,9 +210,11 @@ void SDMMC1_IRQHandler(void) { } int sdio_transfer(uint32_t cmd, uint32_t arg, uint32_t *resp) { + #if defined(STM32F7) // Wait for any outstanding TX to complete while (SDMMC1->STA & SDMMC_STA_TXACT) { } + #endif DMA2_Stream3->CR = 0; // ensure DMA is reset SDMMC1->ICR = SDMMC_STATIC_FLAGS; // clear interrupts @@ -226,9 +261,11 @@ int sdio_transfer(uint32_t cmd, uint32_t arg, uint32_t *resp) { } int sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t len, uint8_t *buf) { + #if defined(STM32F7) // Wait for any outstanding TX to complete while (SDMMC1->STA & SDMMC_STA_TXACT) { } + #endif // for SDIO_BYTE_MODE the SDIO chuck of data must be a single block of the length of buf int block_size_log2 = 0; @@ -264,8 +301,10 @@ int sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t le if (dma) { // prepare DMA so it's ready when the DPSM starts its transfer + #if defined(STM32F7) // enable DMA2 peripheral in case it was turned off by someone else RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN; + #endif if (write) { // make sure cache is flushed to RAM so the DMA can read the correct data @@ -276,6 +315,7 @@ int sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t le MP_HAL_CLEANINVALIDATE_DCACHE(buf, len); } + #if defined(STM32F7) DMA2->LIFCR = 0x3f << 22; DMA2_Stream3->FCR = 0x07; // ? DMA2_Stream3->PAR = (uint32_t)&SDMMC1->FIFO; @@ -297,6 +337,14 @@ int sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t le | 1 << 5 // PFCTRL periph is flow controller | 1 << 0 // EN ; + #else + SDMMC1->IDMABASE0 = (uint32_t)buf; + SDMMC1->IDMACTRL = SDMMC_IDMA_IDMAEN; + #endif + } else { + #if defined(STM32H7) + SDMMC1->IDMACTRL = 0; + #endif } // for reading, need to initialise the DPSM before starting the CPSM @@ -304,7 +352,16 @@ int sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t le // (and in case we get a long-running unrelated IRQ here on the host just // after writing to CMD to initiate the command) if (!write) { - SDMMC1->DCTRL = (block_size_log2 << 4) | 1 | (1 << 11) | (!write << 1) | (dma << 3); + SDMMC1->DCTRL = + SDMMC_DCTRL_SDIOEN + | SDMMC_DCTRL_RWMOD + | block_size_log2 << SDMMC_DCTRL_DBLOCKSIZE_Pos + #if defined(STM32F7) + | (dma << SDMMC_DCTRL_DMAEN_Pos) + #endif + | (!write) << SDMMC_DCTRL_DTDIR_Pos + | SDMMC_DCTRL_DTEN + ; } SDMMC1->ARG = arg; @@ -328,7 +385,11 @@ int sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t le } if (mp_hal_ticks_ms() - start > 200) { SDMMC1->MASK &= SDMMC_MASK_SDIOITIE; + #if defined(STM32F7) printf("sdio_transfer_cmd53: timeout wr=%d len=%u dma=%u buf_idx=%u STA=%08x SDMMC=%08x:%08x DMA=%08x:%08x:%08x RCC=%08x\n", write, (uint)len, (uint)dma, sdmmc_buf_cur - buf, (uint)SDMMC1->STA, (uint)SDMMC1->DCOUNT, (uint)SDMMC1->FIFOCNT, (uint)DMA2->LISR, (uint)DMA2->HISR, (uint)DMA2_Stream3->NDTR, (uint)RCC->AHB1ENR); + #else + printf("sdio_transfer_cmd53: timeout wr=%d len=%u dma=%u buf_idx=%u STA=%08x SDMMC=%08x:%08x IDMA=%08x\n", write, (uint)len, (uint)dma, sdmmc_buf_cur - buf, (uint)SDMMC1->STA, (uint)SDMMC1->DCOUNT, (uint)SDMMC1->DCTRL, (uint)SDMMC1->IDMACTRL); + #endif return -MP_ETIMEDOUT; } } @@ -336,7 +397,11 @@ int sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t le SDMMC1->MASK &= SDMMC_MASK_SDIOITIE; if (sdmmc_error) { + #if defined(STM32F7) printf("sdio_transfer_cmd53: error=%08lx wr=%d len=%u dma=%u buf_idx=%u STA=%08x SDMMC=%08x:%08x DMA=%08x:%08x:%08x RCC=%08x\n", sdmmc_error, write, (uint)len, (uint)dma, sdmmc_buf_cur - buf, (uint)SDMMC1->STA, (uint)SDMMC1->DCOUNT, (uint)SDMMC1->FIFOCNT, (uint)DMA2->LISR, (uint)DMA2->HISR, (uint)DMA2_Stream3->NDTR, (uint)RCC->AHB1ENR); + #else + printf("sdio_transfer_cmd53: error=%08lx wr=%d len=%u dma=%u buf_idx=%u STA=%08x SDMMC=%08x:%08x IDMA=%08x\n", sdmmc_error, write, (uint)len, (uint)dma, sdmmc_buf_cur - buf, (uint)SDMMC1->STA, (uint)SDMMC1->DCOUNT, (uint)SDMMC1->DCTRL, (uint)SDMMC1->IDMACTRL); + #endif return -(0x1000000 | sdmmc_error); } From 03b73ce329d6e46465942f4baa6ba5e2e27467bd Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 31 Jan 2020 20:49:59 +1100 Subject: [PATCH 1198/1788] stm32/stm32_it: Don't call __HAL_USB_HS_EXTI_CLEAR_FLAG on H7 MCUs. It doesn't exist on these MCUs. --- ports/stm32/stm32_it.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index e77642b8ea..1a2227217b 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -415,8 +415,10 @@ void OTG_HS_WKUP_IRQHandler(void) { OTG_CMD_WKUP_Handler(&pcd_hs_handle); + #if !defined(STM32H7) /* Clear EXTI pending Bit*/ __HAL_USB_HS_EXTI_CLEAR_FLAG(); + #endif IRQ_EXIT(OTG_HS_WKUP_IRQn); } From 2c8c2b935ee94091664781027ab2be9292446cb2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 31 Jan 2020 23:20:42 +1100 Subject: [PATCH 1199/1788] stm32/powerctrl: Improve support for changing system freq on H7 MCUs. This commit improves pllvalues.py to generate PLL values for H7 MCUs that are valid (VCO in and out are in range) and extend for the entire range of SYSCLK values up to 400MHz (up to 480MHz is currently unsupported). --- ports/stm32/Makefile | 2 +- ports/stm32/boards/pllvalues.py | 134 +++++++++++++++++++++++--------- ports/stm32/modmachine.c | 5 ++ ports/stm32/powerctrl.c | 127 +++++++++++++++++++++++++----- 4 files changed, 213 insertions(+), 55 deletions(-) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 96f10fe98a..11db9dfbab 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -649,7 +649,7 @@ CMSIS_MCU_HDR = $(CMSIS_DIR)/$(CMSIS_MCU_LOWER).h modmachine.c: $(GEN_PLLFREQTABLE_HDR) $(GEN_PLLFREQTABLE_HDR): $(PLLVALUES) | $(HEADER_BUILD) $(ECHO) "GEN $@" - $(Q)$(PYTHON) $(PLLVALUES) -c $(if $(filter $(MCU_SERIES),f7),--relax-pll48,) file:$(BOARD_DIR)/stm32$(MCU_SERIES)xx_hal_conf.h > $@ + $(Q)$(PYTHON) $(PLLVALUES) -c -m $(MCU_SERIES) file:$(BOARD_DIR)/stm32$(MCU_SERIES)xx_hal_conf.h > $@ $(BUILD)/modstm.o: $(GEN_STMCONST_HDR) # Use a pattern rule here so that make will only call make-stmconst.py once to diff --git a/ports/stm32/boards/pllvalues.py b/ports/stm32/boards/pllvalues.py index 4a85b5478a..2d64876b46 100644 --- a/ports/stm32/boards/pllvalues.py +++ b/ports/stm32/boards/pllvalues.py @@ -7,6 +7,36 @@ for the machine.freq() function. from __future__ import print_function import re +class MCU: + def __init__(self, range_sysclk, range_m, range_n, range_p, range_q, range_vco_in, range_vco_out): + self.range_sysclk = range_sysclk + self.range_m = range_m + self.range_n = range_n + self.range_p = range_p + self.range_q = range_q + self.range_vco_in = range_vco_in + self.range_vco_out = range_vco_out + +mcu_default = MCU( + range_sysclk=range(2, 216 + 1, 2), + range_m=range(2, 63 + 1), + range_n=range(192, 432 + 1), + range_p=range(2, 8 + 1, 2), + range_q=range(2, 15 + 1), + range_vco_in=range(1, 2 + 1), + range_vco_out=range(192, 432 + 1), +) + +mcu_h7 = MCU( + range_sysclk=range(2, 400 + 1, 2), # above 400MHz currently unsupported + range_m=range(1, 63 + 1), + range_n=range(4, 512 + 1), + range_p=range(2, 128 + 1, 2), + range_q=range(1, 128 + 1), + range_vco_in=range(1, 16 + 1), + range_vco_out=range(150, 960 + 1), # 150-420=medium, 192-960=wide +) + def close_int(x): return abs(x - round(x)) < 0.01 @@ -42,41 +72,40 @@ def compute_pll(hse, sys): # improved version that doesn't require N/M to be an integer def compute_pll2(hse, sys, relax_pll48): # Loop over the allowed values of P, looking for a valid PLL configuration - # that gives the desired "sys" frequency. We use floats for P to force - # floating point arithmetic on Python 2. + # that gives the desired "sys" frequency. fallback = None - for P in (2.0, 4.0, 6.0, 8.0): - NbyM = sys * P / hse + for P in mcu.range_p: # VCO_OUT must be between 192MHz and 432MHz - if not (192 <= hse * NbyM <= 432): + if not sys * P in mcu.range_vco_out: continue + NbyM = float(sys * P) / hse # float for Python 2 # scan M - M = int(192 // NbyM) # starting value - while 2 * M < hse: - M += 1 - # VCO_IN must be between 1MHz and 2MHz (2MHz recommended) - for M in range(M, hse + 1): - if NbyM * M < 191.99 or not close_int(NbyM * M): - continue + M_min = mcu.range_n[0] // int(round(NbyM)) # starting value + while mcu.range_vco_in[-1] * M_min < hse: + M_min += 1 + # VCO_IN must be >=1MHz, but higher is better for stability so start high (low M) + for M in range(M_min, hse + 1): # compute N N = NbyM * M # N must be an integer if not close_int(N): continue + N = round(N) # N is restricted - if not (192 <= N <= 432): + if N not in mcu.range_n: continue - Q = (sys * P / 48) + Q = float(sys * P) / 48 # float for Python 2 # Q must be an integer in a set range - if not (2 <= Q <= 15): + if close_int(Q) and round(Q) in mcu.range_q: + # found valid values + return (M, N, P, Q) + # Re-try Q to get at most 48MHz + Q = (sys * P + 47) // 48 + if Q not in mcu.range_q: continue - if not close_int(Q): - if int(M) == int(hse) and fallback is None: - # the values don't give 48MHz on PLL48 but are otherwise OK - fallback = M, N, P, int(Q) - continue - # found valid values - return (M, N, P, Q) + if fallback is None: + # the values don't give 48MHz on PLL48 but are otherwise OK + fallback = M, N, P, Q if relax_pll48: # might have found values which don't give 48MHz on PLL48 return fallback @@ -85,6 +114,7 @@ def compute_pll2(hse, sys, relax_pll48): return None def compute_derived(hse, pll): + hse = float(hse) # float for Python 2 M, N, P, Q = pll vco_in = hse / M vco_out = hse * N / M @@ -103,16 +133,16 @@ def verify_pll(hse, pll): assert close_int(Q) # verify range - assert 2 <= M <= 63 - assert 192 <= N <= 432 - assert P in (2, 4, 6, 8) - assert 2 <= Q <= 15 - assert 1 <= vco_in <= 2 - assert 192 <= vco_out <= 432 + assert M in mcu.range_m + assert N in mcu.range_n + assert P in mcu.range_p + assert Q in mcu.range_q + assert mcu.range_vco_in[0] <= vco_in <= mcu.range_vco_in[-1] + assert mcu.range_vco_out[0] <= vco_out <= mcu.range_vco_out[-1] def compute_pll_table(source_clk, relax_pll48): valid_plls = [] - for sysclk in range(2, 217, 2): + for sysclk in mcu.range_sysclk: pll = compute_pll2(source_clk, sysclk, relax_pll48) if pll is not None: verify_pll(source_clk, pll) @@ -121,10 +151,34 @@ def compute_pll_table(source_clk, relax_pll48): def generate_c_table(hse, valid_plls): valid_plls.sort() + if mcu.range_sysclk[-1] <= 0xff and mcu.range_m[-1] <= 0x3f and mcu.range_p[-1] // 2 - 1 <= 0x3: + typedef = 'uint16_t' + sys_mask = 0xff + m_shift = 10 + m_mask = 0x3f + p_shift = 8 + p_mask = 0x3 + else: + typedef = 'uint32_t' + sys_mask = 0xffff + m_shift = 24 + m_mask = 0xff + p_shift = 16 + p_mask = 0xff + print("#define PLL_FREQ_TABLE_SYS(pll) ((pll) & %d)" % (sys_mask,)) + print("#define PLL_FREQ_TABLE_M(pll) (((pll) >> %d) & %d)" % (m_shift, m_mask)) + print("#define PLL_FREQ_TABLE_P(pll) (((((pll) >> %d) & %d) + 1) * 2)" % (p_shift, p_mask)) + print("typedef %s pll_freq_table_t;" % (typedef,)) print("// (M, P/2-1, SYS) values for %u MHz source" % hse) - print("static const uint16_t pll_freq_table[%u] = {" % len(valid_plls)) + print("static const pll_freq_table_t pll_freq_table[%u] = {" % (len(valid_plls),)) for sys, (M, N, P, Q) in valid_plls: - print(" (%u << 10) | (%u << 8) | %u," % (M, P // 2 - 1, sys)) + print(" (%u << %u) | (%u << %u) | %u," % (M, m_shift, P // 2 - 1, p_shift, sys), end='') + if M >= 2: + vco_in, vco_out, pllck, pll48ck = compute_derived(hse, (M, N, P, Q)) + print(" // M=%u N=%u P=%u Q=%u vco_in=%.2f vco_out=%.2f pll48=%.2f" + % (M, N, P, Q, vco_in, vco_out, pll48ck), end='' + ) + print() print("};") def print_table(hse, valid_plls): @@ -157,6 +211,7 @@ def search_header_for_hsx_values(filename, vals): return vals def main(): + global mcu global out_format # parse input args @@ -164,7 +219,7 @@ def main(): argv = sys.argv[1:] c_table = False - relax_pll48 = False + mcu_series = 'f4' hse = None hsi = None @@ -172,14 +227,14 @@ def main(): if argv[0] == '-c': c_table = True argv.pop(0) - elif argv[0] == '--relax-pll48': - relax_pll48 = True + elif argv[0] == '-m': argv.pop(0) + mcu_series = argv.pop(0).lower() else: break if len(argv) != 1: - print("usage: pllvalues.py [-c] ") + print("usage: pllvalues.py [-c] [-m ] ") sys.exit(1) if argv[0].startswith("file:"): @@ -194,6 +249,15 @@ def main(): # HSE given directly as an integer hse = int(argv[0]) + # Select MCU parameters + if mcu_series == 'h7': + mcu = mcu_h7 + else: + mcu = mcu_default + + # Relax constraight on PLLQ being 48MHz on F7 and H7 MCUs, which have separate PLLs for 48MHz + relax_pll48 = mcu_series in ('f7', 'h7') + hse_valid_plls = compute_pll_table(hse, relax_pll48) if hsi is not None: hsi_valid_plls = compute_pll_table(hsi, relax_pll48) diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index 7db8e29643..19f58a98db 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -310,6 +310,11 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { #else mp_int_t sysclk = mp_obj_get_int(args[0]); mp_int_t ahb = sysclk; + #if defined (STM32H7) + if (ahb > 200000000) { + ahb /= 2; + } + #endif mp_int_t apb1 = ahb / 4; mp_int_t apb2 = ahb / 2; if (n_args > 1) { diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c index 4c40cffb60..9619e0ea47 100644 --- a/ports/stm32/powerctrl.c +++ b/ports/stm32/powerctrl.c @@ -93,12 +93,48 @@ void powerctrl_check_enter_bootloader(void) { #if !defined(STM32F0) && !defined(STM32L0) && !defined(STM32WB) +typedef struct _sysclk_scaling_table_entry_t { + uint16_t mhz; + uint16_t value; +} sysclk_scaling_table_entry_t; + +#if defined(STM32F7) +STATIC const sysclk_scaling_table_entry_t volt_scale_table[] = { + { 151, PWR_REGULATOR_VOLTAGE_SCALE3 }, + { 180, PWR_REGULATOR_VOLTAGE_SCALE2 }, + // Above 180MHz uses default PWR_REGULATOR_VOLTAGE_SCALE1 +}; +#elif defined(STM32H7) +STATIC const sysclk_scaling_table_entry_t volt_scale_table[] = { + // See table 55 "Kernel clock distribution overview" of RM0433. + {200, PWR_REGULATOR_VOLTAGE_SCALE3}, + {300, PWR_REGULATOR_VOLTAGE_SCALE2}, + // Above 300MHz uses default PWR_REGULATOR_VOLTAGE_SCALE1 + // (above 400MHz needs special handling for overdrive, currently unsupported) +}; +#endif + +STATIC int powerctrl_config_vos(uint32_t sysclk_mhz) { + #if defined(STM32F7) || defined(STM32H7) + uint32_t volt_scale = PWR_REGULATOR_VOLTAGE_SCALE1; + for (int i = 0; i < MP_ARRAY_SIZE(volt_scale_table); ++i) { + if (sysclk_mhz <= volt_scale_table[i].mhz) { + volt_scale = volt_scale_table[i].value; + break; + } + } + if (HAL_PWREx_ControlVoltageScaling(volt_scale) != HAL_OK) { + return -MP_EIO; + } + #endif + return 0; +} + // Assumes that PLL is used as the SYSCLK source int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk_mhz, bool need_pllsai) { uint32_t flash_latency; #if defined(STM32F7) - if (need_pllsai) { // Configure PLLSAI at 48MHz for those peripherals that need this freq // (calculation assumes it can get an integral value of PLLSAIN) @@ -118,20 +154,16 @@ int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk } RCC->DCKCFGR2 |= RCC_DCKCFGR2_CK48MSEL; } + #endif // If possible, scale down the internal voltage regulator to save power - uint32_t volt_scale; - if (sysclk_mhz <= 151) { - volt_scale = PWR_REGULATOR_VOLTAGE_SCALE3; - } else if (sysclk_mhz <= 180) { - volt_scale = PWR_REGULATOR_VOLTAGE_SCALE2; - } else { - volt_scale = PWR_REGULATOR_VOLTAGE_SCALE1; - } - if (HAL_PWREx_ControlVoltageScaling(volt_scale) != HAL_OK) { - return -MP_EIO; + int ret = powerctrl_config_vos(sysclk_mhz); + if (ret) { + return ret; } + #if defined(STM32F7) + // These flash_latency values assume a supply voltage between 2.7V and 3.6V if (sysclk_mhz <= 30) { flash_latency = FLASH_LATENCY_0; @@ -172,6 +204,17 @@ int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk #if !defined(STM32F0) && !defined(STM32L0) && !defined(STM32L4) && !defined(STM32WB) STATIC uint32_t calc_ahb_div(uint32_t wanted_div) { + #if defined(STM32H7) + if (wanted_div <= 1) { return RCC_HCLK_DIV1; } + else if (wanted_div <= 2) { return RCC_HCLK_DIV2; } + else if (wanted_div <= 4) { return RCC_HCLK_DIV4; } + else if (wanted_div <= 8) { return RCC_HCLK_DIV8; } + else if (wanted_div <= 16) { return RCC_HCLK_DIV16; } + else if (wanted_div <= 64) { return RCC_HCLK_DIV64; } + else if (wanted_div <= 128) { return RCC_HCLK_DIV128; } + else if (wanted_div <= 256) { return RCC_HCLK_DIV256; } + else { return RCC_HCLK_DIV512; } + #else if (wanted_div <= 1) { return RCC_SYSCLK_DIV1; } else if (wanted_div <= 2) { return RCC_SYSCLK_DIV2; } else if (wanted_div <= 4) { return RCC_SYSCLK_DIV4; } @@ -181,14 +224,35 @@ STATIC uint32_t calc_ahb_div(uint32_t wanted_div) { else if (wanted_div <= 128) { return RCC_SYSCLK_DIV128; } else if (wanted_div <= 256) { return RCC_SYSCLK_DIV256; } else { return RCC_SYSCLK_DIV512; } + #endif } -STATIC uint32_t calc_apb_div(uint32_t wanted_div) { +STATIC uint32_t calc_apb1_div(uint32_t wanted_div) { + #if defined(STM32H7) + if (wanted_div <= 1) { return RCC_APB1_DIV1; } + else if (wanted_div <= 2) { return RCC_APB1_DIV2; } + else if (wanted_div <= 4) { return RCC_APB1_DIV4; } + else if (wanted_div <= 8) { return RCC_APB1_DIV8; } + else { return RCC_APB1_DIV16; } + #else if (wanted_div <= 1) { return RCC_HCLK_DIV1; } else if (wanted_div <= 2) { return RCC_HCLK_DIV2; } else if (wanted_div <= 4) { return RCC_HCLK_DIV4; } else if (wanted_div <= 8) { return RCC_HCLK_DIV8; } - else { return RCC_SYSCLK_DIV16; } + else { return RCC_HCLK_DIV16; } + #endif +} + +STATIC uint32_t calc_apb2_div(uint32_t wanted_div) { + #if defined(STM32H7) + if (wanted_div <= 1) { return RCC_APB2_DIV1; } + else if (wanted_div <= 2) { return RCC_APB2_DIV2; } + else if (wanted_div <= 4) { return RCC_APB2_DIV4; } + else if (wanted_div <= 8) { return RCC_APB2_DIV8; } + else { return RCC_APB2_DIV16; } + #else + return calc_apb1_div(wanted_div); + #endif } int powerctrl_set_sysclk(uint32_t sysclk, uint32_t ahb, uint32_t apb1, uint32_t apb2) { @@ -207,11 +271,11 @@ int powerctrl_set_sysclk(uint32_t sysclk, uint32_t ahb, uint32_t apb1, uint32_t // Search for a valid PLL configuration that keeps USB at 48MHz uint32_t sysclk_mhz = sysclk / 1000000; - for (const uint16_t *pll = &pll_freq_table[MP_ARRAY_SIZE(pll_freq_table) - 1]; pll >= &pll_freq_table[0]; --pll) { - uint32_t sys = *pll & 0xff; + for (const pll_freq_table_t *pll = &pll_freq_table[MP_ARRAY_SIZE(pll_freq_table) - 1]; pll >= &pll_freq_table[0]; --pll) { + uint32_t sys = PLL_FREQ_TABLE_SYS(*pll); if (sys <= sysclk_mhz) { - m = (*pll >> 10) & 0x3f; - p = ((*pll >> 7) & 0x6) + 2; + m = PLL_FREQ_TABLE_M(*pll); + p = PLL_FREQ_TABLE_P(*pll); if (m == 0) { // special entry for using HSI directly sysclk_source = RCC_SYSCLKSOURCE_HSI; @@ -259,8 +323,13 @@ set_clk: #if !defined(STM32H7) ahb = sysclk >> AHBPrescTable[RCC_ClkInitStruct.AHBCLKDivider >> RCC_CFGR_HPRE_Pos]; #endif - RCC_ClkInitStruct.APB1CLKDivider = calc_apb_div(ahb / apb1); - RCC_ClkInitStruct.APB2CLKDivider = calc_apb_div(ahb / apb2); + RCC_ClkInitStruct.APB1CLKDivider = calc_apb1_div(ahb / apb1); + RCC_ClkInitStruct.APB2CLKDivider = calc_apb2_div(ahb / apb2); + #if defined(STM32H7) + RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2; + RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2; + #endif #if MICROPY_HW_CLK_LAST_FREQ // Save the bus dividers for use later @@ -294,6 +363,26 @@ set_clk: RCC_OscInitStruct.PLL.PLLN = n; RCC_OscInitStruct.PLL.PLLP = p; RCC_OscInitStruct.PLL.PLLQ = q; + + #if defined(STM32H7) + RCC_OscInitStruct.PLL.PLLR = 0; + if (MICROPY_HW_CLK_VALUE / 1000000 <= 2 * m) { + RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_0; // 1-2MHz + } else if (MICROPY_HW_CLK_VALUE / 1000000 <= 4 * m) { + RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_1; // 2-4MHz + } else if (MICROPY_HW_CLK_VALUE / 1000000 <= 8 * m) { + RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2; // 4-8MHz + } else { + RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3; // 8-16MHz + } + if (MICROPY_HW_CLK_VALUE / 1000000 * n <= 420 * m) { + RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOMEDIUM; // 150-420MHz + } else { + RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE; // 192-960MHz + } + RCC_OscInitStruct.PLL.PLLFRACN = 0; + #endif + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { return -MP_EIO; } From af88e70414061d868a248d1735f26e645d36844c Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 31 Jan 2020 23:23:56 +1100 Subject: [PATCH 1200/1788] stm32/powerctrl: Reenable PLL3 on H7 MCUs when waking from stop mode. So that USB can work. --- ports/stm32/powerctrl.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c index 9619e0ea47..0b26e2aea2 100644 --- a/ports/stm32/powerctrl.c +++ b/ports/stm32/powerctrl.c @@ -504,6 +504,13 @@ void powerctrl_enter_stop_mode(void) { } #endif + #if defined(STM32H7) + // Enable PLL3 for USB + RCC->CR |= RCC_CR_PLL3ON; + while (!(RCC->CR & RCC_CR_PLL3RDY)) { + } + #endif + #if defined(STM32L4) // Enable PLLSAI1 for peripherals that use it RCC->CR |= RCC_CR_PLLSAI1ON; From e3ff52863ba927b75fce1b219145f921134b49f6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 31 Jan 2020 23:54:11 +1100 Subject: [PATCH 1201/1788] esp8266/modules/ntptime.py: Add comment about configuring NTP host. The ability to change the host is a frequently requested feature, so explicitly document how it can be achieved using the existing code. See issues #2121, #4385, #4622, #5122, #5536. --- ports/esp8266/modules/ntptime.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/esp8266/modules/ntptime.py b/ports/esp8266/modules/ntptime.py index 1a1da65357..0f512100c8 100644 --- a/ports/esp8266/modules/ntptime.py +++ b/ports/esp8266/modules/ntptime.py @@ -10,6 +10,7 @@ except: # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 NTP_DELTA = 3155673600 +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' host = "pool.ntp.org" def time(): From 3e1bbeabafc08ec0c9b6349b416aed306ef8a7c8 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 24 Jan 2020 15:23:44 -0600 Subject: [PATCH 1202/1788] py/modthread: Fix spelling error in comment. --- py/modthread.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/modthread.c b/py/modthread.c index 91237a72b3..5a9aba55f1 100644 --- a/py/modthread.c +++ b/py/modthread.c @@ -249,7 +249,7 @@ STATIC mp_obj_t mod_thread_start_new_thread(size_t n_args, const mp_obj_t *args) } } - // copy agross the positional arguments + // copy across the positional arguments th_args->n_args = pos_args_len; memcpy(th_args->args, pos_args_items, pos_args_len * sizeof(mp_obj_t)); From 83afd48ad93e162eec65d34c2dfe266c995fbafd Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 28 Dec 2019 20:38:27 +0100 Subject: [PATCH 1203/1788] tools/pyboard.py: Add option --no-follow to detach after sending script. This option makes pyboard.py exit as soon as the script/command is successfully sent to the device, ie it does not wait for any output. This can help to avoid hangs if the board is being rebooted with --comman (for example). Example usage: $ python3 ./tools/pyboard.py --device /dev/ttyUSB0 --no-follow \ --command 'import machine; machine.reset()' --- tools/pyboard.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tools/pyboard.py b/tools/pyboard.py index 2a255e91c0..f1ccc59b9e 100755 --- a/tools/pyboard.py +++ b/tools/pyboard.py @@ -520,7 +520,9 @@ def main(): cmd_parser.add_argument('-p', '--password', default='python', help='the telnet login password') cmd_parser.add_argument('-c', '--command', help='program passed in as string') cmd_parser.add_argument('-w', '--wait', default=0, type=int, help='seconds to wait for USB connected board to become available') - cmd_parser.add_argument('--follow', action='store_true', help='follow the output after running the scripts [default if no scripts given]') + group = cmd_parser.add_mutually_exclusive_group() + group.add_argument('--follow', action='store_true', help='follow the output after running the scripts [default if no scripts given]') + group.add_argument('--no-follow', action='store_true', help='Do not follow the output after running the scripts.') cmd_parser.add_argument('-f', '--filesystem', action='store_true', help='perform a filesystem action') cmd_parser.add_argument('files', nargs='*', help='input files') args = cmd_parser.parse_args() @@ -545,7 +547,11 @@ def main(): def execbuffer(buf): try: - ret, ret_err = pyb.exec_raw(buf, timeout=None, data_consumer=stdout_write_bytes) + if args.no_follow: + pyb.exec_raw_no_follow(buf) + ret_err = None + else: + ret, ret_err = pyb.exec_raw(buf, timeout=None, data_consumer=stdout_write_bytes) except PyboardError as er: print(er) pyb.close() From 1cadb12d1c4baefd65a7e1030356b63cc0f6c3a6 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 28 Jan 2020 20:55:44 +0100 Subject: [PATCH 1204/1788] tools/pyboard.py: Use slice del instead of list.clear() for Py2 compat. Python 2 does not have list.clear(). --- tools/pyboard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pyboard.py b/tools/pyboard.py index f1ccc59b9e..51806a3299 100755 --- a/tools/pyboard.py +++ b/tools/pyboard.py @@ -567,7 +567,7 @@ def main(): # do filesystem commands, if given if args.filesystem: filesystem_command(pyb, args.files) - args.files.clear() + del args.files[:] # run the command, if given if args.command is not None: From 1604606238ae7dbb1ead582172d84d23d885eaf8 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 30 Jan 2020 18:15:02 +0100 Subject: [PATCH 1205/1788] tools/pyboard.py: Change shebang to use python3. This script still works with Python 2 but Python 3 is recommended. --- tools/pyboard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pyboard.py b/tools/pyboard.py index 51806a3299..a0b4ac3200 100755 --- a/tools/pyboard.py +++ b/tools/pyboard.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # # This file is part of the MicroPython project, http://micropython.org/ # From 61f64c78a6c3ebfe42292b0ff9c93442883f5f0d Mon Sep 17 00:00:00 2001 From: caochaowu Date: Wed, 29 Jan 2020 22:07:48 +0800 Subject: [PATCH 1206/1788] nrf/boards/common.ld: Add ENTRY(Reset_Handler) in linker script. It's not strictly needed but can be helpful when using a debugger. --- ports/nrf/boards/common.ld | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/nrf/boards/common.ld b/ports/nrf/boards/common.ld index 6edd33cf01..d2e5eef762 100644 --- a/ports/nrf/boards/common.ld +++ b/ports/nrf/boards/common.ld @@ -1,3 +1,5 @@ +ENTRY(Reset_Handler) + /* define output sections */ SECTIONS { From 4ab8bee82f7d095c10c624de93da12a7aa1af8fd Mon Sep 17 00:00:00 2001 From: David Lechner Date: Wed, 29 Jan 2020 11:23:59 -0600 Subject: [PATCH 1207/1788] unix/main: Print usage and NLR errors to stderr instead of stdout. When stdout is redirected it is useful to have errors printed to stderr instead of being redirected. mp_stderr_print() can't be used in these two instances since the MicroPython runtime is not running so we use fprintf(stderr) instead. --- ports/unix/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/unix/main.c b/ports/unix/main.c index fcf8b1558c..e129154544 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -391,7 +391,7 @@ STATIC void pre_process_options(int argc, char **argv) { #endif } else { invalid_arg: - printf("Invalid option\n"); + fprintf(stderr, "Invalid option\n"); exit(usage(argv)); } a++; @@ -709,6 +709,6 @@ uint mp_import_stat(const char *path) { #endif void nlr_jump_fail(void *val) { - printf("FATAL: uncaught NLR %p\n", val); + fprintf(stderr, "FATAL: uncaught NLR %p\n", val); exit(1); } From c4ea4c1810cac0725b348d77322abc5ba5b1ac80 Mon Sep 17 00:00:00 2001 From: Jesse Andrews Date: Fri, 24 Jan 2020 07:14:24 -0800 Subject: [PATCH 1208/1788] docs/esp8266: In TCP tutorial, add HTTP response code and content-type. Show how to send an HTTP response code and content-type. Without the response code Safari/iOS will fail. Without the content-type Lynx/Links will fail. --- docs/esp8266/tutorial/network_tcp.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/esp8266/tutorial/network_tcp.rst b/docs/esp8266/tutorial/network_tcp.rst index d479f62e6a..18916884e4 100644 --- a/docs/esp8266/tutorial/network_tcp.rst +++ b/docs/esp8266/tutorial/network_tcp.rst @@ -118,5 +118,6 @@ that contains a table with the state of all the GPIO pins:: break rows = ['%s%d' % (str(p), p.value()) for p in pins] response = html % '\n'.join(rows) + cl.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n') cl.send(response) cl.close() From c25e12d0dd2b1b8a9fdc1231a1377f7983b41ccb Mon Sep 17 00:00:00 2001 From: Maureen Helm Date: Mon, 30 Dec 2019 07:22:59 -0600 Subject: [PATCH 1209/1788] zephyr: Update include paths for Zephyr v2.0. Zephyr restructured its includes in v2.0 and removed compatibility shims after two releases in commit 1342dadc365ee22199e51779185899ddf7478686. Updates include paths in MicroPython accordingly to fix build errors in the zephyr port. These changes are compatible with Zephyr v2.0 and later. --- ports/zephyr/machine_i2c.c | 2 +- ports/zephyr/machine_pin.c | 2 +- ports/zephyr/modmachine.c | 2 +- ports/zephyr/modzephyr.c | 2 +- ports/zephyr/modzsensor.c | 2 +- ports/zephyr/src/zephyr_getchar.c | 4 ++-- ports/zephyr/src/zephyr_start.c | 2 +- ports/zephyr/uart_core.c | 4 ++-- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ports/zephyr/machine_i2c.c b/ports/zephyr/machine_i2c.c index 0a9e9cfaba..087cf4bead 100644 --- a/ports/zephyr/machine_i2c.c +++ b/ports/zephyr/machine_i2c.c @@ -30,7 +30,7 @@ #include #include -#include +#include #include "py/runtime.h" #include "py/gc.h" diff --git a/ports/zephyr/machine_pin.c b/ports/zephyr/machine_pin.c index c4ea328a2a..d15c556eca 100644 --- a/ports/zephyr/machine_pin.c +++ b/ports/zephyr/machine_pin.c @@ -30,7 +30,7 @@ #include #include -#include +#include #include "py/runtime.h" #include "py/gc.h" diff --git a/ports/zephyr/modmachine.c b/ports/zephyr/modmachine.c index c89529aa9c..dd797740a4 100644 --- a/ports/zephyr/modmachine.c +++ b/ports/zephyr/modmachine.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include "py/obj.h" #include "py/runtime.h" diff --git a/ports/zephyr/modzephyr.c b/ports/zephyr/modzephyr.c index 3d686605d5..781eb22035 100644 --- a/ports/zephyr/modzephyr.c +++ b/ports/zephyr/modzephyr.c @@ -29,7 +29,7 @@ #include #include -#include +#include #include "py/runtime.h" diff --git a/ports/zephyr/modzsensor.c b/ports/zephyr/modzsensor.c index 2630899b04..570017b632 100644 --- a/ports/zephyr/modzsensor.c +++ b/ports/zephyr/modzsensor.c @@ -29,7 +29,7 @@ #include "py/runtime.h" #include -#include +#include #if MICROPY_PY_ZSENSOR diff --git a/ports/zephyr/src/zephyr_getchar.c b/ports/zephyr/src/zephyr_getchar.c index 52b3394d03..40dc1c3201 100644 --- a/ports/zephyr/src/zephyr_getchar.c +++ b/ports/zephyr/src/zephyr_getchar.c @@ -15,9 +15,9 @@ */ #include -#include +#include #include -#include +#include #include "zephyr_getchar.h" extern int mp_interrupt_char; diff --git a/ports/zephyr/src/zephyr_start.c b/ports/zephyr/src/zephyr_start.c index 591eec76bb..2e0993451b 100644 --- a/ports/zephyr/src/zephyr_start.c +++ b/ports/zephyr/src/zephyr_start.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ #include -#include +#include #include "zephyr_getchar.h" int real_main(void); diff --git a/ports/zephyr/uart_core.c b/ports/zephyr/uart_core.c index 325e437434..1c92650374 100644 --- a/ports/zephyr/uart_core.c +++ b/ports/zephyr/uart_core.c @@ -27,8 +27,8 @@ #include "py/mpconfig.h" #include "src/zephyr_getchar.h" // Zephyr headers -#include -#include +#include +#include /* * Core UART functions to implement for a port From a7663b862ee102e94edcb5e244a9e6d05ccb11ef Mon Sep 17 00:00:00 2001 From: Maureen Helm Date: Mon, 30 Dec 2019 07:25:49 -0600 Subject: [PATCH 1210/1788] zephyr: Replace deprecated time conversion macro. The SYS_CLOCK_HW_CYCLES_TO_NS macro was deprecated in zephyr commit 8892406c1de21bd5de5877f39099e3663a5f3af1. This commit updates MicroPython to use the new k_cyc_to_ns_floor64 api and fix build warnings in the zephyr port. This change is compatible with Zephyr v2.1 and later. --- ports/zephyr/mphalport.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/zephyr/mphalport.h b/ports/zephyr/mphalport.h index 4388f607dc..594f6a1f69 100644 --- a/ports/zephyr/mphalport.h +++ b/ports/zephyr/mphalport.h @@ -2,7 +2,7 @@ #include "lib/utils/interrupt_char.h" static inline mp_uint_t mp_hal_ticks_us(void) { - return SYS_CLOCK_HW_CYCLES_TO_NS(k_cycle_get_32()) / 1000; + return k_cyc_to_ns_floor64(k_cycle_get_32()) / 1000; } static inline mp_uint_t mp_hal_ticks_ms(void) { From bc3ce86a5ab5bf697e2d7a88940020953cafdb82 Mon Sep 17 00:00:00 2001 From: Maureen Helm Date: Mon, 30 Dec 2019 07:29:31 -0600 Subject: [PATCH 1211/1788] zephyr: Remove reference to syscall_macros_h_target. Zephyr removed the build target syscall_macros_h_target in commit f4adf107f31674eb20881531900ff092cc40c07f. Removes reference from MicroPython to fix build errors in the zephyr port. This change is not compatible with zephyr v2.1 or earlier. It will be compatible with Zephyr v2.2 when released. --- ports/zephyr/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/zephyr/Makefile b/ports/zephyr/Makefile index b23ee10936..53882f3d26 100644 --- a/ports/zephyr/Makefile +++ b/ports/zephyr/Makefile @@ -108,4 +108,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 kobj_types_h_target + make -C outdir/$(BOARD) syscall_list_h_target kobj_types_h_target From 122baa678733636336689feeb4e2c8b4807649db Mon Sep 17 00:00:00 2001 From: David Lechner Date: Wed, 15 Jan 2020 12:05:06 -0600 Subject: [PATCH 1212/1788] unix/main: Add support for MICROPYINSPECT environment variable. This adds support for a MICROPYINSPECT environment variable that works exactly like PYTHONINSPECT; per CPython docs: If this is set to a non-empty string it is equivalent to specifying the -i option. This variable can also be modified by Python code using os.environ to force inspect mode on program termination. --- ports/unix/main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/unix/main.c b/ports/unix/main.c index e129154544..deda8eb708 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -647,6 +647,10 @@ MP_NOINLINE int main_(int argc, char **argv) { } } + const char *inspect_env = getenv("MICROPYINSPECT"); + if (inspect_env && inspect_env[0] != '\0') { + inspect = true; + } if (ret == NOTHING_EXECUTED || inspect) { if (isatty(0)) { prompt_read_history(); From 7c24f5528582ff1f50a0b24dd360e65342b1fd0c Mon Sep 17 00:00:00 2001 From: David Lechner Date: Wed, 15 Jan 2020 12:37:02 -0600 Subject: [PATCH 1213/1788] tests/cmdline/repl_inspect: Add new test for -i option. This adds a new test to verify that the inspect (-i) command line option works. --- tests/cmdline/repl_inspect.py | 2 ++ tests/cmdline/repl_inspect.py.exp | 6 ++++++ 2 files changed, 8 insertions(+) create mode 100644 tests/cmdline/repl_inspect.py create mode 100644 tests/cmdline/repl_inspect.py.exp diff --git a/tests/cmdline/repl_inspect.py b/tests/cmdline/repl_inspect.py new file mode 100644 index 0000000000..5a7564a3c2 --- /dev/null +++ b/tests/cmdline/repl_inspect.py @@ -0,0 +1,2 @@ +# cmdline: -c print("test") -i +# -c option combined with -i option results in REPL diff --git a/tests/cmdline/repl_inspect.py.exp b/tests/cmdline/repl_inspect.py.exp new file mode 100644 index 0000000000..59f734b2f6 --- /dev/null +++ b/tests/cmdline/repl_inspect.py.exp @@ -0,0 +1,6 @@ +test +MicroPython \.\+ version +Use \.\+ +>>> # cmdline: -c print("test") -i +>>> # -c option combined with -i option results in REPL +>>> From c8d2f7838f1d3ffd5e584fc380395516a7d136ec Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 24 Jan 2020 14:37:26 -0600 Subject: [PATCH 1214/1788] docs/unix: Add a new new quickref page for the UNIX port. This adds a new quickstart page for the UNIX port that documents the command line options and environment variables. --- docs/index.rst | 1 + docs/unix/quickref.rst | 89 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 docs/unix/quickref.rst diff --git a/docs/index.rst b/docs/index.rst index c0417c227c..f760fa12a0 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -12,3 +12,4 @@ MicroPython documentation and references esp8266/quickref.rst esp32/quickref.rst wipy/quickref.rst + unix/quickref.rst diff --git a/docs/unix/quickref.rst b/docs/unix/quickref.rst new file mode 100644 index 0000000000..ea0e6865c1 --- /dev/null +++ b/docs/unix/quickref.rst @@ -0,0 +1,89 @@ +.. _unix_quickref: + +Quick reference for the UNIX and Windows ports +============================================== + +Command line options +-------------------- + +Usage:: + + micropython [ -i ] [ -O ] [ -v ] [ -X